File size: 3,931 Bytes
5c876be | 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 115 116 | /**
* Authentication & user state store.
*
* Manages the current user session, authentication status, and
* onboarding completion. Uses Zustand v5 with immer middleware
* for ergonomic partial updates.
*/
import { create } from 'zustand';
import { immer } from 'zustand/middleware/immer';
import type { User, UserRole } from '../types/user';
// βββ State Shape βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
interface AuthState {
/** Whether the user has a valid auth session */
isAuthenticated: boolean;
/** The currently logged-in user (null when logged out) */
user: User | null;
/** Whether the user has completed the onboarding flow */
isOnboarded: boolean;
/** Whether auth state is currently being restored (e.g., on app launch) */
isRestoring: boolean;
}
// βββ Actions βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
interface AuthActions {
/** Mark the user as authenticated with their full profile */
setAuth: (user: User) => void;
/** Set / replace the user object (e.g., after profile update) */
setUser: (user: User) => void;
/** Mark onboarding as completed */
setOnboarded: (value: boolean) => void;
/** Log out: clear all auth state */
logout: () => void;
/** Apply partial updates to the current user */
updateUser: (partial: Partial<User>) => void;
/** Set the restoring flag (shown during app startup) */
setRestoring: (value: boolean) => void;
/** Check authentication state (e.g., on app launch from persisted data) */
checkAuth: () => void;
}
// βββ Store βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
export const useAuthStore = create<AuthState & AuthActions>()(
immer((set) => ({
// Initial state
isAuthenticated: false,
user: null,
isOnboarded: false,
isRestoring: true,
// Actions
setAuth: (user) =>
set((state) => {
state.isAuthenticated = true;
state.user = user;
state.isRestoring = false;
}),
setUser: (user) =>
set((state) => {
state.user = user;
}),
setOnboarded: (value) =>
set((state) => {
state.isOnboarded = value;
}),
logout: () =>
set((state) => {
state.isAuthenticated = false;
state.user = null;
state.isOnboarded = false;
state.isRestoring = false;
}),
updateUser: (partial) =>
set((state) => {
if (state.user) {
Object.assign(state.user, partial);
}
}),
setRestoring: (value) =>
set((state) => {
state.isRestoring = value;
}),
checkAuth: () =>
set((state) => {
// In a real app this would check SQLite / SecureStore for a persisted
// user session. For now we simply mark restoring as complete.
state.isRestoring = false;
}),
})),
);
// βββ Selectors βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
export const selectIsRider = (state: AuthState) =>
state.user?.currentRole === 'rider';
export const selectIsPassenger = (state: AuthState) =>
state.user?.currentRole === 'passenger';
export const selectUserDisplayName = (state: AuthState) =>
state.user?.displayName ?? '';
export const selectUserAvatar = (state: AuthState) =>
state.user?.avatarUrl ?? null;
export const selectUserId = (state: AuthState) => state.user?.id ?? null;
|