314 lines
13 KiB
TypeScript
314 lines
13 KiB
TypeScript
'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; |