Files
btpxpress-frontend/app/(main)/employes/[id]/page.tsx
2025-10-13 05:29:32 +02:00

365 lines
16 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

'use client';
import React, { useState, useEffect } from 'react';
import { Card } from 'primereact/card';
import { Button } from 'primereact/button';
import { Tag } from 'primereact/tag';
import { Toolbar } from 'primereact/toolbar';
import { TabView, TabPanel } from 'primereact/tabview';
import { DataTable } from 'primereact/datatable';
import { Column } from 'primereact/column';
import { Badge } from 'primereact/badge';
import { useRouter, useParams } from 'next/navigation';
import { apiClient } from '../../../../services/api-client';
interface EmployeDetail {
id: number;
nom: string;
prenom: string;
email: string;
telephone: string;
metier: string;
statut: string;
dateEmbauche: string;
salaire: number;
adresse: string;
numeroSecu: string;
niveauExperience: string;
competences: string[];
certifications: string[];
equipeId?: number;
equipeNom?: string;
chantierActuel?: string;
disponible: boolean;
planning: Array<{
id: number;
chantierNom: string;
dateDebut: string;
dateFin: string;
statut: string;
}>;
historique: Array<{
id: number;
chantierNom: string;
dateDebut: string;
dateFin: string;
role: string;
}>;
}
const EmployeDetailPage = () => {
const [employe, setEmploye] = useState<EmployeDetail | null>(null);
const [loading, setLoading] = useState(true);
const router = useRouter();
const params = useParams();
const employeId = params.id;
useEffect(() => {
if (employeId) {
loadEmployeDetail();
}
}, [employeId]);
const loadEmployeDetail = async () => {
try {
setLoading(true);
console.log('🔄 Chargement du détail employé...', employeId);
const response = await apiClient.get(`/api/employes/${employeId}`);
console.log('✅ Détail employé chargé:', response.data);
setEmploye(response.data);
} catch (error) {
console.error('❌ Erreur lors du chargement du détail:', error);
} finally {
setLoading(false);
}
};
const toggleStatutEmploye = async () => {
if (!employe) return;
try {
const newStatut = employe.statut === 'ACTIF' ? 'INACTIF' : 'ACTIF';
const endpoint = newStatut === 'ACTIF' ? 'activer' : 'desactiver';
await apiClient.post(`/api/employes/${employe.id}/${endpoint}`);
setEmploye({ ...employe, statut: newStatut });
console.log(`✅ Statut employé ${newStatut.toLowerCase()}`);
} catch (error) {
console.error('❌ Erreur lors du changement de statut:', error);
}
};
const getStatutSeverity = (statut: string) => {
switch (statut) {
case 'ACTIF': return 'success';
case 'INACTIF': return 'danger';
case 'CONGE': return 'warning';
case 'FORMATION': return 'info';
default: return 'secondary';
}
};
const getMetierColor = (metier: string) => {
const colors: { [key: string]: string } = {
'MACON': 'info',
'ELECTRICIEN': 'warning',
'PLOMBIER': 'primary',
'CHARPENTIER': 'success',
'PEINTRE': 'secondary',
'CHEF_EQUIPE': 'danger',
'CONDUCTEUR': 'help'
};
return colors[metier] || 'secondary';
};
const leftToolbarTemplate = () => {
return (
<div className="flex flex-wrap gap-2">
<Button
label="Retour"
icon="pi pi-arrow-left"
className="p-button-outlined"
onClick={() => router.push('/employes')}
/>
<Button
label="Modifier"
icon="pi pi-pencil"
className="p-button-success"
onClick={() => router.push(`/employes/${employeId}/edit`)}
/>
<Button
label={employe?.statut === 'ACTIF' ? 'Désactiver' : 'Activer'}
icon={employe?.statut === 'ACTIF' ? 'pi pi-pause' : 'pi pi-play'}
className={employe?.statut === 'ACTIF' ? 'p-button-warning' : 'p-button-success'}
onClick={toggleStatutEmploye}
/>
</div>
);
};
const rightToolbarTemplate = () => {
return (
<div className="flex gap-2">
<Button
label="Planning"
icon="pi pi-calendar"
className="p-button-info"
onClick={() => router.push(`/planning?employeId=${employeId}`)}
/>
<Button
icon="pi pi-refresh"
className="p-button-outlined"
onClick={loadEmployeDetail}
tooltip="Actualiser"
/>
</div>
);
};
if (loading) {
return (
<div className="grid">
<div className="col-12">
<Card>
<div className="flex justify-content-center">
<i className="pi pi-spin pi-spinner" style={{ fontSize: '2rem' }} />
</div>
</Card>
</div>
</div>
);
}
if (!employe) {
return (
<div className="grid">
<div className="col-12">
<Card>
<div className="text-center">
<p>Employé non trouvé</p>
</div>
</Card>
</div>
</div>
);
}
return (
<div className="grid">
<div className="col-12">
<Toolbar
className="mb-4"
left={leftToolbarTemplate}
right={rightToolbarTemplate}
/>
</div>
{/* En-tête employé */}
<div className="col-12">
<Card>
<div className="flex flex-column lg:flex-row lg:align-items-center gap-4">
<div className="flex align-items-center justify-content-center bg-blue-100 border-round" style={{ width: '4rem', height: '4rem' }}>
<i className="pi pi-user text-blue-500 text-2xl" />
</div>
<div className="flex-1">
<h2 className="m-0 mb-2">{employe.prenom} {employe.nom}</h2>
<div className="flex flex-wrap gap-2 mb-2">
<Tag value={employe.metier} severity={getMetierColor(employe.metier) as any} />
<Tag value={employe.statut} severity={getStatutSeverity(employe.statut) as any} />
<Tag value={employe.niveauExperience} severity="info" />
{employe.disponible ? (
<Tag value="Disponible" severity="success" icon="pi pi-check" />
) : (
<Tag value="Occupé" severity="warning" icon="pi pi-clock" />
)}
</div>
<div className="text-600">
<p className="m-0">📧 {employe.email}</p>
<p className="m-0">📞 {employe.telephone}</p>
{employe.equipeNom && <p className="m-0">👥 Équipe: {employe.equipeNom}</p>}
{employe.chantierActuel && <p className="m-0">🏗 Chantier actuel: {employe.chantierActuel}</p>}
</div>
</div>
</div>
</Card>
</div>
{/* Onglets de détail */}
<div className="col-12">
<Card>
<TabView>
<TabPanel header="Informations Générales">
<div className="grid">
<div className="col-12 md:col-6">
<h4>Informations Personnelles</h4>
<div className="field">
<label className="font-medium">Nom complet:</label>
<p>{employe.prenom} {employe.nom}</p>
</div>
<div className="field">
<label className="font-medium">Email:</label>
<p>{employe.email}</p>
</div>
<div className="field">
<label className="font-medium">Téléphone:</label>
<p>{employe.telephone}</p>
</div>
<div className="field">
<label className="font-medium">Adresse:</label>
<p>{employe.adresse || 'Non renseignée'}</p>
</div>
<div className="field">
<label className="font-medium">N° Sécurité Sociale:</label>
<p>{employe.numeroSecu || 'Non renseigné'}</p>
</div>
</div>
<div className="col-12 md:col-6">
<h4>Informations Professionnelles</h4>
<div className="field">
<label className="font-medium">Métier:</label>
<p><Tag value={employe.metier} severity={getMetierColor(employe.metier) as any} /></p>
</div>
<div className="field">
<label className="font-medium">Niveau d'expérience:</label>
<p><Tag value={employe.niveauExperience} severity="info" /></p>
</div>
<div className="field">
<label className="font-medium">Date d'embauche:</label>
<p>{new Date(employe.dateEmbauche).toLocaleDateString('fr-FR')}</p>
</div>
<div className="field">
<label className="font-medium">Salaire:</label>
<p>{employe.salaire ? `${employe.salaire.toLocaleString('fr-FR')}` : 'Non renseigné'}</p>
</div>
<div className="field">
<label className="font-medium">Statut:</label>
<p><Tag value={employe.statut} severity={getStatutSeverity(employe.statut) as any} /></p>
</div>
</div>
</div>
</TabPanel>
<TabPanel header="Compétences & Certifications">
<div className="grid">
<div className="col-12 md:col-6">
<h4>Compétences</h4>
{employe.competences && employe.competences.length > 0 ? (
<div className="flex flex-wrap gap-2">
{employe.competences.map((comp, index) => (
<Tag key={index} value={comp} severity="info" />
))}
</div>
) : (
<p className="text-500">Aucune compétence renseignée</p>
)}
</div>
<div className="col-12 md:col-6">
<h4>Certifications</h4>
{employe.certifications && employe.certifications.length > 0 ? (
<div className="flex flex-wrap gap-2">
{employe.certifications.map((cert, index) => (
<Tag key={index} value={cert} severity="success" />
))}
</div>
) : (
<p className="text-500">Aucune certification renseignée</p>
)}
</div>
</div>
</TabPanel>
<TabPanel header="Planning Actuel">
<DataTable
value={employe.planning || []}
emptyMessage="Aucun planning en cours"
responsiveLayout="scroll"
>
<Column field="chantierNom" header="Chantier" />
<Column
field="dateDebut"
header="Date début"
body={(rowData) => new Date(rowData.dateDebut).toLocaleDateString('fr-FR')}
/>
<Column
field="dateFin"
header="Date fin"
body={(rowData) => new Date(rowData.dateFin).toLocaleDateString('fr-FR')}
/>
<Column
field="statut"
header="Statut"
body={(rowData) => <Tag value={rowData.statut} severity="info" />}
/>
</DataTable>
</TabPanel>
<TabPanel header="Historique">
<DataTable
value={employe.historique || []}
emptyMessage="Aucun historique disponible"
responsiveLayout="scroll"
>
<Column field="chantierNom" header="Chantier" />
<Column
field="dateDebut"
header="Date début"
body={(rowData) => new Date(rowData.dateDebut).toLocaleDateString('fr-FR')}
/>
<Column
field="dateFin"
header="Date fin"
body={(rowData) => new Date(rowData.dateFin).toLocaleDateString('fr-FR')}
/>
<Column field="role" header="Rôle" />
</DataTable>
</TabPanel>
</TabView>
</Card>
</div>
</div>
);
};
export default EmployeDetailPage;