@consilioweb/payload-support 0.6.1 → 0.6.3
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.cjs +77 -0
- package/dist/components/TicketConversation/components/AISummaryPanel.js +76 -0
- package/dist/components/TicketConversation/components/ActionPanels.cjs +121 -0
- package/dist/components/TicketConversation/components/ActionPanels.js +118 -0
- package/dist/components/TicketConversation/components/ActivityLog.cjs +24 -0
- package/dist/components/TicketConversation/components/ActivityLog.js +23 -0
- package/dist/components/TicketConversation/components/ClientBar.cjs +43 -0
- package/dist/components/TicketConversation/components/ClientBar.js +42 -0
- package/dist/components/TicketConversation/components/ClientHistory.cjs +138 -0
- package/dist/components/TicketConversation/components/ClientHistory.js +137 -0
- package/dist/components/TicketConversation/components/CodeBlock.cjs +154 -0
- package/dist/components/TicketConversation/components/CodeBlock.js +152 -0
- package/dist/components/TicketConversation/components/CodeBlockInserter.cjs +156 -0
- package/dist/components/TicketConversation/components/CodeBlockInserter.js +155 -0
- package/dist/components/TicketConversation/components/QuickActions.cjs +66 -0
- package/dist/components/TicketConversation/components/QuickActions.js +65 -0
- package/dist/components/TicketConversation/components/TicketHeader.cjs +93 -0
- package/dist/components/TicketConversation/components/TicketHeader.js +92 -0
- package/dist/components/TicketConversation/components/TimeTrackingPanel.cjs +134 -0
- package/dist/components/TicketConversation/components/TimeTrackingPanel.js +133 -0
- package/dist/components/TicketConversation/config.cjs +44 -0
- package/dist/components/TicketConversation/config.js +41 -0
- package/dist/components/TicketConversation/constants.cjs +100 -0
- package/dist/components/TicketConversation/constants.js +96 -0
- package/dist/components/TicketConversation/context.cjs +13 -0
- package/dist/components/TicketConversation/context.js +11 -0
- package/dist/components/TicketConversation/hooks/useAI.cjs +177 -0
- package/dist/components/TicketConversation/hooks/useAI.js +176 -0
- package/dist/components/TicketConversation/hooks/useMessageActions.cjs +136 -0
- package/dist/components/TicketConversation/hooks/useMessageActions.js +135 -0
- package/dist/components/TicketConversation/hooks/useReply.cjs +188 -0
- package/dist/components/TicketConversation/hooks/useReply.js +187 -0
- package/dist/components/TicketConversation/hooks/useTicketActions.cjs +231 -0
- package/dist/components/TicketConversation/hooks/useTicketActions.js +230 -0
- package/dist/components/TicketConversation/hooks/useTimeTracking.cjs +123 -0
- package/dist/components/TicketConversation/hooks/useTimeTracking.js +122 -0
- package/dist/components/TicketConversation/hooks/useTranslation.cjs +78 -0
- package/dist/components/TicketConversation/hooks/useTranslation.js +70 -0
- package/dist/components/TicketConversation/index.cjs +1128 -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.cjs +2 -0
- package/dist/components/TicketConversation/types.js +2 -0
- package/dist/components/TicketConversation/utils.cjs +27 -0
- package/dist/components/TicketConversation/utils.js +25 -0
- 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/{components/TicketConversation.css → styles/theme.css} +326 -13
- package/dist/views/BillingView/client.cjs +209 -0
- package/dist/views/BillingView/client.js +204 -0
- package/dist/views/BillingView/index.cjs +34 -0
- package/dist/views/BillingView/index.js +29 -0
- package/dist/views/ChatView/client.cjs +253 -0
- package/dist/views/ChatView/client.js +252 -0
- package/dist/views/ChatView/index.cjs +34 -0
- package/dist/views/ChatView/index.js +29 -0
- package/dist/views/CrmView/client.cjs +233 -0
- package/dist/views/CrmView/client.js +232 -0
- package/dist/views/CrmView/index.cjs +34 -0
- package/dist/views/CrmView/index.js +29 -0
- package/dist/views/EmailTrackingView/client.cjs +159 -0
- package/dist/views/EmailTrackingView/client.js +154 -0
- package/dist/views/EmailTrackingView/index.cjs +34 -0
- package/dist/views/EmailTrackingView/index.js +29 -0
- package/dist/views/ImportConversationView/client.cjs +205 -0
- package/dist/views/ImportConversationView/client.js +204 -0
- package/dist/views/ImportConversationView/index.cjs +34 -0
- package/dist/views/ImportConversationView/index.js +29 -0
- package/dist/views/LogsView/client.cjs +149 -0
- package/dist/views/LogsView/client.js +148 -0
- package/dist/views/LogsView/index.cjs +32 -0
- package/dist/views/LogsView/index.js +27 -0
- package/dist/views/NewTicketView/client.cjs +229 -0
- package/dist/views/NewTicketView/client.js +224 -0
- package/dist/views/NewTicketView/index.cjs +32 -0
- package/dist/views/NewTicketView/index.js +27 -0
- package/dist/views/PendingEmailsView/client.cjs +173 -0
- package/dist/views/PendingEmailsView/client.js +172 -0
- package/dist/views/PendingEmailsView/index.cjs +34 -0
- package/dist/views/PendingEmailsView/index.js +29 -0
- package/dist/views/SupportDashboardView/client.cjs +301 -0
- package/dist/views/SupportDashboardView/client.js +296 -0
- package/dist/views/SupportDashboardView/index.cjs +34 -0
- package/dist/views/SupportDashboardView/index.js +29 -0
- package/dist/views/TicketDetailView/client.cjs +850 -0
- package/dist/views/TicketDetailView/client.js +844 -0
- package/dist/views/TicketDetailView/index.cjs +34 -0
- package/dist/views/TicketDetailView/index.js +29 -0
- package/dist/views/TicketInboxView/client.cjs +299 -0
- package/dist/views/TicketInboxView/client.js +294 -0
- package/dist/views/TicketInboxView/index.cjs +32 -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.cjs +733 -0
- package/dist/views/TicketingSettingsView/client.js +728 -0
- package/dist/views/TicketingSettingsView/index.cjs +34 -0
- package/dist/views/TicketingSettingsView/index.js +29 -0
- package/dist/views/TimeDashboardView/client.cjs +169 -0
- package/dist/views/TimeDashboardView/client.js +164 -0
- package/dist/views/TimeDashboardView/index.cjs +34 -0
- package/dist/views/TimeDashboardView/index.js +29 -0
- package/dist/views/shared/AdminViewHeader.cjs +68 -0
- package/dist/views/shared/AdminViewHeader.js +67 -0
- package/dist/views/shared/ErrorBoundary.cjs +55 -0
- package/dist/views/shared/ErrorBoundary.js +50 -0
- package/dist/views/shared/Skeleton.cjs +77 -0
- package/dist/views/shared/Skeleton.js +72 -0
- package/dist/views/shared/adminTokens.cjs +34 -0
- package/dist/views/shared/adminTokens.js +31 -0
- package/dist/views/shared/config.cjs +44 -0
- package/dist/views/shared/config.js +40 -0
- package/dist/views/shared/index.cjs +58 -0
- package/dist/views/shared/index.js +5 -0
- package/dist/views.cjs +77 -6175
- package/dist/views.d.cts +13 -30
- package/dist/views.d.ts +13 -30
- package/dist/views.js +13 -6165
- package/package.json +2 -2
- package/dist/components/TicketConversation.js +0 -3004
|
@@ -0,0 +1,728 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
3
|
+
import { useState, useEffect } from 'react';
|
|
4
|
+
import { Settings, Mail, Bot, Clock, Timer, Globe, FileSignature } from 'lucide-react';
|
|
5
|
+
import { V, btnStyle } from '../shared/adminTokens';
|
|
6
|
+
import { AdminViewHeader } from '../shared/AdminViewHeader';
|
|
7
|
+
import { getFeatures, saveFeatures, DEFAULT_FEATURES } from '../../components/TicketConversation/config';
|
|
8
|
+
import ts from './TicketingSettings.module.scss';
|
|
9
|
+
|
|
10
|
+
const DEFAULT_SETTINGS = {
|
|
11
|
+
email: {
|
|
12
|
+
fromAddress: "",
|
|
13
|
+
fromName: "Support ConsilioWEB",
|
|
14
|
+
replyToAddress: ""
|
|
15
|
+
},
|
|
16
|
+
ai: {
|
|
17
|
+
provider: "ollama",
|
|
18
|
+
apiKey: "",
|
|
19
|
+
model: "qwen2.5:32b",
|
|
20
|
+
enableSentiment: true,
|
|
21
|
+
enableSynthesis: true,
|
|
22
|
+
enableSuggestion: true,
|
|
23
|
+
enableRewrite: true
|
|
24
|
+
},
|
|
25
|
+
sla: {
|
|
26
|
+
firstResponseMinutes: 120,
|
|
27
|
+
resolutionMinutes: 1440,
|
|
28
|
+
businessHoursOnly: true,
|
|
29
|
+
escalationEmail: ""
|
|
30
|
+
},
|
|
31
|
+
autoClose: {
|
|
32
|
+
enabled: true,
|
|
33
|
+
daysBeforeClose: 7,
|
|
34
|
+
reminderDaysBefore: 2
|
|
35
|
+
},
|
|
36
|
+
locale: {
|
|
37
|
+
language: "fr"
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
async function fetchSettingsFromAPI() {
|
|
41
|
+
try {
|
|
42
|
+
const res = await fetch("/api/support/settings", { credentials: "include" });
|
|
43
|
+
if (res.ok) {
|
|
44
|
+
const data = await res.json();
|
|
45
|
+
return {
|
|
46
|
+
email: { ...DEFAULT_SETTINGS.email, ...data.email },
|
|
47
|
+
ai: { ...DEFAULT_SETTINGS.ai, apiKey: "", ...data.ai },
|
|
48
|
+
sla: { ...DEFAULT_SETTINGS.sla, ...data.sla },
|
|
49
|
+
autoClose: { ...DEFAULT_SETTINGS.autoClose, ...data.autoClose },
|
|
50
|
+
locale: DEFAULT_SETTINGS.locale
|
|
51
|
+
// locale is now per-user
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
} catch {
|
|
55
|
+
}
|
|
56
|
+
return DEFAULT_SETTINGS;
|
|
57
|
+
}
|
|
58
|
+
async function saveSettingsToAPI(settings) {
|
|
59
|
+
try {
|
|
60
|
+
const toSave = {
|
|
61
|
+
email: settings.email,
|
|
62
|
+
ai: { ...settings.ai, apiKey: void 0 },
|
|
63
|
+
sla: settings.sla,
|
|
64
|
+
autoClose: settings.autoClose
|
|
65
|
+
// locale excluded — saved per-user via user-prefs
|
|
66
|
+
};
|
|
67
|
+
const res = await fetch("/api/support/settings", {
|
|
68
|
+
method: "POST",
|
|
69
|
+
headers: { "Content-Type": "application/json" },
|
|
70
|
+
credentials: "include",
|
|
71
|
+
body: JSON.stringify(toSave)
|
|
72
|
+
});
|
|
73
|
+
return res.ok;
|
|
74
|
+
} catch {
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
async function fetchUserPrefs() {
|
|
79
|
+
try {
|
|
80
|
+
const res = await fetch("/api/support/user-prefs", { credentials: "include" });
|
|
81
|
+
if (res.ok) return await res.json();
|
|
82
|
+
} catch {
|
|
83
|
+
}
|
|
84
|
+
return { locale: "fr", signature: "" };
|
|
85
|
+
}
|
|
86
|
+
async function saveUserPrefs(prefs) {
|
|
87
|
+
try {
|
|
88
|
+
const res = await fetch("/api/support/user-prefs", {
|
|
89
|
+
method: "POST",
|
|
90
|
+
headers: { "Content-Type": "application/json" },
|
|
91
|
+
credentials: "include",
|
|
92
|
+
body: JSON.stringify(prefs)
|
|
93
|
+
});
|
|
94
|
+
return res.ok;
|
|
95
|
+
} catch {
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
const FEATURE_LIST = [
|
|
100
|
+
// Core
|
|
101
|
+
{ key: "canned", label: "R\xE9ponses rapides", description: "Templates de r\xE9ponses pr\xE9-enregistr\xE9es avec variables dynamiques", category: "core" },
|
|
102
|
+
{ key: "scheduledReplies", label: "R\xE9ponses programm\xE9es", description: "Envoyer une r\xE9ponse \xE0 une date/heure future", category: "core" },
|
|
103
|
+
{ key: "activityLog", label: "Journal d'activit\xE9", description: "Timeline des actions sur chaque ticket (changements de statut, assignation...)", category: "core" },
|
|
104
|
+
// Communication
|
|
105
|
+
{ key: "emailTracking", label: "Suivi des emails", description: "Tracking d'envoi et d'ouverture des notifications email", category: "communication" },
|
|
106
|
+
{ key: "chat", label: "Live Chat", description: "Chat en temps r\xE9el avec conversion en ticket", category: "communication" },
|
|
107
|
+
{ key: "externalMessages", label: "Messages externes", description: "Ajouter manuellement des messages re\xE7us par email, SMS, WhatsApp...", category: "communication" },
|
|
108
|
+
// Productivity
|
|
109
|
+
{ key: "ai", label: "Intelligence Artificielle", description: "Analyse de sentiment, synth\xE8se, suggestion de r\xE9ponse, reformulation", category: "productivity" },
|
|
110
|
+
{ key: "timeTracking", label: "Suivi du temps", description: "Timer, entr\xE9es manuelles, facturation", category: "productivity" },
|
|
111
|
+
{ key: "satisfaction", label: "Enqu\xEAtes satisfaction", description: "Score CSAT apr\xE8s r\xE9solution du ticket", category: "productivity" },
|
|
112
|
+
// Advanced
|
|
113
|
+
{ key: "merge", label: "Fusion de tickets", description: "Combiner deux tickets en un seul", category: "advanced" },
|
|
114
|
+
{ key: "splitTicket", label: "Extraction de message", description: "Extraire un message en nouveau ticket li\xE9", category: "advanced" },
|
|
115
|
+
{ key: "snooze", label: "Snooze", description: "Masquer temporairement un ticket et rappel automatique", category: "advanced" },
|
|
116
|
+
{ key: "clientHistory", label: "Historique client", description: "Tickets pass\xE9s, projets et notes internes du client", category: "advanced" }
|
|
117
|
+
];
|
|
118
|
+
const CATEGORIES = [
|
|
119
|
+
{ key: "core", label: "Fonctionnalit\xE9s de base", color: V.blue },
|
|
120
|
+
{ key: "communication", label: "Communication", color: V.green },
|
|
121
|
+
{ key: "productivity", label: "Productivit\xE9", color: V.amber },
|
|
122
|
+
{ key: "advanced", label: "Avanc\xE9", color: "#7c3aed" }
|
|
123
|
+
];
|
|
124
|
+
const Toggle = ({ checked, onChange, color = V.blue, size = "md" }) => {
|
|
125
|
+
const w = size === "sm" ? 36 : 40;
|
|
126
|
+
const h = size === "sm" ? 20 : 22;
|
|
127
|
+
const knob = size === "sm" ? 16 : 18;
|
|
128
|
+
return /* @__PURE__ */ jsx(
|
|
129
|
+
"div",
|
|
130
|
+
{
|
|
131
|
+
role: "switch",
|
|
132
|
+
"aria-checked": checked,
|
|
133
|
+
tabIndex: 0,
|
|
134
|
+
onClick: onChange,
|
|
135
|
+
onKeyDown: (e) => {
|
|
136
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
137
|
+
e.preventDefault();
|
|
138
|
+
onChange();
|
|
139
|
+
}
|
|
140
|
+
},
|
|
141
|
+
style: {
|
|
142
|
+
width: w,
|
|
143
|
+
height: h,
|
|
144
|
+
borderRadius: h / 2,
|
|
145
|
+
flexShrink: 0,
|
|
146
|
+
backgroundColor: checked ? color : "var(--theme-elevation-300)",
|
|
147
|
+
position: "relative",
|
|
148
|
+
transition: "background 150ms",
|
|
149
|
+
cursor: "pointer"
|
|
150
|
+
},
|
|
151
|
+
children: /* @__PURE__ */ jsx("div", { style: {
|
|
152
|
+
width: knob,
|
|
153
|
+
height: knob,
|
|
154
|
+
borderRadius: "50%",
|
|
155
|
+
backgroundColor: "#fff",
|
|
156
|
+
position: "absolute",
|
|
157
|
+
top: (h - knob) / 2,
|
|
158
|
+
left: checked ? w - knob - (h - knob) / 2 : (h - knob) / 2,
|
|
159
|
+
transition: "left 150ms",
|
|
160
|
+
boxShadow: "0 1px 3px rgba(0,0,0,0.15)"
|
|
161
|
+
} })
|
|
162
|
+
}
|
|
163
|
+
);
|
|
164
|
+
};
|
|
165
|
+
const CollapsibleSection = ({ title, icon, color, defaultOpen = true, children, badge }) => {
|
|
166
|
+
const [open, setOpen] = useState(defaultOpen);
|
|
167
|
+
return /* @__PURE__ */ jsxs("div", { className: ts.sectionWrapper, children: [
|
|
168
|
+
/* @__PURE__ */ jsxs(
|
|
169
|
+
"div",
|
|
170
|
+
{
|
|
171
|
+
className: ts.sectionHeader,
|
|
172
|
+
onClick: () => setOpen(!open),
|
|
173
|
+
role: "button",
|
|
174
|
+
tabIndex: 0,
|
|
175
|
+
onKeyDown: (e) => {
|
|
176
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
177
|
+
e.preventDefault();
|
|
178
|
+
setOpen(!open);
|
|
179
|
+
}
|
|
180
|
+
},
|
|
181
|
+
"aria-expanded": open,
|
|
182
|
+
children: [
|
|
183
|
+
/* @__PURE__ */ jsx("div", { className: ts.sectionIcon, style: { backgroundColor: color }, children: icon }),
|
|
184
|
+
/* @__PURE__ */ jsx("span", { className: ts.sectionTitle, children: title }),
|
|
185
|
+
badge,
|
|
186
|
+
/* @__PURE__ */ jsx("span", { className: `${ts.sectionChevron} ${open ? ts.open : ""}`, children: "\u25BC" })
|
|
187
|
+
]
|
|
188
|
+
}
|
|
189
|
+
),
|
|
190
|
+
open && /* @__PURE__ */ jsx("div", { className: ts.sectionBody, children })
|
|
191
|
+
] });
|
|
192
|
+
};
|
|
193
|
+
const FieldRow = ({ label, description, children }) => /* @__PURE__ */ jsxs("div", { className: ts.fieldRow, children: [
|
|
194
|
+
/* @__PURE__ */ jsxs("div", { className: ts.fieldLabel, children: [
|
|
195
|
+
label,
|
|
196
|
+
description && /* @__PURE__ */ jsx("div", { className: ts.fieldDescription, children: description })
|
|
197
|
+
] }),
|
|
198
|
+
/* @__PURE__ */ jsx("div", { className: ts.fieldContent, children })
|
|
199
|
+
] });
|
|
200
|
+
const TicketingSettingsClient = () => {
|
|
201
|
+
const [features, setFeatures] = useState(() => getFeatures());
|
|
202
|
+
const [settings, setSettings] = useState(DEFAULT_SETTINGS);
|
|
203
|
+
const [signature, setSignature] = useState("");
|
|
204
|
+
const [saved, setSaved] = useState(false);
|
|
205
|
+
const [saving, setSaving] = useState(false);
|
|
206
|
+
const [showApiKey, setShowApiKey] = useState(false);
|
|
207
|
+
const [loadingSettings, setLoadingSettings] = useState(true);
|
|
208
|
+
useEffect(() => {
|
|
209
|
+
let cancelled = false;
|
|
210
|
+
Promise.all([fetchSettingsFromAPI(), fetchUserPrefs()]).then(([s, prefs]) => {
|
|
211
|
+
if (!cancelled) {
|
|
212
|
+
setSettings({ ...s, locale: { language: prefs.locale || "fr" } });
|
|
213
|
+
setSignature(prefs.signature || "");
|
|
214
|
+
setLoadingSettings(false);
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
return () => {
|
|
218
|
+
cancelled = true;
|
|
219
|
+
};
|
|
220
|
+
}, []);
|
|
221
|
+
const handleToggle = (key) => {
|
|
222
|
+
const updated = { ...features, [key]: !features[key] };
|
|
223
|
+
setFeatures(updated);
|
|
224
|
+
setSaved(false);
|
|
225
|
+
};
|
|
226
|
+
const updateEmail = (field, value) => {
|
|
227
|
+
setSettings((prev) => ({ ...prev, email: { ...prev.email, [field]: value } }));
|
|
228
|
+
setSaved(false);
|
|
229
|
+
};
|
|
230
|
+
const updateAI = (field, value) => {
|
|
231
|
+
setSettings((prev) => ({ ...prev, ai: { ...prev.ai, [field]: value } }));
|
|
232
|
+
setSaved(false);
|
|
233
|
+
};
|
|
234
|
+
const updateSLA = (field, value) => {
|
|
235
|
+
setSettings((prev) => ({ ...prev, sla: { ...prev.sla, [field]: value } }));
|
|
236
|
+
setSaved(false);
|
|
237
|
+
};
|
|
238
|
+
const updateAutoClose = (field, value) => {
|
|
239
|
+
setSettings((prev) => ({ ...prev, autoClose: { ...prev.autoClose, [field]: value } }));
|
|
240
|
+
setSaved(false);
|
|
241
|
+
};
|
|
242
|
+
const updateLocale = (field, value) => {
|
|
243
|
+
setSettings((prev) => ({ ...prev, locale: { ...prev.locale, [field]: value } }));
|
|
244
|
+
setSaved(false);
|
|
245
|
+
};
|
|
246
|
+
const handleSave = async () => {
|
|
247
|
+
setSaving(true);
|
|
248
|
+
saveFeatures(features);
|
|
249
|
+
const [settingsOk, prefsOk] = await Promise.all([
|
|
250
|
+
saveSettingsToAPI(settings),
|
|
251
|
+
saveUserPrefs({ locale: settings.locale.language, signature })
|
|
252
|
+
]);
|
|
253
|
+
setSaving(false);
|
|
254
|
+
if (settingsOk && prefsOk) {
|
|
255
|
+
setSaved(true);
|
|
256
|
+
setTimeout(() => setSaved(false), 3e3);
|
|
257
|
+
}
|
|
258
|
+
};
|
|
259
|
+
const handleReset = () => {
|
|
260
|
+
setFeatures({ ...DEFAULT_FEATURES });
|
|
261
|
+
setSettings({ ...DEFAULT_SETTINGS });
|
|
262
|
+
setSignature("");
|
|
263
|
+
setSaved(false);
|
|
264
|
+
};
|
|
265
|
+
const enabledCount = Object.entries(features).filter(([k, v]) => typeof v === "boolean" && v).length;
|
|
266
|
+
const totalCount = Object.entries(features).filter(([k, v]) => typeof v === "boolean").length;
|
|
267
|
+
const smtpHost = process.env.NEXT_PUBLIC_SMTP_HOST || "(non configure)";
|
|
268
|
+
const smtpPort = process.env.NEXT_PUBLIC_SMTP_PORT || "\u2014";
|
|
269
|
+
return /* @__PURE__ */ jsxs("div", { className: ts.page, children: [
|
|
270
|
+
/* @__PURE__ */ jsx(
|
|
271
|
+
AdminViewHeader,
|
|
272
|
+
{
|
|
273
|
+
icon: /* @__PURE__ */ jsx(Settings, { size: 24 }),
|
|
274
|
+
title: "Configuration du module Support",
|
|
275
|
+
subtitle: `${enabledCount}/${totalCount} fonctionnalites activees`,
|
|
276
|
+
actions: /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: 8 }, children: [
|
|
277
|
+
/* @__PURE__ */ jsx("button", { onClick: handleReset, style: btnStyle("var(--theme-elevation-400)", { small: true }), children: "Reinitialiser" }),
|
|
278
|
+
/* @__PURE__ */ jsx(
|
|
279
|
+
"button",
|
|
280
|
+
{
|
|
281
|
+
onClick: handleSave,
|
|
282
|
+
disabled: saving,
|
|
283
|
+
style: btnStyle(saved ? V.green : V.blue, { small: true }),
|
|
284
|
+
children: saving ? "..." : saved ? "\u2713 Sauvegarde" : "Sauvegarder"
|
|
285
|
+
}
|
|
286
|
+
)
|
|
287
|
+
] })
|
|
288
|
+
}
|
|
289
|
+
),
|
|
290
|
+
/* @__PURE__ */ jsx("p", { className: ts.intro, children: "Configurez le module de support : fonctionnalit\xE9s, email, IA, SLA et fermeture automatique. Les changements prennent effet imm\xE9diatement apr\xE8s sauvegarde (rechargez la page du ticket)." }),
|
|
291
|
+
/* @__PURE__ */ jsxs(
|
|
292
|
+
CollapsibleSection,
|
|
293
|
+
{
|
|
294
|
+
title: "Fonctionnalit\xE9s",
|
|
295
|
+
icon: /* @__PURE__ */ jsx(Settings, { size: 16 }),
|
|
296
|
+
color: V.blue,
|
|
297
|
+
badge: /* @__PURE__ */ jsxs("span", { className: ts.badge, style: { backgroundColor: "#dbeafe", color: "#1e40af" }, children: [
|
|
298
|
+
enabledCount,
|
|
299
|
+
"/",
|
|
300
|
+
totalCount
|
|
301
|
+
] }),
|
|
302
|
+
children: [
|
|
303
|
+
/* @__PURE__ */ jsx("p", { className: ts.sectionDescription, children: "Activez ou desactivez les fonctionnalites du module. Les fonctionnalites desactivees sont completement masquees de l'interface." }),
|
|
304
|
+
CATEGORIES.map((cat) => {
|
|
305
|
+
const categoryFeatures = FEATURE_LIST.filter((f) => f.category === cat.key);
|
|
306
|
+
return /* @__PURE__ */ jsxs("div", { className: ts.categoryGroup, children: [
|
|
307
|
+
/* @__PURE__ */ jsxs("h3", { className: ts.categoryHeading, style: { color: cat.color }, children: [
|
|
308
|
+
/* @__PURE__ */ jsx("span", { className: ts.categoryDot, style: { backgroundColor: cat.color } }),
|
|
309
|
+
cat.label
|
|
310
|
+
] }),
|
|
311
|
+
/* @__PURE__ */ jsx("div", { className: ts.featureList, children: categoryFeatures.map((feat) => {
|
|
312
|
+
const enabled = features[feat.key];
|
|
313
|
+
return /* @__PURE__ */ jsxs(
|
|
314
|
+
"div",
|
|
315
|
+
{
|
|
316
|
+
onClick: () => handleToggle(feat.key),
|
|
317
|
+
className: `${ts.featureCard} ${enabled ? ts.enabled : ""}`,
|
|
318
|
+
role: "switch",
|
|
319
|
+
"aria-checked": !!enabled,
|
|
320
|
+
tabIndex: 0,
|
|
321
|
+
onKeyDown: (e) => {
|
|
322
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
323
|
+
e.preventDefault();
|
|
324
|
+
handleToggle(feat.key);
|
|
325
|
+
}
|
|
326
|
+
},
|
|
327
|
+
children: [
|
|
328
|
+
/* @__PURE__ */ jsx(Toggle, { checked: !!enabled, onChange: () => handleToggle(feat.key), color: cat.color }),
|
|
329
|
+
/* @__PURE__ */ jsxs("div", { style: { flex: 1 }, children: [
|
|
330
|
+
/* @__PURE__ */ jsx("div", { className: ts.featureLabel, children: feat.label }),
|
|
331
|
+
/* @__PURE__ */ jsx("div", { className: ts.featureDesc, children: feat.description })
|
|
332
|
+
] })
|
|
333
|
+
]
|
|
334
|
+
},
|
|
335
|
+
feat.key
|
|
336
|
+
);
|
|
337
|
+
}) })
|
|
338
|
+
] }, cat.key);
|
|
339
|
+
})
|
|
340
|
+
]
|
|
341
|
+
}
|
|
342
|
+
),
|
|
343
|
+
/* @__PURE__ */ jsxs(
|
|
344
|
+
CollapsibleSection,
|
|
345
|
+
{
|
|
346
|
+
title: "Configuration Email",
|
|
347
|
+
icon: /* @__PURE__ */ jsx(Mail, { size: 16 }),
|
|
348
|
+
color: "#ea580c",
|
|
349
|
+
defaultOpen: false,
|
|
350
|
+
children: [
|
|
351
|
+
/* @__PURE__ */ jsx("p", { className: ts.sectionDescription, children: "Parametres d'envoi des notifications email. L'adresse SMTP est configuree via les variables d'environnement du serveur." }),
|
|
352
|
+
/* @__PURE__ */ jsx(FieldRow, { label: "Adresse expediteur", description: "Adresse email affichee dans le champ From", children: /* @__PURE__ */ jsx(
|
|
353
|
+
"input",
|
|
354
|
+
{
|
|
355
|
+
type: "email",
|
|
356
|
+
value: settings.email.fromAddress,
|
|
357
|
+
onChange: (e) => updateEmail("fromAddress", e.target.value),
|
|
358
|
+
placeholder: "support@example.com",
|
|
359
|
+
className: ts.input
|
|
360
|
+
}
|
|
361
|
+
) }),
|
|
362
|
+
/* @__PURE__ */ jsx(FieldRow, { label: "Nom expediteur", description: "Nom affiche a cote de l'adresse email", children: /* @__PURE__ */ jsx(
|
|
363
|
+
"input",
|
|
364
|
+
{
|
|
365
|
+
type: "text",
|
|
366
|
+
value: settings.email.fromName,
|
|
367
|
+
onChange: (e) => updateEmail("fromName", e.target.value),
|
|
368
|
+
placeholder: "Support ConsilioWEB",
|
|
369
|
+
className: ts.input
|
|
370
|
+
}
|
|
371
|
+
) }),
|
|
372
|
+
/* @__PURE__ */ jsx(FieldRow, { label: "Adresse Reply-To", description: "Si differente de l'adresse expediteur", children: /* @__PURE__ */ jsx(
|
|
373
|
+
"input",
|
|
374
|
+
{
|
|
375
|
+
type: "email",
|
|
376
|
+
value: settings.email.replyToAddress,
|
|
377
|
+
onChange: (e) => updateEmail("replyToAddress", e.target.value),
|
|
378
|
+
placeholder: "(identique a l'expediteur)",
|
|
379
|
+
className: ts.input
|
|
380
|
+
}
|
|
381
|
+
) }),
|
|
382
|
+
/* @__PURE__ */ jsx("div", { className: ts.separator }),
|
|
383
|
+
/* @__PURE__ */ jsx(FieldRow, { label: "Serveur SMTP", description: "Configure via variables d'environnement", children: /* @__PURE__ */ jsx(
|
|
384
|
+
"input",
|
|
385
|
+
{
|
|
386
|
+
type: "text",
|
|
387
|
+
value: smtpHost,
|
|
388
|
+
readOnly: true,
|
|
389
|
+
className: ts.inputReadonly
|
|
390
|
+
}
|
|
391
|
+
) }),
|
|
392
|
+
/* @__PURE__ */ jsx(FieldRow, { label: "Port SMTP", children: /* @__PURE__ */ jsx(
|
|
393
|
+
"input",
|
|
394
|
+
{
|
|
395
|
+
type: "text",
|
|
396
|
+
value: smtpPort,
|
|
397
|
+
readOnly: true,
|
|
398
|
+
className: ts.inputReadonly,
|
|
399
|
+
style: { maxWidth: 100 }
|
|
400
|
+
}
|
|
401
|
+
) })
|
|
402
|
+
]
|
|
403
|
+
}
|
|
404
|
+
),
|
|
405
|
+
/* @__PURE__ */ jsxs(
|
|
406
|
+
CollapsibleSection,
|
|
407
|
+
{
|
|
408
|
+
title: "Intelligence Artificielle",
|
|
409
|
+
icon: /* @__PURE__ */ jsx(Bot, { size: 16 }),
|
|
410
|
+
color: "#7c3aed",
|
|
411
|
+
defaultOpen: false,
|
|
412
|
+
badge: features.ai ? /* @__PURE__ */ jsx("span", { className: ts.badge, style: { backgroundColor: "#dcfce7", color: "#166534" }, children: "Active" }) : /* @__PURE__ */ jsx("span", { className: ts.badge, style: { backgroundColor: "#fee2e2", color: "#991b1b" }, children: "Inactive" }),
|
|
413
|
+
children: [
|
|
414
|
+
/* @__PURE__ */ jsx("p", { className: ts.sectionDescription, children: `Configurez le fournisseur d'IA et activez/d\xE9sactivez chaque fonctionnalit\xE9 ind\xE9pendamment. Les fonctionnalit\xE9s IA n\xE9cessitent que le flag "Intelligence Artificielle" soit actif dans la section pr\xE9c\xE9dente.` }),
|
|
415
|
+
/* @__PURE__ */ jsx(FieldRow, { label: "Fournisseur", description: "Service d'IA utilise pour l'analyse", children: /* @__PURE__ */ jsxs(
|
|
416
|
+
"select",
|
|
417
|
+
{
|
|
418
|
+
value: settings.ai.provider,
|
|
419
|
+
onChange: (e) => updateAI("provider", e.target.value),
|
|
420
|
+
className: ts.select,
|
|
421
|
+
children: [
|
|
422
|
+
/* @__PURE__ */ jsx("option", { value: "ollama", children: "Ollama (local / tunnel)" }),
|
|
423
|
+
/* @__PURE__ */ jsx("option", { value: "anthropic", children: "Anthropic (Claude)" }),
|
|
424
|
+
/* @__PURE__ */ jsx("option", { value: "openai", children: "OpenAI (GPT)" }),
|
|
425
|
+
/* @__PURE__ */ jsx("option", { value: "gemini", children: "Google (Gemini)" })
|
|
426
|
+
]
|
|
427
|
+
}
|
|
428
|
+
) }),
|
|
429
|
+
settings.ai.provider !== "ollama" && /* @__PURE__ */ jsx(FieldRow, { label: "Cle API", description: "Cle secrete du fournisseur (non stockee en clair)", children: /* @__PURE__ */ jsxs("div", { className: ts.apiKeyRow, children: [
|
|
430
|
+
/* @__PURE__ */ jsx(
|
|
431
|
+
"input",
|
|
432
|
+
{
|
|
433
|
+
type: showApiKey ? "text" : "password",
|
|
434
|
+
value: settings.ai.apiKey,
|
|
435
|
+
onChange: (e) => updateAI("apiKey", e.target.value),
|
|
436
|
+
placeholder: "sk-...",
|
|
437
|
+
className: ts.input,
|
|
438
|
+
style: { flex: 1 }
|
|
439
|
+
}
|
|
440
|
+
),
|
|
441
|
+
/* @__PURE__ */ jsx(
|
|
442
|
+
"button",
|
|
443
|
+
{
|
|
444
|
+
onClick: () => setShowApiKey(!showApiKey),
|
|
445
|
+
className: ts.apiKeyToggle,
|
|
446
|
+
children: showApiKey ? "Masquer" : "Afficher"
|
|
447
|
+
}
|
|
448
|
+
)
|
|
449
|
+
] }) }),
|
|
450
|
+
/* @__PURE__ */ jsx(FieldRow, { label: "Modele", description: "Nom du modele a utiliser", children: /* @__PURE__ */ jsx(
|
|
451
|
+
"input",
|
|
452
|
+
{
|
|
453
|
+
type: "text",
|
|
454
|
+
value: settings.ai.model,
|
|
455
|
+
onChange: (e) => updateAI("model", e.target.value),
|
|
456
|
+
placeholder: "qwen2.5:32b",
|
|
457
|
+
className: ts.input
|
|
458
|
+
}
|
|
459
|
+
) }),
|
|
460
|
+
/* @__PURE__ */ jsx("div", { className: ts.separator }),
|
|
461
|
+
/* @__PURE__ */ jsx("p", { className: ts.aiSubFeaturesLabel, children: "Fonctionnalit\xE9s IA individuelles" }),
|
|
462
|
+
[
|
|
463
|
+
{ key: "enableSentiment", label: "Analyse de sentiment", desc: "Detecte le niveau de frustration ou satisfaction du client" },
|
|
464
|
+
{ key: "enableSynthesis", label: "Synthese automatique", desc: "Resume les conversations longues en quelques phrases" },
|
|
465
|
+
{ key: "enableSuggestion", label: "Suggestion de reponse", desc: "Propose un brouillon de reponse base sur le contexte" },
|
|
466
|
+
{ key: "enableRewrite", label: "Reformulation", desc: "Reformule un message pour le rendre plus professionnel" }
|
|
467
|
+
].map((item) => /* @__PURE__ */ jsxs("div", { className: ts.aiToggleRow, children: [
|
|
468
|
+
/* @__PURE__ */ jsx(
|
|
469
|
+
Toggle,
|
|
470
|
+
{
|
|
471
|
+
checked: settings.ai[item.key],
|
|
472
|
+
onChange: () => updateAI(item.key, !settings.ai[item.key]),
|
|
473
|
+
color: "#7c3aed",
|
|
474
|
+
size: "sm"
|
|
475
|
+
}
|
|
476
|
+
),
|
|
477
|
+
/* @__PURE__ */ jsxs("div", { style: { flex: 1 }, children: [
|
|
478
|
+
/* @__PURE__ */ jsx("span", { className: ts.aiToggleLabel, children: item.label }),
|
|
479
|
+
/* @__PURE__ */ jsx("span", { className: ts.aiToggleDesc, children: item.desc })
|
|
480
|
+
] })
|
|
481
|
+
] }, item.key))
|
|
482
|
+
]
|
|
483
|
+
}
|
|
484
|
+
),
|
|
485
|
+
/* @__PURE__ */ jsxs(
|
|
486
|
+
CollapsibleSection,
|
|
487
|
+
{
|
|
488
|
+
title: "SLA (Accords de niveau de service)",
|
|
489
|
+
icon: /* @__PURE__ */ jsx(Clock, { size: 16 }),
|
|
490
|
+
color: "#0891b2",
|
|
491
|
+
defaultOpen: false,
|
|
492
|
+
children: [
|
|
493
|
+
/* @__PURE__ */ jsx("p", { className: ts.sectionDescription, children: "Definissez les delais de reponse et de resolution attendus. Ces seuils sont utilises pour le suivi de performance et les alertes d'escalade." }),
|
|
494
|
+
/* @__PURE__ */ jsx(FieldRow, { label: "Premiere reponse", description: "D\xE9lai maximum en minutes (d\xE9faut : 120 = 2h)", children: /* @__PURE__ */ jsxs("div", { className: ts.slaInline, children: [
|
|
495
|
+
/* @__PURE__ */ jsx(
|
|
496
|
+
"input",
|
|
497
|
+
{
|
|
498
|
+
type: "number",
|
|
499
|
+
min: 1,
|
|
500
|
+
value: settings.sla.firstResponseMinutes,
|
|
501
|
+
onChange: (e) => updateSLA("firstResponseMinutes", parseInt(e.target.value) || 0),
|
|
502
|
+
className: ts.numberInput
|
|
503
|
+
}
|
|
504
|
+
),
|
|
505
|
+
/* @__PURE__ */ jsxs("span", { className: ts.slaHint, children: [
|
|
506
|
+
"minutes (",
|
|
507
|
+
Math.floor(settings.sla.firstResponseMinutes / 60),
|
|
508
|
+
"h",
|
|
509
|
+
String(settings.sla.firstResponseMinutes % 60).padStart(2, "0"),
|
|
510
|
+
")"
|
|
511
|
+
] })
|
|
512
|
+
] }) }),
|
|
513
|
+
/* @__PURE__ */ jsx(FieldRow, { label: "R\xE9solution", description: "D\xE9lai maximum en minutes (d\xE9faut : 1440 = 24h)", children: /* @__PURE__ */ jsxs("div", { className: ts.slaInline, children: [
|
|
514
|
+
/* @__PURE__ */ jsx(
|
|
515
|
+
"input",
|
|
516
|
+
{
|
|
517
|
+
type: "number",
|
|
518
|
+
min: 1,
|
|
519
|
+
value: settings.sla.resolutionMinutes,
|
|
520
|
+
onChange: (e) => updateSLA("resolutionMinutes", parseInt(e.target.value) || 0),
|
|
521
|
+
className: ts.numberInput
|
|
522
|
+
}
|
|
523
|
+
),
|
|
524
|
+
/* @__PURE__ */ jsxs("span", { className: ts.slaHint, children: [
|
|
525
|
+
"minutes (",
|
|
526
|
+
Math.floor(settings.sla.resolutionMinutes / 60),
|
|
527
|
+
"h",
|
|
528
|
+
String(settings.sla.resolutionMinutes % 60).padStart(2, "0"),
|
|
529
|
+
")"
|
|
530
|
+
] })
|
|
531
|
+
] }) }),
|
|
532
|
+
/* @__PURE__ */ jsxs("div", { className: ts.toggleRow, children: [
|
|
533
|
+
/* @__PURE__ */ jsx(
|
|
534
|
+
Toggle,
|
|
535
|
+
{
|
|
536
|
+
checked: settings.sla.businessHoursOnly,
|
|
537
|
+
onChange: () => updateSLA("businessHoursOnly", !settings.sla.businessHoursOnly),
|
|
538
|
+
color: "#0891b2",
|
|
539
|
+
size: "sm"
|
|
540
|
+
}
|
|
541
|
+
),
|
|
542
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
543
|
+
/* @__PURE__ */ jsx("span", { className: ts.inlineLabel, children: "Heures ouvrables uniquement" }),
|
|
544
|
+
/* @__PURE__ */ jsx("div", { className: ts.inlineDesc, children: "Le decompte SLA est suspendu en dehors des heures de bureau (Lun-Ven, 9h-18h)" })
|
|
545
|
+
] })
|
|
546
|
+
] }),
|
|
547
|
+
/* @__PURE__ */ jsx("div", { className: ts.separator }),
|
|
548
|
+
/* @__PURE__ */ jsx(FieldRow, { label: "Email d'escalade", description: "Adresse notifiee en cas de depassement SLA", children: /* @__PURE__ */ jsx(
|
|
549
|
+
"input",
|
|
550
|
+
{
|
|
551
|
+
type: "email",
|
|
552
|
+
value: settings.sla.escalationEmail,
|
|
553
|
+
onChange: (e) => updateSLA("escalationEmail", e.target.value),
|
|
554
|
+
placeholder: "admin@example.com",
|
|
555
|
+
className: ts.input
|
|
556
|
+
}
|
|
557
|
+
) })
|
|
558
|
+
]
|
|
559
|
+
}
|
|
560
|
+
),
|
|
561
|
+
/* @__PURE__ */ jsxs(
|
|
562
|
+
CollapsibleSection,
|
|
563
|
+
{
|
|
564
|
+
title: "Fermeture automatique",
|
|
565
|
+
icon: /* @__PURE__ */ jsx(Timer, { size: 16 }),
|
|
566
|
+
color: "#d97706",
|
|
567
|
+
defaultOpen: false,
|
|
568
|
+
badge: settings.autoClose.enabled ? /* @__PURE__ */ jsxs("span", { className: ts.badge, style: { backgroundColor: "#dcfce7", color: "#166534" }, children: [
|
|
569
|
+
settings.autoClose.daysBeforeClose,
|
|
570
|
+
"j"
|
|
571
|
+
] }) : /* @__PURE__ */ jsx("span", { className: ts.badge, style: { backgroundColor: "#e5e7eb", color: "#374151" }, children: "Off" }),
|
|
572
|
+
children: [
|
|
573
|
+
/* @__PURE__ */ jsx("p", { className: ts.sectionDescription, children: "Les tickets en attente client sans reponse seront automatiquement resolus apres le delai configure. Un email de rappel est envoye avant la fermeture." }),
|
|
574
|
+
/* @__PURE__ */ jsxs("div", { className: ts.toggleRow, style: { paddingBottom: 14 }, children: [
|
|
575
|
+
/* @__PURE__ */ jsx(
|
|
576
|
+
Toggle,
|
|
577
|
+
{
|
|
578
|
+
checked: settings.autoClose.enabled,
|
|
579
|
+
onChange: () => updateAutoClose("enabled", !settings.autoClose.enabled),
|
|
580
|
+
color: "#d97706"
|
|
581
|
+
}
|
|
582
|
+
),
|
|
583
|
+
/* @__PURE__ */ jsx("span", { className: ts.inlineLabel, children: "Activer la fermeture automatique" })
|
|
584
|
+
] }),
|
|
585
|
+
settings.autoClose.enabled && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
586
|
+
/* @__PURE__ */ jsx(FieldRow, { label: "Delai avant fermeture", description: "Nombre de jours sans reponse du client", children: /* @__PURE__ */ jsxs("div", { className: ts.slaInline, children: [
|
|
587
|
+
/* @__PURE__ */ jsx(
|
|
588
|
+
"input",
|
|
589
|
+
{
|
|
590
|
+
type: "number",
|
|
591
|
+
min: 1,
|
|
592
|
+
max: 90,
|
|
593
|
+
value: settings.autoClose.daysBeforeClose,
|
|
594
|
+
onChange: (e) => updateAutoClose("daysBeforeClose", parseInt(e.target.value) || 7),
|
|
595
|
+
className: ts.numberInput
|
|
596
|
+
}
|
|
597
|
+
),
|
|
598
|
+
/* @__PURE__ */ jsx("span", { className: ts.slaHint, children: "jours" })
|
|
599
|
+
] }) }),
|
|
600
|
+
/* @__PURE__ */ jsx(FieldRow, { label: "Rappel avant fermeture", description: "Email de rappel envoye X jours avant", children: /* @__PURE__ */ jsxs("div", { className: ts.slaInline, children: [
|
|
601
|
+
/* @__PURE__ */ jsx(
|
|
602
|
+
"input",
|
|
603
|
+
{
|
|
604
|
+
type: "number",
|
|
605
|
+
min: 1,
|
|
606
|
+
max: settings.autoClose.daysBeforeClose - 1,
|
|
607
|
+
value: settings.autoClose.reminderDaysBefore,
|
|
608
|
+
onChange: (e) => updateAutoClose("reminderDaysBefore", parseInt(e.target.value) || 2),
|
|
609
|
+
className: ts.numberInput
|
|
610
|
+
}
|
|
611
|
+
),
|
|
612
|
+
/* @__PURE__ */ jsxs("span", { className: ts.slaHint, children: [
|
|
613
|
+
"jours avant (rappel a J-",
|
|
614
|
+
settings.autoClose.reminderDaysBefore,
|
|
615
|
+
")"
|
|
616
|
+
] })
|
|
617
|
+
] }) })
|
|
618
|
+
] })
|
|
619
|
+
]
|
|
620
|
+
}
|
|
621
|
+
),
|
|
622
|
+
/* @__PURE__ */ jsxs("div", { style: {
|
|
623
|
+
marginTop: 32,
|
|
624
|
+
marginBottom: 16,
|
|
625
|
+
padding: "12px 16px",
|
|
626
|
+
borderRadius: 8,
|
|
627
|
+
background: "linear-gradient(135deg, #dbeafe 0%, #ede9fe 100%)",
|
|
628
|
+
border: "1px solid #c7d2fe"
|
|
629
|
+
}, children: [
|
|
630
|
+
/* @__PURE__ */ jsx("div", { style: { fontWeight: 700, fontSize: 15, color: "#1e293b" }, children: "Mes preferences" }),
|
|
631
|
+
/* @__PURE__ */ jsx("div", { style: { fontSize: 13, color: "#64748b", marginTop: 2 }, children: "Ces reglages sont propres a votre compte et ne s'appliquent qu'a vous." })
|
|
632
|
+
] }),
|
|
633
|
+
/* @__PURE__ */ jsxs(
|
|
634
|
+
CollapsibleSection,
|
|
635
|
+
{
|
|
636
|
+
title: "Langue et localisation",
|
|
637
|
+
icon: /* @__PURE__ */ jsx(Globe, { size: 16 }),
|
|
638
|
+
color: "#16a34a",
|
|
639
|
+
defaultOpen: false,
|
|
640
|
+
children: [
|
|
641
|
+
/* @__PURE__ */ jsx("p", { className: ts.sectionDescription, children: "Langue de l'interface du module de support et des notifications email envoyees aux clients." }),
|
|
642
|
+
/* @__PURE__ */ jsx(FieldRow, { label: "Langue", description: "Langue principale du module", children: /* @__PURE__ */ jsxs(
|
|
643
|
+
"select",
|
|
644
|
+
{
|
|
645
|
+
value: settings.locale.language,
|
|
646
|
+
onChange: (e) => updateLocale("language", e.target.value),
|
|
647
|
+
className: ts.select,
|
|
648
|
+
children: [
|
|
649
|
+
/* @__PURE__ */ jsx("option", { value: "fr", children: "Francais" }),
|
|
650
|
+
/* @__PURE__ */ jsx("option", { value: "en", children: "English" })
|
|
651
|
+
]
|
|
652
|
+
}
|
|
653
|
+
) })
|
|
654
|
+
]
|
|
655
|
+
}
|
|
656
|
+
),
|
|
657
|
+
/* @__PURE__ */ jsxs(
|
|
658
|
+
CollapsibleSection,
|
|
659
|
+
{
|
|
660
|
+
title: "Signature email",
|
|
661
|
+
icon: /* @__PURE__ */ jsx(FileSignature, { size: 16 }),
|
|
662
|
+
color: "#6366f1",
|
|
663
|
+
defaultOpen: false,
|
|
664
|
+
children: [
|
|
665
|
+
/* @__PURE__ */ jsx("p", { className: ts.sectionDescription, children: "Signature ajoutee automatiquement en bas de chaque reponse email envoyee au client. Supporte le texte brut et le HTML basique." }),
|
|
666
|
+
/* @__PURE__ */ jsx(
|
|
667
|
+
"textarea",
|
|
668
|
+
{
|
|
669
|
+
value: signature,
|
|
670
|
+
onChange: (e) => {
|
|
671
|
+
setSignature(e.target.value);
|
|
672
|
+
setSaved(false);
|
|
673
|
+
},
|
|
674
|
+
placeholder: "Cordialement,\nL'equipe ConsilioWEB",
|
|
675
|
+
rows: 6,
|
|
676
|
+
className: ts.signatureTextarea
|
|
677
|
+
}
|
|
678
|
+
)
|
|
679
|
+
]
|
|
680
|
+
}
|
|
681
|
+
),
|
|
682
|
+
/* @__PURE__ */ jsxs(CollapsibleSection, { title: "Purge des logs", icon: /* @__PURE__ */ jsx(Settings, { size: 18 }), color: "#ef4444", defaultOpen: false, children: [
|
|
683
|
+
/* @__PURE__ */ jsx("p", { className: ts.sectionDescription, children: "Supprimez les anciens logs pour lib\xE9rer de l'espace. Cette action est irr\xE9versible." }),
|
|
684
|
+
/* @__PURE__ */ jsx("div", { className: ts.purgeGroup, children: ["email-logs", "auth-logs"].map((col) => /* @__PURE__ */ jsxs("div", { className: ts.purgeCategory, children: [
|
|
685
|
+
/* @__PURE__ */ jsx("span", { className: ts.purgeCategoryLabel, children: col === "email-logs" ? "Logs Email" : "Logs Auth" }),
|
|
686
|
+
/* @__PURE__ */ jsx("div", { className: ts.purgeButtons, children: [
|
|
687
|
+
{ label: "7 jours", days: 7 },
|
|
688
|
+
{ label: "30 jours", days: 30 },
|
|
689
|
+
{ label: "90 jours", days: 90 },
|
|
690
|
+
{ label: "Tout", days: 0 }
|
|
691
|
+
].map((opt) => /* @__PURE__ */ jsx(
|
|
692
|
+
"button",
|
|
693
|
+
{
|
|
694
|
+
onClick: async () => {
|
|
695
|
+
if (!window.confirm(`Supprimer les logs ${col} de plus de ${opt.days || "tous les"} jours ?`)) return;
|
|
696
|
+
try {
|
|
697
|
+
const res = await fetch(`/api/support/purge-logs?collection=${col}&days=${opt.days}`, { method: "DELETE", credentials: "include" });
|
|
698
|
+
if (res.ok) {
|
|
699
|
+
const d = await res.json();
|
|
700
|
+
alert(`${d.purged} log(s) supprim\xE9(s)`);
|
|
701
|
+
}
|
|
702
|
+
} catch {
|
|
703
|
+
alert("Erreur");
|
|
704
|
+
}
|
|
705
|
+
},
|
|
706
|
+
style: { ...btnStyle(opt.days === 0 ? "#ef4444" : "var(--theme-elevation-500)", { small: true }), fontSize: 11 },
|
|
707
|
+
children: opt.label
|
|
708
|
+
},
|
|
709
|
+
opt.days
|
|
710
|
+
)) })
|
|
711
|
+
] }, col)) })
|
|
712
|
+
] }),
|
|
713
|
+
/* @__PURE__ */ jsxs("div", { className: ts.bottomBar, children: [
|
|
714
|
+
/* @__PURE__ */ jsx("button", { onClick: handleReset, style: btnStyle("var(--theme-elevation-400)", { small: true }), children: "R\xE9initialiser tout" }),
|
|
715
|
+
/* @__PURE__ */ jsx(
|
|
716
|
+
"button",
|
|
717
|
+
{
|
|
718
|
+
onClick: handleSave,
|
|
719
|
+
disabled: saving,
|
|
720
|
+
style: btnStyle(saved ? V.green : V.blue, { small: true }),
|
|
721
|
+
children: saving ? "Sauvegarde..." : saved ? "\u2713 Sauvegard\xE9" : "Sauvegarder les modifications"
|
|
722
|
+
}
|
|
723
|
+
)
|
|
724
|
+
] })
|
|
725
|
+
] });
|
|
726
|
+
};
|
|
727
|
+
|
|
728
|
+
export { TicketingSettingsClient };
|