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;