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 | 2x 2x 2x 1x 1x 6x 6x 1x 1x 22x 6x 22x 6x 22x 22x 6x 22x 7x 1x 6x 22x 6x 6x 6x 6x 6x 6x 1x 1x 1x 1x 1x 6x 6x 22x | import { useState, useEffect, type Dispatch, type SetStateAction } from 'react'
import { api, type Profile } from '../api/client'
const PROFILE_STORAGE_KEY = 'cookie_selected_profile_id'
export function saveProfileId(id: number) {
localStorage.setItem(PROFILE_STORAGE_KEY, String(id))
document.cookie = `selected_profile_id=${id};path=/;SameSite=Lax`
}
export function clearProfileId() {
localStorage.removeItem(PROFILE_STORAGE_KEY)
document.cookie = 'selected_profile_id=;path=/;expires=Thu, 01 Jan 1970 00:00:00 GMT'
}
function getStoredProfileId(): number | null {
const stored = localStorage.getItem(PROFILE_STORAGE_KEY)
if (!stored) return null
const id = parseInt(stored, 10)
return isNaN(id) ? null : id
}
interface AuthProfile {
id: number
name: string
avatar_color: string
theme: string
unit_preference: string
}
interface UseStoredProfileReturn {
profile: Profile | null
setProfile: Dispatch<SetStateAction<Profile | null>>
theme: 'light' | 'dark'
setTheme: Dispatch<SetStateAction<'light' | 'dark'>>
loading: boolean
}
/**
* Manages profile restoration from localStorage (home mode) or auth (passkey mode).
* Applies the theme class to the document element.
*/
export function useStoredProfile(authProfile?: AuthProfile | null): UseStoredProfileReturn {
const [profile, setProfile] = useState<Profile | null>(() =>
authProfile ? (authProfile as Profile) : null
)
const [theme, setTheme] = useState<'light' | 'dark'>(() =>
authProfile ? (authProfile.theme as 'light' | 'dark') : 'light'
)
const [loading, setLoading] = useState(authProfile === undefined)
// Sync auth profile changes to state (passkey mode)
useEffect(() => {
Eif (authProfile === undefined) return
const id = requestAnimationFrame(() => {
if (authProfile) {
setProfile(authProfile as Profile)
setTheme(authProfile.theme as 'light' | 'dark')
} else {
setProfile(null)
}
setLoading(false)
})
return () => cancelAnimationFrame(id)
}, [authProfile])
// Apply theme class to document
useEffect(() => {
if (theme === 'dark') {
document.documentElement.classList.add('dark')
} else {
document.documentElement.classList.remove('dark')
}
}, [theme])
// Restore profile from localStorage (home mode only)
useEffect(() => {
Iif (authProfile !== undefined) return
let cancelled = false
;(async () => {
try {
const storedId = getStoredProfileId()
if (storedId) {
try {
const restored = await api.profiles.select(storedId)
Eif (!cancelled) {
setProfile(restored)
setTheme(restored.theme as 'light' | 'dark')
}
} catch {
clearProfileId()
}
}
} catch (error) {
console.error('Failed to restore session:', error)
} finally {
Eif (!cancelled) setLoading(false)
}
})()
return () => { cancelled = true }
}, [authProfile])
return { profile, setProfile, theme, setTheme, loading }
}
|