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 107 | 46x 46x 46x 46x 46x 46x 46x 46x 46x 17x 16x 46x 2x 2x 2x 46x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 46x 1x 1x 1x 46x 17x 29x 6x 29x 29x 11x | import { useState, useEffect } from 'react'
import { useNavigate } from 'react-router-dom'
import { Plus } from 'lucide-react'
import { toast } from 'sonner'
import { api, type Profile, type ProfileInput } from '../api/client'
import { useProfile } from '../contexts/ProfileContext'
import CreateProfileForm, { PROFILE_COLORS } from '../components/CreateProfileForm'
export default function ProfileSelector() {
const navigate = useNavigate()
const { selectProfile } = useProfile()
const [profiles, setProfiles] = useState<Profile[]>([])
const [loading, setLoading] = useState(true)
const [showCreateForm, setShowCreateForm] = useState(false)
const [newName, setNewName] = useState('')
const [selectedColor, setSelectedColor] = useState(PROFILE_COLORS[0])
const [creating, setCreating] = useState(false)
useEffect(() => {
api.profiles.list()
.then(setProfiles)
.catch((error) => {
console.error('Failed to load profiles:', error)
toast.error('Failed to load profiles')
})
.finally(() => setLoading(false))
}, [])
const handleProfileSelect = async (profile: Profile) => {
try {
await selectProfile(profile)
navigate('/home')
} catch (error) {
console.error('Failed to select profile:', error)
toast.error('Failed to select profile')
}
}
const handleCreateProfile = async (e: React.FormEvent) => {
e.preventDefault()
Iif (!newName.trim()) return
setCreating(true)
try {
const data: ProfileInput = { name: newName.trim(), avatar_color: selectedColor, theme: 'light', unit_preference: 'metric' }
const profile = await api.profiles.create(data)
setProfiles([...profiles, profile])
await selectProfile(profile)
toast.success(`Welcome, ${profile.name}!`)
navigate('/home')
} catch (error) {
console.error('Failed to create profile:', error)
toast.error('Failed to create profile')
} finally {
setCreating(false)
}
}
const handleCancelCreate = () => {
setShowCreateForm(false)
setNewName('')
setSelectedColor(PROFILE_COLORS[0])
}
if (loading) {
return (
<div className="flex min-h-screen items-center justify-center bg-background">
<div className="text-muted-foreground">Loading...</div>
</div>
)
}
return (
<div className="flex min-h-screen flex-col items-center justify-center bg-background px-4">
<div className="w-full max-w-md text-center">
<h1 className="mb-2 text-4xl font-medium text-primary">Cookie</h1>
<p className="mb-10 text-muted-foreground">Who's cooking today?</p>
<ProfileGrid profiles={profiles} onSelect={handleProfileSelect} onAddClick={() => setShowCreateForm(true)} />
{showCreateForm && (
<CreateProfileForm newName={newName} onNameChange={setNewName} selectedColor={selectedColor} onColorChange={setSelectedColor} creating={creating} onSubmit={handleCreateProfile} onCancel={handleCancelCreate} />
)}
</div>
</div>
)
}
function ProfileGrid({ profiles, onSelect, onAddClick }: { profiles: Profile[]; onSelect: (p: Profile) => void; onAddClick: () => void }) {
const getInitial = (name: string) => name.charAt(0).toUpperCase()
return (
<div className="mb-8 flex flex-wrap justify-center gap-6">
{profiles.map((profile) => (
<button key={profile.id} onClick={() => onSelect(profile)} className="group flex flex-col items-center gap-2">
<div className="flex h-20 w-20 items-center justify-center rounded-full text-2xl font-medium text-white transition-transform group-hover:scale-105" style={{ backgroundColor: profile.avatar_color }}>
{getInitial(profile.name)}
</div>
<span className="text-sm text-foreground">{profile.name}</span>
</button>
))}
<button onClick={onAddClick} className="group flex flex-col items-center gap-2">
<div className="flex h-20 w-20 items-center justify-center rounded-full border-2 border-dashed border-muted-foreground/40 transition-colors group-hover:border-primary">
<Plus className="h-8 w-8 text-muted-foreground/60 group-hover:text-primary" />
</div>
<span className="text-sm text-muted-foreground">Add Profile</span>
</button>
</div>
)
}
|