"use client" import { useState, useEffect, useCallback } from "react" 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 { Folder, Search, FolderPlus, Clock, ChevronRight, SortAsc, SortDesc, X, MessageSquare, List, } from "lucide-react" import { FolderData, 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 FolderModal from "@/components/4nk/FolderModal" import AuthModal from "@/components/4nk/AuthModal" import Iframe from "@/components/4nk/Iframe" import FolderChat from "@/components/4nk/FolderChat" type FolderType = 'contrat' | 'projet' | 'rapport' | 'finance' | 'rh' | 'marketing' | 'autre'; export default function FoldersPage() { const [searchTerm, setSearchTerm] = useState("") const [sortBy, setSortBy] = useState("updated_at") const [sortOrder, setSortOrder] = useState<"asc" | "desc">("desc") const [currentPath, setCurrentPath] = useState(["Racine"]) const [folderType, setFolderType] = useState(null); const [isModalOpen, setIsModalOpen] = useState(false); const [activeTab, setActiveTab] = useState<"folders" | "chat">("folders"); // 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) const [folderProcesses, setFolderProcesses] = useState(null) const [myFolderProcesses, setMyFolderProcesses] = useState([]) const [folderPrivateData, setFolderPrivateData] = useState>>({}) const [loadingFolders, setLoadingFolders] = useState(false) // Modal states const [notification, setNotification] = useState<{ type: "success" | "error" | "info"; message: string } | null>(null) const [folders, setFolders] = useState([]) const [stats, setStats] = useState({ total: 0 }) // Notification system const showNotification = (type: "success" | "error" | "info", message: string) => { setNotification({ type, message }) setTimeout(() => setNotification(null), 5000) } // Function to fetch folder private data const fetchFolderPrivateData = useCallback(async (processId: string, stateId: string) => { if (!myFolderProcesses.includes(processId)) return; try { const messageBus = MessageBus.getInstance(iframeUrl); await messageBus.isReady(); const data = await messageBus.getData(processId, stateId); setFolderPrivateData(prev => ({ ...prev, [stateId]: data })); } catch (err) { console.error('Error fetching folder private data:', err); } }, [myFolderProcesses]); // Function to load folders from 4NK processes (adapted to new FolderData model) const loadFoldersFrom4NK = useCallback(() => { if (!folderProcesses) return; const folderData: FolderData[] = []; let hasAllPrivateData = true; let hasFoldersToLoad = false; const missingPrivateData: Array<{processId: string, stateId: string}> = []; Object.entries(folderProcesses).forEach(([processId, process]: [string, any]) => { // Only include processes that belong to the user (myFolderProcesses) if (!myFolderProcesses.includes(processId)) return; // Check if this process has a folderNumber in pcd_commitment const latestState = process.states[0]; if (!latestState) return; const folderNumber = latestState.pcd_commitment?.folderNumber; if (!folderNumber) return; // Skip processes without folderNumber hasFoldersToLoad = true; // We have at least one folder to load // Get private data for this state if available const privateData = folderPrivateData[latestState.state_id]; // If we don't have private data yet, mark as incomplete and collect missing data if (!privateData) { hasAllPrivateData = false; missingPrivateData.push({processId, stateId: latestState.state_id}); return; // Skip creating folder until we have private data } // Create folder with new simplified model const folder: FolderData = { folderNumber: folderNumber, name: privateData.name || `Dossier ${folderNumber}`, description: privateData.description || '', created_at: privateData.created_at || new Date().toISOString(), updated_at: privateData.updated_at || new Date().toISOString(), notes: privateData.notes || [] }; folderData.push(folder); }); // Manage loading state if (hasFoldersToLoad && !hasAllPrivateData) { setLoadingFolders(true); // Fetch missing private data (but only once per missing item) missingPrivateData.forEach(({processId, stateId}) => { if (!folderPrivateData[stateId]) { fetchFolderPrivateData(processId, stateId); } }); } else if (hasAllPrivateData) { setLoadingFolders(false); setFolders(folderData); // Update stats setStats({ total: folderData.length }); } }, [folderProcesses, myFolderProcesses, folderPrivateData, fetchFolderPrivateData]); // 4NK Integration useEffects useEffect(() => { 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(); } }, [folderProcesses, myFolderProcesses, loadFoldersFrom4NK]); // 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()) return matchesSearch }) 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 } }) // 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] ); // Auth connection handler 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); }, []); return (
{/* Sidebar */}

Dossiers

Gérez vos dossiers 4NK

Total {stats.total}
{/* 4NK Connection Status */}
4NK Status {isConnected ? "Connecté" : "Déconnecté"}
{!isConnected && ( )}
{/* Main Content */}
{/* Header */}
{currentPath.map((path, index) => (
{index > 0 && } {path}
))}
{activeTab === "folders" && ( )}
{/* Tabs */}
{/* Search and filters - only show for folders tab */} {activeTab === "folders" && (
setSearchTerm(e.target.value)} className="pl-10" />
)}
{/* Content */}
{activeTab === "folders" ? (
{loadingFolders ? (

Chargement des dossiers...

) : sortedFolders.length === 0 ? (

Aucun dossier

{searchTerm ? "Aucun dossier ne correspond à votre recherche." : "Commencez par créer votre premier dossier."}

{!searchTerm && ( )}
) : (
{/* Folder list */}
{sortedFolders.map((folder) => (

{folder.name}

{folder.description}

#{folder.folderNumber} {new Date(folder.updated_at).toLocaleDateString()}
{folder.notes.length > 0 && ( {folder.notes.length} notes )}
))}
)}
) : ( )}
{/* Modals */} {isModalOpen && ( )} {showAuthModal && ( )} {/* Notification */} {notification && (
{notification.message}
)} {/* 4NK Iframe - only show when connected */} {isConnected &&