feat: Pages de détails complètes pour chantiers, clients et matériels
PHASE 2 - FINALISATIONS FONCTIONNELLES TERMINÉES ✅ Pages Chantiers [id] créées: - /chantiers/[id]: Vue d'ensemble avec statistiques et navigation - /chantiers/[id]/budget: Suivi budgétaire détaillé avec graphiques - /chantiers/[id]/planning: Chronologie et planning des tâches - /chantiers/[id]/documents: Gestion des documents du chantier - /chantiers/[id]/equipe: Liste et gestion de l'équipe affectée ✅ Pages Clients [id] créées: - /clients/[id]: Fiche client complète avec coordonnées - Onglets: Chantiers, Factures, Documents - Statistiques et historique complet ✅ Pages Matériels [id] créées: - /materiels/[id]: Fiche matériel avec informations techniques - Calendrier de disponibilité - Onglets: Réservations, Maintenances, Documents - Timeline des maintenances Fonctionnalités implémentées: - Navigation fluide entre les pages - Boutons retour vers listes principales - DataTables avec tri et filtres - Graphiques budget (bar chart, doughnut) - Calendriers et timeline - Tags de statut colorés - Cards statistiques - Responsive design Technologies utilisées: - PrimeReact (DataTable, Chart, Calendar, Timeline, TabView) - Next.js App Router avec dynamic routes [id] - TypeScript avec interfaces typées - Integration API backend via fetch Prochaines étapes: - Connecter aux vraies APIs backend - Ajouter formulaires de modification - Implémenter actions (supprimer, modifier) - Ajouter toasts de confirmation 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
197
app/(main)/chantiers/[id]/equipe/page.tsx
Normal file
197
app/(main)/chantiers/[id]/equipe/page.tsx
Normal file
@@ -0,0 +1,197 @@
|
||||
'use client';
|
||||
|
||||
import React, { useState } from 'react';
|
||||
import { useParams, useRouter } from 'next/navigation';
|
||||
import { Card } from 'primereact/card';
|
||||
import { Button } from 'primereact/button';
|
||||
import { DataTable } from 'primereact/datatable';
|
||||
import { Column } from 'primereact/column';
|
||||
import { Avatar } from 'primereact/avatar';
|
||||
import { Tag } from 'primereact/tag';
|
||||
import { Badge } from 'primereact/badge';
|
||||
|
||||
interface MembreEquipe {
|
||||
id: number;
|
||||
nom: string;
|
||||
prenom: string;
|
||||
role: string;
|
||||
specialite: string;
|
||||
email: string;
|
||||
telephone: string;
|
||||
dateAffectation: string;
|
||||
statut: string;
|
||||
}
|
||||
|
||||
export default function ChantierEquipePage() {
|
||||
const params = useParams();
|
||||
const router = useRouter();
|
||||
const id = params.id as string;
|
||||
|
||||
const [membres] = useState<MembreEquipe[]>([
|
||||
{
|
||||
id: 1,
|
||||
nom: 'Dupont',
|
||||
prenom: 'Jean',
|
||||
role: 'Chef de chantier',
|
||||
specialite: 'Gestion',
|
||||
email: 'jean.dupont@btpxpress.fr',
|
||||
telephone: '06 12 34 56 78',
|
||||
dateAffectation: '2025-01-01',
|
||||
statut: 'Actif'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
nom: 'Martin',
|
||||
prenom: 'Marie',
|
||||
role: 'Maçon',
|
||||
specialite: 'Maçonnerie',
|
||||
email: 'marie.martin@btpxpress.fr',
|
||||
telephone: '06 23 45 67 89',
|
||||
dateAffectation: '2025-01-05',
|
||||
statut: 'Actif'
|
||||
}
|
||||
]);
|
||||
|
||||
const nomBodyTemplate = (rowData: MembreEquipe) => {
|
||||
return (
|
||||
<div className="flex align-items-center gap-2">
|
||||
<Avatar
|
||||
label={`${rowData.prenom[0]}${rowData.nom[0]}`}
|
||||
size="large"
|
||||
shape="circle"
|
||||
className="mr-2"
|
||||
/>
|
||||
<div>
|
||||
<div className="font-bold">{rowData.prenom} {rowData.nom}</div>
|
||||
<div className="text-sm text-600">{rowData.role}</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const specialiteBodyTemplate = (rowData: MembreEquipe) => {
|
||||
return <Tag value={rowData.specialite} severity="info" />;
|
||||
};
|
||||
|
||||
const statutBodyTemplate = (rowData: MembreEquipe) => {
|
||||
const severity = rowData.statut === 'Actif' ? 'success' : 'danger';
|
||||
return <Tag value={rowData.statut} severity={severity} />;
|
||||
};
|
||||
|
||||
const actionsBodyTemplate = () => {
|
||||
return (
|
||||
<div className="flex gap-2">
|
||||
<Button icon="pi pi-eye" className="p-button-text p-button-sm" tooltip="Voir le profil" />
|
||||
<Button icon="pi pi-pencil" className="p-button-text p-button-sm" tooltip="Modifier" />
|
||||
<Button icon="pi pi-times" className="p-button-text p-button-sm p-button-danger" tooltip="Retirer du chantier" />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="grid">
|
||||
<div className="col-12">
|
||||
<div className="flex justify-content-between align-items-center mb-3">
|
||||
<div className="flex align-items-center">
|
||||
<Button
|
||||
icon="pi pi-arrow-left"
|
||||
className="p-button-text mr-2"
|
||||
onClick={() => router.push(`/chantiers/${id}`)}
|
||||
tooltip="Retour"
|
||||
/>
|
||||
<h2 className="m-0">Équipe du chantier</h2>
|
||||
<Badge value={membres.length} severity="info" className="ml-2" />
|
||||
</div>
|
||||
<Button
|
||||
label="Affecter un membre"
|
||||
icon="pi pi-plus"
|
||||
className="p-button-success"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Statistiques équipe */}
|
||||
<div className="col-12 md:col-3">
|
||||
<Card>
|
||||
<div className="flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<span className="block text-500 font-medium mb-1">Total membres</span>
|
||||
<div className="text-900 font-medium text-xl">{membres.length}</div>
|
||||
</div>
|
||||
<div className="flex align-items-center justify-content-center bg-blue-100 border-round" style={{width: '2.5rem', height: '2.5rem'}}>
|
||||
<i className="pi pi-users text-blue-500 text-xl"></i>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
<div className="col-12 md:col-3">
|
||||
<Card>
|
||||
<div className="flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<span className="block text-500 font-medium mb-1">Membres actifs</span>
|
||||
<div className="text-900 font-medium text-xl">
|
||||
{membres.filter(m => m.statut === 'Actif').length}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex align-items-center justify-content-center bg-green-100 border-round" style={{width: '2.5rem', height: '2.5rem'}}>
|
||||
<i className="pi pi-check-circle text-green-500 text-xl"></i>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
<div className="col-12 md:col-3">
|
||||
<Card>
|
||||
<div className="flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<span className="block text-500 font-medium mb-1">Spécialités</span>
|
||||
<div className="text-900 font-medium text-xl">
|
||||
{new Set(membres.map(m => m.specialite)).size}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex align-items-center justify-content-center bg-orange-100 border-round" style={{width: '2.5rem', height: '2.5rem'}}>
|
||||
<i className="pi pi-star text-orange-500 text-xl"></i>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
<div className="col-12 md:col-3">
|
||||
<Card>
|
||||
<div className="flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<span className="block text-500 font-medium mb-1">Chef de chantier</span>
|
||||
<div className="text-900 font-medium text-xl">
|
||||
{membres.filter(m => m.role === 'Chef de chantier').length}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex align-items-center justify-content-center bg-purple-100 border-round" style={{width: '2.5rem', height: '2.5rem'}}>
|
||||
<i className="pi pi-user text-purple-500 text-xl"></i>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
{/* Liste des membres */}
|
||||
<div className="col-12">
|
||||
<Card title="Liste des membres">
|
||||
<DataTable
|
||||
value={membres}
|
||||
paginator
|
||||
rows={10}
|
||||
responsiveLayout="scroll"
|
||||
>
|
||||
<Column body={nomBodyTemplate} header="Nom" sortable filter />
|
||||
<Column body={specialiteBodyTemplate} header="Spécialité" sortable filter />
|
||||
<Column field="email" header="Email" sortable />
|
||||
<Column field="telephone" header="Téléphone" sortable />
|
||||
<Column field="dateAffectation" header="Date d'affectation" sortable />
|
||||
<Column body={statutBodyTemplate} header="Statut" sortable filter />
|
||||
<Column body={actionsBodyTemplate} header="Actions" />
|
||||
</DataTable>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user