@consilioweb/payload-support 0.16.0 → 1.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 (193) hide show
  1. package/README.md +347 -435
  2. package/dist/components/TicketConversation/RewriteDropdown.cjs +98 -0
  3. package/dist/components/TicketConversation/RewriteDropdown.js +93 -0
  4. package/dist/components/TicketConversation/SkeletonText.cjs +21 -0
  5. package/dist/components/TicketConversation/SkeletonText.js +20 -0
  6. package/dist/components/TicketConversation/constants.cjs +27 -0
  7. package/dist/components/TicketConversation/constants.js +26 -1
  8. package/dist/components/TicketConversation/hooks/useDocumentIdFromUrl.cjs +20 -0
  9. package/dist/components/TicketConversation/hooks/useDocumentIdFromUrl.js +19 -0
  10. package/dist/components/TicketConversation/index.cjs +10 -147
  11. package/dist/components/TicketConversation/index.js +4 -141
  12. package/dist/index.cjs +1604 -671
  13. package/dist/index.d.cts +3 -0
  14. package/dist/index.d.ts +3 -0
  15. package/dist/index.js +1602 -671
  16. package/dist/views/BillingView/client.cjs +40 -54
  17. package/dist/views/BillingView/client.js +40 -54
  18. package/dist/views/ChatView/client.cjs +4 -3
  19. package/dist/views/ChatView/client.js +4 -3
  20. package/dist/views/CrmView/client.cjs +7 -7
  21. package/dist/views/CrmView/client.js +7 -7
  22. package/dist/views/EmailTrackingView/client.cjs +6 -5
  23. package/dist/views/EmailTrackingView/client.js +6 -5
  24. package/dist/views/ImportConversationView/client.cjs +4 -4
  25. package/dist/views/ImportConversationView/client.js +4 -4
  26. package/dist/views/LogsView/client.cjs +3 -2
  27. package/dist/views/LogsView/client.js +3 -2
  28. package/dist/views/NewTicketView/client.cjs +1 -1
  29. package/dist/views/NewTicketView/client.js +1 -1
  30. package/dist/views/PendingEmailsView/client.cjs +7 -6
  31. package/dist/views/PendingEmailsView/client.js +7 -6
  32. package/dist/views/SupportDashboardView/client.cjs +19 -22
  33. package/dist/views/SupportDashboardView/client.js +19 -22
  34. package/dist/views/TicketDetailView/NextActionItem.cjs +40 -0
  35. package/dist/views/TicketDetailView/NextActionItem.js +34 -0
  36. package/dist/views/TicketDetailView/RewriteDropdown.cjs +80 -0
  37. package/dist/views/TicketDetailView/RewriteDropdown.js +78 -0
  38. package/dist/views/TicketDetailView/client.cjs +59 -190
  39. package/dist/views/TicketDetailView/client.js +52 -183
  40. package/dist/views/TicketDetailView/constants.cjs +20 -0
  41. package/dist/views/TicketDetailView/constants.js +16 -0
  42. package/dist/views/TicketDetailView/helpers.cjs +23 -0
  43. package/dist/views/TicketDetailView/helpers.js +20 -0
  44. package/dist/views/TicketDetailView/types.cjs +2 -0
  45. package/dist/views/TicketDetailView/types.js +1 -0
  46. package/dist/views/TicketInboxView/client.cjs +14 -10
  47. package/dist/views/TicketInboxView/client.js +14 -10
  48. package/dist/views/TicketingSettingsView/client.cjs +101 -96
  49. package/dist/views/TicketingSettingsView/client.js +92 -88
  50. package/dist/views/TimeDashboardView/client.cjs +2 -2
  51. package/dist/views/TimeDashboardView/client.js +2 -2
  52. package/dist/views/shared/StatusPill.cjs +23 -12
  53. package/dist/views/shared/StatusPill.js +23 -12
  54. package/dist/views/shared/dateLocale.cjs +5 -0
  55. package/dist/views/shared/dateLocale.js +3 -0
  56. package/package.json +23 -15
  57. package/src/__tests__/generateTrackingToken.test.ts +53 -0
  58. package/src/__tests__/integration/ai-agent.test.ts +46 -0
  59. package/src/__tests__/integration/auth.test.ts +43 -0
  60. package/src/__tests__/integration/automation-rules.test.ts +68 -0
  61. package/src/__tests__/integration/buildTestPayload.ts +52 -0
  62. package/src/__tests__/integration/channels.test.ts +52 -0
  63. package/src/__tests__/integration/core-behaviors.test.ts +58 -0
  64. package/src/__tests__/integration/dashboard-volume.test.ts +31 -0
  65. package/src/__tests__/integration/digest.test.ts +48 -0
  66. package/src/__tests__/integration/invoice-pdf.test.ts +30 -0
  67. package/src/__tests__/integration/isolation.test.ts +81 -0
  68. package/src/__tests__/integration/mentions-invoice.test.ts +50 -0
  69. package/src/__tests__/integration/nps.test.ts +37 -0
  70. package/src/__tests__/integration/sanitization.test.ts +35 -0
  71. package/src/__tests__/integration/sla-pause.test.ts +39 -0
  72. package/src/__tests__/integration/smoke.test.ts +26 -0
  73. package/src/__tests__/integration/snooze.test.ts +68 -0
  74. package/src/__tests__/integration/teams.test.ts +38 -0
  75. package/src/__tests__/rateLimiter.test.ts +89 -0
  76. package/src/__tests__/sanitizeHtml.test.ts +165 -0
  77. package/src/__tests__/sla.test.ts +258 -0
  78. package/src/collections/AutomationRules.ts +66 -0
  79. package/src/collections/NotificationQueue.ts +30 -0
  80. package/src/collections/SatisfactionSurveys.ts +11 -2
  81. package/src/collections/SupportClients.ts +58 -1
  82. package/src/collections/SupportTeam.ts +27 -0
  83. package/src/collections/TicketActivityLog.ts +9 -4
  84. package/src/collections/TicketMessages.ts +129 -31
  85. package/src/collections/Tickets.ts +31 -73
  86. package/src/collections/index.ts +3 -0
  87. package/src/components/TicketConversation/RewriteDropdown.tsx +86 -0
  88. package/src/components/TicketConversation/SkeletonText.tsx +23 -0
  89. package/src/components/TicketConversation/constants.ts +29 -0
  90. package/src/components/TicketConversation/hooks/useDocumentIdFromUrl.ts +21 -0
  91. package/src/components/TicketConversation/index.tsx +4 -152
  92. package/src/endpoints/admin-chat-stream.ts +3 -4
  93. package/src/endpoints/admin-chat.ts +11 -20
  94. package/src/endpoints/admin-stats.ts +70 -32
  95. package/src/endpoints/ai-agent.ts +36 -0
  96. package/src/endpoints/apply-macro.ts +8 -14
  97. package/src/endpoints/auth-2fa.ts +12 -12
  98. package/src/endpoints/auto-close.ts +6 -10
  99. package/src/endpoints/billing.ts +17 -4
  100. package/src/endpoints/bulk-action.ts +7 -12
  101. package/src/endpoints/channels.ts +89 -0
  102. package/src/endpoints/chat-stream.ts +3 -4
  103. package/src/endpoints/chat.ts +7 -12
  104. package/src/endpoints/chatbot.ts +2 -2
  105. package/src/endpoints/client-intelligence.ts +4 -4
  106. package/src/endpoints/delete-account.ts +9 -16
  107. package/src/endpoints/email-stats.ts +2 -2
  108. package/src/endpoints/escalate.ts +2 -2
  109. package/src/endpoints/export-csv.ts +2 -2
  110. package/src/endpoints/export-data.ts +5 -8
  111. package/src/endpoints/import-conversation.ts +6 -10
  112. package/src/endpoints/index.ts +18 -1
  113. package/src/endpoints/invite-collaborator.ts +30 -15
  114. package/src/endpoints/invoice.ts +127 -0
  115. package/src/endpoints/kb-search.ts +2 -2
  116. package/src/endpoints/login.ts +12 -4
  117. package/src/endpoints/merge-clients.ts +14 -19
  118. package/src/endpoints/merge-tickets.ts +11 -18
  119. package/src/endpoints/oauth-google.ts +86 -39
  120. package/src/endpoints/pending-emails-process.ts +15 -25
  121. package/src/endpoints/process-digests.ts +93 -0
  122. package/src/endpoints/process-scheduled.ts +6 -10
  123. package/src/endpoints/process-snooze.ts +78 -0
  124. package/src/endpoints/purge-logs.ts +2 -2
  125. package/src/endpoints/resend-notification.ts +3 -4
  126. package/src/endpoints/round-robin-config.ts +3 -4
  127. package/src/endpoints/satisfaction.ts +21 -14
  128. package/src/endpoints/search.ts +5 -8
  129. package/src/endpoints/seed-kb.ts +3 -4
  130. package/src/endpoints/send-reminder.ts +6 -9
  131. package/src/endpoints/settings.ts +5 -2
  132. package/src/endpoints/signature.ts +3 -4
  133. package/src/endpoints/sla-check.ts +2 -2
  134. package/src/endpoints/split-ticket.ts +7 -12
  135. package/src/endpoints/statuses.ts +2 -2
  136. package/src/endpoints/ticket-feedback.ts +4 -6
  137. package/src/endpoints/ticket-synthesis.ts +2 -2
  138. package/src/endpoints/track-open.ts +16 -28
  139. package/src/endpoints/transfer-ticket.ts +21 -9
  140. package/src/endpoints/user-prefs.ts +3 -4
  141. package/src/hooks/automationRules.ts +84 -0
  142. package/src/hooks/checkSLA.ts +48 -16
  143. package/src/plugin.ts +6 -0
  144. package/src/portal/LiveChat.tsx +2 -63
  145. package/src/portal/auth/tickets/detail/CloseTicketButton.tsx +10 -0
  146. package/src/portal/auth/tickets/detail/MarkSolutionButton.tsx +14 -2
  147. package/src/portal/auth/tickets/detail/MessageActions.tsx +37 -18
  148. package/src/portal/auth/tickets/detail/ReopenTicketButton.tsx +10 -0
  149. package/src/portal/auth/tickets/detail/TransferAndInviteActions.tsx +3 -2
  150. package/src/portal/auth/tickets/detail/page.tsx +2 -2
  151. package/src/portal/helpers.ts +46 -0
  152. package/src/portal/login/page.tsx +3 -8
  153. package/src/portal/types.ts +15 -0
  154. package/src/types/lucide-react.d.ts +34 -0
  155. package/src/types/payload-config.d.ts +10 -0
  156. package/src/utils/adminNotification.ts +2 -2
  157. package/src/utils/aiAgent.ts +147 -0
  158. package/src/utils/auth.ts +5 -4
  159. package/src/utils/channels.ts +36 -0
  160. package/src/utils/db.ts +73 -0
  161. package/src/utils/emailTemplate.ts +8 -1
  162. package/src/utils/fireWebhooks.ts +4 -6
  163. package/src/utils/generateTicketSynthesis.ts +7 -12
  164. package/src/utils/invoicePdf.ts +88 -0
  165. package/src/utils/notificationQueue.ts +36 -0
  166. package/src/utils/readSettings.ts +22 -6
  167. package/src/utils/sanitizeHtml.ts +57 -0
  168. package/src/utils/slugs.ts +6 -0
  169. package/src/utils/teamAccess.ts +27 -0
  170. package/src/utils/ticketAccess.ts +53 -0
  171. package/src/utils/webhookDispatcher.ts +4 -6
  172. package/src/views/BillingView/client.tsx +49 -37
  173. package/src/views/ChatView/client.tsx +4 -3
  174. package/src/views/CrmView/client.tsx +7 -7
  175. package/src/views/EmailTrackingView/client.tsx +7 -6
  176. package/src/views/ImportConversationView/client.tsx +4 -4
  177. package/src/views/LogsView/client.tsx +3 -2
  178. package/src/views/NewTicketView/client.tsx +1 -1
  179. package/src/views/PendingEmailsView/client.tsx +7 -6
  180. package/src/views/SupportDashboardView/client.tsx +21 -21
  181. package/src/views/TicketDetailView/NextActionItem.tsx +30 -0
  182. package/src/views/TicketDetailView/RewriteDropdown.tsx +63 -0
  183. package/src/views/TicketDetailView/client.tsx +54 -179
  184. package/src/views/TicketDetailView/constants.ts +23 -0
  185. package/src/views/TicketDetailView/helpers.ts +17 -0
  186. package/src/views/TicketDetailView/types.ts +10 -0
  187. package/src/views/TicketInboxView/client.tsx +16 -10
  188. package/src/views/TicketingSettingsView/client.tsx +90 -87
  189. package/src/views/TimeDashboardView/client.tsx +2 -2
  190. package/src/views/shared/StatusPill.tsx +24 -12
  191. package/src/views/shared/dateLocale.ts +5 -0
  192. package/src/views/shared/locales/en.json +708 -0
  193. package/src/views/shared/locales/fr.json +708 -0
@@ -10,7 +10,12 @@ var CodeBlockInserter = require('../../components/TicketConversation/components/
10
10
  var config = require('../shared/config');
11
11
  var sla = require('../shared/sla');
12
12
  var useTranslation = require('../../components/TicketConversation/hooks/useTranslation');
13
+ var dateLocale = require('../shared/dateLocale');
13
14
  var s = require('../../styles/TicketDetail.module.scss');
15
+ var constants = require('./constants');
16
+ var helpers = require('./helpers');
17
+ var RewriteDropdown = require('./RewriteDropdown');
18
+ var NextActionItem = require('./NextActionItem');
14
19
 
15
20
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
16
21
 
@@ -18,139 +23,6 @@ var React__default = /*#__PURE__*/_interopDefault(React);
18
23
  var Link__default = /*#__PURE__*/_interopDefault(Link);
19
24
  var s__default = /*#__PURE__*/_interopDefault(s);
20
25
 
21
- const ALIASES = [
22
- { value: "Support Consilioweb", label: "En tant que : Support Consilioweb" },
23
- { value: "contact@consilioweb.fr", label: "En tant que : contact@consilioweb.fr" }
24
- ];
25
- const STATUS_STYLE = {
26
- open: { bg: "#dbeafe", color: "#1e40af" },
27
- waiting_client: { bg: "#fef3c7", color: "#92400e" },
28
- resolved: { bg: "#dcfce7", color: "#166534" }
29
- };
30
- function timeAgo(d) {
31
- const date = new Date(d), now = /* @__PURE__ */ new Date();
32
- if (date.toDateString() === now.toDateString()) return date.toLocaleTimeString("fr-FR", { hour: "2-digit", minute: "2-digit" });
33
- const y = new Date(now);
34
- y.setDate(y.getDate() - 1);
35
- if (date.toDateString() === y.toDateString()) return `Hier, ${date.toLocaleTimeString("fr-FR", { hour: "2-digit", minute: "2-digit" })}`;
36
- return date.toLocaleDateString("fr-FR", { day: "numeric", month: "short", hour: "2-digit", minute: "2-digit" });
37
- }
38
- function dateLabel(d) {
39
- const date = new Date(d), now = /* @__PURE__ */ new Date();
40
- if (date.toDateString() === now.toDateString()) return "Aujourd'hui";
41
- const y = new Date(now);
42
- y.setDate(y.getDate() - 1);
43
- if (date.toDateString() === y.toDateString()) return "Hier";
44
- return date.toLocaleDateString("fr-FR", { day: "numeric", month: "long" });
45
- }
46
- const REWRITE_STYLES = [
47
- { id: "auto", label: "\u270F\uFE0F Auto", desc: "Garde le ton actuel" },
48
- { id: "tutoyer", label: "\u{1F44B} Tutoyer", desc: "Passe en tu" },
49
- { id: "vouvoyer", label: "\u{1F3A9} Vouvoyer", desc: "Passe en vous" },
50
- { id: "formel", label: "\u{1F4BC} Formel", desc: "Ton professionnel" },
51
- { id: "amical", label: "\u{1F60A} Amical", desc: "Ton chaleureux" },
52
- { id: "court", label: "\u26A1 Court", desc: "Version concise" }
53
- ];
54
- const RewriteDropdown = ({ disabled, loading, onSelect, toolbarBtnClass }) => {
55
- const [open, setOpen] = React.useState(false);
56
- const ref = React.useRef(null);
57
- React.useEffect(() => {
58
- if (!open) return;
59
- const close = (e) => {
60
- if (ref.current && !ref.current.contains(e.target)) setOpen(false);
61
- };
62
- document.addEventListener("mousedown", close);
63
- return () => document.removeEventListener("mousedown", close);
64
- }, [open]);
65
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref, style: { position: "relative", display: "inline-block" }, children: [
66
- /* @__PURE__ */ jsxRuntime.jsxs(
67
- "button",
68
- {
69
- type: "button",
70
- className: toolbarBtnClass,
71
- onClick: () => setOpen(!open),
72
- disabled,
73
- style: { fontSize: 11, fontWeight: 700, padding: "4px 10px", width: "auto", display: "flex", alignItems: "center", gap: 4 },
74
- children: [
75
- loading ? "..." : "\u270F\uFE0F Reformuler",
76
- !loading && /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: 9, opacity: 0.6 }, children: "\u25BC" })
77
- ]
78
- }
79
- ),
80
- open && !disabled && !loading && /* @__PURE__ */ jsxRuntime.jsx("div", { style: {
81
- position: "absolute",
82
- bottom: "100%",
83
- left: 0,
84
- marginBottom: 4,
85
- background: "#fff",
86
- border: "1px solid #e5e7eb",
87
- borderRadius: 8,
88
- boxShadow: "0 4px 16px rgba(0,0,0,0.12)",
89
- zIndex: 100,
90
- minWidth: 180,
91
- overflow: "hidden"
92
- }, children: REWRITE_STYLES.map((style) => /* @__PURE__ */ jsxRuntime.jsxs(
93
- "button",
94
- {
95
- type: "button",
96
- onClick: () => {
97
- setOpen(false);
98
- onSelect(style.id);
99
- },
100
- style: {
101
- display: "flex",
102
- flexDirection: "column",
103
- width: "100%",
104
- padding: "8px 12px",
105
- border: "none",
106
- background: "transparent",
107
- cursor: "pointer",
108
- textAlign: "left",
109
- borderBottom: "1px solid #f3f4f6"
110
- },
111
- onMouseEnter: (e) => {
112
- e.currentTarget.style.background = "#f9fafb";
113
- },
114
- onMouseLeave: (e) => {
115
- e.currentTarget.style.background = "transparent";
116
- },
117
- children: [
118
- /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: 12, fontWeight: 600 }, children: style.label }),
119
- /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: 10, color: "#9ca3af" }, children: style.desc })
120
- ]
121
- },
122
- style.id
123
- )) })
124
- ] });
125
- };
126
- function NextActionItem({ action, index, onToggle }) {
127
- const [pending, setPending] = React.useState(false);
128
- const labelMap = { now: "Maintenant", today: "Aujourd'hui", "this-week": "Cette semaine" };
129
- const done = !!action.done;
130
- return /* @__PURE__ */ jsxRuntime.jsxs("li", { className: s__default.default.aiCardNextAction, children: [
131
- /* @__PURE__ */ jsxRuntime.jsx(
132
- "button",
133
- {
134
- type: "button",
135
- className: `${s__default.default.aiCardNextCheck} ${done ? s__default.default.aiCardNextCheckDone : ""}`,
136
- onClick: async () => {
137
- setPending(true);
138
- try {
139
- await onToggle(!done);
140
- } finally {
141
- setPending(false);
142
- }
143
- },
144
- "aria-pressed": done,
145
- "aria-label": done ? "Marquer non fait" : "Marquer fait",
146
- disabled: pending,
147
- children: done && /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, children: "\u2713" })
148
- }
149
- ),
150
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: `${s__default.default.aiCardNextLabel} ${done ? s__default.default.aiCardNextLabelDone : ""}`, children: action.label }),
151
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: s__default.default.aiCardNextWhen, children: labelMap[action.priority] || action.priority })
152
- ] });
153
- }
154
26
  const TicketDetailClient = () => {
155
27
  const { t } = useTranslation.useTranslation();
156
28
  const searchParams = navigation.useSearchParams();
@@ -705,12 +577,12 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
705
577
  if (!ticketId) return /* @__PURE__ */ jsxRuntime.jsx("div", { style: { padding: 60, textAlign: "center", color: "#94a3b8", fontSize: 14 }, children: t("detail.selectTicket") });
706
578
  if (loading) return /* @__PURE__ */ jsxRuntime.jsx("div", { style: { padding: 60, textAlign: "center", color: "#94a3b8", fontSize: 14 }, children: t("common.loading") });
707
579
  if (!ticket) return /* @__PURE__ */ jsxRuntime.jsx("div", { style: { padding: 60, textAlign: "center", color: "#94a3b8", fontSize: 14 }, children: t("detail.notFound") });
708
- const st = STATUS_STYLE[ticket.status || "open"] || STATUS_STYLE.open;
580
+ const st = constants.STATUS_STYLE[ticket.status || "open"] || constants.STATUS_STYLE.open;
709
581
  const totalMin = timeEntries.reduce((a, e) => a + (e.duration || 0), 0);
710
582
  const initials = client ? `${(client.firstName?.[0] || "").toUpperCase()}${(client.lastName?.[0] || "").toUpperCase()}` : "?";
711
583
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: s__default.default.page, children: [
712
584
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: s__default.default.topBar, children: [
713
- /* @__PURE__ */ jsxRuntime.jsx(Link__default.default, { href: "/admin/support/inbox", className: s__default.default.backLink, "aria-label": "Retour \xE0 la bo\xEEte de r\xE9ception", children: "\u2190" }),
585
+ /* @__PURE__ */ jsxRuntime.jsx(Link__default.default, { href: "/admin/support/inbox", className: s__default.default.backLink, "aria-label": t("detail.backToInbox"), children: "\u2190" }),
714
586
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: s__default.default.ticketMeta, children: [
715
587
  /* @__PURE__ */ jsxRuntime.jsxs("span", { className: s__default.default.ticketNumber, children: [
716
588
  /* @__PURE__ */ jsxRuntime.jsx("span", { children: ticket.ticketNumber }),
@@ -763,7 +635,7 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
763
635
  });
764
636
  if (slaInfo.state !== "breach") return null;
765
637
  const duration = sla.formatSlaRemaining(slaInfo.remainingMs).replace(/^−/, "");
766
- const target = slaInfo.due ? new Date(slaInfo.due).toLocaleString("fr-FR", { day: "2-digit", month: "short", hour: "2-digit", minute: "2-digit" }) : "";
638
+ const target = slaInfo.due ? new Date(slaInfo.due).toLocaleString(dateLocale.DATE_LOCALE, { day: "2-digit", month: "short", hour: "2-digit", minute: "2-digit" }) : "";
767
639
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: s__default.default.slaBanner, role: "alert", children: [
768
640
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: s__default.default.slaBannerIcon, "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
769
641
  /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 9v4M12 17h.01" }),
@@ -818,7 +690,7 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
818
690
  const isAdmin = msg.authorType === "admin";
819
691
  const isPendingDelete = undoToast?.msgId === msg.id;
820
692
  return /* @__PURE__ */ jsxRuntime.jsxs(React__default.default.Fragment, { children: [
821
- showDate && /* @__PURE__ */ jsxRuntime.jsx("div", { className: s__default.default.dateSeparator, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: s__default.default.dateSeparatorText, children: dateLabel(msg.createdAt) }) }),
693
+ showDate && /* @__PURE__ */ jsxRuntime.jsx("div", { className: s__default.default.dateSeparator, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: s__default.default.dateSeparatorText, children: helpers.dateLabel(msg.createdAt) }) }),
822
694
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `${s__default.default.message} ${isAdmin ? s__default.default.messageAdmin : s__default.default.messageClient} ${msg.isInternal ? s__default.default.messageInternal : ""}`, style: isPendingDelete ? { opacity: 0.3, pointerEvents: "none" } : void 0, children: [
823
695
  /* @__PURE__ */ jsxRuntime.jsx(
824
696
  "div",
@@ -833,20 +705,20 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
833
705
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: s__default.default.messageContent, children: [
834
706
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: s__default.default.messageHeader, children: [
835
707
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: s__default.default.messageAuthor, children: msg.fromAlias || (isAdmin ? "Support" : msg.authorType === "email" ? "Email" : client?.firstName || "Client") }),
836
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: s__default.default.messageTime, children: timeAgo(msg.createdAt) }),
837
- msg.isInternal && /* @__PURE__ */ jsxRuntime.jsx("span", { className: s__default.default.badge, style: { background: "#fef3c7", color: "#92400e" }, children: "Interne" }),
838
- msg.isSolution && /* @__PURE__ */ jsxRuntime.jsx("span", { className: s__default.default.badge, style: { background: "#dcfce7", color: "#166534" }, children: "Solution" }),
708
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: s__default.default.messageTime, children: helpers.timeAgo(msg.createdAt) }),
709
+ msg.isInternal && /* @__PURE__ */ jsxRuntime.jsx("span", { className: s__default.default.badge, style: { background: "#fef3c7", color: "#92400e" }, children: t("detail.badgeInternal") }),
710
+ msg.isSolution && /* @__PURE__ */ jsxRuntime.jsx("span", { className: s__default.default.badge, style: { background: "#dcfce7", color: "#166534" }, children: t("detail.badgeSolution") }),
839
711
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: s__default.default.messageMeta, children: isAdmin && !msg.isInternal && (() => {
840
712
  const ext = msg;
841
713
  if (ext.emailOpenedAt) {
842
- const d = new Date(ext.emailOpenedAt).toLocaleString("fr-FR", { day: "numeric", month: "short", hour: "2-digit", minute: "2-digit" });
714
+ const d = new Date(ext.emailOpenedAt).toLocaleString(dateLocale.DATE_LOCALE, { day: "numeric", month: "short", hour: "2-digit", minute: "2-digit" });
843
715
  return /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { color: "#16a34a", cursor: "help" }, title: `Ouvert le ${d}`, children: [
844
716
  "\u2713\u2713 Lu ",
845
717
  d
846
718
  ] });
847
719
  }
848
720
  if (ext.emailSentAt) {
849
- const d = new Date(ext.emailSentAt).toLocaleString("fr-FR", { day: "numeric", month: "short", hour: "2-digit", minute: "2-digit" });
721
+ const d = new Date(ext.emailSentAt).toLocaleString(dateLocale.DATE_LOCALE, { day: "numeric", month: "short", hour: "2-digit", minute: "2-digit" });
850
722
  return /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { color: "#2563eb", cursor: "help" }, title: `Envoy\xE9 le ${d}`, children: [
851
723
  "\u2713 Envoy\xE9 ",
852
724
  d
@@ -865,7 +737,7 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
865
737
  setEditingHtml(html);
866
738
  setEditingBody(text);
867
739
  },
868
- placeholder: "\xC9diter le message...",
740
+ placeholder: t("detail.editPlaceholder"),
869
741
  minHeight: 120,
870
742
  onFileUpload: async (file) => {
871
743
  try {
@@ -883,8 +755,8 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
883
755
  }
884
756
  ),
885
757
  /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", gap: 6, justifyContent: "flex-end" }, children: [
886
- /* @__PURE__ */ jsxRuntime.jsx("button", { onClick: cancelEditMessage, disabled: editSaving, style: { padding: "5px 12px", fontSize: 12, borderRadius: 5, border: "1px solid var(--theme-elevation-200)", background: "var(--theme-elevation-0)", color: "var(--theme-text)", cursor: "pointer" }, children: "Annuler" }),
887
- /* @__PURE__ */ jsxRuntime.jsx("button", { onClick: saveEditMessage, disabled: editSaving || !editingBody.trim(), style: { padding: "5px 12px", fontSize: 12, fontWeight: 600, borderRadius: 5, border: "none", background: "#2563eb", color: "#fff", cursor: editSaving ? "wait" : "pointer", opacity: editSaving ? 0.6 : 1 }, children: editSaving ? "Sauvegarde\u2026" : "Enregistrer" })
758
+ /* @__PURE__ */ jsxRuntime.jsx("button", { onClick: cancelEditMessage, disabled: editSaving, style: { padding: "5px 12px", fontSize: 12, borderRadius: 5, border: "1px solid var(--theme-elevation-200)", background: "var(--theme-elevation-0)", color: "var(--theme-text)", cursor: "pointer" }, children: t("common.cancel") }),
759
+ /* @__PURE__ */ jsxRuntime.jsx("button", { onClick: saveEditMessage, disabled: editSaving || !editingBody.trim(), style: { padding: "5px 12px", fontSize: 12, fontWeight: 600, borderRadius: 5, border: "none", background: "#2563eb", color: "#fff", cursor: editSaving ? "wait" : "pointer", opacity: editSaving ? 0.6 : 1 }, children: editSaving ? t("detail.editSaving") : t("detail.editSave") })
888
760
  ] })
889
761
  ] }) : msg.deletedAt ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: s__default.default.messageBody, style: { color: "#94a3b8", fontStyle: "italic" }, children: t("detail.messageDeleted") }) : msg.bodyHtml && CodeBlock.hasCodeBlocks(msg.bodyHtml.replace(/<[^>]+>/g, "")) ? /* @__PURE__ */ jsxRuntime.jsx(CodeBlock.CodeBlockRendererHtml, { html: msg.bodyHtml }) : msg.bodyHtml ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: `${s__default.default.messageBody} ${s__default.default.rteDisplay}`, dangerouslySetInnerHTML: { __html: msg.bodyHtml } }) : CodeBlock.hasCodeBlocks(msg.body) ? /* @__PURE__ */ jsxRuntime.jsx(CodeBlock.MessageWithCodeBlocks, { text: msg.body, style: { fontSize: "13px", lineHeight: 1.5 } }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: s__default.default.messageBody, children: msg.body }),
890
762
  Array.isArray(msg.attachments) && msg.attachments.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: s__default.default.attachments, children: msg.attachments.map((att, i) => {
@@ -897,7 +769,7 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
897
769
  }) })
898
770
  ] }),
899
771
  editingMsgId !== msg.id && !msg.deletedAt && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: s__default.default.messageActions, children: [
900
- /* @__PURE__ */ jsxRuntime.jsx("button", { className: s__default.default.actionIcon, title: "\xC9diter", "aria-label": "\xC9diter le message", onClick: () => startEditMessage(msg), style: { fontSize: 11, width: "auto", padding: "4px 8px" }, children: "\xC9diter" }),
772
+ /* @__PURE__ */ jsxRuntime.jsx("button", { className: s__default.default.actionIcon, title: t("detail.editMessage"), "aria-label": t("detail.editMessageLabel"), onClick: () => startEditMessage(msg), style: { fontSize: 11, width: "auto", padding: "4px 8px" }, children: t("detail.editMessage") }),
901
773
  /* @__PURE__ */ jsxRuntime.jsx("button", { className: `${s__default.default.actionIcon} ${s__default.default.danger}`, title: t("actions.deleteMessage"), "aria-label": t("actions.deleteMessage"), onClick: () => handleDeleteMessage(msg.id), style: { fontSize: 11, width: "auto", padding: "4px 8px" }, children: t("actions.deleteMessage") }),
902
774
  features.splitTicket && !msg.isInternal && /* @__PURE__ */ jsxRuntime.jsx("button", { className: s__default.default.actionIcon, title: t("actions.extractMessage"), "aria-label": t("actions.extractToNewTicket"), onClick: () => {
903
775
  setSplitModal({ messageId: msg.id, preview: msg.body.slice(0, 200) });
@@ -963,7 +835,7 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
963
835
  children: aiReplying ? `\u23F3 ${t("composer.aiSuggestion.loading")}` : `\u2728 ${t("detail.iaSuggestion")}`
964
836
  }
965
837
  ),
966
- /* @__PURE__ */ jsxRuntime.jsx(RewriteDropdown, { disabled: aiRewriting || !replyBody.trim(), loading: aiRewriting, onSelect: (style) => handleAiRewrite(style), toolbarBtnClass: s__default.default.toolbarBtn })
838
+ /* @__PURE__ */ jsxRuntime.jsx(RewriteDropdown.RewriteDropdown, { disabled: aiRewriting || !replyBody.trim(), loading: aiRewriting, onSelect: (style) => handleAiRewrite(style), toolbarBtnClass: s__default.default.toolbarBtn })
967
839
  ] }),
968
840
  /* @__PURE__ */ jsxRuntime.jsx(
969
841
  CodeBlockInserter.CodeBlockInserter,
@@ -993,7 +865,7 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
993
865
  },
994
866
  disabled: applyingMacro,
995
867
  style: { marginLeft: 0 },
996
- "aria-label": "Appliquer une macro",
868
+ "aria-label": t("detail.macros"),
997
869
  children: [
998
870
  /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: applyingMacro ? t("detail.applyingMacro") : t("detail.macros") }),
999
871
  macros.map((m) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: m.id, children: m.name }, m.id))
@@ -1001,7 +873,7 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
1001
873
  }
1002
874
  ),
1003
875
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: s__default.default.toolbarDivider }),
1004
- features.canned && cannedResponses.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("select", { className: s__default.default.cannedSelect, "aria-label": "R\xE9ponses types", onChange: (e) => {
876
+ features.canned && cannedResponses.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("select", { className: s__default.default.cannedSelect, "aria-label": t("detail.cannedResponses"), onChange: (e) => {
1005
877
  const cr = cannedResponses.find((c) => String(c.id) === e.target.value);
1006
878
  if (cr) {
1007
879
  let b = cr.body;
@@ -1046,11 +918,8 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
1046
918
  }
1047
919
  ),
1048
920
  pendingFiles.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: s__default.default.uploadPreview, children: pendingFiles.map((f, i) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: s__default.default.uploadPreviewItem, children: [
1049
- /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
1050
- "PJ ",
1051
- f.name
1052
- ] }),
1053
- /* @__PURE__ */ jsxRuntime.jsx("button", { className: s__default.default.uploadRemoveBtn, "aria-label": `Retirer ${f.name}`, onClick: () => setPendingFiles((prev) => prev.filter((_, j) => j !== i)), children: "\xD7" })
921
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: t("detail.uploadItem", { name: f.name }) }),
922
+ /* @__PURE__ */ jsxRuntime.jsx("button", { className: s__default.default.uploadRemoveBtn, "aria-label": t("detail.removeUpload", { name: f.name }), onClick: () => setPendingFiles((prev) => prev.filter((_, j) => j !== i)), children: "\xD7" })
1054
923
  ] }, i)) })
1055
924
  ] }),
1056
925
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: s__default.default.composerFooter, children: [
@@ -1069,8 +938,8 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
1069
938
  },
1070
939
  style: { fontSize: "12px", padding: "4px 8px", fontWeight: 600, borderRadius: 6, border: "1px solid var(--theme-elevation-200)", background: "var(--theme-elevation-0)", color: "var(--theme-text)" },
1071
940
  children: [
1072
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "admin", children: "En tant que : Support" }),
1073
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "client", children: "En tant que : Client" })
941
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "admin", children: t("detail.sendAsSupport") }),
942
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "client", children: t("detail.sendAsClient") })
1074
943
  ]
1075
944
  }
1076
945
  ),
@@ -1084,7 +953,7 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
1084
953
  title: t("composer.aliases.tooltip"),
1085
954
  children: [
1086
955
  /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: t("composer.aliases.self") }),
1087
- ALIASES.map((a) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: a.value, children: a.label }, a.value))
956
+ constants.ALIASES.map((a) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: a.value, children: a.label }, a.value))
1088
957
  ]
1089
958
  }
1090
959
  ),
@@ -1105,7 +974,7 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
1105
974
  /* @__PURE__ */ jsxRuntime.jsx("kbd", { children: "\u2318" }),
1106
975
  /* @__PURE__ */ jsxRuntime.jsx("kbd", { children: "\u21B5" })
1107
976
  ] }),
1108
- /* @__PURE__ */ jsxRuntime.jsx("button", { className: `${s__default.default.sendBtn} ${isInternal ? s__default.default.sendBtnInternal : ""}`, onClick: handleSend, disabled: sending || !replyBody.trim(), "data-action": "send-reply", children: sending ? t("detail.sending") : sendAsClient ? "Ajouter message client" : isInternal ? t("detail.sendNote") : t("detail.sendReply") })
977
+ /* @__PURE__ */ jsxRuntime.jsx("button", { className: `${s__default.default.sendBtn} ${isInternal ? s__default.default.sendBtnInternal : ""}`, onClick: handleSend, disabled: sending || !replyBody.trim(), "data-action": "send-reply", children: sending ? t("detail.sending") : sendAsClient ? t("detail.addClientMessage") : isInternal ? t("detail.sendNote") : t("detail.sendReply") })
1109
978
  ] })
1110
979
  ]
1111
980
  }
@@ -1178,7 +1047,7 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
1178
1047
  clientSummary && clientSummary.summary && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `${s__default.default.sideSection} ${s__default.default.aiCard}`, children: [
1179
1048
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: s__default.default.aiCardTitle, children: [
1180
1049
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: s__default.default.aiCardIcon, "aria-hidden": true, children: "\u2728" }),
1181
- "Synth\xE8se client"
1050
+ t("detail.aiCard.title")
1182
1051
  ] }),
1183
1052
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: s__default.default.aiCardLead, children: clientSummary.summary }),
1184
1053
  clientSummary.recurringTopics && clientSummary.recurringTopics.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: s__default.default.aiCardChips, children: clientSummary.recurringTopics.slice(0, 5).map((tp, i) => /* @__PURE__ */ jsxRuntime.jsx("span", { className: s__default.default.aiChip, children: tp.topic }, `tp-${i}`)) }),
@@ -1189,7 +1058,7 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
1189
1058
  clientSummary?.nextActions && clientSummary.nextActions.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1190
1059
  /* @__PURE__ */ jsxRuntime.jsx("h5", { className: s__default.default.aiCardNextTitle, children: t("detail.aiCard.nextActions.title") }),
1191
1060
  /* @__PURE__ */ jsxRuntime.jsx("ul", { className: s__default.default.aiCardNextActions, children: clientSummary.nextActions.map((action, i) => /* @__PURE__ */ jsxRuntime.jsx(
1192
- NextActionItem,
1061
+ NextActionItem.NextActionItem,
1193
1062
  {
1194
1063
  action,
1195
1064
  index: i,
@@ -1257,12 +1126,12 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
1257
1126
  ":",
1258
1127
  String(timerSeconds % 60).padStart(2, "0")
1259
1128
  ] }),
1260
- !timerRunning ? /* @__PURE__ */ jsxRuntime.jsx("button", { className: s__default.default.timerBtn, onClick: () => setTimerRunning(true), "aria-label": "D\xE9marrer le timer", children: timerSeconds > 0 ? "\u25B6" : "\u25B6 Go" }) : /* @__PURE__ */ jsxRuntime.jsx("button", { className: `${s__default.default.timerBtn} ${s__default.default.timerBtnRunning}`, onClick: () => setTimerRunning(false), "aria-label": "Mettre en pause le timer", children: "\u23F8 Pause" }),
1129
+ !timerRunning ? /* @__PURE__ */ jsxRuntime.jsx("button", { className: s__default.default.timerBtn, onClick: () => setTimerRunning(true), "aria-label": t("detail.timerStart"), children: timerSeconds > 0 ? "\u25B6" : "\u25B6 Go" }) : /* @__PURE__ */ jsxRuntime.jsx("button", { className: `${s__default.default.timerBtn} ${s__default.default.timerBtnRunning}`, onClick: () => setTimerRunning(false), "aria-label": t("detail.timerPause"), children: "\u23F8 Pause" }),
1261
1130
  timerSeconds >= 60 && !timerRunning && /* @__PURE__ */ jsxRuntime.jsxs("button", { className: `${s__default.default.timerBtn} ${s__default.default.timerBtnGhost}`, onClick: () => {
1262
1131
  handleTimerSave();
1263
1132
  localStorage.removeItem(`timer-sec-${ticketId}`);
1264
1133
  localStorage.removeItem(`timer-run-${ticketId}`);
1265
- }, "aria-label": "Sauvegarder le temps", children: [
1134
+ }, "aria-label": t("detail.timerSave"), children: [
1266
1135
  "\u{1F4BE} ",
1267
1136
  Math.round(timerSeconds / 60),
1268
1137
  "m"
@@ -1281,11 +1150,11 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
1281
1150
  fetchAll();
1282
1151
  } catch {
1283
1152
  }
1284
- }, style: { fontSize: 11 }, children: "+ Ajouter" })
1153
+ }, style: { fontSize: 11 }, children: t("detail.addTime") })
1285
1154
  ] }),
1286
1155
  /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { marginTop: 8, fontSize: 11, color: "var(--theme-elevation-500)" }, children: [
1287
1156
  /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", justifyContent: "space-between", padding: "2px 0", alignItems: "center" }, children: [
1288
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Facturable" }),
1157
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: t("detail.billing.billable") }),
1289
1158
  /* @__PURE__ */ jsxRuntime.jsx(
1290
1159
  "button",
1291
1160
  {
@@ -1298,12 +1167,12 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
1298
1167
  }
1299
1168
  },
1300
1169
  style: { fontWeight: 600, color: ticket.billable !== false ? "#16a34a" : "#dc2626", background: "none", border: "none", cursor: "pointer", fontSize: 11, textDecoration: "underline" },
1301
- children: ticket.billable !== false ? "Oui" : "Non"
1170
+ children: ticket.billable !== false ? t("detail.billing.yes") : t("detail.billing.no")
1302
1171
  }
1303
1172
  )
1304
1173
  ] }),
1305
1174
  totalMin > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", justifyContent: "space-between", padding: "2px 0" }, children: [
1306
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Montant estim\xE9" }),
1175
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: t("detail.billing.estimatedAmount") }),
1307
1176
  /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { fontWeight: 700, color: "var(--theme-text)" }, children: [
1308
1177
  (totalMin / 60 * 60).toFixed(0),
1309
1178
  "\u20AC"
@@ -1311,7 +1180,7 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
1311
1180
  ] })
1312
1181
  ] }),
1313
1182
  timeEntries.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { marginTop: 8, fontSize: 11 }, children: timeEntries.slice(0, 6).map((e) => /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", justifyContent: "space-between", padding: "3px 0", color: "var(--theme-elevation-500)" }, children: [
1314
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: new Date(e.date).toLocaleDateString("fr-FR", { day: "numeric", month: "short" }) }),
1183
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: new Date(e.date).toLocaleDateString(dateLocale.DATE_LOCALE, { day: "numeric", month: "short" }) }),
1315
1184
  /* @__PURE__ */ jsxRuntime.jsxs("span", { title: e.description, style: { fontWeight: 600, cursor: e.description ? "help" : "default" }, children: [
1316
1185
  e.duration,
1317
1186
  "min"
@@ -1323,7 +1192,7 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
1323
1192
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: s__default.default.tagsWrap, children: [
1324
1193
  tags.map((tag) => /* @__PURE__ */ jsxRuntime.jsxs("span", { className: s__default.default.tagChip, children: [
1325
1194
  tag,
1326
- /* @__PURE__ */ jsxRuntime.jsx("button", { className: s__default.default.tagRemove, "aria-label": `Retirer le tag ${tag}`, onClick: () => handleRemoveTag(tag), children: "\xD7" })
1195
+ /* @__PURE__ */ jsxRuntime.jsx("button", { className: s__default.default.tagRemove, "aria-label": t("detail.removeTag", { tag }), onClick: () => handleRemoveTag(tag), children: "\xD7" })
1327
1196
  ] }, tag)),
1328
1197
  addingTag ? /* @__PURE__ */ jsxRuntime.jsx(
1329
1198
  "input",
@@ -1339,17 +1208,17 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
1339
1208
  }
1340
1209
  },
1341
1210
  onBlur: handleAddTag,
1342
- placeholder: "Tag...",
1211
+ placeholder: t("detail.tagPlaceholder"),
1343
1212
  autoFocus: true
1344
1213
  }
1345
- ) : /* @__PURE__ */ jsxRuntime.jsx("button", { className: s__default.default.tagAddBtn, onClick: () => setAddingTag(true), "aria-label": "Ajouter un tag", children: "+ Tag" })
1214
+ ) : /* @__PURE__ */ jsxRuntime.jsx("button", { className: s__default.default.tagAddBtn, onClick: () => setAddingTag(true), "aria-label": t("detail.addTag"), children: t("detail.addTagBtn") })
1346
1215
  ] })
1347
1216
  ] }),
1348
1217
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: s__default.default.sideSection, children: [
1349
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: s__default.default.sideSectionTitle, children: "Facturation" }),
1218
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: s__default.default.sideSectionTitle, children: t("detail.billing.title") }),
1350
1219
  /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", flexDirection: "column", gap: 8 }, children: [
1351
1220
  /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between" }, children: [
1352
- /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: 12 }, children: "Type" }),
1221
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: 12 }, children: t("detail.billing.type") }),
1353
1222
  /* @__PURE__ */ jsxRuntime.jsxs(
1354
1223
  "select",
1355
1224
  {
@@ -1368,14 +1237,14 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
1368
1237
  },
1369
1238
  style: { fontSize: 12, padding: "4px 8px", borderRadius: 6, border: "1px solid #e5e7eb", background: "#fff" },
1370
1239
  children: [
1371
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "hourly", children: "Au temps" }),
1372
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "flat", children: "Forfait" })
1240
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "hourly", children: t("detail.billing.hourly") }),
1241
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "flat", children: t("detail.billing.flat") })
1373
1242
  ]
1374
1243
  }
1375
1244
  )
1376
1245
  ] }),
1377
1246
  ticket?.billingType === "flat" && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between" }, children: [
1378
- /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: 12 }, children: "Montant forfait" }),
1247
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: 12 }, children: t("detail.billing.flatAmount") }),
1379
1248
  /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "center", gap: 4 }, children: [
1380
1249
  /* @__PURE__ */ jsxRuntime.jsx(
1381
1250
  "input",
@@ -1403,7 +1272,7 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
1403
1272
  ] })
1404
1273
  ] }),
1405
1274
  /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between" }, children: [
1406
- /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: 12 }, children: "Montant factur\xE9" }),
1275
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: 12 }, children: t("detail.billing.billedAmount") }),
1407
1276
  /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "center", gap: 4 }, children: [
1408
1277
  /* @__PURE__ */ jsxRuntime.jsx(
1409
1278
  "input",
@@ -1431,7 +1300,7 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
1431
1300
  ] })
1432
1301
  ] }),
1433
1302
  /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between" }, children: [
1434
- /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: 12 }, children: "Paiement" }),
1303
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: 12 }, children: t("detail.billing.payment") }),
1435
1304
  /* @__PURE__ */ jsxRuntime.jsxs(
1436
1305
  "select",
1437
1306
  {
@@ -1450,16 +1319,16 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
1450
1319
  },
1451
1320
  style: { fontSize: 12, padding: "4px 8px", borderRadius: 6, border: "1px solid #e5e7eb", background: "#fff" },
1452
1321
  children: [
1453
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "unpaid", children: "Non pay\xE9" }),
1454
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "partial", children: "Partiel" }),
1455
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "paid", children: "Pay\xE9" })
1322
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "unpaid", children: t("detail.billing.unpaid") }),
1323
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "partial", children: t("detail.billing.partial") }),
1324
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "paid", children: t("detail.billing.paid") })
1456
1325
  ]
1457
1326
  }
1458
1327
  )
1459
1328
  ] })
1460
1329
  ] })
1461
1330
  ] }),
1462
- summaryLoading && /* @__PURE__ */ jsxRuntime.jsx("div", { className: s__default.default.sideSection, children: /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: 11, color: "var(--theme-elevation-400)", textAlign: "center", padding: 8 }, children: "\u2728 Chargement de la synth\xE8se\u2026" }) })
1331
+ summaryLoading && /* @__PURE__ */ jsxRuntime.jsx("div", { className: s__default.default.sideSection, children: /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: 11, color: "var(--theme-elevation-400)", textAlign: "center", padding: 8 }, children: t("detail.loadingSummary") }) })
1463
1332
  ] }),
1464
1333
  sidebarTab === "client" && /* @__PURE__ */ jsxRuntime.jsxs("div", { role: "tabpanel", id: "sidebar-panel-client", "aria-labelledby": "sidebar-tab-client", children: [
1465
1334
  client && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: s__default.default.sideSection, children: [
@@ -1487,7 +1356,7 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
1487
1356
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: s__default.default.previousTicketsSubject, children: pt.subject || `#${pt.id}` }),
1488
1357
  /* @__PURE__ */ jsxRuntime.jsxs("span", { className: s__default.default.previousTicketsMeta, children: [
1489
1358
  pt.status ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: s__default.default.previousTicketsStatus, children: pt.status }) : null,
1490
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: s__default.default.previousTicketsDate, children: new Date(pt.createdAt).toLocaleDateString("fr-FR", { day: "numeric", month: "short", year: "numeric" }) })
1359
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: s__default.default.previousTicketsDate, children: new Date(pt.createdAt).toLocaleDateString(dateLocale.DATE_LOCALE, { day: "numeric", month: "short", year: "numeric" }) })
1491
1360
  ] })
1492
1361
  ] }) }, pt.id)) })
1493
1362
  ] })
@@ -1498,23 +1367,23 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
1498
1367
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: s__default.default.activityDot, style: { backgroundColor: a.actorType === "admin" ? "#2563eb" : a.actorType === "system" ? "#6b7280" : "#16a34a" } }),
1499
1368
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: s__default.default.activityContent, children: [
1500
1369
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: s__default.default.activityText, children: (a.detail || a.action).slice(0, 120) }),
1501
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: s__default.default.activityTime, children: timeAgo(a.createdAt) })
1370
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: s__default.default.activityTime, children: helpers.timeAgo(a.createdAt) })
1502
1371
  ] })
1503
1372
  ] }, a.id))
1504
1373
  ] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: s__default.default.sideSection, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: s__default.default.previousTicketsEmpty, children: "\u2014" }) }) })
1505
1374
  ] })
1506
1375
  ] }),
1507
1376
  undoToast && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: s__default.default.undoToast, role: "alert", children: [
1508
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Message supprim\xE9" }),
1509
- /* @__PURE__ */ jsxRuntime.jsx("button", { className: s__default.default.undoBtn, onClick: handleUndoDelete, children: "Annuler" })
1377
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: t("detail.messageDeletedToast") }),
1378
+ /* @__PURE__ */ jsxRuntime.jsx("button", { className: s__default.default.undoBtn, onClick: handleUndoDelete, children: t("common.cancel") })
1510
1379
  ] }),
1511
1380
  splitModal && /* @__PURE__ */ jsxRuntime.jsx("div", { className: s__default.default.splitOverlay, onClick: (e) => {
1512
1381
  if (e.target === e.currentTarget) {
1513
1382
  setSplitModal(null);
1514
1383
  setSplitSubject("");
1515
1384
  }
1516
- }, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: s__default.default.splitModal, role: "dialog", "aria-label": "Extraire dans un nouveau ticket", children: [
1517
- /* @__PURE__ */ jsxRuntime.jsx("h3", { className: s__default.default.splitTitle, children: "Extraire dans un nouveau ticket" }),
1385
+ }, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: s__default.default.splitModal, role: "dialog", "aria-label": t("actions.extractToNewTicket"), children: [
1386
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: s__default.default.splitTitle, children: t("actions.extractToNewTicket") }),
1518
1387
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: s__default.default.splitPreview, children: splitModal.preview }),
1519
1388
  /* @__PURE__ */ jsxRuntime.jsx(
1520
1389
  "input",
@@ -1525,7 +1394,7 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
1525
1394
  onKeyDown: (e) => {
1526
1395
  if (e.key === "Enter") handleSplitConfirm();
1527
1396
  },
1528
- placeholder: "Sujet du nouveau ticket...",
1397
+ placeholder: t("detail.split.subjectPlaceholder"),
1529
1398
  autoFocus: true
1530
1399
  }
1531
1400
  ),
@@ -1533,8 +1402,8 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
1533
1402
  /* @__PURE__ */ jsxRuntime.jsx("button", { className: s__default.default.splitCancelBtn, onClick: () => {
1534
1403
  setSplitModal(null);
1535
1404
  setSplitSubject("");
1536
- }, children: "Annuler" }),
1537
- /* @__PURE__ */ jsxRuntime.jsx("button", { className: s__default.default.splitConfirmBtn, onClick: handleSplitConfirm, disabled: !splitSubject.trim(), children: "Cr\xE9er le ticket" })
1405
+ }, children: t("common.cancel") }),
1406
+ /* @__PURE__ */ jsxRuntime.jsx("button", { className: s__default.default.splitConfirmBtn, onClick: handleSplitConfirm, disabled: !splitSubject.trim(), children: t("detail.split.createBtn") })
1538
1407
  ] })
1539
1408
  ] }) })
1540
1409
  ] });