Add toasts, Settings tabs, Clients page and item presets (Phase E1)
- Global Carbon toast stack replaces scattered inline notices; errors persist until closed. - Settings is split into eight tabs with one Save and a remembered last tab; Numbering embeds the series settings. - New Clients page with a DataTable, shared add/edit modal, structured addresses, GST category (informational), per-client notes and payment terms. The composed address string is kept for back-compat. Deleting a client warns about invoice count; issued invoices keep their own snapshot. - Migration M7 adds the client columns and item_presets; existing clients with a GSTIN are backfilled to registered_regular. - New invoice form: client ComboBox with type-ahead and inline create, client defaults applied on selection, and an Add from preset control. - Rust tests for M7 (fresh and v6 upgrade), client validation and CRUD, presets CRUD; vitest for the toast store and new helpers. PDF output and fingerprint goldens are unchanged. The new UI has not been run in a webview yet.
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
const KEY = "voiced.settingsTab";
|
||||
|
||||
export const SETTINGS_TABS = [
|
||||
{ id: "business", label: "Business" },
|
||||
{ id: "branding", label: "Branding" },
|
||||
{ id: "bank", label: "Bank & payments" },
|
||||
{ id: "defaults", label: "Invoice defaults" },
|
||||
{ id: "numbering", label: "Numbering" },
|
||||
{ id: "templates", label: "Templates & export" },
|
||||
{ id: "fonts", label: "Fonts" },
|
||||
{ id: "data", label: "Data" },
|
||||
] as const;
|
||||
|
||||
export type SettingsTabId = (typeof SETTINGS_TABS)[number]["id"];
|
||||
|
||||
/** Index of a stored tab id; 0 (Business) for anything unknown. */
|
||||
export function parseSettingsTab(value: string | null | undefined): number {
|
||||
const index = SETTINGS_TABS.findIndex((t) => t.id === value);
|
||||
return index < 0 ? 0 : index;
|
||||
}
|
||||
|
||||
/** The last Settings tab this viewer used. A per-viewer convenience only. */
|
||||
export function loadSettingsTab(): number {
|
||||
try {
|
||||
return parseSettingsTab(localStorage.getItem(KEY));
|
||||
} catch {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
export function saveSettingsTab(index: number): void {
|
||||
try {
|
||||
const tab = SETTINGS_TABS[index];
|
||||
if (tab) localStorage.setItem(KEY, tab.id);
|
||||
} catch {
|
||||
// Not remembering is harmless.
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user