@consilioweb/payload-support 2.0.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (222) hide show
  1. package/README.md +656 -355
  2. package/dist/components/RichTextEditor/index.d.ts +19 -0
  3. package/dist/components/TicketConversation/RewriteDropdown.d.ts +6 -0
  4. package/dist/components/TicketConversation/SkeletonText.d.ts +4 -0
  5. package/dist/components/TicketConversation/components/AISummaryPanel.d.ts +14 -0
  6. package/dist/components/TicketConversation/components/ActionPanels.d.ts +47 -0
  7. package/dist/components/TicketConversation/components/ActivityLog.d.ts +5 -0
  8. package/dist/components/TicketConversation/components/ClientBar.d.ts +5 -0
  9. package/dist/components/TicketConversation/components/ClientHistory.d.ts +24 -0
  10. package/dist/components/TicketConversation/components/CodeBlock.d.ts +26 -0
  11. package/dist/components/TicketConversation/components/CodeBlockInserter.d.ts +12 -0
  12. package/dist/components/TicketConversation/components/QuickActions.d.ts +32 -0
  13. package/dist/components/TicketConversation/components/TicketHeader.d.ts +19 -0
  14. package/dist/components/TicketConversation/components/TimeTrackingPanel.d.ts +24 -0
  15. package/dist/components/TicketConversation/config.d.ts +10 -0
  16. package/dist/components/TicketConversation/config.js +1 -40
  17. package/dist/components/TicketConversation/constants.d.ts +56 -0
  18. package/dist/components/TicketConversation/context.d.ts +53 -0
  19. package/dist/components/TicketConversation/hooks/useAI.d.ts +21 -0
  20. package/dist/components/TicketConversation/hooks/useDocumentIdFromUrl.d.ts +3 -0
  21. package/dist/components/TicketConversation/hooks/useFeatures.d.ts +23 -0
  22. package/dist/components/TicketConversation/hooks/useFeatures.js +61 -0
  23. package/dist/components/TicketConversation/hooks/useMessageActions.d.ts +20 -0
  24. package/dist/components/TicketConversation/hooks/useReply.d.ts +27 -0
  25. package/dist/components/TicketConversation/hooks/useTicketActions.d.ts +58 -0
  26. package/dist/components/TicketConversation/hooks/useTimeTracking.d.ts +18 -0
  27. package/dist/components/TicketConversation/hooks/useTranslation.d.ts +33 -0
  28. package/dist/components/TicketConversation/hooks/useTranslation.js +22 -3
  29. package/dist/components/TicketConversation/index.d.ts +4 -0
  30. package/dist/components/TicketConversation/index.js +2 -2
  31. package/dist/components/TicketConversation/types.d.ts +56 -0
  32. package/dist/components/TicketConversation/utils.d.ts +2 -0
  33. package/dist/index.cjs +392 -320
  34. package/dist/index.d.cts +100 -3
  35. package/dist/index.d.ts +100 -3
  36. package/dist/index.js +388 -321
  37. package/dist/utils/features.d.ts +123 -0
  38. package/dist/utils/features.js +147 -0
  39. package/dist/views/BillingView/client.d.ts +2 -0
  40. package/dist/views/BillingView/index.d.ts +4 -0
  41. package/dist/views/ChatView/client.d.ts +2 -0
  42. package/dist/views/ChatView/client.js +9 -9
  43. package/dist/views/ChatView/index.d.ts +4 -0
  44. package/dist/views/CrmView/client.d.ts +2 -0
  45. package/dist/views/CrmView/client.js +6 -9
  46. package/dist/views/CrmView/index.d.ts +4 -0
  47. package/dist/views/EmailTrackingView/client.d.ts +2 -0
  48. package/dist/views/EmailTrackingView/index.d.ts +4 -0
  49. package/dist/views/ImportConversationView/client.d.ts +2 -0
  50. package/dist/views/ImportConversationView/index.d.ts +4 -0
  51. package/dist/views/LogsView/client.d.ts +2 -0
  52. package/dist/views/LogsView/index.d.ts +4 -0
  53. package/dist/views/NewTicketView/client.d.ts +2 -0
  54. package/dist/views/NewTicketView/index.d.ts +4 -0
  55. package/dist/views/PendingEmailsView/client.d.ts +2 -0
  56. package/dist/views/PendingEmailsView/index.d.ts +4 -0
  57. package/dist/views/SupportDashboardView/client.d.ts +2 -0
  58. package/dist/views/SupportDashboardView/client.js +1 -1
  59. package/dist/views/SupportDashboardView/index.d.ts +4 -0
  60. package/dist/views/TicketDetailView/NextActionItem.d.ts +6 -0
  61. package/dist/views/TicketDetailView/RewriteDropdown.d.ts +7 -0
  62. package/dist/views/TicketDetailView/client.d.ts +2 -0
  63. package/dist/views/TicketDetailView/client.js +2 -2
  64. package/dist/views/TicketDetailView/constants.d.ts +13 -0
  65. package/dist/views/TicketDetailView/helpers.d.ts +2 -0
  66. package/dist/views/TicketDetailView/index.d.ts +4 -0
  67. package/dist/views/TicketDetailView/types.d.ts +40 -0
  68. package/dist/views/TicketInboxView/client.d.ts +2 -0
  69. package/dist/views/TicketInboxView/client.js +5 -5
  70. package/dist/views/TicketInboxView/index.d.ts +4 -0
  71. package/dist/views/TicketingSettingsView/client.d.ts +2 -0
  72. package/dist/views/TicketingSettingsView/client.js +6 -5
  73. package/dist/views/TicketingSettingsView/index.d.ts +4 -0
  74. package/dist/views/TimeDashboardView/client.d.ts +2 -0
  75. package/dist/views/TimeDashboardView/index.d.ts +4 -0
  76. package/dist/views/shared/AdminViewHeader.d.ts +13 -0
  77. package/dist/views/shared/ErrorBoundary.d.ts +17 -0
  78. package/dist/views/shared/Skeleton.d.ts +21 -0
  79. package/dist/views/shared/StatusPill.d.ts +8 -0
  80. package/dist/views/shared/adminTokens.d.ts +19 -0
  81. package/dist/views/shared/config.d.ts +8 -0
  82. package/dist/views/shared/config.js +1 -40
  83. package/dist/views/shared/dateLocale.d.ts +5 -0
  84. package/dist/views/shared/index.d.ts +12 -0
  85. package/dist/views/shared/index.js +2 -1
  86. package/dist/views/shared/locales/en.json +708 -0
  87. package/dist/views/shared/locales/fr.json +708 -0
  88. package/dist/views/shared/sla.d.ts +14 -0
  89. package/dist/views.d.ts +13 -13
  90. package/package.json +26 -41
  91. package/src/collections/SupportClients.ts +29 -0
  92. package/src/collections/TicketCollaborators.ts +6 -1
  93. package/src/collections/TicketMessages.ts +46 -24
  94. package/src/collections/Tickets.ts +117 -79
  95. package/src/collections/TimeEntries.ts +57 -32
  96. package/src/components/TicketConversation/config.ts +16 -80
  97. package/src/components/TicketConversation/hooks/useFeatures.ts +109 -0
  98. package/src/components/TicketConversation/hooks/useTranslation.ts +38 -4
  99. package/src/components/TicketConversation/index.tsx +2 -2
  100. package/src/endpoints/ai.ts +2 -1
  101. package/src/endpoints/client-intelligence.ts +2 -1
  102. package/src/endpoints/process-scheduled.ts +13 -8
  103. package/src/endpoints/round-robin-config.ts +30 -20
  104. package/src/endpoints/settings.ts +28 -77
  105. package/src/index.ts +6 -2
  106. package/src/portal/LiveChat.tsx +33 -22
  107. package/src/portal/auth/tickets/detail/TicketPolling.tsx +5 -1
  108. package/src/types/lucide-react.d.ts +10 -2
  109. package/src/utils/aiAgent.ts +2 -1
  110. package/src/utils/aiProvider.ts +21 -0
  111. package/src/utils/features.ts +297 -0
  112. package/src/utils/fireWebhooks.ts +6 -0
  113. package/src/utils/generateTicketSynthesis.ts +2 -1
  114. package/src/utils/index.ts +4 -2
  115. package/src/utils/readSettings.ts +82 -9
  116. package/src/utils/webhookDispatcher.ts +19 -7
  117. package/src/views/ChatView/client.tsx +13 -9
  118. package/src/views/CrmView/client.tsx +10 -11
  119. package/src/views/SupportDashboardView/client.tsx +1 -1
  120. package/src/views/TicketDetailView/client.tsx +2 -2
  121. package/src/views/TicketInboxView/client.tsx +10 -5
  122. package/src/views/TicketingSettingsView/client.tsx +9 -7
  123. package/src/views/shared/config.ts +14 -80
  124. package/src/views/shared/index.ts +3 -1
  125. package/src/views/shared/locales/en.json +2 -2
  126. package/src/views/shared/locales/fr.json +2 -2
  127. package/dist/components/RichTextEditor/index.cjs +0 -279
  128. package/dist/components/TicketConversation/RewriteDropdown.cjs +0 -98
  129. package/dist/components/TicketConversation/SkeletonText.cjs +0 -21
  130. package/dist/components/TicketConversation/components/AISummaryPanel.cjs +0 -85
  131. package/dist/components/TicketConversation/components/ActionPanels.cjs +0 -193
  132. package/dist/components/TicketConversation/components/ActivityLog.cjs +0 -24
  133. package/dist/components/TicketConversation/components/ClientBar.cjs +0 -43
  134. package/dist/components/TicketConversation/components/ClientHistory.cjs +0 -138
  135. package/dist/components/TicketConversation/components/CodeBlock.cjs +0 -171
  136. package/dist/components/TicketConversation/components/CodeBlockInserter.cjs +0 -156
  137. package/dist/components/TicketConversation/components/QuickActions.cjs +0 -87
  138. package/dist/components/TicketConversation/components/TicketHeader.cjs +0 -93
  139. package/dist/components/TicketConversation/components/TimeTrackingPanel.cjs +0 -134
  140. package/dist/components/TicketConversation/config.cjs +0 -44
  141. package/dist/components/TicketConversation/constants.cjs +0 -127
  142. package/dist/components/TicketConversation/context.cjs +0 -13
  143. package/dist/components/TicketConversation/hooks/useAI.cjs +0 -196
  144. package/dist/components/TicketConversation/hooks/useDocumentIdFromUrl.cjs +0 -20
  145. package/dist/components/TicketConversation/hooks/useMessageActions.cjs +0 -136
  146. package/dist/components/TicketConversation/hooks/useReply.cjs +0 -188
  147. package/dist/components/TicketConversation/hooks/useTicketActions.cjs +0 -290
  148. package/dist/components/TicketConversation/hooks/useTimeTracking.cjs +0 -123
  149. package/dist/components/TicketConversation/hooks/useTranslation.cjs +0 -78
  150. package/dist/components/TicketConversation/index.cjs +0 -1114
  151. package/dist/components/TicketConversation/types.cjs +0 -2
  152. package/dist/components/TicketConversation/utils.cjs +0 -27
  153. package/dist/views/BillingView/client.cjs +0 -469
  154. package/dist/views/BillingView/index.cjs +0 -34
  155. package/dist/views/ChatView/client.cjs +0 -301
  156. package/dist/views/ChatView/index.cjs +0 -34
  157. package/dist/views/CrmView/client.cjs +0 -458
  158. package/dist/views/CrmView/index.cjs +0 -34
  159. package/dist/views/EmailTrackingView/client.cjs +0 -171
  160. package/dist/views/EmailTrackingView/index.cjs +0 -34
  161. package/dist/views/ImportConversationView/client.cjs +0 -238
  162. package/dist/views/ImportConversationView/index.cjs +0 -34
  163. package/dist/views/LogsView/client.cjs +0 -148
  164. package/dist/views/LogsView/index.cjs +0 -32
  165. package/dist/views/NewTicketView/client.cjs +0 -213
  166. package/dist/views/NewTicketView/index.cjs +0 -32
  167. package/dist/views/PendingEmailsView/client.cjs +0 -471
  168. package/dist/views/PendingEmailsView/index.cjs +0 -34
  169. package/dist/views/SupportDashboardView/client.cjs +0 -437
  170. package/dist/views/SupportDashboardView/index.cjs +0 -34
  171. package/dist/views/TicketDetailView/NextActionItem.cjs +0 -40
  172. package/dist/views/TicketDetailView/RewriteDropdown.cjs +0 -80
  173. package/dist/views/TicketDetailView/client.cjs +0 -1412
  174. package/dist/views/TicketDetailView/constants.cjs +0 -20
  175. package/dist/views/TicketDetailView/helpers.cjs +0 -23
  176. package/dist/views/TicketDetailView/index.cjs +0 -34
  177. package/dist/views/TicketDetailView/types.cjs +0 -2
  178. package/dist/views/TicketInboxView/client.cjs +0 -359
  179. package/dist/views/TicketInboxView/index.cjs +0 -32
  180. package/dist/views/TicketingSettingsView/client.cjs +0 -740
  181. package/dist/views/TicketingSettingsView/index.cjs +0 -34
  182. package/dist/views/TimeDashboardView/client.cjs +0 -180
  183. package/dist/views/TimeDashboardView/index.cjs +0 -34
  184. package/dist/views/shared/AdminViewHeader.cjs +0 -68
  185. package/dist/views/shared/ErrorBoundary.cjs +0 -55
  186. package/dist/views/shared/Skeleton.cjs +0 -77
  187. package/dist/views/shared/StatusPill.cjs +0 -47
  188. package/dist/views/shared/adminTokens.cjs +0 -34
  189. package/dist/views/shared/config.cjs +0 -44
  190. package/dist/views/shared/dateLocale.cjs +0 -5
  191. package/dist/views/shared/index.cjs +0 -72
  192. package/dist/views/shared/sla.cjs +0 -37
  193. package/dist/views.cjs +0 -86
  194. package/dist/views.d.cts +0 -13
  195. package/src/__tests__/aiSummaryRendering.test.ts +0 -21
  196. package/src/__tests__/authResponses.test.ts +0 -69
  197. package/src/__tests__/capabilities.test.ts +0 -71
  198. package/src/__tests__/generateTrackingToken.test.ts +0 -67
  199. package/src/__tests__/integration/ai-agent.test.ts +0 -46
  200. package/src/__tests__/integration/auth.test.ts +0 -43
  201. package/src/__tests__/integration/automation-rules.test.ts +0 -68
  202. package/src/__tests__/integration/buildTestPayload.ts +0 -52
  203. package/src/__tests__/integration/channels.test.ts +0 -52
  204. package/src/__tests__/integration/core-behaviors.test.ts +0 -81
  205. package/src/__tests__/integration/dashboard-volume.test.ts +0 -31
  206. package/src/__tests__/integration/digest.test.ts +0 -48
  207. package/src/__tests__/integration/invoice-pdf.test.ts +0 -30
  208. package/src/__tests__/integration/isolation.test.ts +0 -81
  209. package/src/__tests__/integration/mentions-invoice.test.ts +0 -50
  210. package/src/__tests__/integration/nps.test.ts +0 -37
  211. package/src/__tests__/integration/per-team-sla.test.ts +0 -44
  212. package/src/__tests__/integration/push.test.ts +0 -75
  213. package/src/__tests__/integration/sanitization.test.ts +0 -35
  214. package/src/__tests__/integration/sla-pause.test.ts +0 -39
  215. package/src/__tests__/integration/smoke.test.ts +0 -26
  216. package/src/__tests__/integration/snooze.test.ts +0 -68
  217. package/src/__tests__/integration/teams.test.ts +0 -38
  218. package/src/__tests__/rateLimiter.test.ts +0 -83
  219. package/src/__tests__/sanitizeHtml.test.ts +0 -165
  220. package/src/__tests__/sla.test.ts +0 -258
  221. package/src/__tests__/trackOpenEndpoint.test.ts +0 -54
  222. package/src/__tests__/webhookSecurity.test.ts +0 -58
@@ -1,740 +0,0 @@
1
- 'use strict';
2
-
3
- var jsxRuntime = require('react/jsx-runtime');
4
- var React = require('react');
5
- var lucideReact = require('lucide-react');
6
- var adminTokens = require('../shared/adminTokens');
7
- var AdminViewHeader = require('../shared/AdminViewHeader');
8
- var config = require('../../components/TicketConversation/config');
9
- var useTranslation = require('../../components/TicketConversation/hooks/useTranslation');
10
- var ts = require('../../styles/TicketingSettings.module.scss');
11
-
12
- function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
13
-
14
- var React__default = /*#__PURE__*/_interopDefault(React);
15
- var ts__default = /*#__PURE__*/_interopDefault(ts);
16
-
17
- const DEFAULT_SETTINGS = {
18
- email: {
19
- fromAddress: "",
20
- fromName: "Support ConsilioWEB",
21
- replyToAddress: ""
22
- },
23
- ai: {
24
- provider: "ollama",
25
- apiKey: "",
26
- model: "qwen2.5:32b",
27
- enableSentiment: true,
28
- enableSynthesis: true,
29
- enableSuggestion: true,
30
- enableRewrite: true
31
- },
32
- sla: {
33
- firstResponseMinutes: 120,
34
- resolutionMinutes: 1440,
35
- businessHoursOnly: true,
36
- escalationEmail: ""
37
- },
38
- autoClose: {
39
- enabled: true,
40
- daysBeforeClose: 7,
41
- reminderDaysBefore: 2
42
- },
43
- locale: {
44
- language: "fr"
45
- }
46
- };
47
- async function fetchSettingsFromAPI() {
48
- try {
49
- const res = await fetch("/api/support/settings", { credentials: "include" });
50
- if (res.ok) {
51
- const data = await res.json();
52
- return {
53
- email: { ...DEFAULT_SETTINGS.email, ...data.email },
54
- ai: { ...DEFAULT_SETTINGS.ai, apiKey: "", ...data.ai },
55
- sla: { ...DEFAULT_SETTINGS.sla, ...data.sla },
56
- autoClose: { ...DEFAULT_SETTINGS.autoClose, ...data.autoClose },
57
- locale: DEFAULT_SETTINGS.locale
58
- // locale is now per-user
59
- };
60
- }
61
- } catch {
62
- }
63
- return DEFAULT_SETTINGS;
64
- }
65
- async function saveSettingsToAPI(settings) {
66
- try {
67
- const toSave = {
68
- email: settings.email,
69
- ai: { ...settings.ai, apiKey: void 0 },
70
- sla: settings.sla,
71
- autoClose: settings.autoClose
72
- // locale excluded — saved per-user via user-prefs
73
- };
74
- const res = await fetch("/api/support/settings", {
75
- method: "POST",
76
- headers: { "Content-Type": "application/json" },
77
- credentials: "include",
78
- body: JSON.stringify(toSave)
79
- });
80
- return res.ok;
81
- } catch {
82
- return false;
83
- }
84
- }
85
- async function fetchUserPrefs() {
86
- try {
87
- const res = await fetch("/api/support/user-prefs", { credentials: "include" });
88
- if (res.ok) return await res.json();
89
- } catch {
90
- }
91
- return { locale: "fr", signature: "" };
92
- }
93
- async function saveUserPrefs(prefs) {
94
- try {
95
- const res = await fetch("/api/support/user-prefs", {
96
- method: "POST",
97
- headers: { "Content-Type": "application/json" },
98
- credentials: "include",
99
- body: JSON.stringify(prefs)
100
- });
101
- return res.ok;
102
- } catch {
103
- return false;
104
- }
105
- }
106
- function getFeatureList(t) {
107
- return [
108
- // Core
109
- { key: "canned", label: t("settingsView.features.canned.label"), description: t("settingsView.features.canned.description"), category: "core" },
110
- { key: "scheduledReplies", label: t("settingsView.features.scheduledReplies.label"), description: t("settingsView.features.scheduledReplies.description"), category: "core" },
111
- { key: "activityLog", label: t("settingsView.features.activityLog.label"), description: t("settingsView.features.activityLog.description"), category: "core" },
112
- // Communication
113
- { key: "emailTracking", label: t("settingsView.features.emailTracking.label"), description: t("settingsView.features.emailTracking.description"), category: "communication" },
114
- { key: "chat", label: t("settingsView.features.chat.label"), description: t("settingsView.features.chat.description"), category: "communication" },
115
- { key: "externalMessages", label: t("settingsView.features.externalMessages.label"), description: t("settingsView.features.externalMessages.description"), category: "communication" },
116
- // Productivity
117
- { key: "ai", label: t("settingsView.features.ai.label"), description: t("settingsView.features.ai.description"), category: "productivity" },
118
- { key: "timeTracking", label: t("settingsView.features.timeTracking.label"), description: t("settingsView.features.timeTracking.description"), category: "productivity" },
119
- { key: "satisfaction", label: t("settingsView.features.satisfaction.label"), description: t("settingsView.features.satisfaction.description"), category: "productivity" },
120
- // Advanced
121
- { key: "merge", label: t("settingsView.features.merge.label"), description: t("settingsView.features.merge.description"), category: "advanced" },
122
- { key: "splitTicket", label: t("settingsView.features.splitTicket.label"), description: t("settingsView.features.splitTicket.description"), category: "advanced" },
123
- { key: "snooze", label: t("settingsView.features.snooze.label"), description: t("settingsView.features.snooze.description"), category: "advanced" },
124
- { key: "clientHistory", label: t("settingsView.features.clientHistory.label"), description: t("settingsView.features.clientHistory.description"), category: "advanced" }
125
- ];
126
- }
127
- function getCategories(t) {
128
- return [
129
- { key: "core", label: t("settingsView.categories.core"), color: adminTokens.V.blue },
130
- { key: "communication", label: t("settingsView.categories.communication"), color: adminTokens.V.green },
131
- { key: "productivity", label: t("settingsView.categories.productivity"), color: adminTokens.V.amber },
132
- { key: "advanced", label: t("settingsView.categories.advanced"), color: "#17807c" }
133
- ];
134
- }
135
- const Toggle = ({ checked, onChange, color = adminTokens.V.blue, size = "md" }) => {
136
- const w = size === "sm" ? 36 : 40;
137
- const h = size === "sm" ? 20 : 22;
138
- const knob = size === "sm" ? 16 : 18;
139
- return /* @__PURE__ */ jsxRuntime.jsx(
140
- "div",
141
- {
142
- role: "switch",
143
- "aria-checked": checked,
144
- tabIndex: 0,
145
- onClick: onChange,
146
- onKeyDown: (e) => {
147
- if (e.key === "Enter" || e.key === " ") {
148
- e.preventDefault();
149
- onChange();
150
- }
151
- },
152
- style: {
153
- width: w,
154
- height: h,
155
- borderRadius: h / 2,
156
- flexShrink: 0,
157
- backgroundColor: checked ? color : "var(--theme-elevation-300)",
158
- position: "relative",
159
- transition: "background 150ms",
160
- cursor: "pointer"
161
- },
162
- children: /* @__PURE__ */ jsxRuntime.jsx("div", { style: {
163
- width: knob,
164
- height: knob,
165
- borderRadius: "50%",
166
- backgroundColor: "#fff",
167
- position: "absolute",
168
- top: (h - knob) / 2,
169
- left: checked ? w - knob - (h - knob) / 2 : (h - knob) / 2,
170
- transition: "left 150ms",
171
- boxShadow: "0 1px 3px rgba(0,0,0,0.15)"
172
- } })
173
- }
174
- );
175
- };
176
- const CollapsibleSection = ({ title, icon, color, defaultOpen = true, children, badge }) => {
177
- const [open, setOpen] = React.useState(defaultOpen);
178
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ts__default.default.sectionWrapper, children: [
179
- /* @__PURE__ */ jsxRuntime.jsxs(
180
- "div",
181
- {
182
- className: ts__default.default.sectionHeader,
183
- onClick: () => setOpen(!open),
184
- role: "button",
185
- tabIndex: 0,
186
- onKeyDown: (e) => {
187
- if (e.key === "Enter" || e.key === " ") {
188
- e.preventDefault();
189
- setOpen(!open);
190
- }
191
- },
192
- "aria-expanded": open,
193
- children: [
194
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: ts__default.default.sectionIcon, style: { backgroundColor: color }, children: icon }),
195
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: ts__default.default.sectionTitle, children: title }),
196
- badge,
197
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: `${ts__default.default.sectionChevron} ${open ? ts__default.default.open : ""}`, children: "\u25BC" })
198
- ]
199
- }
200
- ),
201
- open && /* @__PURE__ */ jsxRuntime.jsx("div", { className: ts__default.default.sectionBody, children })
202
- ] });
203
- };
204
- const FieldRow = ({ label, description, children }) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ts__default.default.fieldRow, children: [
205
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ts__default.default.fieldLabel, children: [
206
- label,
207
- description && /* @__PURE__ */ jsxRuntime.jsx("div", { className: ts__default.default.fieldDescription, children: description })
208
- ] }),
209
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: ts__default.default.fieldContent, children })
210
- ] });
211
- const TicketingSettingsClient = () => {
212
- const { t } = useTranslation.useTranslation();
213
- const FEATURE_LIST = React__default.default.useMemo(() => getFeatureList(t), [t]);
214
- const CATEGORIES = React__default.default.useMemo(() => getCategories(t), [t]);
215
- const [features, setFeatures] = React.useState(() => config.getFeatures());
216
- const [settings, setSettings] = React.useState(DEFAULT_SETTINGS);
217
- const [signature, setSignature] = React.useState("");
218
- const [saved, setSaved] = React.useState(false);
219
- const [saving, setSaving] = React.useState(false);
220
- const [showApiKey, setShowApiKey] = React.useState(false);
221
- const [loadingSettings, setLoadingSettings] = React.useState(true);
222
- React.useEffect(() => {
223
- let cancelled = false;
224
- Promise.all([fetchSettingsFromAPI(), fetchUserPrefs()]).then(([s, prefs]) => {
225
- if (!cancelled) {
226
- setSettings({ ...s, locale: { language: prefs.locale || "fr" } });
227
- setSignature(prefs.signature || "");
228
- setLoadingSettings(false);
229
- }
230
- });
231
- return () => {
232
- cancelled = true;
233
- };
234
- }, []);
235
- const handleToggle = (key) => {
236
- const updated = { ...features, [key]: !features[key] };
237
- setFeatures(updated);
238
- setSaved(false);
239
- };
240
- const updateEmail = (field, value) => {
241
- setSettings((prev) => ({ ...prev, email: { ...prev.email, [field]: value } }));
242
- setSaved(false);
243
- };
244
- const updateAI = (field, value) => {
245
- setSettings((prev) => ({ ...prev, ai: { ...prev.ai, [field]: value } }));
246
- setSaved(false);
247
- };
248
- const updateSLA = (field, value) => {
249
- setSettings((prev) => ({ ...prev, sla: { ...prev.sla, [field]: value } }));
250
- setSaved(false);
251
- };
252
- const updateAutoClose = (field, value) => {
253
- setSettings((prev) => ({ ...prev, autoClose: { ...prev.autoClose, [field]: value } }));
254
- setSaved(false);
255
- };
256
- const updateLocale = (field, value) => {
257
- setSettings((prev) => ({ ...prev, locale: { ...prev.locale, [field]: value } }));
258
- setSaved(false);
259
- };
260
- const handleSave = async () => {
261
- setSaving(true);
262
- config.saveFeatures(features);
263
- const [settingsOk, prefsOk] = await Promise.all([
264
- saveSettingsToAPI(settings),
265
- saveUserPrefs({ locale: settings.locale.language, signature })
266
- ]);
267
- setSaving(false);
268
- if (settingsOk && prefsOk) {
269
- setSaved(true);
270
- setTimeout(() => setSaved(false), 3e3);
271
- }
272
- };
273
- const handleReset = () => {
274
- setFeatures({ ...config.DEFAULT_FEATURES });
275
- setSettings({ ...DEFAULT_SETTINGS });
276
- setSignature("");
277
- setSaved(false);
278
- };
279
- const enabledCount = Object.entries(features).filter(([k, v]) => typeof v === "boolean" && v).length;
280
- const totalCount = Object.entries(features).filter(([k, v]) => typeof v === "boolean").length;
281
- const smtpHost = process.env.NEXT_PUBLIC_SMTP_HOST || "(non configure)";
282
- const smtpPort = process.env.NEXT_PUBLIC_SMTP_PORT || "\u2014";
283
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ts__default.default.page, children: [
284
- /* @__PURE__ */ jsxRuntime.jsx(
285
- AdminViewHeader.AdminViewHeader,
286
- {
287
- icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Settings, { size: 24 }),
288
- title: t("settingsView.configTitle"),
289
- subtitle: t("settings.subtitle", { enabled: String(enabledCount), total: String(totalCount) }),
290
- actions: /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", gap: 8 }, children: [
291
- /* @__PURE__ */ jsxRuntime.jsx("button", { onClick: handleReset, style: adminTokens.btnStyle("var(--theme-elevation-400)", { small: true }), children: t("settingsView.reset") }),
292
- /* @__PURE__ */ jsxRuntime.jsx(
293
- "button",
294
- {
295
- onClick: handleSave,
296
- disabled: saving,
297
- style: adminTokens.btnStyle(saved ? adminTokens.V.green : adminTokens.V.blue, { small: true }),
298
- children: saving ? "..." : saved ? t("settingsView.saved") : t("common.save")
299
- }
300
- )
301
- ] })
302
- }
303
- ),
304
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: ts__default.default.intro, children: t("settingsView.intro") }),
305
- /* @__PURE__ */ jsxRuntime.jsxs(
306
- CollapsibleSection,
307
- {
308
- title: t("settingsView.features"),
309
- icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Settings, { size: 16 }),
310
- color: adminTokens.V.blue,
311
- badge: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: ts__default.default.badge, style: { backgroundColor: "#dbeafe", color: "#1e40af" }, children: [
312
- enabledCount,
313
- "/",
314
- totalCount
315
- ] }),
316
- children: [
317
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: ts__default.default.sectionDescription, children: t("settingsView.featuresDescription") }),
318
- CATEGORIES.map((cat) => {
319
- const categoryFeatures = FEATURE_LIST.filter((f) => f.category === cat.key);
320
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ts__default.default.categoryGroup, children: [
321
- /* @__PURE__ */ jsxRuntime.jsxs("h3", { className: ts__default.default.categoryHeading, style: { color: cat.color }, children: [
322
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: ts__default.default.categoryDot, style: { backgroundColor: cat.color } }),
323
- cat.label
324
- ] }),
325
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: ts__default.default.featureList, children: categoryFeatures.map((feat) => {
326
- const enabled = features[feat.key];
327
- return /* @__PURE__ */ jsxRuntime.jsxs(
328
- "div",
329
- {
330
- onClick: () => handleToggle(feat.key),
331
- className: `${ts__default.default.featureCard} ${enabled ? ts__default.default.enabled : ""}`,
332
- role: "switch",
333
- "aria-checked": !!enabled,
334
- tabIndex: 0,
335
- onKeyDown: (e) => {
336
- if (e.key === "Enter" || e.key === " ") {
337
- e.preventDefault();
338
- handleToggle(feat.key);
339
- }
340
- },
341
- children: [
342
- /* @__PURE__ */ jsxRuntime.jsx(Toggle, { checked: !!enabled, onChange: () => handleToggle(feat.key), color: cat.color }),
343
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { flex: 1 }, children: [
344
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: ts__default.default.featureLabel, children: feat.label }),
345
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: ts__default.default.featureDesc, children: feat.description })
346
- ] })
347
- ]
348
- },
349
- feat.key
350
- );
351
- }) })
352
- ] }, cat.key);
353
- })
354
- ]
355
- }
356
- ),
357
- /* @__PURE__ */ jsxRuntime.jsxs(
358
- CollapsibleSection,
359
- {
360
- title: t("settingsView.emailConfig"),
361
- icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Mail, { size: 16 }),
362
- color: "#ea580c",
363
- defaultOpen: false,
364
- children: [
365
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: ts__default.default.sectionDescription, children: t("settingsView.emailDescription") }),
366
- /* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: t("settingsView.senderAddress"), description: t("settingsView.senderAddressDesc"), children: /* @__PURE__ */ jsxRuntime.jsx(
367
- "input",
368
- {
369
- type: "email",
370
- value: settings.email.fromAddress,
371
- onChange: (e) => updateEmail("fromAddress", e.target.value),
372
- placeholder: "support@example.com",
373
- className: ts__default.default.input
374
- }
375
- ) }),
376
- /* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: t("settingsView.senderName"), description: t("settingsView.senderNameDesc"), children: /* @__PURE__ */ jsxRuntime.jsx(
377
- "input",
378
- {
379
- type: "text",
380
- value: settings.email.fromName,
381
- onChange: (e) => updateEmail("fromName", e.target.value),
382
- placeholder: "Support ConsilioWEB",
383
- className: ts__default.default.input
384
- }
385
- ) }),
386
- /* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: t("settingsView.replyTo"), description: t("settingsView.replyToDesc"), children: /* @__PURE__ */ jsxRuntime.jsx(
387
- "input",
388
- {
389
- type: "email",
390
- value: settings.email.replyToAddress,
391
- onChange: (e) => updateEmail("replyToAddress", e.target.value),
392
- placeholder: "(identique a l'expediteur)",
393
- className: ts__default.default.input
394
- }
395
- ) }),
396
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: ts__default.default.separator }),
397
- /* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: t("settingsView.smtpServer"), description: t("settingsView.smtpServerDesc"), children: /* @__PURE__ */ jsxRuntime.jsx(
398
- "input",
399
- {
400
- type: "text",
401
- value: smtpHost,
402
- readOnly: true,
403
- className: ts__default.default.inputReadonly
404
- }
405
- ) }),
406
- /* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: t("settingsView.smtpPort"), children: /* @__PURE__ */ jsxRuntime.jsx(
407
- "input",
408
- {
409
- type: "text",
410
- value: smtpPort,
411
- readOnly: true,
412
- className: ts__default.default.inputReadonly,
413
- style: { maxWidth: 100 }
414
- }
415
- ) })
416
- ]
417
- }
418
- ),
419
- /* @__PURE__ */ jsxRuntime.jsxs(
420
- CollapsibleSection,
421
- {
422
- title: t("settingsView.aiTitle"),
423
- icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Bot, { size: 16 }),
424
- color: "#17807c",
425
- defaultOpen: false,
426
- badge: features.ai ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: ts__default.default.badge, style: { backgroundColor: "#dcfce7", color: "#166534" }, children: t("settingsView.aiBadgeActive") }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: ts__default.default.badge, style: { backgroundColor: "#fee2e2", color: "#991b1b" }, children: t("settingsView.aiBadgeInactive") }),
427
- children: [
428
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: ts__default.default.sectionDescription, children: t("settingsView.aiDescription") }),
429
- /* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: t("settingsView.aiProvider"), description: t("settingsView.aiProviderDesc"), children: /* @__PURE__ */ jsxRuntime.jsxs(
430
- "select",
431
- {
432
- value: settings.ai.provider,
433
- onChange: (e) => updateAI("provider", e.target.value),
434
- className: ts__default.default.select,
435
- children: [
436
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "ollama", children: "Ollama (local / tunnel)" }),
437
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "anthropic", children: "Anthropic (Claude)" }),
438
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "openai", children: "OpenAI (GPT)" }),
439
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "gemini", children: "Google (Gemini)" })
440
- ]
441
- }
442
- ) }),
443
- settings.ai.provider !== "ollama" && /* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: t("settingsView.aiApiKey"), description: t("settingsView.aiApiKeyDesc"), children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ts__default.default.apiKeyRow, children: [
444
- /* @__PURE__ */ jsxRuntime.jsx(
445
- "input",
446
- {
447
- type: showApiKey ? "text" : "password",
448
- value: settings.ai.apiKey,
449
- onChange: (e) => updateAI("apiKey", e.target.value),
450
- placeholder: "sk-...",
451
- className: ts__default.default.input,
452
- style: { flex: 1 }
453
- }
454
- ),
455
- /* @__PURE__ */ jsxRuntime.jsx(
456
- "button",
457
- {
458
- onClick: () => setShowApiKey(!showApiKey),
459
- className: ts__default.default.apiKeyToggle,
460
- children: showApiKey ? t("settingsView.hideKey") : t("settingsView.showKey")
461
- }
462
- )
463
- ] }) }),
464
- /* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: t("settingsView.aiModel"), description: t("settingsView.aiModelDesc"), children: /* @__PURE__ */ jsxRuntime.jsx(
465
- "input",
466
- {
467
- type: "text",
468
- value: settings.ai.model,
469
- onChange: (e) => updateAI("model", e.target.value),
470
- placeholder: "qwen2.5:32b",
471
- className: ts__default.default.input
472
- }
473
- ) }),
474
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: ts__default.default.separator }),
475
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: ts__default.default.aiSubFeaturesLabel, children: t("settingsView.aiSubFeatures") }),
476
- [
477
- { key: "enableSentiment", label: t("settingsView.aiSentiment"), desc: t("settingsView.aiSentimentDesc") },
478
- { key: "enableSynthesis", label: t("settingsView.aiSynthesis"), desc: t("settingsView.aiSynthesisDesc") },
479
- { key: "enableSuggestion", label: t("settingsView.aiSuggestion"), desc: t("settingsView.aiSuggestionDesc") },
480
- { key: "enableRewrite", label: t("settingsView.aiRewrite"), desc: t("settingsView.aiRewriteDesc") }
481
- ].map((item) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ts__default.default.aiToggleRow, children: [
482
- /* @__PURE__ */ jsxRuntime.jsx(
483
- Toggle,
484
- {
485
- checked: settings.ai[item.key],
486
- onChange: () => updateAI(item.key, !settings.ai[item.key]),
487
- color: "#17807c",
488
- size: "sm"
489
- }
490
- ),
491
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { flex: 1 }, children: [
492
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: ts__default.default.aiToggleLabel, children: item.label }),
493
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: ts__default.default.aiToggleDesc, children: item.desc })
494
- ] })
495
- ] }, item.key))
496
- ]
497
- }
498
- ),
499
- /* @__PURE__ */ jsxRuntime.jsxs(
500
- CollapsibleSection,
501
- {
502
- title: t("settingsView.slaTitle"),
503
- icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Clock, { size: 16 }),
504
- color: "#0891b2",
505
- defaultOpen: false,
506
- children: [
507
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: ts__default.default.sectionDescription, children: t("settingsView.slaDescription") }),
508
- /* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: t("settingsView.slaFirstResponse"), description: t("settingsView.slaFirstResponseDesc"), children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ts__default.default.slaInline, children: [
509
- /* @__PURE__ */ jsxRuntime.jsx(
510
- "input",
511
- {
512
- type: "number",
513
- min: 1,
514
- value: settings.sla.firstResponseMinutes,
515
- onChange: (e) => updateSLA("firstResponseMinutes", parseInt(e.target.value) || 0),
516
- className: ts__default.default.numberInput
517
- }
518
- ),
519
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: ts__default.default.slaHint, children: [
520
- t("settingsView.minutes"),
521
- " (",
522
- Math.floor(settings.sla.firstResponseMinutes / 60),
523
- "h",
524
- String(settings.sla.firstResponseMinutes % 60).padStart(2, "0"),
525
- ")"
526
- ] })
527
- ] }) }),
528
- /* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: t("settingsView.slaResolution"), description: t("settingsView.slaResolutionDesc"), children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ts__default.default.slaInline, children: [
529
- /* @__PURE__ */ jsxRuntime.jsx(
530
- "input",
531
- {
532
- type: "number",
533
- min: 1,
534
- value: settings.sla.resolutionMinutes,
535
- onChange: (e) => updateSLA("resolutionMinutes", parseInt(e.target.value) || 0),
536
- className: ts__default.default.numberInput
537
- }
538
- ),
539
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: ts__default.default.slaHint, children: [
540
- t("settingsView.minutes"),
541
- " (",
542
- Math.floor(settings.sla.resolutionMinutes / 60),
543
- "h",
544
- String(settings.sla.resolutionMinutes % 60).padStart(2, "0"),
545
- ")"
546
- ] })
547
- ] }) }),
548
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ts__default.default.toggleRow, children: [
549
- /* @__PURE__ */ jsxRuntime.jsx(
550
- Toggle,
551
- {
552
- checked: settings.sla.businessHoursOnly,
553
- onChange: () => updateSLA("businessHoursOnly", !settings.sla.businessHoursOnly),
554
- color: "#0891b2",
555
- size: "sm"
556
- }
557
- ),
558
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
559
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: ts__default.default.inlineLabel, children: t("settingsView.businessHoursOnly") }),
560
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: ts__default.default.inlineDesc, children: t("settingsView.businessHoursDesc") })
561
- ] })
562
- ] }),
563
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: ts__default.default.separator }),
564
- /* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: t("settingsView.escalationEmail"), description: t("settingsView.escalationEmailDesc"), children: /* @__PURE__ */ jsxRuntime.jsx(
565
- "input",
566
- {
567
- type: "email",
568
- value: settings.sla.escalationEmail,
569
- onChange: (e) => updateSLA("escalationEmail", e.target.value),
570
- placeholder: "admin@example.com",
571
- className: ts__default.default.input
572
- }
573
- ) })
574
- ]
575
- }
576
- ),
577
- /* @__PURE__ */ jsxRuntime.jsxs(
578
- CollapsibleSection,
579
- {
580
- title: t("settingsView.autoCloseTitle"),
581
- icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Timer, { size: 16 }),
582
- color: "#d97706",
583
- defaultOpen: false,
584
- badge: settings.autoClose.enabled ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: ts__default.default.badge, style: { backgroundColor: "#dcfce7", color: "#166534" }, children: [
585
- settings.autoClose.daysBeforeClose,
586
- "j"
587
- ] }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: ts__default.default.badge, style: { backgroundColor: "#e5e7eb", color: "#374151" }, children: "Off" }),
588
- children: [
589
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: ts__default.default.sectionDescription, children: t("settingsView.autoCloseDescription") }),
590
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ts__default.default.toggleRow, style: { paddingBottom: 14 }, children: [
591
- /* @__PURE__ */ jsxRuntime.jsx(
592
- Toggle,
593
- {
594
- checked: settings.autoClose.enabled,
595
- onChange: () => updateAutoClose("enabled", !settings.autoClose.enabled),
596
- color: "#d97706"
597
- }
598
- ),
599
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: ts__default.default.inlineLabel, children: t("settingsView.autoCloseEnable") })
600
- ] }),
601
- settings.autoClose.enabled && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
602
- /* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: t("settingsView.autoCloseDelay"), description: t("settingsView.autoCloseDelayDesc"), children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ts__default.default.slaInline, children: [
603
- /* @__PURE__ */ jsxRuntime.jsx(
604
- "input",
605
- {
606
- type: "number",
607
- min: 1,
608
- max: 90,
609
- value: settings.autoClose.daysBeforeClose,
610
- onChange: (e) => updateAutoClose("daysBeforeClose", parseInt(e.target.value) || 7),
611
- className: ts__default.default.numberInput
612
- }
613
- ),
614
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: ts__default.default.slaHint, children: t("settingsView.days") })
615
- ] }) }),
616
- /* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: t("settingsView.autoCloseReminder"), description: t("settingsView.autoCloseReminderDesc"), children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ts__default.default.slaInline, children: [
617
- /* @__PURE__ */ jsxRuntime.jsx(
618
- "input",
619
- {
620
- type: "number",
621
- min: 1,
622
- max: settings.autoClose.daysBeforeClose - 1,
623
- value: settings.autoClose.reminderDaysBefore,
624
- onChange: (e) => updateAutoClose("reminderDaysBefore", parseInt(e.target.value) || 2),
625
- className: ts__default.default.numberInput
626
- }
627
- ),
628
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: ts__default.default.slaHint, children: t("settingsView.autoCloseDaysBeforeReminder", { count: String(settings.autoClose.reminderDaysBefore) }) })
629
- ] }) })
630
- ] })
631
- ]
632
- }
633
- ),
634
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: {
635
- marginTop: 32,
636
- marginBottom: 16,
637
- padding: "12px 16px",
638
- borderRadius: 8,
639
- background: "linear-gradient(135deg, #dbeafe 0%, #ede9fe 100%)",
640
- border: "1px solid #c7d2fe"
641
- }, children: [
642
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontWeight: 700, fontSize: 15, color: "#1e293b" }, children: t("settingsView.myPreferences") }),
643
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: 13, color: "#64748b", marginTop: 2 }, children: t("settingsView.myPreferencesDesc") })
644
- ] }),
645
- /* @__PURE__ */ jsxRuntime.jsxs(
646
- CollapsibleSection,
647
- {
648
- title: t("settingsView.localeTitle"),
649
- icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Globe, { size: 16 }),
650
- color: "#16a34a",
651
- defaultOpen: false,
652
- children: [
653
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: ts__default.default.sectionDescription, children: t("settingsView.localeDescription") }),
654
- /* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: t("settingsView.language"), description: t("settingsView.languageDesc"), children: /* @__PURE__ */ jsxRuntime.jsxs(
655
- "select",
656
- {
657
- value: settings.locale.language,
658
- onChange: (e) => updateLocale("language", e.target.value),
659
- className: ts__default.default.select,
660
- children: [
661
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "fr", children: t("settingsView.french") }),
662
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "en", children: t("settingsView.english") })
663
- ]
664
- }
665
- ) })
666
- ]
667
- }
668
- ),
669
- /* @__PURE__ */ jsxRuntime.jsxs(
670
- CollapsibleSection,
671
- {
672
- title: t("settingsView.signatureTitle"),
673
- icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileSignature, { size: 16 }),
674
- color: "#6366f1",
675
- defaultOpen: false,
676
- children: [
677
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: ts__default.default.sectionDescription, children: t("settingsView.signatureDescription") }),
678
- /* @__PURE__ */ jsxRuntime.jsx(
679
- "textarea",
680
- {
681
- value: signature,
682
- onChange: (e) => {
683
- setSignature(e.target.value);
684
- setSaved(false);
685
- },
686
- placeholder: t("settingsView.signaturePlaceholder"),
687
- rows: 6,
688
- className: ts__default.default.signatureTextarea
689
- }
690
- )
691
- ]
692
- }
693
- ),
694
- /* @__PURE__ */ jsxRuntime.jsxs(CollapsibleSection, { title: t("settingsView.purgeTitle"), icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Settings, { size: 18 }), color: "#ef4444", defaultOpen: false, children: [
695
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: ts__default.default.sectionDescription, children: t("settingsView.purgeDescription") }),
696
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: ts__default.default.purgeGroup, children: ["email-logs", "auth-logs"].map((col) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ts__default.default.purgeCategory, children: [
697
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: ts__default.default.purgeCategoryLabel, children: col === "email-logs" ? t("settingsView.purgeEmailLogs") : t("settingsView.purgeAuthLogs") }),
698
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: ts__default.default.purgeButtons, children: [
699
- { label: t("settingsView.purge7days"), days: 7 },
700
- { label: t("settingsView.purge30days"), days: 30 },
701
- { label: t("settingsView.purge90days"), days: 90 },
702
- { label: t("settingsView.purgeAllLabel"), days: 0 }
703
- ].map((opt) => /* @__PURE__ */ jsxRuntime.jsx(
704
- "button",
705
- {
706
- onClick: async () => {
707
- if (!window.confirm(t("settingsView.purgeConfirm", { collection: col, days: opt.days === 0 ? t("settingsView.purgeAllLabel") : String(opt.days) }))) return;
708
- try {
709
- const res = await fetch(`/api/support/purge-logs?collection=${col}&days=${opt.days}`, { method: "DELETE", credentials: "include" });
710
- if (res.ok) {
711
- const d = await res.json();
712
- alert(`${d.purged} ${t("settingsView.purgeDone")}`);
713
- }
714
- } catch {
715
- alert(t("import.errorTitle"));
716
- }
717
- },
718
- style: { ...adminTokens.btnStyle(opt.days === 0 ? "#ef4444" : "var(--theme-elevation-500)", { small: true }), fontSize: 11 },
719
- children: opt.label
720
- },
721
- opt.days
722
- )) })
723
- ] }, col)) })
724
- ] }),
725
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ts__default.default.bottomBar, children: [
726
- /* @__PURE__ */ jsxRuntime.jsx("button", { onClick: handleReset, style: adminTokens.btnStyle("var(--theme-elevation-400)", { small: true }), children: t("settingsView.resetAll") }),
727
- /* @__PURE__ */ jsxRuntime.jsx(
728
- "button",
729
- {
730
- onClick: handleSave,
731
- disabled: saving,
732
- style: adminTokens.btnStyle(saved ? adminTokens.V.green : adminTokens.V.blue, { small: true }),
733
- children: saving ? t("settingsView.saving") : saved ? t("settingsView.saved2") : t("settingsView.saveChanges")
734
- }
735
- )
736
- ] })
737
- ] });
738
- };
739
-
740
- exports.TicketingSettingsClient = TicketingSettingsClient;