import { useEffect, useState } from 'react'; import { useNavigate } from 'react-router-dom'; import { ChevronRight, LogOut, Info, Shield, Mail, Mic, LifeBuoy, FileText, Volume2, ArrowLeft, Camera, Sun, Moon, Monitor, Palette, } from 'lucide-react'; import { HumanAvatar } from '@/components/human-avatar'; import { AvatarEditDialog } from '@/features/settings/avatar-edit-dialog'; import { Separator } from '@/components/ui/separator'; import { Switch } from '@/components/ui/switch'; import { ToggleGroup, ToggleGroupItem } from '@/components/ui/toggle-group'; import { WindowControls } from '@/components/window-controls'; import { Button } from '@/components/ui/button'; import { Muted } from '@/components/ui/typography'; import { ScrollArea } from '@/components/ui/scroll-area'; import { CopyableEmail } from '@/components/copyable-email'; import { useAuthStore } from '@/stores/auth-store'; import { useSoundEffectsStore } from '@/stores/sound-effects-store'; import { useThemeStore, type ThemeMode } from '@/stores/theme-store'; import { apiClient } from '@/api/client'; import { logError, toUserMessage } from '@/lib/errors'; import { toast } from 'sonner'; import { PRIVACY_URL, SUPPORT_EMAIL, TERMS_URL } from '@/lib/constants'; import { platform } from '@/lib/platform'; interface SettingsRowProps { icon: React.ReactNode; label: string; detail?: string; onClick?: () => void; destructive?: boolean; } function SettingsRow({ icon, label, detail, onClick, destructive, }: SettingsRowProps) { return ( ); } function SettingsGroup({ title, children, }: { title: string; children: React.ReactNode; }) { return (

{title}

{children}
); } const THEME_OPTIONS: { value: ThemeMode; label: string; icon: React.ReactNode; }[] = [ { value: 'system', label: 'System', icon: }, { value: 'light', label: 'Light', icon: }, { value: 'dark', label: 'Dark', icon: }, ]; function ThemeSetting() { const mode = useThemeStore((s) => s.mode); const setMode = useThemeStore((s) => s.setMode); return (
Theme value && setMode(value as ThemeMode)} className="border-border bg-muted/50 border p-0.5" spacing={2} > {THEME_OPTIONS.map((option) => ( {option.icon} {option.label} ))}
); } export default function SettingsPage() { const navigate = useNavigate(); const user = useAuthStore((s) => s.user); const signOut = useAuthStore((s) => s.signOut); const [emailNotifications, setEmailNotifications] = useState( user?.email_notifications_enabled ?? true, ); const soundEffectsEnabled = useSoundEffectsStore((s) => s.enabled); const setSoundEffectsEnabled = useSoundEffectsStore((s) => s.setEnabled); const [version, setVersion] = useState(); const [avatarOpen, setAvatarOpen] = useState(false); useEffect(() => { platform.app.getVersion().then(setVersion); }, []); const handleToggleEmailNotifications = async (checked: boolean) => { setEmailNotifications(checked); useAuthStore.setState((state) => ({ user: state.user ? { ...state.user, email_notifications_enabled: checked } : null, })); try { await apiClient.updateSettings({ email_notifications_enabled: checked }); } catch (err) { setEmailNotifications(!checked); useAuthStore.setState((state) => ({ user: state.user ? { ...state.user, email_notifications_enabled: !checked } : null, })); toast.error(toUserMessage(err)); logError(err, { scope: 'settings.emailNotifications' }); } }; const initials = user?.email_prefix?.slice(0, 2).toUpperCase() ?? '?'; return (
Settings
{/* Profile header */}

{user?.email_prefix}

{user?.email}
Email notifications
Sound effects
} label="Audio & Video" onClick={() => navigate('/settings/audio-video')} /> } label="Version" detail={version} /> } label="Privacy Policy" onClick={() => platform.link.openExternal(PRIVACY_URL)} /> } label="Terms of Service" onClick={() => platform.link.openExternal(TERMS_URL)} />

Email support

Questions, feedback, or bug reports
} label="Sign out" onClick={signOut} destructive />
); }