"use client" import { useState, useEffect, useCallback } from "react" import { useRouter, useSearchParams } from "next/navigation" import { Card, CardContent } 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 { Checkbox } from "@/components/ui/checkbox" import { Textarea } from "@/components/ui/textarea" import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select" import { Folder, FolderOpen, Grid3X3, List, Search, Filter, Share2, Trash2, Users, FileText, Clock, Star, ChevronRight, FolderPlus, Upload, Download, Lock, SortAsc, SortDesc, X, UserPlus, Crown, Shield, User, CheckCircle, XCircle, Info, CloudUpload, Cloud, HardDrive, FileQuestion, Timer, ShieldCheck, Archive, FileCheck, } from "lucide-react" import ProcessesViewer from "@/components/4nk/ProcessesViewer" import { FolderData as SDKFolderData, FolderCreated, FolderPrivateFields, setDefaultFolderRoles } from "@/lib/4nk/models/FolderData" import MessageBus from "@/lib/4nk/MessageBus" import { iframeUrl } from "@/app/page" import UserStore from "@/lib/4nk/UserStore" import EventBus from "@/lib/4nk/EventBus" import FolderModal from "@/components/4nk/FolderModal" import AuthModal from "@/components/4nk/AuthModal" import Iframe from "@/components/4nk/Iframe" interface FolderData { id: number name: string description: string documentsCount: number subfoldersCount: number size: string created: Date modified: Date owner: string access: "shared" | "private" members: string[] tags: string[] color: string favorite: boolean storageType: "temporary" | "permanent" status: "active" | "archived" | "pending" | "completed" | "validated" type: string expectedDocuments: Array<{ name: string required: boolean assignedRole: "owner" | "editor" | "validator" | "contributor" status: "missing" | "pending" | "received" }> activity: Array<{ user: string action: string item: string time: string }> permissions: { canView: boolean canEdit: boolean canDelete: boolean canInvite: boolean canArchive: boolean canAnalyze: boolean } temporaryStorageConfig?: { duration: number // en jours dataUsage: string thirdPartyAccess: string } documents?: Array<{ id: string name: string hasCertificate: boolean certificateId?: string }> } interface ActionModal { type: | "invite" | "delete" | "create" | "edit" | "archive" | "request_document" | "storage_config" | "certificate" | "documents_certificates" | null folder: FolderData | null folders: FolderData[] } interface UserWithRoles { id: string name: string email: string avatar: string folderRoles: { [folderId: string]: { role: "owner" | "editor" | "viewer" | "validator" | "contributor" assignedDate: Date } } spaceRole: "admin" | "manager" | "user" | "guest" spaceRoles: { [spaceId: string]: { role: "admin" | "manager" | "user" | "guest" spaceName: string } } } interface Role { id: string name: string description: string level: "folder" | "space" | "global" } type FolderType = string; export default function FoldersPage() { const router = useRouter() const searchParams = useSearchParams() const [viewMode, setViewMode] = useState<'list'>('list') const [searchTerm, setSearchTerm] = useState("") const [selectedFolders, setSelectedFolders] = useState([]) const [sortBy, setSortBy] = useState("modified") const [sortOrder, setSortOrder] = useState<"asc" | "desc">("desc") const [filterAccess, setFilterAccess] = useState("all") const [filterOwner, setFilterOwner] = useState("all") const [filterStorage, setFilterStorage] = useState("all") const [showFilters, setShowFilters] = useState(false) const [currentPath, setCurrentPath] = useState(["Racine"]) const [actionModal, setActionModal] = useState({ type: null, folder: null, folders: [] }) const [showCreateFolderModal, setShowCreateFolderModal] = useState(false) const [folderType, setFolderType] = useState(null); const [isModalOpen, setIsModalOpen] = useState(false); const [menuOpen, setMenuOpen] = useState(false); // 4NK Integration states const [isConnected, setIsConnected] = useState(false) const [showAuthModal, setShowAuthModal] = useState(false) const [processes, setProcesses] = useState(null) const [myProcesses, setMyProcesses] = useState([]) const [userPairingId, setUserPairingId] = useState(null) // Modal states const [inviteMessage, setInviteMessage] = useState("") const [selectedUser, setSelectedUser] = useState("") const [selectedRole, setSelectedRole] = useState("") const [inviteScope, setInviteScope] = useState<"user" | "role">("user") const [folderName, setFolderName] = useState("") const [folderDescription, setFolderDescription] = useState("") const [folderColor, setFolderColor] = useState("blue") const [folderTags, setFolderTags] = useState("") const [folderAccess, setFolderAccess] = useState<"shared" | "private">("private") const [archiveReason, setArchiveReason] = useState("") const [retentionPeriod, setRetentionPeriod] = useState("5") const [selectedDocument, setSelectedDocument] = useState("") const [requestMessage, setRequestMessage] = useState("") const [notification, setNotification] = useState<{ type: "success" | "error" | "info"; message: string } | null>(null) // Storage config modal states const [storageDuration, setStorageDuration] = useState("30") const [dataUsage, setDataUsage] = useState("") const [thirdPartyAccess, setThirdPartyAccess] = useState("") const [folders, setFolders] = useState([]) const [stats, setStats] = useState({ total: 0, shared: 0, private: 0, thisWeek: 0, permanent: 0, temporary: 0, }) const [users] = useState([ { id: "1", name: "Marie Dubois", email: "marie.dubois@company.com", avatar: "MD", folderRoles: { "1": { role: "owner", assignedDate: new Date("2024-01-01") }, "4": { role: "editor", assignedDate: new Date("2024-01-05") }, }, spaceRole: "manager", spaceRoles: { main: { role: "manager", spaceName: "Espace Principal" }, legal: { role: "admin", spaceName: "Espace Juridique" }, }, }, { id: "2", name: "Sophie Laurent", email: "sophie.laurent@company.com", avatar: "SL", folderRoles: { "2": { role: "owner", assignedDate: new Date("2024-01-02") }, "3": { role: "contributor", assignedDate: new Date("2024-01-10") }, }, spaceRole: "user", spaceRoles: { main: { role: "user", spaceName: "Espace Principal" }, analytics: { role: "manager", spaceName: "Espace Analytics" }, }, }, { id: "3", name: "Jean Martin", email: "jean.martin@company.com", avatar: "JM", folderRoles: { "3": { role: "owner", assignedDate: new Date("2024-01-03") }, "2": { role: "viewer", assignedDate: new Date("2024-01-15") }, }, spaceRole: "user", spaceRoles: { main: { role: "user", spaceName: "Espace Principal" }, projects: { role: "admin", spaceName: "Espace Projets" }, }, }, { id: "4", name: "Pierre Durand", email: "pierre.durand@company.com", avatar: "PD", folderRoles: { "6": { role: "owner", assignedDate: new Date("2024-01-04") }, "5": { role: "validator", assignedDate: new Date("2024-01-08") }, }, spaceRole: "user", spaceRoles: { main: { role: "user", spaceName: "Espace Principal" }, training: { role: "admin", spaceName: "Espace Formation" }, }, }, { id: "5", name: "Admin Système", email: "admin@company.com", avatar: "AD", folderRoles: { "5": { role: "owner", assignedDate: new Date("2024-01-01") }, "1": { role: "validator", assignedDate: new Date("2024-01-01") }, "4": { role: "validator", assignedDate: new Date("2024-01-01") }, }, spaceRole: "admin", spaceRoles: { main: { role: "admin", spaceName: "Espace Principal" }, legal: { role: "admin", spaceName: "Espace Juridique" }, analytics: { role: "admin", spaceName: "Espace Analytics" }, projects: { role: "admin", spaceName: "Espace Projets" }, training: { role: "admin", spaceName: "Espace Formation" }, }, }, ]) const [roles] = useState([ { id: "folder-owner", name: "Propriétaire du dossier", description: "Contrôle total sur le dossier", level: "folder", }, { id: "folder-editor", name: "Éditeur du dossier", description: "Peut modifier les documents", level: "folder" }, { id: "folder-validator", name: "Validateur du dossier", description: "Peut valider les documents", level: "folder", }, { id: "folder-contributor", name: "Contributeur du dossier", description: "Peut ajouter des documents", level: "folder", }, { id: "folder-viewer", name: "Lecteur du dossier", description: "Lecture seule", level: "folder" }, { id: "space-admin", name: "Administrateur d'espace", description: "Contrôle total sur l'espace", level: "space" }, { id: "space-manager", name: "Gestionnaire d'espace", description: "Gestion des utilisateurs et dossiers", level: "space", }, { id: "space-user", name: "Utilisateur d'espace", description: "Accès standard à l'espace", level: "space" }, { id: "space-guest", name: "Invité d'espace", description: "Accès limité à l'espace", level: "space" }, { id: "global-admin", name: "Administrateur global", description: "Accès à tous les espaces", level: "global" }, { id: "global-manager", name: "Gestionnaire global", description: "Gestion multi-espaces", level: "global" }, ]) const colors = [ { id: "blue", name: "Bleu", class: "text-blue-600 bg-blue-100" }, { id: "green", name: "Vert", class: "text-green-600 bg-green-100" }, { id: "purple", name: "Violet", class: "text-purple-600 bg-purple-100" }, { id: "orange", name: "Orange", class: "text-orange-600 bg-orange-100" }, { id: "red", name: "Rouge", class: "text-red-600 bg-red-100" }, { id: "pink", name: "Rose", class: "text-pink-600 bg-pink-100" }, { id: "yellow", name: "Jaune", class: "text-yellow-600 bg-yellow-100" }, { id: "gray", name: "Gris", class: "text-gray-600 bg-gray-100" }, ] // 4NK Integration useEffects useEffect(() => { const userStore = UserStore.getInstance(); const connected = userStore.isConnected(); const pairingId = userStore.getUserPairingId(); console.log('Initialisation 4NK:', { connected, pairingId }); setIsConnected(connected); setUserPairingId(pairingId); }, []); useEffect(() => { const handleConnectionFlow = async () => { if (!isConnected) return; const userStore = UserStore.getInstance(); const messageBus = MessageBus.getInstance(iframeUrl); try { await messageBus.isReady(); let pairingId = userStore.getUserPairingId(); // 1️⃣ Créer le pairing si non existant if (!pairingId) { console.log("🚀 No pairing found — creating new pairing..."); pairingId = await messageBus.createUserPairing(); console.log("✅ Pairing created:", pairingId); userStore.pair(pairingId); setUserPairingId(pairingId); } else { console.log("🔗 Already paired with ID:", pairingId); } // 2️⃣ Charger les processes const processes = await messageBus.getProcesses(); setProcesses(processes); // 3️⃣ Charger les myProcesses const myProcesses = await messageBus.getMyProcesses(); setMyProcesses(myProcesses); } catch (err) { console.error("❌ Error during pairing or process loading:", err); } }; handleConnectionFlow(); }, [isConnected, iframeUrl]); useEffect(() => { // Simuler le chargement des dossiers const loadFolders = () => { const mockFolders: FolderData[] = [] setFolders(mockFolders) setStats({ total: mockFolders.length, shared: mockFolders.filter((folder) => folder.access === "shared").length, private: mockFolders.filter((folder) => folder.access === "private").length, thisWeek: mockFolders.filter((folder) => { const weekAgo = new Date() weekAgo.setDate(weekAgo.getDate() - 7) return folder.modified > weekAgo }).length, permanent: mockFolders.filter((folder) => folder.storageType === "permanent").length, temporary: mockFolders.filter((folder) => folder.storageType === "temporary").length, }) } loadFolders() }, []) // Notification system const showNotification = (type: "success" | "error" | "info", message: string) => { setNotification({ type, message }) setTimeout(() => setNotification(null), 3000) } // 4NK Authentication handlers const handleLogin = useCallback(() => { setShowAuthModal(true); }, []); const handleLogout = useCallback(() => { UserStore.getInstance().disconnect(); setIsConnected(false); setProcesses(null); setMyProcesses([]); setUserPairingId(null); // Émettre un événement pour vider les messages locaux EventBus.getInstance().emit('CLEAR_CONSOLE'); showNotification("info", "Déconnexion réussie"); }, []); const handleAuthConnect = useCallback(() => { setIsConnected(true); setShowAuthModal(false); console.log('Auth Connect - Connexion établie, le useEffect se chargera de récupérer le userPairingId'); showNotification("success", "Connexion 4NK réussie"); }, []); const handleAuthClose = useCallback(() => { setShowAuthModal(false); }, []); // Fonction pour envoyer une notification dans le chat du dossier const sendFolderChatNotification = (folderId: string, message: string, actionType: string) => { const folderUsers = users.filter((user) => user.folderRoles[folderId]) console.log("Notification envoyée dans le chat du dossier:", { folderId, recipients: folderUsers.map((u) => ({ name: u.name, role: u.folderRoles[folderId]?.role })), message, actionType, timestamp: new Date().toISOString(), }) folderUsers.forEach((user) => { console.log(`📱 Notification push envoyée à ${user.name} (${user.email})`) }) } // Fonction pour organiser les utilisateurs par rôles const organizeUsersForInvitation = (currentFolderId: string) => { const organized = { folderRoles: {} as { [role: string]: UserWithRoles[] }, spaceRoles: {} as { [role: string]: UserWithRoles[] }, otherSpaces: {} as { [spaceName: string]: UserWithRoles[] }, } users.forEach((user) => { if (user.folderRoles[currentFolderId]) { const role = user.folderRoles[currentFolderId].role if (!organized.folderRoles[role]) organized.folderRoles[role] = [] organized.folderRoles[role].push(user) } const spaceRole = user.spaceRole if (!organized.spaceRoles[spaceRole]) organized.spaceRoles[spaceRole] = [] organized.spaceRoles[spaceRole].push(user) Object.values(user.spaceRoles).forEach((spaceInfo) => { if (spaceInfo.spaceName !== "Espace Principal") { if (!organized.otherSpaces[spaceInfo.spaceName]) organized.otherSpaces[spaceInfo.spaceName] = [] organized.otherSpaces[spaceInfo.spaceName].push(user) } }) }) return organized } // Folder actions const handleOpenFolder = (folder: FolderData) => { // Rediriger vers la page documents avec le filtre du dossier router.push(`/dashboard/documents?folder=${encodeURIComponent(folder.name)}`) } const handleInviteFolder = (folder: FolderData) => { setInviteMessage("") setSelectedUser("") setSelectedRole("") setInviteScope("user") setActionModal({ type: "invite", folder, folders: [] }) } const handleArchiveFolder = (folder: FolderData) => { setArchiveReason("") setRetentionPeriod("5") setActionModal({ type: "archive", folder, folders: [] }) } const handleStorageConfig = (folder: FolderData) => { setStorageDuration(folder.temporaryStorageConfig?.duration.toString() || "30") setDataUsage(folder.temporaryStorageConfig?.dataUsage || "") setThirdPartyAccess(folder.temporaryStorageConfig?.thirdPartyAccess || "") setActionModal({ type: "storage_config", folder, folders: [] }) } const handleAIAnalysis = (folder: FolderData) => { showNotification("info", `Analyse IA en cours pour ${folder.name}...`) // Simuler une analyse IA setTimeout( () => { const analysisResults = [ `📊 **Analyse du dossier "${folder.name}"**\n\n` + `**Contenu :** ${folder.documentsCount} documents analysés (${folder.size})\n` + `**Thématiques principales :** ${folder.tags.join(", ")}\n` + `**Niveau d'activité :** ${folder.activity.length > 2 ? "Élevé" : "Modéré"} (dernière modification ${formatDate(folder.modified)})\n\n` + `**Recommandations :**\n` + `• ${folder.storageType === "temporary" ? "Considérer l'archivage vers le stockage permanent" : "Dossier déjà archivé de manière optimale"}\n` + `• ${folder.access === "private" ? "Évaluer les possibilités de partage avec l'équipe" : "Partage actuel avec " + folder.members.length + " membre(s)"}\n` + `• Dernière activité significative détectée il y a ${Math.floor(Math.random() * 7) + 1} jour(s)\n\n` + `**Score de pertinence :** ${Math.floor(Math.random() * 30) + 70}/100`, `🔍 **Analyse approfondie du dossier "${folder.name}"**\n\n` + `**Structure documentaire :**\n` + `• ${Math.floor(folder.documentsCount * 0.4)} documents principaux\n` + `• ${Math.floor(folder.documentsCount * 0.3)} documents de support\n` + `• ${Math.floor(folder.documentsCount * 0.3)} documents annexes\n\n` + `**Analyse temporelle :**\n` + `• Création : ${folder.created.toLocaleDateString("fr-FR")}\n` + `• Pic d'activité détecté en ${new Date().toLocaleDateString("fr-FR", { month: "long", year: "numeric" })}\n` + `• Tendance : ${Math.random() > 0.5 ? "Croissante" : "Stable"}\n\n` + `**Recommandations stratégiques :**\n` + `• ${folder.documentsCount > 50 ? "Envisager une réorganisation en sous-dossiers" : "Structure actuelle optimale"}\n` + `• ${folder.members.length < 3 ? "Potentiel de collaboration à explorer" : "Équipe collaborative active"}\n` + `• Prochaine révision recommandée : ${new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toLocaleDateString("fr-FR")}`, `🎯 **Insights IA pour "${folder.name}"**\n\n` + `**Analyse sémantique :**\n` + `• Cohérence thématique : ${Math.floor(Math.random() * 20) + 80}%\n` + `• Mots-clés dominants : ${folder.tags.slice(0, 3).join(", ")}\n` + `• Complexité moyenne : ${["Faible", "Modérée", "Élevée"][Math.floor(Math.random() * 3)]}\n\n` + `**Patterns détectés :**\n` + `• ${Math.random() > 0.5 ? "Cycle de révision régulier identifié" : "Activité sporadique détectée"}\n` + `• ${Math.random() > 0.5 ? "Collaboration inter-équipes active" : "Usage principalement individuel"}\n` + `• ${folder.storageType === "permanent" ? "Archivage conforme aux bonnes pratiques" : "Optimisation de stockage possible"}\n\n` + `**Actions suggérées :**\n` + `• ${Math.random() > 0.5 ? "Créer un template basé sur ce dossier" : "Standardiser la nomenclature"}\n` + `• ${Math.random() > 0.5 ? "Planifier une session de nettoyage" : "Maintenir la structure actuelle"}\n` + `• Prochaine analyse automatique : ${new Date(Date.now() + 90 * 24 * 60 * 60 * 1000).toLocaleDateString("fr-FR")}`, ] const randomAnalysis = analysisResults[Math.floor(Math.random() * analysisResults.length)] // Envoyer l'analyse dans le chat du dossier sendFolderChatNotification(folder.id.toString(), `🤖 ${randomAnalysis}`, "ai_analysis") showNotification("success", `Analyse IA terminée pour ${folder.name}. Redirection vers le chat...`) // Rediriger vers le chat après 1.5 secondes setTimeout(() => { router.push("/dashboard/chat") }, 1500) }, 2000 + Math.random() * 3000, ) } const handleViewCertificate = (folder: FolderData) => { setActionModal({ type: "certificate", folder, folders: [] }) } const handleViewDocumentsCertificates = (folder: FolderData) => { setActionModal({ type: "documents_certificates", folder, folders: [] }) } const handleDownloadCertificate = (folder: FolderData) => { if (folder.status === "validated") { showNotification("info", `Téléchargement du certificat blockchain pour le dossier ${folder.name}...`) sendFolderChatNotification( folder.id.toString(), `🔗 Certificat blockchain du dossier téléchargé`, "folder_blockchain_certificate_download", ) setTimeout(() => { showNotification("success", `Certificat blockchain du dossier ${folder.name} téléchargé avec succès`) }, 2000) } } const handleManageRoles = (folder: FolderData) => { // Rediriger vers la gestion des rôles du dossier router.push(`/dashboard/folders/${folder.id}/roles`) } const handleRequestDocument = (folder: FolderData) => { setSelectedDocument("") setRequestMessage("") setActionModal({ type: "request_document", folder, folders: [] }) } const handleDeleteFolder = (folder: FolderData) => { setActionModal({ type: "delete", folder, folders: [] }) } const handleOpenModal = (type: FolderType) => { setFolderType(type); setIsModalOpen(true); setMenuOpen(false); }; const handleCloseModal = () => { setIsModalOpen(false); setFolderType(null); }; const handleSaveNewFolder = useCallback( (folderData: SDKFolderData) => { if (!isConnected || !userPairingId) { console.error('Conditions non remplies:', { isConnected, userPairingId }); showNotification( "error", `Vous devez être connecté à 4NK pour créer un dossier (Connected: ${isConnected}, PairingId: ${userPairingId ? 'OK' : 'NULL'})` ); return; } // Ajout du type dans les données du dossier const folderToCreate = { ...folderData, type: folderType }; const roles = setDefaultFolderRoles(userPairingId, [], []); const folderPrivateFields = FolderPrivateFields; MessageBus.getInstance(iframeUrl) .createFolder(folderToCreate, folderPrivateFields, roles) .then((_folderCreated: FolderCreated) => { const firstStateId = _folderCreated.process.states[0].state_id; MessageBus.getInstance(iframeUrl) .notifyProcessUpdate(_folderCreated.processId, firstStateId) .then(() => MessageBus.getInstance(iframeUrl) .validateState(_folderCreated.processId, firstStateId) .then(() => MessageBus.getInstance(iframeUrl) .getProcesses() .then(async (processes: any) => { setProcesses(processes) }) ) ); setShowCreateFolderModal(false); showNotification("success", `Dossier "${folderData.name}" créé avec succès sur 4NK`); }) .catch((error) => { console.error('Erreur lors de la création du dossier 4NK:', error); showNotification("error", "Erreur lors de la création du dossier"); }); }, [userPairingId, isConnected, iframeUrl, folderType] ); const handleToggleFavorite = (folderId: number) => { const folder = folders.find((f) => f.id === folderId) if (!folder) return setFolders((prev) => prev.map((f) => (f.id === folderId ? { ...f, favorite: !f.favorite } : f))) const action = folder.favorite ? "retiré des" : "ajouté aux" showNotification("success", `${folder.name} ${action} favoris`) sendFolderChatNotification(folderId.toString(), `⭐ Le dossier a été ${action} favoris`, "favorite") } // Bulk actions const handleBulkDownload = () => { const selectedFolderData = folders.filter((folder) => selectedFolders.includes(folder.id)) showNotification("info", `Téléchargement de ${selectedFolderData.length} dossier(s)...`) selectedFolderData.forEach((folder) => { sendFolderChatNotification(folder.id.toString(), `📥 Le dossier a été téléchargé`, "download") }) setTimeout(() => { showNotification("success", `${selectedFolderData.length} dossier(s) téléchargé(s) avec succès`) setSelectedFolders([]) }, 2000) } const handleBulkInvite = () => { const selectedFolderData = folders.filter( (folder) => selectedFolders.includes(folder.id) && folder.permissions.canInvite, ) if (selectedFolderData.length === 0) { showNotification("error", "Aucun dossier sélectionné ne peut être partagé") return } setInviteMessage("") setSelectedUser("") setSelectedRole("") setInviteScope("user") setActionModal({ type: "invite", folder: null, folders: selectedFolderData }) } const handleBulkArchive = () => { const selectedFolderData = folders.filter( (folder) => selectedFolders.includes(folder.id) && folder.permissions.canArchive, ) if (selectedFolderData.length === 0) { showNotification("error", "Aucun dossier sélectionné ne peut être archivé") return } setArchiveReason("") setRetentionPeriod("5") setActionModal({ type: "archive", folder: null, folders: selectedFolderData }) } const handleBulkAIAnalysis = () => { const selectedFolderData = folders.filter( (folder) => selectedFolders.includes(folder.id) && folder.permissions.canAnalyze, ) if (selectedFolderData.length === 0) { showNotification("error", "Aucun dossier sélectionné ne peut être analysé") return } showNotification("info", `Analyse IA en cours pour ${selectedFolderData.length} dossier(s)...`) // Analyser chaque dossier avec un délai échelonné selectedFolderData.forEach((folder, index) => { setTimeout(() => { const bulkAnalysis = `📊 **Analyse IA groupée - Dossier "${folder.name}"**\n\n` + `**Position dans l'analyse :** ${index + 1}/${selectedFolderData.length}\n` + `**Contenu :** ${folder.documentsCount} documents (${folder.size})\n` + `**Tags :** ${folder.tags.join(", ")}\n\n` + `**Analyse comparative :**\n` + `• Taille relative : ${folder.documentsCount > 40 ? "Au-dessus de la moyenne" : "Dans la moyenne"}\n` + `• Activité : ${folder.activity.length > 1 ? "Active" : "Modérée"}\n` + `• Collaboration : ${folder.members.length} membre(s)\n\n` + `**Recommandation :** ${folder.storageType === "temporary" ? "Candidat à l'archivage" : "Archivage optimal"}\n` + `**Score global :** ${Math.floor(Math.random() * 30) + 70}/100` sendFolderChatNotification(folder.id.toString(), `🤖 ${bulkAnalysis}`, "bulk_ai_analysis") }, index * 1500) // Échelonner les analyses }) setTimeout( () => { const totalDocs = selectedFolderData.reduce((sum, folder) => sum + folder.documentsCount, 0) showNotification( "success", `Analyse IA terminée pour ${selectedFolderData.length} dossier(s) (${totalDocs} documents). Redirection vers le chat...`, ) setSelectedFolders([]) // Rediriger vers le chat après l'analyse groupée setTimeout(() => { router.push("/dashboard/chat") }, 1500) }, selectedFolderData.length * 1500 + 1000, ) } const handleBulkDelete = () => { const selectedFolderData = folders.filter( (folder) => selectedFolders.includes(folder.id) && folder.permissions.canDelete, ) if (selectedFolderData.length === 0) { showNotification("error", "Aucun dossier sélectionné ne peut être supprimé") return } setActionModal({ type: "delete", folder: null, folders: selectedFolderData }) } // Modal actions const confirmInvite = () => { const recipient = inviteScope === "user" ? users.find((u) => u.id === selectedUser)?.name : roles.find((r) => r.id === selectedRole)?.name if (actionModal.folder) { showNotification("success", `${actionModal.folder.name} partagé avec ${recipient}. Un message a été envoyé.`) sendFolderChatNotification( actionModal.folder.id.toString(), `👥 Le dossier a été partagé avec ${recipient}. Message: ${inviteMessage}`, "invite", ) } else if (actionModal.folders.length > 0) { actionModal.folders.forEach((folder) => { sendFolderChatNotification( folder.id.toString(), `👥 Le dossier a été partagé avec ${recipient}. Message: ${inviteMessage}`, "bulk_invite", ) }) showNotification( "success", `${actionModal.folders.length} dossier(s) partagé(s) avec ${recipient}. Messages envoyés.`, ) setSelectedFolders([]) } setActionModal({ type: null, folder: null, folders: [] }) } const confirmRequestDocument = () => { if (actionModal.folder && selectedDocument) { const document = actionModal.folder.expectedDocuments.find((doc) => doc.name === selectedDocument) if (document) { // Trouver l'utilisateur avec le rôle assigné const assignedUser = users.find( (user) => user.folderRoles[actionModal.folder!.id.toString()]?.role === document.assignedRole, ) if (assignedUser) { // Préparer les données pour le chat const messageData = { userName: assignedUser.name, subject: `Demande de document - ${selectedDocument}`, content: `Bonjour ${assignedUser.name},\n\nPouvez-vous fournir le document "${selectedDocument}" pour le dossier "${actionModal.folder.name}" ?\n\n${requestMessage}\n\nMerci !`, } // Stocker dans sessionStorage pour le chat sessionStorage.setItem("newMessage", JSON.stringify(messageData)) showNotification("success", `Demande envoyée à ${assignedUser.name}. Redirection vers le chat...`) // Rediriger vers le chat avec l'utilisateur setTimeout(() => { router.push(`/dashboard/chat?user=${assignedUser.id}&message=new`) }, 1500) } else { showNotification("error", "Aucun utilisateur trouvé avec le rôle requis pour ce document") } } } setActionModal({ type: null, folder: null, folders: [] }) } const confirmStorageConfig = () => { if (actionModal.folder) { const updatedFolder = { ...actionModal.folder, temporaryStorageConfig: { duration: Number.parseInt(storageDuration), dataUsage: dataUsage, thirdPartyAccess: thirdPartyAccess, }, modified: new Date(), } setFolders((prev) => prev.map((f) => (f.id === updatedFolder.id ? updatedFolder : f))) showNotification("success", `Configuration du stockage temporaire mise à jour pour ${actionModal.folder.name}`) // Notification dans le chat du dossier const message = `⚙️ Configuration du stockage temporaire mise à jour :\n• Durée : ${storageDuration} jours\n• Usage : ${dataUsage}\n• Accès tiers : ${thirdPartyAccess}` sendFolderChatNotification(actionModal.folder.id.toString(), message, "storage_config") } setActionModal({ type: null, folder: null, folders: [] }) } const confirmArchive = () => { if (actionModal.folder) { const updatedFolder = { ...actionModal.folder, storageType: "permanent" as const, modified: new Date(), } setFolders((prev) => prev.map((f) => (f.id === updatedFolder.id ? updatedFolder : f))) showNotification( "success", `${actionModal.folder.name} et tous ses documents archivés vers le stockage permanent`, ) // Notification dans le chat du dossier let message = `📦 Le dossier et tous ses ${actionModal.folder.documentsCount} document(s) ont été archivés vers le stockage permanent (conservation: ${retentionPeriod} ans)` if (archiveReason.trim()) { message += ` - Raison: ${archiveReason}` } sendFolderChatNotification(actionModal.folder.id.toString(), message, "archive") } else if (actionModal.folders.length > 0) { const folderIds = actionModal.folders.map((f) => f.id) setFolders((prev) => prev.map((f) => folderIds.includes(f.id) ? { ...f, storageType: "permanent" as const, modified: new Date(), } : f, ), ) actionModal.folders.forEach((folder) => { let message = `📦 Le dossier et tous ses ${folder.documentsCount} document(s) ont été archivés vers le stockage permanent (conservation: ${retentionPeriod} ans)` if (archiveReason.trim()) { message += ` - Raison: ${archiveReason}` } sendFolderChatNotification(folder.id.toString(), message, "bulk_archive") }) const totalDocuments = actionModal.folders.reduce((sum, folder) => sum + folder.documentsCount, 0) showNotification( "success", `${actionModal.folders.length} dossier(s) et ${totalDocuments} document(s) archivés vers le stockage permanent`, ) setSelectedFolders([]) } setActionModal({ type: null, folder: null, folders: [] }) } const confirmCreate = () => { const newFolder: FolderData = { id: Math.max(...folders.map((f) => f.id)) + 1, name: folderName, description: folderDescription, documentsCount: 0, subfoldersCount: 0, size: "0 MB", created: new Date(), modified: new Date(), owner: "Utilisateur actuel", access: folderAccess, members: ["Utilisateur actuel"], tags: folderTags .split(",") .map((tag) => tag.trim()) .filter((tag) => tag), color: folderColor, favorite: false, storageType: "temporary", status: "active", type: "general", expectedDocuments: [], activity: [], permissions: { canView: true, canEdit: true, canDelete: true, canInvite: true, canArchive: true, canAnalyze: true, }, documents: [], } setFolders((prev) => [...prev, newFolder]) showNotification("success", `Dossier "${folderName}" créé avec succès`) setActionModal({ type: null, folder: null, folders: [] }) } const confirmDelete = () => { if (actionModal.folder) { sendFolderChatNotification(actionModal.folder.id.toString(), `🗑️ Le dossier a été supprimé`, "delete") setFolders((prev) => prev.filter((f) => f.id !== actionModal.folder!.id)) showNotification("success", `${actionModal.folder.name} supprimé`) } else if (actionModal.folders.length > 0) { actionModal.folders.forEach((folder) => { sendFolderChatNotification(folder.id.toString(), `🗑️ Le dossier a été supprimé`, "bulk_delete") }) const folderIds = actionModal.folders.map((f) => f.id) setFolders((prev) => prev.filter((f) => !folderIds.includes(f.id))) showNotification("success", `${actionModal.folders.length} dossier(s) supprimé(s)`) setSelectedFolders([]) } setActionModal({ type: null, folder: null, folders: [] }) } const typeFilter = searchParams.get("type") const filteredFolders = folders .filter((folder) => { if (searchTerm && !folder.name.toLowerCase().includes(searchTerm.toLowerCase())) { return false } if (typeFilter && folder.type !== typeFilter) { return false } if (filterAccess !== "all" && folder.access !== filterAccess) { return false } if (filterOwner !== "all" && folder.owner !== filterOwner) { return false } if (filterStorage !== "all" && folder.storageType !== filterStorage) { return false } return true }) .sort((a, b) => { let aValue, bValue switch (sortBy) { case "name": aValue = a.name.toLowerCase() bValue = b.name.toLowerCase() break case "size": aValue = Number.parseFloat(a.size.replace(/[^\d.]/g, "")) bValue = Number.parseFloat(b.size.replace(/[^\d.]/g, "")) break case "owner": aValue = a.owner.toLowerCase() bValue = b.owner.toLowerCase() break case "documents": aValue = a.documentsCount bValue = b.documentsCount break case "modified": default: aValue = a.modified.getTime() bValue = b.modified.getTime() break } if (sortOrder === "asc") { return aValue > bValue ? 1 : -1 } else { return aValue < bValue ? 1 : -1 } }) const getFolderColor = (color: string) => { const colorObj = colors.find((c) => c.id === color) return colorObj?.class || "text-gray-600 bg-gray-100" } const isNewFolder = (folder: FolderData) => { const now = Date.now() const diffMs = now - folder.modified.getTime() const twoDaysMs = 2 * 24 * 60 * 60 * 1000 return diffMs <= twoDaysMs } const getStorageIcon = (storageType: string) => { return storageType === "permanent" ? ( ) : ( ) } const getRoleIcon = (role: string) => { switch (role) { case "owner": return case "editor": return case "validator": return case "contributor": return case "viewer": return case "admin": return case "manager": return case "user": return case "guest": return default: return } } const getStatusBadge = (status: string) => { switch (status) { case "active": return Actif case "pending": return En attente case "completed": return Terminé case "archived": return Archivé case "validated": return Validé default: return Inconnu } } const formatDate = (date: Date) => { const now = new Date() const diffInHours = (now.getTime() - date.getTime()) / (1000 * 60 * 60) if (diffInHours < 1) { return "Il y a quelques minutes" } else if (diffInHours < 24) { return `Il y a ${Math.floor(diffInHours)} heure${Math.floor(diffInHours) > 1 ? "s" : ""}` } else if (diffInHours < 48) { return "Hier" } else { return date.toLocaleDateString("fr-FR") } } const toggleFolderSelection = (folderId: number) => { setSelectedFolders((prev) => (prev.includes(folderId) ? prev.filter((id) => id !== folderId) : [...prev, folderId])) } const selectAllFolders = () => { if (selectedFolders.length === filteredFolders.length) { setSelectedFolders([]) } else { setSelectedFolders(filteredFolders.map((folder) => folder.id)) } } return (
{/* Notification */} {notification && (
{notification.type === "success" && } {notification.type === "error" && } {notification.type === "info" && } {notification.message}
)} {/* Header */}

Dossiers

Organisez vos documents par dossiers

{isConnected ? (
{/* Nouveau dossier avec menu */}
{menuOpen && (
)}
{/* Déconnexion */}
) : ( )}
{/* Breadcrumb */}
{currentPath.map((path, index) => (
{index > 0 && }
))}
{/* Search and Filters */}
{/* Advanced Filters */} {showFilters && (
)}
{/* Bulk Actions minimalistes: certificats et rôles uniquement */} {selectedFolders.length > 0 && (
{selectedFolders.length} dossier{selectedFolders.length > 1 ? "s" : ""} sélectionné {selectedFolders.length > 1 ? "s" : ""}
)} {/* Folders List/Grid */} {viewMode === "list" ? (
{filteredFolders.map((folder) => ( ))}
Nom Taille Modifié Propriétaire Accès Statut
toggleFolderSelection(folder.id)} />
handleOpenFolder(folder)} > {folder.name} {isNewFolder(folder) && ( NEW )} {getStorageIcon(folder.storageType)} {folder.access === "private" && ( )}

{folder.description}

{folder.size} {formatDate(folder.modified)} {folder.owner} {folder.access === "shared" ? "Partagé" : "Privé"} {getStatusBadge(folder.status)}
) : (
{filteredFolders.map((folder) => (
handleOpenFolder(folder)} >
e.stopPropagation()}> toggleFolderSelection(folder.id)} />
e.stopPropagation()} > {isNewFolder(folder) && ( NEW )} {folder.access === "private" && } {folder.storageType === "temporary" && ( )} {folder.status === "validated" && ( )} {folder.documents && folder.documents.some((doc) => doc.hasCertificate) && ( )}

{folder.name}

{folder.description}

{folder.size}

{formatDate(folder.modified)}

{getStorageIcon(folder.storageType)} {folder.storageType === "permanent" ? "Permanent" : "Temporaire"}
{folder.temporaryStorageConfig && folder.storageType === "temporary" && (
Durée: {folder.temporaryStorageConfig.duration} jours
)}
{getStatusBadge(folder.status)}
{folder.access === "shared" ? "Partagé" : "Privé"}
{/* Recent Activity */}

Activité récente

{folder.activity.slice(0, 2).map((activity, index) => (
{activity.user} a {activity.action}{" "} {activity.item}
{activity.time}
))}
))}
)} {filteredFolders.length === 0 && (

Aucun dossier trouvé

{searchTerm || filterAccess !== "all" || filterOwner !== "all" || filterStorage !== "all" ? "Essayez de modifier vos critères de recherche" : "Commencez par créer votre premier dossier"}

)}
{/* ProcessesViewer Card */}

Processus Blockchain

{/* Intégration du ProcessesViewer */}
{/* Modals */} {actionModal.type && (
{/* Documents Certificates Modal */} {actionModal.type === "documents_certificates" && actionModal.folder && ( <>

Certificats des documents - {actionModal.folder.name}

Certificats des documents

Téléchargez les certificats blockchain individuels des documents de ce dossier

{actionModal.folder.documents?.map((doc) => (
{doc.name}
{doc.hasCertificate && doc.certificateId && (

ID: {doc.certificateId}

)}
{doc.hasCertificate ? ( <> Certifié ) : ( Non certifié )}
))}
Actions groupées
)} {/* Storage Config Modal */} {actionModal.type === "storage_config" && actionModal.folder && ( <>

Configuration du stockage temporaire

Configuration du stockage temporaire

Configurez la durée de conservation et les informations d'usage pour le dossier{" "} {actionModal.folder.name} en stockage temporaire.

Durée pendant laquelle les données seront conservées en stockage temporaire avant archivage automatique