feat: add month breakdown and session backups
Allow recurring costs and confirmations to remain unassigned when created from a purchase without a post. Add browser backup retention and restore controls, with coverage and documentation updates.
This commit is contained in:
@@ -34,7 +34,7 @@ export function BudgetTree({ monthId, rows, onChangeRule }: { monthId: MonthId;
|
||||
};
|
||||
const billContent = (node: Extract<BudgetNode, { kind: "bill" }>) => <div className="space-y-1 py-3 text-sm">
|
||||
<div className="flex flex-wrap items-baseline justify-between gap-2"><span className="font-medium">{node.cost.name} <span className="ml-2 font-money font-normal">{fmt.money(node.cost.amount.amount, node.cost.amount.currency)}</span></span><Link className="text-xs underline underline-offset-2 hover:text-budget-accent" to={`/settings#bill-${node.cost.id}`}>Edit</Link></div>
|
||||
<p className="text-xs text-budget-ink-muted">{cadence(node.cost.recurrence)} · Assigned to {node.cost.splits.map(split => dataset.posts.find(post => post.id === split.postId)?.name).join(", ")} · {node.nextOccurrence ? `Next ${node.nextOccurrence.date}` : "Ended"}</p>
|
||||
<p className="text-xs text-budget-ink-muted">{cadence(node.cost.recurrence)} · {node.cost.splits.length === 0 ? "Unassigned" : `Assigned to ${node.cost.splits.map(split => dataset.posts.find(post => post.id === split.postId)?.name).join(", ")}`} · {node.nextOccurrence ? `Next ${node.nextOccurrence.date}` : "Ended"}</p>
|
||||
</div>;
|
||||
const purchaseContent = (node: Extract<BudgetNode, { kind: "purchase" }>) => <div className="flex flex-wrap items-center justify-between gap-2 py-3 text-sm"><span>{node.purchase.description} <span className="ml-2 font-money">{fmt.money(node.amount.amount, node.amount.currency)}</span></span><span className="flex items-center gap-3">{node.purchase.splits.length === 0 && <button type="button" aria-label={`Create post for ${node.purchase.description}`} className="text-xs underline underline-offset-2 hover:text-budget-accent" onClick={() => void mutate(draft => createPostForPurchase(draft, node.purchase.id))}>Create post</button>}<PurchaseDialog monthId={monthId} purchase={node.purchase} trigger={<button type="button" className="text-xs underline underline-offset-2 hover:text-budget-accent">Edit</button>} /></span></div>;
|
||||
const render = (nodes: BudgetNode[], mobile: boolean, depth = 0): ReactNode[] => nodes.flatMap(node => {
|
||||
|
||||
Reference in New Issue
Block a user