@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,458 +0,0 @@
1
- 'use strict';
2
-
3
- var jsxRuntime = require('react/jsx-runtime');
4
- var react = require('react');
5
- var useTranslation = require('../../components/TicketConversation/hooks/useTranslation');
6
- var styles = require('../../styles/CrmView.module.scss');
7
-
8
- function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
9
-
10
- var styles__default = /*#__PURE__*/_interopDefault(styles);
11
-
12
- const statusBadgeClass = {
13
- open: "badgeAccent",
14
- waiting_client: "badgeOrange",
15
- resolved: "badgeGreen"
16
- };
17
- const statusLabelKeys = {
18
- open: "ticket.status.open",
19
- waiting_client: "ticket.status.waiting_client",
20
- resolved: "ticket.status.resolved"
21
- };
22
- const projectStatusLabelKeys = {
23
- active: "crm.projectStatus.active",
24
- paused: "crm.projectStatus.paused",
25
- completed: "crm.projectStatus.completed"
26
- };
27
- const projectStatusBadgeClass = {
28
- active: "badgeGreen",
29
- paused: "badgeOrange",
30
- completed: "badgeMuted"
31
- };
32
- function formatDuration(minutes) {
33
- const h = Math.floor(minutes / 60);
34
- const m = minutes % 60;
35
- if (h === 0) return `${m}min`;
36
- if (m === 0) return `${h}h`;
37
- return `${h}h${m}m`;
38
- }
39
- function timeAgo(dateStr, tFn) {
40
- const diff = Date.now() - new Date(dateStr).getTime();
41
- const days = Math.floor(diff / 864e5);
42
- if (days === 0) return tFn("crm.timeAgo.today");
43
- if (days === 1) return tFn("crm.timeAgo.yesterday");
44
- if (days < 30) return tFn("crm.timeAgo.daysAgo", { count: days });
45
- const months = Math.floor(days / 30);
46
- return tFn("crm.timeAgo.monthsAgo", { count: months });
47
- }
48
- function getStatColorClass(key, detail) {
49
- switch (key) {
50
- case "total":
51
- return styles__default.default.statAccent;
52
- case "open":
53
- return detail.openTickets > 0 ? styles__default.default.statOrange : styles__default.default.statGreen;
54
- case "resolved":
55
- return styles__default.default.statGreen;
56
- case "time":
57
- return styles__default.default.statAmber;
58
- case "activity":
59
- return styles__default.default.statAccent;
60
- default:
61
- return styles__default.default.statAccent;
62
- }
63
- }
64
- const CrmClient = () => {
65
- const { t } = useTranslation.useTranslation();
66
- const [clients, setClients] = react.useState([]);
67
- const [loading, setLoading] = react.useState(true);
68
- const [search, setSearch] = react.useState("");
69
- const [selectedId, setSelectedId] = react.useState(null);
70
- const [detail, setDetail] = react.useState(null);
71
- const [detailLoading, setDetailLoading] = react.useState(false);
72
- const [showMerge, setShowMerge] = react.useState(false);
73
- const [mergeSearch, setMergeSearch] = react.useState("");
74
- const [mergeResults, setMergeResults] = react.useState([]);
75
- const [merging, setMerging] = react.useState(false);
76
- const [intelligence, setIntelligence] = react.useState(null);
77
- const [intelLoading, setIntelLoading] = react.useState(false);
78
- const [intelRefreshing, setIntelRefreshing] = react.useState(false);
79
- const [mergeSuccess, setMergeSuccess] = react.useState("");
80
- const fetchClients = react.useCallback(async () => {
81
- try {
82
- const params = new URLSearchParams({ limit: "100", sort: "company", depth: "0" });
83
- if (search) params.set("where[company][like]", search);
84
- const res = await fetch(`/api/support-clients?${params}`);
85
- if (res.ok) {
86
- const json = await res.json();
87
- setClients(json.docs || []);
88
- }
89
- } catch {
90
- }
91
- setLoading(false);
92
- }, [search]);
93
- react.useEffect(() => {
94
- const timeout = setTimeout(fetchClients, 300);
95
- return () => clearTimeout(timeout);
96
- }, [fetchClients]);
97
- const fetchDetail = react.useCallback(async (clientId) => {
98
- setDetailLoading(true);
99
- try {
100
- const [clientRes, ticketsRes, projectsRes, timeRes] = await Promise.all([
101
- fetch(`/api/support-clients/${clientId}?depth=0`),
102
- fetch(`/api/tickets?where[client][equals]=${clientId}&sort=-createdAt&limit=20&depth=0`),
103
- fetch(`/api/projects?where[client][equals]=${clientId}&depth=0`),
104
- fetch(`/api/time-entries?limit=0&depth=0`)
105
- ]);
106
- const client = clientRes.ok ? await clientRes.json() : null;
107
- const tickets = ticketsRes.ok ? (await ticketsRes.json()).docs || [] : [];
108
- const projects = projectsRes.ok ? (await projectsRes.json()).docs || [] : [];
109
- const ticketIds = tickets.map((t2) => t2.id);
110
- let totalTimeMinutes = 0;
111
- if (timeRes.ok) {
112
- const timeData = await timeRes.json();
113
- totalTimeMinutes = timeData.docs.filter((e) => ticketIds.includes(e.ticket)).reduce((sum, e) => sum + (e.duration || 0), 0);
114
- }
115
- const openTickets = tickets.filter(
116
- (t2) => ["open", "waiting_client"].includes(t2.status)
117
- ).length;
118
- const resolvedTickets = tickets.filter(
119
- (t2) => t2.status === "resolved"
120
- ).length;
121
- const lastActivity = tickets.length > 0 ? tickets[0].createdAt : null;
122
- setDetail({
123
- client,
124
- tickets,
125
- projects,
126
- stats: {
127
- totalTickets: tickets.length,
128
- openTickets,
129
- resolvedTickets,
130
- totalTimeMinutes,
131
- lastActivity
132
- }
133
- });
134
- } catch {
135
- setDetail(null);
136
- }
137
- setDetailLoading(false);
138
- }, []);
139
- const fetchIntelligence = react.useCallback(async (clientId, force = false) => {
140
- if (force) setIntelRefreshing(true);
141
- else setIntelLoading(true);
142
- try {
143
- const method = force ? "POST" : "GET";
144
- const url = force ? "/api/support/client-intelligence" : `/api/support/client-intelligence?clientId=${clientId}`;
145
- const opts = { method, credentials: "include", headers: { "Content-Type": "application/json" } };
146
- if (force) opts.body = JSON.stringify({ clientId });
147
- const res = await fetch(url, opts);
148
- if (res.ok) setIntelligence(await res.json());
149
- } catch {
150
- }
151
- setIntelLoading(false);
152
- setIntelRefreshing(false);
153
- }, []);
154
- const selectClient = (id) => {
155
- setSelectedId(id);
156
- fetchDetail(id);
157
- fetchIntelligence(id);
158
- setIntelligence(null);
159
- setShowMerge(false);
160
- setMergeSuccess("");
161
- };
162
- react.useEffect(() => {
163
- if (!mergeSearch || mergeSearch.length < 2) {
164
- setMergeResults([]);
165
- return;
166
- }
167
- const timer = setTimeout(async () => {
168
- try {
169
- const res = await fetch(`/api/support-clients?where[or][0][company][like]=${encodeURIComponent(mergeSearch)}&where[or][1][email][like]=${encodeURIComponent(mergeSearch)}&where[or][2][firstName][like]=${encodeURIComponent(mergeSearch)}&limit=10&depth=0`);
170
- if (res.ok) {
171
- const json = await res.json();
172
- setMergeResults((json.docs || []).filter((c) => c.id !== selectedId));
173
- }
174
- } catch {
175
- }
176
- }, 300);
177
- return () => clearTimeout(timer);
178
- }, [mergeSearch, selectedId]);
179
- const handleMerge = async (targetId) => {
180
- if (!selectedId || !detail) return;
181
- const targetClient = mergeResults.find((c) => c.id === targetId) || clients.find((c) => c.id === targetId);
182
- if (!confirm(`Fusionner "${detail.client.company} (${detail.client.email})" dans "${targetClient?.company || targetId}" ?
183
-
184
- Tous les tickets, messages et projets seront transf\xE9r\xE9s.
185
- Le client "${detail.client.company}" sera supprim\xE9.
186
-
187
- Cette action est irr\xE9versible.`)) return;
188
- setMerging(true);
189
- try {
190
- const res = await fetch("/api/support/merge-clients", {
191
- method: "POST",
192
- headers: { "Content-Type": "application/json" },
193
- body: JSON.stringify({ sourceId: selectedId, targetId })
194
- });
195
- if (res.ok) {
196
- const data = await res.json();
197
- setMergeSuccess(data.message);
198
- setShowMerge(false);
199
- setSelectedId(targetId);
200
- fetchDetail(targetId);
201
- fetchClients();
202
- } else {
203
- const err = await res.json().catch(() => ({ error: "Erreur inconnue" }));
204
- alert(`Erreur : ${err.error}`);
205
- }
206
- } catch {
207
- alert("Erreur r\xE9seau");
208
- }
209
- setMerging(false);
210
- };
211
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles__default.default.page, children: [
212
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles__default.default.header, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
213
- /* @__PURE__ */ jsxRuntime.jsx("h1", { className: styles__default.default.title, children: t("crm.title") }),
214
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles__default.default.subtitle, children: t("crm.subtitle") })
215
- ] }) }),
216
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles__default.default.grid, children: [
217
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles__default.default.sidebar, children: [
218
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles__default.default.sidebarSearch, children: /* @__PURE__ */ jsxRuntime.jsx(
219
- "input",
220
- {
221
- type: "text",
222
- placeholder: t("crm.searchPlaceholder"),
223
- value: search,
224
- onChange: (e) => setSearch(e.target.value),
225
- className: styles__default.default.searchInput
226
- }
227
- ) }),
228
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles__default.default.clientList, children: loading ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles__default.default.emptyState, children: [
229
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles__default.default.skeleton }),
230
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles__default.default.skeleton }),
231
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles__default.default.skeleton }),
232
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles__default.default.skeleton })
233
- ] }) : clients.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles__default.default.emptyState, children: t("crm.noClientFound") }) : clients.map((c) => /* @__PURE__ */ jsxRuntime.jsxs(
234
- "div",
235
- {
236
- onClick: () => selectClient(c.id),
237
- className: `${styles__default.default.clientItem} ${selectedId === c.id ? styles__default.default.clientItemActive : ""}`,
238
- children: [
239
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles__default.default.clientCompany, children: c.company }),
240
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles__default.default.clientName, children: [
241
- c.firstName,
242
- " ",
243
- c.lastName
244
- ] }),
245
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles__default.default.clientEmail, children: c.email })
246
- ]
247
- },
248
- c.id
249
- )) })
250
- ] }),
251
- /* @__PURE__ */ jsxRuntime.jsx("div", { children: !selectedId ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles__default.default.placeholder, children: t("crm.selectClient") }) : detailLoading ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles__default.default.loadingCard, children: [
252
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles__default.default.skeleton }),
253
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles__default.default.skeleton }),
254
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles__default.default.skeleton }),
255
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles__default.default.skeleton })
256
- ] }) : detail ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles__default.default.detailStack, children: [
257
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles__default.default.clientHeader, children: [
258
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
259
- /* @__PURE__ */ jsxRuntime.jsx("h2", { className: styles__default.default.clientHeaderName, children: detail.client.company }),
260
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles__default.default.clientHeaderContact, children: [
261
- detail.client.firstName,
262
- " ",
263
- detail.client.lastName
264
- ] }),
265
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles__default.default.clientContactRow, children: [
266
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: detail.client.email }),
267
- detail.client.phone && /* @__PURE__ */ jsxRuntime.jsx("span", { children: detail.client.phone })
268
- ] }),
269
- detail.client.notes && /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles__default.default.clientNotes, children: detail.client.notes })
270
- ] }),
271
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles__default.default.headerActions, children: [
272
- /* @__PURE__ */ jsxRuntime.jsx(
273
- "a",
274
- {
275
- href: `/admin/collections/support-clients/${detail.client.id}`,
276
- className: styles__default.default.btnPrimary,
277
- children: t("crm.editButton")
278
- }
279
- ),
280
- /* @__PURE__ */ jsxRuntime.jsx(
281
- "button",
282
- {
283
- onClick: () => {
284
- setShowMerge(!showMerge);
285
- setMergeSearch("");
286
- setMergeResults([]);
287
- },
288
- className: styles__default.default.btnWarning,
289
- children: t("crm.mergeButton")
290
- }
291
- )
292
- ] })
293
- ] }),
294
- mergeSuccess && /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles__default.default.successBanner, children: mergeSuccess }),
295
- showMerge && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles__default.default.mergePanel, children: [
296
- /* @__PURE__ */ jsxRuntime.jsx("h4", { className: styles__default.default.mergePanelTitle, children: t("crm.mergeTitle") }),
297
- /* @__PURE__ */ jsxRuntime.jsxs("p", { className: styles__default.default.mergePanelDesc, children: [
298
- "Tous les tickets, messages, projets et enquetes de ",
299
- /* @__PURE__ */ jsxRuntime.jsx("strong", { children: detail.client.company }),
300
- " seront transferes vers le client cible. Le client actuel sera supprime."
301
- ] }),
302
- /* @__PURE__ */ jsxRuntime.jsx(
303
- "input",
304
- {
305
- type: "text",
306
- value: mergeSearch,
307
- onChange: (e) => setMergeSearch(e.target.value),
308
- placeholder: t("crm.mergeSearchPlaceholder"),
309
- className: styles__default.default.mergeInput
310
- }
311
- ),
312
- mergeResults.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles__default.default.mergeResultList, children: mergeResults.map((c) => /* @__PURE__ */ jsxRuntime.jsxs(
313
- "button",
314
- {
315
- onClick: () => handleMerge(c.id),
316
- disabled: merging,
317
- className: styles__default.default.mergeResultItem,
318
- children: [
319
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
320
- /* @__PURE__ */ jsxRuntime.jsx("strong", { children: c.company }),
321
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: styles__default.default.mergeResultName, children: [
322
- c.firstName,
323
- " ",
324
- c.lastName
325
- ] })
326
- ] }),
327
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: styles__default.default.mergeResultEmail, children: c.email })
328
- ]
329
- },
330
- c.id
331
- )) }),
332
- mergeSearch.length >= 2 && mergeResults.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("p", { className: styles__default.default.mergeEmpty, children: t("crm.mergeNoClient") })
333
- ] }),
334
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles__default.default.statsGrid, children: [
335
- { key: "total", label: t("crm.stats.totalTickets"), value: String(detail.stats.totalTickets) },
336
- { key: "open", label: t("crm.stats.openTickets"), value: String(detail.stats.openTickets) },
337
- { key: "resolved", label: t("crm.stats.resolvedTickets"), value: String(detail.stats.resolvedTickets) },
338
- { key: "time", label: t("crm.stats.timeSpent"), value: formatDuration(detail.stats.totalTimeMinutes) },
339
- { key: "activity", label: t("crm.stats.lastActivity"), value: detail.stats.lastActivity ? timeAgo(detail.stats.lastActivity, t) : "-" }
340
- ].map((stat) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles__default.default.statCard, children: [
341
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles__default.default.statLabel, children: stat.label }),
342
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: `${styles__default.default.statValue} ${getStatColorClass(stat.key, detail.stats)}`, children: stat.value })
343
- ] }, stat.key)) }),
344
- detail.projects.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles__default.default.sectionCard, children: [
345
- /* @__PURE__ */ jsxRuntime.jsxs("h3", { className: styles__default.default.sectionTitle, children: [
346
- t("crm.sections.projects"),
347
- " (",
348
- detail.projects.length,
349
- ")"
350
- ] }),
351
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles__default.default.projectList, children: detail.projects.map((p) => /* @__PURE__ */ jsxRuntime.jsxs(
352
- "a",
353
- {
354
- href: `/admin/collections/projects/${p.id}`,
355
- className: styles__default.default.projectChip,
356
- children: [
357
- p.name,
358
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: `${styles__default.default.badge} ${styles__default.default[projectStatusBadgeClass[p.status] || "badgeAccent"]}`, children: t(projectStatusLabelKeys[p.status] || "crm.projectStatus.active") })
359
- ]
360
- },
361
- p.id
362
- )) })
363
- ] }),
364
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles__default.default.sectionCard, style: { background: "linear-gradient(135deg, rgba(37,99,235,0.03) 0%, rgba(139,92,246,0.03) 100%)" }, children: [
365
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles__default.default.sectionHeader, children: [
366
- /* @__PURE__ */ jsxRuntime.jsxs("h3", { className: styles__default.default.sectionTitle, style: { display: "flex", alignItems: "center", gap: 6 }, children: [
367
- /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: 16 }, children: "\u{1F9E0}" }),
368
- " R\xE9sum\xE9 IA"
369
- ] }),
370
- /* @__PURE__ */ jsxRuntime.jsx(
371
- "button",
372
- {
373
- onClick: () => selectedId && fetchIntelligence(selectedId, true),
374
- disabled: intelRefreshing,
375
- className: styles__default.default.viewAllLink,
376
- style: { cursor: "pointer", background: "none", border: "none", fontWeight: 600 },
377
- children: intelRefreshing ? "\u23F3 G\xE9n\xE9ration..." : "\u{1F504} Actualiser"
378
- }
379
- )
380
- ] }),
381
- intelLoading ? /* @__PURE__ */ jsxRuntime.jsx("div", { style: { padding: 20, textAlign: "center", color: "#94a3b8", fontSize: 13 }, children: "Chargement du r\xE9sum\xE9..." }) : intelligence ? /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", flexDirection: "column", gap: 12 }, children: [
382
- /* @__PURE__ */ jsxRuntime.jsx("p", { style: { margin: 0, fontSize: 13, lineHeight: 1.6 }, children: intelligence.summary }),
383
- intelligence.recurringTopics?.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
384
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: 11, fontWeight: 700, color: "#6b7280", marginBottom: 6, textTransform: "uppercase" }, children: "Sujets r\xE9currents" }),
385
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", flexWrap: "wrap", gap: 6 }, children: intelligence.recurringTopics.map((tp, i) => /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { padding: "3px 10px", borderRadius: 12, background: "rgba(37,99,235,0.08)", color: "#2563eb", fontSize: 11, fontWeight: 600 }, children: [
386
- tp.topic,
387
- " (",
388
- tp.count,
389
- "x)"
390
- ] }, i)) })
391
- ] }),
392
- intelligence.patterns?.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
393
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: 11, fontWeight: 700, color: "#6b7280", marginBottom: 6, textTransform: "uppercase" }, children: "Patterns" }),
394
- /* @__PURE__ */ jsxRuntime.jsx("ul", { style: { margin: 0, paddingLeft: 18, fontSize: 12, lineHeight: 1.8 }, children: intelligence.patterns.map((p, i) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: p }, i)) })
395
- ] }),
396
- intelligence.keyFacts?.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
397
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: 11, fontWeight: 700, color: "#6b7280", marginBottom: 6, textTransform: "uppercase" }, children: "Faits cl\xE9s" }),
398
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", flexWrap: "wrap", gap: 6 }, children: intelligence.keyFacts.map((f, i) => /* @__PURE__ */ jsxRuntime.jsx("span", { style: { padding: "3px 10px", borderRadius: 12, background: "rgba(22,163,74,0.08)", color: "#16a34a", fontSize: 11, fontWeight: 600 }, children: f }, i)) })
399
- ] }),
400
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { fontSize: 10, color: "#9ca3af", display: "flex", gap: 12 }, children: [
401
- /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
402
- intelligence.ticketCount,
403
- " tickets"
404
- ] }),
405
- /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
406
- intelligence.messageCount,
407
- " messages"
408
- ] }),
409
- intelligence.averageSatisfaction && /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
410
- "Satisfaction: ",
411
- intelligence.averageSatisfaction,
412
- "/5"
413
- ] }),
414
- intelligence.fromCache && /* @__PURE__ */ jsxRuntime.jsx("span", { children: "\u2022 Cache" })
415
- ] })
416
- ] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { style: { padding: 16, textAlign: "center", color: "#94a3b8", fontSize: 13 }, children: "Cliquez sur \xAB Actualiser \xBB pour g\xE9n\xE9rer le r\xE9sum\xE9 IA." })
417
- ] }),
418
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles__default.default.sectionCard, children: [
419
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles__default.default.sectionHeader, children: [
420
- /* @__PURE__ */ jsxRuntime.jsxs("h3", { className: styles__default.default.sectionTitle, children: [
421
- t("crm.sections.tickets"),
422
- " (",
423
- detail.tickets.length,
424
- ")"
425
- ] }),
426
- /* @__PURE__ */ jsxRuntime.jsxs(
427
- "a",
428
- {
429
- href: `/admin/collections/tickets?where[client][equals]=${detail.client.id}`,
430
- className: styles__default.default.sectionLink,
431
- children: [
432
- t("crm.sections.viewAll"),
433
- " \u2192"
434
- ]
435
- }
436
- )
437
- ] }),
438
- detail.tickets.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles__default.default.ticketEmpty, children: t("crm.noTickets") }) : /* @__PURE__ */ jsxRuntime.jsxs("table", { className: styles__default.default.table, children: [
439
- /* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
440
- /* @__PURE__ */ jsxRuntime.jsx("th", { children: t("crm.tableHeaders.number") }),
441
- /* @__PURE__ */ jsxRuntime.jsx("th", { children: t("crm.tableHeaders.subject") }),
442
- /* @__PURE__ */ jsxRuntime.jsx("th", { children: t("crm.tableHeaders.status") }),
443
- /* @__PURE__ */ jsxRuntime.jsx("th", { children: t("crm.tableHeaders.date") })
444
- ] }) }),
445
- /* @__PURE__ */ jsxRuntime.jsx("tbody", { children: detail.tickets.map((tk) => /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
446
- /* @__PURE__ */ jsxRuntime.jsx("td", { children: /* @__PURE__ */ jsxRuntime.jsx("a", { href: `/admin/collections/tickets/${tk.id}`, className: styles__default.default.ticketLink, children: tk.ticketNumber }) }),
447
- /* @__PURE__ */ jsxRuntime.jsx("td", { className: styles__default.default.ticketSubject, children: tk.subject }),
448
- /* @__PURE__ */ jsxRuntime.jsx("td", { className: styles__default.default.ticketStatusCell, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: `${styles__default.default.badge} ${styles__default.default[statusBadgeClass[tk.status] || "badgeAccent"]}`, children: t(statusLabelKeys[tk.status] || "ticket.status.open") }) }),
449
- /* @__PURE__ */ jsxRuntime.jsx("td", { className: styles__default.default.ticketDate, children: timeAgo(tk.createdAt, t) })
450
- ] }, tk.id)) })
451
- ] })
452
- ] })
453
- ] }) : null })
454
- ] })
455
- ] });
456
- };
457
-
458
- exports.CrmClient = CrmClient;
@@ -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 CrmView = ({ 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: "CrmView", children: /* @__PURE__ */ jsxRuntime.jsx(client.CrmClient, {}) })
28
- }
29
- );
30
- };
31
- var CrmView_default = CrmView;
32
-
33
- exports.CrmView = CrmView;
34
- exports.default = CrmView_default;