feat: handling SSR on evaluation
This commit is contained in:
155
components/evaluation/client-wrapper.tsx
Normal file
155
components/evaluation/client-wrapper.tsx
Normal file
@@ -0,0 +1,155 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect } from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useUser } from "@/hooks/use-user-context";
|
||||
import { UserEvaluation, Team } 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;
|
||||
teams: Team[];
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
export function EvaluationClientWrapper({
|
||||
userEvaluation,
|
||||
teams,
|
||||
children,
|
||||
}: EvaluationClientWrapperProps) {
|
||||
const { setUserInfo } = useUser();
|
||||
const router = useRouter();
|
||||
|
||||
// Wrapper functions that refresh the page after API calls
|
||||
const updateSkillLevel = async (
|
||||
category: string,
|
||||
skillId: string,
|
||||
level: any
|
||||
) => {
|
||||
await updateSkillLevelAction(category, skillId, level);
|
||||
router.refresh();
|
||||
};
|
||||
|
||||
const updateSkillMentorStatus = async (
|
||||
category: string,
|
||||
skillId: string,
|
||||
canMentor: boolean
|
||||
) => {
|
||||
await updateSkillMentorStatusAction(category, skillId, canMentor);
|
||||
router.refresh();
|
||||
};
|
||||
|
||||
const updateSkillLearningStatus = async (
|
||||
category: string,
|
||||
skillId: string,
|
||||
wantsToLearn: boolean
|
||||
) => {
|
||||
await updateSkillLearningStatusAction(category, skillId, wantsToLearn);
|
||||
router.refresh();
|
||||
};
|
||||
|
||||
const addSkillToEvaluation = async (category: string, skillId: string) => {
|
||||
await addSkillToEvaluationAction(category, skillId);
|
||||
router.refresh();
|
||||
};
|
||||
|
||||
const removeSkillFromEvaluation = async (
|
||||
category: string,
|
||||
skillId: string
|
||||
) => {
|
||||
await removeSkillFromEvaluationAction(category, skillId);
|
||||
router.refresh();
|
||||
};
|
||||
|
||||
// Update user info in navigation when user evaluation is loaded
|
||||
useEffect(() => {
|
||||
if (userEvaluation) {
|
||||
const teamName =
|
||||
teams.find((t) => t.id === userEvaluation.profile.teamId)?.name || "";
|
||||
setUserInfo({
|
||||
firstName: userEvaluation.profile.firstName,
|
||||
lastName: userEvaluation.profile.lastName,
|
||||
teamName,
|
||||
});
|
||||
} else {
|
||||
setUserInfo(null);
|
||||
}
|
||||
}, [userEvaluation, teams, setUserInfo]);
|
||||
|
||||
// Provide evaluation functions to children through React context or props
|
||||
return (
|
||||
<EvaluationProvider
|
||||
updateSkillLevel={updateSkillLevel}
|
||||
updateSkillMentorStatus={updateSkillMentorStatus}
|
||||
updateSkillLearningStatus={updateSkillLearningStatus}
|
||||
addSkillToEvaluation={addSkillToEvaluation}
|
||||
removeSkillFromEvaluation={removeSkillFromEvaluation}
|
||||
>
|
||||
{children}
|
||||
</EvaluationProvider>
|
||||
);
|
||||
}
|
||||
|
||||
// Simple context provider for evaluation functions
|
||||
import { createContext, useContext } from "react";
|
||||
|
||||
interface EvaluationContextType {
|
||||
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;
|
||||
removeSkillFromEvaluation: (categoryId: string, skillId: string) => void;
|
||||
}
|
||||
|
||||
const EvaluationContext = createContext<EvaluationContextType | undefined>(
|
||||
undefined
|
||||
);
|
||||
|
||||
function EvaluationProvider({
|
||||
children,
|
||||
updateSkillLevel,
|
||||
updateSkillMentorStatus,
|
||||
updateSkillLearningStatus,
|
||||
addSkillToEvaluation,
|
||||
removeSkillFromEvaluation,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
} & EvaluationContextType) {
|
||||
return (
|
||||
<EvaluationContext.Provider
|
||||
value={{
|
||||
updateSkillLevel,
|
||||
updateSkillMentorStatus,
|
||||
updateSkillLearningStatus,
|
||||
addSkillToEvaluation,
|
||||
removeSkillFromEvaluation,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</EvaluationContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
export function useEvaluationContext() {
|
||||
const context = useContext(EvaluationContext);
|
||||
if (context === undefined) {
|
||||
throw new Error(
|
||||
"useEvaluationContext must be used within an EvaluationProvider"
|
||||
);
|
||||
}
|
||||
return context;
|
||||
}
|
||||
@@ -1,5 +1,9 @@
|
||||
export {
|
||||
EvaluationClientWrapper,
|
||||
useEvaluationContext,
|
||||
} from "./client-wrapper";
|
||||
export { WelcomeEvaluationScreen } from "./welcome-screen";
|
||||
export { EvaluationHeader } from "./evaluation-header";
|
||||
export { SkillLevelLegend } from "./skill-level-legend";
|
||||
export { CategoryTabs } from "./category-tabs";
|
||||
export { SkillEvaluationGrid } from "./skill-evaluation-grid";
|
||||
export { SkillEvaluationCard } from "./skill-evaluation-card";
|
||||
export { SkillLevelLegend } from "./skill-level-legend";
|
||||
|
||||
73
components/evaluation/welcome-screen.tsx
Normal file
73
components/evaluation/welcome-screen.tsx
Normal file
@@ -0,0 +1,73 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { ProfileForm } from "@/components/profile-form";
|
||||
import { initializeEmptyEvaluation } from "@/lib/evaluation-actions";
|
||||
import { Team, UserProfile } from "@/lib/types";
|
||||
import { Code2 } from "lucide-react";
|
||||
|
||||
interface WelcomeEvaluationScreenProps {
|
||||
teams: Team[];
|
||||
}
|
||||
|
||||
export function WelcomeEvaluationScreen({
|
||||
teams,
|
||||
}: WelcomeEvaluationScreenProps) {
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
const router = useRouter();
|
||||
|
||||
const handleProfileSubmit = async (profile: UserProfile) => {
|
||||
setIsSubmitting(true);
|
||||
try {
|
||||
await initializeEmptyEvaluation(profile);
|
||||
// Rafraîchir la page pour que le SSR prenne en compte la nouvelle évaluation
|
||||
router.refresh();
|
||||
} catch (error) {
|
||||
console.error("Failed to initialize evaluation:", error);
|
||||
} finally {
|
||||
setIsSubmitting(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-gradient-to-br from-slate-950 via-slate-900 to-slate-950 relative overflow-hidden">
|
||||
<div className="absolute inset-0 bg-[radial-gradient(ellipse_at_top,_var(--tw-gradient-stops))] from-blue-900/20 via-slate-900 to-slate-950" />
|
||||
<div className="absolute inset-0 bg-grid-white/5 bg-[size:50px_50px]" />
|
||||
|
||||
<div className="relative z-10 container mx-auto py-16 px-6">
|
||||
<div className="text-center mb-12">
|
||||
<div className="inline-flex items-center gap-2 px-4 py-2 rounded-full bg-white/5 border border-white/10 backdrop-blur-sm mb-6">
|
||||
<Code2 className="h-4 w-4 text-blue-400" />
|
||||
<span className="text-sm font-medium text-slate-200">
|
||||
PeakSkills - Évaluation
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<h1 className="text-4xl font-bold mb-4 text-white">
|
||||
Commencer l'évaluation
|
||||
</h1>
|
||||
<p className="text-lg text-slate-400 mb-8">
|
||||
Renseignez vos informations pour débuter votre auto-évaluation
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="max-w-2xl mx-auto">
|
||||
<div className="relative">
|
||||
{isSubmitting && (
|
||||
<div className="absolute inset-0 bg-black/20 backdrop-blur-sm z-10 flex items-center justify-center rounded-lg">
|
||||
<div className="text-center">
|
||||
<div className="animate-spin rounded-full h-6 w-6 border-b-2 border-blue-400 mx-auto mb-2"></div>
|
||||
<p className="text-white text-sm">
|
||||
Initialisation de l'évaluation...
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<ProfileForm teams={teams} onSubmit={handleProfileSubmit} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import { useSearchParams, useRouter } from "next/navigation";
|
||||
import { TooltipProvider } from "@/components/ui/tooltip";
|
||||
import { SkillCategory, SkillLevel, CategoryEvaluation } from "@/lib/types";
|
||||
import { SkillSelector } from "./skill-selector";
|
||||
import { useEvaluationContext } from "./evaluation";
|
||||
import {
|
||||
EvaluationHeader,
|
||||
SkillLevelLegend,
|
||||
@@ -15,30 +16,19 @@ import {
|
||||
interface SkillEvaluationProps {
|
||||
categories: SkillCategory[];
|
||||
evaluations: CategoryEvaluation[];
|
||||
onUpdateSkill: (category: string, skillId: string, level: SkillLevel) => void;
|
||||
onUpdateMentorStatus: (
|
||||
category: string,
|
||||
skillId: string,
|
||||
canMentor: boolean
|
||||
) => void;
|
||||
onUpdateLearningStatus: (
|
||||
category: string,
|
||||
skillId: string,
|
||||
wantsToLearn: boolean
|
||||
) => void;
|
||||
onAddSkill: (category: string, skillId: string) => void;
|
||||
onRemoveSkill: (category: string, skillId: string) => void;
|
||||
}
|
||||
|
||||
export function SkillEvaluation({
|
||||
categories,
|
||||
evaluations,
|
||||
onUpdateSkill,
|
||||
onUpdateMentorStatus,
|
||||
onUpdateLearningStatus,
|
||||
onAddSkill,
|
||||
onRemoveSkill,
|
||||
}: SkillEvaluationProps) {
|
||||
const {
|
||||
updateSkillLevel,
|
||||
updateSkillMentorStatus,
|
||||
updateSkillLearningStatus,
|
||||
addSkillToEvaluation,
|
||||
removeSkillFromEvaluation,
|
||||
} = useEvaluationContext();
|
||||
const searchParams = useSearchParams();
|
||||
const router = useRouter();
|
||||
const categoryParam = searchParams.get("category");
|
||||
@@ -97,18 +87,18 @@ export function SkillEvaluation({
|
||||
categories={categories}
|
||||
evaluations={evaluations}
|
||||
selectedCategory={selectedCategory}
|
||||
onAddSkill={onAddSkill}
|
||||
onRemoveSkill={onRemoveSkill}
|
||||
onAddSkill={addSkillToEvaluation}
|
||||
onRemoveSkill={removeSkillFromEvaluation}
|
||||
/>
|
||||
|
||||
{currentEvaluation && (
|
||||
<SkillEvaluationGrid
|
||||
currentCategory={currentCategory}
|
||||
currentEvaluation={currentEvaluation}
|
||||
onUpdateSkill={onUpdateSkill}
|
||||
onUpdateMentorStatus={onUpdateMentorStatus}
|
||||
onUpdateLearningStatus={onUpdateLearningStatus}
|
||||
onRemoveSkill={onRemoveSkill}
|
||||
onUpdateSkill={updateSkillLevel}
|
||||
onUpdateMentorStatus={updateSkillMentorStatus}
|
||||
onUpdateLearningStatus={updateSkillLearningStatus}
|
||||
onRemoveSkill={removeSkillFromEvaluation}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user