"use client"; import React, { useState, useEffect } from "react"; import { useI18n } from "@/lib/i18n"; import { useTheme } from "@/app/providers"; import { getUserSettings, saveUserSettings, UserSettings } from "@/lib/mockData"; import { useUserPrefs } from "@/lib/useUserPrefs"; interface SettingsModalProps { isOpen: boolean; onClose: () => void; user: { id: string; name?: string | null; email?: string | null }; isDemo?: boolean; } /** A toggle-row component used throughout Labs tab */ function LabsRow({ label, desc, children, }: { label: string; desc?: string; children: React.ReactNode; }) { return (
{label}
{desc && (
{desc}
)}
{children}
); } /** Segmented control (radio-style) */ function SegmentedControl({ value, options, onChange, }: { value: T; options: { label: string; value: T }[]; onChange: (v: T) => void; }) { return (
{options.map((opt) => ( ))}
); } /** Slider with live value display */ function PrefSlider({ min, max, value, onChange, unit, }: { min: number; max: number; value: number; onChange: (v: number) => void; unit?: string; }) { return (
onChange(parseInt(e.target.value, 10))} style={{ width: 120, accentColor: "var(--accent)" }} /> {value}{unit}
); } export function SettingsModal({ isOpen, onClose, user, isDemo: _isDemo = false }: SettingsModalProps) { const { t, lang, setLang } = useI18n(); const { theme, toggleTheme } = useTheme(); const { prefs, updatePrefs, resetToDefaults } = useUserPrefs(); const [activeTab, setActiveTab] = useState<"profile" | "preferences" | "labs" | "sync" | "admin">("profile"); const [displayName, setDisplayName] = useState(() => user.name || (typeof window !== "undefined" ? getUserSettings().displayName : "Demo User")); const [email, setEmail] = useState(() => user.email || (typeof window !== "undefined" ? getUserSettings().email : "demo@checkflow.local")); const [password, setPassword] = useState(""); const [trashRetention, setTrashRetention] = useState(() => (typeof window !== "undefined" ? (getUserSettings().trashRetentionDays ?? 30) : 30)); const [savedMsg, setSavedMsg] = useState(""); const [syncPlatform, setSyncPlatform] = useState<"android" | "apple" | "thunderbird">("android"); const [copiedCalDav, setCopiedCalDav] = useState(false); const [testSyncStatus, setTestSyncStatus] = useState<"idle" | "testing" | "success" | "error">("idle"); useEffect(() => { if (isOpen) { const s = getUserSettings(); setDisplayName(user.name || s.displayName); setEmail(user.email || s.email); setTrashRetention(s.trashRetentionDays ?? 30); } }, [isOpen, user]); const handleTestConnection = async () => { setTestSyncStatus("testing"); try { const res = await fetch("/api/dav", { method: "OPTIONS" }); if (res.ok || res.status === 401 || res.status === 207) { setTestSyncStatus("success"); } else { setTestSyncStatus("error"); } } catch { setTestSyncStatus("error"); } setTimeout(() => { setTestSyncStatus("idle"); }, 4000); }; if (!isOpen) return null; const handleSave = () => { const newSettings: UserSettings = { displayName, email, trashRetentionDays: trashRetention, theme, language: lang, }; saveUserSettings(newSettings); setSavedMsg("✓ " + (lang === "ko" ? "설정이 저장되었습니다" : lang === "ja" ? "設定が保存されました" : "Settings saved")); setTimeout(() => { setSavedMsg(""); onClose(); }, 1000); }; const calDavUrl = typeof window !== "undefined" ? `${window.location.origin}/api/dav` : "https://todo.yourdomain.com/api/dav"; // Accent hue preview const hue = prefs.accentHue; const sat = Math.round(prefs.saturation * 0.9); const accentPreview = `hsl(${hue}, ${sat}%, 54%)`; const tabs = [ { id: "profile", label: `👤 ${t("profile") || "Profile"}` }, { id: "preferences", label: `⚙️ ${t("preferences") || "Preferences"}` }, { id: "labs", label: `🧪 ${t("labs") || "Labs"}` }, { id: "sync", label: `📱 ${t("syncIntegrations") || "Integrations"}` }, { id: "admin", label: `👑 ${t("admin") || "Admin"}` }, ] as const; return (
e.stopPropagation()} style={{ maxWidth: 660, width: "92%", padding: "24px 24px 20px", maxHeight: "90vh", display: "flex", flexDirection: "column" }} > {/* Header */}

⚙️ {t("settingsModalTitle") || "Settings"}

{/* Tab Bar */}
{tabs.map((tab) => ( ))}
{/* Scrollable tab content */}
{/* Tab 1: Profile */} {activeTab === "profile" && (
setDisplayName(e.target.value)} placeholder="Your Name" />
setEmail(e.target.value)} placeholder="your.email@example.com" />
setPassword(e.target.value)} placeholder="New password (leave blank to keep current)" />
)} {/* Tab 2: Preferences */} {activeTab === "preferences" && (

{t("trashRetentionHint") || "Deleted tasks will be permanently removed after the specified period."}

{[ { key: "system", icon: "💻", label: t("themeSystem") }, { key: "light", icon: "☀️", label: t("themeLight") }, { key: "dark", icon: "🌙", label: t("themeDark") }, ].map(({ key, icon, label }) => ( ))}
)} {/* Tab 3: 🧪 CheckFlow Labs */} {activeTab === "labs" && (
{/* Section: View */}
View
updatePrefs({ viewMode: v })} /> {/* Section: Layout */}
Layout
updatePrefs({ density: v })} /> updatePrefs({ sidebarWidth: v })} unit="px" /> updatePrefs({ detailWidth: v })} unit="px" /> {/* Section: Appearance */}
Appearance
updatePrefs({ fontSize: v })} />
{/* Hue ring preview */}
{[210, 250, 340, 10, 45, 145, 185].map((h) => (
updatePrefs({ accentHue: h })} title={`Hue ${h}°`} style={{ width: 20, height: 20, borderRadius: "50%", background: `hsl(${h}, ${sat}%, 54%)`, cursor: "pointer", border: prefs.accentHue === h ? "2.5px solid var(--text-primary)" : "2px solid transparent", outline: prefs.accentHue === h ? `3px solid ${accentPreview}` : "none", outlineOffset: 1, transition: "transform var(--dur-fast)", transform: prefs.accentHue === h ? "scale(1.2)" : "scale(1)", }} /> ))}
Saturation updatePrefs({ saturation: v })} unit="%" />
{/* Custom hue input */}
Hue ° updatePrefs({ accentHue: parseInt(e.target.value, 10) })} style={{ width: 100, accentColor: accentPreview }} />
updatePrefs({ roundness: v })} /> updatePrefs({ animationSpeed: v })} /> {/* Reset to Defaults */}
)} {/* Tab: CalDAV / External Sync */} {activeTab === "sync" && (

📱 {t("syncTitle") || "Galaxy & External Sync (CalDAV)"}

{t("syncDesc") || "CheckFlow supports native two-way synchronization with Samsung Galaxy Reminder, Apple Reminders, and Thunderbird via CalDAV."}

{/* Endpoint bar & Action buttons */}
(e.target as HTMLInputElement).select()} />
{/* Actions row: Test & Download */}
📥 {t("syncDownloadIcs") || "Download .ICS Feed"} {testSyncStatus === "success" && ( {t("syncTestSuccess") || "✓ CalDAV endpoint responded successfully"} )} {testSyncStatus === "error" && ( ✕ Endpoint test failed )}
{/* Client setup guides segmented selector */}
setSyncPlatform(v)} />
{/* Step by step cards */}
{syncPlatform === "android" && (
📱 Samsung Galaxy & Android (DAVx⁵ + Reminder / OpenTasks)
  1. {t("syncAndroidStep1")}
  2. {t("syncAndroidStep2")}
  3. {t("syncAndroidStep3")}
  4. {t("syncAndroidStep4")}
💡 Tip: In DAVx⁵ account settings, set Sync Interval to 15 minutes for battery efficiency and near real-time sync.
)} {syncPlatform === "apple" && (
🍎 Apple Reminders & Calendar (iOS / iPadOS / macOS)
  1. {t("syncAppleStep1")}
  2. {t("syncAppleStep2")}
  3. {t("syncAppleStep3")}
  4. {t("syncAppleStep4")}
💡 Tip: If using HTTPS behind a reverse proxy (Nginx/Caddy), ensure valid SSL certificates are trusted by Apple devices.
)} {syncPlatform === "thunderbird" && (
💻 Mozilla Thunderbird (Windows / Mac / Linux)
  1. {t("syncThunderbirdStep1")}
  2. {t("syncThunderbirdStep2")}
  3. {t("syncThunderbirdStep3")}
  4. {t("syncThunderbirdStep4")}
💡 Tip: Thunderbird Tasks view will display CheckFlow priority tags, due dates, and completion status.
)}
)} {/* Tab 4: Admin Quick Access */} {activeTab === "admin" && (

👑 Multi-User Admin Console

Manage registered users, user roles (User/Admin), system statistics, and storage allocations.

🚀 Open Admin Dashboard →
)}
{/* Footer */}
{savedMsg && {savedMsg}}
); }