"use client"; import { useEffect, useState } from "react"; import { useUser } from "@/hooks/use-user-context"; import { UserEvaluation, Team, SkillLevel } from "@/lib/types"; import { updateSkillLevel as updateSkillLevelAction, updateSkillMentorStatus as updateSkillMentorStatusAction, updateSkillLearningStatus as updateSkillLearningStatusAction, addSkillToEvaluation as addSkillToEvaluationAction, removeSkillFromEvaluation as removeSkillFromEvaluationAction, } from "@/lib/evaluation-actions"; interface EvaluationClientWrapperProps { userEvaluation: UserEvaluation | null; teams: Team[]; children: React.ReactNode; } export function EvaluationClientWrapper({ userEvaluation, teams, children, }: EvaluationClientWrapperProps) { const { setUserInfo } = useUser(); // État local pour l'UI optimiste - commence avec les données SSR const [currentEvaluation, setCurrentEvaluation] = useState(userEvaluation); // Met à jour l'état local quand les props changent (SSR) useEffect(() => { setCurrentEvaluation(userEvaluation); }, [userEvaluation]); // Fonctions avec UI optimiste const updateSkillLevel = async ( category: string, skillId: string, level: SkillLevel ) => { if (!currentEvaluation) return; // Sauvegarder l'état actuel pour le rollback const previousEvaluation = currentEvaluation; try { // Optimistic UI update - mettre à jour immédiatement l'interface const updatedEvaluations = currentEvaluation.evaluations.map( (catEval) => { if (catEval.category === category) { const existingSkill = catEval.skills.find( (s) => s.skillId === skillId ); const updatedSkills = existingSkill ? catEval.skills.map((skill) => skill.skillId === skillId ? { ...skill, level } : skill ) : [ ...catEval.skills, { skillId, level, canMentor: false, wantsToLearn: false }, ]; return { ...catEval, skills: updatedSkills, }; } return catEval; } ); const newEvaluation: UserEvaluation = { ...currentEvaluation, evaluations: updatedEvaluations, lastUpdated: new Date().toISOString(), }; setCurrentEvaluation(newEvaluation); // Appel API en arrière-plan await updateSkillLevelAction(category, skillId, level); } catch (error) { console.error("Failed to update skill level:", error); // Rollback optimiste en cas d'erreur setCurrentEvaluation(previousEvaluation); } }; const updateSkillMentorStatus = async ( category: string, skillId: string, canMentor: boolean ) => { if (!currentEvaluation) return; const previousEvaluation = currentEvaluation; try { const updatedEvaluations = currentEvaluation.evaluations.map( (catEval) => { if (catEval.category === category) { const updatedSkills = catEval.skills.map((skill) => skill.skillId === skillId ? { ...skill, canMentor } : skill ); return { ...catEval, skills: updatedSkills, }; } return catEval; } ); const newEvaluation: UserEvaluation = { ...currentEvaluation, evaluations: updatedEvaluations, lastUpdated: new Date().toISOString(), }; setCurrentEvaluation(newEvaluation); await updateSkillMentorStatusAction(category, skillId, canMentor); } catch (error) { console.error("Failed to update skill mentor status:", error); setCurrentEvaluation(previousEvaluation); } }; const updateSkillLearningStatus = async ( category: string, skillId: string, wantsToLearn: boolean ) => { if (!currentEvaluation) return; const previousEvaluation = currentEvaluation; try { const updatedEvaluations = currentEvaluation.evaluations.map( (catEval) => { if (catEval.category === category) { const updatedSkills = catEval.skills.map((skill) => skill.skillId === skillId ? { ...skill, wantsToLearn } : skill ); return { ...catEval, skills: updatedSkills, }; } return catEval; } ); const newEvaluation: UserEvaluation = { ...currentEvaluation, evaluations: updatedEvaluations, lastUpdated: new Date().toISOString(), }; setCurrentEvaluation(newEvaluation); await updateSkillLearningStatusAction(category, skillId, wantsToLearn); } catch (error) { console.error("Failed to update skill learning status:", error); setCurrentEvaluation(previousEvaluation); } }; const addSkillToEvaluation = async (category: string, skillId: string) => { if (!currentEvaluation) return; const previousEvaluation = currentEvaluation; try { const updatedEvaluations = currentEvaluation.evaluations.map( (catEval) => { if (catEval.category === category) { if (!catEval.selectedSkillIds.includes(skillId)) { return { ...catEval, selectedSkillIds: [...catEval.selectedSkillIds, skillId], skills: [ ...catEval.skills, { skillId, level: null, canMentor: false, wantsToLearn: false, }, ], }; } } return catEval; } ); const newEvaluation: UserEvaluation = { ...currentEvaluation, evaluations: updatedEvaluations, lastUpdated: new Date().toISOString(), }; setCurrentEvaluation(newEvaluation); await addSkillToEvaluationAction(category, skillId); } catch (error) { console.error("Failed to add skill to evaluation:", error); setCurrentEvaluation(previousEvaluation); } }; const addMultipleSkillsToEvaluation = async ( category: string, skillIds: string[] ) => { if (!currentEvaluation || skillIds.length === 0) return; const previousEvaluation = currentEvaluation; try { const updatedEvaluations = currentEvaluation.evaluations.map( (catEval) => { if (catEval.category === category) { // Filtrer seulement les compétences qui ne sont pas déjà sélectionnées const newSkillIds = skillIds.filter( (skillId) => !catEval.selectedSkillIds.includes(skillId) ); if (newSkillIds.length > 0) { return { ...catEval, selectedSkillIds: [...catEval.selectedSkillIds, ...newSkillIds], skills: [ ...catEval.skills, ...newSkillIds.map((skillId) => ({ skillId, level: null, canMentor: false, wantsToLearn: false, })), ], }; } } return catEval; } ); const newEvaluation: UserEvaluation = { ...currentEvaluation, evaluations: updatedEvaluations, lastUpdated: new Date().toISOString(), }; setCurrentEvaluation(newEvaluation); // Ajouter toutes les compétences en parallèle côté API await Promise.all( skillIds.map((skillId) => addSkillToEvaluationAction(category, skillId)) ); } catch (error) { console.error("Failed to add multiple skills to evaluation:", error); setCurrentEvaluation(previousEvaluation); } }; const removeSkillFromEvaluation = async ( category: string, skillId: string ) => { if (!currentEvaluation) return; const previousEvaluation = currentEvaluation; try { const updatedEvaluations = currentEvaluation.evaluations.map( (catEval) => { if (catEval.category === category) { return { ...catEval, selectedSkillIds: catEval.selectedSkillIds.filter( (id) => id !== skillId ), skills: catEval.skills.filter( (skill) => skill.skillId !== skillId ), }; } return catEval; } ); const newEvaluation: UserEvaluation = { ...currentEvaluation, evaluations: updatedEvaluations, lastUpdated: new Date().toISOString(), }; setCurrentEvaluation(newEvaluation); await removeSkillFromEvaluationAction(category, skillId); } catch (error) { console.error("Failed to remove skill from evaluation:", error); setCurrentEvaluation(previousEvaluation); } }; // Update user info in navigation when user evaluation is loaded useEffect(() => { if (currentEvaluation) { const teamName = teams.find((t) => t.id === currentEvaluation.profile.teamId)?.name || ""; setUserInfo({ firstName: currentEvaluation.profile.firstName, lastName: currentEvaluation.profile.lastName, teamName, }); } else { setUserInfo(null); } }, [currentEvaluation, teams, setUserInfo]); // Provide evaluation functions to children through React context or props return ( {children} ); } // Simple context provider for evaluation functions import { createContext, useContext } from "react"; interface EvaluationContextType { currentEvaluation: UserEvaluation | null; updateSkillLevel: (categoryId: string, skillId: string, level: any) => void; updateSkillMentorStatus: ( categoryId: string, skillId: string, canMentor: boolean ) => void; updateSkillLearningStatus: ( categoryId: string, skillId: string, wantsToLearn: boolean ) => void; addSkillToEvaluation: (categoryId: string, skillId: string) => void; addMultipleSkillsToEvaluation: ( categoryId: string, skillIds: string[] ) => void; removeSkillFromEvaluation: (categoryId: string, skillId: string) => void; } const EvaluationContext = createContext( undefined ); function EvaluationProvider({ children, currentEvaluation, updateSkillLevel, updateSkillMentorStatus, updateSkillLearningStatus, addSkillToEvaluation, addMultipleSkillsToEvaluation, removeSkillFromEvaluation, }: { children: React.ReactNode; } & EvaluationContextType) { return ( {children} ); } export function useEvaluationContext() { const context = useContext(EvaluationContext); if (context === undefined) { throw new Error( "useEvaluationContext must be used within an EvaluationProvider" ); } return context; }