Files
peakskills/services/api-client.ts
Julien Froidefond 45fb1148ae feat: enhance evaluation loading with cookie authentication
- Updated the GET method in the evaluations route to support user authentication via cookies, improving security and user experience.
- Added compatibility for legacy parameter-based authentication to ensure backward compatibility.
- Refactored the useEvaluation hook to load user profiles from cookies instead of localStorage, streamlining the authentication process.
- Introduced a new method in EvaluationService to retrieve user profiles by ID, enhancing data retrieval efficiency.
- Updated ApiClient to handle cookie-based requests for loading evaluations, ensuring proper session management.
2025-08-21 11:55:50 +02:00

472 lines
11 KiB
TypeScript

import {
UserEvaluation,
UserProfile,
SkillLevel,
Team,
SkillCategory,
Skill,
} from "../lib/types";
export class ApiClient {
private baseUrl: string;
constructor() {
this.baseUrl = process.env.NEXT_PUBLIC_API_URL || "";
}
/**
* Charge une évaluation utilisateur depuis l'API
* Si profile est fourni, utilise les paramètres (mode compatibilité)
* Sinon, utilise l'authentification par cookie
*/
async loadUserEvaluation(
profile?: UserProfile
): Promise<UserEvaluation | null> {
try {
let url = `${this.baseUrl}/api/evaluations`;
// Mode compatibilité avec profile en paramètres
if (profile) {
const params = new URLSearchParams({
firstName: profile.firstName,
lastName: profile.lastName,
teamId: profile.teamId,
});
url += `?${params}`;
}
const response = await fetch(url, {
credentials: "same-origin", // Pour inclure les cookies
});
if (!response.ok) {
throw new Error("Erreur lors du chargement de l'évaluation");
}
const data = await response.json();
return data.evaluation;
} catch (error) {
console.error("Erreur lors du chargement de l'évaluation:", error);
return null;
}
}
/**
* Sauvegarde une évaluation utilisateur via l'API
*/
async saveUserEvaluation(evaluation: UserEvaluation): Promise<void> {
try {
const response = await fetch(`${this.baseUrl}/api/evaluations`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ evaluation }),
credentials: "same-origin",
});
if (!response.ok) {
throw new Error("Erreur lors de la sauvegarde de l'évaluation");
}
} catch (error) {
console.error("Erreur lors de la sauvegarde de l'évaluation:", error);
throw error;
}
}
/**
* Met à jour le niveau d'une skill
*/
async updateSkillLevel(
profile: UserProfile,
category: string,
skillId: string,
level: SkillLevel
): Promise<void> {
await this.updateSkill(profile, category, skillId, {
action: "updateLevel",
level,
});
}
/**
* Met à jour le statut de mentorat d'une skill
*/
async updateSkillMentorStatus(
profile: UserProfile,
category: string,
skillId: string,
canMentor: boolean
): Promise<void> {
await this.updateSkill(profile, category, skillId, {
action: "updateMentorStatus",
canMentor,
});
}
/**
* Met à jour le statut d'apprentissage d'une skill
*/
async updateSkillLearningStatus(
profile: UserProfile,
category: string,
skillId: string,
wantsToLearn: boolean
): Promise<void> {
await this.updateSkill(profile, category, skillId, {
action: "updateLearningStatus",
wantsToLearn,
});
}
/**
* Ajoute une skill à l'évaluation
*/
async addSkillToEvaluation(
profile: UserProfile,
category: string,
skillId: string
): Promise<void> {
await this.updateSkill(profile, category, skillId, {
action: "addSkill",
});
}
/**
* Supprime une skill de l'évaluation
*/
async removeSkillFromEvaluation(
profile: UserProfile,
category: string,
skillId: string
): Promise<void> {
await this.updateSkill(profile, category, skillId, {
action: "removeSkill",
});
}
/**
* Méthode utilitaire pour mettre à jour une skill
*/
private async updateSkill(
profile: UserProfile,
category: string,
skillId: string,
options: {
action:
| "updateLevel"
| "updateMentorStatus"
| "updateLearningStatus"
| "addSkill"
| "removeSkill";
level?: SkillLevel;
canMentor?: boolean;
wantsToLearn?: boolean;
}
): Promise<void> {
try {
const response = await fetch(`${this.baseUrl}/api/evaluations/skills`, {
method: "PUT",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
profile,
category,
skillId,
...options,
}),
credentials: "same-origin",
});
if (!response.ok) {
throw new Error("Erreur lors de la mise à jour de la skill");
}
} catch (error) {
console.error("Erreur lors de la mise à jour de la skill:", error);
throw error;
}
}
/**
* Charge toutes les équipes
*/
async loadTeams(): Promise<Team[]> {
try {
const response = await fetch(`${this.baseUrl}/api/teams`);
if (!response.ok) {
throw new Error("Erreur lors du chargement des équipes");
}
return await response.json();
} catch (error) {
console.error("Erreur lors du chargement des équipes:", error);
return [];
}
}
/**
* Charge une équipe par ID
*/
async loadTeamById(teamId: string): Promise<Team | null> {
try {
const response = await fetch(`${this.baseUrl}/api/teams/${teamId}`);
if (!response.ok) {
if (response.status === 404) {
return null;
}
throw new Error("Erreur lors du chargement de l'équipe");
}
return await response.json();
} catch (error) {
console.error("Erreur lors du chargement de l'équipe:", error);
return null;
}
}
/**
* Charge les équipes par direction
*/
async loadTeamsByDirection(direction: string): Promise<Team[]> {
try {
const response = await fetch(
`${this.baseUrl}/api/teams/direction/${direction}`
);
if (!response.ok) {
throw new Error("Erreur lors du chargement des équipes par direction");
}
return await response.json();
} catch (error) {
console.error(
"Erreur lors du chargement des équipes par direction:",
error
);
return [];
}
}
/**
* Charge toutes les directions
*/
async loadDirections(): Promise<string[]> {
try {
const response = await fetch(`${this.baseUrl}/api/teams/directions`);
if (!response.ok) {
throw new Error("Erreur lors du chargement des directions");
}
return await response.json();
} catch (error) {
console.error("Erreur lors du chargement des directions:", error);
return [];
}
}
/**
* Crée une nouvelle équipe
*/
async createTeam(
team: Omit<Team, "created_at" | "updated_at">
): Promise<Team | null> {
try {
const response = await fetch(`${this.baseUrl}/api/teams`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(team),
});
if (!response.ok) {
throw new Error("Erreur lors de la création de l'équipe");
}
return await response.json();
} catch (error) {
console.error("Erreur lors de la création de l'équipe:", error);
return null;
}
}
/**
* Met à jour une équipe
*/
async updateTeam(
teamId: string,
updates: Partial<Omit<Team, "id">>
): Promise<Team | null> {
try {
const response = await fetch(`${this.baseUrl}/api/teams/${teamId}`, {
method: "PUT",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(updates),
});
if (!response.ok) {
throw new Error("Erreur lors de la mise à jour de l'équipe");
}
return await response.json();
} catch (error) {
console.error("Erreur lors de la mise à jour de l'équipe:", error);
return null;
}
}
/**
* Supprime une équipe
*/
async deleteTeam(teamId: string): Promise<boolean> {
try {
const response = await fetch(`${this.baseUrl}/api/teams/${teamId}`, {
method: "DELETE",
});
if (!response.ok) {
throw new Error("Erreur lors de la suppression de l'équipe");
}
return true;
} catch (error) {
console.error("Erreur lors de la suppression de l'équipe:", error);
return false;
}
}
/**
* Charge toutes les catégories de skills
*/
async loadSkillCategories(): Promise<SkillCategory[]> {
try {
const response = await fetch(`${this.baseUrl}/api/skills`);
if (!response.ok) {
throw new Error("Erreur lors du chargement des catégories de skills");
}
return await response.json();
} catch (error) {
console.error(
"Erreur lors du chargement des catégories de skills:",
error
);
return [];
}
}
/**
* Charge les skills d'une catégorie
*/
async loadSkillsByCategory(categoryId: string): Promise<Skill[]> {
try {
const response = await fetch(`${this.baseUrl}/api/skills/${categoryId}`);
if (!response.ok) {
throw new Error("Erreur lors du chargement des skills par catégorie");
}
return await response.json();
} catch (error) {
console.error(
"Erreur lors du chargement des skills par catégorie:",
error
);
return [];
}
}
/**
* Migre les skills depuis JSON vers PostgreSQL
*/
async migrateSkills(): Promise<{
success: boolean;
stats?: any;
error?: string;
}> {
try {
const response = await fetch(`${this.baseUrl}/api/skills/migrate`, {
method: "POST",
});
if (!response.ok) {
throw new Error("Erreur lors de la migration des skills");
}
return await response.json();
} catch (error) {
console.error("Erreur lors de la migration des skills:", error);
return {
success: false,
error: error instanceof Error ? error.message : "Unknown error",
};
}
}
/**
* Crée une nouvelle catégorie de skill
*/
async createSkillCategory(category: {
id: string;
name: string;
icon: string;
}): Promise<boolean> {
try {
const response = await fetch(`${this.baseUrl}/api/skills`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(category),
});
return response.ok;
} catch (error) {
console.error(
"Erreur lors de la création de la catégorie de skill:",
error
);
return false;
}
}
/**
* Crée une nouvelle skill
*/
async createSkill(
categoryId: string,
skill: {
id: string;
name: string;
description: string;
icon?: string;
links: string[];
}
): Promise<boolean> {
try {
const response = await fetch(`${this.baseUrl}/api/skills/${categoryId}`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(skill),
});
return response.ok;
} catch (error) {
console.error("Erreur lors de la création de la skill:", error);
return false;
}
}
}
// Instance singleton
export const apiClient = new ApiClient();