From f4460a5323ffb17cba11be18edccdf2039280b92 Mon Sep 17 00:00:00 2001 From: kdeterme Date: Fri, 25 Sep 2026 23:36:04 +0200 Subject: [PATCH] feat: add edit note functionality and UI action buttons --- .../interventions/detail/cms_edit_mode.css | 19 +- .../static/interventions/detail/cms_notes.js | 200 ++++++++++-------- .../interventions/detail/card_notes.html | 7 +- .../detail/card_notes_documents.html | 10 +- 4 files changed, 130 insertions(+), 106 deletions(-) diff --git a/loko/interventions/static/interventions/detail/cms_edit_mode.css b/loko/interventions/static/interventions/detail/cms_edit_mode.css index 4b2fa98..3c2eb51 100644 --- a/loko/interventions/static/interventions/detail/cms_edit_mode.css +++ b/loko/interventions/static/interventions/detail/cms_edit_mode.css @@ -146,14 +146,21 @@ body.cms-edit-mode .cms-modal-container { border: 2px solid #f8e8b6; } -/* Delete button hidden by default */ -.delete-note-btn { - display: none !important; +/* Note action buttons */ +.note-actions .delete-note-btn, +.note-actions .edit-note-btn { + opacity: 0.7; + transition: opacity 0.2s ease, transform 0.1s ease; + text-decoration: none; + cursor: pointer; } -/* Delete button visible in edit mode */ -body.cms-edit-mode .delete-note-btn { - display: block !important; +.note-actions .delete-note-btn:hover, +.note-actions .edit-note-btn:hover, +body.cms-edit-mode .note-actions .delete-note-btn, +body.cms-edit-mode .note-actions .edit-note-btn { + opacity: 1; + transform: scale(1.1); } /* Editable notes in CMS edit mode */ diff --git a/loko/interventions/static/interventions/detail/cms_notes.js b/loko/interventions/static/interventions/detail/cms_notes.js index 8dbe7ab..5552834 100644 --- a/loko/interventions/static/interventions/detail/cms_notes.js +++ b/loko/interventions/static/interventions/detail/cms_notes.js @@ -5,10 +5,12 @@ 'use strict'; const interventionId = document.querySelector('[data-intervention-id]')?.dataset.interventionId; - const csrfToken = document.querySelector('[name=csrfmiddlewaretoken]')?.value; + const csrfToken = document.querySelector('[name=csrfmiddlewaretoken]')?.value + || (typeof getCookie === 'function' ? getCookie('csrftoken') : null) + || (typeof csrftoken !== 'undefined' ? csrftoken : null); - if (!interventionId || !csrfToken) { - console.warn('CMS Notes: Missing intervention ID or CSRF token'); + if (!interventionId) { + console.warn('CMS Notes: Missing intervention ID'); return; } @@ -92,17 +94,110 @@ // Store original note values for cancel window.cmsNotesOriginalValues = {}; - // Show delete buttons in edit mode - document.addEventListener('cms-edit-mode-enter', function () { - document.querySelectorAll('.delete-note-btn').forEach(btn => { - btn.style.display = 'block'; - }); - }); + function startEditingNote(noteItem) { + if (!noteItem) return; - // Editable notes - click to edit in CMS mode + const noteId = noteItem.dataset.noteId; + const textarea = noteItem.querySelector('.edit-note-content'); + const select = noteItem.querySelector('.edit-note-type'); + + const originalContent = decodeHtmlToText(noteItem.dataset.noteContent || ''); + const originalType = noteItem.dataset.noteType || ''; + + if (textarea) textarea.value = originalContent; + if (select) select.value = originalType; + + if (!window.cmsNotesOriginalValues[noteId]) { + window.cmsNotesOriginalValues[noteId] = { + content: originalContent, + type: originalType + }; + } + + noteItem.classList.add('editing'); + + if (textarea) { + setTimeout(() => { + textarea.focus(); + textarea.setSelectionRange(textarea.value.length, textarea.value.length); + }, 100); + } + } + + // Notes container click delegation (edit button, delete button, inline edit) if (notesContainer) { notesContainer.addEventListener('click', function (e) { - // Only allow editing in CMS edit mode + // Edit note button handler + const editBtn = e.target.closest('.edit-note-btn'); + if (editBtn) { + e.preventDefault(); + e.stopPropagation(); + + const noteItem = editBtn.closest('.editable-note'); + if (!noteItem) return; + + if (!document.body.classList.contains('cms-edit-mode')) { + const cmsEditBtn = document.getElementById('cms-edit-btn'); + if (cmsEditBtn) { + cmsEditBtn.click(); + } + } + + startEditingNote(noteItem); + return; + } + + // Delete note button handler + const deleteBtn = e.target.closest('.delete-note-btn'); + if (deleteBtn) { + e.preventDefault(); + e.stopPropagation(); + + const noteId = deleteBtn.dataset.noteId; + if (!noteId) return; + + const confirmMsg = typeof gettext === 'function' ? gettext('Voulez-vous vraiment supprimer cette note ?') : 'Voulez-vous vraiment supprimer cette note ?'; + if (!window.confirm(confirmMsg)) { + return; + } + + deleteBtn.disabled = true; + + const token = document.querySelector('[name=csrfmiddlewaretoken]')?.value + || (typeof getCookie === 'function' ? getCookie('csrftoken') : null) + || (typeof csrftoken !== 'undefined' ? csrftoken : null); + + fetch(`/interventions/${interventionId}/notes/${noteId}/delete/`, { + method: 'POST', + headers: { + 'X-CSRFToken': token, + }, + }) + .then(response => response.json()) + .then(data => { + if (data.success) { + const successMsg = typeof gettext === 'function' ? gettext('Note supprimée avec succès !') : 'Note supprimée avec succès !'; + showAlert('✅ ' + successMsg, 'success'); + + const noteItem = document.getElementById(`note-container-${noteId}`); + if (noteItem) { + noteItem.remove(); + } + } else { + showAlert(`❌ ${data.error || 'Une erreur est survenue.'}`, 'danger'); + deleteBtn.disabled = false; + } + }) + .catch(error => { + console.error('Error deleting note:', error); + const errorMsg = typeof gettext === 'function' ? gettext('Une erreur est survenue lors de la suppression.') : 'Une erreur est survenue lors de la suppression.'; + showAlert('❌ ' + errorMsg, 'danger'); + deleteBtn.disabled = false; + }); + return; + } + + // Click anywhere on note in CMS edit mode to edit if (!document.body.classList.contains('cms-edit-mode')) { return; } @@ -110,98 +205,17 @@ const noteItem = e.target.closest('.editable-note'); if (!noteItem) return; - // Don't trigger if clicking on buttons - if (e.target.closest('.delete-note-btn')) { - return; - } - // Don't toggle if already editing if (noteItem.classList.contains('editing')) { return; } - // Store original values when entering edit mode - const noteId = noteItem.dataset.noteId; - const textarea = noteItem.querySelector('.edit-note-content'); - const select = noteItem.querySelector('.edit-note-type'); - - // Force reset textarea value from data attribute to avoid browser cache - const originalContent = decodeHtmlToText(noteItem.dataset.noteContent || ''); - const originalType = noteItem.dataset.noteType || ''; - - if (textarea) textarea.value = originalContent; - if (select) select.value = originalType; - - // Store these values for cancel operation - if (!window.cmsNotesOriginalValues[noteId]) { - window.cmsNotesOriginalValues[noteId] = { - content: originalContent, - type: originalType - }; - } - - // Enter edit mode for this note - noteItem.classList.add('editing'); - - // Focus on the textarea - if (textarea) { - setTimeout(() => { - textarea.focus(); - textarea.setSelectionRange(textarea.value.length, textarea.value.length); - }, 100); - } - }); - - // Delete note button - notesContainer.addEventListener('click', function (e) { - const deleteBtn = e.target.closest('.delete-note-btn'); - if (!deleteBtn) return; - - const noteId = deleteBtn.dataset.noteId; - if (!noteId) return; - - if (!window.confirm('Voulez-vous vraiment supprimer cette note ?')) { - return; - } - - // Disable button during delete - deleteBtn.disabled = true; - - fetch(`/interventions/${interventionId}/notes/${noteId}/delete/`, { - method: 'POST', - headers: { - 'X-CSRFToken': csrfToken, - }, - }) - .then(response => response.json()) - .then(data => { - if (data.success) { - showAlert('✅ Note supprimée avec succès !', 'success'); - - // Remove note from DOM - const noteItem = document.getElementById(`note-container-${noteId}`); - if (noteItem) { - noteItem.remove(); - } - } else { - showAlert(`❌ ${data.error || 'Une erreur est survenue.'}`, 'danger'); - deleteBtn.disabled = false; - } - }) - .catch(error => { - console.error('Error deleting note:', error); - showAlert('❌ Une erreur est survenue lors de la suppression.', 'danger'); - deleteBtn.disabled = false; - }); + startEditingNote(noteItem); }); } // Hide new note editor and restore original values when exiting edit mode document.addEventListener('cms-edit-mode-exit', function () { - // Hide delete buttons - document.querySelectorAll('.delete-note-btn').forEach(btn => { - btn.style.display = 'none'; - }); // Hide and reset new note editor if (newNoteEditor) { diff --git a/loko/interventions/templates/interventions/detail/card_notes.html b/loko/interventions/templates/interventions/detail/card_notes.html index d09a65e..c3ad6a0 100644 --- a/loko/interventions/templates/interventions/detail/card_notes.html +++ b/loko/interventions/templates/interventions/detail/card_notes.html @@ -63,8 +63,11 @@

{{ note.content|safe|linebreaksbr }}

{% if note.id in editable_note_ids %} -
- +
diff --git a/loko/interventions/templates/interventions/detail/card_notes_documents.html b/loko/interventions/templates/interventions/detail/card_notes_documents.html index 8d63afa..c7798b0 100644 --- a/loko/interventions/templates/interventions/detail/card_notes_documents.html +++ b/loko/interventions/templates/interventions/detail/card_notes_documents.html @@ -122,12 +122,12 @@

{{ note.content|linebreaksbr }}

{% if note.id in editable_note_ids %} - {% endif %}