import { useState, useEffect } from "react"; import { createRoute } from "@tanstack/react-router"; import { Route as appRoute } from "../_app"; import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; import { api, useApiQuery, useApiMutation } from "@/lib/api"; import { Plus, Trash2, Pencil, Palette, Sun, Moon, Monitor, Type, Maximize, Sidebar, Eye, Globe, Tag, List, Key, Bot, Webhook, Upload, Download, AlertCircle, Check, X, RefreshCw, TestTube } from "lucide-react"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Textarea } from "@/components/ui/textarea"; import { Badge } from "@/components/ui/badge"; import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card"; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger, DialogFooter } from "@/components/ui/dialog"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { Label } from "@/components/ui/label"; import { Switch } from "@/components/ui/switch"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { ScrollArea } from "@/components/ui/scroll-area"; import { Separator } from "@/components/ui/separator"; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger } from "@/components/ui/alert-dialog"; import { useThemeStore } from "@/lib/stores/use-theme-store"; import { cn } from "@/lib/utils"; import type { Domain, CustomField, Webhook as WebhookType, ErrorLog, Agent, PaginatedResponse } from "@/lib/types"; const SETTINGS_TABS = [ { id: "appearance", label: "Appearance", icon: Palette }, { id: "domains", label: "Domains", icon: Globe }, { id: "tags", label: "Tags", icon: Tag }, { id: "custom-fields", label: "Custom Fields", icon: List }, { id: "shortcuts", label: "Keyboard Shortcuts", icon: Key }, { id: "agents", label: "Agents & Permissions", icon: Bot }, { id: "webhooks", label: "Webhooks", icon: Webhook }, { id: "import-export", label: "Import & Export", icon: Upload }, { id: "error-log", label: "Error Log", icon: AlertCircle }, ] as const; const ACCENT_COLORS = [ { name: "Blue", value: "#3b82f6" }, { name: "Green", value: "#22c55e" }, { name: "Purple", value: "#a855f7" }, { name: "Orange", value: "#f97316" }, { name: "Rose", value: "#e11d48" }, ]; const SHORTCUTS_MAP: Record = { "Cmd+K": "Command palette", "g+t": "Go to Tasks", "g+h": "Go to Habits", "g+p": "Go to Projects", "g+n": "Go to Notes", "g+c": "Go to Calendar", "g+d": "Go to Dashboard", "g+s": "Go to Settings", "g+a": "Go to Analytics", "n": "New task / note (context dependent)", "?": "Show keyboard shortcuts help", }; // ─── Appearance Tab ────────────────────────────────────────────────────── function AppearanceTab() { const { mode, setMode } = useThemeStore(); const [accent, setAccent] = useState(localStorage.getItem("accent-color") || "#3b82f6"); const [fontSize, setFontSize] = useState(localStorage.getItem("font-size") || "normal"); const [density, setDensity] = useState(localStorage.getItem("density") || "comfortable"); const [sidebarPos, setSidebarPos] = useState(localStorage.getItem("sidebar-position") || "left"); const [reducedMotion, setReducedMotion] = useState(localStorage.getItem("reduced-motion") === "true"); useEffect(() => { localStorage.setItem("accent-color", accent); document.documentElement.style.setProperty("--accent-color", accent); }, [accent]); useEffect(() => { localStorage.setItem("font-size", fontSize); document.documentElement.style.fontSize = fontSize === "large" ? "18px" : fontSize === "small" ? "13px" : "16px"; }, [fontSize]); useEffect(() => { localStorage.setItem("density", density); }, [density]); useEffect(() => { localStorage.setItem("sidebar-position", sidebarPos); }, [sidebarPos]); useEffect(() => { localStorage.setItem("reduced-motion", String(reducedMotion)); document.documentElement.classList.toggle("reduce-motion", reducedMotion); }, [reducedMotion]); return (

Theme

{[ { id: "light", icon: Sun, label: "Light" }, { id: "dark", icon: Moon, label: "Dark" }, { id: "system", icon: Monitor, label: "System" }, ].map((t) => ( ))}

Accent Color

{ACCENT_COLORS.map((c) => (

Font Size

Density

Sidebar Position

Reduced Motion

Minimize animations and transitions

); } // ─── Domains Tab ───────────────────────────────────────────────────────── function DomainsTab() { const queryClient = useQueryClient(); const { data } = useApiQuery>(["domains"], "/domains"); const domains = data?.items || []; const [createOpen, setCreateOpen] = useState(false); const [name, setName] = useState(""); const createMutation = useMutation({ mutationFn: (n: string) => api.post("/domains", { name: n }), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["domains"] }); setCreateOpen(false); setName(""); }, }); const deleteMutation = useMutation({ mutationFn: (id: string) => api.delete("/domains/" + id), onSuccess: () => queryClient.invalidateQueries({ queryKey: ["domains"] }), }); return (

Domains

New Domain
setName(e.target.value)} placeholder="Domain name" />
{domains.map((d) => (

{d.name}

{d.slug}

Delete DomainAre you sure? This cannot be undone. Cancel deleteMutation.mutate(d.id)} className="bg-destructive">Delete
))}
); } // ─── Tags Tab ──────────────────────────────────────────────────────────── function TagsTab() { const queryClient = useQueryClient(); const { data } = useApiQuery>(["tags"], "/tags"); const tags = data?.items || []; const [createOpen, setCreateOpen] = useState(false); const [name, setName] = useState(""); const [color, setColor] = useState("#3b82f6"); const createMutation = useMutation({ mutationFn: (d: any) => api.post("/tags", d), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["tags"] }); setCreateOpen(false); setName(""); }, }); const deleteMutation = useMutation({ mutationFn: (id: string) => api.delete("/tags/" + id), onSuccess: () => queryClient.invalidateQueries({ queryKey: ["tags"] }), }); return (

Tags

New Tag
setName(e.target.value)} placeholder="Tag name" />
setColor(e.target.value)} className="w-12 h-10 p-1" /> {color}
{tags.map((t: any) => (
{t.name}
))}
); } // ─── Custom Fields Tab ──────────────────────────────────────────────────── function CustomFieldsTab() { const queryClient = useQueryClient(); const [entityFilter, setEntityFilter] = useState(""); const { data } = useApiQuery>(["custom-fields", entityFilter], "/custom-fields" + (entityFilter ? "?entity=" + entityFilter : "")); const fields = data?.items || []; const [createOpen, setCreateOpen] = useState(false); const [editField, setEditField] = useState(null); const [form, setForm] = useState({ name: "", type: "text", entityType: "tasks", required: false, options: "" }); const createMutation = useMutation({ mutationFn: (d: any) => api.post("/custom-fields", d), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["custom-fields"] }); setCreateOpen(false); }, }); const updateMutation = useMutation({ mutationFn: ({ id, data: d }: { id: string; data: any }) => api.patch("/custom-fields/" + id, d), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["custom-fields"] }); setEditField(null); }, }); const deleteMutation = useMutation({ mutationFn: (id: string) => api.delete("/custom-fields/" + id), onSuccess: () => queryClient.invalidateQueries({ queryKey: ["custom-fields"] }), }); const handleSave = () => { const data: any = { name: form.name, type: form.type, entityType: form.entityType, required: form.required }; if (form.type === "select" || form.type === "multi_select") data.options = form.options.split(",").map((s) => s.trim()).filter(Boolean); if (editField) updateMutation.mutate({ id: editField.id, data }); else createMutation.mutate(data); }; return (

Custom Fields

New Custom Field
setForm({ ...form, name: e.target.value })} />
{(form.type === "select" || form.type === "multi_select") && (
setForm({ ...form, options: e.target.value })} placeholder="Option 1, Option 2" />
)}
setForm({ ...form, required: v })} />
{fields.map((f) => (

{f.name}

{f.type} · {f.entityType}{f.required ? " · Required" : ""}

Delete FieldAre you sure? Cancel deleteMutation.mutate(f.id)} className="bg-destructive">Delete
))}
{editField && ( { if (!o) setEditField(null); }}> Edit Custom Field
setForm({ ...form, name: e.target.value })} />
{(form.type === "select" || form.type === "multi_select") && (
setForm({ ...form, options: e.target.value })} />
)}
setForm({ ...form, required: v })} />
)}
); } // ─── Keyboard Shortcuts Tab ──────────────────────────────────────────────── function ShortcutsTab() { return (

Keyboard Shortcuts

{Object.entries(SHORTCUTS_MAP).map(([key, desc]) => (
{desc} {key}
))}
); } // ─── Agents & Permissions Tab ──────────────────────────────────────────── function AgentsTab() { const queryClient = useQueryClient(); const { data } = useApiQuery>(["agents"], "/agents"); const agents = data?.items || []; const [createOpen, setCreateOpen] = useState(false); const [form, setForm] = useState({ name: "", description: "", permissionTier: "read_only" }); const createMutation = useMutation({ mutationFn: (d: any) => api.post("/agents", d), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["agents"] }); setCreateOpen(false); }, }); const deleteMutation = useMutation({ mutationFn: (id: string) => api.delete("/agents/" + id), onSuccess: () => queryClient.invalidateQueries({ queryKey: ["agents"] }), }); return (

Agents & Permissions

New Agent
setForm({ ...form, name: e.target.value })} />