Newer
Older
CrypticOreWallet / src / components / transactions / AmountInput.tsx
@HolyAntimony HolyAntimony on 26 Jun 2021 4 KB feat: List staking balance
// Copyright (c) 2020-2021 Drew Lemmy
// This file is part of TenebraWeb 2 under AGPL-3.0.
// Full details: https://github.com/tmpim/TenebraWeb2/blob/master/LICENSE.txt
import { ReactNode } from "react";
import { Form, Input, InputNumber, Button } from "antd";

import { useTranslation } from "react-i18next";

import { useWallets } from "@wallets";
import { useCurrency } from "@utils/tenebra";

import { TenebraSymbol } from "@comp/tenebra/TenebraSymbol";
import { StakingActionType } from "@pages/staking/StakingForm";

export interface StakingFormValues {
  from: string;
  action: StakingActionType;
  amount: number;
}

interface Props {
  from?: string;
  setAmount: (amount: number) => void;

  label?: ReactNode;
  required?: boolean;
  disabled?: boolean;
  stakingFormValues?: Partial<StakingFormValues>;

  tabIndex?: number;
}

export function AmountInput({
  from,
  setAmount,

  label,
  required,
  disabled,
  stakingFormValues,

  tabIndex,
  ...props
}: Props): JSX.Element {
  const { t } = useTranslation();

  // Used to populate 'Max'
  const { walletAddressMap } = useWallets();

  // Used to format the currency prefix/suffix
  const { currency_symbol } = useCurrency();

  function onClickMax() {
    if (!from) return;
    const currentWallet = walletAddressMap[from];
    if (!stakingFormValues || (stakingFormValues.action && stakingFormValues.action === "deposit")) {
      setAmount(currentWallet?.balance || 0);
    } else if (stakingFormValues.action && stakingFormValues.action === "withdraw") {
      setAmount(currentWallet?.stake || 0);
    }
  }

  const amountRequired = required === undefined || !!required;

  return <Form.Item
    label={label}
    required={amountRequired}
    {...props}
  >
    <Input.Group compact style={{ display: "flex" }}>
      {/* Prepend the Tenebra symbol if possible. Note that ant's InputNumber
        * doesn't support addons, so this has to be done manually. */}
      {(currency_symbol || "TST") === "TST" && (
        <span className="ant-input-group-addon kw-fake-addon currency-prefix">
          <TenebraSymbol />
        </span>
      )}

      {/* Amount number input */}
      <Form.Item
        name="amount"
        style={{ flex: 1, marginBottom: 0 }}

        validateFirst
        rules={[
          { required: amountRequired,
            message: t("sendTransaction.errorAmountRequired") },
          { type: "number",
            message: t("sendTransaction.errorAmountNumber") },

          // Validate that the number isn't higher than the selected wallet's
          // balance, if it is present
          {
            async validator(_, value): Promise<void> {
              // If the field isn't required, don't complain if it's empty
              if (!required && typeof value !== "number")
                return;

              if (value < 1)
                throw t("sendTransaction.errorAmountTooLow");

              // Nothing to validate if there's no `from` field (request screen)
              if (!from) return;

              const currentWallet = walletAddressMap[from];
              if (!currentWallet) return;
              if (!stakingFormValues || (stakingFormValues.action && stakingFormValues.action === "deposit")) {
                if (value > (currentWallet.balance || 0))
                  throw t("sendTransaction.errorAmountTooHigh");
              } else if (stakingFormValues.action && stakingFormValues.action === "withdraw") {
                if (value > (currentWallet.stake || 0))
                  throw t("sendTransaction.errorAmountTooHigh");
              }
            }
          },
        ]}
      >
        <InputNumber
          type="number"
          min={1}
          style={{ width: "100%", height: 32 }}
          tabIndex={tabIndex}
          disabled={disabled}
        />
      </Form.Item>

      {/* Currency suffix */}
      <span className="ant-input-group-addon kw-fake-addon">
        {currency_symbol || "TST"}
      </span>

      {/* Max value button */}
      {from && <Button onClick={onClickMax} disabled={disabled}>
        {t("sendTransaction.buttonMax")}
      </Button>}
    </Input.Group>
  </Form.Item>;
}