Files
Github-Star-Manager/src/app/store/preferences.ts
2026-04-11 16:18:35 +08:00

101 lines
2.3 KiB
TypeScript

import { useCallback, useSyncExternalStore } from "react";
import type { UiLanguagePreference } from "../i18n/language";
type Preferences = {
hasCompletedOnboarding: boolean;
readmeOptIn: boolean;
patToken: string;
viewerLogin: string;
lastSyncedAt: string;
uiLanguage: UiLanguagePreference;
};
const STORAGE_KEY = "star-manager.preferences";
const defaultPreferences: Preferences = {
hasCompletedOnboarding: false,
readmeOptIn: false,
patToken: "",
viewerLogin: "",
lastSyncedAt: "",
uiLanguage: "auto",
};
let cached = readFromStorage();
const listeners = new Set<() => void>();
function emitChange() {
for (const listener of listeners) {
listener();
}
}
function readFromStorage(): Preferences {
if (typeof window === "undefined") {
return { ...defaultPreferences };
}
try {
const raw = window.localStorage.getItem(STORAGE_KEY);
if (!raw) return { ...defaultPreferences };
const parsed = JSON.parse(raw) as Partial<Preferences>;
return {
...defaultPreferences,
...parsed,
};
} catch {
return { ...defaultPreferences };
}
}
function persist(next: Preferences) {
cached = next;
if (typeof window !== "undefined") {
window.localStorage.setItem(STORAGE_KEY, JSON.stringify(next));
}
emitChange();
}
export function usePreferenceStore() {
const state = useSyncExternalStore(
(onStoreChange) => {
listeners.add(onStoreChange);
return () => listeners.delete(onStoreChange);
},
() => cached,
() => cached
);
const setReadmeOptIn = useCallback((value: boolean) => {
persist({ ...cached, readmeOptIn: value });
}, []);
const markOnboarded = useCallback(() => {
persist({ ...cached, hasCompletedOnboarding: true });
}, []);
const setPatToken = useCallback((token: string, viewerLogin: string) => {
persist({ ...cached, patToken: token, viewerLogin });
}, []);
const setLastSyncedAt = useCallback((timestamp: string) => {
persist({ ...cached, lastSyncedAt: timestamp });
}, []);
const setUiLanguage = useCallback((value: UiLanguagePreference) => {
persist({ ...cached, uiLanguage: value });
}, []);
return {
preferences: state,
setReadmeOptIn,
markOnboarded,
setPatToken,
setLastSyncedAt,
setUiLanguage,
};
}
export function getPreferenceSnapshot(): Preferences {
return cached;
}