158 lines
4.1 KiB
TypeScript
158 lines
4.1 KiB
TypeScript
/**
|
|
* 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; |