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 && (
+ <>