'use client' import { useState, useCallback, useEffect } from 'react' import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@nextsparkjs/core/components/ui/card' import { Badge } from '@nextsparkjs/core/components/ui/badge' import { Switch } from '@nextsparkjs/core/components/ui/switch' import { Button } from '@nextsparkjs/core/components/ui/button' import { toast } from 'sonner' import { Mail, Smartphone, MessageSquare, Shield, Zap, Save, Loader2 } from 'lucide-react' import { sel } from '@nextsparkjs/core/selectors' import { useTranslations } from 'next-intl' import { useUserWithMetaSettings } from '@nextsparkjs/core/hooks/useUserSettings' import { NotificationsPageSkeleton } from '@nextsparkjs/core/components/settings/SettingsPageSkeleton' import { getTemplateOrDefaultClient } from '@nextsparkjs/registries/template-registry.client' function NotificationsPage() { const t = useTranslations('settings') // Hook para manejar user metadata con autenticación de sesión const { data: userData, isLoading: isLoadingUser, updateEntity: updateUserMeta, isUpdating } = useUserWithMetaSettings() // Estado para el master switch de push notifications const [pushNotificationsEnabled, setPushNotificationsEnabled] = useState(true) // Estados individuales para cada notificación const [notificationSettings, setNotificationSettings] = useState({ login_alerts: { email: true, push: true }, password_changes: { email: true, push: true }, suspicious_activity: { email: true, push: true }, mentions: { email: true, push: true }, project_updates: { email: true, push: false }, team_invites: { email: true, push: true }, newsletter: { email: false, push: false }, promotions: { email: false, push: false }, feature_announcements: { email: true, push: false }, }) const [statusMessage, setStatusMessage] = useState('') const [hasUnsavedChanges, setHasUnsavedChanges] = useState(false) // Cargar configuraciones desde metadata al montar el componente useEffect(() => { if (userData?.meta?.notificationsPreferences) { const notifPrefs = userData.meta.notificationsPreferences as Record // Cargar configuración de push notifications if (notifPrefs.pushEnabled !== undefined) { setPushNotificationsEnabled(notifPrefs.pushEnabled as boolean) } // Cargar configuraciones individuales de notificaciones setNotificationSettings({ login_alerts: { email: (notifPrefs.loginAlertsEmail as boolean) ?? true, push: (notifPrefs.loginAlertsPush as boolean) ?? true }, password_changes: { email: (notifPrefs.passwordChangesEmail as boolean) ?? true, push: (notifPrefs.passwordChangesPush as boolean) ?? true }, suspicious_activity: { email: (notifPrefs.suspiciousActivityEmail as boolean) ?? true, push: (notifPrefs.suspiciousActivityPush as boolean) ?? true }, mentions: { email: (notifPrefs.mentionsEmail as boolean) ?? true, push: (notifPrefs.mentionsPush as boolean) ?? true }, project_updates: { email: (notifPrefs.projectUpdatesEmail as boolean) ?? true, push: (notifPrefs.projectUpdatesPush as boolean) ?? false }, team_invites: { email: (notifPrefs.teamInvitesEmail as boolean) ?? true, push: (notifPrefs.teamInvitesPush as boolean) ?? true }, newsletter: { email: (notifPrefs.newsletterEmail as boolean) ?? false, push: (notifPrefs.newsletterPush as boolean) ?? false }, promotions: { email: (notifPrefs.promotionsEmail as boolean) ?? false, push: (notifPrefs.promotionsPush as boolean) ?? false }, feature_announcements: { email: (notifPrefs.featureAnnouncementsEmail as boolean) ?? true, push: (notifPrefs.featureAnnouncementsPush as boolean) ?? false } }) setHasUnsavedChanges(false) } }, [userData?.meta]) const notificationTypes = [ { category: t('notifications.categories.security.title'), icon: , description: t('notifications.categories.security.description'), notifications: [ { id: 'login_alerts', title: t('notifications.types.loginAlerts.title'), description: t('notifications.types.loginAlerts.description'), email: notificationSettings.login_alerts.email, push: notificationSettings.login_alerts.push, required: true, }, { id: 'password_changes', title: t('notifications.types.passwordChanges.title'), description: t('notifications.types.passwordChanges.description'), email: notificationSettings.password_changes.email, push: notificationSettings.password_changes.push, required: true, }, { id: 'suspicious_activity', title: t('notifications.types.suspiciousActivity.title'), description: t('notifications.types.suspiciousActivity.description'), email: notificationSettings.suspicious_activity.email, push: notificationSettings.suspicious_activity.push, required: true, }, ] }, { category: t('notifications.categories.activity.title'), icon: , description: t('notifications.categories.activity.description'), notifications: [ { id: 'mentions', title: t('notifications.types.mentions.title'), description: t('notifications.types.mentions.description'), email: notificationSettings.mentions.email, push: notificationSettings.mentions.push, required: false, }, { id: 'project_updates', title: t('notifications.types.projectUpdates.title'), description: t('notifications.types.projectUpdates.description'), email: notificationSettings.project_updates.email, push: notificationSettings.project_updates.push, required: false, }, { id: 'team_invites', title: t('notifications.types.teamInvites.title'), description: t('notifications.types.teamInvites.description'), email: notificationSettings.team_invites.email, push: notificationSettings.team_invites.push, required: false, }, ] }, { category: t('notifications.categories.marketing.title'), icon: , description: t('notifications.categories.marketing.description'), notifications: [ { id: 'newsletter', title: t('notifications.types.newsletter.title'), description: t('notifications.types.newsletter.description'), email: notificationSettings.newsletter.email, push: notificationSettings.newsletter.push, required: false, }, { id: 'promotions', title: t('notifications.types.promotions.title'), description: t('notifications.types.promotions.description'), email: notificationSettings.promotions.email, push: notificationSettings.promotions.push, required: false, }, { id: 'feature_announcements', title: t('notifications.types.featureAnnouncements.title'), description: t('notifications.types.featureAnnouncements.description'), email: notificationSettings.feature_announcements.email, push: notificationSettings.feature_announcements.push, required: false, }, ] } ] const handleNotificationToggle = useCallback((notificationId: string, type: 'email' | 'push') => { setNotificationSettings(prev => ({ ...prev, [notificationId]: { ...prev[notificationId as keyof typeof prev], [type]: !prev[notificationId as keyof typeof prev][type] } })) const currentValue = notificationSettings[notificationId as keyof typeof notificationSettings][type] const status = currentValue ? t('notifications.labels.disabled') : t('notifications.labels.enabled') setStatusMessage(t('notifications.messages.notificationToggled', { type: type, notification: notificationId, status: status })) setHasUnsavedChanges(true) }, [notificationSettings, t]) // Función para guardar configuraciones como metadata const handleSaveSettings = useCallback(async () => { try { // Crear metadata en formato anidado const notificationsPreferences = { pushEnabled: pushNotificationsEnabled, loginAlertsEmail: notificationSettings.login_alerts.email, loginAlertsPush: notificationSettings.login_alerts.push, passwordChangesEmail: notificationSettings.password_changes.email, passwordChangesPush: notificationSettings.password_changes.push, suspiciousActivityEmail: notificationSettings.suspicious_activity.email, suspiciousActivityPush: notificationSettings.suspicious_activity.push, mentionsEmail: notificationSettings.mentions.email, mentionsPush: notificationSettings.mentions.push, projectUpdatesEmail: notificationSettings.project_updates.email, projectUpdatesPush: notificationSettings.project_updates.push, teamInvitesEmail: notificationSettings.team_invites.email, teamInvitesPush: notificationSettings.team_invites.push, newsletterEmail: notificationSettings.newsletter.email, newsletterPush: notificationSettings.newsletter.push, promotionsEmail: notificationSettings.promotions.email, promotionsPush: notificationSettings.promotions.push, featureAnnouncementsEmail: notificationSettings.feature_announcements.email, featureAnnouncementsPush: notificationSettings.feature_announcements.push, } await updateUserMeta({ meta: { notificationsPreferences } }) setHasUnsavedChanges(false) toast.success(t('notifications.messages.saveSuccess'), { description: t('notifications.messages.saveSuccessDescription'), }) } catch (error) { console.error('Error saving notification settings:', error) toast.error(t('notifications.messages.saveError'), { description: t('notifications.messages.saveErrorDescription'), }) } }, [pushNotificationsEnabled, notificationSettings, updateUserMeta, t]) // Mostrar skeleton mientras cargan los datos if (isLoadingUser) { return } return ( <> {/* MANDATORY: Screen reader announcements */}
{statusMessage}
{/* Header */}

{t('notifications.title')}

{t('notifications.description')}

{/* Main Configuration Card */} {t('notifications.main.title')} {t('notifications.main.description')} {/* Canales de Notificación */}

{t('notifications.channels.title')}

{/* Push Notifications Master Switch */}

{t('notifications.channels.push.title')}

{t('notifications.channels.push.description')}

{pushNotificationsEnabled ? t('notifications.channels.push.enabled') : t('notifications.channels.push.disabled')} { setPushNotificationsEnabled(checked) setStatusMessage(checked ? t('notifications.messages.pushEnabled') : t('notifications.messages.pushDisabled')) setHasUnsavedChanges(true) }} aria-label={pushNotificationsEnabled ? t('notifications.channels.push.ariaEnabled') : t('notifications.channels.push.ariaDisabled')} data-cy={sel('settings.notifications.pushToggle')} />
{/* Email Notifications Info */}

{t('notifications.channels.email.title')}

{t('notifications.channels.email.description')}

{t('notifications.channels.email.alwaysEnabled')}
{/* Divisor */}
{/* Tipos de Notificaciones */} {notificationTypes.map((type, index) => (

{type.icon} {type.category}

{type.notifications.map((notification) => (

{notification.title}

{notification.required && ( {t('notifications.labels.required')} )}

{notification.description}

{/* Email Toggle */}
{t('notifications.labels.email')} handleNotificationToggle(notification.id, 'email')} aria-label={t('notifications.labels.emailAriaLabel', { title: notification.title, status: notification.email ? t('notifications.labels.enabled') : t('notifications.labels.disabled') })} />
{/* Push Toggle */}
{t('notifications.labels.push')} handleNotificationToggle(notification.id, 'push')} aria-label={t('notifications.labels.pushAriaLabel', { title: notification.title, status: (notification.push && pushNotificationsEnabled) ? t('notifications.labels.enabled') : t('notifications.labels.disabled') })} />
))}
{/* Divisor entre secciones (excepto la última) */} {index < notificationTypes.length - 1 && (
)}
))} {/* Botón de Guardar */}
) } export default getTemplateOrDefaultClient('app/dashboard/settings/notifications/page.tsx', NotificationsPage)