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 (
);
}
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 (
{/* 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
/>
);
}