@consilioweb/payload-support 2.0.0 → 3.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.
Files changed (222) hide show
  1. package/README.md +656 -355
  2. package/dist/components/RichTextEditor/index.d.ts +19 -0
  3. package/dist/components/TicketConversation/RewriteDropdown.d.ts +6 -0
  4. package/dist/components/TicketConversation/SkeletonText.d.ts +4 -0
  5. package/dist/components/TicketConversation/components/AISummaryPanel.d.ts +14 -0
  6. package/dist/components/TicketConversation/components/ActionPanels.d.ts +47 -0
  7. package/dist/components/TicketConversation/components/ActivityLog.d.ts +5 -0
  8. package/dist/components/TicketConversation/components/ClientBar.d.ts +5 -0
  9. package/dist/components/TicketConversation/components/ClientHistory.d.ts +24 -0
  10. package/dist/components/TicketConversation/components/CodeBlock.d.ts +26 -0
  11. package/dist/components/TicketConversation/components/CodeBlockInserter.d.ts +12 -0
  12. package/dist/components/TicketConversation/components/QuickActions.d.ts +32 -0
  13. package/dist/components/TicketConversation/components/TicketHeader.d.ts +19 -0
  14. package/dist/components/TicketConversation/components/TimeTrackingPanel.d.ts +24 -0
  15. package/dist/components/TicketConversation/config.d.ts +10 -0
  16. package/dist/components/TicketConversation/config.js +1 -40
  17. package/dist/components/TicketConversation/constants.d.ts +56 -0
  18. package/dist/components/TicketConversation/context.d.ts +53 -0
  19. package/dist/components/TicketConversation/hooks/useAI.d.ts +21 -0
  20. package/dist/components/TicketConversation/hooks/useDocumentIdFromUrl.d.ts +3 -0
  21. package/dist/components/TicketConversation/hooks/useFeatures.d.ts +23 -0
  22. package/dist/components/TicketConversation/hooks/useFeatures.js +61 -0
  23. package/dist/components/TicketConversation/hooks/useMessageActions.d.ts +20 -0
  24. package/dist/components/TicketConversation/hooks/useReply.d.ts +27 -0
  25. package/dist/components/TicketConversation/hooks/useTicketActions.d.ts +58 -0
  26. package/dist/components/TicketConversation/hooks/useTimeTracking.d.ts +18 -0
  27. package/dist/components/TicketConversation/hooks/useTranslation.d.ts +33 -0
  28. package/dist/components/TicketConversation/hooks/useTranslation.js +22 -3
  29. package/dist/components/TicketConversation/index.d.ts +4 -0
  30. package/dist/components/TicketConversation/index.js +2 -2
  31. package/dist/components/TicketConversation/types.d.ts +56 -0
  32. package/dist/components/TicketConversation/utils.d.ts +2 -0
  33. package/dist/index.cjs +392 -320
  34. package/dist/index.d.cts +100 -3
  35. package/dist/index.d.ts +100 -3
  36. package/dist/index.js +388 -321
  37. package/dist/utils/features.d.ts +123 -0
  38. package/dist/utils/features.js +147 -0
  39. package/dist/views/BillingView/client.d.ts +2 -0
  40. package/dist/views/BillingView/index.d.ts +4 -0
  41. package/dist/views/ChatView/client.d.ts +2 -0
  42. package/dist/views/ChatView/client.js +9 -9
  43. package/dist/views/ChatView/index.d.ts +4 -0
  44. package/dist/views/CrmView/client.d.ts +2 -0
  45. package/dist/views/CrmView/client.js +6 -9
  46. package/dist/views/CrmView/index.d.ts +4 -0
  47. package/dist/views/EmailTrackingView/client.d.ts +2 -0
  48. package/dist/views/EmailTrackingView/index.d.ts +4 -0
  49. package/dist/views/ImportConversationView/client.d.ts +2 -0
  50. package/dist/views/ImportConversationView/index.d.ts +4 -0
  51. package/dist/views/LogsView/client.d.ts +2 -0
  52. package/dist/views/LogsView/index.d.ts +4 -0
  53. package/dist/views/NewTicketView/client.d.ts +2 -0
  54. package/dist/views/NewTicketView/index.d.ts +4 -0
  55. package/dist/views/PendingEmailsView/client.d.ts +2 -0
  56. package/dist/views/PendingEmailsView/index.d.ts +4 -0
  57. package/dist/views/SupportDashboardView/client.d.ts +2 -0
  58. package/dist/views/SupportDashboardView/client.js +1 -1
  59. package/dist/views/SupportDashboardView/index.d.ts +4 -0
  60. package/dist/views/TicketDetailView/NextActionItem.d.ts +6 -0
  61. package/dist/views/TicketDetailView/RewriteDropdown.d.ts +7 -0
  62. package/dist/views/TicketDetailView/client.d.ts +2 -0
  63. package/dist/views/TicketDetailView/client.js +2 -2
  64. package/dist/views/TicketDetailView/constants.d.ts +13 -0
  65. package/dist/views/TicketDetailView/helpers.d.ts +2 -0
  66. package/dist/views/TicketDetailView/index.d.ts +4 -0
  67. package/dist/views/TicketDetailView/types.d.ts +40 -0
  68. package/dist/views/TicketInboxView/client.d.ts +2 -0
  69. package/dist/views/TicketInboxView/client.js +5 -5
  70. package/dist/views/TicketInboxView/index.d.ts +4 -0
  71. package/dist/views/TicketingSettingsView/client.d.ts +2 -0
  72. package/dist/views/TicketingSettingsView/client.js +6 -5
  73. package/dist/views/TicketingSettingsView/index.d.ts +4 -0
  74. package/dist/views/TimeDashboardView/client.d.ts +2 -0
  75. package/dist/views/TimeDashboardView/index.d.ts +4 -0
  76. package/dist/views/shared/AdminViewHeader.d.ts +13 -0
  77. package/dist/views/shared/ErrorBoundary.d.ts +17 -0
  78. package/dist/views/shared/Skeleton.d.ts +21 -0
  79. package/dist/views/shared/StatusPill.d.ts +8 -0
  80. package/dist/views/shared/adminTokens.d.ts +19 -0
  81. package/dist/views/shared/config.d.ts +8 -0
  82. package/dist/views/shared/config.js +1 -40
  83. package/dist/views/shared/dateLocale.d.ts +5 -0
  84. package/dist/views/shared/index.d.ts +12 -0
  85. package/dist/views/shared/index.js +2 -1
  86. package/dist/views/shared/locales/en.json +708 -0
  87. package/dist/views/shared/locales/fr.json +708 -0
  88. package/dist/views/shared/sla.d.ts +14 -0
  89. package/dist/views.d.ts +13 -13
  90. package/package.json +26 -41
  91. package/src/collections/SupportClients.ts +29 -0
  92. package/src/collections/TicketCollaborators.ts +6 -1
  93. package/src/collections/TicketMessages.ts +46 -24
  94. package/src/collections/Tickets.ts +117 -79
  95. package/src/collections/TimeEntries.ts +57 -32
  96. package/src/components/TicketConversation/config.ts +16 -80
  97. package/src/components/TicketConversation/hooks/useFeatures.ts +109 -0
  98. package/src/components/TicketConversation/hooks/useTranslation.ts +38 -4
  99. package/src/components/TicketConversation/index.tsx +2 -2
  100. package/src/endpoints/ai.ts +2 -1
  101. package/src/endpoints/client-intelligence.ts +2 -1
  102. package/src/endpoints/process-scheduled.ts +13 -8
  103. package/src/endpoints/round-robin-config.ts +30 -20
  104. package/src/endpoints/settings.ts +28 -77
  105. package/src/index.ts +6 -2
  106. package/src/portal/LiveChat.tsx +33 -22
  107. package/src/portal/auth/tickets/detail/TicketPolling.tsx +5 -1
  108. package/src/types/lucide-react.d.ts +10 -2
  109. package/src/utils/aiAgent.ts +2 -1
  110. package/src/utils/aiProvider.ts +21 -0
  111. package/src/utils/features.ts +297 -0
  112. package/src/utils/fireWebhooks.ts +6 -0
  113. package/src/utils/generateTicketSynthesis.ts +2 -1
  114. package/src/utils/index.ts +4 -2
  115. package/src/utils/readSettings.ts +82 -9
  116. package/src/utils/webhookDispatcher.ts +19 -7
  117. package/src/views/ChatView/client.tsx +13 -9
  118. package/src/views/CrmView/client.tsx +10 -11
  119. package/src/views/SupportDashboardView/client.tsx +1 -1
  120. package/src/views/TicketDetailView/client.tsx +2 -2
  121. package/src/views/TicketInboxView/client.tsx +10 -5
  122. package/src/views/TicketingSettingsView/client.tsx +9 -7
  123. package/src/views/shared/config.ts +14 -80
  124. package/src/views/shared/index.ts +3 -1
  125. package/src/views/shared/locales/en.json +2 -2
  126. package/src/views/shared/locales/fr.json +2 -2
  127. package/dist/components/RichTextEditor/index.cjs +0 -279
  128. package/dist/components/TicketConversation/RewriteDropdown.cjs +0 -98
  129. package/dist/components/TicketConversation/SkeletonText.cjs +0 -21
  130. package/dist/components/TicketConversation/components/AISummaryPanel.cjs +0 -85
  131. package/dist/components/TicketConversation/components/ActionPanels.cjs +0 -193
  132. package/dist/components/TicketConversation/components/ActivityLog.cjs +0 -24
  133. package/dist/components/TicketConversation/components/ClientBar.cjs +0 -43
  134. package/dist/components/TicketConversation/components/ClientHistory.cjs +0 -138
  135. package/dist/components/TicketConversation/components/CodeBlock.cjs +0 -171
  136. package/dist/components/TicketConversation/components/CodeBlockInserter.cjs +0 -156
  137. package/dist/components/TicketConversation/components/QuickActions.cjs +0 -87
  138. package/dist/components/TicketConversation/components/TicketHeader.cjs +0 -93
  139. package/dist/components/TicketConversation/components/TimeTrackingPanel.cjs +0 -134
  140. package/dist/components/TicketConversation/config.cjs +0 -44
  141. package/dist/components/TicketConversation/constants.cjs +0 -127
  142. package/dist/components/TicketConversation/context.cjs +0 -13
  143. package/dist/components/TicketConversation/hooks/useAI.cjs +0 -196
  144. package/dist/components/TicketConversation/hooks/useDocumentIdFromUrl.cjs +0 -20
  145. package/dist/components/TicketConversation/hooks/useMessageActions.cjs +0 -136
  146. package/dist/components/TicketConversation/hooks/useReply.cjs +0 -188
  147. package/dist/components/TicketConversation/hooks/useTicketActions.cjs +0 -290
  148. package/dist/components/TicketConversation/hooks/useTimeTracking.cjs +0 -123
  149. package/dist/components/TicketConversation/hooks/useTranslation.cjs +0 -78
  150. package/dist/components/TicketConversation/index.cjs +0 -1114
  151. package/dist/components/TicketConversation/types.cjs +0 -2
  152. package/dist/components/TicketConversation/utils.cjs +0 -27
  153. package/dist/views/BillingView/client.cjs +0 -469
  154. package/dist/views/BillingView/index.cjs +0 -34
  155. package/dist/views/ChatView/client.cjs +0 -301
  156. package/dist/views/ChatView/index.cjs +0 -34
  157. package/dist/views/CrmView/client.cjs +0 -458
  158. package/dist/views/CrmView/index.cjs +0 -34
  159. package/dist/views/EmailTrackingView/client.cjs +0 -171
  160. package/dist/views/EmailTrackingView/index.cjs +0 -34
  161. package/dist/views/ImportConversationView/client.cjs +0 -238
  162. package/dist/views/ImportConversationView/index.cjs +0 -34
  163. package/dist/views/LogsView/client.cjs +0 -148
  164. package/dist/views/LogsView/index.cjs +0 -32
  165. package/dist/views/NewTicketView/client.cjs +0 -213
  166. package/dist/views/NewTicketView/index.cjs +0 -32
  167. package/dist/views/PendingEmailsView/client.cjs +0 -471
  168. package/dist/views/PendingEmailsView/index.cjs +0 -34
  169. package/dist/views/SupportDashboardView/client.cjs +0 -437
  170. package/dist/views/SupportDashboardView/index.cjs +0 -34
  171. package/dist/views/TicketDetailView/NextActionItem.cjs +0 -40
  172. package/dist/views/TicketDetailView/RewriteDropdown.cjs +0 -80
  173. package/dist/views/TicketDetailView/client.cjs +0 -1412
  174. package/dist/views/TicketDetailView/constants.cjs +0 -20
  175. package/dist/views/TicketDetailView/helpers.cjs +0 -23
  176. package/dist/views/TicketDetailView/index.cjs +0 -34
  177. package/dist/views/TicketDetailView/types.cjs +0 -2
  178. package/dist/views/TicketInboxView/client.cjs +0 -359
  179. package/dist/views/TicketInboxView/index.cjs +0 -32
  180. package/dist/views/TicketingSettingsView/client.cjs +0 -740
  181. package/dist/views/TicketingSettingsView/index.cjs +0 -34
  182. package/dist/views/TimeDashboardView/client.cjs +0 -180
  183. package/dist/views/TimeDashboardView/index.cjs +0 -34
  184. package/dist/views/shared/AdminViewHeader.cjs +0 -68
  185. package/dist/views/shared/ErrorBoundary.cjs +0 -55
  186. package/dist/views/shared/Skeleton.cjs +0 -77
  187. package/dist/views/shared/StatusPill.cjs +0 -47
  188. package/dist/views/shared/adminTokens.cjs +0 -34
  189. package/dist/views/shared/config.cjs +0 -44
  190. package/dist/views/shared/dateLocale.cjs +0 -5
  191. package/dist/views/shared/index.cjs +0 -72
  192. package/dist/views/shared/sla.cjs +0 -37
  193. package/dist/views.cjs +0 -86
  194. package/dist/views.d.cts +0 -13
  195. package/src/__tests__/aiSummaryRendering.test.ts +0 -21
  196. package/src/__tests__/authResponses.test.ts +0 -69
  197. package/src/__tests__/capabilities.test.ts +0 -71
  198. package/src/__tests__/generateTrackingToken.test.ts +0 -67
  199. package/src/__tests__/integration/ai-agent.test.ts +0 -46
  200. package/src/__tests__/integration/auth.test.ts +0 -43
  201. package/src/__tests__/integration/automation-rules.test.ts +0 -68
  202. package/src/__tests__/integration/buildTestPayload.ts +0 -52
  203. package/src/__tests__/integration/channels.test.ts +0 -52
  204. package/src/__tests__/integration/core-behaviors.test.ts +0 -81
  205. package/src/__tests__/integration/dashboard-volume.test.ts +0 -31
  206. package/src/__tests__/integration/digest.test.ts +0 -48
  207. package/src/__tests__/integration/invoice-pdf.test.ts +0 -30
  208. package/src/__tests__/integration/isolation.test.ts +0 -81
  209. package/src/__tests__/integration/mentions-invoice.test.ts +0 -50
  210. package/src/__tests__/integration/nps.test.ts +0 -37
  211. package/src/__tests__/integration/per-team-sla.test.ts +0 -44
  212. package/src/__tests__/integration/push.test.ts +0 -75
  213. package/src/__tests__/integration/sanitization.test.ts +0 -35
  214. package/src/__tests__/integration/sla-pause.test.ts +0 -39
  215. package/src/__tests__/integration/smoke.test.ts +0 -26
  216. package/src/__tests__/integration/snooze.test.ts +0 -68
  217. package/src/__tests__/integration/teams.test.ts +0 -38
  218. package/src/__tests__/rateLimiter.test.ts +0 -83
  219. package/src/__tests__/sanitizeHtml.test.ts +0 -165
  220. package/src/__tests__/sla.test.ts +0 -258
  221. package/src/__tests__/trackOpenEndpoint.test.ts +0 -54
  222. package/src/__tests__/webhookSecurity.test.ts +0 -58
@@ -1,20 +0,0 @@
1
- 'use strict';
2
-
3
- const ALIASES = (process.env.NEXT_PUBLIC_SUPPORT_SEND_ALIASES || "").split(",").map((v) => v.trim()).filter(Boolean).map((value) => ({ value, label: `En tant que : ${value}` }));
4
- const STATUS_STYLE = {
5
- open: { bg: "#dbeafe", color: "#1e40af" },
6
- waiting_client: { bg: "#fef3c7", color: "#92400e" },
7
- resolved: { bg: "#dcfce7", color: "#166534" }
8
- };
9
- const REWRITE_STYLES = [
10
- { id: "auto", label: "\u270F\uFE0F Auto", desc: "Garde le ton actuel" },
11
- { id: "tutoyer", label: "\u{1F44B} Tutoyer", desc: "Passe en tu" },
12
- { id: "vouvoyer", label: "\u{1F3A9} Vouvoyer", desc: "Passe en vous" },
13
- { id: "formel", label: "\u{1F4BC} Formel", desc: "Ton professionnel" },
14
- { id: "amical", label: "\u{1F60A} Amical", desc: "Ton chaleureux" },
15
- { id: "court", label: "\u26A1 Court", desc: "Version concise" }
16
- ];
17
-
18
- exports.ALIASES = ALIASES;
19
- exports.REWRITE_STYLES = REWRITE_STYLES;
20
- exports.STATUS_STYLE = STATUS_STYLE;
@@ -1,23 +0,0 @@
1
- 'use strict';
2
-
3
- var dateLocale = require('../shared/dateLocale');
4
-
5
- function timeAgo(d) {
6
- const date = new Date(d), now = /* @__PURE__ */ new Date();
7
- if (date.toDateString() === now.toDateString()) return date.toLocaleTimeString(dateLocale.DATE_LOCALE, { hour: "2-digit", minute: "2-digit" });
8
- const y = new Date(now);
9
- y.setDate(y.getDate() - 1);
10
- if (date.toDateString() === y.toDateString()) return `Hier, ${date.toLocaleTimeString(dateLocale.DATE_LOCALE, { hour: "2-digit", minute: "2-digit" })}`;
11
- return date.toLocaleDateString(dateLocale.DATE_LOCALE, { day: "numeric", month: "short", hour: "2-digit", minute: "2-digit" });
12
- }
13
- function dateLabel(d) {
14
- const date = new Date(d), now = /* @__PURE__ */ new Date();
15
- if (date.toDateString() === now.toDateString()) return "Aujourd'hui";
16
- const y = new Date(now);
17
- y.setDate(y.getDate() - 1);
18
- if (date.toDateString() === y.toDateString()) return "Hier";
19
- return date.toLocaleDateString(dateLocale.DATE_LOCALE, { day: "numeric", month: "long" });
20
- }
21
-
22
- exports.dateLabel = dateLabel;
23
- exports.timeAgo = timeAgo;
@@ -1,34 +0,0 @@
1
- 'use strict';
2
-
3
- Object.defineProperty(exports, '__esModule', { value: true });
4
-
5
- var jsxRuntime = require('react/jsx-runtime');
6
- var templates = require('@payloadcms/next/templates');
7
- var navigation = require('next/navigation');
8
- var ErrorBoundary = require('../shared/ErrorBoundary');
9
- var client = require('./client');
10
-
11
- const TicketDetailView = ({ initPageResult }) => {
12
- const { req, visibleEntities } = initPageResult;
13
- if (!req.user) {
14
- navigation.redirect("/admin/login");
15
- }
16
- return /* @__PURE__ */ jsxRuntime.jsx(
17
- templates.DefaultTemplate,
18
- {
19
- i18n: req.i18n,
20
- locale: initPageResult.locale,
21
- params: {},
22
- payload: req.payload,
23
- permissions: initPageResult.permissions,
24
- searchParams: {},
25
- user: req.user,
26
- visibleEntities,
27
- children: /* @__PURE__ */ jsxRuntime.jsx(ErrorBoundary.AdminErrorBoundary, { viewName: "TicketDetailView", children: /* @__PURE__ */ jsxRuntime.jsx(client.TicketDetailClient, {}) })
28
- }
29
- );
30
- };
31
- var TicketDetailView_default = TicketDetailView;
32
-
33
- exports.TicketDetailView = TicketDetailView;
34
- exports.default = TicketDetailView_default;
@@ -1,2 +0,0 @@
1
- 'use strict';
2
-
@@ -1,359 +0,0 @@
1
- 'use strict';
2
-
3
- var jsxRuntime = require('react/jsx-runtime');
4
- var react = require('react');
5
- var navigation = require('next/navigation');
6
- var Link = require('next/link');
7
- var useTranslation = require('../../components/TicketConversation/hooks/useTranslation');
8
- var dateLocale = require('../shared/dateLocale');
9
- var StatusPill = require('../shared/StatusPill');
10
- var sla = require('../shared/sla');
11
- var s = require('../../styles/TicketInbox.module.scss');
12
-
13
- function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
14
-
15
- var Link__default = /*#__PURE__*/_interopDefault(Link);
16
- var s__default = /*#__PURE__*/_interopDefault(s);
17
-
18
- const PRIORITY_COLORS = {
19
- urgent: "var(--theme-error-500)",
20
- high: "var(--theme-warning-500)",
21
- normal: "var(--theme-info-500, #2a6bd8)",
22
- low: "var(--theme-elevation-400)"
23
- };
24
- const STATUS_VARIANT = {
25
- open: "open",
26
- waiting_client: "pending",
27
- pending: "pending",
28
- resolved: "resolved",
29
- closed: "closed"
30
- };
31
- function relativeTime(dateStr, tFn) {
32
- const diff = Date.now() - new Date(dateStr).getTime();
33
- const mins = Math.floor(diff / 6e4);
34
- if (mins < 1) return tFn("inbox.timeAgo.now");
35
- if (mins < 60) return `${mins}m`;
36
- const hours = Math.floor(mins / 60);
37
- if (hours < 24) return `${hours}h`;
38
- const days = Math.floor(hours / 24);
39
- if (days < 7) return `${days}j`;
40
- return new Date(dateStr).toLocaleDateString(dateLocale.DATE_LOCALE, { day: "numeric", month: "short" });
41
- }
42
- const TicketInboxClient = () => {
43
- const { t } = useTranslation.useTranslation();
44
- const searchParams = navigation.useSearchParams();
45
- const [tickets, setTickets] = react.useState([]);
46
- const [loading, setLoading] = react.useState(true);
47
- const [tab, setTab] = react.useState(() => {
48
- const urlTab = searchParams.get("tab");
49
- if (urlTab && ["all", "open", "waiting_client", "resolved", "sla_breach"].includes(urlTab)) return urlTab;
50
- return "all";
51
- });
52
- react.useEffect(() => {
53
- const urlTab = searchParams.get("tab");
54
- if (urlTab && ["all", "open", "waiting_client", "resolved", "sla_breach"].includes(urlTab)) {
55
- setTab(urlTab);
56
- } else if (!urlTab) {
57
- setTab("all");
58
- }
59
- }, [searchParams]);
60
- const [search, setSearch] = react.useState("");
61
- const [sort, setSort] = react.useState("-updatedAt");
62
- const [counts, setCounts] = react.useState({ all: 0, open: 0, waiting: 0, resolved: 0, breach: 0 });
63
- const [selectedIdx, setSelectedIdx] = react.useState(-1);
64
- const [checkedIds, setCheckedIds] = react.useState(/* @__PURE__ */ new Set());
65
- const [bulkAction, setBulkAction] = react.useState("");
66
- const [bulkProcessing, setBulkProcessing] = react.useState(false);
67
- const toggleCheck = (id) => {
68
- setCheckedIds((prev) => {
69
- const next = new Set(prev);
70
- if (next.has(id)) next.delete(id);
71
- else next.add(id);
72
- return next;
73
- });
74
- };
75
- const handleBulkAction = async (action) => {
76
- if (checkedIds.size === 0) return;
77
- setBulkProcessing(true);
78
- try {
79
- const res = await fetch("/api/support/bulk-action", {
80
- method: "POST",
81
- headers: { "Content-Type": "application/json" },
82
- credentials: "include",
83
- body: JSON.stringify({ ticketIds: Array.from(checkedIds), action })
84
- });
85
- if (res.ok) {
86
- setCheckedIds(/* @__PURE__ */ new Set());
87
- setBulkAction("");
88
- fetchTickets();
89
- }
90
- } catch {
91
- }
92
- setBulkProcessing(false);
93
- };
94
- const fetchTickets = react.useCallback(async () => {
95
- const params = [
96
- `limit=30`,
97
- `sort=${sort}`,
98
- `depth=1`,
99
- `select[id]=true`,
100
- `select[ticketNumber]=true`,
101
- `select[subject]=true`,
102
- `select[status]=true`,
103
- `select[priority]=true`,
104
- `select[category]=true`,
105
- `select[client]=true`,
106
- `select[updatedAt]=true`,
107
- `select[lastClientMessageAt]=true`,
108
- `select[lastAdminReadAt]=true`,
109
- `select[slaFirstResponseDue]=true`,
110
- `select[slaFirstResponseBreached]=true`,
111
- `select[slaResolutionDue]=true`,
112
- `select[slaResolutionBreached]=true`,
113
- `select[firstResponseAt]=true`
114
- ];
115
- if (tab === "sla_breach") {
116
- params.push(`where[or][0][slaFirstResponseBreached][equals]=true`);
117
- params.push(`where[or][1][slaResolutionBreached][equals]=true`);
118
- } else if (tab !== "all") {
119
- params.push(`where[status][equals]=${tab}`);
120
- }
121
- if (search.trim()) {
122
- params.push(`where[or][0][subject][contains]=${encodeURIComponent(search)}`);
123
- params.push(`where[or][1][ticketNumber][contains]=${encodeURIComponent(search)}`);
124
- }
125
- params.push(`where[and][0][or][0][snoozeUntil][exists]=false`);
126
- params.push(`where[and][0][or][1][snoozeUntil][less_than_equal]=${encodeURIComponent((/* @__PURE__ */ new Date()).toISOString())}`);
127
- try {
128
- const url = `/api/tickets?${params.join("&")}`;
129
- const res = await fetch(url, { credentials: "include" });
130
- if (res.ok) {
131
- const d = await res.json();
132
- setTickets(d.docs || []);
133
- } else {
134
- console.error("[inbox] Fetch failed:", res.status, await res.text().catch(() => ""));
135
- }
136
- } catch (err) {
137
- console.error("[inbox] Fetch error:", err);
138
- }
139
- setLoading(false);
140
- }, [tab, sort, search]);
141
- react.useEffect(() => {
142
- setLoading(true);
143
- fetchTickets();
144
- }, [fetchTickets]);
145
- react.useEffect(() => {
146
- const fetchCounts = async () => {
147
- try {
148
- const sn = `where[and][0][or][0][snoozeUntil][exists]=false&where[and][0][or][1][snoozeUntil][less_than_equal]=${encodeURIComponent((/* @__PURE__ */ new Date()).toISOString())}`;
149
- const [all, openRes, waiting, resolved, breach] = await Promise.all([
150
- fetch(`/api/tickets?limit=0&depth=0&${sn}`, { credentials: "include" }),
151
- fetch(`/api/tickets?limit=0&depth=0&where[status][equals]=open&${sn}`, { credentials: "include" }),
152
- fetch(`/api/tickets?limit=0&depth=0&where[status][equals]=waiting_client&${sn}`, { credentials: "include" }),
153
- fetch(`/api/tickets?limit=0&depth=0&where[status][equals]=resolved&${sn}`, { credentials: "include" }),
154
- fetch(`/api/tickets?limit=0&depth=0&where[or][0][slaFirstResponseBreached][equals]=true&where[or][1][slaResolutionBreached][equals]=true&${sn}`, { credentials: "include" })
155
- ]);
156
- const [a, o, w, r, b] = await Promise.all([all.json(), openRes.json(), waiting.json(), resolved.json(), breach.json()]);
157
- setCounts({
158
- all: a.totalDocs || 0,
159
- open: o.totalDocs || 0,
160
- waiting: w.totalDocs || 0,
161
- resolved: r.totalDocs || 0,
162
- breach: b.totalDocs || 0
163
- });
164
- } catch {
165
- }
166
- };
167
- fetchCounts();
168
- }, []);
169
- react.useEffect(() => {
170
- const iv = setInterval(fetchTickets, 6e4);
171
- return () => clearInterval(iv);
172
- }, [fetchTickets]);
173
- react.useEffect(() => {
174
- const handleKey = (e) => {
175
- if (e.target instanceof HTMLInputElement || e.target instanceof HTMLTextAreaElement) return;
176
- if (e.key === "j" || e.key === "ArrowDown") {
177
- e.preventDefault();
178
- setSelectedIdx((p) => Math.min(p + 1, tickets.length - 1));
179
- }
180
- if (e.key === "k" || e.key === "ArrowUp") {
181
- e.preventDefault();
182
- setSelectedIdx((p) => Math.max(p - 1, 0));
183
- }
184
- if (e.key === "Enter" && selectedIdx >= 0 && tickets[selectedIdx]) {
185
- window.location.href = `/admin/support/ticket?id=${tickets[selectedIdx].id}`;
186
- }
187
- };
188
- window.addEventListener("keydown", handleKey);
189
- return () => window.removeEventListener("keydown", handleKey);
190
- }, [tickets, selectedIdx]);
191
- const tabs = [
192
- { key: "all", label: t("inbox.tabs.all"), count: counts.all },
193
- { key: "open", label: t("inbox.tabs.open"), count: counts.open },
194
- { key: "waiting_client", label: t("inbox.tabs.waiting"), count: counts.waiting },
195
- { key: "sla_breach", label: t("inbox.tabs.slaBreach"), count: counts.breach, alert: true },
196
- { key: "resolved", label: t("inbox.tabs.resolved"), count: counts.resolved }
197
- ];
198
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: s__default.default.page, children: [
199
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: s__default.default.header, children: [
200
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
201
- /* @__PURE__ */ jsxRuntime.jsx("h1", { className: s__default.default.title, children: t("inbox.title") }),
202
- /* @__PURE__ */ jsxRuntime.jsxs("p", { className: s__default.default.subtitle, children: [
203
- tickets.length > 0 && `${tickets.length} sur ${counts.all} \xB7 `,
204
- counts.breach > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: s__default.default.subtitleBreach, children: [
205
- counts.breach,
206
- " SLA d\xE9pass\xE9",
207
- counts.breach > 1 ? "s" : ""
208
- ] }) : /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Aucun SLA en alerte" })
209
- ] })
210
- ] }),
211
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: s__default.default.headerRight, children: [
212
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: s__default.default.searchWrap, children: [
213
- /* @__PURE__ */ jsxRuntime.jsxs("svg", { className: s__default.default.searchIcon, width: "14", height: "14", viewBox: "0 0 16 16", fill: "none", children: [
214
- /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "7", cy: "7", r: "5", stroke: "currentColor", strokeWidth: "1.5" }),
215
- /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M11 11l3.5 3.5", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" })
216
- ] }),
217
- /* @__PURE__ */ jsxRuntime.jsx(
218
- "input",
219
- {
220
- type: "text",
221
- className: s__default.default.searchInput,
222
- placeholder: t("inbox.searchPlaceholder"),
223
- value: search,
224
- onChange: (e) => setSearch(e.target.value)
225
- }
226
- ),
227
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: s__default.default.searchHint, children: "\u2318K" })
228
- ] }),
229
- /* @__PURE__ */ jsxRuntime.jsx(Link__default.default, { href: "/admin/support/new-ticket", className: s__default.default.newTicketBtn, children: t("inbox.newTicketBtn") })
230
- ] })
231
- ] }),
232
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: s__default.default.tabs, role: "tablist", children: tabs.map((tk) => {
233
- const isAlert = tk.alert && tk.count > 0;
234
- return /* @__PURE__ */ jsxRuntime.jsxs(
235
- "button",
236
- {
237
- role: "tab",
238
- "aria-selected": tab === tk.key,
239
- className: `${s__default.default.tab} ${tab === tk.key ? s__default.default.tabActive : ""} ${isAlert ? s__default.default.tabAlert : ""}`,
240
- onClick: () => {
241
- setTab(tk.key);
242
- setSelectedIdx(-1);
243
- },
244
- children: [
245
- tk.label,
246
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: `${s__default.default.tabCount} ${isAlert ? s__default.default.tabCountAlert : ""}`, children: tk.count })
247
- ]
248
- },
249
- tk.key
250
- );
251
- }) }),
252
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: s__default.default.sortRow, children: checkedIds.size > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", gap: 8, alignItems: "center", flex: 1 }, children: [
253
- /* @__PURE__ */ jsxRuntime.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) }) }),
254
- /* @__PURE__ */ jsxRuntime.jsx("button", { className: s__default.default.sortSelect, onClick: () => handleBulkAction("close"), disabled: bulkProcessing, children: t("inbox.closeAction") }),
255
- /* @__PURE__ */ jsxRuntime.jsx("button", { className: s__default.default.sortSelect, onClick: () => handleBulkAction("reopen"), disabled: bulkProcessing, children: t("inbox.reopenAction") }),
256
- /* @__PURE__ */ jsxRuntime.jsxs("select", { className: s__default.default.sortSelect, value: bulkAction, onChange: (e) => {
257
- if (e.target.value) handleBulkAction(e.target.value);
258
- setBulkAction("");
259
- }, children: [
260
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: t("inbox.moreActions") }),
261
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "set_priority", children: t("inbox.changePriority") }),
262
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "delete", children: t("inbox.deleteAction") })
263
- ] }),
264
- /* @__PURE__ */ jsxRuntime.jsx("button", { className: s__default.default.sortSelect, onClick: () => setCheckedIds(/* @__PURE__ */ new Set()), style: { marginLeft: "auto" }, children: t("inbox.deselect") })
265
- ] }) : /* @__PURE__ */ jsxRuntime.jsxs("select", { className: s__default.default.sortSelect, value: sort, onChange: (e) => setSort(e.target.value), children: [
266
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "-updatedAt", children: t("inbox.sort.newest") }),
267
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "updatedAt", children: t("inbox.sort.oldest") }),
268
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "-createdAt", children: t("inbox.sort.created") }),
269
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "priority", children: t("inbox.sort.priority") })
270
- ] }) }),
271
- loading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: s__default.default.loading, children: t("common.loading") }) : tickets.length === 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: s__default.default.empty, children: [
272
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: s__default.default.emptyIcon, children: "--" }),
273
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: s__default.default.emptyText, children: t("inbox.empty") })
274
- ] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: s__default.default.list, children: tickets.map((tk, idx) => {
275
- const clientObj = typeof tk.client === "object" ? tk.client : null;
276
- const clientName = clientObj ? `${clientObj.firstName || ""} ${clientObj.lastName || ""}`.trim() : "";
277
- const clientCompany = clientObj?.company || "";
278
- const displayClient = clientName ? `${clientName}${clientCompany ? `, ${clientCompany}` : ""}` : "\u2014";
279
- const isUnread = tk.lastClientMessageAt && (!tk.lastAdminReadAt || new Date(tk.lastClientMessageAt) > new Date(tk.lastAdminReadAt));
280
- const priorityColor = PRIORITY_COLORS[tk.priority] || "transparent";
281
- const sla$1 = sla.computeSlaState(tk);
282
- const isBreach = sla$1.state === "breach";
283
- const statusVariant = STATUS_VARIANT[tk.status] || "open";
284
- return /* @__PURE__ */ jsxRuntime.jsxs(
285
- "a",
286
- {
287
- href: `/admin/support/ticket?id=${tk.id}`,
288
- className: [
289
- s__default.default.row,
290
- idx === selectedIdx ? s__default.default.rowSelected : "",
291
- isUnread ? s__default.default.rowUnread : "",
292
- isBreach ? s__default.default.rowBreach : ""
293
- ].filter(Boolean).join(" "),
294
- onClick: (e) => {
295
- e.preventDefault();
296
- window.location.href = `/admin/support/ticket?id=${tk.id}`;
297
- },
298
- children: [
299
- /* @__PURE__ */ jsxRuntime.jsx(
300
- "input",
301
- {
302
- type: "checkbox",
303
- checked: checkedIds.has(tk.id),
304
- onClick: (e) => e.stopPropagation(),
305
- onChange: () => toggleCheck(tk.id),
306
- className: s__default.default.rowCheck,
307
- "aria-label": `S\xE9lectionner ${tk.ticketNumber}`
308
- }
309
- ),
310
- /* @__PURE__ */ jsxRuntime.jsx(
311
- "span",
312
- {
313
- className: s__default.default.priorityDot,
314
- style: { background: priorityColor },
315
- "aria-label": `Priorit\xE9 ${tk.priority}`,
316
- title: `Priorit\xE9 ${tk.priority}`
317
- }
318
- ),
319
- /* @__PURE__ */ jsxRuntime.jsx(StatusPill.StatusPill, { status: isBreach ? "sla-breach" : statusVariant }),
320
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: s__default.default.ticketNum, children: tk.ticketNumber }),
321
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: s__default.default.subject, children: tk.subject }),
322
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: s__default.default.client, children: displayClient }),
323
- /* @__PURE__ */ jsxRuntime.jsx(
324
- "span",
325
- {
326
- className: [
327
- s__default.default.slaCell,
328
- sla$1.state === "breach" ? s__default.default.slaBreach : "",
329
- sla$1.state === "warn" ? s__default.default.slaWarn : "",
330
- sla$1.state === "ok" ? s__default.default.slaOk : ""
331
- ].filter(Boolean).join(" "),
332
- title: sla$1.due ? new Date(sla$1.due).toLocaleString(dateLocale.DATE_LOCALE) : "",
333
- children: sla.formatSlaRemaining(sla$1.remainingMs)
334
- }
335
- ),
336
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: s__default.default.timeAgo, children: relativeTime(tk.updatedAt, t) }),
337
- isUnread ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: s__default.default.unreadDot }) : /* @__PURE__ */ jsxRuntime.jsx("span", {})
338
- ]
339
- },
340
- tk.id
341
- );
342
- }) }),
343
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: s__default.default.keyboardHints, children: [
344
- /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
345
- /* @__PURE__ */ jsxRuntime.jsx("kbd", { children: "\u2191" }),
346
- /* @__PURE__ */ jsxRuntime.jsx("kbd", { children: "\u2193" }),
347
- " ",
348
- t("inbox.keyboardNavigate")
349
- ] }),
350
- /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
351
- /* @__PURE__ */ jsxRuntime.jsx("kbd", { children: "\u21B5" }),
352
- " ",
353
- t("inbox.keyboardOpen")
354
- ] })
355
- ] })
356
- ] });
357
- };
358
-
359
- exports.TicketInboxClient = TicketInboxClient;
@@ -1,32 +0,0 @@
1
- 'use strict';
2
-
3
- Object.defineProperty(exports, '__esModule', { value: true });
4
-
5
- var jsxRuntime = require('react/jsx-runtime');
6
- var templates = require('@payloadcms/next/templates');
7
- var navigation = require('next/navigation');
8
- var ErrorBoundary = require('../shared/ErrorBoundary');
9
- var client = require('./client');
10
-
11
- const TicketInboxView = ({ initPageResult }) => {
12
- const { req, visibleEntities } = initPageResult;
13
- if (!req.user) navigation.redirect("/admin/login");
14
- return /* @__PURE__ */ jsxRuntime.jsx(
15
- templates.DefaultTemplate,
16
- {
17
- i18n: req.i18n,
18
- locale: initPageResult.locale,
19
- params: {},
20
- payload: req.payload,
21
- permissions: initPageResult.permissions,
22
- searchParams: {},
23
- user: req.user,
24
- visibleEntities,
25
- children: /* @__PURE__ */ jsxRuntime.jsx(ErrorBoundary.AdminErrorBoundary, { viewName: "TicketInboxView", children: /* @__PURE__ */ jsxRuntime.jsx(client.TicketInboxClient, {}) })
26
- }
27
- );
28
- };
29
- var TicketInboxView_default = TicketInboxView;
30
-
31
- exports.TicketInboxView = TicketInboxView;
32
- exports.default = TicketInboxView_default;