@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,471 +0,0 @@
1
- 'use strict';
2
-
3
- var jsxRuntime = require('react/jsx-runtime');
4
- var react = require('react');
5
- var lucideReact = require('lucide-react');
6
- var Skeleton = require('../shared/Skeleton');
7
- var useTranslation = require('../../components/TicketConversation/hooks/useTranslation');
8
- var styles = require('../../styles/PendingEmails.module.scss');
9
-
10
- function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
11
-
12
- var styles__default = /*#__PURE__*/_interopDefault(styles);
13
-
14
- function timeAgo(dateStr, tFn) {
15
- const diff = Date.now() - new Date(dateStr).getTime();
16
- const mins = Math.floor(diff / 6e4);
17
- if (mins < 1) return tFn("pendingEmails.timeAgo.justNow");
18
- if (mins < 60) return tFn("pendingEmails.timeAgo.minutesAgo", { count: mins });
19
- const hours = Math.floor(mins / 60);
20
- if (hours < 24) return tFn("pendingEmails.timeAgo.hoursAgo", { count: hours });
21
- const days = Math.floor(hours / 24);
22
- return tFn("pendingEmails.timeAgo.daysAgo", { count: days });
23
- }
24
- function TicketSearchModal({
25
- suggestions,
26
- onSelect,
27
- onClose
28
- }) {
29
- const [search, setSearch] = react.useState("");
30
- const [results, setResults] = react.useState([]);
31
- const [searching, setSearching] = react.useState(false);
32
- const doSearch = react.useCallback(async (q) => {
33
- if (q.length < 2) {
34
- setResults([]);
35
- return;
36
- }
37
- setSearching(true);
38
- try {
39
- const res = await fetch(`/api/tickets?where[or][0][ticketNumber][contains]=${encodeURIComponent(q)}&where[or][1][subject][contains]=${encodeURIComponent(q)}&limit=10&sort=-updatedAt&depth=0`);
40
- if (res.ok) {
41
- const data = await res.json();
42
- setResults(data.docs.map((d) => ({
43
- id: d.id,
44
- ticketNumber: d.ticketNumber,
45
- subject: d.subject
46
- })));
47
- }
48
- } catch {
49
- }
50
- setSearching(false);
51
- }, []);
52
- react.useEffect(() => {
53
- const timer = setTimeout(() => doSearch(search), 300);
54
- return () => clearTimeout(timer);
55
- }, [search, doSearch]);
56
- const scoreClass = (score) => score >= 0.7 ? styles__default.default.scoreHigh : score >= 0.5 ? styles__default.default.scoreMedium : styles__default.default.scoreLow;
57
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles__default.default.overlay, onClick: onClose, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles__default.default.modal, onClick: (e) => e.stopPropagation(), children: [
58
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles__default.default.modalHeader, children: [
59
- /* @__PURE__ */ jsxRuntime.jsx("h3", { className: styles__default.default.modalTitle, children: "Rattacher a un ticket" }),
60
- /* @__PURE__ */ jsxRuntime.jsx("button", { onClick: onClose, className: styles__default.default.modalClose, children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { size: 20 }) })
61
- ] }),
62
- suggestions.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles__default.default.sectionBlock, children: [
63
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles__default.default.sectionLabel, children: "Suggestions" }),
64
- suggestions.map((s) => /* @__PURE__ */ jsxRuntime.jsxs("button", { onClick: () => onSelect(s.id), className: styles__default.default.resultRow, children: [
65
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: styles__default.default.resultTicketNum, children: s.ticketNumber }),
66
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: styles__default.default.resultSubject, children: s.subject }),
67
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: `${styles__default.default.scoreBadge} ${scoreClass(s.score)}`, children: [
68
- Math.round(s.score * 100),
69
- "%"
70
- ] })
71
- ] }, s.id))
72
- ] }),
73
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles__default.default.searchWrap, children: [
74
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Search, { size: 16, className: styles__default.default.searchIcon }),
75
- /* @__PURE__ */ jsxRuntime.jsx(
76
- "input",
77
- {
78
- type: "text",
79
- placeholder: "Rechercher un ticket (TK-0042, sujet...)...",
80
- value: search,
81
- onChange: (e) => setSearch(e.target.value),
82
- className: styles__default.default.searchInput
83
- }
84
- )
85
- ] }),
86
- searching && /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles__default.default.searchingHint, children: "Recherche..." }),
87
- results.map((r) => /* @__PURE__ */ jsxRuntime.jsxs("button", { onClick: () => onSelect(r.id), className: styles__default.default.resultRow, children: [
88
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: styles__default.default.resultTicketNum, children: r.ticketNumber }),
89
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: styles__default.default.resultSubject, children: r.subject })
90
- ] }, r.id)),
91
- search.length >= 2 && !searching && results.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles__default.default.noResults, children: "Aucun ticket trouve" })
92
- ] }) });
93
- }
94
- function ClientPickerModal({
95
- defaultEmail,
96
- detectedClient,
97
- onSelect,
98
- onClose
99
- }) {
100
- const [search, setSearch] = react.useState("");
101
- const [results, setResults] = react.useState([]);
102
- const [searching, setSearching] = react.useState(false);
103
- const [showCreate, setShowCreate] = react.useState(false);
104
- const [creating, setCreating] = react.useState(false);
105
- const [newClient, setNewClient] = react.useState({ firstName: "", lastName: "", email: defaultEmail, company: "" });
106
- const [createError, setCreateError] = react.useState("");
107
- const doSearch = react.useCallback(async (q) => {
108
- if (q.length < 2) {
109
- setResults([]);
110
- return;
111
- }
112
- setSearching(true);
113
- try {
114
- const res = await fetch(`/api/support-clients?where[or][0][email][contains]=${encodeURIComponent(q)}&where[or][1][firstName][contains]=${encodeURIComponent(q)}&where[or][2][lastName][contains]=${encodeURIComponent(q)}&where[or][3][company][contains]=${encodeURIComponent(q)}&limit=10&sort=-updatedAt&depth=0`);
115
- if (res.ok) {
116
- const data = await res.json();
117
- setResults(data.docs.map((d) => ({
118
- id: d.id,
119
- firstName: d.firstName,
120
- lastName: d.lastName,
121
- email: d.email,
122
- company: d.company
123
- })));
124
- }
125
- } catch {
126
- }
127
- setSearching(false);
128
- }, []);
129
- react.useEffect(() => {
130
- const timer = setTimeout(() => doSearch(search), 300);
131
- return () => clearTimeout(timer);
132
- }, [search, doSearch]);
133
- const handleCreate = async () => {
134
- setCreateError("");
135
- if (!newClient.email.trim() || !newClient.firstName.trim() || !newClient.company.trim()) {
136
- setCreateError("Email, prenom et entreprise sont obligatoires");
137
- return;
138
- }
139
- setCreating(true);
140
- try {
141
- const res = await fetch("/api/support-clients", {
142
- method: "POST",
143
- headers: { "Content-Type": "application/json" },
144
- body: JSON.stringify({
145
- email: newClient.email.trim(),
146
- firstName: newClient.firstName.trim(),
147
- lastName: newClient.lastName.trim() || void 0,
148
- company: newClient.company.trim(),
149
- password: crypto.randomUUID()
150
- })
151
- });
152
- if (res.ok) {
153
- const data = await res.json();
154
- onSelect(data.doc.id);
155
- } else {
156
- const err = await res.json().catch(() => ({}));
157
- setCreateError(err.errors?.[0]?.message || "Erreur lors de la creation");
158
- }
159
- } catch {
160
- setCreateError("Erreur reseau");
161
- }
162
- setCreating(false);
163
- };
164
- const clientLabel = (c) => {
165
- const parts = [c.firstName, c.lastName].filter(Boolean).join(" ");
166
- return parts ? `${parts}${c.company ? ` \u2014 ${c.company}` : ""}` : c.email || "";
167
- };
168
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles__default.default.overlay, onClick: onClose, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles__default.default.modal, onClick: (e) => e.stopPropagation(), children: [
169
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles__default.default.modalHeader, children: [
170
- /* @__PURE__ */ jsxRuntime.jsx("h3", { className: styles__default.default.modalTitle, children: "Choisir un client" }),
171
- /* @__PURE__ */ jsxRuntime.jsx("button", { onClick: onClose, className: styles__default.default.modalClose, children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { size: 20 }) })
172
- ] }),
173
- detectedClient && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles__default.default.sectionBlock, children: [
174
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles__default.default.sectionLabel, children: "Client detecte" }),
175
- /* @__PURE__ */ jsxRuntime.jsxs("button", { onClick: () => onSelect(detectedClient.id), className: styles__default.default.detectedRow, children: [
176
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: styles__default.default.detectedLabel, children: [
177
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: styles__default.default.detectedName, children: clientLabel(detectedClient) }),
178
- detectedClient.email && /* @__PURE__ */ jsxRuntime.jsx("span", { className: styles__default.default.detectedEmail, children: detectedClient.email })
179
- ] }),
180
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: styles__default.default.useBtn, children: "Utiliser" })
181
- ] })
182
- ] }),
183
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles__default.default.searchWrap, children: [
184
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Search, { size: 16, className: styles__default.default.searchIcon }),
185
- /* @__PURE__ */ jsxRuntime.jsx(
186
- "input",
187
- {
188
- type: "text",
189
- placeholder: "Rechercher un client (nom, email, entreprise)...",
190
- value: search,
191
- onChange: (e) => setSearch(e.target.value),
192
- className: styles__default.default.searchInput
193
- }
194
- )
195
- ] }),
196
- searching && /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles__default.default.searchingHint, children: "Recherche..." }),
197
- results.map((r) => /* @__PURE__ */ jsxRuntime.jsx("button", { onClick: () => onSelect(r.id), className: styles__default.default.resultRow, children: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: styles__default.default.clientResultLabel, children: [
198
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: styles__default.default.clientResultName, children: clientLabel(r) }),
199
- r.email && /* @__PURE__ */ jsxRuntime.jsx("span", { className: styles__default.default.clientResultEmail, children: r.email })
200
- ] }) }, r.id)),
201
- search.length >= 2 && !searching && results.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles__default.default.noResults, children: "Aucun client trouve" }),
202
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles__default.default.separator, children: /* @__PURE__ */ jsxRuntime.jsxs("button", { onClick: () => setShowCreate(!showCreate), className: styles__default.default.createToggle, children: [
203
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { size: 14 }),
204
- showCreate ? "Annuler la creation" : "Creer un nouveau client"
205
- ] }) }),
206
- showCreate && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles__default.default.createForm, children: [
207
- createError && /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles__default.default.formError, children: createError }),
208
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles__default.default.createFormRow, children: [
209
- /* @__PURE__ */ jsxRuntime.jsx(
210
- "input",
211
- {
212
- type: "text",
213
- placeholder: "Prenom *",
214
- value: newClient.firstName,
215
- onChange: (e) => setNewClient((p) => ({ ...p, firstName: e.target.value })),
216
- className: styles__default.default.formInputHalf
217
- }
218
- ),
219
- /* @__PURE__ */ jsxRuntime.jsx(
220
- "input",
221
- {
222
- type: "text",
223
- placeholder: "Nom",
224
- value: newClient.lastName,
225
- onChange: (e) => setNewClient((p) => ({ ...p, lastName: e.target.value })),
226
- className: styles__default.default.formInputHalf
227
- }
228
- )
229
- ] }),
230
- /* @__PURE__ */ jsxRuntime.jsx(
231
- "input",
232
- {
233
- type: "email",
234
- placeholder: "Email *",
235
- value: newClient.email,
236
- onChange: (e) => setNewClient((p) => ({ ...p, email: e.target.value })),
237
- className: styles__default.default.formInput
238
- }
239
- ),
240
- /* @__PURE__ */ jsxRuntime.jsx(
241
- "input",
242
- {
243
- type: "text",
244
- placeholder: "Entreprise *",
245
- value: newClient.company,
246
- onChange: (e) => setNewClient((p) => ({ ...p, company: e.target.value })),
247
- className: styles__default.default.formInput
248
- }
249
- ),
250
- /* @__PURE__ */ jsxRuntime.jsx("button", { onClick: handleCreate, disabled: creating, className: styles__default.default.submitBtn, children: creating ? "Creation..." : "Creer et utiliser" })
251
- ] })
252
- ] }) });
253
- }
254
- function EmailCard({
255
- email,
256
- onProcess,
257
- processing
258
- }) {
259
- const { t } = useTranslation.useTranslation();
260
- const [expanded, setExpanded] = react.useState(false);
261
- const [showLinkModal, setShowLinkModal] = react.useState(false);
262
- const [showClientPicker, setShowClientPicker] = react.useState(false);
263
- const attachmentCount = email.attachments?.length || 0;
264
- const preview = email.body.slice(0, 200) + (email.body.length > 200 ? "..." : "");
265
- const suggestions = email.suggestedTickets || [];
266
- const isPending = email.status === "pending";
267
- const processedTicketNumber = typeof email.processedTicket === "object" ? email.processedTicket?.ticketNumber : null;
268
- const suggestionClass = (score) => score >= 0.7 ? styles__default.default.suggestionHigh : score >= 0.5 ? styles__default.default.suggestionMedium : styles__default.default.suggestionLow;
269
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `${styles__default.default.card} ${processing ? styles__default.default.cardProcessing : ""}`, children: [
270
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles__default.default.cardHeader, children: [
271
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles__default.default.cardInfo, children: [
272
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles__default.default.senderRow, children: [
273
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: styles__default.default.senderName, children: email.senderName || email.senderEmail }),
274
- email.senderName && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: styles__default.default.senderEmail, children: [
275
- "<",
276
- email.senderEmail,
277
- ">"
278
- ] })
279
- ] }),
280
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles__default.default.cardSubject, children: email.subject }),
281
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles__default.default.cardMeta, children: [
282
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: timeAgo(email.createdAt, t) }),
283
- attachmentCount > 0 && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: styles__default.default.attachment, children: [
284
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Paperclip, { size: 12 }),
285
- " ",
286
- attachmentCount,
287
- " PJ"
288
- ] })
289
- ] })
290
- ] }),
291
- !isPending && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `${styles__default.default.statusBadge} ${email.status === "processed" ? styles__default.default.statusProcessed : styles__default.default.statusIgnored}`, children: [
292
- email.processedAction === "ticket_created" && `Ticket cree${processedTicketNumber ? ` (${processedTicketNumber})` : ""}`,
293
- email.processedAction === "message_added" && `Rattache${processedTicketNumber ? ` a ${processedTicketNumber}` : ""}`,
294
- email.processedAction === "ignored" && "Ignore"
295
- ] })
296
- ] }),
297
- suggestions.length > 0 && isPending && /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles__default.default.suggestions, children: suggestions.map((s) => /* @__PURE__ */ jsxRuntime.jsxs("span", { className: `${styles__default.default.suggestionChip} ${suggestionClass(s.score)}`, children: [
298
- "Similaire a ",
299
- s.ticketNumber,
300
- " (",
301
- Math.round(s.score * 100),
302
- "%)"
303
- ] }, s.id)) }),
304
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles__default.default.bodySection, children: [
305
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: `${styles__default.default.bodyText} ${expanded ? styles__default.default.bodyExpanded : ""}`, children: expanded ? email.body : preview }),
306
- email.body.length > 200 && /* @__PURE__ */ jsxRuntime.jsx("button", { onClick: () => setExpanded(!expanded), className: styles__default.default.expandBtn, children: expanded ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
307
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronUp, { size: 14 }),
308
- " Reduire"
309
- ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
310
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { size: 14 }),
311
- " Voir tout"
312
- ] }) })
313
- ] }),
314
- isPending && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles__default.default.actions, children: [
315
- /* @__PURE__ */ jsxRuntime.jsxs(
316
- "button",
317
- {
318
- onClick: () => setShowClientPicker(true),
319
- disabled: processing,
320
- className: `${styles__default.default.actionBtn} ${styles__default.default.btnCreate}`,
321
- children: [
322
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { size: 14 }),
323
- "Creer un ticket"
324
- ]
325
- }
326
- ),
327
- /* @__PURE__ */ jsxRuntime.jsxs(
328
- "button",
329
- {
330
- onClick: () => setShowLinkModal(true),
331
- disabled: processing,
332
- className: `${styles__default.default.actionBtn} ${styles__default.default.btnLink}`,
333
- children: [
334
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Link2, { size: 14 }),
335
- "Rattacher a un ticket"
336
- ]
337
- }
338
- ),
339
- /* @__PURE__ */ jsxRuntime.jsxs(
340
- "button",
341
- {
342
- onClick: () => onProcess("ignore"),
343
- disabled: processing,
344
- className: `${styles__default.default.actionBtn} ${styles__default.default.btnIgnore}`,
345
- children: [
346
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { size: 14 }),
347
- "Ignorer"
348
- ]
349
- }
350
- )
351
- ] }),
352
- showLinkModal && /* @__PURE__ */ jsxRuntime.jsx(
353
- TicketSearchModal,
354
- {
355
- suggestions,
356
- onSelect: (ticketId) => {
357
- setShowLinkModal(false);
358
- onProcess("add_to_ticket", ticketId);
359
- },
360
- onClose: () => setShowLinkModal(false)
361
- }
362
- ),
363
- showClientPicker && /* @__PURE__ */ jsxRuntime.jsx(
364
- ClientPickerModal,
365
- {
366
- defaultEmail: email.senderEmail,
367
- detectedClient: typeof email.client === "object" && email.client ? { id: email.client.id, firstName: email.client.firstName, lastName: email.client.lastName, email: email.client.email, company: email.client.company } : null,
368
- onSelect: (clientId) => {
369
- setShowClientPicker(false);
370
- onProcess("create_ticket", void 0, clientId);
371
- },
372
- onClose: () => setShowClientPicker(false)
373
- }
374
- )
375
- ] });
376
- }
377
- const PendingEmailsClient = () => {
378
- const { t } = useTranslation.useTranslation();
379
- const [emails, setEmails] = react.useState([]);
380
- const [loading, setLoading] = react.useState(true);
381
- const [tab, setTab] = react.useState("pending");
382
- const [processing, setProcessing] = react.useState(null);
383
- const [sessionExpired, setSessionExpired] = react.useState(false);
384
- const fetchEmails = react.useCallback(async () => {
385
- try {
386
- const res = await fetch(`/api/pending-emails?where[status][equals]=${tab}&sort=-createdAt&limit=50&depth=1`);
387
- if (res.ok) {
388
- const data = await res.json();
389
- setEmails(data.docs);
390
- } else if (res.status === 401 || res.status === 403) {
391
- setSessionExpired(true);
392
- }
393
- } catch {
394
- }
395
- setLoading(false);
396
- }, [tab]);
397
- react.useEffect(() => {
398
- setLoading(true);
399
- fetchEmails();
400
- }, [fetchEmails]);
401
- react.useEffect(() => {
402
- if (sessionExpired || tab !== "pending") return;
403
- const interval = setInterval(fetchEmails, 3e4);
404
- return () => clearInterval(interval);
405
- }, [fetchEmails, sessionExpired, tab]);
406
- react.useEffect(() => {
407
- if (sessionExpired) return;
408
- const onFocus = () => fetchEmails();
409
- window.addEventListener("focus", onFocus);
410
- return () => window.removeEventListener("focus", onFocus);
411
- }, [fetchEmails, sessionExpired]);
412
- const handleProcess = async (emailId, action, ticketId, clientId) => {
413
- setProcessing(emailId);
414
- try {
415
- const res = await fetch(`/api/support/pending-emails/${emailId}/process`, {
416
- method: "POST",
417
- headers: { "Content-Type": "application/json" },
418
- body: JSON.stringify({ action, ticketId, clientId })
419
- });
420
- if (res.ok) {
421
- setEmails((prev) => prev.filter((e) => e.id !== emailId));
422
- } else {
423
- const err = await res.json().catch(() => ({ error: "Unknown error" }));
424
- alert(`Erreur : ${err.error || res.statusText}`);
425
- }
426
- } catch {
427
- alert("Erreur reseau");
428
- }
429
- setProcessing(null);
430
- };
431
- if (loading) {
432
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles__default.default.loadingWrap, children: /* @__PURE__ */ jsxRuntime.jsx(Skeleton.SkeletonDashboard, {}) });
433
- }
434
- const tabs = [
435
- { key: "pending", label: t("pendingEmails.tabs.pending") },
436
- { key: "processed", label: t("pendingEmails.tabs.processed") },
437
- { key: "ignored", label: t("pendingEmails.tabs.ignored") }
438
- ];
439
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles__default.default.page, children: [
440
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles__default.default.header, children: [
441
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles__default.default.headerLeft, children: [
442
- /* @__PURE__ */ jsxRuntime.jsxs("h1", { className: styles__default.default.title, children: [
443
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: styles__default.default.titleIcon, children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Inbox, { size: 24 }) }),
444
- t("pendingEmails.title")
445
- ] }),
446
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: styles__default.default.subtitle, children: t("pendingEmails.subtitle") })
447
- ] }),
448
- tab === "pending" && emails.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("span", { className: styles__default.default.pendingBadge, children: t("pendingEmails.pendingCount", { count: String(emails.length) }) })
449
- ] }),
450
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles__default.default.tabs, children: tabs.map((tk) => /* @__PURE__ */ jsxRuntime.jsx(
451
- "button",
452
- {
453
- onClick: () => setTab(tk.key),
454
- className: `${styles__default.default.tab} ${tab === tk.key ? styles__default.default.tabActive : ""}`,
455
- children: tk.label
456
- },
457
- tk.key
458
- )) }),
459
- emails.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles__default.default.empty, children: tab === "pending" ? t("pendingEmails.empty.pending") : tab === "processed" ? t("pendingEmails.empty.processed") : t("pendingEmails.empty.ignored") }) : emails.map((email) => /* @__PURE__ */ jsxRuntime.jsx(
460
- EmailCard,
461
- {
462
- email,
463
- onProcess: (action, ticketId, clientId) => handleProcess(email.id, action, ticketId, clientId),
464
- processing: processing === email.id
465
- },
466
- email.id
467
- ))
468
- ] });
469
- };
470
-
471
- exports.PendingEmailsClient = PendingEmailsClient;
@@ -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 PendingEmailsView = ({ 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: "PendingEmailsView", children: /* @__PURE__ */ jsxRuntime.jsx(client.PendingEmailsClient, {}) })
28
- }
29
- );
30
- };
31
- var PendingEmailsView_default = PendingEmailsView;
32
-
33
- exports.PendingEmailsView = PendingEmailsView;
34
- exports.default = PendingEmailsView_default;