diff --git a/src/app/settings/page.tsx b/src/app/settings/page.tsx new file mode 100644 index 00000000..e9eba083 --- /dev/null +++ b/src/app/settings/page.tsx @@ -0,0 +1,317 @@ +'use client'; + +import { useSession } from 'next-auth/react'; +import { useRouter } from 'next/navigation'; +import { useEffect, useState } from 'react'; +import { MainLayout } from '@/components/layout'; +import { Settings, Bell, Globe, Layout, Save, Check } from 'lucide-react'; + +interface UserSettings { + notifications: { + desktop: boolean; + emailTicketUpdates: boolean; + emailMentions: boolean; + emailAssignments: boolean; + }; + timezone: string; + defaultTicketView: string; +} + +const DEFAULT_SETTINGS: UserSettings = { + notifications: { + desktop: true, + emailTicketUpdates: true, + emailMentions: true, + emailAssignments: true, + }, + timezone: + typeof window !== 'undefined' ? Intl.DateTimeFormat().resolvedOptions().timeZone : 'UTC', + defaultTicketView: 'all-unsolved', +}; + +function getTimezoneOptions(): string[] { + try { + return Intl.supportedValuesOf('timeZone'); + } catch { + return ['UTC']; + } +} + +const VIEW_OPTIONS = [ + { value: 'your-unsolved', label: 'Your unsolved tickets' }, + { value: 'all-unsolved', label: 'All unsolved tickets' }, + { value: 'unassigned', label: 'Unassigned tickets' }, + { value: 'recently-updated', label: 'Recently updated tickets' }, + { value: 'pending', label: 'Pending tickets' }, +]; + +function getInitialSettings(): UserSettings { + if (typeof window === 'undefined') return DEFAULT_SETTINGS; + try { + const stored = localStorage.getItem('zapdesk-settings'); + if (stored) { + const parsed = JSON.parse(stored) as Partial; + return { + ...DEFAULT_SETTINGS, + ...parsed, + notifications: { + ...DEFAULT_SETTINGS.notifications, + ...(parsed.notifications || {}), + }, + }; + } + } catch { + // Ignore parse errors + } + return DEFAULT_SETTINGS; +} + +function saveSettings(settings: UserSettings): void { + if (typeof window === 'undefined') return; + localStorage.setItem('zapdesk-settings', JSON.stringify(settings)); +} + +export default function SettingsPage() { + const { data: session, status } = useSession(); + const router = useRouter(); + const [settings, setSettings] = useState(() => getInitialSettings()); + const [saveSuccess, setSaveSuccess] = useState(false); + + useEffect(() => { + if (status === 'unauthenticated') { + router.push('/login'); + } + }, [status, router]); + + const handleNotificationChange = (key: keyof UserSettings['notifications']) => { + setSettings((prev) => ({ + ...prev, + notifications: { + ...prev.notifications, + [key]: !prev.notifications[key], + }, + })); + setSaveSuccess(false); + }; + + const handleTimezoneChange = (timezone: string) => { + setSettings((prev) => ({ ...prev, timezone })); + setSaveSuccess(false); + }; + + const handleViewChange = (defaultTicketView: string) => { + setSettings((prev) => ({ ...prev, defaultTicketView })); + setSaveSuccess(false); + }; + + const handleSave = () => { + saveSettings(settings); + setSaveSuccess(true); + setTimeout(() => setSaveSuccess(false), 2000); + }; + + if (status === 'loading') { + return ( + +
+
+
+ + ); + } + + if (!session) { + return null; + } + + return ( + +
+ {/* Header */} +
+
+ +

+ Settings +

+
+ +
+ +
+ {/* Notifications Section */} +
+
+ +

+ Notifications +

+
+ +
+ handleNotificationChange('desktop')} + /> + handleNotificationChange('emailTicketUpdates')} + /> + handleNotificationChange('emailMentions')} + /> + handleNotificationChange('emailAssignments')} + /> +
+
+ + {/* Timezone Section */} +
+
+ +

+ Timezone +

+
+ +
+ + +
+
+ + {/* Default View Section */} +
+
+ +

+ Default Ticket View +

+
+ +
+ + +
+
+
+
+
+ ); +} + +interface ToggleOptionProps { + label: string; + description: string; + checked: boolean; + onChange: () => void; +} + +const TOGGLE_OFFSET = 20; // width(44px) - toggle(20px) - padding(4px) + +function ToggleOption({ label, description, checked, onChange }: ToggleOptionProps) { + return ( +
+
+

+ {label} +

+

+ {description} +

+
+ +
+ ); +}