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" ? (
-