refactor: SSR on skills management

This commit is contained in:
Julien Froidefond
2025-08-25 09:04:33 +02:00
parent e02af4f992
commit 0c7903bcb2
6 changed files with 51 additions and 52 deletions

View File

@@ -4,10 +4,15 @@ import { SkillsManagementPage } from "@/components/admin/skills";
export default async function SkillsPage() { export default async function SkillsPage() {
// Charger les données côté serveur // Charger les données côté serveur
try { try {
const { skillCategories, teams } = await AdminService.getAdminData(); const { skillCategories, teams, skills } =
await AdminService.getAdminData();
return ( return (
<SkillsManagementPage skillCategories={skillCategories} teams={teams} /> <SkillsManagementPage
skillCategories={skillCategories}
teams={teams}
initialSkills={skills}
/>
); );
} catch (error) { } catch (error) {
console.error("Failed to load admin data:", error); console.error("Failed to load admin data:", error);

View File

@@ -4,20 +4,6 @@ import { SkillsService } from "@/services/skills-service";
// Configuration pour éviter la génération statique // Configuration pour éviter la génération statique
export const dynamic = "force-dynamic"; export const dynamic = "force-dynamic";
// GET - Récupérer toutes les skills
export async function GET() {
try {
const skills = await SkillsService.getAllSkillsWithUsage();
return NextResponse.json(skills);
} catch (error) {
console.error("Error fetching skills:", error);
return NextResponse.json(
{ error: "Erreur lors de la récupération des skills" },
{ status: 500 }
);
}
}
// POST - Créer une nouvelle skill // POST - Créer une nouvelle skill
export async function POST(request: NextRequest) { export async function POST(request: NextRequest) {
try { try {

View File

@@ -41,10 +41,6 @@ export interface User {
export class AdminClient extends BaseHttpClient { export class AdminClient extends BaseHttpClient {
// Skills Management // Skills Management
async getSkills(): Promise<Skill[]> {
return await this.get<Skill[]>(`/admin/skills`);
}
async createSkill( async createSkill(
skillData: Omit<Skill, "id" | "usageCount"> skillData: Omit<Skill, "id" | "usageCount">
): Promise<Skill> { ): Promise<Skill> {

View File

@@ -15,11 +15,13 @@ import { SkillsList } from "./skills-list";
interface SkillsManagementPageProps { interface SkillsManagementPageProps {
skillCategories: SkillCategory[]; skillCategories: SkillCategory[];
teams: Team[]; teams: Team[];
initialSkills: any[];
} }
export function SkillsManagementPage({ export function SkillsManagementPage({
skillCategories, skillCategories,
teams, teams,
initialSkills,
}: SkillsManagementPageProps) { }: SkillsManagementPageProps) {
const [searchTerm, setSearchTerm] = useState(""); const [searchTerm, setSearchTerm] = useState("");
const { const {
@@ -43,7 +45,7 @@ export function SkillsManagementPage({
handleEditSkill, handleEditSkill,
handleUpdateSkill, handleUpdateSkill,
handleDeleteSkill, handleDeleteSkill,
} = useSkillsManagement(skillCategories); } = useSkillsManagement(skillCategories, initialSkills);
// Utilisation du hook factorisé pour la vue arborescente // Utilisation du hook factorisé pour la vue arborescente
const { const {

View File

@@ -11,9 +11,12 @@ interface SkillFormData {
icon: string; icon: string;
} }
export function useSkillsManagement(skillCategories: SkillCategory[]) { export function useSkillsManagement(
const [skills, setSkills] = useState<Skill[]>([]); skillCategories: SkillCategory[],
const [isLoading, setIsLoading] = useState(true); initialSkills?: any[]
) {
const [skills, setSkills] = useState<Skill[]>(initialSkills || []);
const [isLoading, setIsLoading] = useState(!initialSkills);
const [editingSkill, setEditingSkill] = useState<Skill | null>(null); const [editingSkill, setEditingSkill] = useState<Skill | null>(null);
const [skillFormData, setSkillFormData] = useState<SkillFormData>({ const [skillFormData, setSkillFormData] = useState<SkillFormData>({
name: "", name: "",
@@ -24,28 +27,28 @@ export function useSkillsManagement(skillCategories: SkillCategory[]) {
const [isSubmitting, setIsSubmitting] = useState(false); const [isSubmitting, setIsSubmitting] = useState(false);
const { toast } = useToast(); const { toast } = useToast();
// Charger les skills depuis l'API // Charger les skills depuis l'API si pas de skills initiales
const fetchSkills = async () => {
try {
setIsLoading(true);
const skillsData = await adminClient.getSkills();
setSkills(skillsData);
} catch (error) {
console.error("Error fetching skills:", error);
toast({
title: "Erreur",
description: "Impossible de charger les skills",
variant: "destructive",
});
} finally {
setIsLoading(false);
}
};
// Charger les skills au montage du composant
useEffect(() => { useEffect(() => {
fetchSkills(); if (!initialSkills) {
}, []); const fetchSkills = async () => {
try {
setIsLoading(true);
const skillsData = await adminClient.getSkills();
setSkills(skillsData);
} catch (error) {
console.error("Error fetching skills:", error);
toast({
title: "Erreur",
description: "Impossible de charger les skills",
variant: "destructive",
});
} finally {
setIsLoading(false);
}
};
fetchSkills();
}
}, [initialSkills]);
const resetForm = () => { const resetForm = () => {
setSkillFormData({ name: "", categoryId: "", description: "", icon: "" }); setSkillFormData({ name: "", categoryId: "", description: "", icon: "" });

View File

@@ -1,6 +1,7 @@
import { getPool } from "./database"; import { getPool } from "./database";
import { Team, SkillCategory } from "@/lib/types"; import { Team, SkillCategory } from "@/lib/types";
import { TeamMember, TeamStats, DirectionStats } from "@/lib/admin-types"; import { TeamMember, TeamStats, DirectionStats } from "@/lib/admin-types";
import { SkillsService } from "./skills-service";
export class AdminService { export class AdminService {
/** /**
@@ -197,18 +198,23 @@ export class AdminService {
skillCategories: SkillCategory[]; skillCategories: SkillCategory[];
teamStats: TeamStats[]; teamStats: TeamStats[];
directionStats: DirectionStats[]; directionStats: DirectionStats[];
skills: any[];
}> { }> {
const pool = getPool(); const pool = getPool();
try { try {
// Récupérer toutes les données en parallèle // Récupérer toutes les données en parallèle
const [teamsResult, categoriesResult, teamStats] = await Promise.all([ const [teamsResult, categoriesResult, teamStats, skills] =
pool.query( await Promise.all([
"SELECT id, name, direction FROM teams ORDER BY direction, name" pool.query(
), "SELECT id, name, direction FROM teams ORDER BY direction, name"
pool.query("SELECT id, name, icon FROM skill_categories ORDER BY name"), ),
AdminService.getTeamsStats(), pool.query(
]); "SELECT id, name, icon FROM skill_categories ORDER BY name"
),
AdminService.getTeamsStats(),
SkillsService.getAllSkillsWithUsage(),
]);
const teams = teamsResult.rows; const teams = teamsResult.rows;
const skillCategories = categoriesResult.rows.map((row) => ({ const skillCategories = categoriesResult.rows.map((row) => ({
@@ -224,6 +230,7 @@ export class AdminService {
skillCategories, skillCategories,
teamStats, teamStats,
directionStats, directionStats,
skills,
}; };
} catch (error) { } catch (error) {
console.error("Error fetching admin data:", error); console.error("Error fetching admin data:", error);