All files / src/stores uiStore.ts

77.27% Statements 34/44
20% Branches 2/10
88.88% Functions 16/18
75% Lines 27/36

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 }));
  },
}));