Some checks failed
Deploy to Production / Build and Deploy (push) Failing after 1m7s
Replaced ~100+ hardcoded French and English text strings across 30+ components with proper i18n t() calls. Added 57 new translation keys to all 15 locale files (ar, de, en, es, fa, fr, hi, it, ja, ko, nl, pl, pt, ru, zh). Key changes: - contextual-ai-chat.tsx: 30 French strings → t() (actions, toasts, labels, placeholders) - ai-chat.tsx: 15 French/English strings → t() (header, tabs, welcome, insights, history) - note-inline-editor.tsx: 20 French fallbacks removed (toolbar, save status, checklist) - lab-skeleton.tsx: French loading text → t() - admin-header.tsx, header.tsx, editor-connections-section.tsx: French fallbacks removed - New AI chat component, agent cards, sidebar, settings panel i18n cleanup Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
218 lines
6.9 KiB
TypeScript
218 lines
6.9 KiB
TypeScript
'use client'
|
|
|
|
import { useState } from 'react'
|
|
import { Card } from '@/components/ui/card'
|
|
import { Switch } from '@/components/ui/switch'
|
|
import { Label } from '@/components/ui/label'
|
|
import { Button } from '@/components/ui/button'
|
|
import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group'
|
|
import { updateAISettings } from '@/app/actions/ai-settings'
|
|
import { DemoModeToggle } from '@/components/demo-mode-toggle'
|
|
import { toast } from 'sonner'
|
|
import { Loader2 } from 'lucide-react'
|
|
import { useLanguage } from '@/lib/i18n'
|
|
|
|
interface AISettingsPanelProps {
|
|
initialSettings: {
|
|
titleSuggestions: boolean
|
|
semanticSearch: boolean
|
|
paragraphRefactor: boolean
|
|
memoryEcho: boolean
|
|
memoryEchoFrequency: 'daily' | 'weekly' | 'custom'
|
|
aiProvider: 'auto' | 'openai' | 'ollama'
|
|
preferredLanguage: 'auto' | 'en' | 'fr' | 'es' | 'de' | 'fa' | 'it' | 'pt' | 'ru' | 'zh' | 'ja' | 'ko' | 'ar' | 'hi' | 'nl' | 'pl'
|
|
demoMode: boolean
|
|
languageDetection: boolean
|
|
autoLabeling: boolean
|
|
}
|
|
}
|
|
|
|
export function AISettingsPanel({ initialSettings }: AISettingsPanelProps) {
|
|
const [settings, setSettings] = useState(initialSettings)
|
|
const [isPending, setIsPending] = useState(false)
|
|
const { t } = useLanguage()
|
|
|
|
const handleToggle = async (feature: string, value: boolean) => {
|
|
// Optimistic update
|
|
setSettings(prev => ({ ...prev, [feature]: value }))
|
|
|
|
try {
|
|
setIsPending(true)
|
|
await updateAISettings({ [feature]: value })
|
|
toast.success(t('aiSettings.saved'))
|
|
} catch (error) {
|
|
console.error('Error updating setting:', error)
|
|
toast.error(t('aiSettings.error'))
|
|
// Revert on error
|
|
setSettings(initialSettings)
|
|
} finally {
|
|
setIsPending(false)
|
|
}
|
|
}
|
|
|
|
const handleFrequencyChange = async (value: 'daily' | 'weekly' | 'custom') => {
|
|
setSettings(prev => ({ ...prev, memoryEchoFrequency: value }))
|
|
|
|
try {
|
|
setIsPending(true)
|
|
await updateAISettings({ memoryEchoFrequency: value })
|
|
toast.success(t('aiSettings.saved'))
|
|
} catch (error) {
|
|
console.error('Error updating frequency:', error)
|
|
toast.error(t('aiSettings.error'))
|
|
setSettings(initialSettings)
|
|
} finally {
|
|
setIsPending(false)
|
|
}
|
|
}
|
|
|
|
|
|
|
|
const handleLanguageChange = async (value: 'auto' | 'en' | 'fr' | 'es' | 'de' | 'fa' | 'it' | 'pt' | 'ru' | 'zh' | 'ja' | 'ko' | 'ar' | 'hi' | 'nl' | 'pl') => {
|
|
setSettings(prev => ({ ...prev, preferredLanguage: value }))
|
|
|
|
try {
|
|
setIsPending(true)
|
|
await updateAISettings({ preferredLanguage: value })
|
|
toast.success(t('aiSettings.saved'))
|
|
} catch (error) {
|
|
console.error('Error updating language:', error)
|
|
toast.error(t('aiSettings.error'))
|
|
setSettings(initialSettings)
|
|
} finally {
|
|
setIsPending(false)
|
|
}
|
|
}
|
|
|
|
const handleDemoModeToggle = async (enabled: boolean) => {
|
|
setSettings(prev => ({ ...prev, demoMode: enabled }))
|
|
|
|
try {
|
|
setIsPending(true)
|
|
await updateAISettings({ demoMode: enabled })
|
|
} catch (error) {
|
|
console.error('Error toggling demo mode:', error)
|
|
toast.error(t('aiSettings.error'))
|
|
setSettings(initialSettings)
|
|
throw error
|
|
} finally {
|
|
setIsPending(false)
|
|
}
|
|
}
|
|
|
|
return (
|
|
<div className="space-y-6">
|
|
{isPending && (
|
|
<div className="flex items-center gap-2 text-sm text-gray-600 dark:text-gray-400">
|
|
<Loader2 className="h-4 w-4 animate-spin" />
|
|
{t('aiSettings.saving')}
|
|
</div>
|
|
)}
|
|
|
|
{/* Feature Toggles */}
|
|
<div className="space-y-4">
|
|
<h2 className="text-xl font-semibold">{t('aiSettings.features')}</h2>
|
|
|
|
<FeatureToggle
|
|
name={t('titleSuggestions.available').replace('💡 ', '')}
|
|
description={t('aiSettings.titleSuggestionsDesc')}
|
|
checked={settings.titleSuggestions}
|
|
onChange={(checked) => handleToggle('titleSuggestions', checked)}
|
|
/>
|
|
|
|
|
|
<FeatureToggle
|
|
name="Assistant IA"
|
|
description="Active le bouton de chat IA et les outils d'amélioration du texte"
|
|
checked={settings.paragraphRefactor}
|
|
onChange={(checked) => handleToggle('paragraphRefactor', checked)}
|
|
/>
|
|
|
|
<FeatureToggle
|
|
name={t('memoryEcho.title')}
|
|
description={t('memoryEcho.dailyInsight')}
|
|
checked={settings.memoryEcho}
|
|
onChange={(checked) => handleToggle('memoryEcho', checked)}
|
|
/>
|
|
|
|
{settings.memoryEcho && (
|
|
<Card className="p-4 ml-6">
|
|
<Label htmlFor="frequency" className="text-sm font-medium">
|
|
{t('aiSettings.frequency')}
|
|
</Label>
|
|
<p className="text-xs text-gray-500 mb-3">
|
|
{t('aiSettings.frequencyDesc')}
|
|
</p>
|
|
<RadioGroup
|
|
value={settings.memoryEchoFrequency}
|
|
onValueChange={handleFrequencyChange}
|
|
>
|
|
<div className="flex items-center space-x-2">
|
|
<RadioGroupItem value="daily" id="daily" />
|
|
<Label htmlFor="daily" className="font-normal">
|
|
{t('aiSettings.frequencyDaily')}
|
|
</Label>
|
|
</div>
|
|
<div className="flex items-center space-x-2">
|
|
<RadioGroupItem value="weekly" id="weekly" />
|
|
<Label htmlFor="weekly" className="font-normal">
|
|
{t('aiSettings.frequencyWeekly')}
|
|
</Label>
|
|
</div>
|
|
</RadioGroup>
|
|
</Card>
|
|
)}
|
|
|
|
{/* Language Detection Toggle */}
|
|
<FeatureToggle
|
|
name="Détection de langue"
|
|
description="Détecte automatiquement la langue de vos notes"
|
|
checked={settings.languageDetection ?? true}
|
|
onChange={(checked) => handleToggle('languageDetection', checked)}
|
|
/>
|
|
|
|
{/* Auto Labeling Toggle */}
|
|
<FeatureToggle
|
|
name="Suggestion des labels"
|
|
description="Suggère et applique des étiquettes automatiquement à vos notes"
|
|
checked={settings.autoLabeling ?? true}
|
|
onChange={(checked) => handleToggle('autoLabeling', checked)}
|
|
/>
|
|
|
|
{/* Demo Mode Toggle */}
|
|
<DemoModeToggle
|
|
demoMode={settings.demoMode}
|
|
onToggle={handleDemoModeToggle}
|
|
/>
|
|
</div>
|
|
|
|
|
|
</div>
|
|
)
|
|
}
|
|
|
|
interface FeatureToggleProps {
|
|
name: string
|
|
description: string
|
|
checked: boolean
|
|
onChange: (checked: boolean) => void
|
|
}
|
|
|
|
function FeatureToggle({ name, description, checked, onChange }: FeatureToggleProps) {
|
|
return (
|
|
<Card className="p-4">
|
|
<div className="flex items-center justify-between">
|
|
<div className="space-y-1">
|
|
<Label className="text-base font-medium">{name}</Label>
|
|
<p className="text-sm text-gray-500">{description}</p>
|
|
</div>
|
|
<Switch
|
|
checked={checked}
|
|
onCheckedChange={onChange}
|
|
disabled={false}
|
|
/>
|
|
</div>
|
|
</Card>
|
|
)
|
|
}
|