@consilioweb/payload-support 0.5.2 → 0.6.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 (85) hide show
  1. package/dist/components/TicketConversation/components/AISummaryPanel.js +76 -0
  2. package/dist/components/TicketConversation/components/ActionPanels.js +118 -0
  3. package/dist/components/TicketConversation/components/ActivityLog.js +23 -0
  4. package/dist/components/TicketConversation/components/ClientBar.js +42 -0
  5. package/dist/components/TicketConversation/components/ClientHistory.js +137 -0
  6. package/dist/components/TicketConversation/components/CodeBlock.js +152 -0
  7. package/dist/components/TicketConversation/components/CodeBlockInserter.js +155 -0
  8. package/dist/components/TicketConversation/components/QuickActions.js +65 -0
  9. package/dist/components/TicketConversation/components/TicketHeader.js +92 -0
  10. package/dist/components/TicketConversation/components/TimeTrackingPanel.js +133 -0
  11. package/dist/components/TicketConversation/config.js +41 -0
  12. package/dist/components/TicketConversation/constants.js +96 -0
  13. package/dist/components/TicketConversation/context.js +11 -0
  14. package/dist/components/TicketConversation/hooks/useAI.js +176 -0
  15. package/dist/components/TicketConversation/hooks/useMessageActions.js +135 -0
  16. package/dist/components/TicketConversation/hooks/useReply.js +187 -0
  17. package/dist/components/TicketConversation/hooks/useTicketActions.js +230 -0
  18. package/dist/components/TicketConversation/hooks/useTimeTracking.js +122 -0
  19. package/dist/components/TicketConversation/hooks/useTranslation.js +70 -0
  20. package/dist/components/TicketConversation/index.js +1123 -0
  21. package/dist/components/TicketConversation/locales/en.json +878 -0
  22. package/dist/components/TicketConversation/locales/fr.json +878 -0
  23. package/dist/components/TicketConversation/types.js +2 -0
  24. package/dist/components/TicketConversation/utils.js +25 -0
  25. package/dist/index.cjs +2 -2
  26. package/dist/index.js +2 -2
  27. package/dist/styles/BillingView.module.scss +311 -0
  28. package/dist/styles/ChatView.module.scss +438 -0
  29. package/dist/styles/CommandPalette.module.scss +160 -0
  30. package/dist/styles/CrmView.module.scss +554 -0
  31. package/dist/styles/EmailTracking.module.scss +238 -0
  32. package/dist/styles/ImportConversation.module.scss +267 -0
  33. package/dist/styles/Layout.module.scss +55 -0
  34. package/dist/styles/Logs.module.scss +164 -0
  35. package/dist/styles/NewTicket.module.scss +143 -0
  36. package/dist/styles/PendingEmails.module.scss +629 -0
  37. package/dist/styles/SupportDashboard.module.scss +649 -0
  38. package/dist/styles/TicketDetail.module.scss +1050 -0
  39. package/dist/styles/TicketInbox.module.scss +296 -0
  40. package/dist/styles/TicketingSettings.module.scss +358 -0
  41. package/dist/styles/TimeDashboard.module.scss +287 -0
  42. package/dist/styles/_tokens.scss +78 -0
  43. package/dist/styles/theme.css +633 -0
  44. package/dist/views/BillingView/client.js +204 -0
  45. package/dist/views/BillingView/index.js +29 -0
  46. package/dist/views/ChatView/client.js +252 -0
  47. package/dist/views/ChatView/index.js +29 -0
  48. package/dist/views/CrmView/client.js +232 -0
  49. package/dist/views/CrmView/index.js +29 -0
  50. package/dist/views/EmailTrackingView/client.js +154 -0
  51. package/dist/views/EmailTrackingView/index.js +29 -0
  52. package/dist/views/ImportConversationView/client.js +204 -0
  53. package/dist/views/ImportConversationView/index.js +29 -0
  54. package/dist/views/LogsView/client.js +148 -0
  55. package/dist/views/LogsView/index.js +27 -0
  56. package/dist/views/NewTicketView/client.js +224 -0
  57. package/dist/views/NewTicketView/index.js +27 -0
  58. package/dist/views/PendingEmailsView/client.js +172 -0
  59. package/dist/views/PendingEmailsView/index.js +29 -0
  60. package/dist/views/SupportDashboardView/client.js +296 -0
  61. package/dist/views/SupportDashboardView/index.js +29 -0
  62. package/dist/views/TicketDetailView/client.js +844 -0
  63. package/dist/views/TicketDetailView/index.js +29 -0
  64. package/dist/views/TicketInboxView/client.js +294 -0
  65. package/dist/views/TicketInboxView/index.js +27 -0
  66. package/dist/{views.css → views/TicketingSettingsView/TicketingSettings.module.scss} +138 -66
  67. package/dist/views/TicketingSettingsView/client.js +728 -0
  68. package/dist/views/TicketingSettingsView/index.js +29 -0
  69. package/dist/views/TimeDashboardView/client.js +164 -0
  70. package/dist/views/TimeDashboardView/index.js +29 -0
  71. package/dist/views/shared/AdminViewHeader.js +67 -0
  72. package/dist/views/shared/ErrorBoundary.js +50 -0
  73. package/dist/views/shared/Skeleton.js +72 -0
  74. package/dist/views/shared/adminTokens.js +32 -0
  75. package/dist/views/shared/config.js +41 -0
  76. package/dist/views/shared/index.js +6 -0
  77. package/package.json +8 -12
  78. package/src/collections/Tickets.ts +1 -1
  79. package/src/components/TicketConversation/index.tsx +21 -2
  80. package/src/plugin.ts +3 -2
  81. package/dist/views.cjs +0 -6172
  82. package/dist/views.d.cts +0 -30
  83. package/dist/views.d.ts +0 -30
  84. package/dist/views.js +0 -6153
  85. package/src/views.ts +0 -16
@@ -0,0 +1,76 @@
1
+ "use client";
2
+ import { jsxs, jsx } from 'react/jsx-runtime';
3
+ import { s } from '../constants';
4
+
5
+ function AISummaryPanel({
6
+ showAiSummary,
7
+ setShowAiSummary,
8
+ aiSummary,
9
+ aiGenerating,
10
+ aiSaving,
11
+ aiSaved,
12
+ handleAiGenerate,
13
+ handleAiSave
14
+ }) {
15
+ return /* @__PURE__ */ jsxs("div", { style: { marginBottom: "14px" }, children: [
16
+ /* @__PURE__ */ jsx(
17
+ "button",
18
+ {
19
+ onClick: () => {
20
+ setShowAiSummary(!showAiSummary);
21
+ if (!showAiSummary && !aiSummary) handleAiGenerate();
22
+ },
23
+ style: {
24
+ ...s.ghostBtn("#7c3aed", false),
25
+ fontSize: "12px",
26
+ display: "inline-flex",
27
+ alignItems: "center",
28
+ gap: "6px"
29
+ },
30
+ children: showAiSummary ? "Masquer la synth\xE8se IA" : "Synth\xE8se IA"
31
+ }
32
+ ),
33
+ showAiSummary && /* @__PURE__ */ jsxs("div", { style: {
34
+ marginTop: "10px",
35
+ padding: "14px 18px",
36
+ borderRadius: "8px",
37
+ backgroundColor: "#faf5ff",
38
+ border: "1px solid #e9d5ff"
39
+ }, children: [
40
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: "10px" }, children: [
41
+ /* @__PURE__ */ jsx("h4", { style: { fontSize: "13px", fontWeight: 600, color: "#7c3aed", margin: 0 }, children: "Synth\xE8se IA" }),
42
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: "6px" }, children: [
43
+ /* @__PURE__ */ jsx(
44
+ "button",
45
+ {
46
+ onClick: handleAiGenerate,
47
+ disabled: aiGenerating,
48
+ style: { ...s.outlineBtn("#7c3aed", aiGenerating), fontSize: "11px", padding: "4px 10px" },
49
+ children: aiGenerating ? "G\xE9n\xE9ration..." : "R\xE9g\xE9n\xE9rer"
50
+ }
51
+ ),
52
+ aiSummary && !aiGenerating && /* @__PURE__ */ jsx(
53
+ "button",
54
+ {
55
+ onClick: handleAiSave,
56
+ disabled: aiSaving || aiSaved,
57
+ style: { ...s.btn(aiSaved ? "#16a34a" : "#2563eb", aiSaving), fontSize: "11px", padding: "4px 10px" },
58
+ children: aiSaved ? "Sauvegard\xE9" : aiSaving ? "Sauvegarde..." : "Sauvegarder (note interne)"
59
+ }
60
+ )
61
+ ] })
62
+ ] }),
63
+ aiGenerating ? /* @__PURE__ */ jsx("div", { style: { display: "flex", alignItems: "center", gap: "10px", color: "#7c3aed", fontSize: "13px" }, children: "Analyse de la conversation en cours..." }) : aiSummary ? /* @__PURE__ */ jsx(
64
+ "div",
65
+ {
66
+ style: { fontSize: "13px", lineHeight: "1.7", color: "#1e1b4b", whiteSpace: "pre-wrap" },
67
+ dangerouslySetInnerHTML: {
68
+ __html: aiSummary.replace(/\*\*(.*?)\*\*/g, "<strong>$1</strong>").replace(/\n/g, "<br/>")
69
+ }
70
+ }
71
+ ) : /* @__PURE__ */ jsx("p", { style: { color: "#999", fontStyle: "italic", fontSize: "13px", margin: 0 }, children: `Cliquez sur "R\xE9g\xE9n\xE9rer" pour lancer l'analyse` })
72
+ ] })
73
+ ] });
74
+ }
75
+
76
+ export { AISummaryPanel };
@@ -0,0 +1,118 @@
1
+ "use client";
2
+ import { jsxs, jsx } from 'react/jsx-runtime';
3
+ import { useRef } from 'react';
4
+ import { s } from '../constants';
5
+
6
+ function MergePanel({
7
+ mergeTarget,
8
+ setMergeTarget,
9
+ mergeTargetInfo,
10
+ setMergeTargetInfo,
11
+ mergeError,
12
+ setMergeError,
13
+ merging,
14
+ handleMergeLookup,
15
+ handleMerge
16
+ }) {
17
+ return /* @__PURE__ */ jsxs("div", { style: { padding: "14px 18px", borderRadius: "8px", backgroundColor: "#fdf2f8", border: "1px solid #fbcfe8", marginBottom: "14px" }, children: [
18
+ /* @__PURE__ */ jsx("h4", { style: { fontSize: "13px", fontWeight: 600, marginBottom: "10px", color: "#831843" }, children: "Fusionner ce ticket dans un autre" }),
19
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: "8px", alignItems: "center", marginBottom: "8px" }, children: [
20
+ /* @__PURE__ */ jsx(
21
+ "input",
22
+ {
23
+ type: "text",
24
+ value: mergeTarget,
25
+ onChange: (e) => {
26
+ setMergeTarget(e.target.value);
27
+ setMergeTargetInfo(null);
28
+ setMergeError("");
29
+ },
30
+ placeholder: "TK-0001",
31
+ style: { ...s.input, width: "130px" }
32
+ }
33
+ ),
34
+ /* @__PURE__ */ jsx("button", { onClick: handleMergeLookup, style: { ...s.outlineBtn("#ec4899"), fontSize: "12px", padding: "6px 14px" }, children: "Rechercher" }),
35
+ mergeError && /* @__PURE__ */ jsx("span", { style: { fontSize: "12px", color: "#be185d", fontWeight: 600 }, children: mergeError })
36
+ ] }),
37
+ mergeTargetInfo && /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: "8px", alignItems: "center" }, children: [
38
+ /* @__PURE__ */ jsxs("span", { style: { fontSize: "13px", fontWeight: 600 }, children: [
39
+ mergeTargetInfo.ticketNumber,
40
+ " \u2014 ",
41
+ mergeTargetInfo.subject
42
+ ] }),
43
+ /* @__PURE__ */ jsx("button", { onClick: handleMerge, disabled: merging, style: { ...s.btn("#ec4899", merging), color: "#fff", fontSize: "12px", padding: "6px 14px" }, children: merging ? "Fusion..." : "Confirmer la fusion" })
44
+ ] })
45
+ ] });
46
+ }
47
+ function ExtMessagePanel({
48
+ extMsgBody,
49
+ setExtMsgBody,
50
+ extMsgAuthor,
51
+ setExtMsgAuthor,
52
+ extMsgDate,
53
+ setExtMsgDate,
54
+ extMsgFiles,
55
+ setExtMsgFiles,
56
+ sendingExtMsg,
57
+ handleSendExtMsg,
58
+ handleExtFileChange
59
+ }) {
60
+ const extFileInputRef = useRef(null);
61
+ return /* @__PURE__ */ jsxs("div", { style: { padding: "14px 18px", borderRadius: "8px", backgroundColor: "#eef2ff", border: "1px solid #c7d2fe", marginBottom: "14px" }, children: [
62
+ /* @__PURE__ */ jsx("h4", { style: { fontSize: "13px", fontWeight: 600, marginBottom: "10px", color: "#312e81" }, children: "Ajouter un message re\xE7u (email, SMS, WhatsApp...)" }),
63
+ /* @__PURE__ */ jsx(
64
+ "textarea",
65
+ {
66
+ value: extMsgBody,
67
+ onChange: (e) => setExtMsgBody(e.target.value),
68
+ placeholder: "Coller le contenu du message re\xE7u...",
69
+ rows: 3,
70
+ style: { ...s.input, width: "100%", resize: "vertical", marginBottom: "10px" }
71
+ }
72
+ ),
73
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: "8px", alignItems: "center", flexWrap: "wrap", marginBottom: "10px" }, children: [
74
+ /* @__PURE__ */ jsxs("select", { value: extMsgAuthor, onChange: (e) => setExtMsgAuthor(e.target.value), style: { ...s.input, fontSize: "12px" }, children: [
75
+ /* @__PURE__ */ jsx("option", { value: "client", children: "Envoy\xE9 par le client" }),
76
+ /* @__PURE__ */ jsx("option", { value: "admin", children: "Envoy\xE9 par le support" })
77
+ ] }),
78
+ /* @__PURE__ */ jsx(
79
+ "input",
80
+ {
81
+ type: "datetime-local",
82
+ value: extMsgDate,
83
+ onChange: (e) => setExtMsgDate(e.target.value),
84
+ style: { ...s.input, fontSize: "12px" }
85
+ }
86
+ ),
87
+ /* @__PURE__ */ jsx("input", { ref: extFileInputRef, type: "file", multiple: true, onChange: handleExtFileChange, style: { display: "none" }, accept: "image/*,.pdf,.doc,.docx,.txt,.zip" }),
88
+ /* @__PURE__ */ jsx("button", { type: "button", onClick: () => extFileInputRef.current?.click(), style: { ...s.ghostBtn("#6b7280"), fontSize: "12px", padding: "6px 12px" }, children: "+ PJ" })
89
+ ] }),
90
+ extMsgFiles.length > 0 && /* @__PURE__ */ jsx("div", { style: { marginBottom: "10px", display: "flex", gap: "6px", flexWrap: "wrap" }, children: extMsgFiles.map((file, i) => /* @__PURE__ */ jsxs("span", { style: { ...s.badge("#f1f5f9", "#374151"), display: "inline-flex", alignItems: "center", gap: "4px" }, children: [
91
+ file.name,
92
+ /* @__PURE__ */ jsx("button", { type: "button", onClick: () => setExtMsgFiles((prev) => prev.filter((_, idx) => idx !== i)), style: { border: "none", background: "none", color: "#ef4444", fontWeight: 700, cursor: "pointer", fontSize: "14px", lineHeight: 1 }, children: "\xD7" })
93
+ ] }, i)) }),
94
+ /* @__PURE__ */ jsx("button", { onClick: handleSendExtMsg, disabled: sendingExtMsg || !extMsgBody.trim(), style: s.btn("#818cf8", sendingExtMsg || !extMsgBody.trim()), children: sendingExtMsg ? "Ajout..." : "Ajouter (sans notification)" })
95
+ ] });
96
+ }
97
+ function SnoozePanel({ snoozeSaving, handleSnooze }) {
98
+ return /* @__PURE__ */ jsxs("div", { style: { padding: "14px 18px", borderRadius: "8px", backgroundColor: "#faf5ff", border: "1px solid #e9d5ff", marginBottom: "14px" }, children: [
99
+ /* @__PURE__ */ jsx("h4", { style: { fontSize: "13px", fontWeight: 600, marginBottom: "10px", color: "#5b21b6" }, children: "Snooze \u2014 masquer temporairement" }),
100
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: "8px", flexWrap: "wrap", alignItems: "center" }, children: [
101
+ /* @__PURE__ */ jsx("button", { onClick: () => handleSnooze(1), disabled: snoozeSaving, style: { ...s.outlineBtn("#8b5cf6", snoozeSaving), fontSize: "12px" }, children: "1 jour" }),
102
+ /* @__PURE__ */ jsx("button", { onClick: () => handleSnooze(3), disabled: snoozeSaving, style: { ...s.outlineBtn("#8b5cf6", snoozeSaving), fontSize: "12px" }, children: "3 jours" }),
103
+ /* @__PURE__ */ jsx("button", { onClick: () => handleSnooze(7), disabled: snoozeSaving, style: { ...s.outlineBtn("#8b5cf6", snoozeSaving), fontSize: "12px" }, children: "1 semaine" }),
104
+ /* @__PURE__ */ jsx(
105
+ "input",
106
+ {
107
+ type: "datetime-local",
108
+ onChange: (e) => {
109
+ if (e.target.value) handleSnooze(null, e.target.value);
110
+ },
111
+ style: { ...s.input, fontSize: "12px" }
112
+ }
113
+ )
114
+ ] })
115
+ ] });
116
+ }
117
+
118
+ export { ExtMessagePanel, MergePanel, SnoozePanel };
@@ -0,0 +1,23 @@
1
+ "use client";
2
+ import { jsxs, jsx } from 'react/jsx-runtime';
3
+ import { useState } from 'react';
4
+ import { s, C } from '../constants';
5
+
6
+ function ActivityLog({ activityLog }) {
7
+ const [showActivity, setShowActivity] = useState(false);
8
+ return /* @__PURE__ */ jsxs("div", { style: s.section, children: [
9
+ /* @__PURE__ */ jsxs("h4", { style: { ...s.sectionTitle, cursor: "pointer" }, onClick: () => setShowActivity(!showActivity), children: [
10
+ "Historique ",
11
+ /* @__PURE__ */ jsx("span", { style: s.badge("#f1f5f9", "#475569"), children: activityLog.length }),
12
+ /* @__PURE__ */ jsx("span", { style: { fontSize: "12px", color: C.textMuted, transition: "transform 0.2s", display: "inline-block", transform: showActivity ? "rotate(90deg)" : "none" }, children: "\u25B6" })
13
+ ] }),
14
+ showActivity && (activityLog.length === 0 ? /* @__PURE__ */ jsx("p", { style: { fontSize: "12px", color: C.textMuted, fontStyle: "italic" }, children: "Aucune activit\xE9 enregistr\xE9e." }) : /* @__PURE__ */ jsx("div", { style: { fontSize: "12px", display: "flex", flexDirection: "column", gap: "2px", borderLeft: "2px solid #bfdbfe", paddingLeft: "14px", marginLeft: "4px" }, children: activityLog.map((entry) => /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: "10px", alignItems: "center", padding: "5px 0", borderBottom: "1px solid #f8fafc" }, children: [
15
+ /* @__PURE__ */ jsx("span", { style: { color: C.textMuted, fontSize: "11px", whiteSpace: "nowrap", fontWeight: 500 }, children: new Date(entry.createdAt).toLocaleString("fr-FR", { day: "numeric", month: "short", hour: "2-digit", minute: "2-digit" }) }),
16
+ /* @__PURE__ */ jsx("span", { style: s.badge(entry.actorType === "admin" ? "#eff6ff" : "#dcfce7", entry.actorType === "admin" ? "#1e40af" : "#166534"), children: entry.actorType || "system" }),
17
+ /* @__PURE__ */ jsx("span", { style: { color: "#374151", fontWeight: 500 }, children: (entry.detail || entry.action).replace(/\[object Object\]/g, "(utilisateur)") }),
18
+ /* @__PURE__ */ jsx("span", { style: { color: C.textMuted, fontSize: "11px" }, children: entry.actorEmail })
19
+ ] }, entry.id)) }))
20
+ ] });
21
+ }
22
+
23
+ export { ActivityLog };
@@ -0,0 +1,42 @@
1
+ "use client";
2
+ import { jsxs, jsx } from 'react/jsx-runtime';
3
+ import { C, s } from '../constants';
4
+
5
+ function ClientBar({ client }) {
6
+ return /* @__PURE__ */ jsxs("div", { style: {
7
+ display: "flex",
8
+ alignItems: "center",
9
+ gap: "12px",
10
+ padding: "10px 16px",
11
+ borderRadius: "8px",
12
+ backgroundColor: "var(--theme-elevation-100)",
13
+ marginBottom: "16px",
14
+ flexWrap: "wrap"
15
+ }, children: [
16
+ /* @__PURE__ */ jsx("span", { style: { fontSize: "16px" }, children: "\u{1F464}" }),
17
+ /* @__PURE__ */ jsx("span", { style: { fontWeight: 700, fontSize: "13px", color: C.textPrimary }, children: client.company }),
18
+ /* @__PURE__ */ jsxs("span", { style: { color: C.textSecondary, fontSize: "13px" }, children: [
19
+ client.firstName,
20
+ " ",
21
+ client.lastName
22
+ ] }),
23
+ /* @__PURE__ */ jsx("span", { style: { color: C.textMuted, fontSize: "12px" }, children: "|" }),
24
+ /* @__PURE__ */ jsx("a", { href: `mailto:${client.email}`, style: { color: "#2563eb", fontSize: "12px", fontWeight: 600, textDecoration: "none" }, children: client.email }),
25
+ client.phone && /* @__PURE__ */ jsx("span", { style: { color: C.textSecondary, fontSize: "12px" }, children: client.phone }),
26
+ /* @__PURE__ */ jsxs("span", { style: { marginLeft: "auto", display: "inline-flex", gap: "8px", alignItems: "center" }, children: [
27
+ /* @__PURE__ */ jsx("a", { href: `/admin/collections/support-clients/${client.id}`, style: { ...s.ghostBtn("#475569"), fontSize: "11px", padding: "4px 10px", textDecoration: "none" }, children: "Fiche client" }),
28
+ /* @__PURE__ */ jsx(
29
+ "button",
30
+ {
31
+ type: "button",
32
+ onClick: () => window.open(`/api/admin/impersonate?clientId=${client.id}`, "_blank"),
33
+ style: { ...s.ghostBtn("#7c3aed"), fontSize: "11px", padding: "4px 10px" },
34
+ title: "Se connecter au portail support en tant que ce client",
35
+ children: "Voir en tant que client"
36
+ }
37
+ )
38
+ ] })
39
+ ] });
40
+ }
41
+
42
+ export { ClientBar };
@@ -0,0 +1,137 @@
1
+ "use client";
2
+ import { jsxs, jsx } from 'react/jsx-runtime';
3
+ import { useState } from 'react';
4
+ import { s, C, statusLabels, projectStatusLabels } from '../constants';
5
+
6
+ function ClientHistory({
7
+ client: _client,
8
+ clientTickets,
9
+ clientProjects,
10
+ clientNotes,
11
+ onNotesChange,
12
+ onNotesSave,
13
+ savingNotes,
14
+ notesSaved
15
+ }) {
16
+ const [showClientHistory, setShowClientHistory] = useState(false);
17
+ return /* @__PURE__ */ jsxs("div", { style: s.section, children: [
18
+ /* @__PURE__ */ jsxs(
19
+ "button",
20
+ {
21
+ type: "button",
22
+ onClick: () => setShowClientHistory(!showClientHistory),
23
+ style: {
24
+ background: "none",
25
+ border: `1px dashed ${C.border}`,
26
+ borderRadius: "6px",
27
+ padding: "8px 14px",
28
+ cursor: "pointer",
29
+ color: C.textSecondary,
30
+ fontSize: "13px",
31
+ fontWeight: 600,
32
+ width: "100%",
33
+ textAlign: "left",
34
+ display: "flex",
35
+ alignItems: "center",
36
+ justifyContent: "space-between"
37
+ },
38
+ children: [
39
+ /* @__PURE__ */ jsxs("span", { children: [
40
+ "Historique client (",
41
+ clientTickets.length,
42
+ " ticket",
43
+ clientTickets.length !== 1 ? "s" : "",
44
+ ", ",
45
+ clientProjects.length,
46
+ " projet",
47
+ clientProjects.length !== 1 ? "s" : "",
48
+ ")"
49
+ ] }),
50
+ /* @__PURE__ */ jsx("span", { style: { fontSize: "12px", transition: "transform 0.2s", display: "inline-block", transform: showClientHistory ? "rotate(90deg)" : "none" }, children: "\u25B6" })
51
+ ]
52
+ }
53
+ ),
54
+ showClientHistory && /* @__PURE__ */ jsxs("div", { style: { marginTop: "10px", padding: "14px 18px", borderRadius: "8px", backgroundColor: C.white, border: `1px solid ${C.border}` }, children: [
55
+ /* @__PURE__ */ jsx("h5", { style: { fontSize: "12px", fontWeight: 600, color: C.textSecondary, marginBottom: "8px" }, children: "Derniers tickets" }),
56
+ clientTickets.length === 0 ? /* @__PURE__ */ jsx("p", { style: { fontSize: "12px", color: C.textMuted, fontStyle: "italic", marginBottom: "14px" }, children: "Aucun autre ticket" }) : /* @__PURE__ */ jsx("div", { style: { display: "flex", flexDirection: "column", gap: "4px", marginBottom: "14px" }, children: clientTickets.map((t) => {
57
+ const st = statusLabels[t.status] || statusLabels.open;
58
+ return /* @__PURE__ */ jsxs(
59
+ "a",
60
+ {
61
+ href: `/admin/support/ticket?id=${t.id}`,
62
+ style: {
63
+ display: "flex",
64
+ alignItems: "center",
65
+ gap: "8px",
66
+ padding: "6px 10px",
67
+ borderRadius: "6px",
68
+ border: `1px solid ${C.border}`,
69
+ textDecoration: "none",
70
+ fontSize: "12px",
71
+ color: "#374151",
72
+ backgroundColor: "#fafafa"
73
+ },
74
+ children: [
75
+ /* @__PURE__ */ jsx("span", { style: { fontFamily: "'SF Mono', 'Fira Code', 'JetBrains Mono', 'Cascadia Code', monospace", fontWeight: 600, color: C.textMuted, fontSize: "11px", whiteSpace: "nowrap" }, children: t.ticketNumber }),
76
+ /* @__PURE__ */ jsx("span", { style: { flex: 1, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", fontWeight: 600 }, children: t.subject }),
77
+ /* @__PURE__ */ jsx("span", { style: s.badge(st.bg, st.color), children: st.label }),
78
+ /* @__PURE__ */ jsx("span", { style: { fontSize: "10px", color: C.textMuted, whiteSpace: "nowrap" }, children: new Date(t.createdAt).toLocaleDateString("fr-FR", { day: "numeric", month: "short" }) })
79
+ ]
80
+ },
81
+ t.id
82
+ );
83
+ }) }),
84
+ /* @__PURE__ */ jsx("h5", { style: { fontSize: "12px", fontWeight: 600, color: C.textSecondary, marginBottom: "8px" }, children: "Projets" }),
85
+ clientProjects.length === 0 ? /* @__PURE__ */ jsx("p", { style: { fontSize: "12px", color: C.textMuted, fontStyle: "italic", marginBottom: "14px" }, children: "Aucun projet" }) : /* @__PURE__ */ jsx("div", { style: { display: "flex", gap: "6px", flexWrap: "wrap", marginBottom: "14px" }, children: clientProjects.map((p) => {
86
+ const ps = projectStatusLabels[p.status] || projectStatusLabels.active;
87
+ return /* @__PURE__ */ jsxs(
88
+ "a",
89
+ {
90
+ href: `/admin/collections/projects/${p.id}`,
91
+ style: {
92
+ display: "inline-flex",
93
+ alignItems: "center",
94
+ gap: "6px",
95
+ padding: "5px 10px",
96
+ borderRadius: "6px",
97
+ border: `1px solid ${C.border}`,
98
+ textDecoration: "none",
99
+ fontSize: "12px",
100
+ fontWeight: 600,
101
+ color: "#374151",
102
+ backgroundColor: "#fafafa"
103
+ },
104
+ children: [
105
+ p.name,
106
+ /* @__PURE__ */ jsx("span", { style: s.badge(ps.bg, ps.color), children: ps.label })
107
+ ]
108
+ },
109
+ p.id
110
+ );
111
+ }) }),
112
+ /* @__PURE__ */ jsx("h5", { style: { fontSize: "12px", fontWeight: 600, color: C.textSecondary, marginBottom: "8px" }, children: "Notes internes" }),
113
+ /* @__PURE__ */ jsx(
114
+ "textarea",
115
+ {
116
+ value: clientNotes,
117
+ onChange: (e) => onNotesChange(e.target.value),
118
+ rows: 3,
119
+ style: { ...s.input, width: "100%", resize: "vertical", fontSize: "12px", marginBottom: "8px" },
120
+ placeholder: "Notes sur ce client..."
121
+ }
122
+ ),
123
+ /* @__PURE__ */ jsx(
124
+ "button",
125
+ {
126
+ type: "button",
127
+ onClick: onNotesSave,
128
+ disabled: savingNotes,
129
+ style: { ...s.btn(notesSaved ? "#16a34a" : C.blue, savingNotes), fontSize: "11px", padding: "5px 12px" },
130
+ children: notesSaved ? "Sauvegarde OK" : savingNotes ? "Sauvegarde..." : "Sauvegarder les notes"
131
+ }
132
+ )
133
+ ] })
134
+ ] });
135
+ }
136
+
137
+ export { ClientHistory };
@@ -0,0 +1,152 @@
1
+ "use client";
2
+ import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
3
+ import { useState } from 'react';
4
+
5
+ const LANG_CONFIG = {
6
+ javascript: { label: "JavaScript", accent: "#f7df1e" },
7
+ js: { label: "JavaScript", accent: "#f7df1e" },
8
+ typescript: { label: "TypeScript", accent: "#3178c6" },
9
+ ts: { label: "TypeScript", accent: "#3178c6" },
10
+ tsx: { label: "TSX", accent: "#3178c6" },
11
+ jsx: { label: "JSX", accent: "#f7df1e" },
12
+ php: { label: "PHP", accent: "#777bb4" },
13
+ python: { label: "Python", accent: "#3776ab" },
14
+ py: { label: "Python", accent: "#3776ab" },
15
+ html: { label: "HTML", accent: "#e34f26" },
16
+ css: { label: "CSS", accent: "#1572b6" },
17
+ scss: { label: "SCSS", accent: "#cc6699" },
18
+ json: { label: "JSON", accent: "#292929" },
19
+ sql: { label: "SQL", accent: "#e48e00" },
20
+ bash: { label: "Bash", accent: "#4eaa25" },
21
+ sh: { label: "Shell", accent: "#4eaa25" },
22
+ yaml: { label: "YAML", accent: "#cb171e" },
23
+ yml: { label: "YAML", accent: "#cb171e" },
24
+ xml: { label: "XML", accent: "#f16529" },
25
+ markdown: { label: "Markdown", accent: "#083fa1" },
26
+ md: { label: "Markdown", accent: "#083fa1" },
27
+ diff: { label: "Diff", accent: "#41b883" },
28
+ go: { label: "Go", accent: "#00add8" },
29
+ rust: { label: "Rust", accent: "#dea584" },
30
+ java: { label: "Java", accent: "#ed8b00" },
31
+ c: { label: "C", accent: "#555555" },
32
+ cpp: { label: "C++", accent: "#00599c" },
33
+ ruby: { label: "Ruby", accent: "#cc342d" },
34
+ swift: { label: "Swift", accent: "#f05138" },
35
+ nginx: { label: "Nginx", accent: "#009639" },
36
+ docker: { label: "Docker", accent: "#2496ed" },
37
+ dockerfile: { label: "Dockerfile", accent: "#2496ed" },
38
+ env: { label: ".env", accent: "#ecd53f" }
39
+ };
40
+ const DEFAULT_CONFIG = { label: "Code", accent: "#6b7280" };
41
+ function SingleCodeBlock({ lang, code }) {
42
+ const [copied, setCopied] = useState(false);
43
+ const config = LANG_CONFIG[lang.toLowerCase()] || (lang ? { label: lang.toUpperCase(), accent: "#6b7280" } : DEFAULT_CONFIG);
44
+ const handleCopy = () => {
45
+ navigator.clipboard.writeText(code);
46
+ setCopied(true);
47
+ setTimeout(() => setCopied(false), 1500);
48
+ };
49
+ const lines = code.split("\n");
50
+ return /* @__PURE__ */ jsxs("div", { style: {
51
+ marginTop: 8,
52
+ marginBottom: 8,
53
+ borderRadius: 8,
54
+ overflow: "hidden",
55
+ border: "1px solid #334155",
56
+ backgroundColor: "#0f172a",
57
+ fontSize: 13
58
+ }, children: [
59
+ /* @__PURE__ */ jsxs("div", { style: {
60
+ display: "flex",
61
+ alignItems: "center",
62
+ justifyContent: "space-between",
63
+ padding: "6px 12px",
64
+ backgroundColor: "#1e293b",
65
+ borderBottom: "1px solid #334155"
66
+ }, children: [
67
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: 8 }, children: [
68
+ /* @__PURE__ */ jsx("span", { style: {
69
+ display: "inline-block",
70
+ width: 8,
71
+ height: 8,
72
+ borderRadius: "50%",
73
+ backgroundColor: config.accent,
74
+ flexShrink: 0
75
+ } }),
76
+ /* @__PURE__ */ jsx("span", { style: {
77
+ fontSize: 11,
78
+ fontWeight: 700,
79
+ color: "#e2e8f0",
80
+ letterSpacing: "0.02em"
81
+ }, children: config.label })
82
+ ] }),
83
+ /* @__PURE__ */ jsx(
84
+ "button",
85
+ {
86
+ onClick: handleCopy,
87
+ style: {
88
+ background: "none",
89
+ border: "1px solid #475569",
90
+ borderRadius: 4,
91
+ padding: "2px 10px",
92
+ fontSize: 11,
93
+ color: copied ? "#4ade80" : "#94a3b8",
94
+ cursor: "pointer",
95
+ fontWeight: 600,
96
+ transition: "color 150ms"
97
+ },
98
+ children: copied ? "Copi\xE9 !" : "Copier"
99
+ }
100
+ )
101
+ ] }),
102
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", overflowX: "auto" }, children: [
103
+ /* @__PURE__ */ jsx("div", { style: {
104
+ padding: "12px 0",
105
+ borderRight: "1px solid #334155",
106
+ userSelect: "none",
107
+ flexShrink: 0
108
+ }, children: lines.map((_, i) => /* @__PURE__ */ jsx("div", { style: {
109
+ padding: "0 12px",
110
+ fontSize: 12,
111
+ lineHeight: "20px",
112
+ color: "#475569",
113
+ textAlign: "right",
114
+ fontFamily: '"SF Mono", "Fira Code", "JetBrains Mono", monospace'
115
+ }, children: i + 1 }, i)) }),
116
+ /* @__PURE__ */ jsx("pre", { style: {
117
+ margin: 0,
118
+ padding: 12,
119
+ overflow: "auto",
120
+ flex: 1
121
+ }, children: /* @__PURE__ */ jsx("code", { style: {
122
+ fontSize: 12,
123
+ lineHeight: "20px",
124
+ fontFamily: '"SF Mono", "Fira Code", "JetBrains Mono", monospace',
125
+ color: "#e2e8f0",
126
+ whiteSpace: "pre"
127
+ }, children: code }) })
128
+ ] })
129
+ ] });
130
+ }
131
+ function CodeBlockRenderer({ text }) {
132
+ const parts = text.split(/(```[\s\S]*?```)/g);
133
+ const hasCodeBlock = parts.some((p) => p.startsWith("```"));
134
+ if (!hasCodeBlock) return null;
135
+ return /* @__PURE__ */ jsx(Fragment, { children: parts.map((part, i) => {
136
+ if (part.startsWith("```")) {
137
+ const match = part.match(/^```(\w*)\n?([\s\S]*?)```$/);
138
+ if (match) {
139
+ const lang = match[1] || "";
140
+ const code = match[2].replace(/\n$/, "");
141
+ return /* @__PURE__ */ jsx(SingleCodeBlock, { lang, code }, i);
142
+ }
143
+ }
144
+ return null;
145
+ }) });
146
+ }
147
+ function CodeBlockRendererHtml({ html }) {
148
+ const stripped = html.replace(/<[^>]+>/g, "");
149
+ return /* @__PURE__ */ jsx(CodeBlockRenderer, { text: stripped });
150
+ }
151
+
152
+ export { CodeBlockRenderer, CodeBlockRendererHtml };