221 lines
7.5 KiB
TypeScript
221 lines
7.5 KiB
TypeScript
import { Input } from '@/components/ui/input';
|
|
import { Label } from '@/components/ui/label';
|
|
import {
|
|
Select,
|
|
SelectContent,
|
|
SelectItem,
|
|
SelectTrigger,
|
|
SelectValue,
|
|
} from '@/components/ui/select';
|
|
import {
|
|
ACCOUNT_TYPES,
|
|
CURRENCY_OPTIONS,
|
|
formatAccountType,
|
|
type AccountType,
|
|
type Bank,
|
|
type CurrencyCode,
|
|
} from '@/types/account';
|
|
import { __ } from '@/utils/i18n';
|
|
import { useCallback, useEffect, useState } from 'react';
|
|
import { BankCombobox } from './bank-combobox';
|
|
import { CustomBankData, CustomBankForm } from './custom-bank-form';
|
|
|
|
export interface AccountFormData {
|
|
displayName: string;
|
|
bankId: number | null;
|
|
type: AccountType | null;
|
|
currencyCode: CurrencyCode | null;
|
|
customBank: CustomBankData | null;
|
|
}
|
|
|
|
interface AccountFormProps {
|
|
initialValues?: {
|
|
displayName: string;
|
|
bank: Bank;
|
|
type: AccountType;
|
|
currencyCode: CurrencyCode;
|
|
};
|
|
forceAccountType?: AccountType;
|
|
onChange: (data: AccountFormData) => void;
|
|
}
|
|
|
|
const initialCustomBankData: CustomBankData = {
|
|
name: '',
|
|
logo: null,
|
|
logoPreview: null,
|
|
};
|
|
|
|
export function AccountForm({
|
|
initialValues,
|
|
forceAccountType,
|
|
onChange,
|
|
}: AccountFormProps) {
|
|
const [displayName, setDisplayName] = useState(
|
|
initialValues?.displayName ?? '',
|
|
);
|
|
const [selectedBankId, setSelectedBankId] = useState<number | null>(
|
|
initialValues?.bank.id ?? null,
|
|
);
|
|
const [selectedType, setSelectedType] = useState<AccountType | null>(
|
|
initialValues?.type ?? forceAccountType ?? null,
|
|
);
|
|
const [selectedCurrency, setSelectedCurrency] =
|
|
useState<CurrencyCode | null>(initialValues?.currencyCode ?? null);
|
|
const [isCreatingCustomBank, setIsCreatingCustomBank] = useState(false);
|
|
const [customBankData, setCustomBankData] = useState<CustomBankData>(
|
|
initialCustomBankData,
|
|
);
|
|
|
|
useEffect(() => {
|
|
onChange({
|
|
displayName,
|
|
bankId: isCreatingCustomBank ? null : selectedBankId,
|
|
type: selectedType,
|
|
currencyCode: selectedCurrency,
|
|
customBank: isCreatingCustomBank ? customBankData : null,
|
|
});
|
|
}, [
|
|
displayName,
|
|
selectedBankId,
|
|
selectedType,
|
|
selectedCurrency,
|
|
isCreatingCustomBank,
|
|
customBankData,
|
|
onChange,
|
|
]);
|
|
|
|
useEffect(() => {
|
|
if (initialValues) {
|
|
setDisplayName(initialValues.displayName);
|
|
setSelectedBankId(initialValues.bank.id);
|
|
setSelectedType(initialValues.type);
|
|
setSelectedCurrency(initialValues.currencyCode);
|
|
setIsCreatingCustomBank(false);
|
|
setCustomBankData(initialCustomBankData);
|
|
}
|
|
}, [initialValues]);
|
|
|
|
const handleCreateCustomBank = useCallback((searchQuery: string) => {
|
|
setIsCreatingCustomBank(true);
|
|
setCustomBankData({
|
|
name: searchQuery,
|
|
logo: null,
|
|
logoPreview: null,
|
|
});
|
|
setSelectedBankId(null);
|
|
}, []);
|
|
|
|
const handleCancelCustomBank = useCallback(() => {
|
|
setIsCreatingCustomBank(false);
|
|
setCustomBankData(initialCustomBankData);
|
|
}, []);
|
|
|
|
return (
|
|
<>
|
|
<div className="space-y-2">
|
|
<Label htmlFor="display_name">{__('Name')}</Label>
|
|
<Input
|
|
id="display_name"
|
|
className="mt-1"
|
|
name="display_name"
|
|
value={displayName}
|
|
onChange={(e) => setDisplayName(e.target.value)}
|
|
placeholder={__('Account name')}
|
|
required
|
|
/>
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<Label htmlFor="bank_id">{__('Bank')}</Label>
|
|
<div className="mt-1">
|
|
{isCreatingCustomBank ? (
|
|
<CustomBankForm
|
|
defaultName={customBankData.name}
|
|
value={customBankData}
|
|
onChange={setCustomBankData}
|
|
onCancel={handleCancelCustomBank}
|
|
/>
|
|
) : (
|
|
<>
|
|
<input
|
|
type="hidden"
|
|
name="bank_id"
|
|
value={selectedBankId ?? ''}
|
|
required
|
|
/>
|
|
|
|
<BankCombobox
|
|
value={selectedBankId}
|
|
onValueChange={setSelectedBankId}
|
|
defaultBank={initialValues?.bank}
|
|
onCreateCustomBank={handleCreateCustomBank}
|
|
/>
|
|
</>
|
|
)}
|
|
</div>
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<Label htmlFor="type">{__('Account Type')}</Label>
|
|
<div className="mt-1">
|
|
<Select
|
|
name="type"
|
|
value={selectedType ?? undefined}
|
|
disabled={!!forceAccountType}
|
|
onValueChange={(value) =>
|
|
setSelectedType(value as AccountType)
|
|
}
|
|
required
|
|
>
|
|
<SelectTrigger name="type">
|
|
<SelectValue
|
|
placeholder={__('Select account type')}
|
|
/>
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
{ACCOUNT_TYPES.map((type) => (
|
|
<SelectItem key={type} value={type}>
|
|
{formatAccountType(type)}
|
|
</SelectItem>
|
|
))}
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
{(selectedType === 'investment' ||
|
|
selectedType === 'retirement') && (
|
|
<p className="pl-1 text-xs text-muted-foreground">
|
|
{__(
|
|
"This account type is for balance tracking only and\n doesn't support transactions.",
|
|
)}
|
|
</p>
|
|
)}
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<Label htmlFor="currency_code">{__('Currency')}</Label>
|
|
<div className="mt-1">
|
|
<Select
|
|
name="currency_code"
|
|
value={selectedCurrency ?? undefined}
|
|
onValueChange={(value) =>
|
|
setSelectedCurrency(value as CurrencyCode)
|
|
}
|
|
required
|
|
>
|
|
<SelectTrigger name="currency_code">
|
|
<SelectValue placeholder={__('Select currency')} />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
{CURRENCY_OPTIONS.map((currency) => (
|
|
<SelectItem key={currency} value={currency}>
|
|
{currency}
|
|
</SelectItem>
|
|
))}
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
</div>
|
|
</>
|
|
);
|
|
}
|