175 lines
8.5 KiB
TypeScript
175 lines
8.5 KiB
TypeScript
'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>
|
||
)
|
||
}
|