docv/lib/contexts/FourNKContext.tsx

259 lines
9.4 KiB
TypeScript

"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 { 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<string, Record<string, any>>;
folders: EnrichedFolderData[];
loadingFolders: boolean;
members: string[];
setFolderProcesses: React.Dispatch<React.SetStateAction<any>>;
setMyFolderProcesses: React.Dispatch<React.SetStateAction<string[]>>;
setFolderPrivateData: React.Dispatch<React.SetStateAction<Record<string, Record<string, any>>>>;
setMembers: React.Dispatch<React.SetStateAction<string[]>>;
};
const FourNKContext = createContext<FourNKContextType | undefined>(undefined);
export function FourNKProvider({ children }: { children: ReactNode }) {
const [isConnected, setIsConnected] = useState(false);
const [userPairingId, setUserPairingId] = useState<string | null>(null);
const [processes, setProcesses] = useState<any>(null);
const [members, setMembers] = useState<string[]>([]);;
const [myProcesses, setMyProcesses] = useState<string[]>([]);
const [folderProcesses, setFolderProcesses] = useState<any>(null);
const [myFolderProcesses, setMyFolderProcesses] = useState<string[]>([]);
const [folderPrivateData, setFolderPrivateData] = useState<Record<string, Record<string, any>>>({});
const [loadingFolders, setLoadingFolders] = useState(true);
const [folders, setFolders] = useState<EnrichedFolderData[]>([]);
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;
}
// console.log(validStates);
// validStates.forEach(state => {
hasFoldersToLoad = true;
const stateToProcess = referenceState;
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);
/*
// 4. CONDITION B: On vérifie si cet état contient des messages.
const hasMessages = (privateData.messages && privateData.messages.length > 0);
const hasMessagesOwner = (privateData.messages_owner && privateData.messages_owner.length > 0);
// Si cet état n'a pas de messages, on l'ignore (return)
if (!hasMessages && !hasMessagesOwner) {
return; // Passe à l'état suivant
}
*/
folderData.push({
processId: processId,
folderNumber: mainFolderNumber, // La clé unique
name: privateData.name || `Dossier ${mainFolderNumber}`,
description: privateData.description || '',
created_at: privateData.created_at || new Date().toISOString(),
updated_at: privateData.updated_at || new Date().toISOString(),
notes: privateData.notes || [],
messages: privateData.messages || [],
messages_owner: privateData.messages_owner || [],
});
// });
});
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]); // J'ai ajouté setFolders et setLoadingFolders aux dépendances
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 (
<FourNKContext.Provider value={value}>
{children}
</FourNKContext.Provider>
);
}
export function use4NK() {
const context = useContext(FourNKContext);
if (context === undefined) {
throw new Error('use4NK must be used within a FourNKProvider');
}
return context;
}