Add src/services/dataEvents.ts (ADR 0022): notifyDataChanged() and subscribeDataChanged(), without React, on the model of logService.subscribe. A throwing subscriber is logged and does not stop the others. Notify after every successful write of the tables the getting-started counters read, plus the import folder: setImportFolder, createSource, deleteSource, createImportedFile, updateFileStatus, both import deletions, insertBatch, updateTransactionCategory, applyKeywordWithReassignment (after COMMIT), the four budget writes and runRestore (after COMMIT, one point for the three restore modes). executeImport notifies once more when it ends, succeeded or not. A failed write notifies nothing; transactional writes notify once withTransaction has returned. applyTemplate notifies once for the whole template through a private writeBudgetEntry helper. Each service suite proves the notification after a success and its absence after a failure; executeImport is driven as a plain function with React's hooks stubbed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
46 lines
1.3 KiB
TypeScript
46 lines
1.3 KiB
TypeScript
import { getDb } from "./db";
|
|
import { notifyDataChanged } from "./dataEvents";
|
|
import type { UserPreference } from "../shared/types";
|
|
|
|
export async function getPreference(key: string): Promise<string | null> {
|
|
const db = await getDb();
|
|
const rows = await db.select<UserPreference[]>(
|
|
"SELECT * FROM user_preferences WHERE key = $1",
|
|
[key]
|
|
);
|
|
return rows.length > 0 ? rows[0].value : null;
|
|
}
|
|
|
|
export async function setPreference(
|
|
key: string,
|
|
value: string
|
|
): Promise<void> {
|
|
const db = await getDb();
|
|
await db.execute(
|
|
`INSERT INTO user_preferences (key, value, updated_at)
|
|
VALUES ($1, $2, CURRENT_TIMESTAMP)
|
|
ON CONFLICT(key) DO UPDATE SET value = $2, updated_at = CURRENT_TIMESTAMP`,
|
|
[key, value]
|
|
);
|
|
}
|
|
|
|
export async function deletePreference(key: string): Promise<void> {
|
|
const db = await getDb();
|
|
await db.execute(
|
|
"DELETE FROM user_preferences WHERE key = $1",
|
|
[key]
|
|
);
|
|
}
|
|
|
|
export async function getImportFolder(): Promise<string | null> {
|
|
return getPreference("import_folder");
|
|
}
|
|
|
|
/**
|
|
* Stores the import folder. The getting-started path counts it as a step, so
|
|
* a successful write is announced on the data channel (ADR 0022).
|
|
*/
|
|
export async function setImportFolder(path: string): Promise<void> {
|
|
await setPreference("import_folder", path);
|
|
notifyDataChanged();
|
|
}
|