"use client"; import { useState, useEffect, useRef } from 'react'; import { useRouter } from '@/i18n/navigation'; import { useTranslations } from 'next-intl'; import { ArrowLeft, ChevronRight, LogOut, Settings as SettingsIcon, Palette, Mail, User, Shield, UserPen, PalmtreeIcon, Calendar, Filter, FileText, FolderOpen, Tags, HardDrive, Wrench, BookUser, KeyRound, PanelLeftClose, type LucideIcon, } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { AppearanceSettings } from '@/components/settings/appearance-settings'; import { EmailSettings } from '@/components/settings/email-settings'; import { AccountSettings } from '@/components/settings/account-settings'; import { IdentitySettings } from '@/components/settings/identity-settings'; import { VacationSettings } from '@/components/settings/vacation-settings'; import { CalendarSettings } from '@/components/settings/calendar-settings'; import { CalendarManagementSettings } from '@/components/settings/calendar-management-settings'; import { FilterSettings } from '@/components/settings/filter-settings'; import { TemplateSettings } from '@/components/settings/template-settings'; import { AdvancedSettings } from '@/components/settings/advanced-settings'; import { FolderSettings } from '@/components/settings/folder-settings'; import { KeywordSettings } from '@/components/settings/keyword-settings'; import { AccountSecuritySettings } from '@/components/settings/account-security-settings'; import { FilesSettingsComponent } from '@/components/settings/files-settings'; import { ContactsSettings } from '@/components/settings/contacts-settings'; import { SmimeSettings } from '@/components/settings/smime-settings'; import { SidebarAppsSettings } from '@/components/settings/sidebar-apps-settings'; import { useAuthStore } from '@/stores/auth-store'; import { useEmailStore } from '@/stores/email-store'; import { useIsDesktop } from '@/hooks/use-media-query'; import { NavigationRail } from '@/components/layout/navigation-rail'; import { SidebarAppsModal } from '@/components/layout/sidebar-apps-modal'; import { InlineAppView } from '@/components/layout/inline-app-view'; import { useSidebarApps } from '@/hooks/use-sidebar-apps'; import { ResizeHandle } from '@/components/layout/resize-handle'; import { useConfig } from '@/hooks/use-config'; import { cn } from '@/lib/utils'; type Tab = 'appearance' | 'email' | 'account' | 'security' | 'identities' | 'encryption' | 'vacation' | 'calendar' | 'contacts' | 'filters' | 'templates' | 'folders' | 'keywords' | 'files' | 'sidebar_apps' | 'advanced'; type TabGroup = 'general' | 'account' | 'organization' | 'apps' | 'system'; interface TabDef { id: Tab; label: string; icon: LucideIcon; group: TabGroup; } const tabIcons: Record = { appearance: Palette, email: Mail, account: User, security: Shield, identities: UserPen, encryption: KeyRound, vacation: PalmtreeIcon, calendar: Calendar, contacts: BookUser, filters: Filter, templates: FileText, folders: FolderOpen, keywords: Tags, files: HardDrive, sidebar_apps: PanelLeftClose, advanced: Wrench, }; const tabGroupOrder: TabGroup[] = ['general', 'account', 'organization', 'apps', 'system']; export default function SettingsPage() { const router = useRouter(); const t = useTranslations('settings'); const tSidebar = useTranslations('sidebar'); const { client, isAuthenticated, logout, checkAuth, isLoading: authLoading } = useAuthStore(); const { showAppsModal, inlineApp, loadedApps, handleManageApps, handleInlineApp, closeInlineApp, closeAppsModal } = useSidebarApps(); const [initialCheckDone, setInitialCheckDone] = useState(() => useAuthStore.getState().isAuthenticated && !!useAuthStore.getState().client); const { quota, isPushConnected } = useEmailStore(); const { stalwartFeaturesEnabled } = useConfig(); const [activeTab, setActiveTab] = useState(() => { try { const saved = localStorage.getItem('settings-active-tab'); if (saved) return saved as Tab; } catch { /* ignore */ } return 'appearance'; }); const [mobileShowContent, setMobileShowContent] = useState(false); const isDesktop = useIsDesktop(); // Sidebar resize state const [settingsSidebarWidth, setSettingsSidebarWidth] = useState(() => { try { const v = localStorage.getItem('settings-sidebar-width'); return v ? Number(v) : 256; } catch { return 256; } }); const [isResizing, setIsResizing] = useState(false); const dragStartWidth = useRef(256); // Check auth on mount useEffect(() => { checkAuth().finally(() => { setInitialCheckDone(true); }); }, [checkAuth]); useEffect(() => { if (initialCheckDone && !isAuthenticated && !authLoading) { try { sessionStorage.setItem('redirect_after_login', window.location.pathname); } catch { /* ignore */ } router.push('/login'); } }, [initialCheckDone, isAuthenticated, authLoading, router]); if (!isAuthenticated) { return null; } const supportsVacation = client?.supportsVacationResponse() ?? false; const supportsCalendar = client?.supportsCalendars() ?? false; const supportsSieve = client?.supportsSieve() ?? false; const supportsFiles = client?.supportsFiles() ?? false; const tabs: TabDef[] = [ { id: 'appearance', label: t('tabs.appearance'), icon: tabIcons.appearance, group: 'general' }, { id: 'email', label: t('tabs.email'), icon: tabIcons.email, group: 'general' }, { id: 'account', label: t('tabs.account'), icon: tabIcons.account, group: 'account' }, ...(stalwartFeaturesEnabled ? [{ id: 'security' as Tab, label: t('tabs.security'), icon: tabIcons.security, group: 'account' as TabGroup }] : []), { id: 'identities', label: t('tabs.identities'), icon: tabIcons.identities, group: 'account' }, { id: 'encryption', label: t('tabs.encryption'), icon: tabIcons.encryption, group: 'account' }, ...(supportsVacation ? [{ id: 'vacation' as Tab, label: t('tabs.vacation'), icon: tabIcons.vacation, group: 'account' as TabGroup }] : []), ...(supportsSieve ? [{ id: 'filters' as Tab, label: t('tabs.filters'), icon: tabIcons.filters, group: 'organization' as TabGroup }] : []), { id: 'templates', label: t('tabs.templates'), icon: tabIcons.templates, group: 'organization' }, { id: 'folders', label: t('tabs.folders'), icon: tabIcons.folders, group: 'organization' }, { id: 'keywords', label: t('tabs.keywords'), icon: tabIcons.keywords, group: 'organization' }, ...(supportsCalendar ? [{ id: 'calendar' as Tab, label: t('tabs.calendar'), icon: tabIcons.calendar, group: 'apps' as TabGroup }] : []), { id: 'contacts', label: t('tabs.contacts'), icon: tabIcons.contacts, group: 'apps' }, ...(supportsFiles ? [{ id: 'files' as Tab, label: t('tabs.files'), icon: tabIcons.files, group: 'apps' as TabGroup }] : []), { id: 'sidebar_apps', label: t('tabs.sidebar_apps'), icon: tabIcons.sidebar_apps, group: 'apps' }, { id: 'advanced', label: t('tabs.advanced'), icon: tabIcons.advanced, group: 'system' }, ]; // Group tabs by category const groupedTabs = tabGroupOrder .map((group) => ({ group, label: t(`tab_groups.${group}`), items: tabs.filter((tab) => tab.group === group), })) .filter((g) => g.items.length > 0); const handleTabSelect = (tabId: Tab) => { setActiveTab(tabId); try { localStorage.setItem('settings-active-tab', tabId); } catch { /* ignore */ } if (!isDesktop) { setMobileShowContent(true); } }; const activeTabLabel = tabs.find((tab) => tab.id === activeTab)?.label ?? ''; const renderTabContent = () => ( <> {activeTab === 'appearance' && } {activeTab === 'email' && } {activeTab === 'account' && } {activeTab === 'security' && } {activeTab === 'identities' && } {activeTab === 'encryption' && } {activeTab === 'vacation' && } {activeTab === 'calendar' && <>
} {activeTab === 'contacts' && } {activeTab === 'filters' && } {activeTab === 'templates' && } {activeTab === 'folders' && } {activeTab === 'keywords' && } {activeTab === 'files' && } {activeTab === 'sidebar_apps' && } {activeTab === 'advanced' && } ); // Mobile layout if (!isDesktop) { // Mobile: show content view if (mobileShowContent) { return (
{/* Mobile content header */}

{activeTabLabel}

{/* Content */}
{renderTabContent()}
{/* Bottom Navigation */}
); } // Mobile: show tab list return (
{/* Mobile header */}

{t('title')}

{/* Tab list */}
{groupedTabs.map((group, groupIndex) => (
{groupIndex > 0 &&
}
{group.label}
{group.items.map((tab) => { const Icon = tab.icon; return ( ); })}
))}
{/* Logout */}
{/* Bottom Navigation */}
); } // Desktop layout return (
{/* Navigation Rail */}
{ logout(); router.push('/login'); }} onManageApps={handleManageApps} onInlineApp={handleInlineApp} onCloseInlineApp={closeInlineApp} activeAppId={inlineApp?.id ?? null} />
{inlineApp && ( )} {!inlineApp && ( <> {/* Settings Sidebar */}
{/* Header */}
{/* Tabs */}
{groupedTabs.map((group, groupIndex) => (
{groupIndex > 0 &&
}
{group.label}
{group.items.map((tab) => { const Icon = tab.icon; return ( ); })}
))}
{/* Sidebar resize handle */} { dragStartWidth.current = settingsSidebarWidth; setIsResizing(true); }} onResize={(delta) => setSettingsSidebarWidth(Math.max(180, Math.min(400, dragStartWidth.current + delta)))} onResizeEnd={() => { setIsResizing(false); localStorage.setItem('settings-sidebar-width', String(settingsSidebarWidth)); }} onDoubleClick={() => { setSettingsSidebarWidth(256); localStorage.setItem('settings-sidebar-width', '256'); }} /> {/* Settings Content */}
{/* Page Header */}

{t('title')}

{/* Active Tab Content */}
{renderTabContent()}
)}
); }