diff --git a/app/[locale]/login/page.tsx b/app/[locale]/login/page.tsx index 53123ee7..72ecbc71 100644 --- a/app/[locale]/login/page.tsx +++ b/app/[locale]/login/page.tsx @@ -148,7 +148,7 @@ export default function LoginPage() { if (!serverUrl) return; const handleClickOutside = (event: MouseEvent) => { if (suggestionsRef.current && !suggestionsRef.current.contains(event.target as Node) && - inputRef.current && !inputRef.current.contains(event.target as Node)) { + inputRef.current && !inputRef.current.contains(event.target as Node)) { setShowSuggestions(false); } if (themeMenuRef.current && !themeMenuRef.current.contains(event.target as Node)) { diff --git a/app/[locale]/page.tsx b/app/[locale]/page.tsx index 0f5852ff..5f4ca016 100644 --- a/app/[locale]/page.tsx +++ b/app/[locale]/page.tsx @@ -407,7 +407,10 @@ export default function Home() { // Handle new email notifications - play sound useEffect(() => { if (newEmailNotification) { - playNotificationSound(); + const { emailNotificationsEnabled, emailNotificationSound, notificationSoundChoice } = useSettingsStore.getState(); + if (emailNotificationsEnabled && emailNotificationSound) { + playNotificationSound(notificationSoundChoice); + } debug.log('New email received:', newEmailNotification.subject); clearNewEmailNotification(); } diff --git a/app/[locale]/settings/page.tsx b/app/[locale]/settings/page.tsx index 8ccd3179..d9d81a80 100644 --- a/app/[locale]/settings/page.tsx +++ b/app/[locale]/settings/page.tsx @@ -24,6 +24,7 @@ import { BookUser, KeyRound, PanelLeftClose, + Bell, type LucideIcon, } from 'lucide-react'; import { Button } from '@/components/ui/button'; @@ -44,6 +45,7 @@ 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 { NotificationSettings } from '@/components/settings/notification-settings'; import { useAuthStore, redirectToLogin } from '@/stores/auth-store'; import { useEmailStore } from '@/stores/email-store'; import { useIsDesktop } from '@/hooks/use-media-query'; @@ -55,7 +57,7 @@ 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 Tab = 'appearance' | 'email' | 'notifications' | 'account' | 'security' | 'identities' | 'encryption' | 'vacation' | 'calendar' | 'contacts' | 'filters' | 'templates' | 'folders' | 'keywords' | 'files' | 'sidebar_apps' | 'advanced'; type TabGroup = 'general' | 'account' | 'organization' | 'apps' | 'system'; interface TabDef { @@ -68,6 +70,7 @@ interface TabDef { const tabIcons: Record = { appearance: Palette, email: Mail, + notifications: Bell, account: User, security: Shield, identities: UserPen, @@ -138,6 +141,7 @@ export default function SettingsPage() { 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: 'notifications', label: t('tabs.notifications'), icon: tabIcons.notifications, 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' }, @@ -177,6 +181,7 @@ export default function SettingsPage() { <> {activeTab === 'appearance' && } {activeTab === 'email' && } + {activeTab === 'notifications' && } {activeTab === 'account' && } {activeTab === 'security' && } {activeTab === 'identities' && } diff --git a/components/settings/calendar-settings.tsx b/components/settings/calendar-settings.tsx index 96b6882b..9d714565 100644 --- a/components/settings/calendar-settings.tsx +++ b/components/settings/calendar-settings.tsx @@ -16,9 +16,6 @@ export function CalendarSettings() { firstDayOfWeek, showTimeInMonthView, showWeekNumbers, - calendarNotificationsEnabled, - calendarNotificationSound, - calendarInvitationParsingEnabled, enableCalendarTasks, showTasksOnCalendar, updateSetting, @@ -103,37 +100,6 @@ export function CalendarSettings() { )} - - updateSetting('calendarNotificationsEnabled', checked)} - /> - - - - updateSetting('calendarNotificationSound', checked)} - disabled={!calendarNotificationsEnabled} - /> - - - - updateSetting('calendarInvitationParsingEnabled', checked)} - /> - - ); } diff --git a/components/settings/notification-settings.tsx b/components/settings/notification-settings.tsx new file mode 100644 index 00000000..3198e390 --- /dev/null +++ b/components/settings/notification-settings.tsx @@ -0,0 +1,115 @@ +"use client"; + +import { useTranslations } from 'next-intl'; +import { useSettingsStore } from '@/stores/settings-store'; +import { SettingsSection, SettingItem, ToggleSwitch, Select } from './settings-section'; +import { playNotificationSound, NOTIFICATION_SOUNDS } from '@/lib/notification-sound'; +import type { NotificationSoundChoice } from '@/lib/notification-sound'; +import { Button } from '@/components/ui/button'; +import { Volume2 } from 'lucide-react'; + +export function NotificationSettings() { + const t = useTranslations('settings.notifications'); + const { + emailNotificationsEnabled, + emailNotificationSound, + notificationSoundChoice, + calendarNotificationsEnabled, + calendarNotificationSound, + calendarInvitationParsingEnabled, + updateSetting, + } = useSettingsStore(); + + const soundOptions = NOTIFICATION_SOUNDS.map((s) => ({ + value: s.id, + label: t(`sounds.${s.id}`), + })); + + return ( +
+ + +
+ +