"use client" import { useState, useEffect } from "react" import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" import { Badge } from "@/components/ui/badge" import { Button } from "@/components/ui/button" import { Input } from "@/components/ui/input" import { Label } from "@/components/ui/label" import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select" import { Textarea } from "@/components/ui/textarea" import { Switch } from "@/components/ui/switch" import { User, Mail, Phone, MapPin, Calendar, Globe, Save, Edit, Trash2, Eye, EyeOff, Shield, Key, Bell, Settings as SettingsIcon, Download, Upload, RefreshCw, AlertTriangle, CheckCircle, XCircle, Info, Lock, Unlock, UserCheck, Users, Smartphone, Plus, X, } from "@/lib/icons" export default function SettingsPage() { const [activeTab, setActiveTab] = useState("profile") const [showAddDeviceModal, setShowAddDeviceModal] = useState(false) const [showExportConfirmation, setShowExportConfirmation] = useState(false) const [settings, setSettings] = useState({ profile: { firstName: "Utilisateur", lastName: "Démo", email: "demo@docv.fr", phone: "+33 1 23 45 67 89", position: "Administrateur", department: "Direction", bio: "Utilisateur de démonstration pour DocV", }, security: { sessionTimeout: "30", passwordLastChanged: new Date("2024-01-01"), devices: [ { id: "current", label: "Appareil actuel", addedAt: new Date().toISOString(), ratio: 100 }, ], }, notifications: { emailNotifications: true, pushNotifications: true, documentUpdates: true, folderSharing: true, systemAlerts: true, weeklyReport: false, }, appearance: { theme: "light", language: "fr", timezone: "Europe/Paris", dateFormat: "dd/mm/yyyy", compactMode: false, }, privacy: { profileVisibility: "team", activityTracking: true, dataSharing: false, analyticsOptIn: true, }, storage: { used: 67.3, total: 100, autoBackup: true, retentionPeriod: "365", }, }) const [isSaving, setIsSaving] = useState(false) const [notification, setNotification] = useState<{ type: "success" | "error" | "info"; message: string } | null>(null) const [showPairingWords, setShowPairingWords] = useState(false) const [isSyncing, setIsSyncing] = useState(false) const [syncProgress, setSyncProgress] = useState(0) const [isImporting, setIsImporting] = useState(false) const [isDarkTheme, setIsDarkTheme] = useState(false) const [newDeviceLabel, setNewDeviceLabel] = useState("") const [newDeviceRatio, setNewDeviceRatio] = useState(50) useEffect(() => { if (typeof window !== "undefined") { const saved = localStorage.getItem("theme") const dark = saved ? saved === "dark" : window.matchMedia("(prefers-color-scheme: dark)").matches setIsDarkTheme(dark) document.documentElement.classList.toggle("dark", dark) } }, []) const toggleTheme = (checked: boolean) => { setIsDarkTheme(checked) if (typeof document !== "undefined") { document.documentElement.classList.toggle("dark", checked) } if (typeof localStorage !== "undefined") { localStorage.setItem("theme", checked ? "dark" : "light") } } // Retrait de l'ouverture automatique de la modale d'appareil const showNotification = (type: "success" | "error" | "info", message: string) => { setNotification({ type, message }) setTimeout(() => setNotification(null), 3000) } const tabs = [ { id: "profile", name: "Profil", icon: User }, { id: "devices", name: "Appareils", icon: Smartphone }, { id: "import", name: "Import", icon: Upload }, { id: "sync", name: "Synchroniser", icon: RefreshCw }, ] const handleSave = async () => { setIsSaving(true) // Simuler la sauvegarde await new Promise((resolve) => setTimeout(resolve, 1000)) setIsSaving(false) showNotification("success", "Paramètres sauvegardés avec succès") } const handleExportData = () => { setShowExportConfirmation(true) } const confirmExportData = async () => { setShowExportConfirmation(false) showNotification("info", "Export des données en cours...") try { const data = await exportIndexedDB() const blob = new Blob([JSON.stringify(data, null, 2)], { type: "application/json" }) const url = URL.createObjectURL(blob) const a = document.createElement("a") a.href = url a.download = `docv-export-${new Date().toISOString().split("T")[0]}.json` document.body.appendChild(a) a.click() document.body.removeChild(a) URL.revokeObjectURL(url) showNotification("success", "Export terminé. Fichier téléchargé avec succès.") } catch (e: any) { showNotification("error", e?.message || "Échec de l'export IndexedDB") } } // Exporter toutes les bases IndexedDB (si supporté) async function exportIndexedDB() { const result: any = { timestamp: new Date().toISOString(), databases: [] as any[] } const dbList = (indexedDB as any).databases ? await (indexedDB as any).databases() : [] const dbNames: string[] = dbList?.map((d: any) => d.name).filter(Boolean) || [] // Fallback: si l'API databases() n'est pas dispo, utiliser une liste vide (app ne définit pas de DB explicites) for (const name of dbNames) { if (!name) continue const dbDump: any = { name, version: 1, stores: {} as any } const db: IDBDatabase = await new Promise((resolve, reject) => { const open = indexedDB.open(name) open.onsuccess = () => resolve(open.result) open.onerror = () => reject(open.error) }) dbDump.version = db.version const storeNames = Array.from(db.objectStoreNames) for (const storeName of storeNames) { dbDump.stores[storeName] = [] const tx = db.transaction(storeName, "readonly") const store = tx.objectStore(storeName) const all: any[] = await new Promise((resolve, reject) => { const req = store.getAll() req.onsuccess = () => resolve(req.result) req.onerror = () => reject(req.error) }) dbDump.stores[storeName] = all } db.close() result.databases.push(dbDump) } return result } async function importIndexedDBFromFile(file: File) { setIsImporting(true) try { const text = await file.text() const data = JSON.parse(text) if (!data?.databases) throw new Error("Fichier d'import invalide") for (const dbDump of data.databases) { const name = dbDump.name as string const version = dbDump.version as number const db: IDBDatabase = await new Promise((resolve, reject) => { const open = indexedDB.open(name, version) open.onupgradeneeded = () => { const dbu = open.result for (const storeName of Object.keys(dbDump.stores || {})) { if (!dbu.objectStoreNames.contains(storeName)) { dbu.createObjectStore(storeName, { autoIncrement: true }) } } } open.onsuccess = () => resolve(open.result) open.onerror = () => reject(open.error) }) for (const [storeName, records] of Object.entries(dbDump.stores || {})) { const tx = db.transaction(storeName, "readwrite") const store = tx.objectStore(storeName) await new Promise((resolve, reject) => { const clearReq = store.clear() clearReq.onsuccess = () => resolve(true) clearReq.onerror = () => reject(clearReq.error) }) for (const rec of records) { await new Promise((resolve, reject) => { const req = store.add(rec) req.onsuccess = () => resolve(true) req.onerror = () => reject(req.error) }) } } db.close() } showNotification("success", "Import terminé avec succès") } catch (e: any) { showNotification("error", e?.message || "Échec de l'import IndexedDB") } finally { setIsImporting(false) } } async function synchronizeIndexedDBPreserveKeys() { setIsSyncing(true) setSyncProgress(0) try { const dbList = (indexedDB as any).databases ? await (indexedDB as any).databases() : [] const dbNames: string[] = dbList?.map((d: any) => d.name).filter(Boolean) || [] let processed = 0 for (const name of dbNames) { const db: IDBDatabase = await new Promise((resolve, reject) => { const open = indexedDB.open(name) open.onsuccess = () => resolve(open.result) open.onerror = () => reject(open.error) }) const storeNames = Array.from(db.objectStoreNames) for (const storeName of storeNames) { const shouldPreserve = /key/i.test(storeName) if (shouldPreserve) continue const tx = db.transaction(storeName, "readwrite") const store = tx.objectStore(storeName) await new Promise((resolve, reject) => { const clearReq = store.clear() clearReq.onsuccess = () => resolve(true) clearReq.onerror = () => reject(clearReq.error) }) } db.close() processed += 1 setSyncProgress(Math.round((processed / Math.max(1, dbNames.length)) * 100)) } // Barre de progression finale setSyncProgress(100) showNotification("success", "Synchronisation lancée: données (hors clés) vidées") } catch (e: any) { showNotification("error", e?.message || "Échec de la synchronisation") } finally { setTimeout(() => setIsSyncing(false), 400) } } const generatePairingWords = () => { const words = ["alpha", "bravo", "charlie", "delta", "echo", "foxtrot", "golf", "hotel"] return Array.from({ length: 4 }, () => words[Math.floor(Math.random() * words.length)]) } const [pairingWords] = useState(generatePairingWords()) const handleAddDevice = () => { setShowAddDeviceModal(false) setSettings((prev) => ({ ...prev, security: { ...prev.security, activeDevices: prev.security.activeDevices + 1, }, })) showNotification("success", "Instructions d'appairage générées. Suivez les étapes sur votre autre appareil.") } const renderProfileTab = () => (
Informations personnelles
{settings.profile.firstName.charAt(0)} {settings.profile.lastName.charAt(0)}

JPG, PNG ou GIF. Max 2MB.

setSettings({ ...settings, profile: { ...settings.profile, firstName: e.target.value }, }) } />
setSettings({ ...settings, profile: { ...settings.profile, lastName: e.target.value }, }) } />
setSettings({ ...settings, profile: { ...settings.profile, email: e.target.value }, }) } />
setSettings({ ...settings, profile: { ...settings.profile, phone: e.target.value }, }) } />
setSettings({ ...settings, profile: { ...settings.profile, position: e.target.value }, }) } />
setSettings({ ...settings, profile: { ...settings.profile, department: e.target.value }, }) } />