@consilioweb/payload-support 0.9.12 → 0.10.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.
@@ -18,9 +18,21 @@
18
18
 
19
19
  .title {
20
20
  font-size: 24px;
21
- font-weight: 800;
21
+ font-weight: 700;
22
22
  color: var(--theme-text);
23
23
  margin: 0;
24
+ line-height: 1.2;
25
+ }
26
+
27
+ .subtitle {
28
+ font-size: 13px;
29
+ color: var(--theme-elevation-500);
30
+ margin: 2px 0 0;
31
+ }
32
+
33
+ .subtitleBreach {
34
+ color: var(--theme-error-500, #c4392c);
35
+ font-weight: 600;
24
36
  }
25
37
 
26
38
  .headerRight {
@@ -56,8 +68,8 @@
56
68
 
57
69
  &:focus {
58
70
  outline: none;
59
- border-color: #2563eb;
60
- box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.08);
71
+ border-color: var(--theme-info-500, #2a6bd8);
72
+ box-shadow: 0 0 0 3px color-mix(in srgb, var(--theme-info-500, #2a6bd8) 18%, transparent);
61
73
  }
62
74
 
63
75
  &::placeholder { color: var(--theme-elevation-400); }
@@ -78,50 +90,84 @@
78
90
  .newTicketBtn {
79
91
  padding: 8px 18px;
80
92
  border-radius: 8px;
81
- border: 1px solid var(--theme-elevation-200);
82
- background: var(--theme-elevation-0, #fff);
83
- color: var(--theme-text);
93
+ border: 1px solid var(--theme-text);
94
+ background: var(--theme-text);
95
+ color: var(--theme-bg, #fff);
84
96
  font-size: 13px;
85
97
  font-weight: 600;
86
98
  cursor: pointer;
87
99
  transition: all 100ms;
88
100
  text-decoration: none;
89
- &:hover { background: var(--theme-elevation-100); }
101
+ &:hover {
102
+ background: var(--theme-elevation-800);
103
+ border-color: var(--theme-elevation-800);
104
+ }
90
105
  }
91
106
 
92
- // Filter tabs
107
+ // Filter tabs / segments
93
108
  .tabs {
94
- display: flex;
109
+ display: inline-flex;
110
+ align-items: center;
95
111
  gap: 0;
96
- border-bottom: 1px solid var(--theme-elevation-150, #f1f5f9);
97
- margin-bottom: 0;
112
+ background: var(--theme-elevation-100);
113
+ border: 1px solid var(--theme-elevation-200);
114
+ border-radius: 8px;
115
+ padding: 2px;
116
+ margin: 4px 0 6px;
117
+ flex-wrap: wrap;
98
118
  }
99
119
 
100
120
  .tab {
101
- padding: 10px 16px;
121
+ display: inline-flex;
122
+ align-items: center;
123
+ gap: 6px;
124
+ height: 30px;
125
+ padding: 0 12px;
102
126
  font-size: 13px;
103
- font-weight: 600;
127
+ font-weight: 500;
104
128
  color: var(--theme-elevation-500);
105
129
  background: none;
106
130
  border: none;
107
- border-bottom: 2px solid transparent;
131
+ border-radius: 6px;
108
132
  cursor: pointer;
109
- transition: all 100ms;
133
+ transition: background 100ms, color 100ms;
110
134
  white-space: nowrap;
111
135
 
112
136
  &:hover { color: var(--theme-text); }
113
137
 
114
138
  &.tabActive {
115
139
  color: var(--theme-text);
116
- border-bottom-color: #2563eb;
140
+ background: var(--theme-elevation-0, #fff);
141
+ box-shadow: 0 1px 0 rgba(0, 0, 0, 0.04);
142
+ }
143
+
144
+ &.tabAlert:not(.tabActive) {
145
+ color: var(--theme-error-500, #c4392c);
117
146
  }
118
147
  }
119
148
 
120
149
  .tabCount {
150
+ display: inline-flex;
151
+ align-items: center;
152
+ justify-content: center;
153
+ min-width: 18px;
154
+ height: 18px;
155
+ padding: 0 6px;
121
156
  font-size: 11px;
122
- font-weight: 700;
123
- color: var(--theme-elevation-400);
124
- margin-left: 4px;
157
+ font-weight: 600;
158
+ color: var(--theme-elevation-500);
159
+ background: var(--theme-elevation-200);
160
+ border-radius: 999px;
161
+ }
162
+
163
+ .tabActive .tabCount {
164
+ background: var(--theme-elevation-100);
165
+ color: var(--theme-text);
166
+ }
167
+
168
+ .tabCountAlert {
169
+ color: var(--theme-error-500, #c4392c) !important;
170
+ background: color-mix(in srgb, var(--theme-error-500, #c4392c) 12%, transparent) !important;
125
171
  }
126
172
 
127
173
  .sortRow {
@@ -147,54 +193,73 @@
147
193
  flex-direction: column;
148
194
  }
149
195
 
196
+ // Layout : check | priority-dot | StatusPill | ticket# | subject | client | sla | updated | unread
150
197
  .row {
151
198
  display: grid;
152
- grid-template-columns: 18px 16px 70px 50px 1fr 180px 100px 80px 100px 12px;
153
- gap: 10px;
199
+ grid-template-columns: 18px 12px 110px 80px 1fr 200px 90px 90px 12px;
200
+ gap: 12px;
154
201
  align-items: center;
155
- padding: 11px 12px;
156
- border-bottom: 1px solid var(--theme-elevation-100, #f8fafc);
202
+ padding: 10px 14px;
203
+ border-bottom: 1px solid var(--theme-elevation-100, #f3f3f3);
157
204
  cursor: pointer;
158
- transition: background 60ms;
205
+ transition: background 80ms ease;
159
206
  text-decoration: none;
160
207
  color: inherit;
208
+ position: relative;
161
209
 
162
210
  &:hover { background: var(--theme-elevation-50); }
163
211
 
164
212
  @media (max-width: 900px) {
165
- grid-template-columns: 16px 60px 1fr 100px 80px;
213
+ grid-template-columns: 16px 110px 1fr 80px 80px;
166
214
  }
167
215
  }
168
216
 
169
217
  .rowSelected {
170
- background: #eff6ff;
171
- border-left: 3px solid #2563eb;
172
- padding-left: 9px;
218
+ background: var(--theme-elevation-100);
219
+ }
220
+
221
+ .rowUnread {
222
+ background: linear-gradient(90deg, color-mix(in srgb, var(--theme-info-500, #2a6bd8) 8%, transparent) 0, transparent 6px);
223
+
224
+ .subject { font-weight: 700; }
173
225
  }
174
226
 
175
- .statusDot {
227
+ .rowBreach::before {
228
+ content: '';
229
+ position: absolute;
230
+ left: 0;
231
+ top: 0;
232
+ bottom: 0;
233
+ width: 3px;
234
+ background: var(--theme-error-500, #c4392c);
235
+ }
236
+
237
+ .rowCheck {
238
+ width: 14px;
239
+ height: 14px;
240
+ cursor: pointer;
241
+ accent-color: var(--theme-text);
242
+ }
243
+
244
+ .priorityDot {
245
+ display: inline-block;
176
246
  width: 8px;
177
247
  height: 8px;
178
248
  border-radius: 50%;
179
249
  flex-shrink: 0;
180
250
  }
181
251
 
182
- .statusText {
183
- font-size: 12px;
184
- font-weight: 600;
185
- color: var(--theme-elevation-500);
186
- }
187
-
188
252
  .ticketNum {
189
253
  font-family: 'SF Mono', 'Fira Code', 'JetBrains Mono', 'Cascadia Code', monospace;
190
254
  font-size: 11px;
191
255
  color: var(--theme-elevation-400);
192
256
  font-weight: 500;
257
+ letter-spacing: 0.02em;
193
258
  }
194
259
 
195
260
  .subject {
196
261
  font-size: 13px;
197
- font-weight: 600;
262
+ font-weight: 500;
198
263
  color: var(--theme-text);
199
264
  overflow: hidden;
200
265
  text-overflow: ellipsis;
@@ -209,35 +274,32 @@
209
274
  white-space: nowrap;
210
275
  }
211
276
 
212
- .categoryChip {
277
+ // SLA cell — color reflects state (computed in computeSlaState)
278
+ .slaCell {
213
279
  font-size: 11px;
214
- font-weight: 600;
215
- color: var(--theme-elevation-500);
216
- padding: 2px 8px;
217
- border-radius: 4px;
218
- background: var(--theme-elevation-100);
280
+ font-weight: 500;
281
+ font-variant-numeric: tabular-nums;
282
+ text-align: right;
283
+ color: var(--theme-elevation-400);
219
284
  white-space: nowrap;
220
285
  }
221
-
222
- .priorityBar {
223
- width: 4px;
224
- height: 18px;
225
- border-radius: 2px;
226
- flex-shrink: 0;
227
- }
286
+ .slaOk { color: var(--theme-elevation-400); }
287
+ .slaWarn { color: var(--theme-warning-500, #c97a0a); font-weight: 600; }
288
+ .slaBreach { color: var(--theme-error-500, #c4392c); font-weight: 700; }
228
289
 
229
290
  .timeAgo {
230
291
  font-size: 12px;
231
292
  color: var(--theme-elevation-400);
232
293
  white-space: nowrap;
233
294
  text-align: right;
295
+ font-variant-numeric: tabular-nums;
234
296
  }
235
297
 
236
298
  .unreadDot {
237
299
  width: 7px;
238
300
  height: 7px;
239
301
  border-radius: 50%;
240
- background: #2563eb;
302
+ background: var(--theme-info-500, #2a6bd8);
241
303
  flex-shrink: 0;
242
304
  }
243
305
 
@@ -8,6 +8,7 @@ var index = require('../../components/RichTextEditor/index');
8
8
  var CodeBlock = require('../../components/TicketConversation/components/CodeBlock');
9
9
  var CodeBlockInserter = require('../../components/TicketConversation/components/CodeBlockInserter');
10
10
  var config = require('../shared/config');
11
+ var sla = require('../shared/sla');
11
12
  var useTranslation = require('../../components/TicketConversation/hooks/useTranslation');
12
13
  var s = require('../../styles/TicketDetail.module.scss');
13
14
 
@@ -669,6 +670,46 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
669
670
  ] })
670
671
  ] })
671
672
  ] }),
673
+ (() => {
674
+ const slaInfo = sla.computeSlaState({
675
+ slaFirstResponseDue: ticket.slaFirstResponseDue,
676
+ slaFirstResponseBreached: ticket.slaFirstResponseBreached,
677
+ slaResolutionDue: ticket.slaResolutionDue,
678
+ slaResolutionBreached: ticket.slaResolutionBreached,
679
+ firstResponseAt: ticket.firstResponseAt
680
+ });
681
+ if (slaInfo.state !== "breach") return null;
682
+ const duration = sla.formatSlaRemaining(slaInfo.remainingMs).replace(/^−/, "");
683
+ const target = slaInfo.due ? new Date(slaInfo.due).toLocaleString("fr-FR", { day: "2-digit", month: "short", hour: "2-digit", minute: "2-digit" }) : "";
684
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: s__default.default.slaBanner, role: "alert", children: [
685
+ /* @__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: [
686
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 9v4M12 17h.01" }),
687
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M10.3 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z" })
688
+ ] }) }),
689
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: s__default.default.slaBannerBody, children: [
690
+ /* @__PURE__ */ jsxRuntime.jsx("strong", { children: t("inbox.slaBanner.breached") }),
691
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: s__default.default.slaBannerSep, children: "\u2014" }),
692
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: t("inbox.slaBanner.responseAwaitedFor", { duration }) }),
693
+ target && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: s__default.default.slaBannerTarget, children: [
694
+ "\xB7 ",
695
+ t("inbox.slaBanner.target", { target })
696
+ ] })
697
+ ] }),
698
+ /* @__PURE__ */ jsxRuntime.jsxs(
699
+ "button",
700
+ {
701
+ type: "button",
702
+ className: s__default.default.slaBannerCta,
703
+ onClick: () => handleStatusChange("escalated"),
704
+ "aria-label": t("inbox.slaBanner.escalate"),
705
+ children: [
706
+ "\u2191 ",
707
+ t("inbox.slaBanner.escalate")
708
+ ]
709
+ }
710
+ )
711
+ ] });
712
+ })(),
672
713
  otherViewers.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: {
673
714
  display: "flex",
674
715
  alignItems: "center",
@@ -695,8 +736,17 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
695
736
  const isPendingDelete = undoToast?.msgId === msg.id;
696
737
  return /* @__PURE__ */ jsxRuntime.jsxs(React__default.default.Fragment, { children: [
697
738
  showDate && /* @__PURE__ */ jsxRuntime.jsx("div", { className: s__default.default.dateSeparator, children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: s__default.default.dateSeparatorText, children: dateLabel(msg.createdAt) }) }),
698
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `${s__default.default.message} ${msg.isInternal ? s__default.default.messageInternal : ""}`, style: isPendingDelete ? { opacity: 0.3, pointerEvents: "none" } : void 0, children: [
699
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: s__default.default.avatar, style: { backgroundColor: isAdmin ? "#2563eb" : msg.authorType === "email" ? "#ea580c" : "#7c3aed" }, children: isAdmin ? "CW" : initials }),
739
+ /* @__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: [
740
+ /* @__PURE__ */ jsxRuntime.jsx(
741
+ "div",
742
+ {
743
+ className: s__default.default.avatar,
744
+ style: {
745
+ backgroundColor: isAdmin ? "var(--theme-info-500, #2a6bd8)" : msg.authorType === "email" ? "var(--theme-warning-500, #c97a0a)" : "var(--theme-accent-500, #6b46e8)"
746
+ },
747
+ children: isAdmin ? "CW" : initials
748
+ }
749
+ ),
700
750
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: s__default.default.messageContent, children: [
701
751
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: s__default.default.messageHeader, children: [
702
752
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: s__default.default.messageAuthor, children: isAdmin ? "Support" : msg.authorType === "email" ? "Email" : client?.firstName || "Client" }),
@@ -798,7 +848,17 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
798
848
  children: [
799
849
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: s__default.default.composerToolbar, children: [
800
850
  features.ai && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
801
- /* @__PURE__ */ jsxRuntime.jsx("button", { className: s__default.default.toolbarBtn, "data-tooltip": t("detail.iaSuggestion"), "aria-label": t("detail.iaSuggestion"), onClick: handleAiSuggest, disabled: aiReplying || messages.length === 0, style: { fontSize: 11, fontWeight: 700, padding: "4px 10px", width: "auto" }, children: aiReplying ? "..." : `\u2728 ${t("detail.iaSuggestion")}` }),
851
+ /* @__PURE__ */ jsxRuntime.jsx(
852
+ "button",
853
+ {
854
+ className: `${s__default.default.toolbarBtn} ${s__default.default.toolbarBtnAi}`,
855
+ "data-tooltip": t("detail.iaSuggestion"),
856
+ "aria-label": t("detail.iaSuggestion"),
857
+ onClick: handleAiSuggest,
858
+ disabled: aiReplying || messages.length === 0,
859
+ children: aiReplying ? "\u2026" : `\u2728 ${t("detail.iaSuggestion")}`
860
+ }
861
+ ),
802
862
  /* @__PURE__ */ jsxRuntime.jsx(RewriteDropdown, { disabled: aiRewriting || !replyBody.trim(), loading: aiRewriting, onSelect: (style) => handleAiRewrite(style), toolbarBtnClass: s__default.default.toolbarBtn })
803
863
  ] }),
804
864
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -921,6 +981,10 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
921
981
  ] })
922
982
  ] })
923
983
  ] }),
984
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: s__default.default.sendShortcut, "aria-hidden": true, children: [
985
+ /* @__PURE__ */ jsxRuntime.jsx("kbd", { children: "\u2318" }),
986
+ /* @__PURE__ */ jsxRuntime.jsx("kbd", { children: "\u21B5" })
987
+ ] }),
924
988
  /* @__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") })
925
989
  ] })
926
990
  ]
@@ -946,6 +1010,18 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
946
1010
  /* @__PURE__ */ jsxRuntime.jsx("button", { className: s__default.default.smallBtn, onClick: () => window.open(`/api/admin/impersonate?clientId=${client.id}`, "_blank"), children: t("client.clientPortal") })
947
1011
  ] })
948
1012
  ] }),
1013
+ clientSummary && clientSummary.summary && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `${s__default.default.sideSection} ${s__default.default.aiCard}`, children: [
1014
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: s__default.default.aiCardTitle, children: [
1015
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: s__default.default.aiCardIcon, "aria-hidden": true, children: "\u2728" }),
1016
+ "Synth\xE8se client"
1017
+ ] }),
1018
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: s__default.default.aiCardLead, children: clientSummary.summary }),
1019
+ 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}`)) }),
1020
+ clientSummary.keyFacts && clientSummary.keyFacts.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("ul", { className: s__default.default.aiCardFacts, children: clientSummary.keyFacts.slice(0, 4).map((f, i) => /* @__PURE__ */ jsxRuntime.jsxs("li", { className: s__default.default.aiCardFact, children: [
1021
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: s__default.default.aiCardDot, "aria-hidden": true }),
1022
+ f
1023
+ ] }, `kf-${i}`)) })
1024
+ ] }),
949
1025
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: s__default.default.sideSection, children: [
950
1026
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: s__default.default.sideSectionTitle, children: t("detail.details") }),
951
1027
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: s__default.default.sideField, children: [
@@ -1203,16 +1279,7 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
1203
1279
  ] })
1204
1280
  ] }, a.id))
1205
1281
  ] }),
1206
- clientSummary && clientSummary.summary && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: s__default.default.sideSection, style: { background: "linear-gradient(135deg, rgba(37,99,235,0.03) 0%, rgba(139,92,246,0.03) 100%)" }, children: [
1207
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: s__default.default.sideSectionTitle, style: { display: "flex", alignItems: "center", gap: 4 }, children: [
1208
- /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: 13 }, children: "\u{1F9E0}" }),
1209
- " R\xE9sum\xE9 client"
1210
- ] }),
1211
- /* @__PURE__ */ jsxRuntime.jsx("p", { style: { margin: "0 0 8px", fontSize: 11, lineHeight: 1.6, color: "#374151" }, children: clientSummary.summary }),
1212
- clientSummary.recurringTopics && clientSummary.recurringTopics.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", flexWrap: "wrap", gap: 4, marginBottom: 6 }, children: clientSummary.recurringTopics.slice(0, 3).map((tp, i) => /* @__PURE__ */ jsxRuntime.jsx("span", { style: { padding: "2px 8px", borderRadius: 10, background: "rgba(37,99,235,0.08)", color: "#2563eb", fontSize: 10, fontWeight: 600 }, children: tp.topic }, i)) }),
1213
- clientSummary.keyFacts && clientSummary.keyFacts.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", flexWrap: "wrap", gap: 4 }, children: clientSummary.keyFacts.slice(0, 3).map((f, i) => /* @__PURE__ */ jsxRuntime.jsx("span", { style: { padding: "2px 8px", borderRadius: 10, background: "rgba(22,163,74,0.08)", color: "#16a34a", fontSize: 10, fontWeight: 600 }, children: f }, i)) })
1214
- ] }),
1215
- summaryLoading && /* @__PURE__ */ jsxRuntime.jsx("div", { className: s__default.default.sideSection, children: /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: 11, color: "#94a3b8", textAlign: "center", padding: 8 }, children: "\u{1F9E0} Chargement r\xE9sum\xE9..." }) })
1282
+ 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" }) })
1216
1283
  ] })
1217
1284
  ] }),
1218
1285
  undoToast && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: s__default.default.undoToast, role: "alert", children: [
@@ -7,6 +7,7 @@ import { RichTextEditor } from '../../components/RichTextEditor/index.js';
7
7
  import { hasCodeBlocks, CodeBlockRendererHtml, MessageWithCodeBlocks } from '../../components/TicketConversation/components/CodeBlock.js';
8
8
  import { CodeBlockInserter } from '../../components/TicketConversation/components/CodeBlockInserter.js';
9
9
  import { getFeatures } from '../shared/config.js';
10
+ import { computeSlaState, formatSlaRemaining } from '../shared/sla.js';
10
11
  import { useTranslation } from '../../components/TicketConversation/hooks/useTranslation.js';
11
12
  import s from '../../styles/TicketDetail.module.scss';
12
13
 
@@ -662,6 +663,46 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
662
663
  ] })
663
664
  ] })
664
665
  ] }),
666
+ (() => {
667
+ const slaInfo = computeSlaState({
668
+ slaFirstResponseDue: ticket.slaFirstResponseDue,
669
+ slaFirstResponseBreached: ticket.slaFirstResponseBreached,
670
+ slaResolutionDue: ticket.slaResolutionDue,
671
+ slaResolutionBreached: ticket.slaResolutionBreached,
672
+ firstResponseAt: ticket.firstResponseAt
673
+ });
674
+ if (slaInfo.state !== "breach") return null;
675
+ const duration = formatSlaRemaining(slaInfo.remainingMs).replace(/^−/, "");
676
+ const target = slaInfo.due ? new Date(slaInfo.due).toLocaleString("fr-FR", { day: "2-digit", month: "short", hour: "2-digit", minute: "2-digit" }) : "";
677
+ return /* @__PURE__ */ jsxs("div", { className: s.slaBanner, role: "alert", children: [
678
+ /* @__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: [
679
+ /* @__PURE__ */ jsx("path", { d: "M12 9v4M12 17h.01" }),
680
+ /* @__PURE__ */ jsx("path", { d: "M10.3 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z" })
681
+ ] }) }),
682
+ /* @__PURE__ */ jsxs("div", { className: s.slaBannerBody, children: [
683
+ /* @__PURE__ */ jsx("strong", { children: t("inbox.slaBanner.breached") }),
684
+ /* @__PURE__ */ jsx("span", { className: s.slaBannerSep, children: "\u2014" }),
685
+ /* @__PURE__ */ jsx("span", { children: t("inbox.slaBanner.responseAwaitedFor", { duration }) }),
686
+ target && /* @__PURE__ */ jsxs("span", { className: s.slaBannerTarget, children: [
687
+ "\xB7 ",
688
+ t("inbox.slaBanner.target", { target })
689
+ ] })
690
+ ] }),
691
+ /* @__PURE__ */ jsxs(
692
+ "button",
693
+ {
694
+ type: "button",
695
+ className: s.slaBannerCta,
696
+ onClick: () => handleStatusChange("escalated"),
697
+ "aria-label": t("inbox.slaBanner.escalate"),
698
+ children: [
699
+ "\u2191 ",
700
+ t("inbox.slaBanner.escalate")
701
+ ]
702
+ }
703
+ )
704
+ ] });
705
+ })(),
665
706
  otherViewers.length > 0 && /* @__PURE__ */ jsxs("div", { style: {
666
707
  display: "flex",
667
708
  alignItems: "center",
@@ -688,8 +729,17 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
688
729
  const isPendingDelete = undoToast?.msgId === msg.id;
689
730
  return /* @__PURE__ */ jsxs(React.Fragment, { children: [
690
731
  showDate && /* @__PURE__ */ jsx("div", { className: s.dateSeparator, children: /* @__PURE__ */ jsx("span", { className: s.dateSeparatorText, children: dateLabel(msg.createdAt) }) }),
691
- /* @__PURE__ */ jsxs("div", { className: `${s.message} ${msg.isInternal ? s.messageInternal : ""}`, style: isPendingDelete ? { opacity: 0.3, pointerEvents: "none" } : void 0, children: [
692
- /* @__PURE__ */ jsx("div", { className: s.avatar, style: { backgroundColor: isAdmin ? "#2563eb" : msg.authorType === "email" ? "#ea580c" : "#7c3aed" }, children: isAdmin ? "CW" : initials }),
732
+ /* @__PURE__ */ jsxs("div", { className: `${s.message} ${isAdmin ? s.messageAdmin : s.messageClient} ${msg.isInternal ? s.messageInternal : ""}`, style: isPendingDelete ? { opacity: 0.3, pointerEvents: "none" } : void 0, children: [
733
+ /* @__PURE__ */ jsx(
734
+ "div",
735
+ {
736
+ className: s.avatar,
737
+ style: {
738
+ backgroundColor: isAdmin ? "var(--theme-info-500, #2a6bd8)" : msg.authorType === "email" ? "var(--theme-warning-500, #c97a0a)" : "var(--theme-accent-500, #6b46e8)"
739
+ },
740
+ children: isAdmin ? "CW" : initials
741
+ }
742
+ ),
693
743
  /* @__PURE__ */ jsxs("div", { className: s.messageContent, children: [
694
744
  /* @__PURE__ */ jsxs("div", { className: s.messageHeader, children: [
695
745
  /* @__PURE__ */ jsx("span", { className: s.messageAuthor, children: isAdmin ? "Support" : msg.authorType === "email" ? "Email" : client?.firstName || "Client" }),
@@ -791,7 +841,17 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
791
841
  children: [
792
842
  /* @__PURE__ */ jsxs("div", { className: s.composerToolbar, children: [
793
843
  features.ai && /* @__PURE__ */ jsxs(Fragment, { children: [
794
- /* @__PURE__ */ jsx("button", { className: s.toolbarBtn, "data-tooltip": t("detail.iaSuggestion"), "aria-label": t("detail.iaSuggestion"), onClick: handleAiSuggest, disabled: aiReplying || messages.length === 0, style: { fontSize: 11, fontWeight: 700, padding: "4px 10px", width: "auto" }, children: aiReplying ? "..." : `\u2728 ${t("detail.iaSuggestion")}` }),
844
+ /* @__PURE__ */ jsx(
845
+ "button",
846
+ {
847
+ className: `${s.toolbarBtn} ${s.toolbarBtnAi}`,
848
+ "data-tooltip": t("detail.iaSuggestion"),
849
+ "aria-label": t("detail.iaSuggestion"),
850
+ onClick: handleAiSuggest,
851
+ disabled: aiReplying || messages.length === 0,
852
+ children: aiReplying ? "\u2026" : `\u2728 ${t("detail.iaSuggestion")}`
853
+ }
854
+ ),
795
855
  /* @__PURE__ */ jsx(RewriteDropdown, { disabled: aiRewriting || !replyBody.trim(), loading: aiRewriting, onSelect: (style) => handleAiRewrite(style), toolbarBtnClass: s.toolbarBtn })
796
856
  ] }),
797
857
  /* @__PURE__ */ jsx(
@@ -914,6 +974,10 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
914
974
  ] })
915
975
  ] })
916
976
  ] }),
977
+ /* @__PURE__ */ jsxs("span", { className: s.sendShortcut, "aria-hidden": true, children: [
978
+ /* @__PURE__ */ jsx("kbd", { children: "\u2318" }),
979
+ /* @__PURE__ */ jsx("kbd", { children: "\u21B5" })
980
+ ] }),
917
981
  /* @__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") })
918
982
  ] })
919
983
  ]
@@ -939,6 +1003,18 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
939
1003
  /* @__PURE__ */ jsx("button", { className: s.smallBtn, onClick: () => window.open(`/api/admin/impersonate?clientId=${client.id}`, "_blank"), children: t("client.clientPortal") })
940
1004
  ] })
941
1005
  ] }),
1006
+ clientSummary && clientSummary.summary && /* @__PURE__ */ jsxs("div", { className: `${s.sideSection} ${s.aiCard}`, children: [
1007
+ /* @__PURE__ */ jsxs("div", { className: s.aiCardTitle, children: [
1008
+ /* @__PURE__ */ jsx("span", { className: s.aiCardIcon, "aria-hidden": true, children: "\u2728" }),
1009
+ "Synth\xE8se client"
1010
+ ] }),
1011
+ /* @__PURE__ */ jsx("p", { className: s.aiCardLead, children: clientSummary.summary }),
1012
+ 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}`)) }),
1013
+ clientSummary.keyFacts && clientSummary.keyFacts.length > 0 && /* @__PURE__ */ jsx("ul", { className: s.aiCardFacts, children: clientSummary.keyFacts.slice(0, 4).map((f, i) => /* @__PURE__ */ jsxs("li", { className: s.aiCardFact, children: [
1014
+ /* @__PURE__ */ jsx("span", { className: s.aiCardDot, "aria-hidden": true }),
1015
+ f
1016
+ ] }, `kf-${i}`)) })
1017
+ ] }),
942
1018
  /* @__PURE__ */ jsxs("div", { className: s.sideSection, children: [
943
1019
  /* @__PURE__ */ jsx("div", { className: s.sideSectionTitle, children: t("detail.details") }),
944
1020
  /* @__PURE__ */ jsxs("div", { className: s.sideField, children: [
@@ -1196,16 +1272,7 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
1196
1272
  ] })
1197
1273
  ] }, a.id))
1198
1274
  ] }),
1199
- clientSummary && clientSummary.summary && /* @__PURE__ */ jsxs("div", { className: s.sideSection, style: { background: "linear-gradient(135deg, rgba(37,99,235,0.03) 0%, rgba(139,92,246,0.03) 100%)" }, children: [
1200
- /* @__PURE__ */ jsxs("div", { className: s.sideSectionTitle, style: { display: "flex", alignItems: "center", gap: 4 }, children: [
1201
- /* @__PURE__ */ jsx("span", { style: { fontSize: 13 }, children: "\u{1F9E0}" }),
1202
- " R\xE9sum\xE9 client"
1203
- ] }),
1204
- /* @__PURE__ */ jsx("p", { style: { margin: "0 0 8px", fontSize: 11, lineHeight: 1.6, color: "#374151" }, children: clientSummary.summary }),
1205
- clientSummary.recurringTopics && clientSummary.recurringTopics.length > 0 && /* @__PURE__ */ jsx("div", { style: { display: "flex", flexWrap: "wrap", gap: 4, marginBottom: 6 }, children: clientSummary.recurringTopics.slice(0, 3).map((tp, i) => /* @__PURE__ */ jsx("span", { style: { padding: "2px 8px", borderRadius: 10, background: "rgba(37,99,235,0.08)", color: "#2563eb", fontSize: 10, fontWeight: 600 }, children: tp.topic }, i)) }),
1206
- clientSummary.keyFacts && clientSummary.keyFacts.length > 0 && /* @__PURE__ */ jsx("div", { style: { display: "flex", flexWrap: "wrap", gap: 4 }, children: clientSummary.keyFacts.slice(0, 3).map((f, i) => /* @__PURE__ */ jsx("span", { style: { padding: "2px 8px", borderRadius: 10, background: "rgba(22,163,74,0.08)", color: "#16a34a", fontSize: 10, fontWeight: 600 }, children: f }, i)) })
1207
- ] }),
1208
- summaryLoading && /* @__PURE__ */ jsx("div", { className: s.sideSection, children: /* @__PURE__ */ jsx("div", { style: { fontSize: 11, color: "#94a3b8", textAlign: "center", padding: 8 }, children: "\u{1F9E0} Chargement r\xE9sum\xE9..." }) })
1275
+ 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" }) })
1209
1276
  ] })
1210
1277
  ] }),
1211
1278
  undoToast && /* @__PURE__ */ jsxs("div", { className: s.undoToast, role: "alert", children: [