docv/lib/contexts/FourNKContext.tsx

208 lines
7.3 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";
// --- Définition des types pour plus de clarté ---
export interface FolderMember {
id: string
name: string
avatar: string
isOnline: boolean
}
// Interface enrichie qui inclut maintenant les membres ET les fichiers
export interface EnrichedFolderData extends FolderData {
members: FolderMember[];
files: any[]; // <-- AJOUT DES FICHIERS
// notes: any[]; // 'notes' est déjà dans FolderData
}
// ---
type FourNKContextType = {
isConnected: boolean;
userPairingId: string | null;
processes: any;
myProcesses: string[];
folderProcesses: any;
myFolderProcesses: string[];
folderPrivateData: Record<string, Record<string, any>>;
folders: EnrichedFolderData[]; // <-- Utilise le type enrichi
loadingFolders: boolean;
setFolderProcesses: React.Dispatch<React.SetStateAction<any>>;
setMyFolderProcesses: React.Dispatch<React.SetStateAction<string[]>>;
setFolderPrivateData: React.Dispatch<React.SetStateAction<Record<string, Record<string, any>>>>;
};
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 [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 }> = [];
Object.entries(folderProcesses).forEach(([processId, process]: [string, any]) => {
if (!myFolderProcesses.includes(processId)) return;
const latestState = process.states[0];
if (!latestState) return;
const folderNumber = latestState.pcd_commitment?.folderNumber;
if (!folderNumber) return;
hasFoldersToLoad = true;
const privateData = folderPrivateData[latestState.state_id];
if (!privateData) {
hasAllPrivateData = false;
missingPrivateData.push({ processId, stateId: latestState.state_id });
return;
}
const ownerMembers = latestState.roles?.owner?.members || [];
const members: FolderMember[] = ownerMembers.map((memberId: string) => {
const avatar = memberId.slice(0, 2).toUpperCase();
return {
id: memberId,
name: `Membre ${memberId.slice(0, 4)}`,
avatar: avatar,
isOnline: Math.random() > 0.5
}
});
folderData.push({
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 || [],
files: privateData.files || [], // <-- AJOUT DE L'EXTRACTION DES FICHIERS
members: members
});
});
if (hasFoldersToLoad && !hasAllPrivateData) {
setLoadingFolders(true);
missingPrivateData.forEach(({ processId, stateId }) => {
if (!folderPrivateData[stateId]) {
fetchFolderPrivateData(processId, stateId);
}
});
} else {
setFolders(folderData);
setLoadingFolders(false);
}
}, [folderProcesses, myFolderProcesses, folderPrivateData, fetchFolderPrivateData]);
// 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]);
const value = {
isConnected,
userPairingId,
processes,
myProcesses,
folderProcesses,
myFolderProcesses,
folderPrivateData,
folders,
loadingFolders,
setFolderProcesses,
setMyFolderProcesses,
setFolderPrivateData,
};
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;
}