@consilioweb/payload-support 5.0.0 → 6.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +249 -22
- package/dist/components/RichTextEditor/index.js +1 -1
- package/dist/components/TicketConversation/RewriteDropdown.js +1 -1
- package/dist/components/TicketConversation/components/AISummaryPanel.js +3 -0
- package/dist/components/TicketConversation/components/ActionPanels.js +13 -8
- package/dist/components/TicketConversation/components/ClientHistory.js +1 -0
- package/dist/components/TicketConversation/components/CodeBlock.js +1 -0
- package/dist/components/TicketConversation/components/CodeBlockInserter.js +1 -1
- package/dist/components/TicketConversation/components/QuickActions.js +10 -8
- package/dist/components/TicketConversation/components/TicketHeader.js +2 -0
- package/dist/components/TicketConversation/components/TimeTrackingPanel.js +15 -9
- package/dist/components/TicketConversation/index.d.ts +10 -0
- package/dist/components/TicketConversation/index.js +25 -7
- package/dist/index.cjs +306 -60
- package/dist/index.d.cts +107 -38
- package/dist/index.d.ts +107 -38
- package/dist/index.js +300 -59
- package/dist/styles/BillingView.module.scss +11 -11
- package/dist/styles/ChatView.module.scss +7 -7
- package/dist/styles/CommandPalette.module.scss +1 -1
- package/dist/styles/CrmView.module.scss +9 -9
- package/dist/styles/EmailTracking.module.scss +6 -6
- package/dist/styles/ImportConversation.module.scss +5 -5
- package/dist/styles/Logs.module.scss +5 -5
- package/dist/styles/NewTicket.module.scss +2 -2
- package/dist/styles/PendingEmails.module.scss +13 -13
- package/dist/styles/SupportDashboard.module.scss +24 -8
- package/dist/styles/TicketDetail.module.scss +20 -20
- package/dist/styles/TicketInbox.module.scss +6 -6
- package/dist/styles/TicketingSettings.module.scss +10 -10
- package/dist/styles/TimeDashboard.module.scss +6 -6
- package/dist/styles/_tokens.scss +3 -1
- package/dist/views/BillingView/client.js +15 -8
- package/dist/views/ChatView/client.js +2 -0
- package/dist/views/CrmView/client.js +2 -0
- package/dist/views/EmailTrackingView/client.js +23 -11
- package/dist/views/ImportConversationView/client.js +1 -0
- package/dist/views/LogsView/client.js +1 -1
- package/dist/views/NewTicketView/client.js +20 -13
- package/dist/views/PendingEmailsView/client.js +9 -3
- package/dist/views/SupportDashboardView/client.js +17 -19
- package/dist/views/TicketDetailView/client.js +23 -11
- package/dist/views/TicketInboxView/client.js +52 -26
- package/dist/views/TicketingSettingsView/TicketingSettings.module.scss +7 -7
- package/dist/views/TicketingSettingsView/client.js +44 -26
- package/dist/views/TimeDashboardView/client.js +10 -7
- package/dist/views/shared/ErrorBoundary.d.ts +36 -1
- package/dist/views/shared/ErrorBoundary.js +59 -28
- package/dist/views/shared/adminTokens.d.ts +15 -5
- package/dist/views/shared/adminTokens.js +23 -7
- package/dist/views/shared/icons.d.ts +49 -0
- package/dist/views/shared/icons.js +92 -0
- package/dist/views/shared/locales/en.json +15 -1
- package/dist/views/shared/locales/fr.json +15 -1
- package/package.json +6 -2
- package/scripts/uninstall-data.mjs +178 -0
- package/scripts/uninstall.mjs +184 -0
- package/src/collections/Tickets.ts +7 -0
- package/src/collections/TimeEntries.ts +11 -3
- package/src/components/RichTextEditor/index.tsx +1 -1
- package/src/components/TicketConversation/RewriteDropdown.tsx +1 -1
- package/src/components/TicketConversation/components/AISummaryPanel.tsx +3 -0
- package/src/components/TicketConversation/components/ActionPanels.tsx +13 -8
- package/src/components/TicketConversation/components/ClientHistory.tsx +1 -0
- package/src/components/TicketConversation/components/CodeBlock.tsx +1 -0
- package/src/components/TicketConversation/components/CodeBlockInserter.tsx +1 -1
- package/src/components/TicketConversation/components/QuickActions.tsx +10 -8
- package/src/components/TicketConversation/components/TicketHeader.tsx +2 -0
- package/src/components/TicketConversation/components/TimeTrackingPanel.tsx +17 -9
- package/src/components/TicketConversation/index.tsx +41 -7
- package/src/endpoints/delete-account.ts +191 -47
- package/src/endpoints/export-data.ts +104 -4
- package/src/endpoints/purge-logs.ts +6 -15
- package/src/index.ts +2 -0
- package/src/plugin.ts +51 -1
- package/src/portal/LiveChat.tsx +1 -1
- package/src/portal/auth/profile/page.tsx +3 -2
- package/src/portal/icons.tsx +91 -0
- package/src/styles/BillingView.module.scss +11 -11
- package/src/styles/ChatView.module.scss +7 -7
- package/src/styles/CommandPalette.module.scss +1 -1
- package/src/styles/CrmView.module.scss +9 -9
- package/src/styles/EmailTracking.module.scss +6 -6
- package/src/styles/ImportConversation.module.scss +5 -5
- package/src/styles/Logs.module.scss +5 -5
- package/src/styles/NewTicket.module.scss +2 -2
- package/src/styles/PendingEmails.module.scss +13 -13
- package/src/styles/SupportDashboard.module.scss +24 -8
- package/src/styles/TicketDetail.module.scss +20 -20
- package/src/styles/TicketInbox.module.scss +6 -6
- package/src/styles/TicketingSettings.module.scss +10 -10
- package/src/styles/TimeDashboard.module.scss +6 -6
- package/src/styles/_tokens.scss +3 -1
- package/src/types.ts +20 -0
- package/src/utils/retention.ts +111 -0
- package/src/utils/slugs.ts +15 -0
- package/src/views/BillingView/client.tsx +17 -8
- package/src/views/ChatView/client.tsx +2 -0
- package/src/views/CrmView/client.tsx +2 -0
- package/src/views/EmailTrackingView/client.tsx +18 -7
- package/src/views/ImportConversationView/client.tsx +1 -0
- package/src/views/LogsView/client.tsx +1 -1
- package/src/views/NewTicketView/client.tsx +22 -13
- package/src/views/PendingEmailsView/client.tsx +9 -3
- package/src/views/SupportDashboardView/client.tsx +11 -5
- package/src/views/TicketDetailView/client.tsx +25 -11
- package/src/views/TicketInboxView/client.tsx +47 -7
- package/src/views/TicketingSettingsView/TicketingSettings.module.scss +7 -7
- package/src/views/TicketingSettingsView/client.tsx +201 -144
- package/src/views/TimeDashboardView/client.tsx +10 -7
- package/src/views/shared/ErrorBoundary.tsx +95 -31
- package/src/views/shared/adminTokens.ts +28 -11
- package/src/views/shared/icons.tsx +146 -0
- package/src/views/shared/locales/en.json +15 -1
- package/src/views/shared/locales/fr.json +15 -1
- package/src/types/lucide-react.d.ts +0 -42
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
3
3
|
import { useState, useCallback, useEffect } from 'react';
|
|
4
|
-
import { Inbox, Paperclip, ChevronUp, ChevronDown, Plus, Link2, X, Search } from '
|
|
4
|
+
import { Inbox, Paperclip, ChevronUp, ChevronDown, Plus, Link2, X, Search } from '../shared/icons.js';
|
|
5
5
|
import { SkeletonDashboard } from '../shared/Skeleton.js';
|
|
6
6
|
import { useTranslation } from '../../components/TicketConversation/hooks/useTranslation.js';
|
|
7
7
|
import styles from '../../styles/PendingEmails.module.scss';
|
|
@@ -52,7 +52,7 @@ function TicketSearchModal({
|
|
|
52
52
|
return /* @__PURE__ */ jsx("div", { className: styles.overlay, onClick: onClose, children: /* @__PURE__ */ jsxs("div", { className: styles.modal, onClick: (e) => e.stopPropagation(), children: [
|
|
53
53
|
/* @__PURE__ */ jsxs("div", { className: styles.modalHeader, children: [
|
|
54
54
|
/* @__PURE__ */ jsx("h3", { className: styles.modalTitle, children: "Rattacher a un ticket" }),
|
|
55
|
-
/* @__PURE__ */ jsx("button", { onClick: onClose, className: styles.modalClose, children: /* @__PURE__ */ jsx(X, { size: 20 }) })
|
|
55
|
+
/* @__PURE__ */ jsx("button", { type: "button", "aria-label": "Fermer", onClick: onClose, className: styles.modalClose, children: /* @__PURE__ */ jsx(X, { size: 20 }) })
|
|
56
56
|
] }),
|
|
57
57
|
suggestions.length > 0 && /* @__PURE__ */ jsxs("div", { className: styles.sectionBlock, children: [
|
|
58
58
|
/* @__PURE__ */ jsx("div", { className: styles.sectionLabel, children: "Suggestions" }),
|
|
@@ -71,6 +71,7 @@ function TicketSearchModal({
|
|
|
71
71
|
"input",
|
|
72
72
|
{
|
|
73
73
|
type: "text",
|
|
74
|
+
"aria-label": "Rechercher un ticket",
|
|
74
75
|
placeholder: "Rechercher un ticket (TK-0042, sujet...)...",
|
|
75
76
|
value: search,
|
|
76
77
|
onChange: (e) => setSearch(e.target.value),
|
|
@@ -163,7 +164,7 @@ function ClientPickerModal({
|
|
|
163
164
|
return /* @__PURE__ */ jsx("div", { className: styles.overlay, onClick: onClose, children: /* @__PURE__ */ jsxs("div", { className: styles.modal, onClick: (e) => e.stopPropagation(), children: [
|
|
164
165
|
/* @__PURE__ */ jsxs("div", { className: styles.modalHeader, children: [
|
|
165
166
|
/* @__PURE__ */ jsx("h3", { className: styles.modalTitle, children: "Choisir un client" }),
|
|
166
|
-
/* @__PURE__ */ jsx("button", { onClick: onClose, className: styles.modalClose, children: /* @__PURE__ */ jsx(X, { size: 20 }) })
|
|
167
|
+
/* @__PURE__ */ jsx("button", { type: "button", "aria-label": "Fermer", onClick: onClose, className: styles.modalClose, children: /* @__PURE__ */ jsx(X, { size: 20 }) })
|
|
167
168
|
] }),
|
|
168
169
|
detectedClient && /* @__PURE__ */ jsxs("div", { className: styles.sectionBlock, children: [
|
|
169
170
|
/* @__PURE__ */ jsx("div", { className: styles.sectionLabel, children: "Client detecte" }),
|
|
@@ -181,6 +182,7 @@ function ClientPickerModal({
|
|
|
181
182
|
"input",
|
|
182
183
|
{
|
|
183
184
|
type: "text",
|
|
185
|
+
"aria-label": "Rechercher un client",
|
|
184
186
|
placeholder: "Rechercher un client (nom, email, entreprise)...",
|
|
185
187
|
value: search,
|
|
186
188
|
onChange: (e) => setSearch(e.target.value),
|
|
@@ -205,6 +207,7 @@ function ClientPickerModal({
|
|
|
205
207
|
"input",
|
|
206
208
|
{
|
|
207
209
|
type: "text",
|
|
210
|
+
"aria-label": "Prenom",
|
|
208
211
|
placeholder: "Prenom *",
|
|
209
212
|
value: newClient.firstName,
|
|
210
213
|
onChange: (e) => setNewClient((p) => ({ ...p, firstName: e.target.value })),
|
|
@@ -215,6 +218,7 @@ function ClientPickerModal({
|
|
|
215
218
|
"input",
|
|
216
219
|
{
|
|
217
220
|
type: "text",
|
|
221
|
+
"aria-label": "Nom",
|
|
218
222
|
placeholder: "Nom",
|
|
219
223
|
value: newClient.lastName,
|
|
220
224
|
onChange: (e) => setNewClient((p) => ({ ...p, lastName: e.target.value })),
|
|
@@ -226,6 +230,7 @@ function ClientPickerModal({
|
|
|
226
230
|
"input",
|
|
227
231
|
{
|
|
228
232
|
type: "email",
|
|
233
|
+
"aria-label": "Email",
|
|
229
234
|
placeholder: "Email *",
|
|
230
235
|
value: newClient.email,
|
|
231
236
|
onChange: (e) => setNewClient((p) => ({ ...p, email: e.target.value })),
|
|
@@ -236,6 +241,7 @@ function ClientPickerModal({
|
|
|
236
241
|
"input",
|
|
237
242
|
{
|
|
238
243
|
type: "text",
|
|
244
|
+
"aria-label": "Entreprise",
|
|
239
245
|
placeholder: "Entreprise *",
|
|
240
246
|
value: newClient.company,
|
|
241
247
|
onChange: (e) => setNewClient((p) => ({ ...p, company: e.target.value })),
|
|
@@ -372,25 +372,23 @@ const SupportDashboardClient = () => {
|
|
|
372
372
|
/* @__PURE__ */ jsx("th", { children: t("dashboard.tableHeaders.modified") }),
|
|
373
373
|
/* @__PURE__ */ jsx("th", {})
|
|
374
374
|
] }) }),
|
|
375
|
-
/* @__PURE__ */ jsx("tbody", { children: tickets.map((tk) =>
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
},
|
|
393
|
-
tk.id
|
|
375
|
+
/* @__PURE__ */ jsx("tbody", { children: tickets.map((tk) => (
|
|
376
|
+
/*
|
|
377
|
+
* The row is not the control: a `<tr onClick>` is invisible to
|
|
378
|
+
* the keyboard, and turning it into role="button" would cost
|
|
379
|
+
* the table semantics. The link lives in the subject cell.
|
|
380
|
+
*/
|
|
381
|
+
/* @__PURE__ */ jsxs("tr", { children: [
|
|
382
|
+
/* @__PURE__ */ jsx("td", { children: /* @__PURE__ */ jsx("span", { className: `${styles.statusDot} ${getStatusDotClass(tk.status)}` }) }),
|
|
383
|
+
/* @__PURE__ */ jsxs("td", { className: styles.ticketNum, children: [
|
|
384
|
+
"#",
|
|
385
|
+
tk.ticketNumber
|
|
386
|
+
] }),
|
|
387
|
+
/* @__PURE__ */ jsx("td", { className: styles.ticketSubject, children: /* @__PURE__ */ jsx("a", { className: styles.ticketLink, href: `/admin/support/ticket?id=${tk.id}`, children: tk.subject }) }),
|
|
388
|
+
/* @__PURE__ */ jsx("td", { className: styles.ticketClient, children: getClientName(tk) }),
|
|
389
|
+
/* @__PURE__ */ jsx("td", { className: styles.ticketTime, children: timeAgo(tk.updatedAt) }),
|
|
390
|
+
/* @__PURE__ */ jsx("td", { className: styles.ticketArrow, children: "\u2192" })
|
|
391
|
+
] }, tk.id)
|
|
394
392
|
)) })
|
|
395
393
|
] })
|
|
396
394
|
] }),
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
3
|
-
import React, { useRef, useState, useEffect, useCallback } from 'react';
|
|
3
|
+
import React, { useRef, useId, useState, useEffect, useCallback } from 'react';
|
|
4
4
|
import { useSearchParams } from 'next/navigation';
|
|
5
5
|
import Link from 'next/link';
|
|
6
6
|
import { RichTextEditor } from '../../components/RichTextEditor/index.js';
|
|
@@ -25,6 +25,11 @@ const TicketDetailClient = () => {
|
|
|
25
25
|
const threadEndRef = useRef(null);
|
|
26
26
|
const dropdownRef = useRef(null);
|
|
27
27
|
const fileInputRef = useRef(null);
|
|
28
|
+
const manualTimeId = useId();
|
|
29
|
+
const billingTypeId = useId();
|
|
30
|
+
const flatAmountId = useId();
|
|
31
|
+
const billedAmountId = useId();
|
|
32
|
+
const paymentStatusId = useId();
|
|
28
33
|
const [ticket, setTicket] = useState(null);
|
|
29
34
|
const [messages, setMessages] = useState([]);
|
|
30
35
|
const [client, setClient] = useState(null);
|
|
@@ -755,7 +760,7 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
|
|
|
755
760
|
Array.isArray(msg.attachments) && msg.attachments.length > 0 && /* @__PURE__ */ jsx("div", { className: s.attachments, children: msg.attachments.map((att, i) => {
|
|
756
761
|
const file = typeof att.file === "object" ? att.file : null;
|
|
757
762
|
if (!file) return null;
|
|
758
|
-
return (file.mimeType || "").startsWith("image/") ? /* @__PURE__ */ jsx("a", { href: file.url || "#", target: "_blank", rel: "noopener noreferrer", children: /* @__PURE__ */ jsx("img", { src: file.url || "", alt: "", className: s.attachmentImg }) }, i) : /* @__PURE__ */ jsxs("a", { href: file.url || "#", target: "_blank", rel: "noopener noreferrer", className: s.attachmentFile, children: [
|
|
763
|
+
return (file.mimeType || "").startsWith("image/") ? /* @__PURE__ */ jsx("a", { href: file.url || "#", target: "_blank", rel: "noopener noreferrer", children: /* @__PURE__ */ jsx("img", { src: file.url || "", alt: file.filename || t("detail.file"), className: s.attachmentImg }) }, i) : /* @__PURE__ */ jsxs("a", { href: file.url || "#", target: "_blank", rel: "noopener noreferrer", className: s.attachmentFile, children: [
|
|
759
764
|
"PJ ",
|
|
760
765
|
file.filename || "Fichier"
|
|
761
766
|
] }, i);
|
|
@@ -846,7 +851,7 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
|
|
|
846
851
|
"\u{1F4CE} ",
|
|
847
852
|
t("detail.file")
|
|
848
853
|
] }),
|
|
849
|
-
/* @__PURE__ */ jsx("input", { ref: fileInputRef, type: "file", multiple: true, className: s.hiddenFileInput, onChange: (e) => handleFileSelect(e.target.files) }),
|
|
854
|
+
/* @__PURE__ */ jsx("input", { ref: fileInputRef, type: "file", multiple: true, "aria-label": t("detail.file"), className: s.hiddenFileInput, onChange: (e) => handleFileSelect(e.target.files) }),
|
|
850
855
|
macros.length > 0 && /* @__PURE__ */ jsxs(
|
|
851
856
|
"select",
|
|
852
857
|
{
|
|
@@ -920,6 +925,7 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
|
|
|
920
925
|
/* @__PURE__ */ jsxs(
|
|
921
926
|
"select",
|
|
922
927
|
{
|
|
928
|
+
"aria-label": t("detail.sendAs"),
|
|
923
929
|
value: sendAsClient ? "client" : "admin",
|
|
924
930
|
onChange: (e) => {
|
|
925
931
|
const asClient = e.target.value === "client";
|
|
@@ -1132,9 +1138,9 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
|
|
|
1132
1138
|
] }),
|
|
1133
1139
|
/* @__PURE__ */ jsx("div", { className: s.timerBar, "aria-hidden": true, children: /* @__PURE__ */ jsx("div", { className: s.timerBarFill, style: { width: `${Math.min(100, (totalMin + Math.floor(timerSeconds / 60)) / 120 * 100)}%` } }) }),
|
|
1134
1140
|
/* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: 6, marginTop: 8, alignItems: "center" }, children: [
|
|
1135
|
-
/* @__PURE__ */ jsx("input", { type: "number", min: "1", placeholder: "min", style: { width: 60, padding: "4px 8px", borderRadius: 6, border: "1px solid var(--theme-elevation-200)", fontSize: 12, color: "var(--theme-text)", background: "var(--theme-elevation-0)" }, id:
|
|
1141
|
+
/* @__PURE__ */ jsx("input", { type: "number", min: "1", placeholder: "min", "aria-label": t("detail.manualMinutes"), style: { width: 60, padding: "4px 8px", borderRadius: 6, border: "1px solid var(--theme-elevation-200)", fontSize: 12, color: "var(--theme-text)", background: "var(--theme-elevation-0)" }, id: manualTimeId }),
|
|
1136
1142
|
/* @__PURE__ */ jsx("button", { className: `${s.timerBtn} ${s.timerBtnGhost}`, onClick: async () => {
|
|
1137
|
-
const input = document.getElementById(
|
|
1143
|
+
const input = document.getElementById(manualTimeId);
|
|
1138
1144
|
const mins = Number(input?.value);
|
|
1139
1145
|
if (!mins || mins < 1 || !ticketId) return;
|
|
1140
1146
|
try {
|
|
@@ -1145,7 +1151,7 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
|
|
|
1145
1151
|
}
|
|
1146
1152
|
}, style: { fontSize: 11 }, children: t("detail.addTime") })
|
|
1147
1153
|
] }),
|
|
1148
|
-
/* @__PURE__ */ jsxs("div", { style: { marginTop: 8, fontSize: 11, color: "var(--theme-elevation-
|
|
1154
|
+
/* @__PURE__ */ jsxs("div", { style: { marginTop: 8, fontSize: 11, color: "var(--theme-elevation-650)" }, children: [
|
|
1149
1155
|
/* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between", padding: "2px 0", alignItems: "center" }, children: [
|
|
1150
1156
|
/* @__PURE__ */ jsx("span", { children: t("detail.billing.billable") }),
|
|
1151
1157
|
/* @__PURE__ */ jsx(
|
|
@@ -1172,7 +1178,7 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
|
|
|
1172
1178
|
] })
|
|
1173
1179
|
] })
|
|
1174
1180
|
] }),
|
|
1175
|
-
timeEntries.length > 0 && /* @__PURE__ */ jsx("div", { style: { marginTop: 8, fontSize: 11 }, children: timeEntries.slice(0, 6).map((e) => /* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between", padding: "3px 0", color: "var(--theme-elevation-
|
|
1181
|
+
timeEntries.length > 0 && /* @__PURE__ */ jsx("div", { style: { marginTop: 8, fontSize: 11 }, children: timeEntries.slice(0, 6).map((e) => /* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between", padding: "3px 0", color: "var(--theme-elevation-650)" }, children: [
|
|
1176
1182
|
/* @__PURE__ */ jsx("span", { children: new Date(e.date).toLocaleDateString(DATE_LOCALE, { day: "numeric", month: "short" }) }),
|
|
1177
1183
|
/* @__PURE__ */ jsxs("span", { title: e.description, style: { fontWeight: 600, cursor: e.description ? "help" : "default" }, children: [
|
|
1178
1184
|
e.duration,
|
|
@@ -1191,6 +1197,7 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
|
|
|
1191
1197
|
"input",
|
|
1192
1198
|
{
|
|
1193
1199
|
className: s.tagInput,
|
|
1200
|
+
"aria-label": t("detail.addTag"),
|
|
1194
1201
|
value: newTagValue,
|
|
1195
1202
|
onChange: (e) => setNewTagValue(e.target.value),
|
|
1196
1203
|
onKeyDown: (e) => {
|
|
@@ -1211,10 +1218,11 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
|
|
|
1211
1218
|
/* @__PURE__ */ jsx("div", { className: s.sideSectionTitle, children: t("detail.billing.title") }),
|
|
1212
1219
|
/* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: 8 }, children: [
|
|
1213
1220
|
/* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between" }, children: [
|
|
1214
|
-
/* @__PURE__ */ jsx("
|
|
1221
|
+
/* @__PURE__ */ jsx("label", { style: { fontSize: 12 }, htmlFor: billingTypeId, children: t("detail.billing.type") }),
|
|
1215
1222
|
/* @__PURE__ */ jsxs(
|
|
1216
1223
|
"select",
|
|
1217
1224
|
{
|
|
1225
|
+
id: billingTypeId,
|
|
1218
1226
|
value: ticket?.billingType || "hourly",
|
|
1219
1227
|
onChange: async (e) => {
|
|
1220
1228
|
try {
|
|
@@ -1237,11 +1245,12 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
|
|
|
1237
1245
|
)
|
|
1238
1246
|
] }),
|
|
1239
1247
|
ticket?.billingType === "flat" && /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between" }, children: [
|
|
1240
|
-
/* @__PURE__ */ jsx("
|
|
1248
|
+
/* @__PURE__ */ jsx("label", { style: { fontSize: 12 }, htmlFor: flatAmountId, children: t("detail.billing.flatAmount") }),
|
|
1241
1249
|
/* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: 4 }, children: [
|
|
1242
1250
|
/* @__PURE__ */ jsx(
|
|
1243
1251
|
"input",
|
|
1244
1252
|
{
|
|
1253
|
+
id: flatAmountId,
|
|
1245
1254
|
type: "number",
|
|
1246
1255
|
defaultValue: ticket?.flatRateAmount ?? "",
|
|
1247
1256
|
placeholder: "0",
|
|
@@ -1265,11 +1274,12 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
|
|
|
1265
1274
|
] })
|
|
1266
1275
|
] }),
|
|
1267
1276
|
/* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between" }, children: [
|
|
1268
|
-
/* @__PURE__ */ jsx("
|
|
1277
|
+
/* @__PURE__ */ jsx("label", { style: { fontSize: 12 }, htmlFor: billedAmountId, children: t("detail.billing.billedAmount") }),
|
|
1269
1278
|
/* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: 4 }, children: [
|
|
1270
1279
|
/* @__PURE__ */ jsx(
|
|
1271
1280
|
"input",
|
|
1272
1281
|
{
|
|
1282
|
+
id: billedAmountId,
|
|
1273
1283
|
type: "number",
|
|
1274
1284
|
defaultValue: ticket?.billedAmount ?? "",
|
|
1275
1285
|
placeholder: "0",
|
|
@@ -1293,10 +1303,11 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
|
|
|
1293
1303
|
] })
|
|
1294
1304
|
] }),
|
|
1295
1305
|
/* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between" }, children: [
|
|
1296
|
-
/* @__PURE__ */ jsx("
|
|
1306
|
+
/* @__PURE__ */ jsx("label", { style: { fontSize: 12 }, htmlFor: paymentStatusId, children: t("detail.billing.payment") }),
|
|
1297
1307
|
/* @__PURE__ */ jsxs(
|
|
1298
1308
|
"select",
|
|
1299
1309
|
{
|
|
1310
|
+
id: paymentStatusId,
|
|
1300
1311
|
value: ticket?.paymentStatus || "unpaid",
|
|
1301
1312
|
onChange: async (e) => {
|
|
1302
1313
|
try {
|
|
@@ -1382,6 +1393,7 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
|
|
|
1382
1393
|
"input",
|
|
1383
1394
|
{
|
|
1384
1395
|
className: s.splitInput,
|
|
1396
|
+
"aria-label": t("detail.split.subjectLabel"),
|
|
1385
1397
|
value: splitSubject,
|
|
1386
1398
|
onChange: (e) => setSplitSubject(e.target.value),
|
|
1387
1399
|
onKeyDown: (e) => {
|
|
@@ -9,6 +9,7 @@ import { StatusPill } from '../shared/StatusPill.js';
|
|
|
9
9
|
import { computeSlaState, formatSlaRemaining } from '../shared/sla.js';
|
|
10
10
|
import s from '../../styles/TicketInbox.module.scss';
|
|
11
11
|
|
|
12
|
+
const INBOX_TABPANEL_ID = "inbox-tabpanel";
|
|
12
13
|
const PRIORITY_COLORS = {
|
|
13
14
|
urgent: "var(--theme-error-500)",
|
|
14
15
|
high: "var(--theme-warning-500)",
|
|
@@ -213,6 +214,7 @@ const TicketInboxClient = () => {
|
|
|
213
214
|
{
|
|
214
215
|
type: "text",
|
|
215
216
|
className: s.searchInput,
|
|
217
|
+
"aria-label": t("inbox.searchLabel"),
|
|
216
218
|
placeholder: t("inbox.searchPlaceholder"),
|
|
217
219
|
value: search,
|
|
218
220
|
onChange: (e) => setSearch(e.target.value)
|
|
@@ -223,31 +225,55 @@ const TicketInboxClient = () => {
|
|
|
223
225
|
/* @__PURE__ */ jsx(Link, { href: "/admin/support/new-ticket", className: s.newTicketBtn, children: t("inbox.newTicketBtn") })
|
|
224
226
|
] })
|
|
225
227
|
] }),
|
|
226
|
-
/* @__PURE__ */ jsx(
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
228
|
+
/* @__PURE__ */ jsx(
|
|
229
|
+
"div",
|
|
230
|
+
{
|
|
231
|
+
className: s.tabs,
|
|
232
|
+
role: "tablist",
|
|
233
|
+
"aria-label": t("inbox.tabsLabel"),
|
|
234
|
+
onKeyDown: (e) => {
|
|
235
|
+
const keys = ["ArrowLeft", "ArrowRight", "Home", "End"];
|
|
236
|
+
if (!keys.includes(e.key)) return;
|
|
237
|
+
e.preventDefault();
|
|
238
|
+
const i = tabs.findIndex((tk) => tk.key === tab);
|
|
239
|
+
const next = e.key === "Home" ? 0 : e.key === "End" ? tabs.length - 1 : e.key === "ArrowLeft" ? (i - 1 + tabs.length) % tabs.length : (i + 1) % tabs.length;
|
|
240
|
+
const target = tabs[next];
|
|
241
|
+
if (!target) return;
|
|
242
|
+
setTab(target.key);
|
|
243
|
+
setSelectedIdx(-1);
|
|
244
|
+
document.getElementById(`inbox-tab-${target.key}`)?.focus();
|
|
242
245
|
},
|
|
243
|
-
tk
|
|
244
|
-
|
|
245
|
-
|
|
246
|
+
children: tabs.map((tk) => {
|
|
247
|
+
const isAlert = tk.alert && tk.count > 0;
|
|
248
|
+
return /* @__PURE__ */ jsxs(
|
|
249
|
+
"button",
|
|
250
|
+
{
|
|
251
|
+
type: "button",
|
|
252
|
+
role: "tab",
|
|
253
|
+
id: `inbox-tab-${tk.key}`,
|
|
254
|
+
"aria-selected": tab === tk.key,
|
|
255
|
+
"aria-controls": INBOX_TABPANEL_ID,
|
|
256
|
+
tabIndex: tab === tk.key ? 0 : -1,
|
|
257
|
+
className: `${s.tab} ${tab === tk.key ? s.tabActive : ""} ${isAlert ? s.tabAlert : ""}`,
|
|
258
|
+
onClick: () => {
|
|
259
|
+
setTab(tk.key);
|
|
260
|
+
setSelectedIdx(-1);
|
|
261
|
+
},
|
|
262
|
+
children: [
|
|
263
|
+
tk.label,
|
|
264
|
+
/* @__PURE__ */ jsx("span", { className: `${s.tabCount} ${isAlert ? s.tabCountAlert : ""}`, children: tk.count })
|
|
265
|
+
]
|
|
266
|
+
},
|
|
267
|
+
tk.key
|
|
268
|
+
);
|
|
269
|
+
})
|
|
270
|
+
}
|
|
271
|
+
),
|
|
246
272
|
/* @__PURE__ */ jsx("div", { className: s.sortRow, children: checkedIds.size > 0 ? /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: 8, alignItems: "center", flex: 1 }, children: [
|
|
247
273
|
/* @__PURE__ */ jsx("span", { style: { fontSize: 13, fontWeight: 600, color: "var(--theme-text)" }, children: checkedIds.size > 1 ? t("inbox.selectedPlural", { count: String(checkedIds.size) }) : t("inbox.selected", { count: String(checkedIds.size) }) }),
|
|
248
|
-
/* @__PURE__ */ jsx("button", { className: s.sortSelect, onClick: () => handleBulkAction("close"), disabled: bulkProcessing, children: t("inbox.closeAction") }),
|
|
249
|
-
/* @__PURE__ */ jsx("button", { className: s.sortSelect, onClick: () => handleBulkAction("reopen"), disabled: bulkProcessing, children: t("inbox.reopenAction") }),
|
|
250
|
-
/* @__PURE__ */ jsxs("select", { className: s.sortSelect, value: bulkAction, onChange: (e) => {
|
|
274
|
+
/* @__PURE__ */ jsx("button", { type: "button", className: s.sortSelect, onClick: () => handleBulkAction("close"), disabled: bulkProcessing, children: t("inbox.closeAction") }),
|
|
275
|
+
/* @__PURE__ */ jsx("button", { type: "button", className: s.sortSelect, onClick: () => handleBulkAction("reopen"), disabled: bulkProcessing, children: t("inbox.reopenAction") }),
|
|
276
|
+
/* @__PURE__ */ jsxs("select", { className: s.sortSelect, "aria-label": t("inbox.moreActions"), value: bulkAction, onChange: (e) => {
|
|
251
277
|
if (e.target.value) handleBulkAction(e.target.value);
|
|
252
278
|
setBulkAction("");
|
|
253
279
|
}, children: [
|
|
@@ -255,14 +281,14 @@ const TicketInboxClient = () => {
|
|
|
255
281
|
/* @__PURE__ */ jsx("option", { value: "set_priority", children: t("inbox.changePriority") }),
|
|
256
282
|
/* @__PURE__ */ jsx("option", { value: "delete", children: t("inbox.deleteAction") })
|
|
257
283
|
] }),
|
|
258
|
-
/* @__PURE__ */ jsx("button", { className: s.sortSelect, onClick: () => setCheckedIds(/* @__PURE__ */ new Set()), style: { marginLeft: "auto" }, children: t("inbox.deselect") })
|
|
259
|
-
] }) : /* @__PURE__ */ jsxs("select", { className: s.sortSelect, value: sort, onChange: (e) => setSort(e.target.value), children: [
|
|
284
|
+
/* @__PURE__ */ jsx("button", { type: "button", className: s.sortSelect, onClick: () => setCheckedIds(/* @__PURE__ */ new Set()), style: { marginLeft: "auto" }, children: t("inbox.deselect") })
|
|
285
|
+
] }) : /* @__PURE__ */ jsxs("select", { className: s.sortSelect, "aria-label": t("inbox.sortLabel"), value: sort, onChange: (e) => setSort(e.target.value), children: [
|
|
260
286
|
/* @__PURE__ */ jsx("option", { value: "-updatedAt", children: t("inbox.sort.newest") }),
|
|
261
287
|
/* @__PURE__ */ jsx("option", { value: "updatedAt", children: t("inbox.sort.oldest") }),
|
|
262
288
|
/* @__PURE__ */ jsx("option", { value: "-createdAt", children: t("inbox.sort.created") }),
|
|
263
289
|
/* @__PURE__ */ jsx("option", { value: "priority", children: t("inbox.sort.priority") })
|
|
264
290
|
] }) }),
|
|
265
|
-
loading ? /* @__PURE__ */ jsx("div", { className: s.loading, children: t("common.loading") }) : tickets.length === 0 ? /* @__PURE__ */ jsxs("div", { className: s.empty, children: [
|
|
291
|
+
/* @__PURE__ */ jsx("div", { role: "tabpanel", id: INBOX_TABPANEL_ID, "aria-labelledby": `inbox-tab-${tab}`, children: loading ? /* @__PURE__ */ jsx("div", { className: s.loading, children: t("common.loading") }) : tickets.length === 0 ? /* @__PURE__ */ jsxs("div", { className: s.empty, children: [
|
|
266
292
|
/* @__PURE__ */ jsx("div", { className: s.emptyIcon, children: "--" }),
|
|
267
293
|
/* @__PURE__ */ jsx("div", { className: s.emptyText, children: t("inbox.empty") })
|
|
268
294
|
] }) : /* @__PURE__ */ jsx("div", { className: s.list, children: tickets.map((tk, idx) => {
|
|
@@ -333,7 +359,7 @@ const TicketInboxClient = () => {
|
|
|
333
359
|
},
|
|
334
360
|
tk.id
|
|
335
361
|
);
|
|
336
|
-
}) }),
|
|
362
|
+
}) }) }),
|
|
337
363
|
/* @__PURE__ */ jsxs("div", { className: s.keyboardHints, children: [
|
|
338
364
|
/* @__PURE__ */ jsxs("span", { children: [
|
|
339
365
|
/* @__PURE__ */ jsx("kbd", { children: "\u2191" }),
|
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
|
|
71
71
|
.sectionDescription {
|
|
72
72
|
font-size: 0.8125rem;
|
|
73
|
-
color: var(--theme-elevation-
|
|
73
|
+
color: var(--theme-elevation-650);
|
|
74
74
|
margin: 0 0 1rem;
|
|
75
75
|
line-height: 1.5;
|
|
76
76
|
}
|
|
@@ -143,7 +143,7 @@
|
|
|
143
143
|
|
|
144
144
|
.featureDesc {
|
|
145
145
|
font-size: 0.75rem;
|
|
146
|
-
color: var(--theme-elevation-
|
|
146
|
+
color: var(--theme-elevation-650);
|
|
147
147
|
margin-top: 0.125rem;
|
|
148
148
|
}
|
|
149
149
|
|
|
@@ -166,7 +166,7 @@
|
|
|
166
166
|
|
|
167
167
|
.fieldDescription {
|
|
168
168
|
font-size: 0.75rem;
|
|
169
|
-
color: var(--theme-elevation-
|
|
169
|
+
color: var(--theme-elevation-650);
|
|
170
170
|
font-weight: 400;
|
|
171
171
|
margin-top: 0.125rem;
|
|
172
172
|
}
|
|
@@ -194,7 +194,7 @@
|
|
|
194
194
|
.inputReadonly {
|
|
195
195
|
composes: input;
|
|
196
196
|
background: var(--theme-elevation-50);
|
|
197
|
-
color: var(--theme-elevation-
|
|
197
|
+
color: var(--theme-elevation-650);
|
|
198
198
|
cursor: not-allowed;
|
|
199
199
|
}
|
|
200
200
|
|
|
@@ -230,7 +230,7 @@
|
|
|
230
230
|
|
|
231
231
|
.inlineDesc {
|
|
232
232
|
font-size: 0.75rem;
|
|
233
|
-
color: var(--theme-elevation-
|
|
233
|
+
color: var(--theme-elevation-650);
|
|
234
234
|
margin-top: 0.125rem;
|
|
235
235
|
}
|
|
236
236
|
|
|
@@ -244,7 +244,7 @@
|
|
|
244
244
|
|
|
245
245
|
.slaHint {
|
|
246
246
|
font-size: 0.75rem;
|
|
247
|
-
color: var(--theme-elevation-
|
|
247
|
+
color: var(--theme-elevation-650);
|
|
248
248
|
}
|
|
249
249
|
|
|
250
250
|
// ── API Key ───────────────────────────────────
|
|
@@ -290,7 +290,7 @@
|
|
|
290
290
|
.aiToggleDesc {
|
|
291
291
|
display: block;
|
|
292
292
|
font-size: 0.6875rem;
|
|
293
|
-
color: var(--theme-elevation-
|
|
293
|
+
color: var(--theme-elevation-650);
|
|
294
294
|
}
|
|
295
295
|
|
|
296
296
|
// ── Signature ─────────────────────────────────
|