@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,196 +0,0 @@
1
- 'use strict';
2
-
3
- var react = require('react');
4
-
5
- function useAI(messages, client, ticketSubject, replyBody, setReplyBody, setReplyHtml, replyEditorRef) {
6
- const [clientSentiment, setClientSentiment] = react.useState(null);
7
- const [aiReplying, setAiReplying] = react.useState(false);
8
- const [aiRewriting, setAiRewriting] = react.useState(false);
9
- const [showAiSummary, setShowAiSummary] = react.useState(false);
10
- const [aiSummary, setAiSummary] = react.useState("");
11
- const [aiGenerating, setAiGenerating] = react.useState(false);
12
- const [aiSaving, setAiSaving] = react.useState(false);
13
- const [aiSaved, setAiSaved] = react.useState(false);
14
- react.useEffect(() => {
15
- if (messages.length === 0) return;
16
- const lastClientMsg = [...messages].reverse().find((m) => m.authorType === "client" || m.authorType === "email");
17
- if (!lastClientMsg) return;
18
- const analyze = async () => {
19
- try {
20
- const res = await fetch("/api/support/ai", {
21
- method: "POST",
22
- headers: { "Content-Type": "application/json" },
23
- credentials: "include",
24
- body: JSON.stringify({ action: "sentiment", text: lastClientMsg.body.slice(0, 500) })
25
- });
26
- if (res.ok) {
27
- const data = await res.json();
28
- const raw = (data.sentiment || "").toLowerCase().trim();
29
- const sentimentMap = {
30
- "frustr\xE9": { emoji: "\u{1F624}", label: "Frustr\xE9", color: "#dc2626" },
31
- "frustre": { emoji: "\u{1F624}", label: "Frustr\xE9", color: "#dc2626" },
32
- "m\xE9content": { emoji: "\u{1F620}", label: "M\xE9content", color: "#ea580c" },
33
- "mecontent": { emoji: "\u{1F620}", label: "M\xE9content", color: "#ea580c" },
34
- "urgent": { emoji: "\u{1F525}", label: "Urgent", color: "#dc2626" },
35
- "neutre": { emoji: "\u{1F610}", label: "Neutre", color: "#6b7280" },
36
- "satisfait": { emoji: "\u{1F60A}", label: "Satisfait", color: "#16a34a" }
37
- };
38
- const match = Object.keys(sentimentMap).find((k) => raw.includes(k));
39
- if (match) setClientSentiment(sentimentMap[match]);
40
- else setClientSentiment({ emoji: "\u{1F610}", label: "Neutre", color: "#6b7280" });
41
- }
42
- } catch {
43
- }
44
- };
45
- analyze();
46
- }, [messages.length]);
47
- const handleAiSuggestReply = async () => {
48
- if (messages.length === 0) return;
49
- setAiReplying(true);
50
- try {
51
- const res = await fetch("/api/support/ai", {
52
- method: "POST",
53
- headers: { "Content-Type": "application/json" },
54
- credentials: "include",
55
- body: JSON.stringify({
56
- action: "suggest_reply",
57
- messages: messages.slice(-10).map((m) => ({ authorType: m.authorType, body: m.body })),
58
- clientName: `${client?.firstName || ""} ${client?.lastName || ""}`.trim(),
59
- clientCompany: client?.company
60
- })
61
- });
62
- if (res.ok) {
63
- const data = await res.json();
64
- const suggestion = data.reply || "";
65
- if (suggestion) {
66
- setReplyBody(suggestion);
67
- setReplyHtml(suggestion.replace(/\n/g, "<br/>"));
68
- if (replyEditorRef.current?.setContent) {
69
- replyEditorRef.current.setContent(suggestion.replace(/\n/g, "<br/>"));
70
- }
71
- }
72
- }
73
- } catch (err) {
74
- console.error("AI suggest error:", err);
75
- }
76
- setAiReplying(false);
77
- };
78
- const handleAiRewrite = async (style = "auto") => {
79
- if (!replyBody.trim()) return;
80
- const sel = typeof window !== "undefined" ? window.getSelection() : null;
81
- const selectedText = sel?.toString().trim() || "";
82
- const hasSelection = selectedText.length > 3;
83
- const textToRewrite = hasSelection ? selectedText : replyBody;
84
- setAiRewriting(true);
85
- try {
86
- const res = await fetch("/api/support/ai", {
87
- method: "POST",
88
- headers: { "Content-Type": "application/json" },
89
- credentials: "include",
90
- body: JSON.stringify({ action: "rewrite", text: textToRewrite, style })
91
- });
92
- if (res.ok) {
93
- const data = await res.json();
94
- const rewritten = data.rewritten || "";
95
- if (rewritten) {
96
- if (hasSelection && sel && sel.rangeCount > 0) {
97
- const range = sel.getRangeAt(0);
98
- range.deleteContents();
99
- range.insertNode(document.createTextNode(rewritten));
100
- const editorEl = replyEditorRef.current;
101
- editorEl?.focus?.();
102
- const rootEl = range.commonAncestorContainer.closest?.("[contenteditable]");
103
- if (rootEl) {
104
- const newHtml = rootEl.innerHTML;
105
- const newText = rootEl.innerText?.trim() || "";
106
- setReplyBody(newText);
107
- setReplyHtml(newHtml);
108
- }
109
- } else {
110
- setReplyBody(rewritten);
111
- setReplyHtml(rewritten.replace(/\n/g, "<br/>"));
112
- if (replyEditorRef.current?.setContent) {
113
- replyEditorRef.current.setContent(rewritten.replace(/\n/g, "<br/>"));
114
- }
115
- }
116
- }
117
- }
118
- } catch (err) {
119
- console.error("AI rewrite error:", err);
120
- }
121
- setAiRewriting(false);
122
- };
123
- const handleAiGenerate = async () => {
124
- if (messages.length === 0) return;
125
- setAiGenerating(true);
126
- setAiSummary("");
127
- setAiSaved(false);
128
- try {
129
- const res = await fetch("/api/support/ai", {
130
- method: "POST",
131
- headers: { "Content-Type": "application/json" },
132
- credentials: "include",
133
- body: JSON.stringify({
134
- action: "synthesis",
135
- messages: messages.map((m) => ({ authorType: m.authorType, body: m.body, createdAt: m.createdAt })),
136
- ticketSubject,
137
- clientName: `${client?.firstName || ""} ${client?.lastName || ""}`.trim(),
138
- clientCompany: client?.company
139
- })
140
- });
141
- if (res.ok) {
142
- const data = await res.json();
143
- setAiSummary(data.synthesis || "Aucune r\xE9ponse g\xE9n\xE9r\xE9e");
144
- } else {
145
- setAiSummary("Erreur lors de la g\xE9n\xE9ration de la synth\xE8se.");
146
- }
147
- } catch (err) {
148
- setAiSummary(`Erreur de connexion : ${err instanceof Error ? err.message : "erreur inconnue"}`);
149
- } finally {
150
- setAiGenerating(false);
151
- }
152
- };
153
- const handleAiSave = async (id, fetchAll) => {
154
- if (!id || !aiSummary) return;
155
- setAiSaving(true);
156
- try {
157
- const res = await fetch("/api/ticket-messages", {
158
- method: "POST",
159
- headers: { "Content-Type": "application/json" },
160
- credentials: "include",
161
- body: JSON.stringify({
162
- ticket: id,
163
- body: `\u{1F4CB} **Synth\xE8se IA (${(/* @__PURE__ */ new Date()).toLocaleDateString("fr-FR")})**
164
-
165
- ${aiSummary}`,
166
- authorType: "admin",
167
- isInternal: true
168
- })
169
- });
170
- if (res.ok) {
171
- setAiSaved(true);
172
- fetchAll();
173
- }
174
- } catch {
175
- } finally {
176
- setAiSaving(false);
177
- }
178
- };
179
- return {
180
- clientSentiment,
181
- aiReplying,
182
- handleAiSuggestReply,
183
- aiRewriting,
184
- handleAiRewrite,
185
- showAiSummary,
186
- setShowAiSummary,
187
- aiSummary,
188
- aiGenerating,
189
- handleAiGenerate,
190
- aiSaving,
191
- aiSaved,
192
- handleAiSave
193
- };
194
- }
195
-
196
- exports.useAI = useAI;
@@ -1,20 +0,0 @@
1
- 'use strict';
2
-
3
- var react = require('react');
4
-
5
- function useDocumentIdFromUrl() {
6
- const [id, setId] = react.useState(void 0);
7
- react.useEffect(() => {
8
- const match = window.location.pathname.match(
9
- /\/admin\/collections\/[^/]+\/([^/?#]+)/
10
- );
11
- if (match && match[1] !== "create") {
12
- const raw = match[1];
13
- const num = Number(raw);
14
- setId(Number.isFinite(num) && String(num) === raw ? num : raw);
15
- }
16
- }, []);
17
- return { id };
18
- }
19
-
20
- exports.useDocumentIdFromUrl = useDocumentIdFromUrl;
@@ -1,136 +0,0 @@
1
- 'use strict';
2
-
3
- var react = require('react');
4
-
5
- function useMessageActions(id, client, fetchAll) {
6
- const [togglingAuthor, setTogglingAuthor] = react.useState(null);
7
- const [editingMsg, setEditingMsg] = react.useState(null);
8
- const [editBody, setEditBody] = react.useState("");
9
- const [editHtml, setEditHtml] = react.useState("");
10
- const [savingEdit, setSavingEdit] = react.useState(false);
11
- const [deletingMsg, setDeletingMsg] = react.useState(null);
12
- const [resendingMsg, setResendingMsg] = react.useState(null);
13
- const [resendSuccess, setResendSuccess] = react.useState(null);
14
- const handleEditStart = (msg) => {
15
- setEditingMsg(msg.id);
16
- setEditBody(msg.body);
17
- setEditHtml(msg.bodyHtml || msg.body.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/\n/g, "<br />"));
18
- };
19
- const handleEditSave = async (msgId) => {
20
- if (!editBody.trim()) return;
21
- setSavingEdit(true);
22
- try {
23
- const res = await fetch(`/api/ticket-messages/${msgId}`, {
24
- method: "PATCH",
25
- headers: { "Content-Type": "application/json" },
26
- credentials: "include",
27
- body: JSON.stringify({ body: editBody.trim(), ...editHtml ? { bodyHtml: editHtml } : {} })
28
- });
29
- if (res.ok) {
30
- setEditingMsg(null);
31
- setEditBody("");
32
- fetchAll();
33
- }
34
- } catch {
35
- } finally {
36
- setSavingEdit(false);
37
- }
38
- };
39
- const handleEditCancel = () => {
40
- setEditingMsg(null);
41
- setEditBody("");
42
- setEditHtml("");
43
- };
44
- const handleDelete = async (msgId) => {
45
- if (!window.confirm("Supprimer ce message ?")) return;
46
- setDeletingMsg(msgId);
47
- try {
48
- const res = await fetch(`/api/ticket-messages/${msgId}`, {
49
- method: "DELETE",
50
- credentials: "include"
51
- });
52
- if (res.ok) fetchAll();
53
- } catch {
54
- } finally {
55
- setDeletingMsg(null);
56
- }
57
- };
58
- const handleResend = async (msgId) => {
59
- setResendingMsg(msgId);
60
- setResendSuccess(null);
61
- try {
62
- const res = await fetch("/api/support/resend-notification", {
63
- method: "POST",
64
- headers: { "Content-Type": "application/json" },
65
- credentials: "include",
66
- body: JSON.stringify({ messageId: msgId })
67
- });
68
- if (res.ok) {
69
- setResendSuccess(msgId);
70
- setTimeout(() => setResendSuccess(null), 3e3);
71
- }
72
- } catch {
73
- } finally {
74
- setResendingMsg(null);
75
- }
76
- };
77
- const handleToggleAuthor = async (msgId, currentType) => {
78
- const newType = currentType === "admin" ? "client" : "admin";
79
- setTogglingAuthor(msgId);
80
- try {
81
- const patchData = { authorType: newType };
82
- if (newType === "client" && client) {
83
- patchData.authorClient = client.id;
84
- }
85
- const res = await fetch(`/api/ticket-messages/${msgId}`, {
86
- method: "PATCH",
87
- headers: { "Content-Type": "application/json" },
88
- credentials: "include",
89
- body: JSON.stringify(patchData)
90
- });
91
- if (res.ok) fetchAll();
92
- } catch {
93
- } finally {
94
- setTogglingAuthor(null);
95
- }
96
- };
97
- const handleSplitMessage = async (msgId, ticketSubject) => {
98
- const subject = prompt("Sujet du nouveau ticket :", `Split: ${ticketSubject}`);
99
- if (!subject) return;
100
- try {
101
- const res = await fetch("/api/support/split-ticket", {
102
- method: "POST",
103
- headers: { "Content-Type": "application/json" },
104
- credentials: "include",
105
- body: JSON.stringify({ messageId: msgId, subject })
106
- });
107
- if (res.ok) {
108
- const data = await res.json();
109
- alert(`Ticket ${data.ticketNumber} cr\xE9\xE9`);
110
- fetchAll();
111
- }
112
- } catch {
113
- }
114
- };
115
- return {
116
- togglingAuthor,
117
- editingMsg,
118
- editBody,
119
- editHtml,
120
- setEditHtml,
121
- savingEdit,
122
- handleEditStart,
123
- handleEditSave,
124
- handleEditCancel,
125
- deletingMsg,
126
- handleDelete,
127
- resendingMsg,
128
- resendSuccess,
129
- handleResend,
130
- handleToggleAuthor,
131
- handleSplitMessage,
132
- setEditBody
133
- };
134
- }
135
-
136
- exports.useMessageActions = useMessageActions;
@@ -1,188 +0,0 @@
1
- 'use strict';
2
-
3
- var react = require('react');
4
-
5
- function useReply(id, client, cannedResponses, ticketNumber, ticketSubject, fetchAll, handleNextTicket, replyEditorRef) {
6
- const fileInputRef = react.useRef(null);
7
- const [replyBody, setReplyBody] = react.useState("");
8
- const [replyHtml, setReplyHtml] = react.useState("");
9
- const [replyFiles, setReplyFiles] = react.useState([]);
10
- const [isInternal, setIsInternal] = react.useState(false);
11
- const [notifyClient, setNotifyClient] = react.useState(false);
12
- const [sendAsClient, setSendAsClient] = react.useState(false);
13
- const [sending, setSending] = react.useState(false);
14
- const [showSchedule, setShowSchedule] = react.useState(false);
15
- const [scheduleDate, setScheduleDate] = react.useState("");
16
- const handleEditorFileUpload = react.useCallback(async (file) => {
17
- if (file.size > 5 * 1024 * 1024) return null;
18
- const formData = new FormData();
19
- formData.append("file", file);
20
- formData.append("_payload", JSON.stringify({ alt: file.name }));
21
- try {
22
- const res = await fetch("/api/media", { method: "POST", credentials: "include", body: formData });
23
- if (res.ok) {
24
- const data = await res.json();
25
- return data.doc?.url || null;
26
- }
27
- } catch {
28
- }
29
- return null;
30
- }, []);
31
- const replaceCannedVariables = react.useCallback((text) => {
32
- let result = text;
33
- if (client) {
34
- result = result.replace(/\{\{client\.firstName\}\}/g, client.firstName || "Client");
35
- result = result.replace(/\{\{client\.lastName\}\}/g, client.lastName || "");
36
- result = result.replace(/\{\{client\.company\}\}/g, client.company || "");
37
- result = result.replace(/\{\{client\.email\}\}/g, client.email || "");
38
- result = result.replace(/\{\{clientName\}\}/g, client.firstName || "Client");
39
- }
40
- result = result.replace(/\{\{ticket\.number\}\}/g, ticketNumber || "");
41
- result = result.replace(/\{\{ticket\.subject\}\}/g, ticketSubject || "");
42
- result = result.replace(/\{\{agent\.name\}\}/g, "Support");
43
- return result;
44
- }, [client, ticketNumber, ticketSubject]);
45
- const handleCannedSelect = (e) => {
46
- const selected = cannedResponses.find((cr) => String(cr.id) === e.target.value);
47
- if (selected) {
48
- const body = replaceCannedVariables(selected.body);
49
- const html = body.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/\n/g, "<br />");
50
- setReplyBody(body);
51
- setReplyHtml(html);
52
- replyEditorRef.current?.setContent(html);
53
- }
54
- e.target.value = "";
55
- };
56
- const handleReplyFileChange = (e) => {
57
- if (e.target.files) {
58
- const maxSize = 1 * 1024 * 1024;
59
- const newFiles = Array.from(e.target.files);
60
- const tooLarge = newFiles.filter((f) => f.size > maxSize);
61
- if (tooLarge.length > 0) {
62
- alert(`Fichier(s) trop volumineux (max 1 Mo) : ${tooLarge.map((f) => f.name).join(", ")}`);
63
- }
64
- setReplyFiles((prev) => [...prev, ...newFiles.filter((f) => f.size <= maxSize)]);
65
- }
66
- if (fileInputRef.current) fileInputRef.current.value = "";
67
- };
68
- const uploadFiles = async (files) => {
69
- const uploadedIds = [];
70
- for (const file of files) {
71
- if (file.size > 1 * 1024 * 1024) continue;
72
- const formData = new FormData();
73
- formData.append("file", file);
74
- formData.append("_payload", JSON.stringify({ alt: file.name }));
75
- const uploadRes = await fetch("/api/media", { method: "POST", credentials: "include", body: formData });
76
- if (uploadRes.ok) {
77
- const d = await uploadRes.json();
78
- if (d.doc?.id) uploadedIds.push(d.doc.id);
79
- }
80
- }
81
- return uploadedIds;
82
- };
83
- const resetReply = () => {
84
- setReplyBody("");
85
- setReplyHtml("");
86
- setReplyFiles([]);
87
- setIsInternal(false);
88
- setNotifyClient(false);
89
- setSendAsClient(false);
90
- replyEditorRef.current?.clear();
91
- };
92
- const handleSendReply = async () => {
93
- if (!replyBody.trim() || !id) return;
94
- setSending(true);
95
- try {
96
- const uploadedIds = await uploadFiles(replyFiles);
97
- const finalBody = replyBody.trim() || (replyHtml ? "[Contenu enrichi]" : "");
98
- const messageData = {
99
- ticket: id,
100
- body: finalBody,
101
- ...replyHtml ? { bodyHtml: replyHtml } : {},
102
- authorType: sendAsClient ? "client" : "admin",
103
- isInternal,
104
- skipNotification: isInternal || !notifyClient,
105
- ...sendAsClient && client ? { authorClient: client.id } : {}
106
- };
107
- if (uploadedIds.length > 0) {
108
- messageData.attachments = uploadedIds.map((mid) => ({ file: mid }));
109
- }
110
- const res = await fetch("/api/ticket-messages", {
111
- method: "POST",
112
- headers: { "Content-Type": "application/json" },
113
- credentials: "include",
114
- body: JSON.stringify(messageData)
115
- });
116
- if (res.ok) {
117
- resetReply();
118
- fetchAll();
119
- if (!isInternal) handleNextTicket();
120
- }
121
- } catch {
122
- } finally {
123
- setSending(false);
124
- }
125
- };
126
- const handleScheduleReply = async () => {
127
- if (!replyBody.trim() || !id || !scheduleDate) return;
128
- setSending(true);
129
- try {
130
- const uploadedIds = await uploadFiles(replyFiles);
131
- const messageData = {
132
- ticket: id,
133
- body: replyBody.trim(),
134
- ...replyHtml ? { bodyHtml: replyHtml } : {},
135
- authorType: "admin",
136
- isInternal: false,
137
- skipNotification: true,
138
- scheduledAt: new Date(scheduleDate).toISOString(),
139
- scheduledSent: false
140
- };
141
- if (uploadedIds.length > 0) {
142
- messageData.attachments = uploadedIds.map((mid) => ({ file: mid }));
143
- }
144
- const res = await fetch("/api/ticket-messages", {
145
- method: "POST",
146
- headers: { "Content-Type": "application/json" },
147
- credentials: "include",
148
- body: JSON.stringify(messageData)
149
- });
150
- if (res.ok) {
151
- resetReply();
152
- setShowSchedule(false);
153
- setScheduleDate("");
154
- fetchAll();
155
- }
156
- } catch {
157
- } finally {
158
- setSending(false);
159
- }
160
- };
161
- return {
162
- fileInputRef,
163
- replyBody,
164
- setReplyBody,
165
- replyHtml,
166
- setReplyHtml,
167
- replyFiles,
168
- setReplyFiles,
169
- isInternal,
170
- setIsInternal,
171
- notifyClient,
172
- setNotifyClient,
173
- sendAsClient,
174
- setSendAsClient,
175
- sending,
176
- showSchedule,
177
- setShowSchedule,
178
- scheduleDate,
179
- setScheduleDate,
180
- handleEditorFileUpload,
181
- handleCannedSelect,
182
- handleReplyFileChange,
183
- handleSendReply,
184
- handleScheduleReply
185
- };
186
- }
187
-
188
- exports.useReply = useReply;