"use client" import { createContext, useContext, useState, useEffect, useCallback, ReactNode } from 'react'; import MessageBus from "@/lib/4nk/MessageBus"; import { iframeUrl } from "@/app/page"; import UserStore from "@/lib/4nk/UserStore"; import { FolderChatData, FolderData } from "@/lib/4nk/models/FolderData"; // Interface enrichie qui inclut maintenant les membres ET les fichiers export interface EnrichedFolderData extends FolderData { processId: string, } // --- type FourNKContextType = { isConnected: boolean; userPairingId: string | null; processes: any; myProcesses: string[]; folderProcesses: any; myFolderProcesses: string[]; folderPrivateData: Record>; folders: EnrichedFolderData[]; loadingFolders: boolean; members: string[]; setFolderProcesses: React.Dispatch>; setMyFolderProcesses: React.Dispatch>; setFolderPrivateData: React.Dispatch>>>; setMembers: React.Dispatch>; }; const FourNKContext = createContext(undefined); export function FourNKProvider({ children }: { children: ReactNode }) { const [isConnected, setIsConnected] = useState(false); const [userPairingId, setUserPairingId] = useState(null); const [processes, setProcesses] = useState(null); const [members, setMembers] = useState([]);; const [myProcesses, setMyProcesses] = useState([]); const [folderProcesses, setFolderProcesses] = useState(null); const [myFolderProcesses, setMyFolderProcesses] = useState([]); const [folderPrivateData, setFolderPrivateData] = useState>>({}); const [loadingFolders, setLoadingFolders] = useState(true); const [folders, setFolders] = useState([]); const fetchFolderPrivateData = useCallback(async (processId: string, stateId: string) => { try { const messageBus = MessageBus.getInstance(iframeUrl); await messageBus.isReady(); const data = await messageBus.getData(processId, stateId); setFolderPrivateData(prev => ({ ...prev, [stateId]: data })); return data; } catch (err) { console.error('Error fetching folder private data:', err); return null; } }, []); const loadFoldersFrom4NK = useCallback(() => { if (!folderProcesses || !myFolderProcesses) { return; } const folderData: EnrichedFolderData[] = []; let hasAllPrivateData = true; let hasFoldersToLoad = false; const missingPrivateData: Array<{ processId: string, stateId: string }> = []; const EXCLUDED_STATE_ID = "0000000000000000000000000000000000000000000000000000000000000000"; Object.entries(folderProcesses).forEach(([processId, process]: [string, any]) => { if (!myFolderProcesses.includes(processId)) return; const validStates = process.states.filter( (state: any) => state && state.state_id !== EXCLUDED_STATE_ID ); if (validStates.length === 0) return; const referenceState = validStates.find( (state: any) => state.pcd_commitment?.folderNumber ); const mainFolderNumber = referenceState?.pcd_commitment.folderNumber; if (!mainFolderNumber) { return; } let basePrivateData; let mergedMessages: FolderChatData[] = []; let mergedMessagesOwner: FolderChatData[] = []; validStates.forEach((state: any) => { hasFoldersToLoad = true; const stateToProcess = state; const privateData = folderPrivateData[stateToProcess.state_id]; // Si on n'a pas les données pour cet état de référence... if (!privateData) { hasAllPrivateData = false; missingPrivateData.push({ processId, stateId: stateToProcess.state_id }); return; // On quitte ce process, on réessaiera au prochain rendu } // console.log("Données déchiffrées pour le state:", stateToProcess.state_id, privateData); if (privateData.messages_owner instanceof Map) { const messageOwnerObj = Object.fromEntries(privateData.messages_owner); mergedMessagesOwner.push(messageOwnerObj); } if (privateData.messages instanceof Map) { const messageObj = Object.fromEntries(privateData.messages); mergedMessages.push(messageObj); } if (privateData.folderNumber) { basePrivateData = privateData; } }); if (!basePrivateData) return; folderData.push({ processId: processId, folderNumber: mainFolderNumber, name: basePrivateData.name || `Dossier ${mainFolderNumber}`, description: basePrivateData.description || '', created_at: basePrivateData.created_at || new Date().toISOString(), updated_at: basePrivateData.updated_at || new Date().toISOString(), notes: basePrivateData.notes || [], messages: mergedMessages || [], messages_owner: mergedMessagesOwner || [], attachedFiles: basePrivateData.attachedFiles || [], }); }); if (hasFoldersToLoad && !hasAllPrivateData) { setLoadingFolders(true); const firstMissing = missingPrivateData[0]; if (firstMissing) { if (!folderPrivateData[firstMissing.stateId]) { fetchFolderPrivateData(firstMissing.processId, firstMissing.stateId); } } } else { setFolders(folderData); setLoadingFolders(false); } }, [folderProcesses, myFolderProcesses, folderPrivateData, fetchFolderPrivateData, setFolders, setLoadingFolders]); const loadMembersFrom4NK = useCallback(() => { if (!processes || !userPairingId) return; const memberList: string[] = []; const EXCLUDED_STATE_ID = "0000000000000000000000000000000000000000000000000000000000000000"; Object.entries(processes).forEach(([processId, process]: [string, any]) => { const validStates = process.states.filter( (state: any) => state && state.state_id !== EXCLUDED_STATE_ID ); if (validStates.length === 0) return; const referenceState = validStates.find( (state: any) => state.pcd_commitment?.pairedAddresses ); if (!referenceState) return; const userAddress = referenceState.commited_in memberList.push(userAddress); }); // Filtrer la liste pour enlever l'ID de l'utilisateur connecté const filteredMemberList = memberList.filter( member => member !== userPairingId ); // Sauvegarder la liste filtrée dans l'état setMembers(filteredMemberList); }, [processes, userPairingId]); // Chargement initial des données 4NK useEffect(() => { const userStore = UserStore.getInstance(); const connected = userStore.isConnected(); const pairingId = userStore.getUserPairingId(); setIsConnected(connected); setUserPairingId(pairingId); const handleConnectionFlow = async () => { if (!connected) { setLoadingFolders(false); return; } setLoadingFolders(true); try { const messageBus = MessageBus.getInstance(iframeUrl); await messageBus.isReady(); let pid = pairingId; if (!pid) { pid = await messageBus.createUserPairing(); if (pid) { userStore.pair(pid); setUserPairingId(pid); } } const procs = await messageBus.getProcesses(); const myProcs = await messageBus.getMyProcesses(); setProcesses(procs); setFolderProcesses(procs); setMyProcesses(myProcs); setMyFolderProcesses(myProcs); } catch (err) { console.error("❌ Error during global connection flow:", err); setLoadingFolders(false); } }; handleConnectionFlow(); }, [isConnected]); // Re-calculer les dossiers lorsque les données changent useEffect(() => { loadFoldersFrom4NK(); }, [loadFoldersFrom4NK]); // Re-calculer les membres lorsque les données changent useEffect(() => { loadMembersFrom4NK(); }, [loadMembersFrom4NK]); const value = { isConnected, userPairingId, processes, myProcesses, folderProcesses, myFolderProcesses, folderPrivateData, folders, loadingFolders, members, setFolderProcesses, setMyFolderProcesses, setFolderPrivateData, setMembers, }; return ( {children} ); } export function use4NK() { const context = useContext(FourNKContext); if (context === undefined) { throw new Error('use4NK must be used within a FourNKProvider'); } return context; }