refactor(frontend): adopt store/storage helpers; centralize persistence
- errorDialog + hints now use createStore (drop their bespoke listener arrays). - theme/sidebarLayout/notifications/App filters/Playlists plSort use readMerged/ readJSON/writeJSON instead of inline try/JSON.parse/catch. - Stats, SettingsPanel and App's channel filter/view tabs use usePersistedState (the 3 sites that reinvented usePersistedTab inline). - Every siftlode.* key now sourced from the LS registry (no scattered literals).
This commit is contained in:
parent
634921b35a
commit
472aba6480
15 changed files with 80 additions and 147 deletions
|
|
@ -2,6 +2,7 @@
|
|||
// the Notification Center shows (info events, actions awaiting interaction, and app
|
||||
// errors). History is persisted to localStorage so it survives reloads; action
|
||||
// callbacks are live-only and dropped on reload.
|
||||
import { LS, readJSON, readMerged, writeJSON } from "./storage";
|
||||
|
||||
export type NotifLevel = "info" | "success" | "warning" | "error" | "fatal";
|
||||
|
||||
|
|
@ -71,8 +72,8 @@ export interface NotifyInput {
|
|||
transient?: boolean; // live status: sticky toast, not persisted (see Notification.transient)
|
||||
}
|
||||
|
||||
const HISTORY_KEY = "siftlode.notifications";
|
||||
const SETTINGS_KEY = "siftlode.notifSettings";
|
||||
const HISTORY_KEY = LS.notifHistory;
|
||||
const SETTINGS_KEY = LS.notifSettings;
|
||||
const MAX_HISTORY = 100;
|
||||
const ERROR_TTL = 15000;
|
||||
|
||||
|
|
@ -86,11 +87,7 @@ const DEFAULT_SETTINGS: NotifSettings = { sound: false, durationMs: 6000 };
|
|||
let config: NotifSettings = loadSettings();
|
||||
|
||||
function loadSettings(): NotifSettings {
|
||||
try {
|
||||
return { ...DEFAULT_SETTINGS, ...JSON.parse(localStorage.getItem(SETTINGS_KEY) || "{}") };
|
||||
} catch {
|
||||
return DEFAULT_SETTINGS;
|
||||
}
|
||||
return readMerged(SETTINGS_KEY, DEFAULT_SETTINGS);
|
||||
}
|
||||
|
||||
export function getNotifSettings(): NotifSettings {
|
||||
|
|
@ -99,11 +96,7 @@ export function getNotifSettings(): NotifSettings {
|
|||
|
||||
export function configureNotifications(p: Partial<NotifSettings>): void {
|
||||
config = { ...config, ...p };
|
||||
try {
|
||||
localStorage.setItem(SETTINGS_KEY, JSON.stringify(config));
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
writeJSON(SETTINGS_KEY, config);
|
||||
}
|
||||
|
||||
let audioCtx: AudioContext | null = null;
|
||||
|
|
@ -137,7 +130,7 @@ let cachedUnread = 0;
|
|||
|
||||
function load(): Notification[] {
|
||||
try {
|
||||
const raw = JSON.parse(localStorage.getItem(HISTORY_KEY) || "[]");
|
||||
const raw = readJSON<unknown>(HISTORY_KEY, []);
|
||||
if (!Array.isArray(raw)) return [];
|
||||
// Restored entries are history only. Mark them dismissed so they don't
|
||||
// resurrect as active toasts on reload — their auto-dismiss timers aren't
|
||||
|
|
@ -154,7 +147,7 @@ function persist() {
|
|||
// Transient status notices are live-session only — never write them to history,
|
||||
// so a reload can't leave one stranded with no producer left to clear it.
|
||||
const slim = items.filter((n) => !n.transient).map(({ action: _action, ...n }) => n);
|
||||
localStorage.setItem(HISTORY_KEY, JSON.stringify(slim));
|
||||
writeJSON(HISTORY_KEY, slim);
|
||||
} catch {
|
||||
/* ignore quota / serialization errors */
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue