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,294 @@
'use client';
import React, { useState, useRef } from 'react';
import { useRouter } from 'next/navigation';
import { Card } from 'primereact/card';
import { Button } from 'primereact/button';
import { InputText } from 'primereact/inputtext';
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 { materielService } from '../../../../services/api';
import { TypeMateriel, StatutMateriel } from '../../../../types/btp';
import { useApiCall } from '../../../../hooks/useApiCall';
const NouveauMaterielPage = () => {
const router = useRouter();
const [materiel, setMateriel] = useState({
nom: '',
marque: '',
modele: '',
numeroSerie: '',
type: '' as TypeMateriel,
description: '',
dateAchat: null as Date | null,
valeurAchat: 0,
valeurActuelle: 0,
statut: StatutMateriel.DISPONIBLE,
localisation: '',
proprietaire: '',
quantiteStock: 0,
seuilMinimum: 0,
unite: 'unité',
actif: true
});
const [submitted, setSubmitted] = useState(false);
// Utilisation du hook pour la création de matériel avec gestion d'erreurs automatique
const createMaterielCall = useApiCall(
(data: any) => materielService.create(data),
{
showSuccessToast: true,
successMessage: 'Matériel créé avec succès',
retryAttempts: 2,
retryDelay: 2000,
onSuccess: () => {
// Rediriger vers la liste après succès
setTimeout(() => {
router.push('/materiels');
}, 2000);
}
}
);
const typeOptions = Object.values(TypeMateriel).map(type => ({
label: type.replace('_', ' '),
value: type
}));
const statutOptions = Object.values(StatutMateriel).map(statut => ({
label: statut.replace('_', ' '),
value: statut
}));
const onInputChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>, name: string) => {
const val = (e.target && e.target.value) || '';
setMateriel(prev => ({ ...prev, [name]: val }));
};
const onInputNumberChange = (value: number | null, name: string) => {
setMateriel(prev => ({ ...prev, [name]: value || 0 }));
};
const onDropdownChange = (e: any, name: string) => {
setMateriel(prev => ({ ...prev, [name]: e.value }));
};
const onDateChange = (e: any, name: string) => {
setMateriel(prev => ({ ...prev, [name]: e.value }));
};
const saveMateriel = async () => {
setSubmitted(true);
if (materiel.nom?.trim() && materiel.type) {
await createMaterielCall.execute(materiel);
}
};
const annuler = () => {
router.back();
};
return (
<div className="grid">
<div className="col-12">
<Toast ref={createMaterielCall.toast} />
<div className="flex align-items-center justify-content-between mb-4">
<h2 className="m-0">Nouveau Matériel</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={saveMateriel}
loading={createMaterielCall.loading}
/>
</div>
</div>
<Card>
<div className="p-fluid formgrid grid">
<div className="field col-12 md:col-6">
<label htmlFor="nom" className="font-bold">
Nom <span className="text-red-500">*</span>
</label>
<InputText
id="nom"
value={materiel.nom}
onChange={(e) => onInputChange(e, 'nom')}
required
autoFocus
className={submitted && !materiel.nom ? 'p-invalid' : ''}
/>
{submitted && !materiel.nom && <small className="p-error">Le nom est obligatoire.</small>}
</div>
<div className="field col-12 md:col-6">
<label htmlFor="type" className="font-bold">
Type <span className="text-red-500">*</span>
</label>
<Dropdown
id="type"
value={materiel.type}
onChange={(e) => onDropdownChange(e, 'type')}
options={typeOptions}
placeholder="Sélectionner un type"
className={submitted && !materiel.type ? 'p-invalid' : ''}
/>
{submitted && !materiel.type && <small className="p-error">Le type est obligatoire.</small>}
</div>
<div className="field col-12 md:col-6">
<label htmlFor="marque" className="font-bold">Marque</label>
<InputText
id="marque"
value={materiel.marque}
onChange={(e) => onInputChange(e, 'marque')}
/>
</div>
<div className="field col-12 md:col-6">
<label htmlFor="modele" className="font-bold">Modèle</label>
<InputText
id="modele"
value={materiel.modele}
onChange={(e) => onInputChange(e, 'modele')}
/>
</div>
<div className="field col-12 md:col-6">
<label htmlFor="numeroSerie" className="font-bold">Numéro de série</label>
<InputText
id="numeroSerie"
value={materiel.numeroSerie}
onChange={(e) => onInputChange(e, 'numeroSerie')}
/>
</div>
<div className="field col-12 md:col-6">
<label htmlFor="statut" className="font-bold">Statut</label>
<Dropdown
id="statut"
value={materiel.statut}
onChange={(e) => onDropdownChange(e, 'statut')}
options={statutOptions}
placeholder="Sélectionner un statut"
/>
</div>
<div className="field col-12 md:col-6">
<label htmlFor="dateAchat" className="font-bold">Date d'achat</label>
<Calendar
id="dateAchat"
value={materiel.dateAchat}
onChange={(e) => onDateChange(e, 'dateAchat')}
dateFormat="dd/mm/yy"
showIcon
/>
</div>
<div className="field col-12 md:col-6">
<label htmlFor="valeurAchat" className="font-bold">Valeur d'achat</label>
<InputNumber
id="valeurAchat"
value={materiel.valeurAchat}
onValueChange={(e) => onInputNumberChange(e.value, 'valeurAchat')}
mode="currency"
currency="EUR"
locale="fr-FR"
min={0}
/>
</div>
<div className="field col-12 md:col-6">
<label htmlFor="valeurActuelle" className="font-bold">Valeur actuelle</label>
<InputNumber
id="valeurActuelle"
value={materiel.valeurActuelle}
onValueChange={(e) => onInputNumberChange(e.value, 'valeurActuelle')}
mode="currency"
currency="EUR"
locale="fr-FR"
min={0}
/>
</div>
<div className="field col-12 md:col-6">
<label htmlFor="localisation" className="font-bold">Localisation</label>
<InputText
id="localisation"
value={materiel.localisation}
onChange={(e) => onInputChange(e, 'localisation')}
/>
</div>
<div className="field col-12 md:col-6">
<label htmlFor="proprietaire" className="font-bold">Propriétaire</label>
<InputText
id="proprietaire"
value={materiel.proprietaire}
onChange={(e) => onInputChange(e, 'proprietaire')}
/>
</div>
<div className="field col-12 md:col-6">
<label htmlFor="quantiteStock" className="font-bold">Quantité en stock</label>
<InputNumber
id="quantiteStock"
value={materiel.quantiteStock}
onValueChange={(e) => onInputNumberChange(e.value, 'quantiteStock')}
min={0}
showButtons
/>
</div>
<div className="field col-12 md:col-6">
<label htmlFor="seuilMinimum" className="font-bold">Seuil minimum</label>
<InputNumber
id="seuilMinimum"
value={materiel.seuilMinimum}
onValueChange={(e) => onInputNumberChange(e.value, 'seuilMinimum')}
min={0}
showButtons
/>
</div>
<div className="field col-12 md:col-6">
<label htmlFor="unite" className="font-bold">Unité</label>
<InputText
id="unite"
value={materiel.unite}
onChange={(e) => onInputChange(e, 'unite')}
placeholder="ex: unité, kg, m, etc."
/>
</div>
<div className="field col-12">
<label htmlFor="description" className="font-bold">Description</label>
<InputTextarea
id="description"
value={materiel.description}
onChange={(e) => onInputChange(e, 'description')}
rows={3}
cols={20}
placeholder="Description détaillée du matériel..."
/>
</div>
</div>
</Card>
</div>
</div>
);
};
export default NouveauMaterielPage;