feat: add PostgreSQL support and enhance evaluation loading
- Added `pg` and `@types/pg` dependencies for PostgreSQL integration. - Updated `useEvaluation` hook to load user evaluations from the API, improving data management. - Refactored `saveUserEvaluation` and `loadUserEvaluation` functions to interact with the API instead of localStorage. - Introduced error handling for profile loading and evaluation saving to enhance robustness. - Added new methods for managing user profiles and evaluations, including `clearUserProfile` and `loadEvaluationForProfile`.
This commit is contained in:
174
services/api-client.ts
Normal file
174
services/api-client.ts
Normal file
@@ -0,0 +1,174 @@
|
||||
import { UserEvaluation, UserProfile, SkillLevel } 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
|
||||
*/
|
||||
async loadUserEvaluation(
|
||||
profile: UserProfile
|
||||
): Promise<UserEvaluation | null> {
|
||||
try {
|
||||
const params = new URLSearchParams({
|
||||
firstName: profile.firstName,
|
||||
lastName: profile.lastName,
|
||||
teamId: profile.teamId,
|
||||
});
|
||||
|
||||
const response = await fetch(`${this.baseUrl}/api/evaluations?${params}`);
|
||||
|
||||
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 }),
|
||||
});
|
||||
|
||||
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,
|
||||
}),
|
||||
});
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Instance singleton
|
||||
export const apiClient = new ApiClient();
|
||||
4
services/client.ts
Normal file
4
services/client.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
// Client-side services only
|
||||
// Safe to import in React components and hooks
|
||||
|
||||
export { ApiClient, apiClient } from "./api-client";
|
||||
33
services/database.ts
Normal file
33
services/database.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import { Pool } from "pg";
|
||||
|
||||
// Configuration de la base de données
|
||||
const dbConfig = {
|
||||
host: process.env.DB_HOST || "localhost",
|
||||
port: parseInt(process.env.DB_PORT || "5432"),
|
||||
database: process.env.DB_NAME || "peakskills",
|
||||
user: process.env.DB_USER || "peakskills_user",
|
||||
password: process.env.DB_PASSWORD || "peakskills_password",
|
||||
};
|
||||
|
||||
// Pool de connexions global
|
||||
let pool: Pool | null = null;
|
||||
|
||||
export function getPool(): Pool {
|
||||
if (!pool) {
|
||||
pool = new Pool(dbConfig);
|
||||
|
||||
pool.on("error", (err) => {
|
||||
console.error("Unexpected error on idle client", err);
|
||||
process.exit(-1);
|
||||
});
|
||||
}
|
||||
|
||||
return pool;
|
||||
}
|
||||
|
||||
export async function closePool(): Promise<void> {
|
||||
if (pool) {
|
||||
await pool.end();
|
||||
pool = null;
|
||||
}
|
||||
}
|
||||
527
services/evaluation-service.ts
Normal file
527
services/evaluation-service.ts
Normal file
@@ -0,0 +1,527 @@
|
||||
import { getPool } from "./database";
|
||||
import {
|
||||
UserEvaluation,
|
||||
UserProfile,
|
||||
CategoryEvaluation,
|
||||
SkillEvaluation,
|
||||
SkillLevel,
|
||||
} from "../lib/types";
|
||||
|
||||
export class EvaluationService {
|
||||
/**
|
||||
* Crée ou met à jour un utilisateur
|
||||
*/
|
||||
async upsertUser(profile: UserProfile): Promise<number> {
|
||||
const pool = getPool();
|
||||
const client = await pool.connect();
|
||||
|
||||
try {
|
||||
// Vérifier si l'utilisateur existe déjà (par firstName + lastName + teamId)
|
||||
const existingUserQuery = `
|
||||
SELECT id FROM users
|
||||
WHERE first_name = $1 AND last_name = $2 AND team_id = $3
|
||||
`;
|
||||
|
||||
const existingUser = await client.query(existingUserQuery, [
|
||||
profile.firstName,
|
||||
profile.lastName,
|
||||
profile.teamId,
|
||||
]);
|
||||
|
||||
if (existingUser.rows.length > 0) {
|
||||
// Mettre à jour l'utilisateur existant
|
||||
const updateQuery = `
|
||||
UPDATE users
|
||||
SET first_name = $1, last_name = $2, team_id = $3, updated_at = CURRENT_TIMESTAMP
|
||||
WHERE id = $4
|
||||
RETURNING id
|
||||
`;
|
||||
|
||||
const result = await client.query(updateQuery, [
|
||||
profile.firstName,
|
||||
profile.lastName,
|
||||
profile.teamId,
|
||||
existingUser.rows[0].id,
|
||||
]);
|
||||
|
||||
return result.rows[0].id;
|
||||
} else {
|
||||
// Créer un nouvel utilisateur
|
||||
const insertQuery = `
|
||||
INSERT INTO users (first_name, last_name, team_id)
|
||||
VALUES ($1, $2, $3)
|
||||
RETURNING id
|
||||
`;
|
||||
|
||||
const result = await client.query(insertQuery, [
|
||||
profile.firstName,
|
||||
profile.lastName,
|
||||
profile.teamId,
|
||||
]);
|
||||
|
||||
return result.rows[0].id;
|
||||
}
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sauvegarde une évaluation utilisateur complète
|
||||
*/
|
||||
async saveUserEvaluation(evaluation: UserEvaluation): Promise<void> {
|
||||
const pool = getPool();
|
||||
const client = await pool.connect();
|
||||
|
||||
try {
|
||||
await client.query("BEGIN");
|
||||
|
||||
// 1. Upsert user
|
||||
const userId = await this.upsertUser(evaluation.profile);
|
||||
|
||||
// 2. Upsert user_evaluation
|
||||
const userEvalQuery = `
|
||||
INSERT INTO user_evaluations (user_id, last_updated)
|
||||
VALUES ($1, $2)
|
||||
ON CONFLICT (user_id)
|
||||
DO UPDATE SET last_updated = $2
|
||||
RETURNING id
|
||||
`;
|
||||
|
||||
const userEvalResult = await client.query(userEvalQuery, [
|
||||
userId,
|
||||
new Date(evaluation.lastUpdated),
|
||||
]);
|
||||
|
||||
const userEvaluationId = userEvalResult.rows[0].id;
|
||||
|
||||
// 3. Supprimer les anciennes évaluations de catégories
|
||||
await client.query(
|
||||
"DELETE FROM category_evaluations WHERE user_evaluation_id = $1",
|
||||
[userEvaluationId]
|
||||
);
|
||||
|
||||
// 4. Sauvegarder les nouvelles évaluations
|
||||
for (const catEval of evaluation.evaluations) {
|
||||
await this.saveCategoryEvaluation(client, userEvaluationId, catEval);
|
||||
}
|
||||
|
||||
await client.query("COMMIT");
|
||||
} catch (error) {
|
||||
await client.query("ROLLBACK");
|
||||
throw error;
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sauvegarde une évaluation de catégorie
|
||||
*/
|
||||
private async saveCategoryEvaluation(
|
||||
client: any,
|
||||
userEvaluationId: number,
|
||||
catEval: CategoryEvaluation
|
||||
): Promise<void> {
|
||||
// Insérer la catégorie d'évaluation
|
||||
const catEvalQuery = `
|
||||
INSERT INTO category_evaluations (user_evaluation_id, category)
|
||||
VALUES ($1, $2)
|
||||
RETURNING id
|
||||
`;
|
||||
|
||||
const catEvalResult = await client.query(catEvalQuery, [
|
||||
userEvaluationId,
|
||||
catEval.category,
|
||||
]);
|
||||
|
||||
const categoryEvaluationId = catEvalResult.rows[0].id;
|
||||
|
||||
// Insérer les skills sélectionnées
|
||||
for (const skillId of catEval.selectedSkillIds) {
|
||||
await client.query(
|
||||
"INSERT INTO selected_skills (category_evaluation_id, skill_id) VALUES ($1, $2)",
|
||||
[categoryEvaluationId, skillId]
|
||||
);
|
||||
}
|
||||
|
||||
// Insérer les évaluations de skills
|
||||
for (const skillEval of catEval.skills) {
|
||||
if (skillEval.level !== null) {
|
||||
await client.query(
|
||||
`
|
||||
INSERT INTO skill_evaluations
|
||||
(category_evaluation_id, skill_id, level, can_mentor, wants_to_learn)
|
||||
VALUES ($1, $2, $3, $4, $5)
|
||||
`,
|
||||
[
|
||||
categoryEvaluationId,
|
||||
skillEval.skillId,
|
||||
skillEval.level,
|
||||
skillEval.canMentor || false,
|
||||
skillEval.wantsToLearn || false,
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Charge une évaluation utilisateur
|
||||
*/
|
||||
async loadUserEvaluation(
|
||||
profile: UserProfile
|
||||
): Promise<UserEvaluation | null> {
|
||||
const pool = getPool();
|
||||
const client = await pool.connect();
|
||||
|
||||
try {
|
||||
// Trouver l'utilisateur
|
||||
const userQuery = `
|
||||
SELECT u.*, ue.id as user_evaluation_id, ue.last_updated
|
||||
FROM users u
|
||||
LEFT JOIN user_evaluations ue ON u.id = ue.user_id
|
||||
WHERE u.first_name = $1 AND u.last_name = $2 AND u.team_id = $3
|
||||
`;
|
||||
|
||||
const userResult = await client.query(userQuery, [
|
||||
profile.firstName,
|
||||
profile.lastName,
|
||||
profile.teamId,
|
||||
]);
|
||||
|
||||
if (
|
||||
userResult.rows.length === 0 ||
|
||||
!userResult.rows[0].user_evaluation_id
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const userData = userResult.rows[0];
|
||||
const userEvaluationId = userData.user_evaluation_id;
|
||||
|
||||
// Charger les évaluations de catégories
|
||||
const categoriesQuery = `
|
||||
SELECT ce.*,
|
||||
array_agg(DISTINCT ss.skill_id) FILTER (WHERE ss.skill_id IS NOT NULL) as selected_skill_ids,
|
||||
array_agg(
|
||||
json_build_object(
|
||||
'skillId', se.skill_id,
|
||||
'level', se.level,
|
||||
'canMentor', se.can_mentor,
|
||||
'wantsToLearn', se.wants_to_learn
|
||||
)
|
||||
) FILTER (WHERE se.skill_id IS NOT NULL) as skill_evaluations
|
||||
FROM category_evaluations ce
|
||||
LEFT JOIN selected_skills ss ON ce.id = ss.category_evaluation_id
|
||||
LEFT JOIN skill_evaluations se ON ce.id = se.category_evaluation_id
|
||||
WHERE ce.user_evaluation_id = $1
|
||||
GROUP BY ce.id, ce.category
|
||||
ORDER BY ce.category
|
||||
`;
|
||||
|
||||
const categoriesResult = await client.query(categoriesQuery, [
|
||||
userEvaluationId,
|
||||
]);
|
||||
|
||||
const evaluations: CategoryEvaluation[] = categoriesResult.rows.map(
|
||||
(row) => ({
|
||||
category: row.category,
|
||||
selectedSkillIds: row.selected_skill_ids || [],
|
||||
skills: (row.skill_evaluations || []).filter(
|
||||
(se: any) => se.skillId !== null
|
||||
),
|
||||
})
|
||||
);
|
||||
|
||||
return {
|
||||
profile,
|
||||
evaluations,
|
||||
lastUpdated: userData.last_updated.toISOString(),
|
||||
};
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Met à jour le niveau d'une skill
|
||||
*/
|
||||
async updateSkillLevel(
|
||||
profile: UserProfile,
|
||||
category: string,
|
||||
skillId: string,
|
||||
level: SkillLevel
|
||||
): Promise<void> {
|
||||
const pool = getPool();
|
||||
const client = await pool.connect();
|
||||
|
||||
try {
|
||||
await client.query("BEGIN");
|
||||
|
||||
const userId = await this.upsertUser(profile);
|
||||
|
||||
// Obtenir ou créer user_evaluation
|
||||
const userEvalResult = await client.query(
|
||||
`
|
||||
INSERT INTO user_evaluations (user_id, last_updated)
|
||||
VALUES ($1, CURRENT_TIMESTAMP)
|
||||
ON CONFLICT (user_id)
|
||||
DO UPDATE SET last_updated = CURRENT_TIMESTAMP
|
||||
RETURNING id
|
||||
`,
|
||||
[userId]
|
||||
);
|
||||
|
||||
const userEvaluationId = userEvalResult.rows[0].id;
|
||||
|
||||
// Obtenir ou créer category_evaluation
|
||||
const catEvalResult = await client.query(
|
||||
`
|
||||
INSERT INTO category_evaluations (user_evaluation_id, category)
|
||||
VALUES ($1, $2)
|
||||
ON CONFLICT (user_evaluation_id, category)
|
||||
DO UPDATE SET category = $2
|
||||
RETURNING id
|
||||
`,
|
||||
[userEvaluationId, category]
|
||||
);
|
||||
|
||||
const categoryEvaluationId = catEvalResult.rows[0].id;
|
||||
|
||||
// Upsert skill evaluation
|
||||
await client.query(
|
||||
`
|
||||
INSERT INTO skill_evaluations (category_evaluation_id, skill_id, level)
|
||||
VALUES ($1, $2, $3)
|
||||
ON CONFLICT (category_evaluation_id, skill_id)
|
||||
DO UPDATE SET level = $3, updated_at = CURRENT_TIMESTAMP
|
||||
`,
|
||||
[categoryEvaluationId, skillId, level]
|
||||
);
|
||||
|
||||
await client.query("COMMIT");
|
||||
} catch (error) {
|
||||
await client.query("ROLLBACK");
|
||||
throw error;
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Met à jour le statut de mentorat d'une skill
|
||||
*/
|
||||
async updateSkillMentorStatus(
|
||||
profile: UserProfile,
|
||||
category: string,
|
||||
skillId: string,
|
||||
canMentor: boolean
|
||||
): Promise<void> {
|
||||
await this.updateSkillProperty(
|
||||
profile,
|
||||
category,
|
||||
skillId,
|
||||
"can_mentor",
|
||||
canMentor
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Met à jour le statut d'apprentissage d'une skill
|
||||
*/
|
||||
async updateSkillLearningStatus(
|
||||
profile: UserProfile,
|
||||
category: string,
|
||||
skillId: string,
|
||||
wantsToLearn: boolean
|
||||
): Promise<void> {
|
||||
await this.updateSkillProperty(
|
||||
profile,
|
||||
category,
|
||||
skillId,
|
||||
"wants_to_learn",
|
||||
wantsToLearn
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Méthode utilitaire pour mettre à jour une propriété de skill
|
||||
*/
|
||||
private async updateSkillProperty(
|
||||
profile: UserProfile,
|
||||
category: string,
|
||||
skillId: string,
|
||||
property: "can_mentor" | "wants_to_learn",
|
||||
value: boolean
|
||||
): Promise<void> {
|
||||
const pool = getPool();
|
||||
const client = await pool.connect();
|
||||
|
||||
try {
|
||||
await client.query("BEGIN");
|
||||
|
||||
const userId = await this.upsertUser(profile);
|
||||
|
||||
const userEvalResult = await client.query(
|
||||
`
|
||||
INSERT INTO user_evaluations (user_id, last_updated)
|
||||
VALUES ($1, CURRENT_TIMESTAMP)
|
||||
ON CONFLICT (user_id)
|
||||
DO UPDATE SET last_updated = CURRENT_TIMESTAMP
|
||||
RETURNING id
|
||||
`,
|
||||
[userId]
|
||||
);
|
||||
|
||||
const userEvaluationId = userEvalResult.rows[0].id;
|
||||
|
||||
const catEvalResult = await client.query(
|
||||
`
|
||||
INSERT INTO category_evaluations (user_evaluation_id, category)
|
||||
VALUES ($1, $2)
|
||||
ON CONFLICT (user_evaluation_id, category)
|
||||
DO UPDATE SET category = $2
|
||||
RETURNING id
|
||||
`,
|
||||
[userEvaluationId, category]
|
||||
);
|
||||
|
||||
const categoryEvaluationId = catEvalResult.rows[0].id;
|
||||
|
||||
// Update the specific property
|
||||
const updateQuery = `
|
||||
UPDATE skill_evaluations
|
||||
SET ${property} = $3, updated_at = CURRENT_TIMESTAMP
|
||||
WHERE category_evaluation_id = $1 AND skill_id = $2
|
||||
`;
|
||||
|
||||
await client.query(updateQuery, [categoryEvaluationId, skillId, value]);
|
||||
|
||||
await client.query("COMMIT");
|
||||
} catch (error) {
|
||||
await client.query("ROLLBACK");
|
||||
throw error;
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajoute une skill à l'évaluation
|
||||
*/
|
||||
async addSkillToEvaluation(
|
||||
profile: UserProfile,
|
||||
category: string,
|
||||
skillId: string
|
||||
): Promise<void> {
|
||||
const pool = getPool();
|
||||
const client = await pool.connect();
|
||||
|
||||
try {
|
||||
await client.query("BEGIN");
|
||||
|
||||
const userId = await this.upsertUser(profile);
|
||||
|
||||
const userEvalResult = await client.query(
|
||||
`
|
||||
INSERT INTO user_evaluations (user_id, last_updated)
|
||||
VALUES ($1, CURRENT_TIMESTAMP)
|
||||
ON CONFLICT (user_id)
|
||||
DO UPDATE SET last_updated = CURRENT_TIMESTAMP
|
||||
RETURNING id
|
||||
`,
|
||||
[userId]
|
||||
);
|
||||
|
||||
const userEvaluationId = userEvalResult.rows[0].id;
|
||||
|
||||
const catEvalResult = await client.query(
|
||||
`
|
||||
INSERT INTO category_evaluations (user_evaluation_id, category)
|
||||
VALUES ($1, $2)
|
||||
ON CONFLICT (user_evaluation_id, category)
|
||||
DO UPDATE SET category = $2
|
||||
RETURNING id
|
||||
`,
|
||||
[userEvaluationId, category]
|
||||
);
|
||||
|
||||
const categoryEvaluationId = catEvalResult.rows[0].id;
|
||||
|
||||
// Ajouter à selected_skills
|
||||
await client.query(
|
||||
`
|
||||
INSERT INTO selected_skills (category_evaluation_id, skill_id)
|
||||
VALUES ($1, $2)
|
||||
ON CONFLICT DO NOTHING
|
||||
`,
|
||||
[categoryEvaluationId, skillId]
|
||||
);
|
||||
|
||||
await client.query("COMMIT");
|
||||
} catch (error) {
|
||||
await client.query("ROLLBACK");
|
||||
throw error;
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Supprime une skill de l'évaluation
|
||||
*/
|
||||
async removeSkillFromEvaluation(
|
||||
profile: UserProfile,
|
||||
category: string,
|
||||
skillId: string
|
||||
): Promise<void> {
|
||||
const pool = getPool();
|
||||
const client = await pool.connect();
|
||||
|
||||
try {
|
||||
await client.query("BEGIN");
|
||||
|
||||
// Trouver les IDs nécessaires
|
||||
const findQuery = `
|
||||
SELECT ce.id as category_evaluation_id
|
||||
FROM users u
|
||||
JOIN user_evaluations ue ON u.id = ue.user_id
|
||||
JOIN category_evaluations ce ON ue.id = ce.user_evaluation_id
|
||||
WHERE u.first_name = $1 AND u.last_name = $2 AND u.team_id = $3 AND ce.category = $4
|
||||
`;
|
||||
|
||||
const result = await client.query(findQuery, [
|
||||
profile.firstName,
|
||||
profile.lastName,
|
||||
profile.teamId,
|
||||
category,
|
||||
]);
|
||||
|
||||
if (result.rows.length > 0) {
|
||||
const categoryEvaluationId = result.rows[0].category_evaluation_id;
|
||||
|
||||
// Supprimer de selected_skills et skill_evaluations
|
||||
await client.query(
|
||||
"DELETE FROM selected_skills WHERE category_evaluation_id = $1 AND skill_id = $2",
|
||||
[categoryEvaluationId, skillId]
|
||||
);
|
||||
|
||||
await client.query(
|
||||
"DELETE FROM skill_evaluations WHERE category_evaluation_id = $1 AND skill_id = $2",
|
||||
[categoryEvaluationId, skillId]
|
||||
);
|
||||
}
|
||||
|
||||
await client.query("COMMIT");
|
||||
} catch (error) {
|
||||
await client.query("ROLLBACK");
|
||||
throw error;
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Instance singleton
|
||||
export const evaluationService = new EvaluationService();
|
||||
12
services/index.ts
Normal file
12
services/index.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
// Server-side services (Node.js only)
|
||||
// Note: These exports are only for server-side usage (API routes)
|
||||
// Don't import from this index in client-side code to avoid bundling server dependencies
|
||||
|
||||
// Database services (server-only)
|
||||
export { getPool, closePool } from "./database";
|
||||
|
||||
// Evaluation services (server-only)
|
||||
export { EvaluationService, evaluationService } from "./evaluation-service";
|
||||
|
||||
// API client (can be used client-side)
|
||||
export { ApiClient, apiClient } from "./api-client";
|
||||
Reference in New Issue
Block a user