@consilioweb/payload-support 0.15.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 (202) 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/components/ActionPanels.cjs +72 -0
  7. package/dist/components/TicketConversation/components/ActionPanels.js +73 -2
  8. package/dist/components/TicketConversation/components/QuickActions.cjs +22 -1
  9. package/dist/components/TicketConversation/components/QuickActions.js +22 -1
  10. package/dist/components/TicketConversation/constants.cjs +27 -0
  11. package/dist/components/TicketConversation/constants.js +26 -1
  12. package/dist/components/TicketConversation/hooks/useDocumentIdFromUrl.cjs +20 -0
  13. package/dist/components/TicketConversation/hooks/useDocumentIdFromUrl.js +19 -0
  14. package/dist/components/TicketConversation/hooks/useTicketActions.cjs +59 -0
  15. package/dist/components/TicketConversation/hooks/useTicketActions.js +59 -0
  16. package/dist/components/TicketConversation/index.cjs +42 -149
  17. package/dist/components/TicketConversation/index.js +37 -144
  18. package/dist/index.cjs +1835 -741
  19. package/dist/index.d.cts +3 -0
  20. package/dist/index.d.ts +3 -0
  21. package/dist/index.js +1833 -741
  22. package/dist/views/BillingView/client.cjs +40 -54
  23. package/dist/views/BillingView/client.js +40 -54
  24. package/dist/views/ChatView/client.cjs +4 -3
  25. package/dist/views/ChatView/client.js +4 -3
  26. package/dist/views/CrmView/client.cjs +7 -7
  27. package/dist/views/CrmView/client.js +7 -7
  28. package/dist/views/EmailTrackingView/client.cjs +6 -5
  29. package/dist/views/EmailTrackingView/client.js +6 -5
  30. package/dist/views/ImportConversationView/client.cjs +4 -4
  31. package/dist/views/ImportConversationView/client.js +4 -4
  32. package/dist/views/LogsView/client.cjs +3 -2
  33. package/dist/views/LogsView/client.js +3 -2
  34. package/dist/views/NewTicketView/client.cjs +1 -1
  35. package/dist/views/NewTicketView/client.js +1 -1
  36. package/dist/views/PendingEmailsView/client.cjs +7 -6
  37. package/dist/views/PendingEmailsView/client.js +7 -6
  38. package/dist/views/SupportDashboardView/client.cjs +19 -22
  39. package/dist/views/SupportDashboardView/client.js +19 -22
  40. package/dist/views/TicketDetailView/NextActionItem.cjs +40 -0
  41. package/dist/views/TicketDetailView/NextActionItem.js +34 -0
  42. package/dist/views/TicketDetailView/RewriteDropdown.cjs +80 -0
  43. package/dist/views/TicketDetailView/RewriteDropdown.js +78 -0
  44. package/dist/views/TicketDetailView/client.cjs +59 -190
  45. package/dist/views/TicketDetailView/client.js +52 -183
  46. package/dist/views/TicketDetailView/constants.cjs +20 -0
  47. package/dist/views/TicketDetailView/constants.js +16 -0
  48. package/dist/views/TicketDetailView/helpers.cjs +23 -0
  49. package/dist/views/TicketDetailView/helpers.js +20 -0
  50. package/dist/views/TicketDetailView/types.cjs +2 -0
  51. package/dist/views/TicketDetailView/types.js +1 -0
  52. package/dist/views/TicketInboxView/client.cjs +14 -10
  53. package/dist/views/TicketInboxView/client.js +14 -10
  54. package/dist/views/TicketingSettingsView/client.cjs +101 -96
  55. package/dist/views/TicketingSettingsView/client.js +92 -88
  56. package/dist/views/TimeDashboardView/client.cjs +2 -2
  57. package/dist/views/TimeDashboardView/client.js +2 -2
  58. package/dist/views/shared/StatusPill.cjs +23 -12
  59. package/dist/views/shared/StatusPill.js +23 -12
  60. package/dist/views/shared/dateLocale.cjs +5 -0
  61. package/dist/views/shared/dateLocale.js +3 -0
  62. package/package.json +23 -15
  63. package/src/__tests__/generateTrackingToken.test.ts +53 -0
  64. package/src/__tests__/integration/ai-agent.test.ts +46 -0
  65. package/src/__tests__/integration/auth.test.ts +43 -0
  66. package/src/__tests__/integration/automation-rules.test.ts +68 -0
  67. package/src/__tests__/integration/buildTestPayload.ts +52 -0
  68. package/src/__tests__/integration/channels.test.ts +52 -0
  69. package/src/__tests__/integration/core-behaviors.test.ts +58 -0
  70. package/src/__tests__/integration/dashboard-volume.test.ts +31 -0
  71. package/src/__tests__/integration/digest.test.ts +48 -0
  72. package/src/__tests__/integration/invoice-pdf.test.ts +30 -0
  73. package/src/__tests__/integration/isolation.test.ts +81 -0
  74. package/src/__tests__/integration/mentions-invoice.test.ts +50 -0
  75. package/src/__tests__/integration/nps.test.ts +37 -0
  76. package/src/__tests__/integration/sanitization.test.ts +35 -0
  77. package/src/__tests__/integration/sla-pause.test.ts +39 -0
  78. package/src/__tests__/integration/smoke.test.ts +26 -0
  79. package/src/__tests__/integration/snooze.test.ts +68 -0
  80. package/src/__tests__/integration/teams.test.ts +38 -0
  81. package/src/__tests__/rateLimiter.test.ts +89 -0
  82. package/src/__tests__/sanitizeHtml.test.ts +165 -0
  83. package/src/__tests__/sla.test.ts +258 -0
  84. package/src/collections/AutomationRules.ts +66 -0
  85. package/src/collections/NotificationQueue.ts +30 -0
  86. package/src/collections/SatisfactionSurveys.ts +11 -2
  87. package/src/collections/SupportClients.ts +58 -1
  88. package/src/collections/SupportTeam.ts +27 -0
  89. package/src/collections/TicketActivityLog.ts +9 -4
  90. package/src/collections/TicketMessages.ts +137 -31
  91. package/src/collections/Tickets.ts +31 -72
  92. package/src/collections/index.ts +3 -0
  93. package/src/components/TicketConversation/RewriteDropdown.tsx +86 -0
  94. package/src/components/TicketConversation/SkeletonText.tsx +23 -0
  95. package/src/components/TicketConversation/components/ActionPanels.tsx +82 -1
  96. package/src/components/TicketConversation/components/QuickActions.tsx +25 -0
  97. package/src/components/TicketConversation/constants.ts +29 -0
  98. package/src/components/TicketConversation/hooks/useDocumentIdFromUrl.ts +21 -0
  99. package/src/components/TicketConversation/hooks/useTicketActions.ts +51 -0
  100. package/src/components/TicketConversation/index.tsx +29 -157
  101. package/src/endpoints/admin-chat-stream.ts +3 -4
  102. package/src/endpoints/admin-chat.ts +11 -20
  103. package/src/endpoints/admin-stats.ts +70 -32
  104. package/src/endpoints/ai-agent.ts +36 -0
  105. package/src/endpoints/apply-macro.ts +8 -14
  106. package/src/endpoints/auth-2fa.ts +12 -12
  107. package/src/endpoints/auto-close.ts +38 -18
  108. package/src/endpoints/billing.ts +17 -4
  109. package/src/endpoints/bulk-action.ts +7 -12
  110. package/src/endpoints/channels.ts +89 -0
  111. package/src/endpoints/chat-stream.ts +3 -4
  112. package/src/endpoints/chat.ts +7 -12
  113. package/src/endpoints/chatbot.ts +2 -2
  114. package/src/endpoints/client-intelligence.ts +4 -4
  115. package/src/endpoints/delete-account.ts +9 -16
  116. package/src/endpoints/email-stats.ts +2 -2
  117. package/src/endpoints/escalate.ts +2 -2
  118. package/src/endpoints/export-csv.ts +2 -2
  119. package/src/endpoints/export-data.ts +5 -8
  120. package/src/endpoints/import-conversation.ts +6 -10
  121. package/src/endpoints/index.ts +24 -2
  122. package/src/endpoints/invite-collaborator.ts +30 -15
  123. package/src/endpoints/invoice.ts +127 -0
  124. package/src/endpoints/kb-search.ts +2 -2
  125. package/src/endpoints/login.ts +12 -4
  126. package/src/endpoints/merge-clients.ts +14 -19
  127. package/src/endpoints/merge-tickets.ts +11 -18
  128. package/src/endpoints/oauth-google.ts +86 -39
  129. package/src/endpoints/pending-emails-process.ts +15 -25
  130. package/src/endpoints/process-digests.ts +93 -0
  131. package/src/endpoints/process-scheduled.ts +6 -10
  132. package/src/endpoints/process-snooze.ts +78 -0
  133. package/src/endpoints/purge-logs.ts +2 -2
  134. package/src/endpoints/resend-notification.ts +3 -4
  135. package/src/endpoints/round-robin-config.ts +3 -4
  136. package/src/endpoints/satisfaction.ts +21 -14
  137. package/src/endpoints/search.ts +5 -8
  138. package/src/endpoints/seed-kb.ts +3 -4
  139. package/src/endpoints/send-reminder.ts +186 -0
  140. package/src/endpoints/settings.ts +5 -2
  141. package/src/endpoints/signature.ts +3 -4
  142. package/src/endpoints/sla-check.ts +2 -2
  143. package/src/endpoints/split-ticket.ts +7 -12
  144. package/src/endpoints/statuses.ts +2 -2
  145. package/src/endpoints/ticket-feedback.ts +4 -6
  146. package/src/endpoints/ticket-synthesis.ts +2 -2
  147. package/src/endpoints/track-open.ts +16 -28
  148. package/src/endpoints/transfer-ticket.ts +21 -9
  149. package/src/endpoints/user-prefs.ts +3 -4
  150. package/src/hooks/automationRules.ts +84 -0
  151. package/src/hooks/checkSLA.ts +48 -16
  152. package/src/plugin.ts +6 -0
  153. package/src/portal/LiveChat.tsx +2 -63
  154. package/src/portal/auth/tickets/detail/CloseTicketButton.tsx +10 -0
  155. package/src/portal/auth/tickets/detail/MarkSolutionButton.tsx +14 -2
  156. package/src/portal/auth/tickets/detail/MessageActions.tsx +37 -18
  157. package/src/portal/auth/tickets/detail/ReopenTicketButton.tsx +10 -0
  158. package/src/portal/auth/tickets/detail/TransferAndInviteActions.tsx +3 -2
  159. package/src/portal/auth/tickets/detail/page.tsx +2 -2
  160. package/src/portal/helpers.ts +46 -0
  161. package/src/portal/login/page.tsx +3 -8
  162. package/src/portal/types.ts +15 -0
  163. package/src/types/lucide-react.d.ts +34 -0
  164. package/src/types/payload-config.d.ts +10 -0
  165. package/src/utils/adminNotification.ts +2 -2
  166. package/src/utils/aiAgent.ts +147 -0
  167. package/src/utils/auth.ts +5 -4
  168. package/src/utils/channels.ts +36 -0
  169. package/src/utils/db.ts +73 -0
  170. package/src/utils/emailTemplate.ts +8 -1
  171. package/src/utils/fireWebhooks.ts +4 -6
  172. package/src/utils/generateTicketSynthesis.ts +7 -12
  173. package/src/utils/invoicePdf.ts +88 -0
  174. package/src/utils/notificationQueue.ts +36 -0
  175. package/src/utils/readSettings.ts +22 -6
  176. package/src/utils/sanitizeHtml.ts +57 -0
  177. package/src/utils/slugs.ts +6 -0
  178. package/src/utils/teamAccess.ts +27 -0
  179. package/src/utils/ticketAccess.ts +53 -0
  180. package/src/utils/webhookDispatcher.ts +4 -6
  181. package/src/views/BillingView/client.tsx +49 -37
  182. package/src/views/ChatView/client.tsx +4 -3
  183. package/src/views/CrmView/client.tsx +7 -7
  184. package/src/views/EmailTrackingView/client.tsx +7 -6
  185. package/src/views/ImportConversationView/client.tsx +4 -4
  186. package/src/views/LogsView/client.tsx +3 -2
  187. package/src/views/NewTicketView/client.tsx +1 -1
  188. package/src/views/PendingEmailsView/client.tsx +7 -6
  189. package/src/views/SupportDashboardView/client.tsx +21 -21
  190. package/src/views/TicketDetailView/NextActionItem.tsx +30 -0
  191. package/src/views/TicketDetailView/RewriteDropdown.tsx +63 -0
  192. package/src/views/TicketDetailView/client.tsx +54 -179
  193. package/src/views/TicketDetailView/constants.ts +23 -0
  194. package/src/views/TicketDetailView/helpers.ts +17 -0
  195. package/src/views/TicketDetailView/types.ts +10 -0
  196. package/src/views/TicketInboxView/client.tsx +16 -10
  197. package/src/views/TicketingSettingsView/client.tsx +90 -87
  198. package/src/views/TimeDashboardView/client.tsx +2 -2
  199. package/src/views/shared/StatusPill.tsx +24 -12
  200. package/src/views/shared/dateLocale.ts +5 -0
  201. package/src/views/shared/locales/en.json +708 -0
  202. package/src/views/shared/locales/fr.json +708 -0
@@ -9,141 +9,13 @@ import { CodeBlockInserter } from '../../components/TicketConversation/component
9
9
  import { getFeatures } from '../shared/config.js';
10
10
  import { computeSlaState, formatSlaRemaining } from '../shared/sla.js';
11
11
  import { useTranslation } from '../../components/TicketConversation/hooks/useTranslation.js';
12
+ import { DATE_LOCALE } from '../shared/dateLocale.js';
12
13
  import s from '../../styles/TicketDetail.module.scss';
14
+ import { STATUS_STYLE, ALIASES } from './constants.js';
15
+ import { dateLabel, timeAgo } from './helpers.js';
16
+ import { RewriteDropdown } from './RewriteDropdown.js';
17
+ import { NextActionItem } from './NextActionItem.js';
13
18
 
14
- const ALIASES = [
15
- { value: "Support Consilioweb", label: "En tant que : Support Consilioweb" },
16
- { value: "contact@consilioweb.fr", label: "En tant que : contact@consilioweb.fr" }
17
- ];
18
- const STATUS_STYLE = {
19
- open: { bg: "#dbeafe", color: "#1e40af" },
20
- waiting_client: { bg: "#fef3c7", color: "#92400e" },
21
- resolved: { bg: "#dcfce7", color: "#166534" }
22
- };
23
- function timeAgo(d) {
24
- const date = new Date(d), now = /* @__PURE__ */ new Date();
25
- if (date.toDateString() === now.toDateString()) return date.toLocaleTimeString("fr-FR", { hour: "2-digit", minute: "2-digit" });
26
- const y = new Date(now);
27
- y.setDate(y.getDate() - 1);
28
- if (date.toDateString() === y.toDateString()) return `Hier, ${date.toLocaleTimeString("fr-FR", { hour: "2-digit", minute: "2-digit" })}`;
29
- return date.toLocaleDateString("fr-FR", { day: "numeric", month: "short", hour: "2-digit", minute: "2-digit" });
30
- }
31
- function dateLabel(d) {
32
- const date = new Date(d), now = /* @__PURE__ */ new Date();
33
- if (date.toDateString() === now.toDateString()) return "Aujourd'hui";
34
- const y = new Date(now);
35
- y.setDate(y.getDate() - 1);
36
- if (date.toDateString() === y.toDateString()) return "Hier";
37
- return date.toLocaleDateString("fr-FR", { day: "numeric", month: "long" });
38
- }
39
- const REWRITE_STYLES = [
40
- { id: "auto", label: "\u270F\uFE0F Auto", desc: "Garde le ton actuel" },
41
- { id: "tutoyer", label: "\u{1F44B} Tutoyer", desc: "Passe en tu" },
42
- { id: "vouvoyer", label: "\u{1F3A9} Vouvoyer", desc: "Passe en vous" },
43
- { id: "formel", label: "\u{1F4BC} Formel", desc: "Ton professionnel" },
44
- { id: "amical", label: "\u{1F60A} Amical", desc: "Ton chaleureux" },
45
- { id: "court", label: "\u26A1 Court", desc: "Version concise" }
46
- ];
47
- const RewriteDropdown = ({ disabled, loading, onSelect, toolbarBtnClass }) => {
48
- const [open, setOpen] = useState(false);
49
- const ref = useRef(null);
50
- useEffect(() => {
51
- if (!open) return;
52
- const close = (e) => {
53
- if (ref.current && !ref.current.contains(e.target)) setOpen(false);
54
- };
55
- document.addEventListener("mousedown", close);
56
- return () => document.removeEventListener("mousedown", close);
57
- }, [open]);
58
- return /* @__PURE__ */ jsxs("div", { ref, style: { position: "relative", display: "inline-block" }, children: [
59
- /* @__PURE__ */ jsxs(
60
- "button",
61
- {
62
- type: "button",
63
- className: toolbarBtnClass,
64
- onClick: () => setOpen(!open),
65
- disabled,
66
- style: { fontSize: 11, fontWeight: 700, padding: "4px 10px", width: "auto", display: "flex", alignItems: "center", gap: 4 },
67
- children: [
68
- loading ? "..." : "\u270F\uFE0F Reformuler",
69
- !loading && /* @__PURE__ */ jsx("span", { style: { fontSize: 9, opacity: 0.6 }, children: "\u25BC" })
70
- ]
71
- }
72
- ),
73
- open && !disabled && !loading && /* @__PURE__ */ jsx("div", { style: {
74
- position: "absolute",
75
- bottom: "100%",
76
- left: 0,
77
- marginBottom: 4,
78
- background: "#fff",
79
- border: "1px solid #e5e7eb",
80
- borderRadius: 8,
81
- boxShadow: "0 4px 16px rgba(0,0,0,0.12)",
82
- zIndex: 100,
83
- minWidth: 180,
84
- overflow: "hidden"
85
- }, children: REWRITE_STYLES.map((style) => /* @__PURE__ */ jsxs(
86
- "button",
87
- {
88
- type: "button",
89
- onClick: () => {
90
- setOpen(false);
91
- onSelect(style.id);
92
- },
93
- style: {
94
- display: "flex",
95
- flexDirection: "column",
96
- width: "100%",
97
- padding: "8px 12px",
98
- border: "none",
99
- background: "transparent",
100
- cursor: "pointer",
101
- textAlign: "left",
102
- borderBottom: "1px solid #f3f4f6"
103
- },
104
- onMouseEnter: (e) => {
105
- e.currentTarget.style.background = "#f9fafb";
106
- },
107
- onMouseLeave: (e) => {
108
- e.currentTarget.style.background = "transparent";
109
- },
110
- children: [
111
- /* @__PURE__ */ jsx("span", { style: { fontSize: 12, fontWeight: 600 }, children: style.label }),
112
- /* @__PURE__ */ jsx("span", { style: { fontSize: 10, color: "#9ca3af" }, children: style.desc })
113
- ]
114
- },
115
- style.id
116
- )) })
117
- ] });
118
- };
119
- function NextActionItem({ action, index, onToggle }) {
120
- const [pending, setPending] = useState(false);
121
- const labelMap = { now: "Maintenant", today: "Aujourd'hui", "this-week": "Cette semaine" };
122
- const done = !!action.done;
123
- return /* @__PURE__ */ jsxs("li", { className: s.aiCardNextAction, children: [
124
- /* @__PURE__ */ jsx(
125
- "button",
126
- {
127
- type: "button",
128
- className: `${s.aiCardNextCheck} ${done ? s.aiCardNextCheckDone : ""}`,
129
- onClick: async () => {
130
- setPending(true);
131
- try {
132
- await onToggle(!done);
133
- } finally {
134
- setPending(false);
135
- }
136
- },
137
- "aria-pressed": done,
138
- "aria-label": done ? "Marquer non fait" : "Marquer fait",
139
- disabled: pending,
140
- children: done && /* @__PURE__ */ jsx("span", { "aria-hidden": true, children: "\u2713" })
141
- }
142
- ),
143
- /* @__PURE__ */ jsx("span", { className: `${s.aiCardNextLabel} ${done ? s.aiCardNextLabelDone : ""}`, children: action.label }),
144
- /* @__PURE__ */ jsx("span", { className: s.aiCardNextWhen, children: labelMap[action.priority] || action.priority })
145
- ] });
146
- }
147
19
  const TicketDetailClient = () => {
148
20
  const { t } = useTranslation();
149
21
  const searchParams = useSearchParams();
@@ -703,7 +575,7 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
703
575
  const initials = client ? `${(client.firstName?.[0] || "").toUpperCase()}${(client.lastName?.[0] || "").toUpperCase()}` : "?";
704
576
  return /* @__PURE__ */ jsxs("div", { className: s.page, children: [
705
577
  /* @__PURE__ */ jsxs("div", { className: s.topBar, children: [
706
- /* @__PURE__ */ jsx(Link, { href: "/admin/support/inbox", className: s.backLink, "aria-label": "Retour \xE0 la bo\xEEte de r\xE9ception", children: "\u2190" }),
578
+ /* @__PURE__ */ jsx(Link, { href: "/admin/support/inbox", className: s.backLink, "aria-label": t("detail.backToInbox"), children: "\u2190" }),
707
579
  /* @__PURE__ */ jsxs("div", { className: s.ticketMeta, children: [
708
580
  /* @__PURE__ */ jsxs("span", { className: s.ticketNumber, children: [
709
581
  /* @__PURE__ */ jsx("span", { children: ticket.ticketNumber }),
@@ -756,7 +628,7 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
756
628
  });
757
629
  if (slaInfo.state !== "breach") return null;
758
630
  const duration = formatSlaRemaining(slaInfo.remainingMs).replace(/^−/, "");
759
- const target = slaInfo.due ? new Date(slaInfo.due).toLocaleString("fr-FR", { day: "2-digit", month: "short", hour: "2-digit", minute: "2-digit" }) : "";
631
+ const target = slaInfo.due ? new Date(slaInfo.due).toLocaleString(DATE_LOCALE, { day: "2-digit", month: "short", hour: "2-digit", minute: "2-digit" }) : "";
760
632
  return /* @__PURE__ */ jsxs("div", { className: s.slaBanner, role: "alert", children: [
761
633
  /* @__PURE__ */ jsx("span", { className: s.slaBannerIcon, "aria-hidden": true, children: /* @__PURE__ */ jsxs("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
762
634
  /* @__PURE__ */ jsx("path", { d: "M12 9v4M12 17h.01" }),
@@ -827,19 +699,19 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
827
699
  /* @__PURE__ */ jsxs("div", { className: s.messageHeader, children: [
828
700
  /* @__PURE__ */ jsx("span", { className: s.messageAuthor, children: msg.fromAlias || (isAdmin ? "Support" : msg.authorType === "email" ? "Email" : client?.firstName || "Client") }),
829
701
  /* @__PURE__ */ jsx("span", { className: s.messageTime, children: timeAgo(msg.createdAt) }),
830
- msg.isInternal && /* @__PURE__ */ jsx("span", { className: s.badge, style: { background: "#fef3c7", color: "#92400e" }, children: "Interne" }),
831
- msg.isSolution && /* @__PURE__ */ jsx("span", { className: s.badge, style: { background: "#dcfce7", color: "#166534" }, children: "Solution" }),
702
+ msg.isInternal && /* @__PURE__ */ jsx("span", { className: s.badge, style: { background: "#fef3c7", color: "#92400e" }, children: t("detail.badgeInternal") }),
703
+ msg.isSolution && /* @__PURE__ */ jsx("span", { className: s.badge, style: { background: "#dcfce7", color: "#166534" }, children: t("detail.badgeSolution") }),
832
704
  /* @__PURE__ */ jsx("span", { className: s.messageMeta, children: isAdmin && !msg.isInternal && (() => {
833
705
  const ext = msg;
834
706
  if (ext.emailOpenedAt) {
835
- const d = new Date(ext.emailOpenedAt).toLocaleString("fr-FR", { day: "numeric", month: "short", hour: "2-digit", minute: "2-digit" });
707
+ const d = new Date(ext.emailOpenedAt).toLocaleString(DATE_LOCALE, { day: "numeric", month: "short", hour: "2-digit", minute: "2-digit" });
836
708
  return /* @__PURE__ */ jsxs("span", { style: { color: "#16a34a", cursor: "help" }, title: `Ouvert le ${d}`, children: [
837
709
  "\u2713\u2713 Lu ",
838
710
  d
839
711
  ] });
840
712
  }
841
713
  if (ext.emailSentAt) {
842
- const d = new Date(ext.emailSentAt).toLocaleString("fr-FR", { day: "numeric", month: "short", hour: "2-digit", minute: "2-digit" });
714
+ const d = new Date(ext.emailSentAt).toLocaleString(DATE_LOCALE, { day: "numeric", month: "short", hour: "2-digit", minute: "2-digit" });
843
715
  return /* @__PURE__ */ jsxs("span", { style: { color: "#2563eb", cursor: "help" }, title: `Envoy\xE9 le ${d}`, children: [
844
716
  "\u2713 Envoy\xE9 ",
845
717
  d
@@ -858,7 +730,7 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
858
730
  setEditingHtml(html);
859
731
  setEditingBody(text);
860
732
  },
861
- placeholder: "\xC9diter le message...",
733
+ placeholder: t("detail.editPlaceholder"),
862
734
  minHeight: 120,
863
735
  onFileUpload: async (file) => {
864
736
  try {
@@ -876,8 +748,8 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
876
748
  }
877
749
  ),
878
750
  /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: 6, justifyContent: "flex-end" }, children: [
879
- /* @__PURE__ */ 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" }),
880
- /* @__PURE__ */ 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" })
751
+ /* @__PURE__ */ 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") }),
752
+ /* @__PURE__ */ 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") })
881
753
  ] })
882
754
  ] }) : msg.deletedAt ? /* @__PURE__ */ jsx("div", { className: s.messageBody, style: { color: "#94a3b8", fontStyle: "italic" }, children: t("detail.messageDeleted") }) : msg.bodyHtml && hasCodeBlocks(msg.bodyHtml.replace(/<[^>]+>/g, "")) ? /* @__PURE__ */ jsx(CodeBlockRendererHtml, { html: msg.bodyHtml }) : msg.bodyHtml ? /* @__PURE__ */ jsx("div", { className: `${s.messageBody} ${s.rteDisplay}`, dangerouslySetInnerHTML: { __html: msg.bodyHtml } }) : hasCodeBlocks(msg.body) ? /* @__PURE__ */ jsx(MessageWithCodeBlocks, { text: msg.body, style: { fontSize: "13px", lineHeight: 1.5 } }) : /* @__PURE__ */ jsx("div", { className: s.messageBody, children: msg.body }),
883
755
  Array.isArray(msg.attachments) && msg.attachments.length > 0 && /* @__PURE__ */ jsx("div", { className: s.attachments, children: msg.attachments.map((att, i) => {
@@ -890,7 +762,7 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
890
762
  }) })
891
763
  ] }),
892
764
  editingMsgId !== msg.id && !msg.deletedAt && /* @__PURE__ */ jsxs("div", { className: s.messageActions, children: [
893
- /* @__PURE__ */ jsx("button", { className: s.actionIcon, title: "\xC9diter", "aria-label": "\xC9diter le message", onClick: () => startEditMessage(msg), style: { fontSize: 11, width: "auto", padding: "4px 8px" }, children: "\xC9diter" }),
765
+ /* @__PURE__ */ jsx("button", { className: s.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") }),
894
766
  /* @__PURE__ */ jsx("button", { className: `${s.actionIcon} ${s.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") }),
895
767
  features.splitTicket && !msg.isInternal && /* @__PURE__ */ jsx("button", { className: s.actionIcon, title: t("actions.extractMessage"), "aria-label": t("actions.extractToNewTicket"), onClick: () => {
896
768
  setSplitModal({ messageId: msg.id, preview: msg.body.slice(0, 200) });
@@ -986,7 +858,7 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
986
858
  },
987
859
  disabled: applyingMacro,
988
860
  style: { marginLeft: 0 },
989
- "aria-label": "Appliquer une macro",
861
+ "aria-label": t("detail.macros"),
990
862
  children: [
991
863
  /* @__PURE__ */ jsx("option", { value: "", children: applyingMacro ? t("detail.applyingMacro") : t("detail.macros") }),
992
864
  macros.map((m) => /* @__PURE__ */ jsx("option", { value: m.id, children: m.name }, m.id))
@@ -994,7 +866,7 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
994
866
  }
995
867
  ),
996
868
  /* @__PURE__ */ jsx("span", { className: s.toolbarDivider }),
997
- features.canned && cannedResponses.length > 0 && /* @__PURE__ */ jsxs("select", { className: s.cannedSelect, "aria-label": "R\xE9ponses types", onChange: (e) => {
869
+ features.canned && cannedResponses.length > 0 && /* @__PURE__ */ jsxs("select", { className: s.cannedSelect, "aria-label": t("detail.cannedResponses"), onChange: (e) => {
998
870
  const cr = cannedResponses.find((c) => String(c.id) === e.target.value);
999
871
  if (cr) {
1000
872
  let b = cr.body;
@@ -1039,11 +911,8 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
1039
911
  }
1040
912
  ),
1041
913
  pendingFiles.length > 0 && /* @__PURE__ */ jsx("div", { className: s.uploadPreview, children: pendingFiles.map((f, i) => /* @__PURE__ */ jsxs("div", { className: s.uploadPreviewItem, children: [
1042
- /* @__PURE__ */ jsxs("span", { children: [
1043
- "PJ ",
1044
- f.name
1045
- ] }),
1046
- /* @__PURE__ */ jsx("button", { className: s.uploadRemoveBtn, "aria-label": `Retirer ${f.name}`, onClick: () => setPendingFiles((prev) => prev.filter((_, j) => j !== i)), children: "\xD7" })
914
+ /* @__PURE__ */ jsx("span", { children: t("detail.uploadItem", { name: f.name }) }),
915
+ /* @__PURE__ */ jsx("button", { className: s.uploadRemoveBtn, "aria-label": t("detail.removeUpload", { name: f.name }), onClick: () => setPendingFiles((prev) => prev.filter((_, j) => j !== i)), children: "\xD7" })
1047
916
  ] }, i)) })
1048
917
  ] }),
1049
918
  /* @__PURE__ */ jsxs("div", { className: s.composerFooter, children: [
@@ -1062,8 +931,8 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
1062
931
  },
1063
932
  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)" },
1064
933
  children: [
1065
- /* @__PURE__ */ jsx("option", { value: "admin", children: "En tant que : Support" }),
1066
- /* @__PURE__ */ jsx("option", { value: "client", children: "En tant que : Client" })
934
+ /* @__PURE__ */ jsx("option", { value: "admin", children: t("detail.sendAsSupport") }),
935
+ /* @__PURE__ */ jsx("option", { value: "client", children: t("detail.sendAsClient") })
1067
936
  ]
1068
937
  }
1069
938
  ),
@@ -1098,7 +967,7 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
1098
967
  /* @__PURE__ */ jsx("kbd", { children: "\u2318" }),
1099
968
  /* @__PURE__ */ jsx("kbd", { children: "\u21B5" })
1100
969
  ] }),
1101
- /* @__PURE__ */ jsx("button", { className: `${s.sendBtn} ${isInternal ? s.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") })
970
+ /* @__PURE__ */ jsx("button", { className: `${s.sendBtn} ${isInternal ? s.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") })
1102
971
  ] })
1103
972
  ]
1104
973
  }
@@ -1171,7 +1040,7 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
1171
1040
  clientSummary && clientSummary.summary && /* @__PURE__ */ jsxs("div", { className: `${s.sideSection} ${s.aiCard}`, children: [
1172
1041
  /* @__PURE__ */ jsxs("div", { className: s.aiCardTitle, children: [
1173
1042
  /* @__PURE__ */ jsx("span", { className: s.aiCardIcon, "aria-hidden": true, children: "\u2728" }),
1174
- "Synth\xE8se client"
1043
+ t("detail.aiCard.title")
1175
1044
  ] }),
1176
1045
  /* @__PURE__ */ jsx("p", { className: s.aiCardLead, children: clientSummary.summary }),
1177
1046
  clientSummary.recurringTopics && clientSummary.recurringTopics.length > 0 && /* @__PURE__ */ jsx("div", { className: s.aiCardChips, children: clientSummary.recurringTopics.slice(0, 5).map((tp, i) => /* @__PURE__ */ jsx("span", { className: s.aiChip, children: tp.topic }, `tp-${i}`)) }),
@@ -1250,12 +1119,12 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
1250
1119
  ":",
1251
1120
  String(timerSeconds % 60).padStart(2, "0")
1252
1121
  ] }),
1253
- !timerRunning ? /* @__PURE__ */ jsx("button", { className: s.timerBtn, onClick: () => setTimerRunning(true), "aria-label": "D\xE9marrer le timer", children: timerSeconds > 0 ? "\u25B6" : "\u25B6 Go" }) : /* @__PURE__ */ jsx("button", { className: `${s.timerBtn} ${s.timerBtnRunning}`, onClick: () => setTimerRunning(false), "aria-label": "Mettre en pause le timer", children: "\u23F8 Pause" }),
1122
+ !timerRunning ? /* @__PURE__ */ jsx("button", { className: s.timerBtn, onClick: () => setTimerRunning(true), "aria-label": t("detail.timerStart"), children: timerSeconds > 0 ? "\u25B6" : "\u25B6 Go" }) : /* @__PURE__ */ jsx("button", { className: `${s.timerBtn} ${s.timerBtnRunning}`, onClick: () => setTimerRunning(false), "aria-label": t("detail.timerPause"), children: "\u23F8 Pause" }),
1254
1123
  timerSeconds >= 60 && !timerRunning && /* @__PURE__ */ jsxs("button", { className: `${s.timerBtn} ${s.timerBtnGhost}`, onClick: () => {
1255
1124
  handleTimerSave();
1256
1125
  localStorage.removeItem(`timer-sec-${ticketId}`);
1257
1126
  localStorage.removeItem(`timer-run-${ticketId}`);
1258
- }, "aria-label": "Sauvegarder le temps", children: [
1127
+ }, "aria-label": t("detail.timerSave"), children: [
1259
1128
  "\u{1F4BE} ",
1260
1129
  Math.round(timerSeconds / 60),
1261
1130
  "m"
@@ -1274,11 +1143,11 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
1274
1143
  fetchAll();
1275
1144
  } catch {
1276
1145
  }
1277
- }, style: { fontSize: 11 }, children: "+ Ajouter" })
1146
+ }, style: { fontSize: 11 }, children: t("detail.addTime") })
1278
1147
  ] }),
1279
1148
  /* @__PURE__ */ jsxs("div", { style: { marginTop: 8, fontSize: 11, color: "var(--theme-elevation-500)" }, children: [
1280
1149
  /* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between", padding: "2px 0", alignItems: "center" }, children: [
1281
- /* @__PURE__ */ jsx("span", { children: "Facturable" }),
1150
+ /* @__PURE__ */ jsx("span", { children: t("detail.billing.billable") }),
1282
1151
  /* @__PURE__ */ jsx(
1283
1152
  "button",
1284
1153
  {
@@ -1291,12 +1160,12 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
1291
1160
  }
1292
1161
  },
1293
1162
  style: { fontWeight: 600, color: ticket.billable !== false ? "#16a34a" : "#dc2626", background: "none", border: "none", cursor: "pointer", fontSize: 11, textDecoration: "underline" },
1294
- children: ticket.billable !== false ? "Oui" : "Non"
1163
+ children: ticket.billable !== false ? t("detail.billing.yes") : t("detail.billing.no")
1295
1164
  }
1296
1165
  )
1297
1166
  ] }),
1298
1167
  totalMin > 0 && /* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between", padding: "2px 0" }, children: [
1299
- /* @__PURE__ */ jsx("span", { children: "Montant estim\xE9" }),
1168
+ /* @__PURE__ */ jsx("span", { children: t("detail.billing.estimatedAmount") }),
1300
1169
  /* @__PURE__ */ jsxs("span", { style: { fontWeight: 700, color: "var(--theme-text)" }, children: [
1301
1170
  (totalMin / 60 * 60).toFixed(0),
1302
1171
  "\u20AC"
@@ -1304,7 +1173,7 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
1304
1173
  ] })
1305
1174
  ] }),
1306
1175
  timeEntries.length > 0 && /* @__PURE__ */ jsx("div", { style: { marginTop: 8, fontSize: 11 }, children: timeEntries.slice(0, 6).map((e) => /* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between", padding: "3px 0", color: "var(--theme-elevation-500)" }, children: [
1307
- /* @__PURE__ */ jsx("span", { children: new Date(e.date).toLocaleDateString("fr-FR", { day: "numeric", month: "short" }) }),
1176
+ /* @__PURE__ */ jsx("span", { children: new Date(e.date).toLocaleDateString(DATE_LOCALE, { day: "numeric", month: "short" }) }),
1308
1177
  /* @__PURE__ */ jsxs("span", { title: e.description, style: { fontWeight: 600, cursor: e.description ? "help" : "default" }, children: [
1309
1178
  e.duration,
1310
1179
  "min"
@@ -1316,7 +1185,7 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
1316
1185
  /* @__PURE__ */ jsxs("div", { className: s.tagsWrap, children: [
1317
1186
  tags.map((tag) => /* @__PURE__ */ jsxs("span", { className: s.tagChip, children: [
1318
1187
  tag,
1319
- /* @__PURE__ */ jsx("button", { className: s.tagRemove, "aria-label": `Retirer le tag ${tag}`, onClick: () => handleRemoveTag(tag), children: "\xD7" })
1188
+ /* @__PURE__ */ jsx("button", { className: s.tagRemove, "aria-label": t("detail.removeTag", { tag }), onClick: () => handleRemoveTag(tag), children: "\xD7" })
1320
1189
  ] }, tag)),
1321
1190
  addingTag ? /* @__PURE__ */ jsx(
1322
1191
  "input",
@@ -1332,17 +1201,17 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
1332
1201
  }
1333
1202
  },
1334
1203
  onBlur: handleAddTag,
1335
- placeholder: "Tag...",
1204
+ placeholder: t("detail.tagPlaceholder"),
1336
1205
  autoFocus: true
1337
1206
  }
1338
- ) : /* @__PURE__ */ jsx("button", { className: s.tagAddBtn, onClick: () => setAddingTag(true), "aria-label": "Ajouter un tag", children: "+ Tag" })
1207
+ ) : /* @__PURE__ */ jsx("button", { className: s.tagAddBtn, onClick: () => setAddingTag(true), "aria-label": t("detail.addTag"), children: t("detail.addTagBtn") })
1339
1208
  ] })
1340
1209
  ] }),
1341
1210
  /* @__PURE__ */ jsxs("div", { className: s.sideSection, children: [
1342
- /* @__PURE__ */ jsx("div", { className: s.sideSectionTitle, children: "Facturation" }),
1211
+ /* @__PURE__ */ jsx("div", { className: s.sideSectionTitle, children: t("detail.billing.title") }),
1343
1212
  /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: 8 }, children: [
1344
1213
  /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between" }, children: [
1345
- /* @__PURE__ */ jsx("span", { style: { fontSize: 12 }, children: "Type" }),
1214
+ /* @__PURE__ */ jsx("span", { style: { fontSize: 12 }, children: t("detail.billing.type") }),
1346
1215
  /* @__PURE__ */ jsxs(
1347
1216
  "select",
1348
1217
  {
@@ -1361,14 +1230,14 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
1361
1230
  },
1362
1231
  style: { fontSize: 12, padding: "4px 8px", borderRadius: 6, border: "1px solid #e5e7eb", background: "#fff" },
1363
1232
  children: [
1364
- /* @__PURE__ */ jsx("option", { value: "hourly", children: "Au temps" }),
1365
- /* @__PURE__ */ jsx("option", { value: "flat", children: "Forfait" })
1233
+ /* @__PURE__ */ jsx("option", { value: "hourly", children: t("detail.billing.hourly") }),
1234
+ /* @__PURE__ */ jsx("option", { value: "flat", children: t("detail.billing.flat") })
1366
1235
  ]
1367
1236
  }
1368
1237
  )
1369
1238
  ] }),
1370
1239
  ticket?.billingType === "flat" && /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between" }, children: [
1371
- /* @__PURE__ */ jsx("span", { style: { fontSize: 12 }, children: "Montant forfait" }),
1240
+ /* @__PURE__ */ jsx("span", { style: { fontSize: 12 }, children: t("detail.billing.flatAmount") }),
1372
1241
  /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: 4 }, children: [
1373
1242
  /* @__PURE__ */ jsx(
1374
1243
  "input",
@@ -1396,7 +1265,7 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
1396
1265
  ] })
1397
1266
  ] }),
1398
1267
  /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between" }, children: [
1399
- /* @__PURE__ */ jsx("span", { style: { fontSize: 12 }, children: "Montant factur\xE9" }),
1268
+ /* @__PURE__ */ jsx("span", { style: { fontSize: 12 }, children: t("detail.billing.billedAmount") }),
1400
1269
  /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: 4 }, children: [
1401
1270
  /* @__PURE__ */ jsx(
1402
1271
  "input",
@@ -1424,7 +1293,7 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
1424
1293
  ] })
1425
1294
  ] }),
1426
1295
  /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between" }, children: [
1427
- /* @__PURE__ */ jsx("span", { style: { fontSize: 12 }, children: "Paiement" }),
1296
+ /* @__PURE__ */ jsx("span", { style: { fontSize: 12 }, children: t("detail.billing.payment") }),
1428
1297
  /* @__PURE__ */ jsxs(
1429
1298
  "select",
1430
1299
  {
@@ -1443,16 +1312,16 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
1443
1312
  },
1444
1313
  style: { fontSize: 12, padding: "4px 8px", borderRadius: 6, border: "1px solid #e5e7eb", background: "#fff" },
1445
1314
  children: [
1446
- /* @__PURE__ */ jsx("option", { value: "unpaid", children: "Non pay\xE9" }),
1447
- /* @__PURE__ */ jsx("option", { value: "partial", children: "Partiel" }),
1448
- /* @__PURE__ */ jsx("option", { value: "paid", children: "Pay\xE9" })
1315
+ /* @__PURE__ */ jsx("option", { value: "unpaid", children: t("detail.billing.unpaid") }),
1316
+ /* @__PURE__ */ jsx("option", { value: "partial", children: t("detail.billing.partial") }),
1317
+ /* @__PURE__ */ jsx("option", { value: "paid", children: t("detail.billing.paid") })
1449
1318
  ]
1450
1319
  }
1451
1320
  )
1452
1321
  ] })
1453
1322
  ] })
1454
1323
  ] }),
1455
- summaryLoading && /* @__PURE__ */ jsx("div", { className: s.sideSection, children: /* @__PURE__ */ jsx("div", { style: { fontSize: 11, color: "var(--theme-elevation-400)", textAlign: "center", padding: 8 }, children: "\u2728 Chargement de la synth\xE8se\u2026" }) })
1324
+ summaryLoading && /* @__PURE__ */ jsx("div", { className: s.sideSection, children: /* @__PURE__ */ jsx("div", { style: { fontSize: 11, color: "var(--theme-elevation-400)", textAlign: "center", padding: 8 }, children: t("detail.loadingSummary") }) })
1456
1325
  ] }),
1457
1326
  sidebarTab === "client" && /* @__PURE__ */ jsxs("div", { role: "tabpanel", id: "sidebar-panel-client", "aria-labelledby": "sidebar-tab-client", children: [
1458
1327
  client && /* @__PURE__ */ jsxs("div", { className: s.sideSection, children: [
@@ -1480,7 +1349,7 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
1480
1349
  /* @__PURE__ */ jsx("span", { className: s.previousTicketsSubject, children: pt.subject || `#${pt.id}` }),
1481
1350
  /* @__PURE__ */ jsxs("span", { className: s.previousTicketsMeta, children: [
1482
1351
  pt.status ? /* @__PURE__ */ jsx("span", { className: s.previousTicketsStatus, children: pt.status }) : null,
1483
- /* @__PURE__ */ jsx("span", { className: s.previousTicketsDate, children: new Date(pt.createdAt).toLocaleDateString("fr-FR", { day: "numeric", month: "short", year: "numeric" }) })
1352
+ /* @__PURE__ */ jsx("span", { className: s.previousTicketsDate, children: new Date(pt.createdAt).toLocaleDateString(DATE_LOCALE, { day: "numeric", month: "short", year: "numeric" }) })
1484
1353
  ] })
1485
1354
  ] }) }, pt.id)) })
1486
1355
  ] })
@@ -1498,16 +1367,16 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
1498
1367
  ] })
1499
1368
  ] }),
1500
1369
  undoToast && /* @__PURE__ */ jsxs("div", { className: s.undoToast, role: "alert", children: [
1501
- /* @__PURE__ */ jsx("span", { children: "Message supprim\xE9" }),
1502
- /* @__PURE__ */ jsx("button", { className: s.undoBtn, onClick: handleUndoDelete, children: "Annuler" })
1370
+ /* @__PURE__ */ jsx("span", { children: t("detail.messageDeletedToast") }),
1371
+ /* @__PURE__ */ jsx("button", { className: s.undoBtn, onClick: handleUndoDelete, children: t("common.cancel") })
1503
1372
  ] }),
1504
1373
  splitModal && /* @__PURE__ */ jsx("div", { className: s.splitOverlay, onClick: (e) => {
1505
1374
  if (e.target === e.currentTarget) {
1506
1375
  setSplitModal(null);
1507
1376
  setSplitSubject("");
1508
1377
  }
1509
- }, children: /* @__PURE__ */ jsxs("div", { className: s.splitModal, role: "dialog", "aria-label": "Extraire dans un nouveau ticket", children: [
1510
- /* @__PURE__ */ jsx("h3", { className: s.splitTitle, children: "Extraire dans un nouveau ticket" }),
1378
+ }, children: /* @__PURE__ */ jsxs("div", { className: s.splitModal, role: "dialog", "aria-label": t("actions.extractToNewTicket"), children: [
1379
+ /* @__PURE__ */ jsx("h3", { className: s.splitTitle, children: t("actions.extractToNewTicket") }),
1511
1380
  /* @__PURE__ */ jsx("div", { className: s.splitPreview, children: splitModal.preview }),
1512
1381
  /* @__PURE__ */ jsx(
1513
1382
  "input",
@@ -1518,7 +1387,7 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
1518
1387
  onKeyDown: (e) => {
1519
1388
  if (e.key === "Enter") handleSplitConfirm();
1520
1389
  },
1521
- placeholder: "Sujet du nouveau ticket...",
1390
+ placeholder: t("detail.split.subjectPlaceholder"),
1522
1391
  autoFocus: true
1523
1392
  }
1524
1393
  ),
@@ -1526,8 +1395,8 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
1526
1395
  /* @__PURE__ */ jsx("button", { className: s.splitCancelBtn, onClick: () => {
1527
1396
  setSplitModal(null);
1528
1397
  setSplitSubject("");
1529
- }, children: "Annuler" }),
1530
- /* @__PURE__ */ jsx("button", { className: s.splitConfirmBtn, onClick: handleSplitConfirm, disabled: !splitSubject.trim(), children: "Cr\xE9er le ticket" })
1398
+ }, children: t("common.cancel") }),
1399
+ /* @__PURE__ */ jsx("button", { className: s.splitConfirmBtn, onClick: handleSplitConfirm, disabled: !splitSubject.trim(), children: t("detail.split.createBtn") })
1531
1400
  ] })
1532
1401
  ] }) })
1533
1402
  ] });
@@ -0,0 +1,20 @@
1
+ 'use strict';
2
+
3
+ const ALIASES = (process.env.NEXT_PUBLIC_SUPPORT_SEND_ALIASES || "").split(",").map((v) => v.trim()).filter(Boolean).map((value) => ({ value, label: `En tant que : ${value}` }));
4
+ const STATUS_STYLE = {
5
+ open: { bg: "#dbeafe", color: "#1e40af" },
6
+ waiting_client: { bg: "#fef3c7", color: "#92400e" },
7
+ resolved: { bg: "#dcfce7", color: "#166534" }
8
+ };
9
+ const REWRITE_STYLES = [
10
+ { id: "auto", label: "\u270F\uFE0F Auto", desc: "Garde le ton actuel" },
11
+ { id: "tutoyer", label: "\u{1F44B} Tutoyer", desc: "Passe en tu" },
12
+ { id: "vouvoyer", label: "\u{1F3A9} Vouvoyer", desc: "Passe en vous" },
13
+ { id: "formel", label: "\u{1F4BC} Formel", desc: "Ton professionnel" },
14
+ { id: "amical", label: "\u{1F60A} Amical", desc: "Ton chaleureux" },
15
+ { id: "court", label: "\u26A1 Court", desc: "Version concise" }
16
+ ];
17
+
18
+ exports.ALIASES = ALIASES;
19
+ exports.REWRITE_STYLES = REWRITE_STYLES;
20
+ exports.STATUS_STYLE = STATUS_STYLE;
@@ -0,0 +1,16 @@
1
+ const ALIASES = (process.env.NEXT_PUBLIC_SUPPORT_SEND_ALIASES || "").split(",").map((v) => v.trim()).filter(Boolean).map((value) => ({ value, label: `En tant que : ${value}` }));
2
+ const STATUS_STYLE = {
3
+ open: { bg: "#dbeafe", color: "#1e40af" },
4
+ waiting_client: { bg: "#fef3c7", color: "#92400e" },
5
+ resolved: { bg: "#dcfce7", color: "#166534" }
6
+ };
7
+ const REWRITE_STYLES = [
8
+ { id: "auto", label: "\u270F\uFE0F Auto", desc: "Garde le ton actuel" },
9
+ { id: "tutoyer", label: "\u{1F44B} Tutoyer", desc: "Passe en tu" },
10
+ { id: "vouvoyer", label: "\u{1F3A9} Vouvoyer", desc: "Passe en vous" },
11
+ { id: "formel", label: "\u{1F4BC} Formel", desc: "Ton professionnel" },
12
+ { id: "amical", label: "\u{1F60A} Amical", desc: "Ton chaleureux" },
13
+ { id: "court", label: "\u26A1 Court", desc: "Version concise" }
14
+ ];
15
+
16
+ export { ALIASES, REWRITE_STYLES, STATUS_STYLE };
@@ -0,0 +1,23 @@
1
+ 'use strict';
2
+
3
+ var dateLocale = require('../shared/dateLocale');
4
+
5
+ function timeAgo(d) {
6
+ const date = new Date(d), now = /* @__PURE__ */ new Date();
7
+ if (date.toDateString() === now.toDateString()) return date.toLocaleTimeString(dateLocale.DATE_LOCALE, { hour: "2-digit", minute: "2-digit" });
8
+ const y = new Date(now);
9
+ y.setDate(y.getDate() - 1);
10
+ if (date.toDateString() === y.toDateString()) return `Hier, ${date.toLocaleTimeString(dateLocale.DATE_LOCALE, { hour: "2-digit", minute: "2-digit" })}`;
11
+ return date.toLocaleDateString(dateLocale.DATE_LOCALE, { day: "numeric", month: "short", hour: "2-digit", minute: "2-digit" });
12
+ }
13
+ function dateLabel(d) {
14
+ const date = new Date(d), now = /* @__PURE__ */ new Date();
15
+ if (date.toDateString() === now.toDateString()) return "Aujourd'hui";
16
+ const y = new Date(now);
17
+ y.setDate(y.getDate() - 1);
18
+ if (date.toDateString() === y.toDateString()) return "Hier";
19
+ return date.toLocaleDateString(dateLocale.DATE_LOCALE, { day: "numeric", month: "long" });
20
+ }
21
+
22
+ exports.dateLabel = dateLabel;
23
+ exports.timeAgo = timeAgo;
@@ -0,0 +1,20 @@
1
+ import { DATE_LOCALE } from '../shared/dateLocale.js';
2
+
3
+ function timeAgo(d) {
4
+ const date = new Date(d), now = /* @__PURE__ */ new Date();
5
+ if (date.toDateString() === now.toDateString()) return date.toLocaleTimeString(DATE_LOCALE, { hour: "2-digit", minute: "2-digit" });
6
+ const y = new Date(now);
7
+ y.setDate(y.getDate() - 1);
8
+ if (date.toDateString() === y.toDateString()) return `Hier, ${date.toLocaleTimeString(DATE_LOCALE, { hour: "2-digit", minute: "2-digit" })}`;
9
+ return date.toLocaleDateString(DATE_LOCALE, { day: "numeric", month: "short", hour: "2-digit", minute: "2-digit" });
10
+ }
11
+ function dateLabel(d) {
12
+ const date = new Date(d), now = /* @__PURE__ */ new Date();
13
+ if (date.toDateString() === now.toDateString()) return "Aujourd'hui";
14
+ const y = new Date(now);
15
+ y.setDate(y.getDate() - 1);
16
+ if (date.toDateString() === y.toDateString()) return "Hier";
17
+ return date.toLocaleDateString(DATE_LOCALE, { day: "numeric", month: "long" });
18
+ }
19
+
20
+ export { dateLabel, timeAgo };
@@ -0,0 +1,2 @@
1
+ 'use strict';
2
+