70 lines
2.3 KiB
TypeScript
70 lines
2.3 KiB
TypeScript
import { useMemo, useState } from 'react';
|
|
|
|
import { useAccountSelection } from '../../home/hooks/useAccounts';
|
|
|
|
/**
|
|
* The half of a transfer form that is the same whichever way the money is
|
|
* addressed: which account it leaves, how much, and the note against it.
|
|
*
|
|
* The account list is read from `GET /accounts` on every mount — never from
|
|
* Redux, and never carried in from the previous screen.
|
|
*
|
|
* There is no balance check here, and that is not an omission. No endpoint in
|
|
* the CBS API returns a balance, so the app has nothing to compare an amount
|
|
* against; inventing a limit would be worse than having none, because a
|
|
* customer refused by the app has no way to find out they were refused
|
|
* wrongly. The bank rejects an overdrawn transfer on submission, and that
|
|
* refusal is the authoritative one.
|
|
*/
|
|
export const useTransferForm = () => {
|
|
const { accounts, selectedAccountNumber, setSelectedAccountNumber, selectedAccount, isLoading, refetch } =
|
|
useAccountSelection();
|
|
|
|
const [amount, setAmount] = useState('');
|
|
const [remarks, setRemarks] = useState('');
|
|
|
|
/** Grouping separators are allowed in, but never reach the parsed value. */
|
|
const parsedAmount = useMemo(() => Number.parseFloat(amount.replace(/,/g, '')), [amount]);
|
|
|
|
const amountError = useMemo(() => {
|
|
if (amount.length === 0) {
|
|
return undefined;
|
|
}
|
|
|
|
if (Number.isNaN(parsedAmount) || parsedAmount <= 0) {
|
|
return 'Enter a valid amount';
|
|
}
|
|
|
|
return undefined;
|
|
}, [amount, parsedAmount]);
|
|
|
|
const amountValid = !amountError && parsedAmount > 0;
|
|
|
|
const handleAmountChange = (value: string) => {
|
|
// One decimal point, digits either side, at most two paise. Filtering on
|
|
// the way in beats validating after the fact: the field cannot hold
|
|
// something the parser would then have to reject.
|
|
const cleaned = value.replace(/[^0-9.]/g, '');
|
|
const [rupees = '', ...rest] = cleaned.split('.');
|
|
const paise = rest.join('').slice(0, 2);
|
|
|
|
setAmount(rest.length ? `${rupees}.${paise}` : rupees);
|
|
};
|
|
|
|
return {
|
|
accounts,
|
|
selectedAccount,
|
|
sourceAccountNumber: selectedAccountNumber,
|
|
setSourceAccountNumber: setSelectedAccountNumber,
|
|
accountsLoading: isLoading,
|
|
refetchAccounts: refetch,
|
|
amount,
|
|
handleAmountChange,
|
|
parsedAmount,
|
|
amountError,
|
|
amountValid,
|
|
remarks,
|
|
setRemarks,
|
|
};
|
|
};
|