| /** | |
| * Global app preferences & UI state store. | |
| * | |
| * Manages cross-cutting concerns like the user's current role, | |
| * online status, and theme preference. These are persisted | |
| * separately from auth because they survive logouts. | |
| */ | |
| import { create } from 'zustand'; | |
| import { persist, createJSONStorage } from 'zustand/middleware'; | |
| import type { UserRole } from '../types/user'; | |
| // βββ State Shape βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| interface AppState { | |
| /** The role the user is currently acting as (rider or passenger) */ | |
| currentRole: UserRole; | |
| /** Whether the user is visible to others as online */ | |
| isOnline: boolean; | |
| /** Whether dark mode is active */ | |
| isDarkMode: boolean; | |
| /** Whether push notifications are enabled */ | |
| notificationsEnabled: boolean; | |
| } | |
| // βββ Actions βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| interface AppActions { | |
| /** Switch between rider and passenger mode */ | |
| setRole: (role: UserRole) => void; | |
| /** Toggle online/offline visibility */ | |
| setOnline: (value: boolean) => void; | |
| /** Toggle dark mode */ | |
| setDarkMode: (value: boolean) => void; | |
| /** Toggle notifications */ | |
| setNotificationsEnabled: (value: boolean) => void; | |
| } | |
| // βββ Persisted Store βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| export const useAppStore = create<AppState & AppActions>()( | |
| persist( | |
| (set) => ({ | |
| // Initial / default state | |
| currentRole: 'rider' as UserRole, | |
| isOnline: true, | |
| isDarkMode: false, | |
| notificationsEnabled: true, | |
| // Actions | |
| setRole: (role) => | |
| set({ currentRole: role }), | |
| setOnline: (value) => | |
| set({ isOnline: value }), | |
| setDarkMode: (value) => | |
| set({ isDarkMode: value }), | |
| setNotificationsEnabled: (value) => | |
| set({ notificationsEnabled: value }), | |
| }), | |
| { | |
| name: 'antaram-app-storage', | |
| storage: createJSONStorage(() => { | |
| // AsyncStorage will be used in React Native by default when available | |
| // This also falls back to localStorage in web / Expo web | |
| try { | |
| // eslint-disable-next-line @typescript-eslint/no-require-imports | |
| const { AsyncStorage } = require('@react-native-async-storage/async-storage'); | |
| return AsyncStorage; | |
| } catch { | |
| // Web fallback | |
| return localStorage; | |
| } | |
| }), | |
| // Only persist these specific keys | |
| partialize: (state) => ({ | |
| currentRole: state.currentRole, | |
| isOnline: state.isOnline, | |
| isDarkMode: state.isDarkMode, | |
| notificationsEnabled: state.notificationsEnabled, | |
| }), | |
| }, | |
| ), | |
| ); | |
| // βββ Selectors βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| export const selectIsRider = (state: AppState) => state.currentRole === 'rider'; | |
| export const selectIsPassenger = (state: AppState) => state.currentRole === 'passenger'; | |