Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 | 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 2x 2x 2x 2x 6x 6x 3x 3x 25x 25x 25x 25x | /**
* UI Store
* Story 1.17, Task 5b: Zustand UI store implementation
*
* Manages UI state including locale, sidebar state, notification drawer, and user menu.
* Persists locale and sidebar state to localStorage.
*/
import { create } from 'zustand';
import type { UserRole } from '@/types/auth';
type Locale = 'de' | 'en';
interface UIState {
locale: Locale;
sidebarCollapsed: boolean;
notificationDrawerOpen: boolean;
userMenuOpen: boolean;
/** Active role filter for the nav RoleSelector; null means "no preference / single-role user". */
activeNavRole: UserRole | null;
}
interface UIActions {
setLocale: (locale: Locale) => void;
toggleSidebar: () => void;
setSidebarCollapsed: (collapsed: boolean) => void;
setNotificationDrawerOpen: (open: boolean) => void;
setUserMenuOpen: (open: boolean) => void;
setActiveNavRole: (role: UserRole | null) => void;
reset: () => void;
}
type UIStore = UIState & UIActions;
const initialState: UIState = {
locale: 'de', // German as default
sidebarCollapsed: false,
notificationDrawerOpen: false,
userMenuOpen: false,
activeNavRole: null,
};
// Initialize locale from localStorage if available
const getInitialLocale = (): Locale => {
const stored = localStorage.getItem('batbern-ui-locale');
Iif (stored) {
try {
const parsed = JSON.parse(stored);
return parsed === 'en' ? 'en' : 'de';
} catch {
return 'de';
}
}
return 'de';
};
const getInitialSidebarState = (): boolean => {
const stored = localStorage.getItem('batbern-ui-sidebar');
return stored === 'true';
};
const VALID_ROLES: ReadonlySet<UserRole> = new Set(['organizer', 'partner', 'speaker', 'attendee']);
const getInitialActiveNavRole = (): UserRole | null => {
const stored = localStorage.getItem('batbern-ui-active-nav-role');
Eif (!stored) return null;
return VALID_ROLES.has(stored as UserRole) ? (stored as UserRole) : null;
};
export const useUIStore = create<UIStore>()((set) => ({
locale: getInitialLocale(),
sidebarCollapsed: getInitialSidebarState(),
notificationDrawerOpen: false,
userMenuOpen: false,
activeNavRole: getInitialActiveNavRole(),
setLocale: (locale) => {
localStorage.setItem('batbern-ui-locale', JSON.stringify(locale));
set(() => ({ locale }));
},
toggleSidebar: () =>
set((state) => {
const newValue = !state.sidebarCollapsed;
localStorage.setItem('batbern-ui-sidebar', String(newValue));
return { sidebarCollapsed: newValue };
}),
setSidebarCollapsed: (sidebarCollapsed) => {
localStorage.setItem('batbern-ui-sidebar', String(sidebarCollapsed));
set(() => ({ sidebarCollapsed }));
},
setNotificationDrawerOpen: (notificationDrawerOpen) => set(() => ({ notificationDrawerOpen })),
setUserMenuOpen: (userMenuOpen) => set(() => ({ userMenuOpen })),
setActiveNavRole: (activeNavRole) => {
if (activeNavRole) {
localStorage.setItem('batbern-ui-active-nav-role', activeNavRole);
} else {
localStorage.removeItem('batbern-ui-active-nav-role');
}
set(() => ({ activeNavRole }));
},
reset: () => {
localStorage.removeItem('batbern-ui-locale');
localStorage.removeItem('batbern-ui-sidebar');
localStorage.removeItem('batbern-ui-active-nav-role');
set(() => ({ ...initialState }));
},
}));
|