@bazous/ui 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +150 -0
- package/dist/answers/AnswerPicture.d.ts +13 -0
- package/dist/answers/contract.d.ts +160 -0
- package/dist/answers/draw.d.ts +16 -0
- package/dist/answers/index.d.ts +6 -0
- package/dist/answers/messages.d.ts +3 -0
- package/dist/answers.js +10 -0
- package/dist/answers.js.map +1 -0
- package/dist/canvas/index.d.ts +32 -0
- package/dist/canvas.js +285 -0
- package/dist/canvas.js.map +1 -0
- package/dist/contract/snapshot.d.ts +173 -0
- package/dist/engine/scenario.d.ts +40 -0
- package/dist/format/index.d.ts +37 -0
- package/dist/i18n/index.d.ts +25 -0
- package/dist/i18n/shared.d.ts +3 -0
- package/dist/index-yeBMtDf1.js +649 -0
- package/dist/index-yeBMtDf1.js.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.js +1258 -0
- package/dist/index.js.map +1 -0
- package/dist/modules/Question.d.ts +18 -0
- package/dist/modules/available-now/index.d.ts +8 -0
- package/dist/modules/due-before-payday/index.d.ts +9 -0
- package/dist/modules/low-point/index.d.ts +12 -0
- package/dist/modules/margin-after-payday/index.d.ts +9 -0
- package/dist/modules/monthly-structure/index.d.ts +24 -0
- package/dist/modules/next-actions/index.d.ts +13 -0
- package/dist/modules/pay-cycles/index.d.ts +31 -0
- package/dist/modules/registry.d.ts +7 -0
- package/dist/modules/types.d.ts +77 -0
- package/dist/modules/what-if/index.d.ts +6 -0
- package/dist/primitives/CashflowChart.d.ts +22 -0
- package/dist/primitives/index.d.ts +57 -0
- package/dist/styles.css +1 -0
- package/package.json +84 -0
- package/schema/answers.schema.json +719 -0
- package/schema/canvas.json +181 -0
- package/schema/snapshot.schema.json +821 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/i18n/shared.ts","../src/primitives/index.tsx","../src/primitives/CashflowChart.tsx","../src/engine/scenario.ts","../src/modules/types.ts","../src/modules/available-now/index.tsx","../src/modules/due-before-payday/index.tsx","../src/modules/low-point/index.tsx","../src/modules/margin-after-payday/index.tsx","../src/modules/monthly-structure/index.tsx","../src/modules/next-actions/index.tsx","../src/modules/pay-cycles/index.tsx","../src/modules/what-if/index.tsx","../src/modules/registry.ts","../src/modules/Question.tsx","../src/answers/AnswerPicture.tsx"],"sourcesContent":["import type { Catalog } from \"./index\";\n\n/** Words every module may use. Module catalogs can override a key for their own wording. */\nexport const shared: Catalog = {\n fr: {\n brand: \"Bazous\",\n sample: \"APERÇU · DONNÉES FICTIVES\",\n notEnough: \"Pas encore assez de données pour répondre.\",\n today: \"Aujourd’hui\",\n payday: \"Salaire {date}\",\n \"inDays.one\": \"Dans {n} jour\",\n \"inDays.other\": \"Dans {n} jours\",\n equivalent: \"{cur} équivalent\",\n theme: \"Thème\",\n themeDark: \"Sombre\",\n themeLight: \"Clair\",\n language: \"Langue\",\n },\n de: {\n brand: \"Bazous\",\n sample: \"VORSCHAU · FIKTIVE DATEN\",\n notEnough: \"Noch nicht genug Daten für eine Antwort.\",\n today: \"Heute\",\n payday: \"Lohn {date}\",\n \"inDays.one\": \"In {n} Tag\",\n \"inDays.other\": \"In {n} Tagen\",\n equivalent: \"{cur}-Gegenwert\",\n theme: \"Darstellung\",\n themeDark: \"Dunkel\",\n themeLight: \"Hell\",\n language: \"Sprache\",\n },\n it: {\n brand: \"Bazous\",\n sample: \"ANTEPRIMA · DATI FITTIZI\",\n notEnough: \"Dati non ancora sufficienti per rispondere.\",\n today: \"Oggi\",\n payday: \"Stipendio {date}\",\n \"inDays.one\": \"Tra {n} giorno\",\n \"inDays.other\": \"Tra {n} giorni\",\n equivalent: \"equivalente {cur}\",\n theme: \"Tema\",\n themeDark: \"Scuro\",\n themeLight: \"Chiaro\",\n language: \"Lingua\",\n },\n rm: {\n brand: \"Bazous\",\n sample: \"PREVISTA · DATAS FICTIVAS\",\n notEnough: \"Anc betg avunda datas per respunder.\",\n today: \"Oz\",\n payday: \"Salari {date}\",\n \"inDays.one\": \"En {n} di\",\n \"inDays.other\": \"En {n} dis\",\n equivalent: \"equivalent {cur}\",\n theme: \"Design\",\n themeDark: \"Stgir\",\n themeLight: \"Cler\",\n language: \"Lingua\",\n },\n en: {\n brand: \"Bazous\",\n sample: \"PREVIEW · SAMPLE DATA\",\n notEnough: \"Not enough data to answer yet.\",\n today: \"Today\",\n payday: \"Payday {date}\",\n \"inDays.one\": \"In {n} day\",\n \"inDays.other\": \"In {n} days\",\n equivalent: \"{cur} equivalent\",\n theme: \"Theme\",\n themeDark: \"Dark\",\n themeLight: \"Light\",\n language: \"Language\",\n },\n};\n","import type { ReactNode } from \"react\";\n\nimport type { Tone } from \"../format\";\n\n/**\n * Primitives: the only markup modules are expected to use. Every class starts\n * with `bz-` so the kit never collides with the host application's styles.\n */\n\nexport function Card({ question, title, meta, actions, children, className }: {\n /** The money question, shown small above the title. */\n question?: string;\n title?: ReactNode;\n meta?: ReactNode;\n actions?: ReactNode;\n children: ReactNode;\n className?: string;\n}) {\n return (\n <article className={`bz-card${className ? ` ${className}` : \"\"}`}>\n {(question || title || meta || actions) && (\n <header className=\"bz-card-head\">\n <div className=\"bz-card-titles\">\n {question && <p className=\"bz-question\">{question}</p>}\n {title && <h2 className=\"bz-title\">{title}</h2>}\n </div>\n {meta && <span className=\"bz-meta\">{meta}</span>}\n {actions && <div className=\"bz-card-actions\">{actions}</div>}\n </header>\n )}\n {children}\n </article>\n );\n}\n\nexport function Tile({ question, label, value, unit, note, tone, emphasis }: {\n question: string;\n label: string;\n value: string;\n unit: string;\n note?: ReactNode;\n tone?: Tone;\n /** The one number that matters most on the page (the low point): drawn in gold. */\n emphasis?: boolean;\n}) {\n return (\n <article className={`bz-tile${emphasis ? \" bz-tile-emphasis\" : \"\"}`} aria-label={question}>\n <p className=\"bz-eyebrow\">{label}</p>\n <p className={`bz-tile-value${tone ? ` bz-${tone}` : \"\"}`}>\n {value} <span className=\"bz-unit\">{unit}</span>\n </p>\n {note && <p className=\"bz-note\">{note}</p>}\n </article>\n );\n}\n\nexport function Row({ date, title, sub, amount, amountTone, late, children }: {\n date?: string;\n title: ReactNode;\n sub?: ReactNode;\n amount?: ReactNode;\n amountTone?: Tone;\n late?: boolean;\n children?: ReactNode;\n}) {\n return (\n <div className={`bz-row${late ? \" bz-late\" : \"\"}`}>\n {date !== undefined && <span className=\"bz-date\">{date}</span>}\n <div className=\"bz-row-body\">\n <strong>{title}</strong>\n {sub && <span>{sub}</span>}\n </div>\n {amount !== undefined && <strong className={`bz-amount${amountTone ? ` bz-${amountTone}` : \"\"}`}>{amount}</strong>}\n {children}\n </div>\n );\n}\n\nexport function Button({ children, onClick, variant = \"secondary\", disabled }: {\n children: ReactNode;\n onClick: () => void;\n variant?: \"primary\" | \"secondary\" | \"ghost\" | \"link\";\n disabled?: boolean;\n}) {\n return (\n <button type=\"button\" className={`bz-button bz-${variant}`} onClick={onClick} disabled={disabled}>\n {children}\n </button>\n );\n}\n\nexport function Segmented<K extends string>({ options, value, onChange, label }: {\n options: { key: K; label: string }[];\n value: K;\n onChange: (key: K) => void;\n label: string;\n}) {\n return (\n <div className=\"bz-seg\" role=\"group\" aria-label={label}>\n {options.map((o) => (\n <button type=\"button\" key={o.key} className={o.key === value ? \"bz-on\" : \"\"} aria-pressed={o.key === value} onClick={() => onChange(o.key)}>\n {o.label}\n </button>\n ))}\n </div>\n );\n}\n\nexport function Dot({ tone }: { tone: \"danger\" | \"warn\" | \"muted\" }) {\n return <i className={`bz-dot bz-dot-${tone}`} aria-hidden=\"true\" />;\n}\n\nexport function Empty({ children }: { children: ReactNode }) {\n return <p className=\"bz-empty\">{children}</p>;\n}\n\n/** Proportional bars (drivers, categories) in the kit's four ink shades. */\nexport const SHADES = [\"bz-shade-1\", \"bz-shade-2\", \"bz-shade-3\", \"bz-shade-4\"] as const;\n","import { useEffect, useRef, useState } from \"react\";\n\nimport type { IsoDate } from \"../contract/snapshot\";\nimport type { SeriesPoint, Series } from \"../engine/scenario\";\nimport { num, shortDate } from \"../format\";\n\nexport type ChartLabels = {\n today: string;\n payday: (date: string) => string;\n aria: string;\n};\n\ntype Props = {\n base: Series;\n scenario?: Series | null;\n today: IsoDate;\n incomes: IsoDate[];\n markers: { date: IsoDate; label: string }[];\n labels: ChartLabels;\n};\n\n// The drawing is laid out at the container's real width, so 11 px labels stay 11 px on a phone.\nconst DEFAULT_W = 880;\nconst PAD = { left: 52, right: 10, top: 40, bottom: 34 };\n\nexport function CashflowChart(props: Props) {\n const ref = useRef<HTMLDivElement>(null);\n const [width, setWidth] = useState(DEFAULT_W);\n useEffect(() => {\n const el = ref.current;\n if (!el || typeof ResizeObserver === \"undefined\") return;\n const observer = new ResizeObserver(([entry]) => {\n const w = Math.round(entry?.contentRect.width ?? DEFAULT_W);\n if (w > 0) setWidth(Math.max(300, w));\n });\n observer.observe(el);\n return () => observer.disconnect();\n }, []);\n return (\n <div ref={ref} className=\"bz-chart-box\">\n <Drawing {...props} W={width} />\n </div>\n );\n}\n\nfunction Drawing({ base, scenario, today, incomes, markers, labels, W }: Props & { W: number }) {\n const H = W < 560 ? 260 : 330;\n const compact = W < 560;\n const all = [...base.points, ...(scenario?.points ?? [])].flatMap((p) => (p.peak === undefined ? [p.balance] : [p.balance, p.peak]));\n const n = base.points.length;\n if (n === 0) return null;\n const ticks = niceTicks(Math.min(0, ...all), Math.max(0, ...all), 4);\n const min = ticks[0] ?? 0;\n const max = ticks[ticks.length - 1] ?? 1;\n const x = (i: number) => PAD.left + (i / Math.max(n - 1, 1)) * (W - PAD.left - PAD.right);\n const y = (v: number) => PAD.top + ((max - v) / (max - min || 1)) * (H - PAD.top - PAD.bottom);\n const idx = (date: IsoDate) => base.points.findIndex((p) => p.date === date);\n const balanceOn = (date: IsoDate) => base.points[idx(date)]?.balance ?? 0;\n const zeroY = y(0);\n const bottom = H - PAD.bottom;\n const lowI = idx(base.low.date);\n const lowX = x(lowI);\n\n const axis: { i: number; anchor: \"start\" | \"middle\" | \"end\" }[] = Math.abs(lowX - x(0)) > (compact ? 110 : 70) ? [{ i: 0, anchor: \"start\" }] : [];\n for (const m of markers) {\n const i = idx(m.date);\n if (!compact && i > 0 && i < n - 1 && axis.every((a) => Math.abs(x(a.i) - x(i)) > 60) && Math.abs(x(i) - lowX) > 70) axis.push({ i, anchor: \"middle\" });\n }\n if (Math.abs(x(n - 1) - lowX) > (compact ? 110 : 70)) axis.push({ i: n - 1, anchor: \"end\" });\n // \"Aujourd'hui\" moves up one line when a payday label sits right next to it.\n const todayX = x(idx(today));\n const crowded = incomes.some((d) => idx(d) >= 0 && Math.abs(x(idx(d)) - todayX) < 90);\n const first = base.points[0];\n const last = base.points[n - 1];\n\n return (\n <svg className=\"bz-chart\" viewBox={`0 0 ${W} ${H}`} role=\"img\" aria-label={labels.aria}>\n {zeroY < bottom && <rect x={PAD.left} y={zeroY} width={W - PAD.left - PAD.right} height={bottom - zeroY} className=\"bz-chart-danger\" />}\n {ticks.map((t) => (\n <g key={t}>\n <line x1={PAD.left} x2={W - PAD.right} y1={y(t)} y2={y(t)} className={t === 0 ? \"bz-chart-zero\" : \"bz-chart-grid\"} />\n <text x={PAD.left - 8} y={y(t) + 4} textAnchor=\"end\" className={t === 0 ? \"bz-chart-tick bz-strong\" : \"bz-chart-tick\"}>{num(t)}</text>\n </g>\n ))}\n {incomes.map((d) => {\n if (idx(d) < 0) return null;\n // On a phone the two payday captions would touch: the dashed green line already says \"payday\".\n const text = compact ? shortDate(d) : labels.payday(shortDate(d));\n const flip = x(idx(d)) + text.length * 6.5 > W - PAD.right;\n return (\n <g key={d}>\n <line x1={x(idx(d))} x2={x(idx(d))} y1={PAD.top} y2={bottom} className=\"bz-chart-income\" />\n {/* ~6.5 px per character at 11 px: flip the label left of its line near the right edge. */}\n <text x={x(idx(d)) + (flip ? -4 : 4)} y={PAD.top - 10} textAnchor={flip ? \"end\" : \"start\"} className=\"bz-chart-label bz-income\">\n {text}\n </text>\n </g>\n );\n })}\n {idx(today) >= 0 && (\n <g>\n <line x1={todayX} x2={todayX} y1={PAD.top} y2={bottom} className=\"bz-chart-today\" />\n <text x={todayX + 4} y={crowded ? PAD.top - 26 : PAD.top - 10} className=\"bz-chart-label bz-today\">{labels.today}</text>\n </g>\n )}\n {scenario && <polyline points={polyline(scenario.points, x, y)} className=\"bz-chart-scenario\" />}\n <polyline points={polyline(base.points, x, y)} className=\"bz-chart-base\" />\n {markers.map((m) => idx(m.date) >= 0 && (\n <g key={`${m.date}-${m.label}`}>\n <circle cx={x(idx(m.date))} cy={y(balanceOn(m.date))} r=\"5\" className=\"bz-chart-dot\" />\n {!compact && <text x={x(idx(m.date)) + 10} y={y(balanceOn(m.date)) + 4} className=\"bz-chart-label\">{m.label}</text>}\n </g>\n ))}\n {lowI >= 0 && (\n <g>\n <circle cx={lowX} cy={y(base.low.balance)} r=\"7\" className=\"bz-chart-low\" />\n <text x={lowX} y={H - 8} textAnchor={lowX > W - 60 ? \"end\" : \"middle\"} className=\"bz-chart-label bz-low\">\n {shortDate(base.low.date)} · {num(base.low.balance)}\n </text>\n </g>\n )}\n {axis.map((a) => {\n const p = a.i === 0 ? first : a.i === n - 1 ? last : base.points[a.i];\n return p ? <text key={a.i} x={x(a.i)} y={H - 8} textAnchor={a.anchor} className=\"bz-chart-tick\">{shortDate(p.date)}</text> : null;\n })}\n </svg>\n );\n}\n\n/** One vertex per movement; a pay day that also pays bills shows its peak. */\nfunction polyline(points: SeriesPoint[], x: (i: number) => number, y: (v: number) => number): string {\n const out: string[] = [];\n let prev: number | null = null;\n points.forEach((p, i) => {\n if (prev === null || p.balance !== prev || p.peak !== undefined || i === points.length - 1) {\n if (p.peak !== undefined) out.push(`${x(i).toFixed(1)},${y(p.peak).toFixed(1)}`);\n out.push(`${x(i).toFixed(1)},${y(p.balance).toFixed(1)}`);\n }\n prev = p.balance;\n });\n return out.join(\" \");\n}\n\n/** Round ticks that always include 0 and enclose the data (8’000 / 4’000 / 0 / −4’000). */\nexport function niceTicks(min: number, max: number, count: number): number[] {\n const raw = (max - min) / Math.max(count, 1) || 1;\n const mag = 10 ** Math.floor(Math.log10(raw));\n const step = [1, 2, 2.5, 5, 10].map((m) => m * mag).find((s) => s >= raw) ?? mag * 10;\n const lo = Math.floor(min / step) * step;\n const hi = Math.ceil(max / step) * step;\n const ticks: number[] = [];\n for (let v = lo; v <= hi + step / 2; v += step) ticks.push(Math.round(v));\n if (ticks.length < 2) ticks.push(Math.round(lo + step));\n return ticks;\n}\n","import type { CashEvent, IsoDate, Snapshot } from \"../contract/snapshot\";\nimport { toNumber } from \"../contract/snapshot\";\nimport { addDays, daysBetween } from \"../format\";\n\n/**\n * What-if levers, replayed on the engine's own events.\n *\n * This is the one calculation the kit does: it re-sums the snapshot's events day by\n * day after moving some of them. It does not invent events, amounts or dates beyond\n * the lever's target, and with no lever active it reproduces the engine's curve exactly.\n */\n\nexport type LeverKind = \"split\" | \"defer\" | \"reserve\";\n\nexport type Lever = {\n id: string;\n kind: LeverKind;\n event: CashEvent;\n /** Where the moved money lands: the income after the main cycle. */\n target: IsoDate;\n /** For `reserve`: the cushion kept after the next income. */\n reserve?: number;\n};\n\nexport type SeriesPoint = {\n date: IsoDate;\n balance: number;\n /** Set on days that both receive and pay: balance right after the income. */\n peak?: number;\n};\n\nexport type Series = {\n points: SeriesPoint[];\n low: { date: IsoDate; balance: number; daysFromNow: number };\n end: { date: IsoDate; balance: number };\n};\n\nexport function buildLevers(snapshot: Snapshot): Lever[] {\n const target = snapshot.second_income_date ?? addDays(snapshot.as_of, 30);\n const { start, end } = snapshot.main_cycle;\n const candidates = snapshot.events\n .filter((e) => e.direction === \"outflow\" && e.date >= start && e.date <= end)\n .sort((a, b) => toNumber(b.amount) - toNumber(a.amount))\n .slice(0, 2);\n const levers: Lever[] = [];\n const [top, second] = candidates;\n if (top) levers.push({ id: `split:${top.ref_id ?? top.label}`, kind: \"split\", event: top, target });\n if (second) levers.push({ id: `defer:${second.ref_id ?? second.label}`, kind: \"defer\", event: second, target });\n if (snapshot.next_income_date) {\n const income = snapshot.events.find((e) => e.direction === \"inflow\" && e.date === snapshot.next_income_date);\n if (income) {\n const reserve = Math.round((toNumber(income.amount) * 0.4) / 500) * 500;\n if (reserve > 0) levers.push({ id: `reserve:${snapshot.next_income_date}`, kind: \"reserve\", event: income, target, reserve });\n }\n }\n return levers;\n}\n\nexport function computeSeries(snapshot: Snapshot, active: ReadonlySet<string>, levers: readonly Lever[]): Series {\n const moved: { date: IsoDate; amount: number }[] = [];\n const on = levers.filter((l) => active.has(l.id));\n const byRef = new Map(on.filter((l) => l.kind !== \"reserve\").map((l) => [l.event.ref_id ?? l.event.label, l]));\n const reserve = on.find((l) => l.kind === \"reserve\");\n\n for (const e of snapshot.events) {\n const amount = toNumber(e.amount) * (e.direction === \"inflow\" ? 1 : -1);\n const lever = byRef.get(e.ref_id ?? e.label);\n if (!lever) moved.push({ date: e.date, amount });\n else if (lever.kind === \"defer\") moved.push({ date: lever.target, amount });\n else {\n moved.push({ date: e.date, amount: amount / 2 });\n moved.push({ date: lever.target, amount: amount / 2 });\n }\n }\n\n if (reserve?.reserve && snapshot.next_income_date) {\n // Keep `reserve` after the next income: bills in that cycle that would dig into it\n // wait for the following income.\n const start = snapshot.next_income_date;\n const end = snapshot.second_income_date ?? snapshot.horizon_end;\n let bank = toNumber(snapshot.opening_balance);\n const sorted = [...moved].sort((a, b) => a.date.localeCompare(b.date) || b.amount - a.amount);\n moved.length = 0;\n for (const m of sorted) {\n if (m.date >= start && m.date < end && m.amount < 0 && bank + m.amount < reserve.reserve) {\n moved.push({ date: end, amount: m.amount });\n continue;\n }\n bank += m.amount;\n moved.push(m);\n }\n }\n\n const perDay = new Map<IsoDate, { inflow: number; outflow: number }>();\n for (const m of moved) {\n if (m.date < snapshot.as_of || m.date > snapshot.horizon_end) continue;\n const d = perDay.get(m.date) ?? { inflow: 0, outflow: 0 };\n if (m.amount >= 0) d.inflow += m.amount;\n else d.outflow += m.amount;\n perDay.set(m.date, d);\n }\n\n let balance = toNumber(snapshot.opening_balance);\n let low = { date: snapshot.as_of, balance, daysFromNow: 0 };\n const points: SeriesPoint[] = [];\n const days = daysBetween(snapshot.as_of, snapshot.horizon_end);\n for (let i = 0; i <= days; i++) {\n const date = addDays(snapshot.as_of, i);\n const d = perDay.get(date);\n const peak = d && d.inflow > 0 && d.outflow < 0 ? balance + d.inflow : undefined;\n balance = round2(balance + (d ? d.inflow + d.outflow : 0));\n if (balance < low.balance) low = { date, balance, daysFromNow: i };\n points.push(peak === undefined ? { date, balance } : { date, balance, peak: round2(peak) });\n }\n return { points, low, end: { date: snapshot.horizon_end, balance } };\n}\n\n/** The engine's own curve, read from `points` (no replay). */\nexport function baseSeries(snapshot: Snapshot): Series {\n let prev = toNumber(snapshot.opening_balance);\n const points: SeriesPoint[] = snapshot.points.map((p) => {\n const inflow = toNumber(p.inflows);\n const outflow = toNumber(p.outflows);\n const balance = toNumber(p.closing_balance);\n const point: SeriesPoint = inflow > 0 && outflow > 0 ? { date: p.date, balance, peak: round2(prev + inflow) } : { date: p.date, balance };\n prev = balance;\n return point;\n });\n const last = points[points.length - 1];\n return {\n points,\n low: { date: snapshot.low_point.date, balance: toNumber(snapshot.low_point.balance), daysFromNow: snapshot.low_point.days_from_now },\n end: { date: snapshot.end_of_horizon.date, balance: last ? last.balance : toNumber(snapshot.end_of_horizon.balance) },\n };\n}\n\nconst round2 = (v: number) => Math.round(v * 100) / 100;\n","import type { ComponentType } from \"react\";\n\nimport type { Decimal, IsoDate, Snapshot } from \"../contract/snapshot\";\nimport type { Formatters } from \"../format\";\nimport type { Catalog, Locale, Translate } from \"../i18n\";\n\n/**\n * What a module may ask the host to do. Modules never call the network: they emit\n * an intent, the app executes it with the user's credentials and sends a fresh snapshot.\n */\nexport type ModuleAction =\n | { type: \"mark_paid\"; ref_id: string }\n | { type: \"reschedule\"; ref_id: string; date: IsoDate }\n | { type: \"classify_transaction\"; ref_id: string; internal_transfer: boolean }\n | { type: \"review_obligation\"; ref_id: string; decision: \"accept\" | \"cancel\" }\n | { type: \"open\"; target: \"recurrences\" | \"balances\" | \"import\" | \"capture\" | \"obligations\" }\n | { type: \"set_horizon\"; horizon: Horizon }\n | {\n type: \"save_scenario\";\n name: string;\n levers: { id: string; kind: \"split\" | \"defer\" | \"reserve\"; label: string; ref_id: string | null; target: IsoDate; amount: Decimal }[];\n low_before: Decimal;\n low_after: Decimal;\n };\n\nexport type Horizon = \"7\" | \"30\" | \"cycles\" | \"90\";\n\n/** Where a module sits in the page grid. */\nexport type ModuleSize = \"tile\" | \"narrow\" | \"wide\" | \"full\";\n\nexport type ModuleContext = {\n locale: Locale;\n /** Horizon the snapshot was computed for (the host refetches when it changes). */\n horizon: Horizon;\n};\n\nexport type ViewProps<Model> = {\n model: Model;\n t: Translate;\n fmt: Formatters;\n ctx: ModuleContext;\n onAction: (action: ModuleAction) => void;\n};\n\nexport type QuestionModule<Model = unknown> = {\n /** Stable kebab-case id: it is part of the public API. */\n id: string;\n /** The money question this module answers, in the five languages. */\n question: Record<Locale, string>;\n size: ModuleSize;\n /** Contract fields the module reads; the host can check them before rendering. */\n reads: readonly (keyof Snapshot)[];\n messages: Catalog;\n /**\n * Pure and deterministic: same snapshot, same model. Returns `null` when the\n * snapshot does not contain enough to answer (the host shows an empty state).\n * It selects and shapes numbers the engine already computed; it never forecasts.\n */\n select: (snapshot: Snapshot, ctx: ModuleContext) => Model | null;\n View: ComponentType<ViewProps<Model>>;\n};\n\n/** Identity helper that keeps the Model type flowing from `select` to `View`. */\nexport function defineModule<Model>(module: QuestionModule<Model>): QuestionModule<Model> {\n return module;\n}\n","import { toNumber } from \"../../contract/snapshot\";\nimport { Tile } from \"../../primitives\";\nimport { defineModule } from \"../types\";\n\nconst LIQUID = new Set([\"bank\", \"prepaid\", \"cash\"]);\n\ntype Model = { amount: string; currency: string; known: string[]; missing: number };\n\nexport default defineModule<Model>({\n id: \"available-now\",\n size: \"tile\",\n question: {\n fr: \"Combien ai-je maintenant ?\",\n de: \"Wie viel habe ich jetzt?\",\n it: \"Quanto ho adesso?\",\n rm: \"Quant hai jau ussa?\",\n en: \"How much do I have now?\",\n },\n reads: [\"opening_balance\", \"base_currency\", \"accounts\", \"data_quality\"],\n messages: {\n fr: { label: \"Disponible maintenant\", \"missing.one\": \"{n} compte sans solde\", \"missing.other\": \"{n} comptes sans solde\", none: \"Aucun solde renseigné\" },\n de: { label: \"Jetzt verfügbar\", \"missing.one\": \"{n} Konto ohne Saldo\", \"missing.other\": \"{n} Konten ohne Saldo\", none: \"Noch kein Saldo erfasst\" },\n it: { label: \"Disponibile ora\", \"missing.one\": \"{n} conto senza saldo\", \"missing.other\": \"{n} conti senza saldo\", none: \"Nessun saldo inserito\" },\n rm: { label: \"Disponibel ussa\", \"missing.one\": \"{n} conto senza saldo\", \"missing.other\": \"{n} contos senza saldo\", none: \"Anc nagin saldo endatà\" },\n en: { label: \"Available now\", \"missing.one\": \"{n} account without a balance\", \"missing.other\": \"{n} accounts without a balance\", none: \"No balance entered yet\" },\n },\n select: (s) => ({\n amount: s.opening_balance,\n currency: s.base_currency,\n known: s.accounts.filter((a) => a.balance !== null && LIQUID.has(a.account_type)).map((a) => a.name),\n missing: s.data_quality.accounts_without_balance.length,\n }),\n View: ({ model, t, fmt }) => {\n const parts = [...(model.known.length ? [model.known.join(\", \")] : []), ...(model.missing ? [t(\"missing\", { n: model.missing })] : [])];\n return (\n <Tile\n question={t(\"question\")}\n label={t(\"label\")}\n value={fmt.num(model.amount)}\n unit={model.currency}\n tone={toNumber(model.amount) < 0 ? \"neg\" : undefined}\n note={parts.join(\" · \") || t(\"none\")}\n />\n );\n },\n});\n","import { toNumber } from \"../../contract/snapshot\";\nimport { Tile } from \"../../primitives\";\nimport { defineModule } from \"../types\";\n\ntype Model = { due: string; available: string; gap: string; currency: string; payday: string | null };\n\nexport default defineModule<Model>({\n id: \"due-before-payday\",\n size: \"tile\",\n question: {\n fr: \"Que dois-je payer avant le salaire ?\",\n de: \"Was muss ich vor dem Lohn bezahlen?\",\n it: \"Cosa devo pagare prima dello stipendio?\",\n rm: \"Tge stoss jau pajar avant il salari?\",\n en: \"What do I owe before payday?\",\n },\n reads: [\"due_before_next_income\", \"gap_before_next_income\", \"opening_balance\", \"next_income_date\", \"base_currency\"],\n messages: {\n fr: { label: \"À payer avant le revenu · {day} {date}\", labelNone: \"Aucun revenu prévu\", covered: \"Couvert · il reste {rest}\", short: \"Il manque {gap} avant le revenu\", split: \"{due} dus − {available} disponibles\" },\n de: { label: \"Vor dem Einkommen fällig · {day} {date}\", labelNone: \"Kein Einkommen geplant\", covered: \"Gedeckt · es bleiben {rest}\", short: \"Bis zum Einkommen fehlen {gap}\", split: \"{due} fällig − {available} verfügbar\" },\n it: { label: \"Da pagare prima del reddito · {day} {date}\", labelNone: \"Nessun reddito previsto\", covered: \"Coperto · restano {rest}\", short: \"Mancano {gap} prima del reddito\", split: \"{due} dovuti − {available} disponibili\" },\n rm: { label: \"Da pajar avant il salari · {day} {date}\", labelNone: \"Nagin salari previs\", covered: \"Cuvrì · i restan {rest}\", short: \"I mancan {gap} avant il salari\", split: \"{due} da pajar − {available} disponibels\" },\n en: { label: \"Due before payday · {day} {date}\", labelNone: \"No income scheduled\", covered: \"Covered · {rest} left\", short: \"{gap} short before payday\", split: \"{due} due − {available} available\" },\n },\n select: (s) => ({\n due: s.due_before_next_income,\n available: s.opening_balance,\n gap: s.gap_before_next_income,\n currency: s.base_currency,\n payday: s.next_income_date,\n }),\n View: ({ model, t, fmt }) => {\n const gap = toNumber(model.gap);\n const short = gap < 0;\n return (\n <Tile\n question={t(\"question\")}\n label={model.payday ? t(\"label\", { day: fmt.weekday(model.payday), date: fmt.shortDate(model.payday) }) : t(\"labelNone\")}\n value={fmt.num(model.due)}\n unit={model.currency}\n tone={short ? \"neg\" : undefined}\n note={\n <>\n {short ? t(\"short\", { gap: fmt.num(Math.abs(gap)) }) : t(\"covered\", { rest: fmt.num(gap) })}\n <br />\n {t(\"split\", { due: fmt.num(model.due), available: fmt.num(model.available) })}\n </>\n }\n />\n );\n },\n});\n","import { toNumber } from \"../../contract/snapshot\";\nimport { daysBetween } from \"../../format\";\nimport { Tile } from \"../../primitives\";\nimport { defineModule } from \"../types\";\n\ntype Model = { balance: string; date: string; days: number; currency: string; beforeIncome: { days: number; date: string } | null };\n\nexport default defineModule<Model>({\n id: \"low-point\",\n size: \"tile\",\n question: {\n fr: \"Jusqu’où puis-je descendre ?\",\n de: \"Wie tief sinkt mein Saldo?\",\n it: \"Quanto scenderà il saldo?\",\n rm: \"Quant bass vegn il saldo?\",\n en: \"How low might I go?\",\n },\n reads: [\"low_point\", \"next_income_date\", \"second_income_date\", \"base_currency\"],\n messages: {\n fr: { label: \"Point bas prévu · {day} {date}\", \"before.one\": \"{n} jour avant le revenu du {date}\", \"before.other\": \"{n} jours avant le revenu du {date}\" },\n de: { label: \"Prognostizierter Tiefpunkt · {day} {date}\", \"before.one\": \"{n} Tag vor dem Einkommen am {date}\", \"before.other\": \"{n} Tage vor dem Einkommen am {date}\" },\n it: { label: \"Minimo previsto · {day} {date}\", \"before.one\": \"{n} giorno prima del reddito del {date}\", \"before.other\": \"{n} giorni prima del reddito del {date}\" },\n rm: { label: \"Punct bass previs · {day} {date}\", \"before.one\": \"{n} di avant il salari dals {date}\", \"before.other\": \"{n} dis avant il salari dals {date}\" },\n en: { label: \"Projected low point · {day} {date}\", \"before.one\": \"{n} day before the {date} income\", \"before.other\": \"{n} days before the {date} income\" },\n },\n select: (s) => {\n // The income that follows the low point, if the horizon contains it.\n const after = [s.next_income_date, s.second_income_date].find((d): d is string => !!d && d > s.low_point.date) ?? null;\n return {\n balance: s.low_point.balance,\n date: s.low_point.date,\n days: s.low_point.days_from_now,\n currency: s.base_currency,\n beforeIncome: after ? { days: daysBetween(s.low_point.date, after), date: after } : null,\n };\n },\n View: ({ model, t, fmt }) => {\n const when = model.days === 0 ? t(\"today\") : t(\"inDays\", { n: model.days });\n const note = model.beforeIncome ? `${when} · ${t(\"before\", { n: model.beforeIncome.days, date: fmt.shortDate(model.beforeIncome.date) })}` : when;\n return (\n <Tile\n emphasis\n question={t(\"question\")}\n label={t(\"label\", { day: fmt.weekday(model.date), date: fmt.shortDate(model.date) })}\n value={fmt.num(model.balance)}\n unit={model.currency}\n tone={toNumber(model.balance) < 0 ? \"neg\" : undefined}\n note={note}\n />\n );\n },\n});\n","import { tone } from \"../../format\";\nimport { Tile } from \"../../primitives\";\nimport { defineModule } from \"../types\";\n\ntype Model = { balance: string; date: string; twoIncomes: boolean; currency: string; missing: number };\n\nexport default defineModule<Model>({\n id: \"margin-after-payday\",\n size: \"tile\",\n question: {\n fr: \"Que me restera-t-il ?\",\n de: \"Was bleibt mir?\",\n it: \"Cosa mi resterà?\",\n rm: \"Tge ma resta?\",\n en: \"What will be left?\",\n },\n reads: [\"end_of_horizon\", \"second_income_date\", \"data_quality\", \"base_currency\"],\n messages: {\n fr: { label: \"Marge au {date}\", labelTwo: \"Marge au {date} · 2 salaires\", ok: \"Après toutes les échéances connues\", \"missing.one\": \"{n} récurrence encore sans montant\", \"missing.other\": \"{n} récurrences encore sans montant\" },\n de: { label: \"Spielraum am {date}\", labelTwo: \"Spielraum am {date} · 2 Löhne\", ok: \"Nach allen bekannten Fälligkeiten\", \"missing.one\": \"{n} wiederkehrender Posten noch ohne Betrag\", \"missing.other\": \"{n} wiederkehrende Posten noch ohne Betrag\" },\n it: { label: \"Margine al {date}\", labelTwo: \"Margine al {date} · 2 stipendi\", ok: \"Dopo tutte le scadenze note\", \"missing.one\": \"{n} ricorrenza ancora senza importo\", \"missing.other\": \"{n} ricorrenze ancora senza importo\" },\n rm: { label: \"Margin ils {date}\", labelTwo: \"Margin ils {date} · 2 salaris\", ok: \"Suenter tut ils termins enconuschents\", \"missing.one\": \"{n} repetiziun anc senza summa\", \"missing.other\": \"{n} repetiziuns anc senza summa\" },\n en: { label: \"Margin on {date}\", labelTwo: \"Margin on {date} · 2 paydays\", ok: \"After every known bill\", \"missing.one\": \"{n} recurring item still without an amount\", \"missing.other\": \"{n} recurring items still without an amount\" },\n },\n select: (s) => ({\n balance: s.end_of_horizon.balance,\n date: s.end_of_horizon.date,\n twoIncomes: !!s.second_income_date,\n currency: s.base_currency,\n missing: s.data_quality.rules_without_amount.length,\n }),\n View: ({ model, t, fmt }) => (\n <Tile\n question={t(\"question\")}\n label={t(model.twoIncomes ? \"labelTwo\" : \"label\", { date: fmt.shortDate(model.date) })}\n value={fmt.signed(model.balance)}\n unit={model.currency}\n tone={tone(model.balance)}\n note={model.missing > 0 ? t(\"missing\", { n: model.missing }) : t(\"ok\")}\n />\n ),\n});\n","import { toNumber } from \"../../contract/snapshot\";\nimport { tone } from \"../../format\";\nimport { Card, Empty, SHADES } from \"../../primitives\";\nimport { defineModule } from \"../types\";\n\ntype Slice = { category: string; amount: number; others?: string[] };\ntype Model = {\n fixed: string;\n income: string;\n ratio: string | null;\n margin: string | null;\n slices: Slice[];\n currency: string;\n missing: number;\n debts: { total: string; items: { name: string; principal: string }[] } | null;\n target: string | null;\n};\n\nexport default defineModule<Model>({\n id: \"monthly-structure\",\n size: \"narrow\",\n question: {\n fr: \"Combien me coûte un mois ?\",\n de: \"Was kostet mich ein Monat?\",\n it: \"Quanto mi costa un mese?\",\n rm: \"Quant ma custa in mais?\",\n en: \"What does a month cost me?\",\n },\n reads: [\"structure\", \"debts\", \"data_quality\", \"second_income_date\", \"base_currency\"],\n messages: {\n fr: { title: \"Structure mensuelle\", fixedOf: \"{cur} de charges fixes / {income} de revenus\", others: \"Autres ({names})\", marginTitle: \"Marge structurelle\", margin: \"≈ {amount} {cur} / mois\", noIncome: \"Revenus récurrents non définis\", ratio: \"Taux de charges fixes : {p} %.\", \"missing.one\": \"{n} récurrence sans montant non comptée.\", \"missing.other\": \"{n} récurrences sans montant non comptées.\", debts: \"Dettes court terme\", target: \"objectif zéro au {date}\", empty: \"Aucune récurrence active.\" },\n de: { title: \"Monatliche Struktur\", fixedOf: \"{cur} Fixkosten / {income} Einkommen\", others: \"Übrige ({names})\", marginTitle: \"Struktureller Spielraum\", margin: \"≈ {amount} {cur} / Monat\", noIncome: \"Wiederkehrendes Einkommen fehlt\", ratio: \"Fixkostenquote: {p} %.\", \"missing.one\": \"{n} Posten ohne Betrag nicht eingerechnet.\", \"missing.other\": \"{n} Posten ohne Betrag nicht eingerechnet.\", debts: \"Kurzfristige Schulden\", target: \"Ziel null bis {date}\", empty: \"Keine wiederkehrenden Posten.\" },\n it: { title: \"Struttura mensile\", fixedOf: \"{cur} di costi fissi / {income} di reddito\", others: \"Altro ({names})\", marginTitle: \"Margine strutturale\", margin: \"≈ {amount} {cur} / mese\", noIncome: \"Reddito ricorrente non definito\", ratio: \"Quota di costi fissi: {p} %.\", \"missing.one\": \"{n} ricorrenza senza importo non conteggiata.\", \"missing.other\": \"{n} ricorrenze senza importo non conteggiate.\", debts: \"Debiti a breve termine\", target: \"obiettivo zero entro il {date}\", empty: \"Nessuna ricorrenza attiva.\" },\n rm: { title: \"Structura mensila\", fixedOf: \"{cur} custs fixs / {income} entradas\", others: \"Auters ({names})\", marginTitle: \"Margin structural\", margin: \"≈ {amount} {cur} / mais\", noIncome: \"Entradas regularas betg definidas\", ratio: \"Quota da custs fixs: {p} %.\", \"missing.one\": \"{n} repetiziun senza summa betg quintada.\", \"missing.other\": \"{n} repetiziuns senza summa betg quintadas.\", debts: \"Debits a curta vista\", target: \"finamira nulla fin ils {date}\", empty: \"Naginas repetiziuns activas.\" },\n en: { title: \"Monthly structure\", fixedOf: \"{cur} fixed costs / {income} income\", others: \"Other ({names})\", marginTitle: \"Structural margin\", margin: \"≈ {amount} {cur} / month\", noIncome: \"No recurring income set\", ratio: \"Fixed-cost ratio: {p}%.\", \"missing.one\": \"{n} item without an amount not counted.\", \"missing.other\": \"{n} items without an amount not counted.\", debts: \"Short-term debt\", target: \"target zero by {date}\", empty: \"No active recurring items.\" },\n },\n select: (s) => {\n const cats = s.structure.by_category.map((c) => ({ category: c.category, amount: toNumber(c.amount) }));\n const slices: Slice[] =\n cats.length <= 4\n ? cats\n : [...cats.slice(0, 3), { category: \"\", amount: cats.slice(3).reduce((sum, c) => sum + c.amount, 0), others: cats.slice(3).map((c) => c.category) }];\n return {\n fixed: s.structure.fixed_monthly,\n income: s.structure.income_monthly,\n ratio: s.structure.fixed_ratio_percent,\n margin: s.structure.structural_margin,\n slices,\n currency: s.base_currency,\n missing: s.data_quality.rules_without_amount.length,\n debts: s.debts.items.length ? { total: s.debts.total_base, items: s.debts.items.map((d) => ({ name: d.name, principal: d.principal })) } : null,\n target: s.second_income_date,\n };\n },\n View: ({ model, t, fmt }) => {\n const income = toNumber(model.income);\n const name = (sl: Slice) => (sl.others ? t(\"others\", { names: sl.others.join(\", \") }) : sl.category);\n return (\n <Card question={t(\"question\")} title={t(\"title\")}>\n <div className=\"bz-inline\">\n <strong className=\"bz-figure\">{fmt.num(model.fixed)}</strong>\n <span className=\"bz-note\">{t(\"fixedOf\", { cur: model.currency, income: fmt.num(model.income) })}</span>\n </div>\n <div className=\"bz-stack\" role=\"img\" aria-label={model.slices.map((sl) => `${name(sl)} ${fmt.num(sl.amount)}`).join(\", \")}>\n {model.slices.map((sl, i) => (\n <i key={name(sl)} className={SHADES[i]} style={{ width: `${income > 0 ? (sl.amount / income) * 100 : 0}%` }} />\n ))}\n </div>\n <div className=\"bz-cats\">\n {model.slices.map((sl, i) => (\n <div key={name(sl)}><i className={SHADES[i]} /><span>{name(sl)}</span><strong>{fmt.num(sl.amount)}</strong></div>\n ))}\n {model.slices.length === 0 && <Empty>{t(\"empty\")}</Empty>}\n </div>\n <hr className=\"bz-rule\" />\n <p className=\"bz-eyebrow\">{t(\"marginTitle\")}</p>\n <strong className={`bz-figure-s bz-${tone(model.margin ?? 0)}`}>\n {model.margin ? t(\"margin\", { amount: fmt.num(model.margin), cur: model.currency }) : t(\"noIncome\")}\n </strong>\n <p className=\"bz-note\">\n {model.ratio ? t(\"ratio\", { p: fmt.num(model.ratio) }) : \"\"}\n {model.missing > 0 ? ` ${t(\"missing\", { n: model.missing })}` : \"\"}\n </p>\n {model.debts && (\n <>\n <hr className=\"bz-rule\" />\n <p className=\"bz-eyebrow\">{t(\"debts\")}</p>\n <strong className=\"bz-figure-s\">{fmt.num(model.debts.total)} {model.currency}</strong>\n <p className=\"bz-note\">\n {model.debts.items.map((d) => `${d.name} ${fmt.num(d.principal)}`).join(\" · \")}\n {model.target ? ` · ${t(\"target\", { date: fmt.shortDate(model.target) })}` : \"\"}\n </p>\n </>\n )}\n </Card>\n );\n },\n});\n","import type { Action, BillAction } from \"../../contract/snapshot\";\nimport { toNumber } from \"../../contract/snapshot\";\nimport type { Formatters } from \"../../format\";\nimport type { Translate } from \"../../i18n\";\nimport { Button, Card, Dot, Empty } from \"../../primitives\";\nimport { defineModule, type ModuleAction } from \"../types\";\n\ntype GroupKey = \"late\" | \"beforePayday\" | \"toConfirm\" | \"toPlan\";\ntype Model = { groups: { key: GroupKey; items: Action[] }[]; count: number; currency: string; payday: string | null };\n\nconst GROUPS: { key: GroupKey; accepts: (a: Action) => boolean }[] = [\n { key: \"late\", accepts: (a) => a.type === \"overdue\" || a.type === \"due_today\" },\n { key: \"beforePayday\", accepts: (a) => a.type === \"before_income\" },\n { key: \"toConfirm\", accepts: (a) => a.type === \"undated\" || a.type === \"needs_review\" || a.type === \"missing_amounts\" },\n { key: \"toPlan\", accepts: (a) => a.type === \"plan\" },\n];\n\nexport default defineModule<Model>({\n id: \"next-actions\",\n size: \"wide\",\n question: {\n fr: \"Que faire ensuite ?\",\n de: \"Was kommt als Nächstes?\",\n it: \"Cosa faccio dopo?\",\n rm: \"Tge vegn suenter?\",\n en: \"What next?\",\n },\n reads: [\"actions\", \"base_currency\", \"next_income_date\"],\n messages: {\n fr: {\n title: \"À traiter\", \"count.one\": \"{n} décision · {m} min\", \"count.other\": \"{n} décisions · {m} min\", empty: \"Rien à traiter aujourd’hui.\",\n \"g.late\": \"En retard\", \"g.beforePayday\": \"À payer avant le prochain salaire\", \"g.toConfirm\": \"Sans date ou à confirmer\", \"g.toPlan\": \"À planifier\",\n overdue: \"{label} · échu depuis le {date}\", dueToday: \"{label} · échu aujourd’hui\", beforePayday: \"{label} · à payer avant le salaire · {date}\", undated: \"{label} · date à confirmer\",\n markPaid: \"Marquer payé\", planOn: \"Planifier le {date}\",\n plan: \"{label} · {amount} avant le {date}\", planBody: \"Échéance après le salaire : rien à faire avant, prévoyez-la dans le prochain cycle.\",\n review: \"{label} · à qualifier\", reviewTx: \"Transaction du {date} · {amount}\", reviewOb: \"Échéance du {date} · {amount}\", confidence: \"confiance {p} %\",\n internal: \"Transfert interne\", expense: \"Dépense\", accept: \"Valider\", cancel: \"Annuler\",\n \"missing.one\": \"{n} récurrence sans montant\", \"missing.other\": \"{n} récurrences sans montant\", missingBody: \"{items} · la marge finale est fausse tant qu’elles manquent\", complete: \"Compléter\",\n },\n de: {\n title: \"Zu erledigen\", \"count.one\": \"{n} Entscheidung · {m} Min.\", \"count.other\": \"{n} Entscheidungen · {m} Min.\", empty: \"Heute nichts zu erledigen.\",\n \"g.late\": \"Überfällig\", \"g.beforePayday\": \"Vor dem nächsten Lohn zu bezahlen\", \"g.toConfirm\": \"Ohne Datum oder zu bestätigen\", \"g.toPlan\": \"Zu planen\",\n overdue: \"{label} · überfällig seit {date}\", dueToday: \"{label} · heute fällig\", beforePayday: \"{label} · vor dem Lohn fällig · {date}\", undated: \"{label} · Datum zu bestätigen\",\n markPaid: \"Als bezahlt markieren\", planOn: \"Auf {date} planen\",\n plan: \"{label} · {amount} bis {date}\", planBody: \"Nach dem Lohn fällig: vorher ist nichts zu tun, planen Sie sie im nächsten Zyklus ein.\",\n review: \"{label} · zu prüfen\", reviewTx: \"Transaktion vom {date} · {amount}\", reviewOb: \"Fälligkeit vom {date} · {amount}\", confidence: \"Sicherheit {p} %\",\n internal: \"Interne Überweisung\", expense: \"Ausgabe\", accept: \"Bestätigen\", cancel: \"Stornieren\",\n \"missing.one\": \"{n} wiederkehrender Posten ohne Betrag\", \"missing.other\": \"{n} wiederkehrende Posten ohne Betrag\", missingBody: \"{items} · der Spielraum stimmt erst, wenn sie erfasst sind\", complete: \"Ergänzen\",\n },\n it: {\n title: \"Da fare\", \"count.one\": \"{n} decisione · {m} min\", \"count.other\": \"{n} decisioni · {m} min\", empty: \"Niente da fare oggi.\",\n \"g.late\": \"In ritardo\", \"g.beforePayday\": \"Da pagare prima del prossimo stipendio\", \"g.toConfirm\": \"Senza data o da confermare\", \"g.toPlan\": \"Da pianificare\",\n overdue: \"{label} · scaduto dal {date}\", dueToday: \"{label} · scade oggi\", beforePayday: \"{label} · da pagare prima dello stipendio · {date}\", undated: \"{label} · data da confermare\",\n markPaid: \"Segna come pagato\", planOn: \"Pianifica il {date}\",\n plan: \"{label} · {amount} entro il {date}\", planBody: \"Scade dopo lo stipendio: niente da fare prima, la preveda nel prossimo ciclo.\",\n review: \"{label} · da verificare\", reviewTx: \"Transazione del {date} · {amount}\", reviewOb: \"Scadenza del {date} · {amount}\", confidence: \"affidabilità {p} %\",\n internal: \"Trasferimento interno\", expense: \"Spesa\", accept: \"Conferma\", cancel: \"Annulla\",\n \"missing.one\": \"{n} ricorrenza senza importo\", \"missing.other\": \"{n} ricorrenze senza importo\", missingBody: \"{items} · il margine finale è sbagliato finché mancano\", complete: \"Completa\",\n },\n rm: {\n title: \"Da far\", \"count.one\": \"{n} decisiun · {m} min\", \"count.other\": \"{n} decisiuns · {m} min\", empty: \"Oz nagut da far.\",\n \"g.late\": \"Retardà\", \"g.beforePayday\": \"Da pajar avant il proxim salari\", \"g.toConfirm\": \"Senza data u da confermar\", \"g.toPlan\": \"Da planisar\",\n overdue: \"{label} · scadì dapi ils {date}\", dueToday: \"{label} · scada oz\", beforePayday: \"{label} · da pajar avant il salari · {date}\", undated: \"{label} · data da confermar\",\n markPaid: \"Marcar sco pajà\", planOn: \"Planisar ils {date}\",\n plan: \"{label} · {amount} fin ils {date}\", planBody: \"Scadenza suenter il salari: nagut da far avant, planisai ella en il proxim ciclus.\",\n review: \"{label} · da controllar\", reviewTx: \"Transacziun dals {date} · {amount}\", reviewOb: \"Termin dals {date} · {amount}\", confidence: \"fidanza {p} %\",\n internal: \"Transfer intern\", expense: \"Expensa\", accept: \"Confermar\", cancel: \"Annullar\",\n \"missing.one\": \"{n} repetiziun senza summa\", \"missing.other\": \"{n} repetiziuns senza summa\", missingBody: \"{items} · il margin final è fauss uschè ditg ch’ellas mancan\", complete: \"Cumplettar\",\n },\n en: {\n title: \"To do\", \"count.one\": \"{n} decision · {m} min\", \"count.other\": \"{n} decisions · {m} min\", empty: \"Nothing to do today.\",\n \"g.late\": \"Overdue\", \"g.beforePayday\": \"Due before next payday\", \"g.toConfirm\": \"No date or to confirm\", \"g.toPlan\": \"To schedule\",\n overdue: \"{label} · overdue since {date}\", dueToday: \"{label} · due today\", beforePayday: \"{label} · due before payday · {date}\", undated: \"{label} · date to confirm\",\n markPaid: \"Mark paid\", planOn: \"Schedule on {date}\",\n plan: \"{label} · {amount} by {date}\", planBody: \"Due after payday: nothing to do before then, plan it in the next cycle.\",\n review: \"{label} · to review\", reviewTx: \"Transaction on {date} · {amount}\", reviewOb: \"Bill due {date} · {amount}\", confidence: \"confidence {p}%\",\n internal: \"Internal transfer\", expense: \"Expense\", accept: \"Confirm\", cancel: \"Cancel\",\n \"missing.one\": \"{n} recurring item without an amount\", \"missing.other\": \"{n} recurring items without an amount\", missingBody: \"{items} · the final margin is wrong until they are filled in\", complete: \"Fill in\",\n },\n },\n select: (s) => ({\n groups: GROUPS.map((g) => ({ key: g.key, items: s.actions.filter(g.accepts) })).filter((g) => g.items.length > 0),\n count: s.actions.length,\n currency: s.base_currency,\n payday: s.next_income_date,\n }),\n View: ({ model, t, fmt, onAction }) => (\n <Card question={t(\"question\")} title={t(\"title\")} meta={model.count > 0 ? t(\"count\", { n: model.count, m: Math.max(1, Math.ceil(model.count / 2)) }) : undefined}>\n {model.count === 0 && <Empty>{t(\"empty\")}</Empty>}\n {model.groups.map((g) => (\n <div className=\"bz-group\" key={g.key}>\n <h3 className=\"bz-group-title\">{t(`g.${g.key}`)} <span>{g.items.length}</span></h3>\n {g.items.map((a, i) => (\n <ActionRow key={`${a.type}-${\"ref_id\" in a ? a.ref_id : i}`} a={a} currency={model.currency} payday={model.payday} t={t} fmt={fmt} onAction={onAction} />\n ))}\n </div>\n ))}\n </Card>\n ),\n});\n\nfunction ActionRow({ a, currency, payday, t, fmt, onAction }: { a: Action; currency: string; payday: string | null; t: Translate; fmt: Formatters; onAction: (a: ModuleAction) => void }) {\n if (a.type === \"missing_amounts\") {\n return (\n <div className=\"bz-row bz-action\">\n <Dot tone=\"warn\" />\n <div className=\"bz-row-body\">\n <strong>{t(\"missing\", { n: a.items.length })}</strong>\n <span>{t(\"missingBody\", { items: a.items.join(\", \") })}</span>\n </div>\n <Button onClick={() => onAction({ type: \"open\", target: \"recurrences\" })}>{t(\"complete\")}</Button>\n </div>\n );\n }\n const conf = a.confidence ? ` · ${t(\"confidence\", { p: fmt.num(toNumber(a.confidence) * 100) })}` : \"\";\n if (a.type === \"needs_review\") {\n const tx = a.kind === \"transaction\";\n return (\n <div className=\"bz-row bz-action\">\n <Dot tone=\"warn\" />\n <div className=\"bz-row-body\">\n <strong>{t(\"review\", { label: a.label })}</strong>\n <span>{t(tx ? \"reviewTx\" : \"reviewOb\", { date: fmt.shortDate(a.date), amount: fmt.money(a.amount, a.currency) })}{conf}</span>\n </div>\n {tx ? (\n <>\n <Button onClick={() => onAction({ type: \"classify_transaction\", ref_id: a.ref_id, internal_transfer: true })}>{t(\"internal\")}</Button>\n <Button onClick={() => onAction({ type: \"classify_transaction\", ref_id: a.ref_id, internal_transfer: false })}>{t(\"expense\")}</Button>\n </>\n ) : (\n <>\n <Button onClick={() => onAction({ type: \"review_obligation\", ref_id: a.ref_id, decision: \"accept\" })}>{t(\"accept\")}</Button>\n <Button variant=\"ghost\" onClick={() => onAction({ type: \"review_obligation\", ref_id: a.ref_id, decision: \"cancel\" })}>{t(\"cancel\")}</Button>\n </>\n )}\n </div>\n );\n }\n return <BillRow a={a} currency={currency} payday={payday} conf={conf} t={t} fmt={fmt} onAction={onAction} />;\n}\n\nfunction BillRow({ a, currency, payday, conf, t, fmt, onAction }: { a: BillAction; currency: string; payday: string | null; conf: string; t: Translate; fmt: Formatters; onAction: (a: ModuleAction) => void }) {\n const amount = a.currency === currency ? fmt.money(a.amount, a.currency) : `${fmt.money(a.amount, a.currency)} · ${fmt.num(a.amount_base)} ${currency}`;\n const date = fmt.shortDate(a.date);\n const title =\n a.type === \"overdue\" ? t(\"overdue\", { label: a.label, date })\n : a.type === \"due_today\" ? t(\"dueToday\", { label: a.label })\n : a.type === \"before_income\" ? t(\"beforePayday\", { label: a.label, date })\n : a.type === \"undated\" ? t(\"undated\", { label: a.label })\n : t(\"plan\", { label: a.label, amount: fmt.money(a.amount, a.currency), date });\n const detail = a.type === \"plan\" ? (a.description || t(\"planBody\")) : [amount, a.description].filter(Boolean).join(\" · \");\n // A late bill can still be postponed to the next payday. A bill due after payday is never\n // moved earlier: paying sooner cannot lift a later low point and can create a new one.\n const moveTo = a.type === \"overdue\" || a.type === \"due_today\" ? (payday && a.date && payday > a.date ? payday : null) : null;\n const tone = a.type === \"overdue\" || a.type === \"due_today\" ? \"danger\" : a.type === \"plan\" ? \"muted\" : \"warn\";\n return (\n <div className=\"bz-row bz-action\">\n <Dot tone={tone} />\n <div className=\"bz-row-body\">\n <strong>{title}</strong>\n <span>{detail}{conf}</span>\n </div>\n {moveTo && <Button onClick={() => onAction({ type: \"reschedule\", ref_id: a.ref_id, date: moveTo })}>{t(\"planOn\", { date: fmt.shortDate(moveTo) })}</Button>}\n <Button variant={a.type === \"overdue\" || a.type === \"due_today\" ? \"primary\" : \"secondary\"} onClick={() => onAction({ type: \"mark_paid\", ref_id: a.ref_id })}>{t(\"markPaid\")}</Button>\n </div>\n );\n}\n","import { useState } from \"react\";\n\nimport type { CashEvent, Cycle } from \"../../contract/snapshot\";\nimport { toNumber } from \"../../contract/snapshot\";\nimport { daysBetween, type Formatters } from \"../../format\";\nimport type { Translate } from \"../../i18n\";\nimport { Button, Card, Empty } from \"../../primitives\";\nimport { defineModule, type ModuleAction } from \"../types\";\n\ntype Group = { key: string; items: CashEvent[] };\ntype Column = { key: string; title: { kind: \"before\"; date: string } | { kind: \"cycle\"; from: string; to: string }; totalOut: string; totalIn: string; truncated: string | null; cycle: Cycle };\ntype Model = { columns: Column[]; outflows: number; currency: string; today: string; missing: number };\n\nexport default defineModule<Model>({\n id: \"pay-cycles\",\n size: \"full\",\n question: {\n fr: \"Qu’est-ce qui tombe à chaque salaire ?\",\n de: \"Was fällt in jeder Lohnperiode an?\",\n it: \"Cosa scade in ogni periodo di paga?\",\n rm: \"Tge croda en mintga perioda da salari?\",\n en: \"What falls due each pay cycle?\",\n },\n reads: [\"cycles\", \"events\", \"next_income_date\", \"horizon_end\", \"as_of\", \"data_quality\", \"base_currency\"],\n messages: {\n fr: { title: \"Échéances par cycle de paie\", sub: \"{n} sorties · {cur} équivalent, devise d’origine entre parenthèses\", all: \"Toutes les échéances →\", compact: \"Vue condensée ←\", before: \"Avant le revenu du {date}\", cycle: \"Cycle {from} → {to}\", until: \"au {date}\", \"group.one\": \"{n} échéance · déplier\", \"group.other\": \"{n} échéances · déplier\", paid: \"Payé\", recurring: \"récurrence\", \"missing.one\": \"{n} récurrence sans montant\", \"missing.other\": \"{n} récurrences sans montant\", toEnter: \"à saisir\", empty: \"Aucune sortie.\" },\n de: { title: \"Fälligkeiten pro Lohnperiode\", sub: \"{n} Ausgaben · {cur}-Gegenwert, Originalwährung in Klammern\", all: \"Alle Fälligkeiten →\", compact: \"Kompakte Ansicht ←\", before: \"Vor dem Einkommen am {date}\", cycle: \"Periode {from} → {to}\", until: \"bis {date}\", \"group.one\": \"{n} Fälligkeit · aufklappen\", \"group.other\": \"{n} Fälligkeiten · aufklappen\", paid: \"Bezahlt\", recurring: \"wiederkehrend\", \"missing.one\": \"{n} wiederkehrender Posten ohne Betrag\", \"missing.other\": \"{n} wiederkehrende Posten ohne Betrag\", toEnter: \"erfassen\", empty: \"Keine Ausgaben.\" },\n it: { title: \"Scadenze per periodo di paga\", sub: \"{n} uscite · equivalente {cur}, valuta originale tra parentesi\", all: \"Tutte le scadenze →\", compact: \"Vista compatta ←\", before: \"Prima del reddito del {date}\", cycle: \"Periodo {from} → {to}\", until: \"al {date}\", \"group.one\": \"{n} scadenza · espandi\", \"group.other\": \"{n} scadenze · espandi\", paid: \"Pagato\", recurring: \"ricorrente\", \"missing.one\": \"{n} ricorrenza senza importo\", \"missing.other\": \"{n} ricorrenze senza importo\", toEnter: \"da inserire\", empty: \"Nessuna uscita.\" },\n rm: { title: \"Termins per perioda da salari\", sub: \"{n} sortidas · equivalent {cur}, valuta originala tranter parentesas\", all: \"Tut ils termins →\", compact: \"Vista cumpacta ←\", before: \"Avant il salari dals {date}\", cycle: \"Perioda {from} → {to}\", until: \"fin ils {date}\", \"group.one\": \"{n} termin · extender\", \"group.other\": \"{n} termins · extender\", paid: \"Pajà\", recurring: \"repetitiv\", \"missing.one\": \"{n} repetiziun senza summa\", \"missing.other\": \"{n} repetiziuns senza summa\", toEnter: \"endatar\", empty: \"Naginas sortidas.\" },\n en: { title: \"Bills by pay cycle\", sub: \"{n} outflows · {cur} equivalent, original currency in brackets\", all: \"All bills →\", compact: \"Compact view ←\", before: \"Before the {date} income\", cycle: \"Cycle {from} → {to}\", until: \"to {date}\", \"group.one\": \"{n} bill · expand\", \"group.other\": \"{n} bills · expand\", paid: \"Paid\", recurring: \"recurring\", \"missing.one\": \"{n} recurring item without an amount\", \"missing.other\": \"{n} recurring items without an amount\", toEnter: \"to enter\", empty: \"No outflows.\" },\n },\n select: (s) => {\n const last = s.cycles.length - 1;\n return {\n columns: s.cycles.map((c, i) => ({\n key: c.key,\n title: c.key === \"before_income\" ? { kind: \"before\" as const, date: s.next_income_date ?? c.end } : { kind: \"cycle\" as const, from: c.start, to: c.end },\n totalOut: c.total_out,\n totalIn: c.total_in,\n truncated: i === last && c.end === s.horizon_end && daysBetween(c.start, c.end) < 25 ? c.end : null,\n cycle: c,\n })),\n outflows: s.events.filter((e) => e.direction === \"outflow\").length,\n currency: s.base_currency,\n today: s.as_of,\n missing: s.data_quality.rules_without_amount.length,\n };\n },\n View: ({ model, t, fmt, onAction }) => {\n const [all, setAll] = useState(false);\n return (\n <Card\n question={t(\"question\")}\n title={t(\"title\")}\n meta={t(\"sub\", { n: model.outflows, cur: model.currency })}\n actions={<Button variant=\"link\" onClick={() => setAll((v) => !v)}>{all ? t(\"compact\") : t(\"all\")}</Button>}\n >\n <div className=\"bz-cycles\">\n {model.columns.map((col, i) => (\n <CycleColumn key={col.key} col={col} all={all} missing={i === model.columns.length - 1 ? model.missing : 0} currency={model.currency} today={model.today} t={t} fmt={fmt} onAction={onAction} />\n ))}\n </div>\n </Card>\n );\n },\n});\n\nfunction CycleColumn({ col, all, missing, currency, today, t, fmt, onAction }: {\n col: Column; all: boolean; missing: number; currency: string; today: string;\n t: Translate; fmt: Formatters; onAction: (a: ModuleAction) => void;\n}) {\n const [open, setOpen] = useState<Set<string>>(new Set());\n const items = all ? col.cycle.items : col.cycle.items.filter((e) => e.direction === \"outflow\");\n const groups: Group[] = all ? items.map((e) => ({ key: `${e.ref_id}-${e.date}`, items: [e] })) : groupCycle(items);\n const title = col.title.kind === \"before\" ? t(\"before\", { date: fmt.shortDate(col.title.date) }) : t(\"cycle\", { from: fmt.shortDate(col.title.from), to: fmt.shortDate(col.title.to) });\n return (\n <div className=\"bz-cycle\">\n <div className=\"bz-cycle-head\">\n <span>{title}</span>\n <strong className={toNumber(col.totalOut) > 0 ? \"bz-neg\" : \"bz-muted\"}>\n {fmt.signed(-toNumber(col.totalOut))}\n {all && toNumber(col.totalIn) > 0 && <span className=\"bz-pos\"> {fmt.signed(col.totalIn)}</span>}\n {col.truncated && <span className=\"bz-muted\"> {t(\"until\", { date: fmt.shortDate(col.truncated) })}</span>}\n </strong>\n </div>\n {groups.map((g) => {\n if (g.items.length === 1 || open.has(g.key)) {\n return g.items.map((e) => <EventRow key={`${e.ref_id}-${e.date}-${e.label}`} e={e} currency={currency} today={today} t={t} fmt={fmt} onAction={onAction} />);\n }\n const first = g.items[0]!;\n const lastItem = g.items[g.items.length - 1]!;\n return (\n <button type=\"button\" className=\"bz-row bz-row-button\" key={g.key} onClick={() => setOpen((prev) => new Set(prev).add(g.key))}>\n <span className=\"bz-date\">{fmt.dateSpan(first.date, lastItem.date)}</span>\n <div className=\"bz-row-body bz-wrap\">\n <strong>{g.items.map((e) => shortLabel(e.label)).join(\", \")}</strong>\n <span>{t(\"group\", { n: g.items.length })}</span>\n </div>\n <strong className=\"bz-amount\">{fmt.num(g.items.reduce((sum, e) => sum + toNumber(e.amount), 0))}</strong>\n </button>\n );\n })}\n {items.length === 0 && <Empty>{t(\"empty\")}</Empty>}\n {missing > 0 && (\n <button type=\"button\" className=\"bz-row bz-row-button bz-warn-row\" onClick={() => onAction({ type: \"open\", target: \"recurrences\" })}>\n <span className=\"bz-date\">?</span>\n <div className=\"bz-row-body bz-wrap\"><strong>{t(\"missing\", { n: missing })}</strong></div>\n <strong className=\"bz-amount\">{t(\"toEnter\")}</strong>\n </button>\n )}\n </div>\n );\n}\n\nfunction EventRow({ e, currency, today, t, fmt, onAction }: {\n e: CashEvent; currency: string; today: string;\n t: Translate; fmt: Formatters; onAction: (a: ModuleAction) => void;\n}) {\n const late = e.date < today || e.status === \"overdue\";\n const foreign = e.currency !== currency;\n const payable = e.kind === \"obligation\" && e.ref_id && daysBetween(today, e.date) <= 0;\n return (\n <div className={`bz-row${late ? \" bz-late\" : \"\"}`}>\n <span className=\"bz-date\">{fmt.shortDate(e.date)}</span>\n <div className=\"bz-row-body\">\n <strong>{e.direction === \"inflow\" ? \"+ \" : \"\"}{e.label}</strong>\n {foreign && <span>({fmt.money(e.original_amount, e.currency)})</span>}\n {!foreign && e.kind === \"recurrence\" && <span>{t(\"recurring\")}</span>}\n </div>\n <strong className={`bz-amount${e.direction === \"inflow\" ? \" bz-pos\" : \"\"}`}>{fmt.num(e.amount)}</strong>\n {payable && <Button variant=\"ghost\" onClick={() => onAction({ type: \"mark_paid\", ref_id: e.ref_id! })}>{t(\"paid\")}</Button>}\n </div>\n );\n}\n\n/** Big bills stand alone; small ones fold into one line per week (at most four per line). */\nexport function groupCycle(items: CashEvent[]): Group[] {\n const sorted = [...items].sort((a, b) => a.date.localeCompare(b.date) || toNumber(b.amount) - toNumber(a.amount));\n const total = sorted.reduce((sum, e) => sum + toNumber(e.amount), 0);\n const big = (e: CashEvent) => toNumber(e.amount) >= Math.max(400, total * 0.08) || e.status === \"overdue\";\n const out: Group[] = [];\n let bucket: CashEvent[] = [];\n const flush = () => {\n const head = bucket[0];\n const tail = bucket[bucket.length - 1];\n if (head && tail) out.push({ key: `${head.date}-${tail.date}-${bucket.length}`, items: bucket });\n bucket = [];\n };\n for (const e of sorted) {\n if (big(e)) {\n flush();\n out.push({ key: `${e.ref_id}-${e.date}`, items: [e] });\n continue;\n }\n const head = bucket[0];\n if (head && (daysBetween(head.date, e.date) > 7 || bucket.length >= 4)) flush();\n bucket.push(e);\n }\n flush();\n return out;\n}\n\n/** Keep whole words up to 18 characters: \"Carte de crédit solde\" → \"Carte de crédit\". */\nfunction shortLabel(label: string): string {\n if (label.length <= 18) return label;\n let out = \"\";\n for (const word of label.split(/\\s+/)) {\n const next = out ? `${out} ${word}` : word;\n if (next.length > 18) break;\n out = next;\n }\n return out || label.slice(0, 18);\n}\n","import { useEffect, useMemo, useRef, useState } from \"react\";\n\nimport type { Snapshot } from \"../../contract/snapshot\";\nimport { toNumber } from \"../../contract/snapshot\";\nimport { baseSeries, buildLevers, computeSeries, type Lever } from \"../../engine/scenario\";\nimport { tone } from \"../../format\";\nimport { Button, Card, Segmented, SHADES } from \"../../primitives\";\nimport { CashflowChart } from \"../../primitives/CashflowChart\";\nimport type { Translate } from \"../../i18n\";\nimport { defineModule, type Horizon } from \"../types\";\n\ntype Model = { snapshot: Snapshot };\n\nconst HORIZONS: Horizon[] = [\"7\", \"30\", \"cycles\", \"90\"];\n\nexport default defineModule<Model>({\n id: \"what-if\",\n size: \"full\",\n question: {\n fr: \"Et si je décale un paiement ?\",\n de: \"Und wenn ich eine Zahlung verschiebe?\",\n it: \"E se sposto un pagamento?\",\n rm: \"E sche jau spustel in pajament?\",\n en: \"What if I move a payment?\",\n },\n reads: [\"points\", \"events\", \"main_cycle\", \"low_point\", \"end_of_horizon\", \"next_income_date\", \"second_income_date\", \"as_of\", \"horizon_end\", \"opening_balance\", \"base_currency\"],\n messages: {\n fr: {\n title: \"Trésorerie prévisionnelle\", span: \"{from} → {to} · {cur} équivalent\", horizon: \"Horizon\",\n \"h.7\": \"7J\", \"h.30\": \"30J\", \"h.cycles\": \"2 salaires\", \"h.90\": \"90J\",\n base: \"Base\", scenario: \"Scénario : {name}\", overdraft: \"Découvert\",\n aria: \"Trésorerie du {from} au {to}, point bas {low} le {date}\",\n why: \"Pourquoi {low} le {date} ?\", whyBody: \"Entre le {start} et le {end}, {out} {cur} sortent pour {in} entrés.\",\n \"drivers.one\": \"{n} poste fait {share} % des sorties :\", \"drivers.other\": \"{n} postes font {share} % des sorties :\",\n levers: \"Leviers\", split: \"{label} en 2 tranches ({a} / {b})\", defer: \"Reporter {label} au {date}\", reserve: \"Garder {amount} de réserve après le {date}\",\n effectLow: \"Point bas {from} → {to}\", effectEnd: \"Marge {date} {from} → {to}\", effectSafe: \"Aucun jour sous zéro jusqu’au {date}\",\n result: \"Scénario : point bas {low} le {date}, marge finale {end}.\", save: \"Enregistrer comme scénario →\", noOut: \"Aucune sortie prévue.\",\n },\n de: {\n title: \"Liquiditätsprognose\", span: \"{from} → {to} · {cur}-Gegenwert\", horizon: \"Zeitraum\",\n \"h.7\": \"7T\", \"h.30\": \"30T\", \"h.cycles\": \"2 Löhne\", \"h.90\": \"90T\",\n base: \"Basis\", scenario: \"Szenario: {name}\", overdraft: \"Überzug\",\n aria: \"Liquidität vom {from} bis {to}, Tiefpunkt {low} am {date}\",\n why: \"Warum {low} am {date}?\", whyBody: \"Zwischen {start} und {end} gehen {out} {cur} hinaus und {in} herein.\",\n \"drivers.one\": \"{n} Posten macht {share} % der Ausgaben aus:\", \"drivers.other\": \"{n} Posten machen {share} % der Ausgaben aus:\",\n levers: \"Hebel\", split: \"{label} in 2 Raten ({a} / {b})\", defer: \"{label} auf {date} verschieben\", reserve: \"{amount} Reserve nach dem {date} behalten\",\n effectLow: \"Tiefpunkt {from} → {to}\", effectEnd: \"Spielraum {date} {from} → {to}\", effectSafe: \"Kein Tag unter null bis {date}\",\n result: \"Szenario: Tiefpunkt {low} am {date}, Spielraum am Ende {end}.\", save: \"Als Szenario speichern →\", noOut: \"Keine Ausgaben geplant.\",\n },\n it: {\n title: \"Previsione di liquidità\", span: \"{from} → {to} · equivalente {cur}\", horizon: \"Orizzonte\",\n \"h.7\": \"7G\", \"h.30\": \"30G\", \"h.cycles\": \"2 stipendi\", \"h.90\": \"90G\",\n base: \"Base\", scenario: \"Scenario: {name}\", overdraft: \"Scoperto\",\n aria: \"Liquidità dal {from} al {to}, minimo {low} il {date}\",\n why: \"Perché {low} il {date}?\", whyBody: \"Tra il {start} e il {end} escono {out} {cur} ed entrano {in}.\",\n \"drivers.one\": \"{n} voce fa il {share} % delle uscite:\", \"drivers.other\": \"{n} voci fanno il {share} % delle uscite:\",\n levers: \"Leve\", split: \"{label} in 2 rate ({a} / {b})\", defer: \"Rinviare {label} al {date}\", reserve: \"Tenere {amount} di riserva dopo il {date}\",\n effectLow: \"Minimo {from} → {to}\", effectEnd: \"Margine {date} {from} → {to}\", effectSafe: \"Nessun giorno sotto zero fino al {date}\",\n result: \"Scenario: minimo {low} il {date}, margine finale {end}.\", save: \"Salva come scenario →\", noOut: \"Nessuna uscita prevista.\",\n },\n rm: {\n title: \"Prognosa da liquiditad\", span: \"{from} → {to} · equivalent {cur}\", horizon: \"Orizont\",\n \"h.7\": \"7D\", \"h.30\": \"30D\", \"h.cycles\": \"2 salaris\", \"h.90\": \"90D\",\n base: \"Basa\", scenario: \"Scenari: {name}\", overdraft: \"Surtratga\",\n aria: \"Liquiditad dals {from} fin ils {to}, punct bass {low} ils {date}\",\n why: \"Pertge {low} ils {date}?\", whyBody: \"Tranter ils {start} ed ils {end} sortan {out} {cur} ed entran {in}.\",\n \"drivers.one\": \"{n} post fa {share} % da las sortidas:\", \"drivers.other\": \"{n} posts fan {share} % da las sortidas:\",\n levers: \"Levas\", split: \"{label} en 2 ratas ({a} / {b})\", defer: \"Spustar {label} sin ils {date}\", reserve: \"Tegnair {amount} reserva suenter ils {date}\",\n effectLow: \"Punct bass {from} → {to}\", effectEnd: \"Margin {date} {from} → {to}\", effectSafe: \"Nagin di sut nulla fin ils {date}\",\n result: \"Scenari: punct bass {low} ils {date}, margin final {end}.\", save: \"Memorisar sco scenari →\", noOut: \"Naginas sortidas previsas.\",\n },\n en: {\n title: \"Cash-flow forecast\", span: \"{from} → {to} · {cur} equivalent\", horizon: \"Horizon\",\n \"h.7\": \"7D\", \"h.30\": \"30D\", \"h.cycles\": \"2 paydays\", \"h.90\": \"90D\",\n base: \"Baseline\", scenario: \"Scenario: {name}\", overdraft: \"Overdraft\",\n aria: \"Cash from {from} to {to}, low point {low} on {date}\",\n why: \"Why {low} on {date}?\", whyBody: \"Between {start} and {end}, {out} {cur} goes out and {in} comes in.\",\n \"drivers.one\": \"{n} item makes up {share}% of outflows:\", \"drivers.other\": \"{n} items make up {share}% of outflows:\",\n levers: \"Levers\", split: \"{label} in 2 instalments ({a} / {b})\", defer: \"Move {label} to {date}\", reserve: \"Keep {amount} in reserve after {date}\",\n effectLow: \"Low point {from} → {to}\", effectEnd: \"Margin {date} {from} → {to}\", effectSafe: \"No day below zero until {date}\",\n result: \"Scenario: low point {low} on {date}, final margin {end}.\", save: \"Save as scenario →\", noOut: \"No outflows planned.\",\n },\n },\n select: (s) => (s.points.length > 0 ? { snapshot: s } : null),\n View: ({ model, t, fmt, ctx, onAction }) => {\n const s = model.snapshot;\n const cur = s.base_currency;\n const base = useMemo(() => baseSeries(s), [s]);\n const levers = useMemo(() => buildLevers(s), [s]);\n const touched = useRef(false);\n const [active, setActive] = useState<Set<string>>(new Set());\n // The first lever starts on, so the scenario line is visible on arrival.\n useEffect(() => {\n if (!touched.current) setActive(levers[0] ? new Set([levers[0].id]) : new Set());\n }, [levers]);\n const scenario = useMemo(() => (active.size > 0 ? computeSeries(s, active, levers) : null), [s, active, levers]);\n const chosen = levers.filter((l) => active.has(l.id));\n const title = (l: Lever) => leverTitle(l, t, fmt.num, fmt.shortDate);\n const drivers = s.main_cycle.drivers;\n const share = drivers.reduce((sum, d) => sum + toNumber(d.share), 0);\n const markers = groupMarkers(s, fmt.num);\n\n return (\n <div className=\"bz-split\">\n <Card\n className=\"bz-span-2\"\n question={t(\"question\")}\n title={t(\"title\")}\n meta={t(\"span\", { from: fmt.shortDate(s.as_of), to: fmt.shortDate(s.horizon_end), cur })}\n actions={\n <Segmented\n label={t(\"horizon\")}\n value={ctx.horizon}\n options={HORIZONS.map((h) => ({ key: h, label: t(`h.${h}`) }))}\n onChange={(h) => onAction({ type: \"set_horizon\", horizon: h })}\n />\n }\n >\n <CashflowChart\n base={base}\n scenario={scenario}\n today={s.as_of}\n incomes={[s.next_income_date, s.second_income_date].filter((d): d is string => !!d)}\n markers={markers}\n labels={{\n today: t(\"today\"),\n payday: (date) => t(\"payday\", { date }),\n aria: t(\"aria\", { from: fmt.shortDate(s.as_of), to: fmt.shortDate(s.horizon_end), low: fmt.num(base.low.balance), date: fmt.shortDate(base.low.date) }),\n }}\n />\n <div className=\"bz-legend\">\n <span><i className=\"bz-sw bz-sw-base\" />{t(\"base\")}</span>\n {scenario && <span><i className=\"bz-sw bz-sw-scenario\" />{t(\"scenario\", { name: chosen.map(title).join(\" + \") })}</span>}\n <span><i className=\"bz-sw bz-sw-danger\" />{t(\"overdraft\")}</span>\n </div>\n </Card>\n\n <Card title={t(\"why\", { low: fmt.num(s.low_point.balance), date: fmt.shortDate(s.low_point.date) })}>\n <p className=\"bz-body\">\n {t(\"whyBody\", { start: fmt.shortDate(s.main_cycle.start), end: fmt.shortDate(s.main_cycle.end), out: fmt.num(s.main_cycle.total_out), in: fmt.num(s.main_cycle.total_in), cur })}\n {drivers.length > 0 && ` ${t(\"drivers\", { n: drivers.length, share: fmt.num(share) })}`}\n </p>\n <div className=\"bz-bars\">\n {drivers.map((d, i) => (\n <div className=\"bz-bar\" key={`${d.label}-${d.date}`}>\n <i className={SHADES[Math.min(i, 3)]} style={{ width: `${Math.max(6, toNumber(d.share) * 2.4)}px` }} />\n <span>{d.label} <em>{fmt.shortDate(d.date)}</em></span>\n <strong>{fmt.num(d.amount)}</strong>\n </div>\n ))}\n {drivers.length === 0 && <p className=\"bz-empty\">{t(\"noOut\")}</p>}\n </div>\n {levers.length > 0 && (\n <>\n <hr className=\"bz-rule\" />\n <p className=\"bz-eyebrow\">{t(\"levers\")}</p>\n <div className=\"bz-levers\">\n {levers.map((lever) => {\n const solo = computeSeries(s, new Set([lever.id]), levers);\n const on = active.has(lever.id);\n return (\n <label className={on ? \"bz-lever bz-on\" : \"bz-lever\"} key={lever.id}>\n <input\n type=\"checkbox\"\n checked={on}\n onChange={() => {\n touched.current = true;\n setActive((prev) => {\n const next = new Set(prev);\n if (next.has(lever.id)) next.delete(lever.id);\n else next.add(lever.id);\n return next;\n });\n }}\n />\n <span>\n <strong>{title(lever)}</strong>\n <em>\n {lever.kind === \"reserve\" && solo.low.balance >= 0\n ? t(\"effectSafe\", { date: fmt.shortDate(s.horizon_end) })\n : solo.low.balance === base.low.balance\n ? <>{t(\"effectEnd\", { date: fmt.shortDate(s.horizon_end), from: fmt.signed(base.end.balance), to: \"\" })}<b className={`bz-${tone(solo.end.balance)}`}>{fmt.signed(solo.end.balance)}</b></>\n : <>{t(\"effectLow\", { from: fmt.num(base.low.balance), to: \"\" })}<b className={`bz-${tone(solo.low.balance)}`}>{fmt.num(solo.low.balance)}</b></>}\n </em>\n </span>\n </label>\n );\n })}\n </div>\n {scenario && (\n <p className=\"bz-note\">{t(\"result\", { low: fmt.num(scenario.low.balance), date: fmt.shortDate(scenario.low.date), end: fmt.signed(scenario.end.balance) })}</p>\n )}\n <Button\n variant=\"ghost\"\n disabled={!scenario}\n onClick={() =>\n scenario &&\n onAction({\n type: \"save_scenario\",\n name: chosen.map(title).join(\" + \").slice(0, 120),\n levers: chosen.map((l) => ({ id: l.id, kind: l.kind, label: title(l), ref_id: l.event.ref_id, target: l.target, amount: l.reserve ? String(l.reserve) : l.event.amount })),\n low_before: String(base.low.balance),\n low_after: String(scenario.low.balance),\n })\n }\n >\n {t(\"save\")}\n </Button>\n </>\n )}\n </Card>\n </div>\n );\n },\n});\n\nfunction leverTitle(l: Lever, t: Translate, num: (v: number) => string, short: (d: string) => string): string {\n const amount = toNumber(l.event.amount);\n if (l.kind === \"split\") return t(\"split\", { label: l.event.label, a: num(amount / 2), b: num(amount / 2) });\n if (l.kind === \"reserve\") return t(\"reserve\", { amount: num(l.reserve ?? 0), date: short(l.event.date) });\n return t(\"defer\", { label: l.event.label, date: short(l.target) });\n}\n\n/** Up to three annotated drops: the main cycle's drivers, grouped by day. */\nfunction groupMarkers(s: Snapshot, num: (v: number) => string): { date: string; label: string }[] {\n const byDate = new Map<string, { labels: string[]; amount: number }>();\n for (const d of s.main_cycle.drivers) {\n const g = byDate.get(d.date) ?? { labels: [], amount: 0 };\n g.labels.push(shorten(d.label));\n g.amount += toNumber(d.amount);\n byDate.set(d.date, g);\n }\n return [...byDate.entries()].slice(0, 3).map(([date, g]) => ({\n date,\n label: `${g.labels.length <= 2 ? g.labels.join(\" + \") : `${g.labels[0]} +${g.labels.length - 1}`} −${num(g.amount)}`,\n }));\n}\n\n/** Keep whole words up to 18 characters: \"Carte de crédit solde\" → \"Carte de crédit\". */\nfunction shorten(label: string): string {\n if (label.length <= 18) return label;\n let out = \"\";\n for (const word of label.split(/\\s+/)) {\n const next = out ? `${out} ${word}` : word;\n if (next.length > 18) break;\n out = next;\n }\n return out || label.slice(0, 18);\n}\n","import availableNow from \"./available-now\";\nimport duePayday from \"./due-before-payday\";\nimport lowPoint from \"./low-point\";\nimport marginAfterPayday from \"./margin-after-payday\";\nimport monthlyStructure from \"./monthly-structure\";\nimport nextActions from \"./next-actions\";\nimport payCycles from \"./pay-cycles\";\nimport type { QuestionModule } from \"./types\";\nimport whatIf from \"./what-if\";\n\n/**\n * Every module, in the order the cockpit shows them. Adding a question = adding a\n * folder under src/modules/ and one line here (see CONTRIBUTING.md).\n */\nexport const MODULES: readonly QuestionModule<any>[] = [\n availableNow,\n duePayday,\n lowPoint,\n marginAfterPayday,\n whatIf,\n nextActions,\n monthlyStructure,\n payCycles,\n];\n\nexport function findModule(id: string): QuestionModule<any> | undefined {\n return MODULES.find((m) => m.id === id);\n}\n","import { useMemo } from \"react\";\n\nimport type { Snapshot } from \"../contract/snapshot\";\nimport { createFormatters } from \"../format\";\nimport { createT, type Locale } from \"../i18n\";\nimport { shared } from \"../i18n/shared\";\nimport { Card, Empty } from \"../primitives\";\nimport type { Horizon, ModuleAction, QuestionModule } from \"./types\";\n\nexport type QuestionProps = {\n module: QuestionModule<any>;\n snapshot: Snapshot;\n locale: Locale;\n horizon?: Horizon;\n onAction?: (action: ModuleAction) => void;\n};\n\n/** Render one module: select its model, build its translations, show an empty state when it cannot answer. */\nexport function Question({ module, snapshot, locale, horizon = \"cycles\", onAction = () => {} }: QuestionProps) {\n const ctx = useMemo(() => ({ locale, horizon }), [locale, horizon]);\n const t = useMemo(\n () =>\n createT(locale, shared, module.messages, {\n fr: { question: module.question.fr },\n de: { question: module.question.de },\n it: { question: module.question.it },\n rm: { question: module.question.rm },\n en: { question: module.question.en },\n }),\n [locale, module],\n );\n const fmt = useMemo(() => createFormatters(locale), [locale]);\n const model = useMemo(() => module.select(snapshot, ctx), [module, snapshot, ctx]);\n if (model === null) {\n return (\n <Card question={t(\"question\")}>\n <Empty>{t(\"notEnough\")}</Empty>\n </Card>\n );\n }\n const View = module.View;\n return <View model={model} t={t} fmt={fmt} ctx={ctx} onAction={onAction} />;\n}\n\nexport type DashboardProps = Omit<QuestionProps, \"module\"> & {\n modules: readonly QuestionModule<any>[];\n theme?: \"dark\" | \"light\";\n};\n\n/** The cockpit grid: tiles in a row of four, then wide/narrow/full modules on a three-column grid. */\nexport function Dashboard({ modules, theme = \"dark\", ...rest }: DashboardProps) {\n const tiles = modules.filter((m) => m.size === \"tile\");\n const others = modules.filter((m) => m.size !== \"tile\");\n return (\n <div className=\"bz\" data-theme={theme}>\n {tiles.length > 0 && (\n <section className=\"bz-tiles\">\n {tiles.map((m) => <Question key={m.id} module={m} {...rest} />)}\n </section>\n )}\n <section className=\"bz-grid\">\n {others.map((m) => (\n <div key={m.id} className={`bz-slot bz-slot-${m.size}`} data-module={m.id}>\n <Question module={m} {...rest} />\n </div>\n ))}\n </section>\n </div>\n );\n}\n","import { useLayoutEffect, useRef } from \"react\";\n\nimport type { Locale } from \"../i18n\";\nimport type { AnswerVisual } from \"./contract\";\nimport { MAX_WIDTH, MIN_WIDTH, drawVisual } from \"./draw\";\n\nexport type AnswerPictureProps = { visual: AnswerVisual | null | undefined; locale: Locale; className?: string };\n\nconst laidOutAt = (px: number) => Math.round(Math.min(Math.max(px || MAX_WIDTH, MIN_WIDTH), MAX_WIDTH));\n\n/**\n * The picture of an answer, drawn by the same code as in the assistants' card. Nothing when there is none.\n * It is laid out at the width of its container and redrawn when that width changes, so the labels keep\n * their size on a phone.\n */\nexport function AnswerPicture({ visual, locale, className }: AnswerPictureProps) {\n const host = useRef<HTMLDivElement>(null);\n useLayoutEffect(() => {\n const node = host.current;\n if (!node) return;\n let width = 0;\n const draw = () => {\n const next = laidOutAt(node.clientWidth);\n if (next === width) return;\n width = next;\n const svg = drawVisual(visual, locale, node.ownerDocument, { width });\n node.replaceChildren(...(svg ? [svg] : []));\n node.hidden = !svg;\n };\n draw();\n if (typeof ResizeObserver === \"undefined\") return;\n const observer = new ResizeObserver(draw);\n observer.observe(node);\n return () => observer.disconnect();\n }, [visual, locale]);\n return <div ref={host} className={className ? `bz-answer-picture ${className}` : \"bz-answer-picture\"} hidden={!visual} />;\n}\n"],"names":["shared","Card","question","title","meta","actions","children","className","jsxs","jsx","Tile","label","value","unit","note","tone","emphasis","Row","date","sub","amount","amountTone","late","Button","onClick","variant","disabled","Segmented","options","onChange","Dot","Empty","SHADES","DEFAULT_W","PAD","CashflowChart","props","ref","useRef","width","setWidth","useState","useEffect","el","observer","entry","w","Drawing","base","scenario","today","incomes","markers","labels","W","H","compact","all","p","n","ticks","niceTicks","min","max","x","i","y","v","idx","balanceOn","zeroY","bottom","lowI","lowX","axis","m","a","todayX","crowded","d","first","last","t","num","text","shortDate","flip","polyline","points","out","prev","count","raw","mag","step","s","lo","hi","buildLevers","snapshot","target","addDays","start","end","candidates","e","b","toNumber","levers","top","second","income","reserve","computeSeries","active","moved","on","l","byRef","lever","bank","sorted","perDay","balance","low","days","daysBetween","peak","round2","baseSeries","inflow","outflow","point","defineModule","module","LIQUID","availableNow","model","fmt","parts","duePayday","gap","short","Fragment","lowPoint","after","when","marginAfterPayday","monthlyStructure","cats","c","slices","sum","name","sl","GROUPS","nextActions","g","onAction","ActionRow","currency","payday","conf","tx","BillRow","detail","moveTo","payCycles","setAll","col","CycleColumn","missing","open","setOpen","items","groups","groupCycle","EventRow","lastItem","shortLabel","foreign","payable","total","big","bucket","flush","head","tail","word","next","HORIZONS","whatIf","ctx","cur","useMemo","touched","setActive","chosen","leverTitle","drivers","share","groupMarkers","solo","byDate","shorten","MODULES","findModule","id","Question","locale","horizon","createT","createFormatters","View","Dashboard","modules","theme","rest","tiles","others","laidOutAt","px","MAX_WIDTH","MIN_WIDTH","AnswerPicture","visual","host","useLayoutEffect","node","draw","svg","drawVisual"],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Snapshot } from "../contract/snapshot";
|
|
2
|
+
import { type Locale } from "../i18n";
|
|
3
|
+
import type { Horizon, ModuleAction, QuestionModule } from "./types";
|
|
4
|
+
export type QuestionProps = {
|
|
5
|
+
module: QuestionModule<any>;
|
|
6
|
+
snapshot: Snapshot;
|
|
7
|
+
locale: Locale;
|
|
8
|
+
horizon?: Horizon;
|
|
9
|
+
onAction?: (action: ModuleAction) => void;
|
|
10
|
+
};
|
|
11
|
+
/** Render one module: select its model, build its translations, show an empty state when it cannot answer. */
|
|
12
|
+
export declare function Question({ module, snapshot, locale, horizon, onAction }: QuestionProps): import("react").JSX.Element;
|
|
13
|
+
export type DashboardProps = Omit<QuestionProps, "module"> & {
|
|
14
|
+
modules: readonly QuestionModule<any>[];
|
|
15
|
+
theme?: "dark" | "light";
|
|
16
|
+
};
|
|
17
|
+
/** The cockpit grid: tiles in a row of four, then wide/narrow/full modules on a three-column grid. */
|
|
18
|
+
export declare function Dashboard({ modules, theme, ...rest }: DashboardProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
type Slice = {
|
|
2
|
+
category: string;
|
|
3
|
+
amount: number;
|
|
4
|
+
others?: string[];
|
|
5
|
+
};
|
|
6
|
+
type Model = {
|
|
7
|
+
fixed: string;
|
|
8
|
+
income: string;
|
|
9
|
+
ratio: string | null;
|
|
10
|
+
margin: string | null;
|
|
11
|
+
slices: Slice[];
|
|
12
|
+
currency: string;
|
|
13
|
+
missing: number;
|
|
14
|
+
debts: {
|
|
15
|
+
total: string;
|
|
16
|
+
items: {
|
|
17
|
+
name: string;
|
|
18
|
+
principal: string;
|
|
19
|
+
}[];
|
|
20
|
+
} | null;
|
|
21
|
+
target: string | null;
|
|
22
|
+
};
|
|
23
|
+
declare const _default: import("../types").QuestionModule<Model>;
|
|
24
|
+
export default _default;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Action } from "../../contract/snapshot";
|
|
2
|
+
type GroupKey = "late" | "beforePayday" | "toConfirm" | "toPlan";
|
|
3
|
+
type Model = {
|
|
4
|
+
groups: {
|
|
5
|
+
key: GroupKey;
|
|
6
|
+
items: Action[];
|
|
7
|
+
}[];
|
|
8
|
+
count: number;
|
|
9
|
+
currency: string;
|
|
10
|
+
payday: string | null;
|
|
11
|
+
};
|
|
12
|
+
declare const _default: import("../types").QuestionModule<Model>;
|
|
13
|
+
export default _default;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { CashEvent, Cycle } from "../../contract/snapshot";
|
|
2
|
+
type Group = {
|
|
3
|
+
key: string;
|
|
4
|
+
items: CashEvent[];
|
|
5
|
+
};
|
|
6
|
+
type Column = {
|
|
7
|
+
key: string;
|
|
8
|
+
title: {
|
|
9
|
+
kind: "before";
|
|
10
|
+
date: string;
|
|
11
|
+
} | {
|
|
12
|
+
kind: "cycle";
|
|
13
|
+
from: string;
|
|
14
|
+
to: string;
|
|
15
|
+
};
|
|
16
|
+
totalOut: string;
|
|
17
|
+
totalIn: string;
|
|
18
|
+
truncated: string | null;
|
|
19
|
+
cycle: Cycle;
|
|
20
|
+
};
|
|
21
|
+
type Model = {
|
|
22
|
+
columns: Column[];
|
|
23
|
+
outflows: number;
|
|
24
|
+
currency: string;
|
|
25
|
+
today: string;
|
|
26
|
+
missing: number;
|
|
27
|
+
};
|
|
28
|
+
declare const _default: import("../types").QuestionModule<Model>;
|
|
29
|
+
export default _default;
|
|
30
|
+
/** Big bills stand alone; small ones fold into one line per week (at most four per line). */
|
|
31
|
+
export declare function groupCycle(items: CashEvent[]): Group[];
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { QuestionModule } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* Every module, in the order the cockpit shows them. Adding a question = adding a
|
|
4
|
+
* folder under src/modules/ and one line here (see CONTRIBUTING.md).
|
|
5
|
+
*/
|
|
6
|
+
export declare const MODULES: readonly QuestionModule<any>[];
|
|
7
|
+
export declare function findModule(id: string): QuestionModule<any> | undefined;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import type { ComponentType } from "react";
|
|
2
|
+
import type { Decimal, IsoDate, Snapshot } from "../contract/snapshot";
|
|
3
|
+
import type { Formatters } from "../format";
|
|
4
|
+
import type { Catalog, Locale, Translate } from "../i18n";
|
|
5
|
+
/**
|
|
6
|
+
* What a module may ask the host to do. Modules never call the network: they emit
|
|
7
|
+
* an intent, the app executes it with the user's credentials and sends a fresh snapshot.
|
|
8
|
+
*/
|
|
9
|
+
export type ModuleAction = {
|
|
10
|
+
type: "mark_paid";
|
|
11
|
+
ref_id: string;
|
|
12
|
+
} | {
|
|
13
|
+
type: "reschedule";
|
|
14
|
+
ref_id: string;
|
|
15
|
+
date: IsoDate;
|
|
16
|
+
} | {
|
|
17
|
+
type: "classify_transaction";
|
|
18
|
+
ref_id: string;
|
|
19
|
+
internal_transfer: boolean;
|
|
20
|
+
} | {
|
|
21
|
+
type: "review_obligation";
|
|
22
|
+
ref_id: string;
|
|
23
|
+
decision: "accept" | "cancel";
|
|
24
|
+
} | {
|
|
25
|
+
type: "open";
|
|
26
|
+
target: "recurrences" | "balances" | "import" | "capture" | "obligations";
|
|
27
|
+
} | {
|
|
28
|
+
type: "set_horizon";
|
|
29
|
+
horizon: Horizon;
|
|
30
|
+
} | {
|
|
31
|
+
type: "save_scenario";
|
|
32
|
+
name: string;
|
|
33
|
+
levers: {
|
|
34
|
+
id: string;
|
|
35
|
+
kind: "split" | "defer" | "reserve";
|
|
36
|
+
label: string;
|
|
37
|
+
ref_id: string | null;
|
|
38
|
+
target: IsoDate;
|
|
39
|
+
amount: Decimal;
|
|
40
|
+
}[];
|
|
41
|
+
low_before: Decimal;
|
|
42
|
+
low_after: Decimal;
|
|
43
|
+
};
|
|
44
|
+
export type Horizon = "7" | "30" | "cycles" | "90";
|
|
45
|
+
/** Where a module sits in the page grid. */
|
|
46
|
+
export type ModuleSize = "tile" | "narrow" | "wide" | "full";
|
|
47
|
+
export type ModuleContext = {
|
|
48
|
+
locale: Locale;
|
|
49
|
+
/** Horizon the snapshot was computed for (the host refetches when it changes). */
|
|
50
|
+
horizon: Horizon;
|
|
51
|
+
};
|
|
52
|
+
export type ViewProps<Model> = {
|
|
53
|
+
model: Model;
|
|
54
|
+
t: Translate;
|
|
55
|
+
fmt: Formatters;
|
|
56
|
+
ctx: ModuleContext;
|
|
57
|
+
onAction: (action: ModuleAction) => void;
|
|
58
|
+
};
|
|
59
|
+
export type QuestionModule<Model = unknown> = {
|
|
60
|
+
/** Stable kebab-case id: it is part of the public API. */
|
|
61
|
+
id: string;
|
|
62
|
+
/** The money question this module answers, in the five languages. */
|
|
63
|
+
question: Record<Locale, string>;
|
|
64
|
+
size: ModuleSize;
|
|
65
|
+
/** Contract fields the module reads; the host can check them before rendering. */
|
|
66
|
+
reads: readonly (keyof Snapshot)[];
|
|
67
|
+
messages: Catalog;
|
|
68
|
+
/**
|
|
69
|
+
* Pure and deterministic: same snapshot, same model. Returns `null` when the
|
|
70
|
+
* snapshot does not contain enough to answer (the host shows an empty state).
|
|
71
|
+
* It selects and shapes numbers the engine already computed; it never forecasts.
|
|
72
|
+
*/
|
|
73
|
+
select: (snapshot: Snapshot, ctx: ModuleContext) => Model | null;
|
|
74
|
+
View: ComponentType<ViewProps<Model>>;
|
|
75
|
+
};
|
|
76
|
+
/** Identity helper that keeps the Model type flowing from `select` to `View`. */
|
|
77
|
+
export declare function defineModule<Model>(module: QuestionModule<Model>): QuestionModule<Model>;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { IsoDate } from "../contract/snapshot";
|
|
2
|
+
import type { Series } from "../engine/scenario";
|
|
3
|
+
export type ChartLabels = {
|
|
4
|
+
today: string;
|
|
5
|
+
payday: (date: string) => string;
|
|
6
|
+
aria: string;
|
|
7
|
+
};
|
|
8
|
+
type Props = {
|
|
9
|
+
base: Series;
|
|
10
|
+
scenario?: Series | null;
|
|
11
|
+
today: IsoDate;
|
|
12
|
+
incomes: IsoDate[];
|
|
13
|
+
markers: {
|
|
14
|
+
date: IsoDate;
|
|
15
|
+
label: string;
|
|
16
|
+
}[];
|
|
17
|
+
labels: ChartLabels;
|
|
18
|
+
};
|
|
19
|
+
export declare function CashflowChart(props: Props): import("react").JSX.Element;
|
|
20
|
+
/** Round ticks that always include 0 and enclose the data (8’000 / 4’000 / 0 / −4’000). */
|
|
21
|
+
export declare function niceTicks(min: number, max: number, count: number): number[];
|
|
22
|
+
export {};
|