refactor: revew all design of services, clients, deadcode, ...
This commit is contained in:
@@ -1,193 +0,0 @@
|
||||
export interface Skill {
|
||||
id: string;
|
||||
name: string;
|
||||
description: string;
|
||||
icon: string;
|
||||
categoryId: string;
|
||||
category: string;
|
||||
usageCount: number;
|
||||
}
|
||||
|
||||
export interface Team {
|
||||
id: string;
|
||||
name: string;
|
||||
direction: string;
|
||||
memberCount: number;
|
||||
}
|
||||
|
||||
export interface TeamMember {
|
||||
id: string;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
fullName: string;
|
||||
joinedAt: string;
|
||||
}
|
||||
|
||||
export class AdminManagementService {
|
||||
private static baseUrl = "/api/admin";
|
||||
|
||||
// Skills Management
|
||||
static async getSkills(): Promise<Skill[]> {
|
||||
const response = await fetch(`${this.baseUrl}/skills`);
|
||||
if (!response.ok) {
|
||||
throw new Error("Failed to fetch skills");
|
||||
}
|
||||
return response.json();
|
||||
}
|
||||
|
||||
static async createSkill(
|
||||
skillData: Omit<Skill, "id" | "usageCount">
|
||||
): Promise<Skill> {
|
||||
const response = await fetch(`${this.baseUrl}/skills`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(skillData),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const error = await response.json();
|
||||
throw new Error(error.error || "Failed to create skill");
|
||||
}
|
||||
|
||||
return response.json();
|
||||
}
|
||||
|
||||
static async updateSkill(skillData: Skill): Promise<Skill> {
|
||||
const response = await fetch(`${this.baseUrl}/skills`, {
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(skillData),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const error = await response.json();
|
||||
throw new Error(error.error || "Failed to update skill");
|
||||
}
|
||||
|
||||
return response.json();
|
||||
}
|
||||
|
||||
static async deleteSkill(skillId: string): Promise<void> {
|
||||
const response = await fetch(`${this.baseUrl}/skills?id=${skillId}`, {
|
||||
method: "DELETE",
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const error = await response.json();
|
||||
throw new Error(error.error || "Failed to delete skill");
|
||||
}
|
||||
}
|
||||
|
||||
// Teams Management
|
||||
static async getTeams(): Promise<Team[]> {
|
||||
const response = await fetch(`${this.baseUrl}/teams`);
|
||||
if (!response.ok) {
|
||||
throw new Error("Failed to fetch teams");
|
||||
}
|
||||
return response.json();
|
||||
}
|
||||
|
||||
static async createTeam(
|
||||
teamData: Omit<Team, "id" | "memberCount">
|
||||
): Promise<Team> {
|
||||
const response = await fetch(`${this.baseUrl}/teams`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(teamData),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const error = await response.json();
|
||||
throw new Error(error.error || "Failed to create team");
|
||||
}
|
||||
|
||||
return response.json();
|
||||
}
|
||||
|
||||
static async updateTeam(teamData: Team): Promise<Team> {
|
||||
const response = await fetch(`${this.baseUrl}/teams`, {
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(teamData),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const error = await response.json();
|
||||
throw new Error(error.error || "Failed to update team");
|
||||
}
|
||||
|
||||
return response.json();
|
||||
}
|
||||
|
||||
static async deleteTeam(teamId: string): Promise<void> {
|
||||
const response = await fetch(`${this.baseUrl}/teams?id=${teamId}`, {
|
||||
method: "DELETE",
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const error = await response.json();
|
||||
throw new Error(error.error || "Failed to delete team");
|
||||
}
|
||||
}
|
||||
|
||||
static async deleteDirection(direction: string): Promise<void> {
|
||||
const response = await fetch(
|
||||
`${this.baseUrl}/teams?direction=${encodeURIComponent(direction)}`,
|
||||
{
|
||||
method: "DELETE",
|
||||
}
|
||||
);
|
||||
|
||||
if (!response.ok) {
|
||||
const error = await response.json();
|
||||
throw new Error(error.error || "Failed to delete direction");
|
||||
}
|
||||
}
|
||||
|
||||
// Team Members
|
||||
static async getTeamMembers(teamId: string): Promise<TeamMember[]> {
|
||||
const response = await fetch(`${this.baseUrl}/teams/${teamId}/members`);
|
||||
if (!response.ok) {
|
||||
throw new Error("Failed to fetch team members");
|
||||
}
|
||||
return response.json();
|
||||
}
|
||||
|
||||
static async removeTeamMember(
|
||||
teamId: string,
|
||||
memberId: string
|
||||
): Promise<void> {
|
||||
const response = await fetch(`${this.baseUrl}/teams/${teamId}/members`, {
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({ memberId }),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const error = await response.json();
|
||||
throw new Error(error.error || "Failed to remove team member");
|
||||
}
|
||||
}
|
||||
|
||||
// User Management
|
||||
static async deleteUser(userId: string): Promise<void> {
|
||||
const response = await fetch(`${this.baseUrl}/users/${userId}`, {
|
||||
method: "DELETE",
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const error = await response.json();
|
||||
throw new Error(error.error || "Failed to delete user");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,39 +1,6 @@
|
||||
import { getPool } from "./database";
|
||||
import { Team, SkillCategory } from "@/lib/types";
|
||||
|
||||
export interface TeamMember {
|
||||
uuid: string;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
skills: Array<{
|
||||
skillId: string;
|
||||
skillName: string;
|
||||
category: string;
|
||||
level: number;
|
||||
canMentor: boolean;
|
||||
wantsToLearn: boolean;
|
||||
}>;
|
||||
joinDate: string;
|
||||
}
|
||||
|
||||
export interface TeamStats {
|
||||
teamId: string;
|
||||
teamName: string;
|
||||
direction: string;
|
||||
totalMembers: number;
|
||||
averageSkillLevel: number;
|
||||
topSkills: Array<{ skillName: string; averageLevel: number; icon?: string }>;
|
||||
skillCoverage: number; // Percentage of skills evaluated
|
||||
members: TeamMember[];
|
||||
}
|
||||
|
||||
export interface DirectionStats {
|
||||
direction: string;
|
||||
teams: TeamStats[];
|
||||
totalMembers: number;
|
||||
averageSkillLevel: number;
|
||||
topCategories: Array<{ category: string; averageLevel: number }>;
|
||||
}
|
||||
import { TeamMember, TeamStats, DirectionStats } from "@/lib/admin-types";
|
||||
|
||||
export class AdminService {
|
||||
/**
|
||||
|
||||
@@ -1,444 +0,0 @@
|
||||
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 [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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();
|
||||
32
services/auth-service.ts
Normal file
32
services/auth-service.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { cookies } from "next/headers";
|
||||
// Constantes pour les cookies (définies ici car auth-service.ts a été supprimé)
|
||||
export const COOKIE_NAME = "peakSkills_userId";
|
||||
export const COOKIE_MAX_AGE = 30 * 24 * 60 * 60; // 30 jours
|
||||
|
||||
/**
|
||||
* Service d'authentification côté serveur
|
||||
* Implémente les méthodes qui nécessitent next/headers
|
||||
*/
|
||||
export class AuthService {
|
||||
/**
|
||||
* Récupère l'UUID utilisateur depuis le cookie côté serveur
|
||||
*/
|
||||
static async getUserUuidFromCookie(): Promise<string | null> {
|
||||
const cookieStore = await cookies();
|
||||
const userUuidCookie = cookieStore.get(COOKIE_NAME);
|
||||
|
||||
if (!userUuidCookie?.value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return userUuidCookie.value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si l'utilisateur est authentifié côté serveur
|
||||
*/
|
||||
static async isUserAuthenticated(): Promise<boolean> {
|
||||
const userUuid = await this.getUserUuidFromCookie();
|
||||
return !!userUuid;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
// Client-side services only
|
||||
// Safe to import in React components and hooks
|
||||
|
||||
export { ApiClient, apiClient } from "./api-client";
|
||||
@@ -15,6 +15,9 @@ export class EvaluationService {
|
||||
async loadUserEvaluationByUuid(
|
||||
userUuid: string
|
||||
): Promise<UserEvaluation | null> {
|
||||
if (!userUuid) {
|
||||
return null;
|
||||
}
|
||||
const pool = getPool();
|
||||
const client = await pool.connect();
|
||||
|
||||
@@ -677,6 +680,23 @@ export class EvaluationService {
|
||||
client.release();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Récupère l'évaluation complète de l'utilisateur côté serveur
|
||||
* Combine la récupération du cookie et le chargement de l'évaluation
|
||||
*/
|
||||
async getServerUserEvaluation(userUuid: string) {
|
||||
if (!userUuid) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
return await this.loadUserEvaluationByUuid(userUuid);
|
||||
} catch (error) {
|
||||
console.error("Failed to get user evaluation:", error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Instance singleton
|
||||
|
||||
@@ -20,8 +20,8 @@ export { SkillsService } from "./skills-service";
|
||||
// Admin services (server-only)
|
||||
export { AdminService } from "./admin-service";
|
||||
|
||||
// Admin management services (client-side compatible)
|
||||
export { AdminManagementService } from "./admin-management-service";
|
||||
// Admin types (can be imported anywhere)
|
||||
export type { TeamMember, TeamStats, DirectionStats } from "@/lib/admin-types";
|
||||
|
||||
// API client (can be used client-side)
|
||||
export { ApiClient, apiClient } from "./api-client";
|
||||
// Server auth service (server-side only)
|
||||
export { AuthService, COOKIE_NAME, COOKIE_MAX_AGE } from "./auth-service";
|
||||
|
||||
Reference in New Issue
Block a user