Add score color logic and evaluation migration
- Introduced `getScoreColors` function to dynamically set badge colors based on skill scores for better visual feedback. - Updated HomePage to display skill evaluation percentages with corresponding colors. - Implemented `migrateEvaluation` function to ensure existing evaluations are updated with new skill categories, enhancing data integrity. - Refactored data loading in `loadSkillCategories` and `loadTeams` to fetch from API endpoints, improving flexibility and maintainability.
This commit is contained in:
41
app/api/skills/route.ts
Normal file
41
app/api/skills/route.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import { SkillCategory } from "@/lib/types";
|
||||
|
||||
export async function GET() {
|
||||
try {
|
||||
const dataDir = path.join(process.cwd(), "data", "skills");
|
||||
|
||||
const categories = [
|
||||
"frontend",
|
||||
"backend",
|
||||
"devops",
|
||||
"mobile",
|
||||
"data",
|
||||
"cloud",
|
||||
"security",
|
||||
"design",
|
||||
];
|
||||
|
||||
const skillCategories: SkillCategory[] = [];
|
||||
|
||||
for (const category of categories) {
|
||||
const filePath = path.join(dataDir, `${category}.json`);
|
||||
|
||||
if (fs.existsSync(filePath)) {
|
||||
const fileContent = fs.readFileSync(filePath, "utf-8");
|
||||
const data = JSON.parse(fileContent);
|
||||
skillCategories.push(data);
|
||||
}
|
||||
}
|
||||
|
||||
return NextResponse.json(skillCategories);
|
||||
} catch (error) {
|
||||
console.error("Error loading skills:", error);
|
||||
return NextResponse.json(
|
||||
{ error: "Failed to load skills" },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
25
app/api/teams/route.ts
Normal file
25
app/api/teams/route.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import { Team } from "@/lib/types";
|
||||
|
||||
export async function GET() {
|
||||
try {
|
||||
const filePath = path.join(process.cwd(), "data", "teams.json");
|
||||
|
||||
if (!fs.existsSync(filePath)) {
|
||||
return NextResponse.json({ teams: [] });
|
||||
}
|
||||
|
||||
const fileContent = fs.readFileSync(filePath, "utf-8");
|
||||
const data = JSON.parse(fileContent);
|
||||
|
||||
return NextResponse.json(data.teams as Team[]);
|
||||
} catch (error) {
|
||||
console.error("Error loading teams:", error);
|
||||
return NextResponse.json(
|
||||
{ error: "Failed to load teams" },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
98
app/page.tsx
98
app/page.tsx
@@ -20,6 +20,43 @@ import Link from "next/link";
|
||||
import { Code2, ChevronDown, ChevronRight, ExternalLink } from "lucide-react";
|
||||
import { getCategoryIcon } from "@/lib/category-icons";
|
||||
|
||||
// Fonction pour déterminer la couleur du badge selon le niveau moyen
|
||||
function getScoreColors(score: number) {
|
||||
if (score >= 2.5) {
|
||||
// Expert/Maîtrise (violet)
|
||||
return {
|
||||
bg: "bg-violet-500/20",
|
||||
border: "border-violet-500/30",
|
||||
text: "text-violet-400",
|
||||
gradient: "from-violet-500 to-violet-400",
|
||||
};
|
||||
} else if (score >= 1.5) {
|
||||
// Autonome (vert)
|
||||
return {
|
||||
bg: "bg-green-500/20",
|
||||
border: "border-green-500/30",
|
||||
text: "text-green-400",
|
||||
gradient: "from-green-500 to-green-400",
|
||||
};
|
||||
} else if (score >= 0.5) {
|
||||
// Non autonome (orange/amber)
|
||||
return {
|
||||
bg: "bg-amber-500/20",
|
||||
border: "border-amber-500/30",
|
||||
text: "text-amber-400",
|
||||
gradient: "from-amber-500 to-amber-400",
|
||||
};
|
||||
} else {
|
||||
// Jamais pratiqué (rouge)
|
||||
return {
|
||||
bg: "bg-red-500/20",
|
||||
border: "border-red-500/30",
|
||||
text: "text-red-400",
|
||||
gradient: "from-red-500 to-red-400",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export default function HomePage() {
|
||||
const { userEvaluation, skillCategories, teams, loading, updateProfile } =
|
||||
useEvaluation();
|
||||
@@ -186,26 +223,53 @@ export default function HomePage() {
|
||||
{category.category}
|
||||
</h4>
|
||||
</div>
|
||||
<div className="px-2 py-0.5 rounded-full bg-blue-500/20 border border-blue-500/30">
|
||||
<span className="text-xs font-medium text-blue-400">
|
||||
{category.score.toFixed(1)}/3
|
||||
</span>
|
||||
</div>
|
||||
{skillsCount > 0 ? (
|
||||
(() => {
|
||||
const colors = getScoreColors(category.score);
|
||||
return (
|
||||
<div
|
||||
className={`px-2 py-0.5 rounded-full ${colors.bg} border ${colors.border}`}
|
||||
>
|
||||
<span
|
||||
className={`text-xs font-medium ${colors.text}`}
|
||||
>
|
||||
{Math.round((category.score / 3) * 100)}%
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
})()
|
||||
) : (
|
||||
<div className="px-2 py-0.5 rounded-full bg-slate-500/20 border border-slate-500/30">
|
||||
<span className="text-xs font-medium text-slate-400">
|
||||
Aucune
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="text-xs text-slate-400 mb-2">
|
||||
{evaluatedCount}/{skillsCount} compétences sélectionnées
|
||||
évaluées
|
||||
</div>
|
||||
<div className="w-full bg-white/10 rounded-full h-1.5">
|
||||
<div
|
||||
className="bg-gradient-to-r from-blue-500 to-blue-400 h-1.5 rounded-full transition-all"
|
||||
style={{
|
||||
width: `${
|
||||
(category.score / category.maxScore) * 100
|
||||
}%`,
|
||||
}}
|
||||
></div>
|
||||
{skillsCount > 0
|
||||
? `${evaluatedCount}/${skillsCount} compétences sélectionnées évaluées`
|
||||
: "Aucune compétence sélectionnée"}
|
||||
</div>
|
||||
{skillsCount > 0 ? (
|
||||
<div className="w-full bg-white/10 rounded-full h-1.5">
|
||||
{(() => {
|
||||
const colors = getScoreColors(category.score);
|
||||
return (
|
||||
<div
|
||||
className={`bg-gradient-to-r ${colors.gradient} h-1.5 rounded-full transition-all`}
|
||||
style={{
|
||||
width: `${
|
||||
(category.score / category.maxScore) * 100
|
||||
}%`,
|
||||
}}
|
||||
></div>
|
||||
);
|
||||
})()}
|
||||
</div>
|
||||
) : (
|
||||
<div className="w-full bg-slate-500/10 rounded-full h-1.5"></div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Expanded Skills */}
|
||||
|
||||
Reference in New Issue
Block a user