diff --git a/app/dashboard/folders/page.tsx b/app/dashboard/folders/page.tsx index 3ad31e6..6db3606 100644 --- a/app/dashboard/folders/page.tsx +++ b/app/dashboard/folders/page.tsx @@ -131,61 +131,166 @@ export default function FoldersPage() { // 4NK Integration useEffects useEffect(() => { - // Load folders from 4NK when folder processes are available + const userStore = UserStore.getInstance(); + const connected = userStore.isConnected(); + const pairingId = userStore.getUserPairingId(); + + console.log('Initial 4NK state:', { connected, pairingId }); + setIsConnected(connected); + setUserPairingId(pairingId); + }, []); + + useEffect(() => { + const handleConnectionFlow = async () => { + if (!isConnected) return; + + try { + const messageBus = MessageBus.getInstance(iframeUrl); + await messageBus.isReady(); + + const userStore = UserStore.getInstance(); + let pairingId = userStore.getUserPairingId(); + + // 1️⃣ Créer ou récupérer le pairing + if (!pairingId) { + pairingId = await messageBus.createUserPairing(); + console.log("✅ Pairing created:", pairingId); + + if (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); + setFolderProcesses(processes); + + // 3️⃣ Charger les myProcesses + const myProcesses = await messageBus.getMyProcesses(); + setMyProcesses(myProcesses); + setMyFolderProcesses(myProcesses); + + } catch (err) { + console.error("❌ Error during pairing or process loading:", err); + } + }; + + handleConnectionFlow(); + }, [isConnected, iframeUrl]); + + // Load folders from 4NK when folder processes are available + useEffect(() => { if (folderProcesses && myFolderProcesses.length >= 0) { loadFoldersFrom4NK(); - } else { - // Fallback: load empty folders if not connected to 4NK - 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, - }) } - }, [folderProcesses, myFolderProcesses, loadFoldersFrom4NK]) + }, [folderProcesses, myFolderProcesses, loadFoldersFrom4NK]); // Update folders when private data changes useEffect(() => { if (folderProcesses && Object.keys(folderPrivateData).length > 0) { loadFoldersFrom4NK(); } - }, [folderPrivateData, folderProcesses, loadFoldersFrom4NK]) + }, [folderPrivateData, loadFoldersFrom4NK, folderProcesses]); - // 4NK Authentication handlers - const handleLogin = useCallback(() => { - setShowAuthModal(true); - - }, []); - - const handleLogout = useCallback(() => { - UserStore.getInstance().disconnect(); - setIsConnected(false); - setProcesses(null); - setMyProcesses([]); - setUserPairingId(null); + // Filter and sort folders + const filteredFolders = folders.filter(folder => { + const matchesSearch = folder.name.toLowerCase().includes(searchTerm.toLowerCase()) || + folder.description.toLowerCase().includes(searchTerm.toLowerCase()) || + folder.folderNumber.toLowerCase().includes(searchTerm.toLowerCase()) - // Clear folder-related states - setFolderProcesses(null); - setMyFolderProcesses([]); - setFolderPrivateData({}); - setFolders([]); - setLoadingFolders(false); + return matchesSearch + }) - // Émettre un événement pour vider les messages locaux - EventBus.getInstance().emit('CLEAR_CONSOLE'); + const sortedFolders = [...filteredFolders].sort((a, b) => { + let aValue: any, bValue: any + + switch (sortBy) { + case "name": + aValue = a.name.toLowerCase() + bValue = b.name.toLowerCase() + break + case "created_at": + aValue = new Date(a.created_at) + bValue = new Date(b.created_at) + break + case "updated_at": + aValue = new Date(a.updated_at) + bValue = new Date(b.updated_at) + break + default: + aValue = a.name.toLowerCase() + bValue = b.name.toLowerCase() + } + + if (sortOrder === "asc") { + return aValue < bValue ? -1 : aValue > bValue ? 1 : 0 + } else { + return aValue > bValue ? -1 : aValue < bValue ? 1 : 0 + } + }) - showNotification("info", "Déconnexion réussie"); - }, []); + // Modal handlers + const handleOpenModal = (type: FolderType) => { + setFolderType(type); + setIsModalOpen(true); + }; + + const handleCloseModal = () => { + setIsModalOpen(false); + setFolderType(null); + }; + + const handleSaveNewFolder = useCallback( + (folderData: FolderData) => { + 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; + } + + const roles = setDefaultFolderRoles(userPairingId); + const folderPrivateFields = FolderPrivateFields; + + MessageBus.getInstance(iframeUrl) + .createFolder(folderData, folderPrivateFields, roles) + .then((_folderCreated: FolderCreated) => { + const firstStateId = _folderCreated.process.states[0].state_id; + MessageBus.getInstance(iframeUrl) + .notifyProcessUpdate(_folderCreated.processId, firstStateId) + .then(async () => { + // Recharger les processes et myProcesses + const messageBus = MessageBus.getInstance(iframeUrl); + const [processes, myProcesses] = await Promise.all([ + messageBus.getProcesses(), + messageBus.getMyProcesses() + ]); + + setProcesses(processes); + setFolderProcesses(processes); + setMyProcesses(myProcesses); + setMyFolderProcesses(myProcesses); + + showNotification("success", "Dossier créé avec succès !"); + handleCloseModal(); + }); + }) + .catch((error: any) => { + console.error('Erreur lors de la création du dossier:', error); + showNotification("error", "Erreur lors de la création du dossier"); + }); + }, + [isConnected, userPairingId, loadFoldersFrom4NK] + ); + + // Auth connection handler const handleAuthConnect = useCallback(() => { setIsConnected(true); setShowAuthModal(false); @@ -198,694 +303,6 @@ export default function FoldersPage() { }, []); - // 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) - setFolderProcesses(processes) // Update folder processes as well - }) - ) - ); - - 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 */}