# 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