refactor phase 7-8

This commit is contained in:
alorig
2025-11-20 22:40:18 +05:00
parent 45dc0d1fa2
commit 3e142afc7a
11 changed files with 695 additions and 74 deletions

View File

@@ -1,28 +1,84 @@
/**
* Onboarding Store (Zustand)
* Manages welcome/guide screen state and dismissal
* Syncs with backend UserSettings for cross-device persistence
*/
import { create } from 'zustand';
import { persist } from 'zustand/middleware';
import { fetchUserSetting, createUserSetting, updateUserSetting } from '../services/api';
interface OnboardingState {
isGuideDismissed: boolean;
isGuideVisible: boolean;
isLoading: boolean;
lastSyncedAt: Date | null;
// Actions
dismissGuide: () => void;
dismissGuide: () => Promise<void>;
showGuide: () => void;
toggleGuide: () => void;
loadFromBackend: () => Promise<void>;
syncToBackend: (dismissed: boolean) => Promise<void>;
}
const GUIDE_SETTING_KEY = 'workflow_guide_dismissed';
export const useOnboardingStore = create<OnboardingState>()(
persist<OnboardingState>(
(set) => ({
(set, get) => ({
isGuideDismissed: false,
isGuideVisible: false,
isLoading: false,
lastSyncedAt: null,
loadFromBackend: async () => {
set({ isLoading: true });
try {
const setting = await fetchUserSetting(GUIDE_SETTING_KEY);
const dismissed = setting.value?.dismissed === true;
set({
isGuideDismissed: dismissed,
isGuideVisible: !dismissed,
lastSyncedAt: new Date(),
isLoading: false
});
} catch (error: any) {
// 404 means setting doesn't exist yet - that's fine, use local state
if (error.status !== 404) {
console.warn('Failed to load guide dismissal from backend:', error);
}
set({ isLoading: false });
}
},
syncToBackend: async (dismissed: boolean) => {
try {
const data = { value: { dismissed, dismissed_at: new Date().toISOString() } };
try {
await updateUserSetting(GUIDE_SETTING_KEY, data);
} catch (error: any) {
// If setting doesn't exist, create it
if (error.status === 404) {
await createUserSetting({ key: GUIDE_SETTING_KEY, value: data.value });
} else {
throw error;
}
}
set({ lastSyncedAt: new Date() });
} catch (error) {
console.warn('Failed to sync guide dismissal to backend:', error);
// Don't throw - local state is still updated
}
},
dismissGuide: async () => {
set({ isGuideDismissed: true, isGuideVisible: false });
// Sync to backend asynchronously
await get().syncToBackend(true);
},
dismissGuide: () => set({ isGuideDismissed: true, isGuideVisible: false }),
showGuide: () => set({ isGuideVisible: true }),
toggleGuide: () => set((state) => ({ isGuideVisible: !state.isGuideVisible })),
}),
{