@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.
- package/dist/components/TicketConversation/components/AISummaryPanel.js +76 -0
- package/dist/components/TicketConversation/components/ActionPanels.js +118 -0
- package/dist/components/TicketConversation/components/ActivityLog.js +23 -0
- package/dist/components/TicketConversation/components/ClientBar.js +42 -0
- package/dist/components/TicketConversation/components/ClientHistory.js +137 -0
- package/dist/components/TicketConversation/components/CodeBlock.js +152 -0
- package/dist/components/TicketConversation/components/CodeBlockInserter.js +155 -0
- package/dist/components/TicketConversation/components/QuickActions.js +65 -0
- package/dist/components/TicketConversation/components/TicketHeader.js +92 -0
- package/dist/components/TicketConversation/components/TimeTrackingPanel.js +133 -0
- package/dist/components/TicketConversation/config.js +41 -0
- package/dist/components/TicketConversation/constants.js +96 -0
- package/dist/components/TicketConversation/context.js +11 -0
- package/dist/components/TicketConversation/hooks/useAI.js +176 -0
- package/dist/components/TicketConversation/hooks/useMessageActions.js +135 -0
- package/dist/components/TicketConversation/hooks/useReply.js +187 -0
- package/dist/components/TicketConversation/hooks/useTicketActions.js +230 -0
- package/dist/components/TicketConversation/hooks/useTimeTracking.js +122 -0
- package/dist/components/TicketConversation/hooks/useTranslation.js +70 -0
- package/dist/components/TicketConversation/index.js +1123 -0
- package/dist/components/TicketConversation/locales/en.json +878 -0
- package/dist/components/TicketConversation/locales/fr.json +878 -0
- package/dist/components/TicketConversation/types.js +2 -0
- package/dist/components/TicketConversation/utils.js +25 -0
- package/dist/index.cjs +2 -2
- package/dist/index.js +2 -2
- package/dist/styles/BillingView.module.scss +311 -0
- package/dist/styles/ChatView.module.scss +438 -0
- package/dist/styles/CommandPalette.module.scss +160 -0
- package/dist/styles/CrmView.module.scss +554 -0
- package/dist/styles/EmailTracking.module.scss +238 -0
- package/dist/styles/ImportConversation.module.scss +267 -0
- package/dist/styles/Layout.module.scss +55 -0
- package/dist/styles/Logs.module.scss +164 -0
- package/dist/styles/NewTicket.module.scss +143 -0
- package/dist/styles/PendingEmails.module.scss +629 -0
- package/dist/styles/SupportDashboard.module.scss +649 -0
- package/dist/styles/TicketDetail.module.scss +1050 -0
- package/dist/styles/TicketInbox.module.scss +296 -0
- package/dist/styles/TicketingSettings.module.scss +358 -0
- package/dist/styles/TimeDashboard.module.scss +287 -0
- package/dist/styles/_tokens.scss +78 -0
- package/dist/styles/theme.css +633 -0
- package/dist/views/BillingView/client.js +204 -0
- package/dist/views/BillingView/index.js +29 -0
- package/dist/views/ChatView/client.js +252 -0
- package/dist/views/ChatView/index.js +29 -0
- package/dist/views/CrmView/client.js +232 -0
- package/dist/views/CrmView/index.js +29 -0
- package/dist/views/EmailTrackingView/client.js +154 -0
- package/dist/views/EmailTrackingView/index.js +29 -0
- package/dist/views/ImportConversationView/client.js +204 -0
- package/dist/views/ImportConversationView/index.js +29 -0
- package/dist/views/LogsView/client.js +148 -0
- package/dist/views/LogsView/index.js +27 -0
- package/dist/views/NewTicketView/client.js +224 -0
- package/dist/views/NewTicketView/index.js +27 -0
- package/dist/views/PendingEmailsView/client.js +172 -0
- package/dist/views/PendingEmailsView/index.js +29 -0
- package/dist/views/SupportDashboardView/client.js +296 -0
- package/dist/views/SupportDashboardView/index.js +29 -0
- package/dist/views/TicketDetailView/client.js +844 -0
- package/dist/views/TicketDetailView/index.js +29 -0
- package/dist/views/TicketInboxView/client.js +294 -0
- package/dist/views/TicketInboxView/index.js +27 -0
- package/dist/{views.css → views/TicketingSettingsView/TicketingSettings.module.scss} +138 -66
- package/dist/views/TicketingSettingsView/client.js +728 -0
- package/dist/views/TicketingSettingsView/index.js +29 -0
- package/dist/views/TimeDashboardView/client.js +164 -0
- package/dist/views/TimeDashboardView/index.js +29 -0
- package/dist/views/shared/AdminViewHeader.js +67 -0
- package/dist/views/shared/ErrorBoundary.js +50 -0
- package/dist/views/shared/Skeleton.js +72 -0
- package/dist/views/shared/adminTokens.js +32 -0
- package/dist/views/shared/config.js +41 -0
- package/dist/views/shared/index.js +6 -0
- package/package.json +8 -12
- package/src/collections/Tickets.ts +1 -1
- package/src/components/TicketConversation/index.tsx +21 -2
- package/src/plugin.ts +3 -2
- package/dist/views.cjs +0 -6172
- package/dist/views.d.cts +0 -30
- package/dist/views.d.ts +0 -30
- package/dist/views.js +0 -6153
- 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 };
|