diff --git a/public/locales/en.json b/public/locales/en.json index 7b8a896..bf133f9 100644 --- a/public/locales/en.json +++ b/public/locales/en.json @@ -728,7 +728,7 @@ "optionalFieldUnset": "(unset)", "addressPicker": { - "placeholder": "Type an address, or choose a wallet", + "placeholder": "Choose a recipient", "placeholderWalletsOnly": "Choose a wallet", "hintCurrentBalance": "Current balance: <1 />", @@ -766,7 +766,15 @@ "labelMetadata": "Metadata", "placeholderMetadata": "Optional metadata", - "buttonMax": "Max" + "buttonMax": "Max", + + "errorAmountRequired": "Amount is required.", + "errorAmountNumber": "Amount must be a number.", + "errorAmountTooLow": "Amount must be at least 1.", + "errorAmountTooHigh": "Insufficient funds in wallet.", + + "errorMetadataTooLong": "Metadata must be less than 256 characters.", + "errorMetadataInvalid": "Metadata contains invalid characters." // TODO: modals/warnings for confirmation of sending over 50% of balance, // whole balance, and form validation messages diff --git a/public/locales/nl.json b/public/locales/nl.json index 036c432..706d9cc 100644 --- a/public/locales/nl.json +++ b/public/locales/nl.json @@ -727,7 +727,7 @@ "optionalFieldUnset": "(geen waarde)", "addressPicker": { - "placeholder": "Typ een adres of kies een wallet", + "placeholder": "Kies een ontvanger", "placeholderWalletsOnly": "Kies een wallet", "hintCurrentBalance": "Huidige balans: <1 />", diff --git a/src/components/addresses/picker/AddressPicker.tsx b/src/components/addresses/picker/AddressPicker.tsx index 5bd5b39..faf8928 100644 --- a/src/components/addresses/picker/AddressPicker.tsx +++ b/src/components/addresses/picker/AddressPicker.tsx @@ -169,6 +169,7 @@ > void; +} + +export function AmountInput({ from, setValue, ...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() { + const currentWallet = walletAddressMap[from]; + setValue(currentWallet?.balance || 0); + } + + return + + {/* Prepend the Krist symbol if possible. Note that ant's InputNumber + * doesn't support addons, so this has to be done manually. */} + {(currency_symbol || "KST") === "KST" && ( + + + + )} + + {/* Value/amount number input */} + { + if (value < 1) + throw t("sendTransaction.errorAmountTooLow"); + + const currentWallet = walletAddressMap[from]; + if (!currentWallet) return; + if (value > (currentWallet.balance || 0)) + throw t("sendTransaction.errorAmountTooHigh"); + } + }, + ]} + > + + + + {/* Currency suffix */} + + {currency_symbol || "KST"} + + + {/* Max value button */} + + + ; +} diff --git a/src/pages/transactions/send/SendTransactionForm.less b/src/pages/transactions/send/SendTransactionForm.less new file mode 100644 index 0000000..95ae29f --- /dev/null +++ b/src/pages/transactions/send/SendTransactionForm.less @@ -0,0 +1,22 @@ +// Copyright (c) 2020-2021 Drew Lemmy +// This file is part of KristWeb 2 under GPL-3.0. +// Full details: https://github.com/tmpim/KristWeb2/blob/master/LICENSE.txt +@import (reference) "../../../App.less"; + +.send-transaction-form { + .ant-input-group-addon { + border: none; + flex: 0; + width: auto; + vertical-align: middle; + line-height: @input-height-base; + height: @input-height-base; + + &.currency-prefix .anticon { + color: @kw-text-tertiary; + font-size: 80%; + vertical-align: middle; + line-height: @input-height-base; + } + } +} diff --git a/src/pages/transactions/send/SendTransactionForm.tsx b/src/pages/transactions/send/SendTransactionForm.tsx index 826eb08..ebc460d 100644 --- a/src/pages/transactions/send/SendTransactionForm.tsx +++ b/src/pages/transactions/send/SendTransactionForm.tsx @@ -1,17 +1,21 @@ // Copyright (c) 2020-2021 Drew Lemmy // This file is part of KristWeb 2 under GPL-3.0. // Full details: https://github.com/tmpim/KristWeb2/blob/master/LICENSE.txt -import React, { useState } from "react"; -import { Form, FormInstance, Input, InputNumber, Button } from "antd"; +import { useState } from "react"; +import { Row, Col, Form, FormInstance, Input } from "antd"; import { useTranslation } from "react-i18next"; import { useWallets } from "@wallets"; -import { useCurrency } from "@utils/currency"; import { AddressPicker } from "@comp/addresses/picker/AddressPicker"; +import { AmountInput } from "./AmountInput"; -import { KristSymbol } from "@comp/krist/KristSymbol"; +import "./SendTransactionForm.less"; + +// This is from https://github.com/tmpim/Krist/blob/a924f3f/src/controllers/transactions.js#L102 +// except `+` is changed to `*`. +const METADATA_REGEXP = /^[\x20-\x7F\n]*$/i; export interface FormValues { from: string; @@ -33,15 +37,12 @@ // Used to get the initial wallet to show for the 'from' field // TODO: Remember this value? - const { addressList, walletAddressMap } = useWallets(); + const { addressList } = useWallets(); const initialFrom = addressList[0] || ""; // TODO: initialFrom here should never be an empty string, so need to add a // modal that says "You currently don't have any saved wallets" etc, // and prevents opening the sendTX modal/rendering the page - // Used to format the 'amount' field - const { currency_symbol } = useCurrency(); - const [from, setFrom] = useState(initialFrom); const [to, setTo] = useState(""); @@ -57,6 +58,7 @@ // `useTransactionForm` hook. form={form} layout="vertical" + className="send-transaction-form" name="sendTransaction" @@ -70,46 +72,49 @@ onValuesChange={onValuesChange} onFinish={triggerSubmit} > - {/* From */} - + + {/* From */} + + + - {/* To */} - + {/* To */} + + + + {/* Amount */} - - - {/* Prepend the Krist symbol if possible. Note that ant's InputNumber - * doesn't support addons, so this has to be done manually. */} - {(currency_symbol || "KST") === "KST" && ( - - )} + form.setFieldsValue({ value })} + /> - {/* Value/amount number input */} - - - - - {/* Max value button */} - - + {/* Metadata */} + + ; }