269 lines
12 KiB
TypeScript
269 lines
12 KiB
TypeScript
'use client';
|
|
|
|
import React, { useState, useContext } from 'react';
|
|
import { Panel } from 'primereact/panel';
|
|
import { Button } from 'primereact/button';
|
|
import { Toast } from 'primereact/toast';
|
|
import { useRef } from 'react';
|
|
import { LayoutContext } from '../../../../../layout/context/layoutcontext';
|
|
import AtlantisResponsivePhasesTable from '../../../../../components/phases/AtlantisResponsivePhasesTable';
|
|
import AtlantisAccessibilityControls from '../../../../../components/phases/AtlantisAccessibilityControls';
|
|
import PhasesQuickPreview from '../../../../../components/phases/PhasesQuickPreview';
|
|
import PhaseValidationPanel from '../../../../../components/phases/PhaseValidationPanel';
|
|
import { Dialog } from 'primereact/dialog';
|
|
import testDataService from '../../../../../services/testDataService';
|
|
import type { PhaseChantier } from '../../../../../types/btp';
|
|
|
|
const ResponsivePhasesPage: React.FC = () => {
|
|
const [phases, setPhases] = useState<PhaseChantier[]>([]);
|
|
const [selectedPhase, setSelectedPhase] = useState<PhaseChantier | null>(null);
|
|
const [validationDialogVisible, setValidationDialogVisible] = useState(false);
|
|
const [loading, setLoading] = useState(false);
|
|
const { isDesktop } = useContext(LayoutContext);
|
|
const toast = useRef<Toast>(null);
|
|
|
|
// Générer des données de test au chargement
|
|
React.useEffect(() => {
|
|
const client = testDataService.generateTestClient(1);
|
|
const chantier = testDataService.generateTestChantier(1, 'MAISON_INDIVIDUELLE', client);
|
|
const generatedPhases = testDataService.generatePhasesWithPrerequisites(chantier);
|
|
setPhases(generatedPhases);
|
|
}, []);
|
|
|
|
const handlePhaseSelect = (phase: PhaseChantier) => {
|
|
setSelectedPhase(phase);
|
|
|
|
toast.current?.show({
|
|
severity: 'info',
|
|
summary: 'Phase sélectionnée',
|
|
detail: `${phase.nom} - ${phase.statut}`,
|
|
life: 3000
|
|
});
|
|
};
|
|
|
|
const handlePhaseStart = (phaseId: string) => {
|
|
setPhases(prev => prev.map(p =>
|
|
p.id === phaseId
|
|
? { ...p, statut: 'EN_COURS' as const, dateDebutReelle: new Date().toISOString().split('T')[0] }
|
|
: p
|
|
));
|
|
|
|
toast.current?.show({
|
|
severity: 'success',
|
|
summary: 'Phase démarrée',
|
|
detail: 'La phase a été mise en cours',
|
|
life: 3000
|
|
});
|
|
};
|
|
|
|
const handlePhaseValidation = (phase: PhaseChantier) => {
|
|
setSelectedPhase(phase);
|
|
setValidationDialogVisible(true);
|
|
};
|
|
|
|
const headerTemplate = (
|
|
<div className="flex align-items-center justify-content-between">
|
|
<div className="flex align-items-center gap-3">
|
|
<i className="pi pi-building text-2xl text-primary" />
|
|
<div>
|
|
<h2 className="m-0 text-color">Gestion des phases - Vue responsive</h2>
|
|
<p className="m-0 text-color-secondary text-sm">
|
|
Interface adaptative utilisant le template Atlantis React
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
{isDesktop() && (
|
|
<div className="flex align-items-center gap-2">
|
|
<Button
|
|
label="Actualiser"
|
|
icon="pi pi-refresh"
|
|
className="p-button-outlined"
|
|
onClick={() => window.location.reload()}
|
|
/>
|
|
<Button
|
|
label="Paramètres"
|
|
icon="pi pi-cog"
|
|
className="p-button-text"
|
|
/>
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
|
|
return (
|
|
<div className="grid">
|
|
<Toast ref={toast} />
|
|
|
|
{/* En-tête de page avec style Atlantis */}
|
|
<div className="col-12">
|
|
<div className="card">
|
|
{headerTemplate}
|
|
</div>
|
|
</div>
|
|
|
|
{/* Contrôles d'accessibilité */}
|
|
<div className="col-12">
|
|
<AtlantisAccessibilityControls />
|
|
</div>
|
|
|
|
{/* Vue d'ensemble rapide */}
|
|
{phases.length > 0 && (
|
|
<div className="col-12 lg:col-4">
|
|
<PhasesQuickPreview
|
|
phases={phases}
|
|
className="h-full"
|
|
/>
|
|
</div>
|
|
)}
|
|
|
|
{/* Tableau principal responsive */}
|
|
<div className={`col-12 ${phases.length > 0 ? 'lg:col-8' : ''}`}>
|
|
<AtlantisResponsivePhasesTable
|
|
phases={phases}
|
|
onPhaseSelect={handlePhaseSelect}
|
|
onPhaseStart={handlePhaseStart}
|
|
onPhaseValidate={handlePhaseValidation}
|
|
/>
|
|
</div>
|
|
|
|
{/* Informations complémentaires sur mobile */}
|
|
{!isDesktop() && selectedPhase && (
|
|
<div className="col-12">
|
|
<div className="card">
|
|
<h6 className="mt-0 mb-3 text-color">Phase sélectionnée</h6>
|
|
<div className="grid">
|
|
<div className="col-12 sm:col-6">
|
|
<div className="field">
|
|
<label className="font-semibold text-color-secondary">Nom</label>
|
|
<p className="m-0 text-color">{selectedPhase.nom}</p>
|
|
</div>
|
|
</div>
|
|
<div className="col-12 sm:col-6">
|
|
<div className="field">
|
|
<label className="font-semibold text-color-secondary">Statut</label>
|
|
<p className="m-0 text-color">{selectedPhase.statut}</p>
|
|
</div>
|
|
</div>
|
|
<div className="col-12 sm:col-6">
|
|
<div className="field">
|
|
<label className="font-semibold text-color-secondary">Avancement</label>
|
|
<p className="m-0 text-color">{selectedPhase.pourcentageAvancement || 0}%</p>
|
|
</div>
|
|
</div>
|
|
<div className="col-12 sm:col-6">
|
|
<div className="field">
|
|
<label className="font-semibold text-color-secondary">Date début prévue</label>
|
|
<p className="m-0 text-color">
|
|
{selectedPhase.dateDebutPrevue ?
|
|
new Date(selectedPhase.dateDebutPrevue).toLocaleDateString('fr-FR') :
|
|
'-'
|
|
}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
{selectedPhase.description && (
|
|
<div className="col-12">
|
|
<div className="field">
|
|
<label className="font-semibold text-color-secondary">Description</label>
|
|
<p className="m-0 text-color-secondary">{selectedPhase.description}</p>
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{/* Actions rapides pour mobile */}
|
|
{!isDesktop() && (
|
|
<div className="col-12">
|
|
<div className="card">
|
|
<h6 className="mt-0 mb-3 text-color">Actions rapides</h6>
|
|
<div className="flex flex-wrap gap-2">
|
|
<Button
|
|
label="Nouvelle phase"
|
|
icon="pi pi-plus"
|
|
className="p-button-success flex-1 sm:flex-none"
|
|
/>
|
|
<Button
|
|
label="Filtrer"
|
|
icon="pi pi-filter"
|
|
className="p-button-outlined flex-1 sm:flex-none"
|
|
/>
|
|
<Button
|
|
label="Exporter"
|
|
icon="pi pi-download"
|
|
className="p-button-outlined flex-1 sm:flex-none"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{/* Statistiques rapides */}
|
|
<div className="col-12">
|
|
<div className="grid">
|
|
<div className="col-6 md:col-3">
|
|
<div className="card text-center">
|
|
<div className="text-2xl font-bold text-primary">
|
|
{phases.length}
|
|
</div>
|
|
<div className="text-color-secondary text-sm">Total phases</div>
|
|
</div>
|
|
</div>
|
|
<div className="col-6 md:col-3">
|
|
<div className="card text-center">
|
|
<div className="text-2xl font-bold text-green-500">
|
|
{phases.filter(p => p.statut === 'TERMINEE').length}
|
|
</div>
|
|
<div className="text-color-secondary text-sm">Terminées</div>
|
|
</div>
|
|
</div>
|
|
<div className="col-6 md:col-3">
|
|
<div className="card text-center">
|
|
<div className="text-2xl font-bold text-blue-500">
|
|
{phases.filter(p => p.statut === 'EN_COURS').length}
|
|
</div>
|
|
<div className="text-color-secondary text-sm">En cours</div>
|
|
</div>
|
|
</div>
|
|
<div className="col-6 md:col-3">
|
|
<div className="card text-center">
|
|
<div className="text-2xl font-bold text-orange-500">
|
|
{phases.filter(p => p.critique).length}
|
|
</div>
|
|
<div className="text-color-secondary text-sm">Critiques</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Dialog de validation */}
|
|
<Dialog
|
|
header="Validation des prérequis"
|
|
visible={validationDialogVisible}
|
|
onHide={() => setValidationDialogVisible(false)}
|
|
style={{ width: isDesktop() ? '800px' : '95vw' }}
|
|
modal
|
|
className="p-fluid"
|
|
>
|
|
{selectedPhase && (
|
|
<PhaseValidationPanel
|
|
phase={selectedPhase}
|
|
allPhases={phases}
|
|
onStartPhase={handlePhaseStart}
|
|
onViewPrerequisite={(prereqId) => {
|
|
const prereq = phases.find(p => p.id === prereqId);
|
|
if (prereq) {
|
|
setSelectedPhase(prereq);
|
|
}
|
|
}}
|
|
/>
|
|
)}
|
|
</Dialog>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default ResponsivePhasesPage; |