refactor: SSR on page teams and split getAdminData
This commit is contained in:
@@ -4,13 +4,11 @@ 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, skills } =
|
const { skillCategories, skills } = await AdminService.getSkillsPageData();
|
||||||
await AdminService.getAdminData();
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SkillsManagementPage
|
<SkillsManagementPage
|
||||||
skillCategories={skillCategories}
|
skillCategories={skillCategories}
|
||||||
teams={teams}
|
|
||||||
initialSkills={skills}
|
initialSkills={skills}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -4,16 +4,10 @@ import { TeamsManagementPage } from "@/components/admin/teams";
|
|||||||
export default async function TeamsPage() {
|
export default async function TeamsPage() {
|
||||||
// Charger les données côté serveur
|
// Charger les données côté serveur
|
||||||
try {
|
try {
|
||||||
const { teams, teamStats, skillCategories } =
|
const { teams, teamStats, directionStats } =
|
||||||
await AdminService.getAdminData();
|
await AdminService.getTeamsPageData();
|
||||||
|
|
||||||
return (
|
return <TeamsManagementPage teams={teams} teamStats={teamStats} />;
|
||||||
<TeamsManagementPage
|
|
||||||
teams={teams}
|
|
||||||
teamStats={teamStats}
|
|
||||||
skillCategories={skillCategories}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Failed to load admin data:", error);
|
console.error("Failed to load admin data:", error);
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ import { UsersManagementPage } from "@/components/admin/users";
|
|||||||
export default async function UsersPage() {
|
export default async function UsersPage() {
|
||||||
// Charger les données côté serveur
|
// Charger les données côté serveur
|
||||||
try {
|
try {
|
||||||
const { teams } = await AdminService.getAdminData();
|
const { teams, users } = await AdminService.getUsersPageData();
|
||||||
|
|
||||||
return <UsersManagementPage teams={teams} />;
|
return <UsersManagementPage teams={teams} initialUsers={users} />;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Failed to load admin data:", error);
|
console.error("Failed to load admin data:", error);
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { AdminClientWrapper } from "@/components/admin";
|
|||||||
export default async function AdminPage() {
|
export default async function AdminPage() {
|
||||||
// Charger les données côté serveur
|
// Charger les données côté serveur
|
||||||
try {
|
try {
|
||||||
const adminData = await AdminService.getAdminData();
|
const adminData = await AdminService.getOverviewPageData();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AdminClientWrapper
|
<AdminClientWrapper
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
import { NextRequest, NextResponse } from "next/server";
|
|
||||||
import { UserService } from "@/services/user-service";
|
|
||||||
|
|
||||||
// GET - Récupérer la liste des utilisateurs
|
|
||||||
export async function GET(request: NextRequest) {
|
|
||||||
try {
|
|
||||||
const users = await UserService.getAllUsersForAdmin();
|
|
||||||
return NextResponse.json(users);
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error fetching users:", error);
|
|
||||||
return NextResponse.json(
|
|
||||||
{ error: "Erreur lors de la récupération des utilisateurs" },
|
|
||||||
{ status: 500 }
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -90,10 +90,6 @@ export class AdminClient extends BaseHttpClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// User Management
|
// User Management
|
||||||
async getUsers(): Promise<User[]> {
|
|
||||||
return await this.get<User[]>(`/admin/users`);
|
|
||||||
}
|
|
||||||
|
|
||||||
async createUser(userData: UserFormData): Promise<User> {
|
async createUser(userData: UserFormData): Promise<User> {
|
||||||
return await this.post<User>(`/admin/users`, userData);
|
return await this.post<User>(`/admin/users`, userData);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,13 +14,11 @@ import { SkillsList } from "./skills-list";
|
|||||||
|
|
||||||
interface SkillsManagementPageProps {
|
interface SkillsManagementPageProps {
|
||||||
skillCategories: SkillCategory[];
|
skillCategories: SkillCategory[];
|
||||||
teams: Team[];
|
|
||||||
initialSkills: any[];
|
initialSkills: any[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function SkillsManagementPage({
|
export function SkillsManagementPage({
|
||||||
skillCategories,
|
skillCategories,
|
||||||
teams,
|
|
||||||
initialSkills,
|
initialSkills,
|
||||||
}: SkillsManagementPageProps) {
|
}: SkillsManagementPageProps) {
|
||||||
const [searchTerm, setSearchTerm] = useState("");
|
const [searchTerm, setSearchTerm] = useState("");
|
||||||
|
|||||||
@@ -16,13 +16,11 @@ import { TeamMembersModal } from "../management/team-members-modal";
|
|||||||
interface TeamsManagementPageProps {
|
interface TeamsManagementPageProps {
|
||||||
teams: TeamType[];
|
teams: TeamType[];
|
||||||
teamStats: TeamStats[];
|
teamStats: TeamStats[];
|
||||||
skillCategories: SkillCategory[];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function TeamsManagementPage({
|
export function TeamsManagementPage({
|
||||||
teams,
|
teams,
|
||||||
teamStats,
|
teamStats,
|
||||||
skillCategories,
|
|
||||||
}: TeamsManagementPageProps) {
|
}: TeamsManagementPageProps) {
|
||||||
const [searchTerm, setSearchTerm] = useState("");
|
const [searchTerm, setSearchTerm] = useState("");
|
||||||
const [isMembersModalOpen, setIsMembersModalOpen] = useState(false);
|
const [isMembersModalOpen, setIsMembersModalOpen] = useState(false);
|
||||||
|
|||||||
@@ -13,9 +13,13 @@ import { UsersList } from "./users-list";
|
|||||||
|
|
||||||
interface UsersManagementPageProps {
|
interface UsersManagementPageProps {
|
||||||
teams: Team[];
|
teams: Team[];
|
||||||
|
initialUsers: any[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function UsersManagementPage({ teams }: UsersManagementPageProps) {
|
export function UsersManagementPage({
|
||||||
|
teams,
|
||||||
|
initialUsers,
|
||||||
|
}: UsersManagementPageProps) {
|
||||||
const [searchTerm, setSearchTerm] = useState("");
|
const [searchTerm, setSearchTerm] = useState("");
|
||||||
|
|
||||||
const { isCreateDialogOpen, openCreateDialog, closeCreateDialog } =
|
const { isCreateDialogOpen, openCreateDialog, closeCreateDialog } =
|
||||||
@@ -31,7 +35,7 @@ export function UsersManagementPage({ teams }: UsersManagementPageProps) {
|
|||||||
resetForm,
|
resetForm,
|
||||||
handleCreateUser,
|
handleCreateUser,
|
||||||
handleDeleteUser,
|
handleDeleteUser,
|
||||||
} = useUsersManagement(teams);
|
} = useUsersManagement(teams, initialUsers);
|
||||||
|
|
||||||
// Utilisation du hook factorisé pour la vue arborescente
|
// Utilisation du hook factorisé pour la vue arborescente
|
||||||
const {
|
const {
|
||||||
|
|||||||
@@ -27,36 +27,12 @@ export function useSkillsManagement(
|
|||||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
|
|
||||||
// Charger les skills depuis l'API si pas de skills initiales
|
|
||||||
useEffect(() => {
|
|
||||||
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: "" });
|
||||||
setEditingSkill(null);
|
setEditingSkill(null);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCreateSkill = async () => {
|
const handleCreateSkill = async () => {
|
||||||
console.log("skillFormData", skillFormData);
|
|
||||||
if (!skillFormData.name || !skillFormData.categoryId) {
|
if (!skillFormData.name || !skillFormData.categoryId) {
|
||||||
toast({
|
toast({
|
||||||
title: "Erreur",
|
title: "Erreur",
|
||||||
|
|||||||
@@ -23,27 +23,6 @@ export function useTeamsManagement(
|
|||||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
|
|
||||||
// Charger les teams depuis l'API
|
|
||||||
const fetchTeams = async () => {
|
|
||||||
try {
|
|
||||||
const teamsData = await adminClient.getTeams();
|
|
||||||
// Note: on garde les teams existantes pour la compatibilité
|
|
||||||
// Les nouvelles teams créées via l'API seront visibles après rafraîchissement
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error fetching teams:", error);
|
|
||||||
toast({
|
|
||||||
title: "Erreur",
|
|
||||||
description: "Impossible de charger les teams",
|
|
||||||
variant: "destructive",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Charger les teams au montage du composant
|
|
||||||
useEffect(() => {
|
|
||||||
fetchTeams();
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const resetForm = () => {
|
const resetForm = () => {
|
||||||
setTeamFormData({ name: "", direction: "" });
|
setTeamFormData({ name: "", direction: "" });
|
||||||
setEditingTeam(null);
|
setEditingTeam(null);
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ import { Team } from "@/lib/types";
|
|||||||
import { adminClient } from "@/clients";
|
import { adminClient } from "@/clients";
|
||||||
import { User, UserFormData } from "@/clients/domains/admin-client";
|
import { User, UserFormData } from "@/clients/domains/admin-client";
|
||||||
|
|
||||||
export function useUsersManagement(teams: Team[]) {
|
export function useUsersManagement(teams: Team[], initialUsers?: any[]) {
|
||||||
const [users, setUsers] = useState<User[]>([]);
|
const [users, setUsers] = useState<User[]>(initialUsers || []);
|
||||||
const [isLoading, setIsLoading] = useState(true);
|
const [isLoading, setIsLoading] = useState(!initialUsers);
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
const [deletingUserId, setDeletingUserId] = useState<string | null>(null);
|
const [deletingUserId, setDeletingUserId] = useState<string | null>(null);
|
||||||
const [userFormData, setUserFormData] = useState<UserFormData>({
|
const [userFormData, setUserFormData] = useState<UserFormData>({
|
||||||
@@ -17,25 +17,6 @@ export function useUsersManagement(teams: Team[]) {
|
|||||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
|
|
||||||
// Charger les utilisateurs depuis l'API
|
|
||||||
const fetchUsers = async () => {
|
|
||||||
setIsLoading(true);
|
|
||||||
setError(null);
|
|
||||||
try {
|
|
||||||
const usersData = await adminClient.getUsers();
|
|
||||||
setUsers(usersData);
|
|
||||||
} catch (err: any) {
|
|
||||||
setError(err.message || "Erreur lors du chargement des utilisateurs");
|
|
||||||
} finally {
|
|
||||||
setIsLoading(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Charger les utilisateurs au montage du composant
|
|
||||||
useEffect(() => {
|
|
||||||
fetchUsers();
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const resetForm = () => {
|
const resetForm = () => {
|
||||||
setUserFormData({ firstName: "", lastName: "", teamId: "" });
|
setUserFormData({ firstName: "", lastName: "", teamId: "" });
|
||||||
};
|
};
|
||||||
@@ -52,15 +33,15 @@ export function useUsersManagement(teams: Team[]) {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
setIsSubmitting(true);
|
setIsSubmitting(true);
|
||||||
await adminClient.createUser(userFormData);
|
const newUser = await adminClient.createUser(userFormData);
|
||||||
toast({
|
toast({
|
||||||
title: "Succès",
|
title: "Succès",
|
||||||
description: "Utilisateur créé avec succès",
|
description: "Utilisateur créé avec succès",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Ajouter le nouvel utilisateur à la liste locale
|
||||||
|
setUsers([...users, newUser]);
|
||||||
resetForm();
|
resetForm();
|
||||||
// Rafraîchir la liste
|
|
||||||
await fetchUsers();
|
|
||||||
return true;
|
return true;
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
toast({
|
toast({
|
||||||
@@ -128,6 +109,5 @@ export function useUsersManagement(teams: Team[]) {
|
|||||||
resetForm,
|
resetForm,
|
||||||
handleCreateUser,
|
handleCreateUser,
|
||||||
handleDeleteUser,
|
handleDeleteUser,
|
||||||
fetchUsers,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -191,36 +191,132 @@ export class AdminService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Récupère toutes les données nécessaires pour l'admin
|
* Récupère les données nécessaires pour la page de gestion des skills
|
||||||
*/
|
*/
|
||||||
static async getAdminData(): Promise<{
|
static async getSkillsPageData(): Promise<{
|
||||||
teams: Team[];
|
|
||||||
skillCategories: SkillCategory[];
|
skillCategories: SkillCategory[];
|
||||||
teamStats: TeamStats[];
|
|
||||||
directionStats: DirectionStats[];
|
|
||||||
skills: any[];
|
skills: any[];
|
||||||
}> {
|
}> {
|
||||||
const pool = getPool();
|
const pool = getPool();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Récupérer toutes les données en parallèle
|
const [categoriesResult, skills] = await Promise.all([
|
||||||
const [teamsResult, categoriesResult, teamStats, skills] =
|
pool.query("SELECT id, name, icon FROM skill_categories ORDER BY name"),
|
||||||
await Promise.all([
|
SkillsService.getAllSkillsWithUsage(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
const skillCategories = categoriesResult.rows.map((row) => ({
|
||||||
|
...row,
|
||||||
|
category: row.name,
|
||||||
|
skills: [],
|
||||||
|
}));
|
||||||
|
|
||||||
|
return {
|
||||||
|
skillCategories,
|
||||||
|
skills,
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error fetching skills page data:", error);
|
||||||
|
throw new Error("Failed to fetch skills page data");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Récupère les données nécessaires pour la page de gestion des utilisateurs
|
||||||
|
*/
|
||||||
|
static async getUsersPageData(): Promise<{
|
||||||
|
teams: Team[];
|
||||||
|
users: any[];
|
||||||
|
}> {
|
||||||
|
const pool = getPool();
|
||||||
|
|
||||||
|
try {
|
||||||
|
const [teamsResult, usersResult] = await Promise.all([
|
||||||
pool.query(
|
pool.query(
|
||||||
"SELECT id, name, direction FROM teams ORDER BY direction, name"
|
"SELECT id, name, direction FROM teams ORDER BY direction, name"
|
||||||
),
|
),
|
||||||
|
pool.query(`
|
||||||
|
SELECT
|
||||||
|
u.uuid_id as uuid,
|
||||||
|
u.first_name as "firstName",
|
||||||
|
u.last_name as "lastName",
|
||||||
|
t.name as "teamName",
|
||||||
|
EXISTS (
|
||||||
|
SELECT 1 FROM user_evaluations ue
|
||||||
|
WHERE ue.user_uuid = u.uuid_id
|
||||||
|
) as "hasEvaluations"
|
||||||
|
FROM users u
|
||||||
|
LEFT JOIN teams t ON u.team_id = t.id
|
||||||
|
ORDER BY u.first_name, u.last_name
|
||||||
|
`),
|
||||||
|
]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
teams: teamsResult.rows,
|
||||||
|
users: usersResult.rows,
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error fetching users page data:", error);
|
||||||
|
throw new Error("Failed to fetch users page data");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Récupère les données nécessaires pour la page de gestion des équipes
|
||||||
|
*/
|
||||||
|
static async getTeamsPageData(): Promise<{
|
||||||
|
teams: Team[];
|
||||||
|
teamStats: TeamStats[];
|
||||||
|
directionStats: DirectionStats[];
|
||||||
|
}> {
|
||||||
|
const pool = getPool();
|
||||||
|
|
||||||
|
try {
|
||||||
|
const [teamsResult, teamStats] = await Promise.all([
|
||||||
pool.query(
|
pool.query(
|
||||||
"SELECT id, name, icon FROM skill_categories ORDER BY name"
|
"SELECT id, name, direction FROM teams ORDER BY direction, name"
|
||||||
),
|
),
|
||||||
AdminService.getTeamsStats(),
|
AdminService.getTeamsStats(),
|
||||||
SkillsService.getAllSkillsWithUsage(),
|
]);
|
||||||
|
|
||||||
|
const directionStats = AdminService.generateDirectionStats(teamStats);
|
||||||
|
|
||||||
|
return {
|
||||||
|
teams: teamsResult.rows,
|
||||||
|
teamStats,
|
||||||
|
directionStats,
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error fetching teams page data:", error);
|
||||||
|
throw new Error("Failed to fetch teams page data");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Récupère les données nécessaires pour la page d'accueil admin
|
||||||
|
*/
|
||||||
|
static async getOverviewPageData(): Promise<{
|
||||||
|
teams: Team[];
|
||||||
|
skillCategories: SkillCategory[];
|
||||||
|
teamStats: TeamStats[];
|
||||||
|
directionStats: DirectionStats[];
|
||||||
|
}> {
|
||||||
|
const pool = getPool();
|
||||||
|
|
||||||
|
try {
|
||||||
|
const [teamsResult, categoriesResult, teamStats] = await Promise.all([
|
||||||
|
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(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const teams = teamsResult.rows;
|
const teams = teamsResult.rows;
|
||||||
const skillCategories = categoriesResult.rows.map((row) => ({
|
const skillCategories = categoriesResult.rows.map((row) => ({
|
||||||
...row,
|
...row,
|
||||||
category: row.name, // Adapter le format
|
category: row.name,
|
||||||
skills: [], // Les skills individuelles ne sont pas nécessaires pour l'admin
|
skills: [],
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const directionStats = AdminService.generateDirectionStats(teamStats);
|
const directionStats = AdminService.generateDirectionStats(teamStats);
|
||||||
@@ -230,11 +326,10 @@ 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 overview page data:", error);
|
||||||
throw new Error("Failed to fetch admin data");
|
throw new Error("Failed to fetch overview page data");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user