add parent pages

This commit is contained in:
root
2026-04-23 02:24:05 -04:00
parent 9191fd32f0
commit 94700d4f0f
30 changed files with 8179 additions and 634 deletions
+63 -7
View File
@@ -14,9 +14,16 @@ export type { AuthUser }
type AuthState = {
token: string | null
user: AuthUser | null
selectedRole: string | null
}
const STORAGE_USER = 'alrahma_api_user'
const STORAGE_ROLE = 'alrahma_selected_role'
function enabledRoles(user: AuthUser | null): string[] {
if (!user?.roles) return []
return Object.keys(user.roles).filter((k) => user.roles[k])
}
function readUser(): AuthUser | null {
try {
@@ -33,11 +40,30 @@ function writeUser(user: AuthUser | null): void {
else localStorage.removeItem(STORAGE_USER)
}
function readSelectedRole(): string | null {
const role = localStorage.getItem(STORAGE_ROLE)
return role && role.trim() ? role : null
}
function writeSelectedRole(role: string | null): void {
if (role) localStorage.setItem(STORAGE_ROLE, role)
else localStorage.removeItem(STORAGE_ROLE)
}
function validSelectedRole(user: AuthUser | null, role: string | null): string | null {
if (!role) return null
const roles = enabledRoles(user)
return roles.includes(role) ? role : null
}
let memory: AuthState = {
token: getStoredToken(),
user: readUser(),
selectedRole: null,
}
memory.selectedRole = validSelectedRole(memory.user, readSelectedRole())
const listeners = new Set<() => void>()
function emit(): void {
@@ -59,9 +85,11 @@ function getSnapshot(): AuthState {
}
export function hydrateAuthFromStorage(): void {
const user = readUser()
memory = {
token: getStoredToken(),
user: readUser(),
user,
selectedRole: validSelectedRole(user, readSelectedRole()),
}
emit()
}
@@ -77,22 +105,42 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
message: result.message ?? 'Login failed.',
}
}
const roles = enabledRoles(result.user)
const nextRole = roles.length === 1 ? roles[0] : null
setStoredToken(result.token)
writeUser(result.user)
setAuth({ token: result.token, user: result.user })
return { ok: true as const }
writeSelectedRole(nextRole)
setAuth({ token: result.token, user: result.user, selectedRole: nextRole })
return {
ok: true as const,
requiresRoleSelection: roles.length > 1,
roles,
selectedRole: nextRole,
}
}, [])
const logout = useCallback(() => {
setStoredToken(null)
writeUser(null)
setAuth({ token: null, user: null })
writeSelectedRole(null)
setAuth({ token: null, user: null, selectedRole: null })
}, [])
const setSession = useCallback((token: string, user: AuthUser) => {
const roles = enabledRoles(user)
const nextRole = roles.length === 1 ? roles[0] : null
setStoredToken(token)
writeUser(user)
setAuth({ token, user })
writeSelectedRole(nextRole)
setAuth({ token, user, selectedRole: nextRole })
}, [])
const setSelectedRole = useCallback((role: string | null) => {
const roles = enabledRoles(memory.user)
const nextRole = role && roles.includes(role) ? role : null
writeSelectedRole(nextRole)
setAuth({ ...memory, selectedRole: nextRole })
}, [])
const value = useMemo(
@@ -100,11 +148,14 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
login,
logout,
setSession,
setSelectedRole,
token: state.token,
user: state.user,
selectedRole: state.selectedRole,
roles: enabledRoles(state.user),
isAuthenticated: Boolean(state.token && state.user),
}),
[state.token, state.user, login, logout, setSession],
[state.token, state.user, state.selectedRole, login, logout, setSession, setSelectedRole],
)
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>
@@ -114,11 +165,16 @@ type AuthContextValue = {
login: (
email: string,
password: string,
) => Promise<{ ok: true } | { ok: false; message: string }>
) => Promise<
{ ok: true; requiresRoleSelection: boolean; roles: string[]; selectedRole: string | null } | { ok: false; message: string }
>
logout: () => void
setSession: (token: string, user: AuthUser) => void
setSelectedRole: (role: string | null) => void
token: string | null
user: AuthUser | null
selectedRole: string | null
roles: string[]
isAuthenticated: boolean
}