Files
btpxpress-frontend/components/dashboard/ChantiersList.tsx

158 lines
4.1 KiB
TypeScript
Executable File

/**
* Composant liste des chantiers récents
*/
import React from 'react';
import { Card } from 'primereact/card';
import { DataTable } from 'primereact/datatable';
import { Column } from 'primereact/column';
import { Badge } from 'primereact/badge';
import { Button } from 'primereact/button';
import { Skeleton } from 'primereact/skeleton';
import { ChantierRecent, StatutChantier } from '../../types/btp';
interface ChantiersListProps {
chantiers: ChantierRecent[];
loading?: boolean;
onViewAll?: () => void;
}
const ChantiersList: React.FC<ChantiersListProps> = ({
chantiers,
loading = false,
onViewAll
}) => {
const getStatutSeverity = (statut: StatutChantier) => {
switch (statut) {
case StatutChantier.EN_COURS:
return 'info';
case StatutChantier.PLANIFIE:
return 'warning';
case StatutChantier.TERMINE:
return 'success';
case StatutChantier.ANNULE:
return 'danger';
case StatutChantier.SUSPENDU:
return 'secondary';
default:
return 'info';
}
};
const getStatutLabel = (statut: StatutChantier) => {
switch (statut) {
case StatutChantier.EN_COURS:
return 'En cours';
case StatutChantier.PLANIFIE:
return 'Planifié';
case StatutChantier.TERMINE:
return 'Terminé';
case StatutChantier.ANNULE:
return 'Annulé';
case StatutChantier.SUSPENDU:
return 'Suspendu';
default:
return statut;
}
};
const statutBodyTemplate = (rowData: ChantierRecent) => {
return (
<Badge
value={getStatutLabel(rowData.statut)}
severity={getStatutSeverity(rowData.statut)}
/>
);
};
const montantBodyTemplate = (rowData: ChantierRecent) => {
return rowData.montantPrevu
? `${rowData.montantPrevu.toLocaleString()}`
: '-';
};
const dateBodyTemplate = (rowData: ChantierRecent) => {
return new Date(rowData.dateDebut).toLocaleDateString('fr-FR');
};
const header = (
<div className="flex align-items-center justify-content-between">
<h5 className="m-0">Chantiers récents</h5>
{onViewAll && (
<Button
label="Voir tout"
icon="pi pi-external-link"
className="p-button-text p-button-sm"
onClick={onViewAll}
/>
)}
</div>
);
if (loading) {
return (
<Card>
<div className="flex align-items-center justify-content-between mb-3">
<Skeleton width="8rem" height="1.5rem" />
<Skeleton width="5rem" height="2rem" />
</div>
<div className="space-y-3">
{[...Array(5)].map((_, i) => (
<div key={i} className="flex align-items-center justify-content-between p-3 border-1 border-200 border-round">
<div className="flex-1">
<Skeleton width="60%" height="1rem" className="mb-2" />
<Skeleton width="40%" height="0.8rem" />
</div>
<Skeleton width="5rem" height="1.5rem" />
</div>
))}
</div>
</Card>
);
}
return (
<Card>
<DataTable
value={chantiers}
header={header}
responsiveLayout="scroll"
showHeaders={false}
emptyMessage="Aucun chantier récent"
className="p-datatable-sm"
>
<Column
field="nom"
header="Nom"
style={{ width: '35%' }}
body={(rowData: ChantierRecent) => (
<div>
<div className="font-medium text-900">{rowData.nom}</div>
<div className="text-500 text-sm">{rowData.client}</div>
</div>
)}
/>
<Column
field="statut"
header="Statut"
style={{ width: '25%' }}
body={statutBodyTemplate}
/>
<Column
field="dateDebut"
header="Date"
style={{ width: '20%' }}
body={dateBodyTemplate}
/>
<Column
field="montantPrevu"
header="Montant"
style={{ width: '20%' }}
body={montantBodyTemplate}
/>
</DataTable>
</Card>
);
};
export default ChantiersList;