# Session 2025-12-31 : Implémentation du bouton "Modifier"
## 🎯 Objectif
Implémenter le bouton "Modifier" dans la page de détail du périphérique pour permettre l'édition complète des informations.
## 📊 État initial
**Avant** :
- ✅ Bouton "Modifier" présent dans l'interface
- ❌ Fonction `toggleEditMode()` affichait juste "Mode édition à venir"
- ❌ Pas de modale d'édition
- ❌ Pas de fonction de sauvegarde
## ✅ Implémentation
### 1. Modale d'édition HTML
**Fichier** : `frontend/peripheral-detail.html` (lignes 305-453)
**Structure** :
```html
```
**Champs disponibles** :
#### Section Identification
- `nom` * (requis)
- `type_principal` * (requis)
- `sous_type`
- `marque`
- `modele`
- `numero_serie`
#### Section Achat
- `boutique`
- `date_achat` (type date)
- `prix` (number)
- `devise` (3 caractères, défaut: EUR)
- `garantie_duree_mois` (number)
#### Section État et localisation
- `etat` (select: Neuf, Bon, Usagé, Défectueux, Retiré)
- `rating` (0-5 étoiles cliquables)
- `quantite_totale` (number)
- `quantite_disponible` (number)
#### Section Documentation technique
- `synthese` (textarea Markdown)
- `cli_yaml` (textarea YAML)
- `cli_raw` (textarea Markdown)
- `specifications` (textarea Markdown)
- `notes` (textarea Markdown)
### 2. Fonction JavaScript : `toggleEditMode()`
**Fichier** : `frontend/js/peripheral-detail.js` (lignes 461-494)
```javascript
function toggleEditMode() {
if (!peripheral) {
showError('Aucun périphérique chargé');
return;
}
// Populate form with peripheral data
document.getElementById('edit-nom').value = peripheral.nom || '';
document.getElementById('edit-type_principal').value = peripheral.type_principal || '';
// ... (tous les champs)
// Special handling for rating (star system)
setEditRating(peripheral.rating || 0);
// Show modal
document.getElementById('modal-edit').style.display = 'block';
}
```
**Fonctionnement** :
1. Vérifie que le périphérique est chargé
2. Remplit tous les champs du formulaire avec les données actuelles
3. Applique la note avec le système d'étoiles
4. Affiche la modale
### 3. Fonction : `setEditRating()`
**Fichier** : `frontend/js/peripheral-detail.js` (lignes 500-513)
```javascript
function setEditRating(rating) {
const stars = document.querySelectorAll('#edit-star-rating .fa-star');
const ratingInput = document.getElementById('edit-rating');
ratingInput.value = rating;
stars.forEach((star, index) => {
if (index < rating) {
star.classList.add('active');
} else {
star.classList.remove('active');
}
});
}
```
**Fonctionnement** :
- Active les étoiles jusqu'à la note donnée
- Stocke la valeur dans le champ hidden
- Utilisé à la fois lors du chargement et lors du clic
### 4. Event listeners pour les étoiles
**Fichier** : `frontend/js/peripheral-detail.js` (lignes 515-525)
```javascript
document.addEventListener('DOMContentLoaded', () => {
const editStars = document.querySelectorAll('#edit-star-rating .fa-star');
editStars.forEach(star => {
star.addEventListener('click', () => {
const rating = parseInt(star.getAttribute('data-rating'));
setEditRating(rating);
});
});
});
```
**Fonctionnement** :
- Attache un event listener à chaque étoile
- Au clic, récupère la note (1-5)
- Appelle `setEditRating()` pour mettre Ă jour visuellement
### 5. Fonction : `savePeripheral()`
**Fichier** : `frontend/js/peripheral-detail.js` (lignes 527-559)
```javascript
async function savePeripheral(event) {
event.preventDefault();
const form = event.target;
const formData = new FormData(form);
const data = {};
// Convert FormData to object
for (let [key, value] of formData.entries()) {
// Convert numeric fields
if (['prix', 'garantie_duree_mois', 'quantite_totale', 'quantite_disponible', 'rating'].includes(key)) {
data[key] = value ? parseFloat(value) : null;
} else {
data[key] = value || null;
}
}
try {
const response = await apiRequest(`/peripherals/${peripheralId}`, {
method: 'PUT',
body: JSON.stringify(data)
});
showSuccess('Périphérique mis à jour avec succès');
closeEditModal();
// Reload peripheral data
await loadPeripheral();
} catch (error) {
console.error('Error updating peripheral:', error);
showError('Erreur lors de la mise à jour du périphérique');
}
}
```
**Fonctionnement** :
1. Empêche le submit par défaut
2. Récupère toutes les données du formulaire
3. Convertit les champs numériques en `float`
4. Envoie une requĂŞte `PUT` Ă l'API
5. Affiche un message de succès/erreur
6. Ferme la modale
7. Recharge les données du périphérique pour afficher les changements
### 6. Fonction : `closeEditModal()`
**Fichier** : `frontend/js/peripheral-detail.js` (lignes 496-498)
```javascript
function closeEditModal() {
document.getElementById('modal-edit').style.display = 'none';
}
```
**Utilisation** :
- Bouton "Annuler" dans la modale
- Croix de fermeture (Ă—)
- Clic en dehors de la modale (via `window.onclick`)
### 7. Style CSS pour grande modale
**Fichier** : `frontend/css/peripherals.css` (lignes 284-287)
```css
.modal-content.modal-large {
max-width: 1400px;
width: 95%;
}
```
**Usage** : Classe `.modal-large` appliquée à la modale d'édition pour afficher tous les champs confortablement.
## 🔄 Flux complet
```
1. User clique "Modifier"
↓
2. toggleEditMode()
├─> Vérifie que peripheral est chargé
├─> Remplit tous les champs du formulaire
├─> Applique la note (étoiles)
└─> Affiche la modale
↓
3. User modifie les champs
├─> Clic sur étoiles → setEditRating()
└─> Saisie texte, nombres, dates
↓
4. User clique "Enregistrer"
↓
5. savePeripheral()
├─> Prévient le submit par défaut
├─> Récupère FormData
├─> Convertit types (string → number)
├─> PUT /api/peripherals/{id}
├─> Succès → showSuccess() + closeEditModal()
├─> Erreur → showError()
└─> Recharge → loadPeripheral()
↓
6. Page mise à jour avec nouvelles données
```
## đź“‹ RequĂŞte API
### Endpoint
```
PUT /api/peripherals/{id}
```
### Headers
```json
{
"Content-Type": "application/json",
"X-API-Token": "YOUR_TOKEN"
}
```
### Body (exemple)
```json
{
"nom": "Logitech MX Master 3S",
"type_principal": "Souris",
"sous_type": "Sans fil",
"marque": "Logitech",
"modele": "MX Master 3S",
"numero_serie": "LGI-2024-001",
"boutique": "Amazon",
"date_achat": "2024-12-01",
"prix": 99.99,
"devise": "EUR",
"garantie_duree_mois": 24,
"etat": "Neuf",
"rating": 5,
"quantite_totale": 1,
"quantite_disponible": 1,
"synthese": "# Souris ergonomique\n\nExcellente souris pour le travail.",
"cli_yaml": "identification:\n vendor_id: 046d\n product_id: 4082",
"cli_raw": "```\nBus 001 Device 005: ID 046d:4082 Logitech, Inc.\n```",
"specifications": "## Caractéristiques\n- DPI : 8000\n- Bluetooth 5.0",
"notes": "Achetée en promotion"
}
```
### Réponse (200 OK)
```json
{
"id": 3,
"nom": "Logitech MX Master 3S",
"type_principal": "Souris",
// ... tous les champs mis Ă jour
"updated_at": "2025-12-31T12:00:00"
}
```
## đź§Ş Test de validation
### 1. Ouvrir la page de détail
```
http://10.0.0.50:8087/peripheral-detail.html?id=3
```
### 2. Cliquer sur "Modifier"
**Vérifications** :
- âś… La modale s'affiche
- ✅ Tous les champs sont pré-remplis avec les données actuelles
- ✅ Les étoiles correspondent à la note actuelle
### 3. Modifier des champs
**Test** :
- Modifier le nom
- Changer la note (clic sur étoiles)
- Modifier le prix
- Ajouter des notes
**Vérifications** :
- ✅ Les étoiles s'activent au clic
- âś… Les champs acceptent la saisie
- âś… La validation fonctionne (champs requis)
### 4. Enregistrer
**Vérifications** :
- ✅ Message "Périphérique mis à jour avec succès"
- âś… Modale se ferme
- ✅ Données affichées sont mises à jour
- âś… Pas d'erreur console
### 5. Vérifier la persistance
**Test** :
- Rafraîchir la page (F5)
- Vérifier que les modifications sont conservées
**Vérifications** :
- ✅ Les données modifiées sont affichées
- ✅ La base de données a bien été mise à jour
## 🎨 Interface utilisateur
### Bouton "Modifier"
**Position** : En haut à droite de la carte "Informations générales"
```html
```
### Modale d'édition
**Largeur** : 95% (max 1400px) grâce à `.modal-large`
**Layout** : Grid responsive avec 3 colonnes sur desktop
**Sections** :
1. Identification (colonne 1)
2. Achat (colonne 2)
3. État et localisation (colonne 3)
4. Documentation technique (pleine largeur)
### Boutons d'action
```html
```
## 📝 Notes techniques
### Gestion des types de données
**String vers Number** :
```javascript
if (['prix', 'garantie_duree_mois', 'quantite_totale', 'quantite_disponible', 'rating'].includes(key)) {
data[key] = value ? parseFloat(value) : null;
}
```
**Date** : Format `YYYY-MM-DD` (HTML5 input type="date")
**Null values** : Les champs vides sont envoyés comme `null` au lieu de chaînes vides
### Validation
**Côté client** :
- Champs requis : `nom`, `type_principal`
- Type number : min="0" pour prix et quantités
- Type date : format ISO 8601
**Côté serveur** : Validation Pydantic dans le backend FastAPI
### Système d'étoiles
**État actif** : Classe CSS `.active` ajoutée aux étoiles
**HTML structure** :
```html
```
**CSS** :
```css
.star-rating .fa-star.active {
color: #f1c40f;
text-shadow: 0 0 3px rgba(241, 196, 15, 0.5);
}
```
## 🔧 Améliorations futures possibles
- [ ] Validation en temps réel des champs
- [ ] Preview Markdown pour les textareas
- [ ] Auto-save (brouillon local)
- [ ] Historique des modifications (qui/quand)
- [ ] Undo/Redo
- [ ] Dropdowns pour type_principal/sous_type (au lieu de input text)
- [ ] Upload photo directement depuis la modale d'édition
- [ ] Confirmation avant fermeture si modifications non sauvegardées
---
**Date** : 31 décembre 2025
**Statut** : ✅ Implémenté et testé
**Impact** : Édition complète des périphériques depuis la page de détail