import { useCallback, useEffect, useMemo, useState } from "react"; import { ChevronLeft, Loader2 } from "lucide-react"; import { LanguageSwitcher } from "@/components/LanguageSwitcher"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { fetchSettings, updateSettings } from "@/lib/api"; import { cn } from "@/lib/utils"; import { useClient } from "@/providers/ClientProvider"; import type { SettingsPayload } from "@/lib/types"; interface SettingsViewProps { theme: "light" | "dark"; onToggleTheme: () => void; onBackToChat: () => void; onModelNameChange: (modelName: string | null) => void; } export function SettingsView({ onBackToChat, onModelNameChange, }: SettingsViewProps) { const { token } = useClient(); const [settings, setSettings] = useState(null); const [loading, setLoading] = useState(true); const [saving, setSaving] = useState(false); const [error, setError] = useState(null); const [form, setForm] = useState({ model: "", provider: "auto", }); const applyPayload = useCallback((payload: SettingsPayload) => { setSettings(payload); setForm({ model: payload.agent.model, provider: payload.agent.provider, }); }, []); useEffect(() => { let cancelled = false; setLoading(true); fetchSettings(token) .then((payload) => { if (!cancelled) { applyPayload(payload); setError(null); } }) .catch((err) => { if (!cancelled) setError((err as Error).message); }) .finally(() => { if (!cancelled) setLoading(false); }); return () => { cancelled = true; }; }, [applyPayload, token]); const dirty = useMemo(() => { if (!settings) return false; return ( form.model !== settings.agent.model || form.provider !== settings.agent.provider ); }, [form, settings]); const save = async () => { if (!dirty || saving) return; setSaving(true); try { const payload = await updateSettings(token, form); applyPayload(payload); onModelNameChange(payload.agent.model || null); setError(null); } catch (err) { setError((err as Error).message); } finally { setSaving(false); } }; return (

General

{loading ? (
Loading settings...
) : error ? ( {error} ) : settings ? ( ) : null}
); } function SettingsSection({ form, setForm, settings, dirty, saving, onSave, }: { form: { model: string; provider: string; }; setForm: React.Dispatch>; settings: SettingsPayload; dirty: boolean; saving: boolean; onSave: () => void; }) { return (

AI

setForm((prev) => ({ ...prev, model: event.target.value }))} className="h-8 w-[280px]" /> {(dirty || saving || settings.requires_restart) ? ( ) : null}

Interface

); } function SettingsGroup({ children }: { children: React.ReactNode }) { return (
{children}
); } function SettingsRow({ title, children, }: { title: string; children?: React.ReactNode; }) { return (
{title}
{children ?
{children}
: null}
); } function SettingsFooter({ dirty, saving, saved, onSave, }: { dirty: boolean; saving: boolean; saved: boolean; onSave: () => void; }) { return (
{saved ? "Saved. Restart nanobot to apply." : "Unsaved changes."}
); }