Files
Momento/memento-note/app/(main)/settings/general/general-settings-client.tsx
Antigravity 368b43cb8e
Some checks failed
Deploy to Production / Build and Deploy (push) Failing after 1m50s
feat: improve AI Chat UX, add notebook summary, and fix shared/reminders routing
2026-05-09 14:40:36 +00:00

175 lines
8.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'use client'
import { useState } from 'react'
import { useLanguage } from '@/lib/i18n'
import { updateAISettings } from '@/app/actions/ai-settings'
import { toast } from 'sonner'
import { useRouter } from 'next/navigation'
import { Globe, Bell } from 'lucide-react'
interface GeneralSettingsClientProps {
initialSettings: {
preferredLanguage: string
emailNotifications: boolean
desktopNotifications: boolean
autoSave: boolean
}
}
export function GeneralSettingsClient({ initialSettings }: GeneralSettingsClientProps) {
const { t, setLanguage: setContextLanguage } = useLanguage()
const router = useRouter()
const [language, setLanguage] = useState(initialSettings.preferredLanguage || 'auto')
const [emailNotifications, setEmailNotifications] = useState(initialSettings.emailNotifications ?? false)
const [desktopNotifications, setDesktopNotifications] = useState(initialSettings.desktopNotifications ?? false)
const [autoSave, setAutoSave] = useState(initialSettings.autoSave ?? true)
const handleLanguageChange = async (value: string) => {
setLanguage(value)
await updateAISettings({ preferredLanguage: value as any })
if (value === 'auto') {
localStorage.removeItem('user-language')
document.cookie = 'user-language=;path=/;max-age=0'
toast.success(t('settings.languageAuto') || 'Language set to Auto')
} else {
localStorage.setItem('user-language', value)
document.cookie = `user-language=${value};path=/;max-age=${60 * 60 * 24 * 365};samesite=lax`
setContextLanguage(value as any)
toast.success(t('profile.languageUpdateSuccess') || 'Language updated')
}
setTimeout(() => router.refresh(), 300)
}
const handleEmailNotificationsChange = async (enabled: boolean) => {
setEmailNotifications(enabled)
await updateAISettings({ emailNotifications: enabled })
toast.success(t('settings.settingsSaved') || 'Saved')
}
const handleDesktopNotificationsChange = async (enabled: boolean) => {
setDesktopNotifications(enabled)
await updateAISettings({ desktopNotifications: enabled })
toast.success(t('settings.settingsSaved') || 'Saved')
}
const handleAutoSaveChange = async (enabled: boolean) => {
setAutoSave(enabled)
await updateAISettings({ autoSave: enabled })
toast.success(t('settings.settingsSaved') || 'Saved')
}
return (
<div className="space-y-8">
<p className="text-[11px] font-bold uppercase tracking-[0.2em] text-muted-foreground">
{t('generalSettings.description')}
</p>
{/* 2-column card grid */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
{/* Language card */}
<div className="bg-card rounded-lg border border-border p-6 shadow-sm flex flex-col gap-4">
<div className="flex items-center gap-3">
<div className="w-10 h-10 rounded-full bg-primary/10 flex items-center justify-center text-primary shrink-0">
<Globe className="h-5 w-5" />
</div>
<div>
<h3 className="font-semibold text-foreground">{t('settings.language')}</h3>
<p className="text-sm text-muted-foreground">{t('settings.selectLanguage')}</p>
</div>
</div>
<div className="relative mt-2">
<select
value={language}
onChange={(e) => handleLanguageChange(e.target.value)}
className="w-full h-11 px-4 bg-muted border border-border rounded-lg text-foreground text-sm focus:ring-2 focus:ring-primary/20 focus:border-primary outline-none appearance-none cursor-pointer transition-colors"
>
<option value="auto">{t('profile.autoDetect')}</option>
<option value="en">English</option>
<option value="fr">Français</option>
<option value="es">Español</option>
<option value="de">Deutsch</option>
<option value="fa">فارسی</option>
<option value="it">Italiano</option>
<option value="pt">Português</option>
<option value="ru">Русский</option>
<option value="zh"></option>
<option value="ja"></option>
<option value="ko"></option>
<option value="ar">العربية</option>
<option value="hi">ि</option>
<option value="nl">Nederlands</option>
<option value="pl">Polski</option>
</select>
<div className="absolute right-4 top-1/2 -translate-y-1/2 pointer-events-none text-muted-foreground">
<svg className="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" /></svg>
</div>
</div>
</div>
{/* Notifications card */}
<div className="bg-card rounded-lg border border-border p-6 shadow-sm flex flex-col gap-4">
<div className="flex items-center gap-3">
<div className="w-10 h-10 rounded-full bg-primary/10 flex items-center justify-center text-primary shrink-0">
<Bell className="h-5 w-5" />
</div>
<div>
<h3 className="font-semibold text-foreground">{t('settings.notifications')}</h3>
<p className="text-sm text-muted-foreground">{t('settings.notificationsDesc')}</p>
</div>
</div>
<div className="mt-2 space-y-5">
{/* Email toggle */}
<div className="flex items-center justify-between">
<div>
<p className="text-sm font-medium text-foreground">{t('settings.emailNotifications')}</p>
<p className="text-xs text-muted-foreground">{t('settings.emailNotificationsDesc')}</p>
</div>
<button
type="button"
role="switch"
aria-checked={emailNotifications}
onClick={() => handleEmailNotificationsChange(!emailNotifications)}
className={`relative inline-flex h-6 w-11 items-center rounded-full transition-colors focus:outline-none focus:ring-2 focus:ring-primary/30 ${emailNotifications ? 'bg-primary' : 'bg-muted-foreground/30'}`}
>
<span className={`inline-block h-4 w-4 transform rounded-full bg-white shadow transition-transform ${emailNotifications ? 'translate-x-6' : 'translate-x-1'}`} />
</button>
</div>
{/* Desktop toggle */}
<div className="flex items-center justify-between">
<div>
<p className="text-sm font-medium text-foreground">{t('settings.desktopNotifications')}</p>
<p className="text-xs text-muted-foreground">{t('settings.desktopNotificationsDesc')}</p>
</div>
<button
type="button"
role="switch"
aria-checked={desktopNotifications}
onClick={() => handleDesktopNotificationsChange(!desktopNotifications)}
className={`relative inline-flex h-6 w-11 items-center rounded-full transition-colors focus:outline-none focus:ring-2 focus:ring-primary/30 ${desktopNotifications ? 'bg-primary' : 'bg-muted-foreground/30'}`}
>
<span className={`inline-block h-4 w-4 transform rounded-full bg-white shadow transition-transform ${desktopNotifications ? 'translate-x-6' : 'translate-x-1'}`} />
</button>
</div>
<div className="border-t border-border pt-5 flex items-center justify-between">
<div>
<p className="text-sm font-medium text-foreground">{t('settings.autoSave') || 'Auto-Save'}</p>
<p className="text-xs text-muted-foreground">{t('settings.autoSaveDesc') || 'Sauvegarder automatiquement les modifications'}</p>
</div>
<button
type="button"
role="switch"
aria-checked={autoSave}
onClick={() => handleAutoSaveChange(!autoSave)}
className={`relative inline-flex h-6 w-11 items-center rounded-full transition-colors focus:outline-none focus:ring-2 focus:ring-primary/30 ${autoSave ? 'bg-primary' : 'bg-muted-foreground/30'}`}
>
<span className={`inline-block h-4 w-4 transform rounded-full bg-white shadow transition-transform ${autoSave ? 'translate-x-6' : 'translate-x-1'}`} />
</button>
</div>
</div>
</div>
</div>
</div>
)
}