Files
mymoney/src/components/income/IncomeForm.tsx
2026-06-02 04:02:59 +02:00

133 lines
3.9 KiB
TypeScript

"use client";
import { useEffect, useState } from "react";
import { DateField } from "@/components/shared/DateField";
import { Field, inputClass } from "@/components/shared/Field";
import { Select } from "@/components/shared/Select";
import {
SimpleFormActions,
SimpleFormReview,
SimpleFormStepIndicator,
} from "@/components/shared/SimpleFormSteps";
import { TitleCombobox } from "@/components/shared/TitleCombobox";
import { formatItalianDate, todayIso } from "@/lib/date/formatDate";
import { incomeTypeLabel } from "@/lib/finance/labels";
import {
euroFormatter,
formatMoneyInput,
parseMoneyInput,
} from "@/lib/finance/money";
import type { Income, PaymentTitle } from "@/types/finance";
export function IncomeForm({
titles,
editing,
defaultDate = todayIso(),
onSubmit,
onCreateTitle,
onCancel,
saving = false,
}: {
titles: PaymentTitle[];
editing?: Income;
defaultDate?: string;
onSubmit: (data: object) => Promise<void>;
onCreateTitle?: (name: string) => Promise<void>;
onCancel?: () => void;
saving?: boolean;
}) {
const [review, setReview] = useState(false);
const [title, setTitle] = useState(editing?.title ?? "");
const [amount, setAmount] = useState(formatMoneyInput(editing?.amount));
const [type, setType] = useState(editing?.type ?? "salary");
const [date, setDate] = useState(editing?.date ?? defaultDate);
const [error, setError] = useState("");
useEffect(() => {
setReview(false);
setTitle(editing?.title ?? "");
setAmount(formatMoneyInput(editing?.amount));
setType(editing?.type ?? "salary");
setDate(editing?.date ?? defaultDate);
setError("");
}, [defaultDate, editing]);
function payload() {
if (!title.trim()) throw new Error("Inserisci il titolo dell'entrata");
if (!date) throw new Error("Inserisci la data dell'entrata");
return { title, amount: parseMoneyInput(amount), type, date };
}
return (
<form
onSubmit={async (event) => {
event.preventDefault();
try {
setError("");
const data = payload();
if (!review) {
setReview(true);
return;
}
await onSubmit(data);
} catch (err) {
setError(
err instanceof Error ? err.message : "Salvataggio non riuscito",
);
}
}}
>
<SimpleFormStepIndicator review={review} />
{review ? (
<SimpleFormReview
rows={[
{
label: "Importo",
value: euroFormatter.format(parseMoneyInput(amount)),
},
{ label: "Tipo", value: incomeTypeLabel(type) },
{ label: "Data", value: formatItalianDate(date) },
]}
title={title}
/>
) : (
<div className="grid gap-3 md:grid-cols-4">
<TitleCombobox
titles={titles}
type="income"
value={title}
onChange={setTitle}
onCreate={onCreateTitle}
/>
<Field label="Importo">
<input
className={inputClass}
value={amount}
onChange={(event) => setAmount(event.target.value)}
/>
</Field>
<Select
label="Tipo"
value={type}
onChange={(value) => setType(value as typeof type)}
options={[
{ value: "salary", label: "Stipendio" },
{ value: "recurring", label: "Ricorrente" },
{ value: "one_time", label: "Una tantum" },
{ value: "other", label: "Altro" },
]}
/>
<DateField label="Data" name="date" value={date} onChange={setDate} />
</div>
)}
{error ? <p className="mt-4 text-sm text-rose-300">{error}</p> : null}
<SimpleFormActions
onBack={() => setReview(false)}
onCancel={onCancel}
review={review}
saving={saving}
/>
</form>
);
}