Files
firefly-ui/src/lib/components/receipt/fields.ts
T
hh 349a6a0b32 feat(transactions): the transaction page as a receipt with context
The amount is the headline, notes come first at full width, then the
last twelve visits to the same place as a dot timeline next to the
paying account's days around it with the running balance. Fields edit in
place: j and k move, Enter opens and saves, Esc cancels, s c, s b, s t
and s s jump to classification. A matching subscription shows as a
suggestion, L links it.
2026-10-16 15:51:00 +00:00

77 lines
1.9 KiB
TypeScript

import type { Split } from "#lib/api/types.js";
import {
isEditableType,
SHARED,
type Side,
} from "#lib/components/editor/model.js";
export type FieldName =
| "date"
| "description"
| "amount"
| "source"
| "destination"
| "category"
| "budget"
| "tags"
| "bill"
| "notes";
export interface Row {
field: FieldName;
index: number;
key: string;
}
export const FIELD_LABEL: Record<FieldName, string> = {
amount: "amount",
bill: "subscription",
budget: "budget",
category: "category",
date: "date",
description: "description",
destination: "destination account",
notes: "notes",
source: "source account",
tags: "tags",
};
const SIDES: Side[] = ["source", "destination"];
export const rowKey = (field: FieldName, index: number) => `${index}:${field}`;
export function rowsOf(splits: Split[]): Row[] {
const type = splits[0]?.type ?? "";
if (!isEditableType(type)) {
return [];
}
const many = splits.length > 1;
const withdrawal = type === "withdrawal";
const locked = splits.some((split) => split.reconciled);
const shared = SIDES.filter((side) => SHARED[type][side]);
const top: FieldName[] = many
? ["date", ...(locked ? [] : shared)]
: [
"date",
"description",
...(locked ? [] : (["amount", ...SIDES] as FieldName[])),
];
const own = (split: Split): FieldName[] => [
...(many ? (["description"] as const) : []),
...(many && !split.reconciled
? ["amount" as const, ...SIDES.filter((side) => !SHARED[type][side])]
: []),
"category",
...(withdrawal ? (["budget"] as const) : []),
"tags",
...(withdrawal ? (["bill"] as const) : []),
"notes",
];
return [
...top.map((field) => ({ field, index: 0 })),
...splits.flatMap((split, index) =>
own(split).map((field) => ({ field, index }))
),
].map((row) => ({ ...row, key: rowKey(row.field, row.index) }));
}