From 5f86950dba318b555138f94660074ac75717d8ed Mon Sep 17 00:00:00 2001 From: Olivier Date: Thu, 18 Jun 2026 22:42:10 +0200 Subject: [PATCH] Fix --- backend/src/routes/tickets.js | 15 ++++ frontend/src/pages/Communication.jsx | 126 ++++++++++++++++++++++++--- 2 files changed, 128 insertions(+), 13 deletions(-) diff --git a/backend/src/routes/tickets.js b/backend/src/routes/tickets.js index ee53e88..5aa68a6 100644 --- a/backend/src/routes/tickets.js +++ b/backend/src/routes/tickets.js @@ -242,6 +242,21 @@ router.patch('/:id/status', requireAdmin, (req, res) => { res.json({ ok: true }); }); +// ── PATCH /api/tickets/:id/categorize — modifier type et pages ─────────────── +router.patch('/:id/categorize', (req, res) => { + const { id: userId, role } = req.user; + const isAdmin = role === 'admin'; + + const ticket = db.prepare('SELECT * FROM tickets WHERE id = ?').get(req.params.id); + if (!ticket) return res.status(404).json({ error: 'Ticket introuvable' }); + if (!isAdmin && ticket.user_id !== userId) return res.status(403).json({ error: 'Accès refusé' }); + + const { ticket_type, ticket_pages } = req.body; + db.prepare("UPDATE tickets SET ticket_type = ?, ticket_pages = ?, updated_at = datetime('now') WHERE id = ?") + .run(ticket_type ?? null, ticket_pages ?? null, req.params.id); + res.json({ ok: true }); +}); + // ── PATCH /api/tickets/:id/assign — assigner à un admin ────────────────────── router.patch('/:id/assign', requireAdmin, (req, res) => { const { assigned_to } = req.body; // null pour désassigner diff --git a/frontend/src/pages/Communication.jsx b/frontend/src/pages/Communication.jsx index 9da2cfb..75f5cb5 100644 --- a/frontend/src/pages/Communication.jsx +++ b/frontend/src/pages/Communication.jsx @@ -558,7 +558,10 @@ export default function Communication() { const navigate = useNavigate(); const [notifMenuPos, setNotifMenuPos] = useState(null); // { x, y } const [supportMenuPos, setSupportMenuPos] = useState(null); // { x, y } - const [showAssignModal, setShowAssignModal] = useState(false); + const [showAssignModal, setShowAssignModal] = useState(false); + const [showCategModal, setShowCategModal] = useState(false); + const [categType, setCategType] = useState(null); + const [categPages, setCategPages] = useState([]); const [assignSearch, setAssignSearch] = useState(''); const [tab, setTab] = useState('support'); // 'support' | 'notifications' @@ -1036,9 +1039,9 @@ export default function Communication() {
{t.ticket_number} — {t.subject}
- + {t.last_body && ( -
{stripPreview(t.last_body)}
+
{stripPreview(t.last_body)}
)}
{t.message_count} message{t.message_count > 1 ? 's' : ''} @@ -1159,19 +1162,44 @@ export default function Communication() { {/* Détail ticket */} {tab === 'support' && thread && ( <> -
-
-
+
+ {/* Ligne 1 : type chip + titre + badge statut */} +
+ {thread.ticket.ticket_type && (() => { + const type = TICKET_TYPES.find(t => t.value === thread.ticket.ticket_type); + return type ? ( + + {type.label} + + ) : null; + })()} + {thread.ticket.ticket_number} — {thread.ticket.subject} -
-
- Ouvert par {thread.ticket.user_name} · {fmtDate(thread.ticket.created_at)} -
- -
-
+
+ {/* Ligne 2 : meta gauche + chips pages droite */} + {(() => { + const pages = thread.ticket.ticket_pages + ? (Array.isArray(thread.ticket.ticket_pages) ? thread.ticket.ticket_pages : JSON.parse(thread.ticket.ticket_pages)) + : []; + return ( +
+ + Ouvert par {thread.ticket.user_name} · {fmtDate(thread.ticket.created_at)} + {thread.ticket.assigned_name && ( + <> — assigné à {thread.ticket.assigned_name} + )} + +
+ {pages.map(p => { + const page = TICKET_PAGES.find(x => x.value === p); + return page ? {page.label} : null; + })} +
+
+ ); + })()}
@@ -1540,6 +1568,23 @@ export default function Communication() { Nouveau ticket + {thread && ( + + )} {thread && isAdmin && ( <> + + )} + {thread && ( + <>
+
+
+
+
Type
+ +
+
+
Pages concernées
+ +
+
+ + +
+
+
+
+ )} + {/* ── Lightbox image ── */} {lightbox && (
setLightbox(null)}>