Initial commit

This commit is contained in:
dahoud
2025-10-01 01:39:07 +00:00
commit b430bf3b96
826 changed files with 255287 additions and 0 deletions

View File

@@ -0,0 +1,314 @@
'use client';
import React, { useState, useEffect, useRef } from 'react';
import { useRouter } from 'next/navigation';
import { Card } from 'primereact/card';
import { Button } from 'primereact/button';
import { InputNumber } from 'primereact/inputnumber';
import { Dropdown } from 'primereact/dropdown';
import { Calendar } from 'primereact/calendar';
import { InputTextarea } from 'primereact/inputtextarea';
import { Toast } from 'primereact/toast';
import { maintenanceService, materielService } from '../../../../services/api';
import { Materiel, TypeMaintenance, StatutMaintenance } from '../../../../types/btp';
const NouvelleMaintenancePage = () => {
const router = useRouter();
const [maintenance, setMaintenance] = useState({
materiel: null as Materiel | null,
type: TypeMaintenance.PREVENTIVE,
statut: StatutMaintenance.PLANIFIEE,
description: '',
datePrevue: new Date(),
dateRealisee: null as Date | null,
cout: 0,
notes: ''
});
const [materiels, setMateriels] = useState<Materiel[]>([]);
const [submitted, setSubmitted] = useState(false);
const [saving, setSaving] = useState(false);
const toast = useRef<Toast>(null);
const typeOptions = Object.values(TypeMaintenance).map(type => ({
label: type.replace('_', ' '),
value: type
}));
const statutOptions = Object.values(StatutMaintenance).map(statut => ({
label: statut.replace('_', ' '),
value: statut
}));
useEffect(() => {
loadMateriels();
}, []);
const loadMateriels = async () => {
try {
const data = await materielService.getAll();
setMateriels(data);
} catch (error) {
console.error('Erreur lors du chargement des matériels:', error);
}
};
const onInputChange = (e: React.ChangeEvent<HTMLTextAreaElement>, name: string) => {
const val = (e.target && e.target.value) || '';
setMaintenance(prev => ({ ...prev, [name]: val }));
};
const onInputNumberChange = (value: number | null, name: string) => {
setMaintenance(prev => ({ ...prev, [name]: value || 0 }));
};
const onDropdownChange = (e: any, name: string) => {
setMaintenance(prev => ({ ...prev, [name]: e.value }));
};
const onDateChange = (e: any, name: string) => {
setMaintenance(prev => ({ ...prev, [name]: e.value }));
};
const saveMaintenance = async () => {
setSubmitted(true);
if (maintenance.description?.trim() && maintenance.materiel) {
try {
setSaving(true);
const savedMaintenance = await maintenanceService.create(maintenance);
toast.current?.show({
severity: 'success',
summary: 'Succès',
detail: 'Maintenance créée avec succès',
life: 3000
});
// Rediriger vers la liste après 2 secondes
setTimeout(() => {
router.push('/maintenances');
}, 2000);
} catch (error: any) {
toast.current?.show({
severity: 'error',
summary: 'Erreur',
detail: error?.userMessage || 'Erreur lors de la création',
life: 3000
});
} finally {
setSaving(false);
}
}
};
const annuler = () => {
router.back();
};
const materielOptions = materiels.map(materiel => ({
label: `${materiel.nom} - ${materiel.marque} ${materiel.modele}`,
value: materiel
}));
// Templates prédéfinis selon le type
const onTypeChange = (newType: TypeMaintenance) => {
let description = '';
let cout = 0;
switch (newType) {
case TypeMaintenance.PREVENTIVE:
description = 'Maintenance préventive programmée selon planning';
cout = 100;
break;
case TypeMaintenance.CORRECTIVE:
description = 'Réparation suite à dysfonctionnement';
cout = 300;
break;
case TypeMaintenance.REVISION:
description = 'Révision complète du matériel';
cout = 200;
break;
case TypeMaintenance.CONTROLE_TECHNIQUE:
description = 'Contrôle technique réglementaire';
cout = 150;
break;
case TypeMaintenance.NETTOYAGE:
description = 'Nettoyage et entretien courant';
cout = 50;
break;
}
setMaintenance(prev => ({ ...prev, type: newType, description, cout }));
};
return (
<div className="grid">
<div className="col-12">
<Toast ref={toast} />
<div className="flex align-items-center justify-content-between mb-4">
<h2 className="m-0">Nouvelle Maintenance</h2>
<div className="flex gap-2">
<Button
label="Annuler"
icon="pi pi-times"
className="p-button-text p-button-rounded"
onClick={annuler}
/>
<Button
label="Sauvegarder"
icon="pi pi-check"
className="p-button-text p-button-rounded"
onClick={saveMaintenance}
loading={saving}
/>
</div>
</div>
<Card>
<div className="p-fluid formgrid grid">
<div className="field col-12 md:col-6">
<label htmlFor="materiel" className="font-bold">
Matériel <span className="text-red-500">*</span>
</label>
<Dropdown
id="materiel"
value={maintenance.materiel}
onChange={(e) => onDropdownChange(e, 'materiel')}
options={materielOptions}
placeholder="Sélectionner un matériel"
filter
className={submitted && !maintenance.materiel ? 'p-invalid' : ''}
/>
{submitted && !maintenance.materiel && <small className="p-error">Le matériel est obligatoire.</small>}
</div>
<div className="field col-12 md:col-6">
<label htmlFor="type" className="font-bold">Type</label>
<Dropdown
id="type"
value={maintenance.type}
onChange={(e) => onTypeChange(e.value)}
options={typeOptions}
placeholder="Sélectionner un type"
/>
</div>
<div className="field col-12 md:col-6">
<label htmlFor="statut" className="font-bold">Statut</label>
<Dropdown
id="statut"
value={maintenance.statut}
onChange={(e) => onDropdownChange(e, 'statut')}
options={statutOptions}
placeholder="Sélectionner un statut"
/>
</div>
<div className="field col-12 md:col-6">
<label htmlFor="datePrevue" className="font-bold">Date prévue</label>
<Calendar
id="datePrevue"
value={maintenance.datePrevue}
onChange={(e) => onDateChange(e, 'datePrevue')}
dateFormat="dd/mm/yy"
showIcon
showTime
hourFormat="24"
/>
</div>
<div className="field col-12 md:col-6">
<label htmlFor="dateRealisee" className="font-bold">Date de réalisation</label>
<Calendar
id="dateRealisee"
value={maintenance.dateRealisee}
onChange={(e) => onDateChange(e, 'dateRealisee')}
dateFormat="dd/mm/yy"
showIcon
showTime
hourFormat="24"
/>
</div>
<div className="field col-12 md:col-6">
<label htmlFor="cout" className="font-bold">Coût estimé</label>
<InputNumber
id="cout"
value={maintenance.cout}
onValueChange={(e) => onInputNumberChange(e.value, 'cout')}
mode="currency"
currency="EUR"
locale="fr-FR"
min={0}
/>
</div>
<div className="field col-12">
<label htmlFor="description" className="font-bold">
Description <span className="text-red-500">*</span>
</label>
<InputTextarea
id="description"
value={maintenance.description}
onChange={(e) => onInputChange(e, 'description')}
rows={3}
cols={20}
placeholder="Description détaillée de la maintenance..."
className={submitted && !maintenance.description ? 'p-invalid' : ''}
/>
{submitted && !maintenance.description && <small className="p-error">La description est obligatoire.</small>}
</div>
<div className="field col-12">
<label htmlFor="notes" className="font-bold">Notes</label>
<InputTextarea
id="notes"
value={maintenance.notes}
onChange={(e) => onInputChange(e, 'notes')}
rows={2}
cols={20}
placeholder="Notes et observations..."
/>
</div>
</div>
<div className="mt-4 p-3 surface-100 border-round">
<h5>Informations sur le matériel sélectionné</h5>
{maintenance.materiel ? (
<div className="grid">
<div className="col-12 md:col-6">
<strong>Nom:</strong> {maintenance.materiel.nom}
</div>
<div className="col-12 md:col-6">
<strong>Marque:</strong> {maintenance.materiel.marque}
</div>
<div className="col-12 md:col-6">
<strong>Modèle:</strong> {maintenance.materiel.modele}
</div>
<div className="col-12 md:col-6">
<strong>Statut:</strong> {maintenance.materiel.statut?.replace('_', ' ')}
</div>
<div className="col-12 md:col-6">
<strong>Localisation:</strong> {maintenance.materiel.localisation}
</div>
<div className="col-12 md:col-6">
<strong>Dernière maintenance:</strong>
{maintenance.materiel.maintenances?.length ?
new Date(maintenance.materiel.maintenances[0].dateRealisee || maintenance.materiel.maintenances[0].datePrevue).toLocaleDateString('fr-FR') :
'Aucune'
}
</div>
</div>
) : (
<p className="text-500">Sélectionnez un matériel pour voir ses informations</p>
)}
</div>
</Card>
</div>
</div>
);
};
export default NouvelleMaintenancePage;