diff --git a/src/ui/components/PlanEditor.tsx b/src/ui/components/PlanEditor.tsx new file mode 100644 index 0000000..9ef729d --- /dev/null +++ b/src/ui/components/PlanEditor.tsx @@ -0,0 +1,86 @@ +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { formatAmount } from "../format.ts"; +import { + planBalance, + setSliceAmount, + withPlan, + withoutPlan, + type PurchaseDraft, +} from "../purchaseForm.ts"; +import { monthOf } from "../../domain/months.ts"; + +interface Props { + draft: PurchaseDraft; + onChange: (next: PurchaseDraft) => void; +} + +export function PlanEditor({ draft, onChange }: Props) { + const balance = planBalance(draft); + + if (!draft.plan) { + return ( + + ); + } + + return ( +
+
+ +
+ months + { + const months = Number(event.target.value); + if (months >= 1) { + onChange(withPlan(draft, draft.plan!.startMonth, months)); + } + }} + /> + +
+
+ +
+ {draft.plan.slices.map((slice, index) => ( +
+ {slice.month} + + onChange(setSliceAmount(draft, index, Number(event.target.value) || 0)) + } + /> + {draft.currency} +
+ ))} +
+ +

+ {balance === 0 + ? `Slices total ${formatAmount(draft.amount)} ${draft.currency}, matching the purchase.` + : `Slices are ${formatAmount(Math.abs(balance))} ${draft.currency} ${ + balance > 0 ? "short of" : "over" + } the purchase total.`} +

+
+ ); +} diff --git a/src/ui/components/PurchaseDialog.tsx b/src/ui/components/PurchaseDialog.tsx index ad8e105..8456555 100644 --- a/src/ui/components/PurchaseDialog.tsx +++ b/src/ui/components/PurchaseDialog.tsx @@ -11,6 +11,7 @@ import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { SplitEditor } from "./SplitEditor.tsx"; +import { PlanEditor } from "./PlanEditor.tsx"; import { emptyDraft, fromPurchase, @@ -20,7 +21,7 @@ import { } from "../purchaseForm.ts"; import { useDataset } from "../hooks/useDataset.ts"; import { useMutate } from "../hooks/useMutate.ts"; -import { addPurchase, updatePurchase } from "../../store/actions.ts"; +import { addPurchase, cancelScheduleFrom, updatePurchase } from "../../store/actions.ts"; import { CURRENCIES, type MonthId, type Purchase } from "../../domain/types.ts"; interface Props { @@ -128,6 +129,22 @@ export function PurchaseDialog({ monthId, purchase, trigger }: Props) { + + + {purchase?.schedule && !purchase.schedule.cancelledFromMonth && ( + + )} + {errors.length > 0 && (