@consilioweb/payload-support 0.8.2 → 0.9.5

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 (50) hide show
  1. package/dist/components/RichTextEditor/index.cjs +233 -0
  2. package/dist/components/RichTextEditor/index.js +232 -0
  3. package/dist/components/TicketConversation/components/CodeBlock.cjs +24 -7
  4. package/dist/components/TicketConversation/components/CodeBlock.js +23 -9
  5. package/dist/index.cjs +19 -1
  6. package/dist/index.js +19 -1
  7. package/dist/views/BillingView/client.cjs +260 -103
  8. package/dist/views/BillingView/client.js +259 -103
  9. package/dist/views/ChatView/client.cjs +184 -137
  10. package/dist/views/ChatView/client.js +180 -137
  11. package/dist/views/CrmView/client.cjs +270 -122
  12. package/dist/views/CrmView/client.js +266 -122
  13. package/dist/views/EmailTrackingView/client.cjs +80 -69
  14. package/dist/views/EmailTrackingView/client.js +80 -70
  15. package/dist/views/ImportConversationView/client.cjs +127 -94
  16. package/dist/views/ImportConversationView/client.js +123 -94
  17. package/dist/views/LogsView/client.cjs +56 -58
  18. package/dist/views/LogsView/client.js +52 -58
  19. package/dist/views/NewTicketView/client.cjs +39 -55
  20. package/dist/views/NewTicketView/client.js +38 -55
  21. package/dist/views/PendingEmailsView/client.cjs +399 -102
  22. package/dist/views/PendingEmailsView/client.js +396 -103
  23. package/dist/views/SupportDashboardView/client.cjs +276 -137
  24. package/dist/views/SupportDashboardView/client.js +275 -137
  25. package/dist/views/TicketDetailView/client.cjs +487 -204
  26. package/dist/views/TicketDetailView/client.js +486 -204
  27. package/dist/views/TicketInboxView/client.cjs +62 -65
  28. package/dist/views/TicketInboxView/client.js +62 -66
  29. package/dist/views/TicketingSettingsView/client.cjs +10 -8
  30. package/dist/views/TicketingSettingsView/client.js +10 -8
  31. package/dist/views/TimeDashboardView/client.cjs +70 -59
  32. package/dist/views/TimeDashboardView/client.js +69 -59
  33. package/package.json +7 -3
  34. package/src/components/RichTextEditor/index.tsx +261 -0
  35. package/src/components/TicketConversation/components/CodeBlock.tsx +53 -14
  36. package/src/plugin.ts +2 -0
  37. package/src/utils/emailTemplate.ts +37 -0
  38. package/src/views/BillingView/client.tsx +362 -69
  39. package/src/views/ChatView/client.tsx +225 -140
  40. package/src/views/CrmView/client.tsx +447 -189
  41. package/src/views/EmailTrackingView/client.tsx +111 -71
  42. package/src/views/ImportConversationView/client.tsx +255 -70
  43. package/src/views/LogsView/client.tsx +85 -50
  44. package/src/views/NewTicketView/client.tsx +37 -53
  45. package/src/views/PendingEmailsView/client.tsx +512 -92
  46. package/src/views/SupportDashboardView/client.tsx +294 -134
  47. package/src/views/TicketDetailView/client.tsx +486 -213
  48. package/src/views/TicketInboxView/client.tsx +52 -61
  49. package/src/views/TicketingSettingsView/client.tsx +10 -9
  50. package/src/views/TimeDashboardView/client.tsx +184 -69
@@ -3,9 +3,32 @@
3
3
  var jsxRuntime = require('react/jsx-runtime');
4
4
  var react = require('react');
5
5
  var useTranslation = require('../../components/TicketConversation/hooks/useTranslation');
6
+ var styles = require('../../styles/CrmView.module.scss');
6
7
 
7
- const statusLabelKeys = { open: "ticket.status.open", waiting_client: "ticket.status.waiting_client", resolved: "ticket.status.resolved" };
8
- const statusColors = { open: "#3b82f6", waiting_client: "#f59e0b", resolved: "#22c55e" };
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
+ };
9
32
  function formatDuration(minutes) {
10
33
  const h = Math.floor(minutes / 60);
11
34
  const m = minutes % 60;
@@ -19,7 +42,24 @@ function timeAgo(dateStr) {
19
42
  if (days === 0) return "Aujourd'hui";
20
43
  if (days === 1) return "Hier";
21
44
  if (days < 30) return `Il y a ${days}j`;
22
- return `Il y a ${Math.floor(days / 30)} mois`;
45
+ const months = Math.floor(days / 30);
46
+ return `Il y a ${months} mois`;
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
+ }
23
63
  }
24
64
  const CrmClient = () => {
25
65
  const { t } = useTranslation.useTranslation();
@@ -31,11 +71,11 @@ const CrmClient = () => {
31
71
  const [detailLoading, setDetailLoading] = react.useState(false);
32
72
  const [showMerge, setShowMerge] = react.useState(false);
33
73
  const [mergeSearch, setMergeSearch] = react.useState("");
74
+ const [mergeResults, setMergeResults] = react.useState([]);
75
+ const [merging, setMerging] = react.useState(false);
34
76
  const [intelligence, setIntelligence] = react.useState(null);
35
77
  const [intelLoading, setIntelLoading] = react.useState(false);
36
78
  const [intelRefreshing, setIntelRefreshing] = react.useState(false);
37
- const [mergeResults, setMergeResults] = react.useState([]);
38
- const [merging, setMerging] = react.useState(false);
39
79
  const [mergeSuccess, setMergeSuccess] = react.useState("");
40
80
  const fetchClients = react.useCallback(async () => {
41
81
  try {
@@ -72,9 +112,25 @@ const CrmClient = () => {
72
112
  const timeData = await timeRes.json();
73
113
  totalTimeMinutes = timeData.docs.filter((e) => ticketIds.includes(e.ticket)).reduce((sum, e) => sum + (e.duration || 0), 0);
74
114
  }
75
- const openTickets = tickets.filter((t2) => ["open", "waiting_client"].includes(t2.status)).length;
76
- const resolvedTickets = tickets.filter((t2) => t2.status === "resolved").length;
77
- setDetail({ client, tickets, projects, stats: { totalTickets: tickets.length, openTickets, resolvedTickets, totalTimeMinutes, lastActivity: tickets.length > 0 ? tickets[0].createdAt : null } });
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
+ });
78
134
  } catch {
79
135
  setDetail(null);
80
136
  }
@@ -99,9 +155,9 @@ const CrmClient = () => {
99
155
  setSelectedId(id);
100
156
  fetchDetail(id);
101
157
  fetchIntelligence(id);
158
+ setIntelligence(null);
102
159
  setShowMerge(false);
103
160
  setMergeSuccess("");
104
- setIntelligence(null);
105
161
  };
106
162
  react.useEffect(() => {
107
163
  if (!mergeSearch || mergeSearch.length < 2) {
@@ -110,7 +166,7 @@ const CrmClient = () => {
110
166
  }
111
167
  const timer = setTimeout(async () => {
112
168
  try {
113
- const res = await fetch(`/api/support-clients?where[or][0][company][like]=${encodeURIComponent(mergeSearch)}&where[or][1][email][like]=${encodeURIComponent(mergeSearch)}&limit=10&depth=0`);
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`);
114
170
  if (res.ok) {
115
171
  const json = await res.json();
116
172
  setMergeResults((json.docs || []).filter((c) => c.id !== selectedId));
@@ -122,10 +178,20 @@ const CrmClient = () => {
122
178
  }, [mergeSearch, selectedId]);
123
179
  const handleMerge = async (targetId) => {
124
180
  if (!selectedId || !detail) return;
125
- if (!confirm(`Fusionner ce client dans un autre ? Cette action est irreversible.`)) 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;
126
188
  setMerging(true);
127
189
  try {
128
- const res = await fetch("/api/support/merge-clients", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ sourceId: selectedId, targetId }) });
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
+ });
129
195
  if (res.ok) {
130
196
  const data = await res.json();
131
197
  setMergeSuccess(data.message);
@@ -138,94 +204,166 @@ const CrmClient = () => {
138
204
  alert(`Erreur : ${err.error}`);
139
205
  }
140
206
  } catch {
141
- alert("Erreur reseau");
207
+ alert("Erreur r\xE9seau");
142
208
  }
143
209
  setMerging(false);
144
210
  };
145
- const S = {
146
- page: { padding: "20px 30px", maxWidth: 1200, margin: "0 auto" },
147
- grid: { display: "grid", gridTemplateColumns: "300px 1fr", gap: 20 },
148
- sidebar: { borderRight: "1px solid var(--theme-elevation-200)", paddingRight: 16 },
149
- searchInput: { width: "100%", padding: "8px 12px", borderRadius: 8, border: "1px solid var(--theme-elevation-200)", fontSize: 13, marginBottom: 12, color: "var(--theme-text)", background: "var(--theme-elevation-0)" },
150
- clientItem: { padding: "10px 12px", borderRadius: 8, cursor: "pointer", marginBottom: 4, border: "1px solid transparent" },
151
- clientItemActive: { background: "var(--theme-elevation-50)", borderColor: "var(--theme-elevation-200)" },
152
- statsGrid: { display: "grid", gridTemplateColumns: "repeat(5, 1fr)", gap: 8, marginBottom: 16 },
153
- statCard: { padding: "10px 12px", borderRadius: 8, border: "1px solid var(--theme-elevation-150)", textAlign: "center" },
154
- table: { width: "100%", borderCollapse: "collapse", fontSize: 13 },
155
- th: { textAlign: "left", padding: "6px 8px", borderBottom: "1px solid var(--theme-elevation-200)", fontSize: 11, color: "var(--theme-elevation-500)" },
156
- td: { padding: "6px 8px", borderBottom: "1px solid var(--theme-elevation-100)" },
157
- badge: { padding: "2px 6px", borderRadius: 4, fontSize: 10, fontWeight: 600 }
158
- };
159
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: S.page, children: [
160
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { marginBottom: 20 }, children: [
161
- /* @__PURE__ */ jsxRuntime.jsx("h1", { style: { fontSize: 22, fontWeight: 700, margin: 0, color: "var(--theme-text)" }, children: t("crm.title") }),
162
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: 13, color: "var(--theme-elevation-500)", marginTop: 4 }, children: t("crm.subtitle") })
163
- ] }),
164
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: S.grid, children: [
165
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: S.sidebar, children: [
166
- /* @__PURE__ */ jsxRuntime.jsx("input", { type: "text", placeholder: t("crm.searchPlaceholder"), value: search, onChange: (e) => setSearch(e.target.value), style: S.searchInput }),
167
- /* @__PURE__ */ jsxRuntime.jsx("div", { children: loading ? /* @__PURE__ */ jsxRuntime.jsx("div", { style: { padding: 20, textAlign: "center", color: "#94a3b8" }, children: t("common.loading") }) : clients.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { style: { padding: 20, textAlign: "center", color: "#94a3b8" }, children: t("crm.noClientFound") }) : clients.map((c) => /* @__PURE__ */ jsxRuntime.jsxs("div", { onClick: () => selectClient(c.id), style: { ...S.clientItem, ...selectedId === c.id ? S.clientItemActive : {} }, children: [
168
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontWeight: 600, fontSize: 13 }, children: c.company }),
169
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { fontSize: 12, color: "var(--theme-elevation-500)" }, children: [
170
- c.firstName,
171
- " ",
172
- c.lastName
173
- ] }),
174
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: 11, color: "var(--theme-elevation-400)" }, children: c.email })
175
- ] }, c.id)) })
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
+ )) })
176
250
  ] }),
177
- /* @__PURE__ */ jsxRuntime.jsx("div", { children: !selectedId ? /* @__PURE__ */ jsxRuntime.jsx("div", { style: { padding: 60, textAlign: "center", color: "#94a3b8" }, children: t("crm.selectClient") }) : detailLoading ? /* @__PURE__ */ jsxRuntime.jsx("div", { style: { padding: 60, textAlign: "center", color: "#94a3b8" }, children: t("common.loading") }) : detail ? /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
178
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", justifyContent: "space-between", marginBottom: 16 }, children: [
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: [
179
258
  /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
180
- /* @__PURE__ */ jsxRuntime.jsx("h2", { style: { fontSize: 20, fontWeight: 700, margin: 0 }, children: detail.client.company }),
181
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { fontSize: 13, color: "var(--theme-elevation-500)" }, 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: [
182
261
  detail.client.firstName,
183
262
  " ",
184
263
  detail.client.lastName
185
264
  ] }),
186
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { fontSize: 12, color: "var(--theme-elevation-400)" }, children: [
187
- detail.client.email,
188
- " ",
189
- detail.client.phone && `-- ${detail.client.phone}`
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 })
190
268
  ] }),
191
- detail.client.notes && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: 12, color: "var(--theme-elevation-500)", marginTop: 4, fontStyle: "italic" }, children: detail.client.notes })
269
+ detail.client.notes && /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles__default.default.clientNotes, children: detail.client.notes })
192
270
  ] }),
193
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", gap: 8 }, children: [
194
- /* @__PURE__ */ jsxRuntime.jsx("a", { href: `/admin/collections/support-clients/${detail.client.id}`, style: { padding: "6px 14px", borderRadius: 6, background: "#2563eb", color: "#fff", fontSize: 12, fontWeight: 600, textDecoration: "none" }, children: t("crm.editButton") }),
195
- /* @__PURE__ */ jsxRuntime.jsx("button", { onClick: () => {
196
- setShowMerge(!showMerge);
197
- setMergeSearch("");
198
- setMergeResults([]);
199
- }, style: { padding: "6px 14px", borderRadius: 6, border: "1px solid #d97706", background: "none", color: "#d97706", fontSize: 12, fontWeight: 600, cursor: "pointer" }, children: t("crm.mergeButton") })
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
+ )
200
292
  ] })
201
293
  ] }),
202
- mergeSuccess && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { padding: "8px 14px", borderRadius: 6, background: "#dcfce7", color: "#166534", fontSize: 13, marginBottom: 12 }, children: mergeSuccess }),
203
- showMerge && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { padding: 16, borderRadius: 8, border: "1px solid #fde68a", background: "#fefce8", marginBottom: 16 }, children: [
204
- /* @__PURE__ */ jsxRuntime.jsx("h4", { style: { margin: "0 0 8px", fontSize: 14 }, children: t("crm.mergeTitle") }),
205
- /* @__PURE__ */ jsxRuntime.jsx("input", { type: "text", value: mergeSearch, onChange: (e) => setMergeSearch(e.target.value), placeholder: t("crm.mergeSearchPlaceholder"), style: S.searchInput }),
206
- mergeResults.map((c) => /* @__PURE__ */ jsxRuntime.jsxs("button", { onClick: () => handleMerge(c.id), disabled: merging, style: { display: "block", width: "100%", padding: "8px 12px", border: "1px solid var(--theme-elevation-200)", borderRadius: 6, background: "var(--theme-elevation-0)", cursor: "pointer", textAlign: "left", marginBottom: 4, fontSize: 13 }, children: [
207
- /* @__PURE__ */ jsxRuntime.jsx("strong", { children: c.company }),
208
- " -- ",
209
- c.firstName,
210
- " ",
211
- c.lastName,
212
- " ",
213
- /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "var(--theme-elevation-400)", fontSize: 11 }, children: c.email })
214
- ] }, c.id))
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") })
215
333
  ] }),
216
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: S.statsGrid, children: [
217
- { label: t("crm.stats.totalTickets"), value: String(detail.stats.totalTickets) },
218
- { label: t("crm.stats.openTickets"), value: String(detail.stats.openTickets) },
219
- { label: t("crm.stats.resolvedTickets"), value: String(detail.stats.resolvedTickets) },
220
- { label: t("crm.stats.timeSpent"), value: formatDuration(detail.stats.totalTimeMinutes) },
221
- { label: t("crm.stats.lastActivity"), value: detail.stats.lastActivity ? timeAgo(detail.stats.lastActivity) : "-" }
222
- ].map((stat) => /* @__PURE__ */ jsxRuntime.jsxs("div", { style: S.statCard, children: [
223
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: 11, color: "var(--theme-elevation-500)", marginBottom: 2 }, children: stat.label }),
224
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: 18, fontWeight: 700, color: "var(--theme-text)" }, children: stat.value })
225
- ] }, stat.label)) }),
226
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { padding: 16, borderRadius: 10, border: "1px solid var(--theme-elevation-150)", marginBottom: 16, background: "linear-gradient(135deg, rgba(37,99,235,0.03) 0%, rgba(139,92,246,0.03) 100%)" }, children: [
227
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 12 }, children: [
228
- /* @__PURE__ */ jsxRuntime.jsxs("h3", { style: { fontSize: 14, fontWeight: 700, margin: 0, display: "flex", alignItems: "center", gap: 6 }, children: [
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) : "-" }
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: [
229
367
  /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: 16 }, children: "\u{1F9E0}" }),
230
368
  " R\xE9sum\xE9 IA"
231
369
  ] }),
@@ -234,34 +372,35 @@ const CrmClient = () => {
234
372
  {
235
373
  onClick: () => selectedId && fetchIntelligence(selectedId, true),
236
374
  disabled: intelRefreshing,
237
- style: { padding: "4px 10px", borderRadius: 6, border: "1px solid var(--theme-elevation-200)", background: "var(--theme-elevation-0)", fontSize: 11, fontWeight: 600, cursor: "pointer", color: "var(--theme-text)" },
375
+ className: styles__default.default.viewAllLink,
376
+ style: { cursor: "pointer", background: "none", border: "none", fontWeight: 600 },
238
377
  children: intelRefreshing ? "\u23F3 G\xE9n\xE9ration..." : "\u{1F504} Actualiser"
239
378
  }
240
379
  )
241
380
  ] }),
242
- intelLoading ? /* @__PURE__ */ jsxRuntime.jsx("div", { style: { padding: 20, textAlign: "center", color: "var(--theme-elevation-400)", fontSize: 13 }, children: "Chargement du r\xE9sum\xE9..." }) : intelligence ? /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", flexDirection: "column", gap: 12 }, children: [
243
- /* @__PURE__ */ jsxRuntime.jsx("p", { style: { margin: 0, fontSize: 13, lineHeight: 1.6, color: "var(--theme-text)" }, children: intelligence.summary }),
244
- intelligence.recurringTopics && intelligence.recurringTopics.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
245
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: 11, fontWeight: 700, color: "var(--theme-elevation-500)", marginBottom: 6, textTransform: "uppercase" }, children: "Sujets r\xE9currents" }),
246
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", flexWrap: "wrap", gap: 6 }, children: intelligence.recurringTopics.map((t2, 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: [
247
- t2.topic,
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,
248
387
  " (",
249
- t2.count,
388
+ tp.count,
250
389
  "x)"
251
390
  ] }, i)) })
252
391
  ] }),
253
- intelligence.patterns && intelligence.patterns.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
254
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: 11, fontWeight: 700, color: "var(--theme-elevation-500)", marginBottom: 6, textTransform: "uppercase" }, children: "Patterns d\xE9tect\xE9s" }),
255
- /* @__PURE__ */ jsxRuntime.jsx("ul", { style: { margin: 0, paddingLeft: 18, fontSize: 12, color: "var(--theme-text)", lineHeight: 1.8 }, children: intelligence.patterns.map((p, i) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: p }, i)) })
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)) })
256
395
  ] }),
257
- intelligence.keyFacts && intelligence.keyFacts.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
258
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: 11, fontWeight: 700, color: "var(--theme-elevation-500)", marginBottom: 6, textTransform: "uppercase" }, children: "Faits cl\xE9s" }),
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" }),
259
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)) })
260
399
  ] }),
261
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { fontSize: 10, color: "var(--theme-elevation-400)", display: "flex", gap: 12, marginTop: 4 }, children: [
400
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { fontSize: 10, color: "#9ca3af", display: "flex", gap: 12 }, children: [
262
401
  /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
263
402
  intelligence.ticketCount,
264
- " tickets analys\xE9s"
403
+ " tickets"
265
404
  ] }),
266
405
  /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
267
406
  intelligence.messageCount,
@@ -272,33 +411,42 @@ const CrmClient = () => {
272
411
  intelligence.averageSatisfaction,
273
412
  "/5"
274
413
  ] }),
275
- intelligence.fromCache && /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Cache" }),
276
- intelligence.generatedAt && /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
277
- "G\xE9n\xE9r\xE9 ",
278
- timeAgo(intelligence.generatedAt)
279
- ] })
414
+ intelligence.fromCache && /* @__PURE__ */ jsxRuntime.jsx("span", { children: "\u2022 Cache" })
280
415
  ] })
281
- ] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { style: { padding: 16, textAlign: "center", color: "var(--theme-elevation-400)", fontSize: 13 }, children: 'Cliquez sur "Actualiser" pour g\xE9n\xE9rer le r\xE9sum\xE9 IA de ce client.' })
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." })
282
417
  ] }),
283
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { padding: 16, borderRadius: 10, border: "1px solid var(--theme-elevation-150)", marginBottom: 16 }, children: [
284
- /* @__PURE__ */ jsxRuntime.jsxs("h3", { style: { fontSize: 14, fontWeight: 700, margin: "0 0 8px" }, children: [
285
- t("crm.sections.tickets"),
286
- " (",
287
- detail.tickets.length,
288
- ")"
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
+ )
289
437
  ] }),
290
- detail.tickets.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { style: { color: "#94a3b8", fontSize: 13 }, children: t("crm.noTickets") }) : /* @__PURE__ */ jsxRuntime.jsxs("table", { style: S.table, children: [
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: [
291
439
  /* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
292
- /* @__PURE__ */ jsxRuntime.jsx("th", { style: S.th, children: t("crm.tableHeaders.number") }),
293
- /* @__PURE__ */ jsxRuntime.jsx("th", { style: S.th, children: t("crm.tableHeaders.subject") }),
294
- /* @__PURE__ */ jsxRuntime.jsx("th", { style: S.th, children: t("crm.tableHeaders.status") }),
295
- /* @__PURE__ */ jsxRuntime.jsx("th", { style: S.th, children: t("crm.tableHeaders.date") })
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") })
296
444
  ] }) }),
297
445
  /* @__PURE__ */ jsxRuntime.jsx("tbody", { children: detail.tickets.map((tk) => /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
298
- /* @__PURE__ */ jsxRuntime.jsx("td", { style: S.td, children: /* @__PURE__ */ jsxRuntime.jsx("a", { href: `/admin/support/ticket?id=${tk.id}`, style: { color: "#2563eb", fontWeight: 600, textDecoration: "none" }, children: tk.ticketNumber }) }),
299
- /* @__PURE__ */ jsxRuntime.jsx("td", { style: S.td, children: tk.subject }),
300
- /* @__PURE__ */ jsxRuntime.jsx("td", { style: S.td, children: /* @__PURE__ */ jsxRuntime.jsx("span", { style: { ...S.badge, background: `${statusColors[tk.status] || "#94a3b8"}20`, color: statusColors[tk.status] || "#94a3b8" }, children: statusLabelKeys[tk.status] ? t(statusLabelKeys[tk.status]) : tk.status }) }),
301
- /* @__PURE__ */ jsxRuntime.jsx("td", { style: { ...S.td, fontSize: 12, color: "var(--theme-elevation-400)" }, children: timeAgo(tk.createdAt) })
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) })
302
450
  ] }, tk.id)) })
303
451
  ] })
304
452
  ] })