@consilioweb/payload-support 0.8.2 → 0.9.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/dist/components/RichTextEditor/index.cjs +233 -0
  2. package/dist/components/RichTextEditor/index.js +232 -0
  3. package/dist/components/TicketConversation/components/CodeBlock.cjs +24 -7
  4. package/dist/components/TicketConversation/components/CodeBlock.js +23 -9
  5. package/dist/index.cjs +19 -1
  6. package/dist/index.js +19 -1
  7. package/dist/views/BillingView/client.cjs +260 -103
  8. package/dist/views/BillingView/client.js +259 -103
  9. package/dist/views/ChatView/client.cjs +184 -137
  10. package/dist/views/ChatView/client.js +180 -137
  11. package/dist/views/CrmView/client.cjs +270 -122
  12. package/dist/views/CrmView/client.js +266 -122
  13. package/dist/views/EmailTrackingView/client.cjs +80 -69
  14. package/dist/views/EmailTrackingView/client.js +80 -70
  15. package/dist/views/ImportConversationView/client.cjs +127 -94
  16. package/dist/views/ImportConversationView/client.js +123 -94
  17. package/dist/views/LogsView/client.cjs +56 -58
  18. package/dist/views/LogsView/client.js +52 -58
  19. package/dist/views/NewTicketView/client.cjs +39 -55
  20. package/dist/views/NewTicketView/client.js +38 -55
  21. package/dist/views/PendingEmailsView/client.cjs +399 -102
  22. package/dist/views/PendingEmailsView/client.js +396 -103
  23. package/dist/views/SupportDashboardView/client.cjs +276 -137
  24. package/dist/views/SupportDashboardView/client.js +275 -137
  25. package/dist/views/TicketDetailView/client.cjs +487 -204
  26. package/dist/views/TicketDetailView/client.js +486 -204
  27. package/dist/views/TicketInboxView/client.cjs +62 -65
  28. package/dist/views/TicketInboxView/client.js +62 -66
  29. package/dist/views/TicketingSettingsView/client.cjs +10 -8
  30. package/dist/views/TicketingSettingsView/client.js +10 -8
  31. package/dist/views/TimeDashboardView/client.cjs +70 -59
  32. package/dist/views/TimeDashboardView/client.js +69 -59
  33. package/package.json +7 -3
  34. package/src/components/RichTextEditor/index.tsx +261 -0
  35. package/src/components/TicketConversation/components/CodeBlock.tsx +53 -14
  36. package/src/plugin.ts +2 -0
  37. package/src/utils/emailTemplate.ts +37 -0
  38. package/src/views/BillingView/client.tsx +362 -69
  39. package/src/views/ChatView/client.tsx +225 -140
  40. package/src/views/CrmView/client.tsx +447 -189
  41. package/src/views/EmailTrackingView/client.tsx +111 -71
  42. package/src/views/ImportConversationView/client.tsx +255 -70
  43. package/src/views/LogsView/client.tsx +85 -50
  44. package/src/views/NewTicketView/client.tsx +37 -53
  45. package/src/views/PendingEmailsView/client.tsx +512 -92
  46. package/src/views/SupportDashboardView/client.tsx +294 -134
  47. package/src/views/TicketDetailView/client.tsx +486 -213
  48. package/src/views/TicketInboxView/client.tsx +52 -61
  49. package/src/views/TicketingSettingsView/client.tsx +10 -9
  50. package/src/views/TimeDashboardView/client.tsx +184 -69
@@ -5,10 +5,12 @@ var react = require('react');
5
5
  var navigation = require('next/navigation');
6
6
  var Link = require('next/link');
7
7
  var useTranslation = require('../../components/TicketConversation/hooks/useTranslation');
8
+ var s = require('../../styles/TicketInbox.module.scss');
8
9
 
9
10
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
10
11
 
11
12
  var Link__default = /*#__PURE__*/_interopDefault(Link);
13
+ var s__default = /*#__PURE__*/_interopDefault(s);
12
14
 
13
15
  const STATUS_DOTS = {
14
16
  open: "#22c55e",
@@ -54,6 +56,14 @@ const TicketInboxClient = () => {
54
56
  if (urlTab && ["all", "open", "waiting_client", "resolved"].includes(urlTab)) return urlTab;
55
57
  return "all";
56
58
  });
59
+ react.useEffect(() => {
60
+ const urlTab = searchParams.get("tab");
61
+ if (urlTab && ["all", "open", "waiting_client", "resolved"].includes(urlTab)) {
62
+ setTab(urlTab);
63
+ } else if (!urlTab) {
64
+ setTab("all");
65
+ }
66
+ }, [searchParams]);
57
67
  const [search, setSearch] = react.useState("");
58
68
  const [sort, setSort] = react.useState("-updatedAt");
59
69
  const [counts, setCounts] = react.useState({ all: 0, open: 0, waiting: 0, resolved: 0 });
@@ -157,70 +167,54 @@ const TicketInboxClient = () => {
157
167
  { key: "waiting_client", label: t("inbox.tabs.waiting"), count: counts.waiting },
158
168
  { key: "resolved", label: t("inbox.tabs.resolved"), count: counts.resolved }
159
169
  ];
160
- const S = {
161
- page: { padding: "20px 30px", maxWidth: 1100, margin: "0 auto" },
162
- header: { display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 16 },
163
- title: { fontSize: 24, fontWeight: 700, margin: 0, color: "var(--theme-text)" },
164
- headerRight: { display: "flex", gap: 10, alignItems: "center" },
165
- searchWrap: { position: "relative", display: "flex", alignItems: "center" },
166
- searchInput: { padding: "6px 12px 6px 30px", borderRadius: 8, border: "1px solid var(--theme-elevation-200)", fontSize: 13, background: "var(--theme-elevation-0)", color: "var(--theme-text)", width: 200 },
167
- newTicketBtn: { padding: "7px 14px", borderRadius: 8, background: "#2563eb", color: "#fff", fontSize: 13, fontWeight: 600, textDecoration: "none", whiteSpace: "nowrap" },
168
- tabsRow: { display: "flex", gap: 4, marginBottom: 12, borderBottom: "1px solid var(--theme-elevation-200)", paddingBottom: 8 },
169
- tab: { padding: "6px 12px", borderRadius: 6, border: "none", background: "none", cursor: "pointer", fontSize: 13, color: "var(--theme-elevation-500)", fontWeight: 500 },
170
- tabActive: { background: "var(--theme-elevation-100)", color: "var(--theme-text)", fontWeight: 700 },
171
- sortRow: { display: "flex", alignItems: "center", marginBottom: 12 },
172
- sortSelect: { padding: "4px 10px", borderRadius: 6, border: "1px solid var(--theme-elevation-200)", fontSize: 12, background: "var(--theme-elevation-0)", color: "var(--theme-text)", cursor: "pointer" },
173
- loading: { padding: 40, textAlign: "center", color: "#94a3b8" },
174
- empty: { padding: 60, textAlign: "center", color: "#94a3b8" },
175
- list: { display: "flex", flexDirection: "column", gap: 1 },
176
- row: { display: "grid", gridTemplateColumns: "20px 10px 60px 70px 1fr 140px 80px 4px 50px 10px", gap: 8, alignItems: "center", padding: "10px 12px", borderRadius: 8, textDecoration: "none", color: "var(--theme-text)", fontSize: 13, cursor: "pointer", transition: "background 100ms", background: "var(--theme-elevation-0)" },
177
- statusDot: { width: 8, height: 8, borderRadius: "50%" },
178
- priorityBar: { width: 4, height: 20, borderRadius: 2 },
179
- unreadDot: { width: 8, height: 8, borderRadius: "50%", background: "#2563eb" },
180
- keyboardHints: { display: "flex", gap: 12, marginTop: 16, fontSize: 11, color: "var(--theme-elevation-400)" }
181
- };
182
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: S.page, children: [
183
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: S.header, children: [
184
- /* @__PURE__ */ jsxRuntime.jsx("h1", { style: S.title, children: t("inbox.title") }),
185
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: S.headerRight, children: [
186
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: S.searchWrap, children: /* @__PURE__ */ jsxRuntime.jsx(
187
- "input",
188
- {
189
- type: "text",
190
- style: S.searchInput,
191
- placeholder: t("inbox.searchPlaceholder"),
192
- value: search,
193
- onChange: (e) => setSearch(e.target.value)
194
- }
195
- ) }),
196
- /* @__PURE__ */ jsxRuntime.jsx(Link__default.default, { href: "/admin/support/new-ticket", style: S.newTicketBtn, children: t("inbox.newTicketBtn") })
170
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: s__default.default.page, children: [
171
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: s__default.default.header, children: [
172
+ /* @__PURE__ */ jsxRuntime.jsx("h1", { className: s__default.default.title, children: t("inbox.title") }),
173
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: s__default.default.headerRight, children: [
174
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: s__default.default.searchWrap, children: [
175
+ /* @__PURE__ */ jsxRuntime.jsxs("svg", { className: s__default.default.searchIcon, width: "14", height: "14", viewBox: "0 0 16 16", fill: "none", children: [
176
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "7", cy: "7", r: "5", stroke: "currentColor", strokeWidth: "1.5" }),
177
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M11 11l3.5 3.5", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" })
178
+ ] }),
179
+ /* @__PURE__ */ jsxRuntime.jsx(
180
+ "input",
181
+ {
182
+ type: "text",
183
+ className: s__default.default.searchInput,
184
+ placeholder: t("inbox.searchPlaceholder"),
185
+ value: search,
186
+ onChange: (e) => setSearch(e.target.value)
187
+ }
188
+ ),
189
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: s__default.default.searchHint, children: "\u2318K" })
190
+ ] }),
191
+ /* @__PURE__ */ jsxRuntime.jsx(Link__default.default, { href: "/admin/support/new-ticket", className: s__default.default.newTicketBtn, children: t("inbox.newTicketBtn") })
197
192
  ] })
198
193
  ] }),
199
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: S.tabsRow, children: tabs.map((tb) => /* @__PURE__ */ jsxRuntime.jsxs(
194
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: s__default.default.tabs, children: tabs.map((tk) => /* @__PURE__ */ jsxRuntime.jsxs(
200
195
  "button",
201
196
  {
202
- style: { ...S.tab, ...tab === tb.key ? S.tabActive : {} },
197
+ className: `${s__default.default.tab} ${tab === tk.key ? s__default.default.tabActive : ""}`,
203
198
  onClick: () => {
204
- setTab(tb.key);
199
+ setTab(tk.key);
205
200
  setSelectedIdx(-1);
206
201
  },
207
202
  children: [
208
- tb.label,
209
- " ",
210
- /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { opacity: 0.6 }, children: [
203
+ tk.label,
204
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: s__default.default.tabCount, children: [
211
205
  "(",
212
- tb.count,
206
+ tk.count,
213
207
  ")"
214
208
  ] })
215
209
  ]
216
210
  },
217
- tb.key
211
+ tk.key
218
212
  )) }),
219
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: S.sortRow, children: checkedIds.size > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", gap: 8, alignItems: "center", flex: 1 }, children: [
213
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: s__default.default.sortRow, children: checkedIds.size > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", gap: 8, alignItems: "center", flex: 1 }, children: [
220
214
  /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: 13, fontWeight: 600, color: "var(--theme-text)" }, children: checkedIds.size > 1 ? t("inbox.selectedPlural", { count: String(checkedIds.size) }) : t("inbox.selected", { count: String(checkedIds.size) }) }),
221
- /* @__PURE__ */ jsxRuntime.jsx("button", { style: S.sortSelect, onClick: () => handleBulkAction("close"), disabled: bulkProcessing, children: t("inbox.closeAction") }),
222
- /* @__PURE__ */ jsxRuntime.jsx("button", { style: S.sortSelect, onClick: () => handleBulkAction("reopen"), disabled: bulkProcessing, children: t("inbox.reopenAction") }),
223
- /* @__PURE__ */ jsxRuntime.jsxs("select", { style: S.sortSelect, value: bulkAction, onChange: (e) => {
215
+ /* @__PURE__ */ jsxRuntime.jsx("button", { className: s__default.default.sortSelect, onClick: () => handleBulkAction("close"), disabled: bulkProcessing, children: t("inbox.closeAction") }),
216
+ /* @__PURE__ */ jsxRuntime.jsx("button", { className: s__default.default.sortSelect, onClick: () => handleBulkAction("reopen"), disabled: bulkProcessing, children: t("inbox.reopenAction") }),
217
+ /* @__PURE__ */ jsxRuntime.jsxs("select", { className: s__default.default.sortSelect, value: bulkAction, onChange: (e) => {
224
218
  if (e.target.value) handleBulkAction(e.target.value);
225
219
  setBulkAction("");
226
220
  }, children: [
@@ -228,25 +222,28 @@ const TicketInboxClient = () => {
228
222
  /* @__PURE__ */ jsxRuntime.jsx("option", { value: "set_priority", children: t("inbox.changePriority") }),
229
223
  /* @__PURE__ */ jsxRuntime.jsx("option", { value: "delete", children: t("inbox.deleteAction") })
230
224
  ] }),
231
- /* @__PURE__ */ jsxRuntime.jsx("button", { style: { ...S.sortSelect, marginLeft: "auto" }, onClick: () => setCheckedIds(/* @__PURE__ */ new Set()), children: t("inbox.deselect") })
232
- ] }) : /* @__PURE__ */ jsxRuntime.jsxs("select", { style: S.sortSelect, value: sort, onChange: (e) => setSort(e.target.value), children: [
225
+ /* @__PURE__ */ jsxRuntime.jsx("button", { className: s__default.default.sortSelect, onClick: () => setCheckedIds(/* @__PURE__ */ new Set()), style: { marginLeft: "auto" }, children: t("inbox.deselect") })
226
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs("select", { className: s__default.default.sortSelect, value: sort, onChange: (e) => setSort(e.target.value), children: [
233
227
  /* @__PURE__ */ jsxRuntime.jsx("option", { value: "-updatedAt", children: t("inbox.sort.newest") }),
234
228
  /* @__PURE__ */ jsxRuntime.jsx("option", { value: "updatedAt", children: t("inbox.sort.oldest") }),
235
229
  /* @__PURE__ */ jsxRuntime.jsx("option", { value: "-createdAt", children: t("inbox.sort.created") }),
236
230
  /* @__PURE__ */ jsxRuntime.jsx("option", { value: "priority", children: t("inbox.sort.priority") })
237
231
  ] }) }),
238
- loading ? /* @__PURE__ */ jsxRuntime.jsx("div", { style: S.loading, children: t("common.loading") }) : tickets.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { style: S.empty, children: t("inbox.empty") }) : /* @__PURE__ */ jsxRuntime.jsx("div", { style: S.list, children: tickets.map((tk, idx) => {
232
+ loading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: s__default.default.loading, children: t("common.loading") }) : tickets.length === 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: s__default.default.empty, children: [
233
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: s__default.default.emptyIcon, children: "--" }),
234
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: s__default.default.emptyText, children: t("inbox.empty") })
235
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: s__default.default.list, children: tickets.map((tk, idx) => {
239
236
  const clientObj = typeof tk.client === "object" ? tk.client : null;
240
237
  const clientName = clientObj ? `${clientObj.firstName || ""} ${clientObj.lastName || ""}`.trim() : "";
241
238
  const clientCompany = clientObj?.company || "";
242
- const displayClient = clientName ? `${clientName}${clientCompany ? `, ${clientCompany}` : ""}` : "--";
239
+ const displayClient = clientName ? `${clientName}${clientCompany ? `, ${clientCompany}` : ""}` : "\u2014";
243
240
  const isUnread = tk.lastClientMessageAt && (!tk.lastAdminReadAt || new Date(tk.lastClientMessageAt) > new Date(tk.lastAdminReadAt));
244
241
  const priorityColor = PRIORITY_COLORS[tk.priority] || "transparent";
245
242
  return /* @__PURE__ */ jsxRuntime.jsxs(
246
243
  "a",
247
244
  {
248
245
  href: `/admin/support/ticket?id=${tk.id}`,
249
- style: { ...S.row, ...idx === selectedIdx ? { background: "var(--theme-elevation-100)" } : {} },
246
+ className: `${s__default.default.row} ${idx === selectedIdx ? s__default.default.rowSelected : ""}`,
250
247
  onClick: (e) => {
251
248
  e.preventDefault();
252
249
  window.location.href = `/admin/support/ticket?id=${tk.id}`;
@@ -262,25 +259,25 @@ const TicketInboxClient = () => {
262
259
  style: { width: 14, height: 14, cursor: "pointer", accentColor: "#2563eb" }
263
260
  }
264
261
  ),
265
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: { ...S.statusDot, backgroundColor: STATUS_DOTS[tk.status] || "#94a3b8" } }),
266
- /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: 11, color: "var(--theme-elevation-500)" }, children: STATUS_LABEL_KEYS[tk.status] ? t(STATUS_LABEL_KEYS[tk.status]) : tk.status }),
267
- /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontWeight: 600, fontSize: 12, color: "var(--theme-elevation-400)" }, children: tk.ticketNumber }),
268
- /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontWeight: 500 }, children: tk.subject }),
269
- /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: 12, color: "var(--theme-elevation-500)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }, children: displayClient }),
270
- tk.category ? /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { fontSize: 11, color: "var(--theme-elevation-400)" }, children: [
262
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: s__default.default.statusDot, style: { backgroundColor: STATUS_DOTS[tk.status] || "#94a3b8" } }),
263
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: s__default.default.statusText, children: t(STATUS_LABEL_KEYS[tk.status] || "ticket.status.open") }),
264
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: s__default.default.ticketNum, children: tk.ticketNumber }),
265
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: s__default.default.subject, children: tk.subject }),
266
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: s__default.default.client, children: displayClient }),
267
+ tk.category ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: s__default.default.categoryChip, children: [
271
268
  "[",
272
- CATEGORY_LABEL_KEYS[tk.category] ? t(CATEGORY_LABEL_KEYS[tk.category]) : tk.category,
269
+ t(CATEGORY_LABEL_KEYS[tk.category] || "ticket.category.bug"),
273
270
  "]"
274
271
  ] }) : /* @__PURE__ */ jsxRuntime.jsx("span", {}),
275
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: { ...S.priorityBar, backgroundColor: priorityColor } }),
276
- /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: 11, color: "var(--theme-elevation-400)", textAlign: "right" }, children: relativeTime(tk.updatedAt) }),
277
- isUnread ? /* @__PURE__ */ jsxRuntime.jsx("div", { style: S.unreadDot }) : /* @__PURE__ */ jsxRuntime.jsx("span", {})
272
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: s__default.default.priorityBar, style: { backgroundColor: priorityColor } }),
273
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: s__default.default.timeAgo, children: relativeTime(tk.updatedAt) }),
274
+ isUnread ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: s__default.default.unreadDot }) : /* @__PURE__ */ jsxRuntime.jsx("span", {})
278
275
  ]
279
276
  },
280
277
  tk.id
281
278
  );
282
279
  }) }),
283
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: S.keyboardHints, children: [
280
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: s__default.default.keyboardHints, children: [
284
281
  /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
285
282
  /* @__PURE__ */ jsxRuntime.jsx("kbd", { children: "\u2191" }),
286
283
  /* @__PURE__ */ jsxRuntime.jsx("kbd", { children: "\u2193" }),
@@ -1,9 +1,10 @@
1
1
  "use client";
2
2
  import { jsxs, jsx } from 'react/jsx-runtime';
3
- import { useState, useCallback, useEffect } from 'react';
3
+ import { useState, useEffect, useCallback } from 'react';
4
4
  import { useSearchParams } from 'next/navigation';
5
5
  import Link from 'next/link';
6
6
  import { useTranslation } from '../../components/TicketConversation/hooks/useTranslation.js';
7
+ import s from '../../styles/TicketInbox.module.scss';
7
8
 
8
9
  const STATUS_DOTS = {
9
10
  open: "#22c55e",
@@ -49,6 +50,14 @@ const TicketInboxClient = () => {
49
50
  if (urlTab && ["all", "open", "waiting_client", "resolved"].includes(urlTab)) return urlTab;
50
51
  return "all";
51
52
  });
53
+ useEffect(() => {
54
+ const urlTab = searchParams.get("tab");
55
+ if (urlTab && ["all", "open", "waiting_client", "resolved"].includes(urlTab)) {
56
+ setTab(urlTab);
57
+ } else if (!urlTab) {
58
+ setTab("all");
59
+ }
60
+ }, [searchParams]);
52
61
  const [search, setSearch] = useState("");
53
62
  const [sort, setSort] = useState("-updatedAt");
54
63
  const [counts, setCounts] = useState({ all: 0, open: 0, waiting: 0, resolved: 0 });
@@ -152,70 +161,54 @@ const TicketInboxClient = () => {
152
161
  { key: "waiting_client", label: t("inbox.tabs.waiting"), count: counts.waiting },
153
162
  { key: "resolved", label: t("inbox.tabs.resolved"), count: counts.resolved }
154
163
  ];
155
- const S = {
156
- page: { padding: "20px 30px", maxWidth: 1100, margin: "0 auto" },
157
- header: { display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 16 },
158
- title: { fontSize: 24, fontWeight: 700, margin: 0, color: "var(--theme-text)" },
159
- headerRight: { display: "flex", gap: 10, alignItems: "center" },
160
- searchWrap: { position: "relative", display: "flex", alignItems: "center" },
161
- searchInput: { padding: "6px 12px 6px 30px", borderRadius: 8, border: "1px solid var(--theme-elevation-200)", fontSize: 13, background: "var(--theme-elevation-0)", color: "var(--theme-text)", width: 200 },
162
- newTicketBtn: { padding: "7px 14px", borderRadius: 8, background: "#2563eb", color: "#fff", fontSize: 13, fontWeight: 600, textDecoration: "none", whiteSpace: "nowrap" },
163
- tabsRow: { display: "flex", gap: 4, marginBottom: 12, borderBottom: "1px solid var(--theme-elevation-200)", paddingBottom: 8 },
164
- tab: { padding: "6px 12px", borderRadius: 6, border: "none", background: "none", cursor: "pointer", fontSize: 13, color: "var(--theme-elevation-500)", fontWeight: 500 },
165
- tabActive: { background: "var(--theme-elevation-100)", color: "var(--theme-text)", fontWeight: 700 },
166
- sortRow: { display: "flex", alignItems: "center", marginBottom: 12 },
167
- sortSelect: { padding: "4px 10px", borderRadius: 6, border: "1px solid var(--theme-elevation-200)", fontSize: 12, background: "var(--theme-elevation-0)", color: "var(--theme-text)", cursor: "pointer" },
168
- loading: { padding: 40, textAlign: "center", color: "#94a3b8" },
169
- empty: { padding: 60, textAlign: "center", color: "#94a3b8" },
170
- list: { display: "flex", flexDirection: "column", gap: 1 },
171
- row: { display: "grid", gridTemplateColumns: "20px 10px 60px 70px 1fr 140px 80px 4px 50px 10px", gap: 8, alignItems: "center", padding: "10px 12px", borderRadius: 8, textDecoration: "none", color: "var(--theme-text)", fontSize: 13, cursor: "pointer", transition: "background 100ms", background: "var(--theme-elevation-0)" },
172
- statusDot: { width: 8, height: 8, borderRadius: "50%" },
173
- priorityBar: { width: 4, height: 20, borderRadius: 2 },
174
- unreadDot: { width: 8, height: 8, borderRadius: "50%", background: "#2563eb" },
175
- keyboardHints: { display: "flex", gap: 12, marginTop: 16, fontSize: 11, color: "var(--theme-elevation-400)" }
176
- };
177
- return /* @__PURE__ */ jsxs("div", { style: S.page, children: [
178
- /* @__PURE__ */ jsxs("div", { style: S.header, children: [
179
- /* @__PURE__ */ jsx("h1", { style: S.title, children: t("inbox.title") }),
180
- /* @__PURE__ */ jsxs("div", { style: S.headerRight, children: [
181
- /* @__PURE__ */ jsx("div", { style: S.searchWrap, children: /* @__PURE__ */ jsx(
182
- "input",
183
- {
184
- type: "text",
185
- style: S.searchInput,
186
- placeholder: t("inbox.searchPlaceholder"),
187
- value: search,
188
- onChange: (e) => setSearch(e.target.value)
189
- }
190
- ) }),
191
- /* @__PURE__ */ jsx(Link, { href: "/admin/support/new-ticket", style: S.newTicketBtn, children: t("inbox.newTicketBtn") })
164
+ return /* @__PURE__ */ jsxs("div", { className: s.page, children: [
165
+ /* @__PURE__ */ jsxs("div", { className: s.header, children: [
166
+ /* @__PURE__ */ jsx("h1", { className: s.title, children: t("inbox.title") }),
167
+ /* @__PURE__ */ jsxs("div", { className: s.headerRight, children: [
168
+ /* @__PURE__ */ jsxs("div", { className: s.searchWrap, children: [
169
+ /* @__PURE__ */ jsxs("svg", { className: s.searchIcon, width: "14", height: "14", viewBox: "0 0 16 16", fill: "none", children: [
170
+ /* @__PURE__ */ jsx("circle", { cx: "7", cy: "7", r: "5", stroke: "currentColor", strokeWidth: "1.5" }),
171
+ /* @__PURE__ */ jsx("path", { d: "M11 11l3.5 3.5", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" })
172
+ ] }),
173
+ /* @__PURE__ */ jsx(
174
+ "input",
175
+ {
176
+ type: "text",
177
+ className: s.searchInput,
178
+ placeholder: t("inbox.searchPlaceholder"),
179
+ value: search,
180
+ onChange: (e) => setSearch(e.target.value)
181
+ }
182
+ ),
183
+ /* @__PURE__ */ jsx("span", { className: s.searchHint, children: "\u2318K" })
184
+ ] }),
185
+ /* @__PURE__ */ jsx(Link, { href: "/admin/support/new-ticket", className: s.newTicketBtn, children: t("inbox.newTicketBtn") })
192
186
  ] })
193
187
  ] }),
194
- /* @__PURE__ */ jsx("div", { style: S.tabsRow, children: tabs.map((tb) => /* @__PURE__ */ jsxs(
188
+ /* @__PURE__ */ jsx("div", { className: s.tabs, children: tabs.map((tk) => /* @__PURE__ */ jsxs(
195
189
  "button",
196
190
  {
197
- style: { ...S.tab, ...tab === tb.key ? S.tabActive : {} },
191
+ className: `${s.tab} ${tab === tk.key ? s.tabActive : ""}`,
198
192
  onClick: () => {
199
- setTab(tb.key);
193
+ setTab(tk.key);
200
194
  setSelectedIdx(-1);
201
195
  },
202
196
  children: [
203
- tb.label,
204
- " ",
205
- /* @__PURE__ */ jsxs("span", { style: { opacity: 0.6 }, children: [
197
+ tk.label,
198
+ /* @__PURE__ */ jsxs("span", { className: s.tabCount, children: [
206
199
  "(",
207
- tb.count,
200
+ tk.count,
208
201
  ")"
209
202
  ] })
210
203
  ]
211
204
  },
212
- tb.key
205
+ tk.key
213
206
  )) }),
214
- /* @__PURE__ */ jsx("div", { style: S.sortRow, children: checkedIds.size > 0 ? /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: 8, alignItems: "center", flex: 1 }, children: [
207
+ /* @__PURE__ */ jsx("div", { className: s.sortRow, children: checkedIds.size > 0 ? /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: 8, alignItems: "center", flex: 1 }, children: [
215
208
  /* @__PURE__ */ jsx("span", { style: { fontSize: 13, fontWeight: 600, color: "var(--theme-text)" }, children: checkedIds.size > 1 ? t("inbox.selectedPlural", { count: String(checkedIds.size) }) : t("inbox.selected", { count: String(checkedIds.size) }) }),
216
- /* @__PURE__ */ jsx("button", { style: S.sortSelect, onClick: () => handleBulkAction("close"), disabled: bulkProcessing, children: t("inbox.closeAction") }),
217
- /* @__PURE__ */ jsx("button", { style: S.sortSelect, onClick: () => handleBulkAction("reopen"), disabled: bulkProcessing, children: t("inbox.reopenAction") }),
218
- /* @__PURE__ */ jsxs("select", { style: S.sortSelect, value: bulkAction, onChange: (e) => {
209
+ /* @__PURE__ */ jsx("button", { className: s.sortSelect, onClick: () => handleBulkAction("close"), disabled: bulkProcessing, children: t("inbox.closeAction") }),
210
+ /* @__PURE__ */ jsx("button", { className: s.sortSelect, onClick: () => handleBulkAction("reopen"), disabled: bulkProcessing, children: t("inbox.reopenAction") }),
211
+ /* @__PURE__ */ jsxs("select", { className: s.sortSelect, value: bulkAction, onChange: (e) => {
219
212
  if (e.target.value) handleBulkAction(e.target.value);
220
213
  setBulkAction("");
221
214
  }, children: [
@@ -223,25 +216,28 @@ const TicketInboxClient = () => {
223
216
  /* @__PURE__ */ jsx("option", { value: "set_priority", children: t("inbox.changePriority") }),
224
217
  /* @__PURE__ */ jsx("option", { value: "delete", children: t("inbox.deleteAction") })
225
218
  ] }),
226
- /* @__PURE__ */ jsx("button", { style: { ...S.sortSelect, marginLeft: "auto" }, onClick: () => setCheckedIds(/* @__PURE__ */ new Set()), children: t("inbox.deselect") })
227
- ] }) : /* @__PURE__ */ jsxs("select", { style: S.sortSelect, value: sort, onChange: (e) => setSort(e.target.value), children: [
219
+ /* @__PURE__ */ jsx("button", { className: s.sortSelect, onClick: () => setCheckedIds(/* @__PURE__ */ new Set()), style: { marginLeft: "auto" }, children: t("inbox.deselect") })
220
+ ] }) : /* @__PURE__ */ jsxs("select", { className: s.sortSelect, value: sort, onChange: (e) => setSort(e.target.value), children: [
228
221
  /* @__PURE__ */ jsx("option", { value: "-updatedAt", children: t("inbox.sort.newest") }),
229
222
  /* @__PURE__ */ jsx("option", { value: "updatedAt", children: t("inbox.sort.oldest") }),
230
223
  /* @__PURE__ */ jsx("option", { value: "-createdAt", children: t("inbox.sort.created") }),
231
224
  /* @__PURE__ */ jsx("option", { value: "priority", children: t("inbox.sort.priority") })
232
225
  ] }) }),
233
- loading ? /* @__PURE__ */ jsx("div", { style: S.loading, children: t("common.loading") }) : tickets.length === 0 ? /* @__PURE__ */ jsx("div", { style: S.empty, children: t("inbox.empty") }) : /* @__PURE__ */ jsx("div", { style: S.list, children: tickets.map((tk, idx) => {
226
+ loading ? /* @__PURE__ */ jsx("div", { className: s.loading, children: t("common.loading") }) : tickets.length === 0 ? /* @__PURE__ */ jsxs("div", { className: s.empty, children: [
227
+ /* @__PURE__ */ jsx("div", { className: s.emptyIcon, children: "--" }),
228
+ /* @__PURE__ */ jsx("div", { className: s.emptyText, children: t("inbox.empty") })
229
+ ] }) : /* @__PURE__ */ jsx("div", { className: s.list, children: tickets.map((tk, idx) => {
234
230
  const clientObj = typeof tk.client === "object" ? tk.client : null;
235
231
  const clientName = clientObj ? `${clientObj.firstName || ""} ${clientObj.lastName || ""}`.trim() : "";
236
232
  const clientCompany = clientObj?.company || "";
237
- const displayClient = clientName ? `${clientName}${clientCompany ? `, ${clientCompany}` : ""}` : "--";
233
+ const displayClient = clientName ? `${clientName}${clientCompany ? `, ${clientCompany}` : ""}` : "\u2014";
238
234
  const isUnread = tk.lastClientMessageAt && (!tk.lastAdminReadAt || new Date(tk.lastClientMessageAt) > new Date(tk.lastAdminReadAt));
239
235
  const priorityColor = PRIORITY_COLORS[tk.priority] || "transparent";
240
236
  return /* @__PURE__ */ jsxs(
241
237
  "a",
242
238
  {
243
239
  href: `/admin/support/ticket?id=${tk.id}`,
244
- style: { ...S.row, ...idx === selectedIdx ? { background: "var(--theme-elevation-100)" } : {} },
240
+ className: `${s.row} ${idx === selectedIdx ? s.rowSelected : ""}`,
245
241
  onClick: (e) => {
246
242
  e.preventDefault();
247
243
  window.location.href = `/admin/support/ticket?id=${tk.id}`;
@@ -257,25 +253,25 @@ const TicketInboxClient = () => {
257
253
  style: { width: 14, height: 14, cursor: "pointer", accentColor: "#2563eb" }
258
254
  }
259
255
  ),
260
- /* @__PURE__ */ jsx("div", { style: { ...S.statusDot, backgroundColor: STATUS_DOTS[tk.status] || "#94a3b8" } }),
261
- /* @__PURE__ */ jsx("span", { style: { fontSize: 11, color: "var(--theme-elevation-500)" }, children: STATUS_LABEL_KEYS[tk.status] ? t(STATUS_LABEL_KEYS[tk.status]) : tk.status }),
262
- /* @__PURE__ */ jsx("span", { style: { fontWeight: 600, fontSize: 12, color: "var(--theme-elevation-400)" }, children: tk.ticketNumber }),
263
- /* @__PURE__ */ jsx("span", { style: { fontWeight: 500 }, children: tk.subject }),
264
- /* @__PURE__ */ jsx("span", { style: { fontSize: 12, color: "var(--theme-elevation-500)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }, children: displayClient }),
265
- tk.category ? /* @__PURE__ */ jsxs("span", { style: { fontSize: 11, color: "var(--theme-elevation-400)" }, children: [
256
+ /* @__PURE__ */ jsx("div", { className: s.statusDot, style: { backgroundColor: STATUS_DOTS[tk.status] || "#94a3b8" } }),
257
+ /* @__PURE__ */ jsx("span", { className: s.statusText, children: t(STATUS_LABEL_KEYS[tk.status] || "ticket.status.open") }),
258
+ /* @__PURE__ */ jsx("span", { className: s.ticketNum, children: tk.ticketNumber }),
259
+ /* @__PURE__ */ jsx("span", { className: s.subject, children: tk.subject }),
260
+ /* @__PURE__ */ jsx("span", { className: s.client, children: displayClient }),
261
+ tk.category ? /* @__PURE__ */ jsxs("span", { className: s.categoryChip, children: [
266
262
  "[",
267
- CATEGORY_LABEL_KEYS[tk.category] ? t(CATEGORY_LABEL_KEYS[tk.category]) : tk.category,
263
+ t(CATEGORY_LABEL_KEYS[tk.category] || "ticket.category.bug"),
268
264
  "]"
269
265
  ] }) : /* @__PURE__ */ jsx("span", {}),
270
- /* @__PURE__ */ jsx("div", { style: { ...S.priorityBar, backgroundColor: priorityColor } }),
271
- /* @__PURE__ */ jsx("span", { style: { fontSize: 11, color: "var(--theme-elevation-400)", textAlign: "right" }, children: relativeTime(tk.updatedAt) }),
272
- isUnread ? /* @__PURE__ */ jsx("div", { style: S.unreadDot }) : /* @__PURE__ */ jsx("span", {})
266
+ /* @__PURE__ */ jsx("div", { className: s.priorityBar, style: { backgroundColor: priorityColor } }),
267
+ /* @__PURE__ */ jsx("span", { className: s.timeAgo, children: relativeTime(tk.updatedAt) }),
268
+ isUnread ? /* @__PURE__ */ jsx("div", { className: s.unreadDot }) : /* @__PURE__ */ jsx("span", {})
273
269
  ]
274
270
  },
275
271
  tk.id
276
272
  );
277
273
  }) }),
278
- /* @__PURE__ */ jsxs("div", { style: S.keyboardHints, children: [
274
+ /* @__PURE__ */ jsxs("div", { className: s.keyboardHints, children: [
279
275
  /* @__PURE__ */ jsxs("span", { children: [
280
276
  /* @__PURE__ */ jsx("kbd", { children: "\u2191" }),
281
277
  /* @__PURE__ */ jsx("kbd", { children: "\u2193" }),
@@ -6,7 +6,8 @@ var lucideReact = require('lucide-react');
6
6
  var adminTokens = require('../shared/adminTokens');
7
7
  var AdminViewHeader = require('../shared/AdminViewHeader');
8
8
  var config = require('../../components/TicketConversation/config');
9
- var ts = require('./TicketingSettings.module.scss');
9
+ var useTranslation = require('../../components/TicketConversation/hooks/useTranslation');
10
+ var ts = require('../../styles/TicketingSettings.module.scss');
10
11
 
11
12
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
12
13
 
@@ -203,6 +204,7 @@ const FieldRow = ({ label, description, children }) => /* @__PURE__ */ jsxRuntim
203
204
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: ts__default.default.fieldContent, children })
204
205
  ] });
205
206
  const TicketingSettingsClient = () => {
207
+ const { t } = useTranslation.useTranslation();
206
208
  const [features, setFeatures] = react.useState(() => config.getFeatures());
207
209
  const [settings, setSettings] = react.useState(DEFAULT_SETTINGS);
208
210
  const [signature, setSignature] = react.useState("");
@@ -276,27 +278,27 @@ const TicketingSettingsClient = () => {
276
278
  AdminViewHeader.AdminViewHeader,
277
279
  {
278
280
  icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Settings, { size: 24 }),
279
- title: "Configuration du module Support",
280
- subtitle: `${enabledCount}/${totalCount} fonctionnalites activees`,
281
+ title: t("settingsView.configTitle"),
282
+ subtitle: t("settings.subtitle", { enabled: String(enabledCount), total: String(totalCount) }),
281
283
  actions: /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", gap: 8 }, children: [
282
- /* @__PURE__ */ jsxRuntime.jsx("button", { onClick: handleReset, style: adminTokens.btnStyle("var(--theme-elevation-400)", { small: true }), children: "Reinitialiser" }),
284
+ /* @__PURE__ */ jsxRuntime.jsx("button", { onClick: handleReset, style: adminTokens.btnStyle("var(--theme-elevation-400)", { small: true }), children: t("settingsView.reset") }),
283
285
  /* @__PURE__ */ jsxRuntime.jsx(
284
286
  "button",
285
287
  {
286
288
  onClick: handleSave,
287
289
  disabled: saving,
288
290
  style: adminTokens.btnStyle(saved ? adminTokens.V.green : adminTokens.V.blue, { small: true }),
289
- children: saving ? "..." : saved ? "\u2713 Sauvegarde" : "Sauvegarder"
291
+ children: saving ? "..." : saved ? t("settingsView.saved") : t("common.save")
290
292
  }
291
293
  )
292
294
  ] })
293
295
  }
294
296
  ),
295
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: ts__default.default.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)." }),
297
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: ts__default.default.intro, children: t("settingsView.intro") }),
296
298
  /* @__PURE__ */ jsxRuntime.jsxs(
297
299
  CollapsibleSection,
298
300
  {
299
- title: "Fonctionnalit\xE9s",
301
+ title: t("settingsView.features"),
300
302
  icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Settings, { size: 16 }),
301
303
  color: adminTokens.V.blue,
302
304
  badge: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: ts__default.default.badge, style: { backgroundColor: "#dbeafe", color: "#1e40af" }, children: [
@@ -305,7 +307,7 @@ const TicketingSettingsClient = () => {
305
307
  totalCount
306
308
  ] }),
307
309
  children: [
308
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: ts__default.default.sectionDescription, children: "Activez ou desactivez les fonctionnalites du module. Les fonctionnalites desactivees sont completement masquees de l'interface." }),
310
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: ts__default.default.sectionDescription, children: t("settingsView.featuresDescription") }),
309
311
  CATEGORIES.map((cat) => {
310
312
  const categoryFeatures = FEATURE_LIST.filter((f) => f.category === cat.key);
311
313
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ts__default.default.categoryGroup, children: [
@@ -5,7 +5,8 @@ import { Settings, Mail, Bot, Clock, Timer, Globe, FileSignature } from 'lucide-
5
5
  import { V, btnStyle } from '../shared/adminTokens.js';
6
6
  import { AdminViewHeader } from '../shared/AdminViewHeader.js';
7
7
  import { getFeatures, saveFeatures, DEFAULT_FEATURES } from '../../components/TicketConversation/config.js';
8
- import ts from './TicketingSettings.module.scss';
8
+ import { useTranslation } from '../../components/TicketConversation/hooks/useTranslation.js';
9
+ import ts from '../../styles/TicketingSettings.module.scss';
9
10
 
10
11
  const DEFAULT_SETTINGS = {
11
12
  email: {
@@ -198,6 +199,7 @@ const FieldRow = ({ label, description, children }) => /* @__PURE__ */ jsxs("div
198
199
  /* @__PURE__ */ jsx("div", { className: ts.fieldContent, children })
199
200
  ] });
200
201
  const TicketingSettingsClient = () => {
202
+ const { t } = useTranslation();
201
203
  const [features, setFeatures] = useState(() => getFeatures());
202
204
  const [settings, setSettings] = useState(DEFAULT_SETTINGS);
203
205
  const [signature, setSignature] = useState("");
@@ -271,27 +273,27 @@ const TicketingSettingsClient = () => {
271
273
  AdminViewHeader,
272
274
  {
273
275
  icon: /* @__PURE__ */ jsx(Settings, { size: 24 }),
274
- title: "Configuration du module Support",
275
- subtitle: `${enabledCount}/${totalCount} fonctionnalites activees`,
276
+ title: t("settingsView.configTitle"),
277
+ subtitle: t("settings.subtitle", { enabled: String(enabledCount), total: String(totalCount) }),
276
278
  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" }),
279
+ /* @__PURE__ */ jsx("button", { onClick: handleReset, style: btnStyle("var(--theme-elevation-400)", { small: true }), children: t("settingsView.reset") }),
278
280
  /* @__PURE__ */ jsx(
279
281
  "button",
280
282
  {
281
283
  onClick: handleSave,
282
284
  disabled: saving,
283
285
  style: btnStyle(saved ? V.green : V.blue, { small: true }),
284
- children: saving ? "..." : saved ? "\u2713 Sauvegarde" : "Sauvegarder"
286
+ children: saving ? "..." : saved ? t("settingsView.saved") : t("common.save")
285
287
  }
286
288
  )
287
289
  ] })
288
290
  }
289
291
  ),
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)." }),
292
+ /* @__PURE__ */ jsx("p", { className: ts.intro, children: t("settingsView.intro") }),
291
293
  /* @__PURE__ */ jsxs(
292
294
  CollapsibleSection,
293
295
  {
294
- title: "Fonctionnalit\xE9s",
296
+ title: t("settingsView.features"),
295
297
  icon: /* @__PURE__ */ jsx(Settings, { size: 16 }),
296
298
  color: V.blue,
297
299
  badge: /* @__PURE__ */ jsxs("span", { className: ts.badge, style: { backgroundColor: "#dbeafe", color: "#1e40af" }, children: [
@@ -300,7 +302,7 @@ const TicketingSettingsClient = () => {
300
302
  totalCount
301
303
  ] }),
302
304
  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." }),
305
+ /* @__PURE__ */ jsx("p", { className: ts.sectionDescription, children: t("settingsView.featuresDescription") }),
304
306
  CATEGORIES.map((cat) => {
305
307
  const categoryFeatures = FEATURE_LIST.filter((f) => f.category === cat.key);
306
308
  return /* @__PURE__ */ jsxs("div", { className: ts.categoryGroup, children: [