318 lines
10 KiB
React
318 lines
10 KiB
React
import { useState, useEffect } from 'react';
|
|
import { createFormexMaterial, updateFormexMaterial } from '../api/client';
|
|
import styles from './MaterialModal.module.css';
|
|
|
|
export default function MaterialModal({ material, collections, onClose, onSave }) {
|
|
const isEditing = !!material;
|
|
|
|
const [formData, setFormData] = useState({
|
|
formex_code: '',
|
|
name: '',
|
|
collection: '',
|
|
width_mm: '',
|
|
height_mm: '',
|
|
thickness_mm: '',
|
|
diameter_mm: '',
|
|
length_mm: '',
|
|
bore_diameter_mm: '',
|
|
bore_depth_base_mm: '',
|
|
bore_depth_piece_mm: '',
|
|
price_chf: '',
|
|
price_unit: '',
|
|
formex_url: ''
|
|
});
|
|
|
|
const [error, setError] = useState('');
|
|
const [saving, setSaving] = useState(false);
|
|
|
|
useEffect(() => {
|
|
if (material) {
|
|
setFormData({
|
|
formex_code: material.formex_code || '',
|
|
name: material.name || '',
|
|
collection: material.collection || '',
|
|
width_mm: material.width_mm?.toString() || '',
|
|
height_mm: material.height_mm?.toString() || '',
|
|
thickness_mm: material.thickness_mm?.toString() || '',
|
|
diameter_mm: material.diameter_mm?.toString() || '',
|
|
length_mm: material.length_mm?.toString() || '',
|
|
bore_diameter_mm: material.bore_diameter_mm?.toString() || '',
|
|
bore_depth_base_mm: material.bore_depth_base_mm?.toString() || '',
|
|
bore_depth_piece_mm: material.bore_depth_piece_mm?.toString() || '',
|
|
price_chf: material.price_chf?.toString() || '',
|
|
price_unit: material.price_unit || '',
|
|
formex_url: material.formex_url || ''
|
|
});
|
|
}
|
|
}, [material]);
|
|
|
|
const handleChange = (e) => {
|
|
const { name, value } = e.target;
|
|
setFormData(prev => ({ ...prev, [name]: value }));
|
|
};
|
|
|
|
const handleSubmit = async (e) => {
|
|
e.preventDefault();
|
|
setError('');
|
|
|
|
// Validation
|
|
if (!formData.formex_code.trim() || !formData.name.trim() || !formData.collection.trim()) {
|
|
setError('Le code, le nom et la collection sont requis.');
|
|
return;
|
|
}
|
|
|
|
setSaving(true);
|
|
|
|
try {
|
|
const payload = {
|
|
formex_code: formData.formex_code.trim(),
|
|
name: formData.name.trim(),
|
|
collection: formData.collection.trim(),
|
|
width_mm: formData.width_mm ? parseInt(formData.width_mm, 10) : null,
|
|
height_mm: formData.height_mm ? parseInt(formData.height_mm, 10) : null,
|
|
thickness_mm: formData.thickness_mm ? parseFloat(formData.thickness_mm) : null,
|
|
diameter_mm: formData.diameter_mm ? parseFloat(formData.diameter_mm) : null,
|
|
length_mm: formData.length_mm ? parseFloat(formData.length_mm) : null,
|
|
bore_diameter_mm: formData.bore_diameter_mm ? parseFloat(formData.bore_diameter_mm) : null,
|
|
bore_depth_base_mm: formData.bore_depth_base_mm ? parseFloat(formData.bore_depth_base_mm) : null,
|
|
bore_depth_piece_mm: formData.bore_depth_piece_mm ? parseFloat(formData.bore_depth_piece_mm) : null,
|
|
price_chf: formData.price_chf ? parseFloat(formData.price_chf) : null,
|
|
price_unit: formData.price_unit.trim() || null,
|
|
formex_url: formData.formex_url.trim() || null
|
|
};
|
|
|
|
if (isEditing) {
|
|
await updateFormexMaterial(material.id, payload);
|
|
} else {
|
|
await createFormexMaterial(payload);
|
|
}
|
|
|
|
onSave();
|
|
} catch (err) {
|
|
setError(err.message);
|
|
} finally {
|
|
setSaving(false);
|
|
}
|
|
};
|
|
|
|
const handleOverlayClick = (e) => {
|
|
if (e.target === e.currentTarget) {
|
|
onClose();
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div className={styles.overlay} onClick={handleOverlayClick}>
|
|
<div className={styles.modal}>
|
|
<div className={styles.header}>
|
|
<h2>{isEditing ? 'Modifier le matériau' : 'Nouveau matériau'}</h2>
|
|
<button type="button" onClick={onClose} className={styles.closeBtn}>
|
|
×
|
|
</button>
|
|
</div>
|
|
|
|
<form onSubmit={handleSubmit} className={styles.form}>
|
|
{error && <p className={styles.error}>{error}</p>}
|
|
|
|
<div className={styles.field}>
|
|
<label htmlFor="formex_code">Code Formex *</label>
|
|
<input
|
|
type="text"
|
|
id="formex_code"
|
|
name="formex_code"
|
|
value={formData.formex_code}
|
|
onChange={handleChange}
|
|
placeholder="ex: 10000"
|
|
required
|
|
/>
|
|
</div>
|
|
|
|
<div className={styles.field}>
|
|
<label htmlFor="name">Nom *</label>
|
|
<input
|
|
type="text"
|
|
id="name"
|
|
name="name"
|
|
value={formData.name}
|
|
onChange={handleChange}
|
|
placeholder="ex: Panneaux mélaminés Duplex Plus 10000 Tilia"
|
|
required
|
|
/>
|
|
</div>
|
|
|
|
<div className={styles.field}>
|
|
<label htmlFor="collection">Collection *</label>
|
|
<input
|
|
type="text"
|
|
id="collection"
|
|
name="collection"
|
|
value={formData.collection}
|
|
onChange={handleChange}
|
|
list="collections-list"
|
|
placeholder="ex: Duplex Plus"
|
|
required
|
|
/>
|
|
<datalist id="collections-list">
|
|
{collections.map((c) => (
|
|
<option key={c} value={c} />
|
|
))}
|
|
</datalist>
|
|
</div>
|
|
|
|
<div className={styles.row}>
|
|
<div className={styles.field}>
|
|
<label htmlFor="width_mm">Largeur (mm)</label>
|
|
<input
|
|
type="number"
|
|
id="width_mm"
|
|
name="width_mm"
|
|
value={formData.width_mm}
|
|
onChange={handleChange}
|
|
placeholder="2800"
|
|
/>
|
|
</div>
|
|
<div className={styles.field}>
|
|
<label htmlFor="height_mm">Hauteur (mm)</label>
|
|
<input
|
|
type="number"
|
|
id="height_mm"
|
|
name="height_mm"
|
|
value={formData.height_mm}
|
|
onChange={handleChange}
|
|
placeholder="2070"
|
|
/>
|
|
</div>
|
|
<div className={styles.field}>
|
|
<label htmlFor="thickness_mm">Épaisseur (mm)</label>
|
|
<input
|
|
type="number"
|
|
id="thickness_mm"
|
|
name="thickness_mm"
|
|
value={formData.thickness_mm}
|
|
onChange={handleChange}
|
|
placeholder="19"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div className={styles.row}>
|
|
<div className={styles.field}>
|
|
<label htmlFor="diameter_mm">Ø Diamètre (mm)</label>
|
|
<input
|
|
type="number"
|
|
id="diameter_mm"
|
|
name="diameter_mm"
|
|
value={formData.diameter_mm}
|
|
onChange={handleChange}
|
|
placeholder="8"
|
|
step="0.1"
|
|
/>
|
|
</div>
|
|
<div className={styles.field}>
|
|
<label htmlFor="length_mm">Longueur (mm)</label>
|
|
<input
|
|
type="number"
|
|
id="length_mm"
|
|
name="length_mm"
|
|
value={formData.length_mm}
|
|
onChange={handleChange}
|
|
placeholder="55"
|
|
step="0.1"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<fieldset className={styles.fieldset}>
|
|
<legend>Perçage</legend>
|
|
<div className={styles.row}>
|
|
<div className={styles.field}>
|
|
<label htmlFor="bore_diameter_mm">Ø Perçage (mm)</label>
|
|
<input
|
|
type="number"
|
|
id="bore_diameter_mm"
|
|
name="bore_diameter_mm"
|
|
value={formData.bore_diameter_mm}
|
|
onChange={handleChange}
|
|
placeholder="8"
|
|
step="0.1"
|
|
/>
|
|
</div>
|
|
<div className={styles.field}>
|
|
<label htmlFor="bore_depth_base_mm">Prof. fond (mm)</label>
|
|
<input
|
|
type="number"
|
|
id="bore_depth_base_mm"
|
|
name="bore_depth_base_mm"
|
|
value={formData.bore_depth_base_mm}
|
|
onChange={handleChange}
|
|
placeholder="11"
|
|
step="0.1"
|
|
/>
|
|
</div>
|
|
<div className={styles.field}>
|
|
<label htmlFor="bore_depth_piece_mm">Prof. pièce (mm)</label>
|
|
<input
|
|
type="number"
|
|
id="bore_depth_piece_mm"
|
|
name="bore_depth_piece_mm"
|
|
value={formData.bore_depth_piece_mm}
|
|
onChange={handleChange}
|
|
placeholder="8"
|
|
step="0.1"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</fieldset>
|
|
|
|
<div className={styles.row}>
|
|
<div className={styles.field}>
|
|
<label htmlFor="price_chf">Prix CHF</label>
|
|
<input
|
|
type="number"
|
|
id="price_chf"
|
|
name="price_chf"
|
|
value={formData.price_chf}
|
|
onChange={handleChange}
|
|
placeholder="0.60"
|
|
step="0.01"
|
|
/>
|
|
</div>
|
|
<div className={styles.field}>
|
|
<label htmlFor="price_unit">Unité de prix</label>
|
|
<input
|
|
type="text"
|
|
id="price_unit"
|
|
name="price_unit"
|
|
value={formData.price_unit}
|
|
onChange={handleChange}
|
|
placeholder="par Pièce (PC)"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div className={styles.field}>
|
|
<label htmlFor="formex_url">URL</label>
|
|
<input
|
|
type="url"
|
|
id="formex_url"
|
|
name="formex_url"
|
|
value={formData.formex_url}
|
|
onChange={handleChange}
|
|
placeholder="https://..."
|
|
/>
|
|
</div>
|
|
|
|
<div className={styles.actions}>
|
|
<button type="button" onClick={onClose} className={styles.cancelBtn}>
|
|
Annuler
|
|
</button>
|
|
<button type="submit" disabled={saving} className={styles.saveBtn}>
|
|
{saving ? 'Enregistrement…' : (isEditing ? 'Enregistrer' : 'Créer')}
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|