@consilioweb/payload-support 0.11.0 → 0.12.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.
@@ -712,8 +712,22 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
712
712
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: s__default.default.topBar, children: [
713
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" }),
714
714
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: s__default.default.ticketMeta, children: [
715
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: s__default.default.ticketNumber, children: ticket.ticketNumber }),
716
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: s__default.default.ticketSubject, children: ticket.subject })
715
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: s__default.default.ticketNumber, children: [
716
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: ticket.ticketNumber }),
717
+ ticket.category ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
718
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: s__default.default.ticketNumberSep, children: "\xB7" }),
719
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: s__default.default.ticketNumberCat, children: ticket.category })
720
+ ] }) : null,
721
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: s__default.default.ticketNumberSep, children: "\xB7" }),
722
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: s__default.default.ticketNumberSource, "aria-label": t("detail.source"), children: [
723
+ /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "11", height: "11", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
724
+ /* @__PURE__ */ jsxRuntime.jsx("rect", { x: "3", y: "5", width: "18", height: "14", rx: "2" }),
725
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m3 7 9 6 9-6" })
726
+ ] }),
727
+ ticket.source === "email" ? "Email" : ticket.source || t("ticket.source.portal")
728
+ ] })
729
+ ] }),
730
+ /* @__PURE__ */ jsxRuntime.jsx("h1", { className: s__default.default.ticketSubject, children: ticket.subject })
717
731
  ] }),
718
732
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: s__default.default.topBarRight, children: [
719
733
  /* @__PURE__ */ jsxRuntime.jsxs("select", { className: s__default.default.statusChip, style: { background: st.bg, color: st.color }, value: ticket.status || "open", onChange: (e) => handleStatusChange(e.target.value), disabled: statusUpdating, "aria-label": t("ticket.status.label"), children: [
@@ -1004,39 +1018,41 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
1004
1018
  cannedResponses.map((cr) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: String(cr.id), children: cr.title }, cr.id))
1005
1019
  ] })
1006
1020
  ] }),
1007
- /* @__PURE__ */ jsxRuntime.jsx(
1008
- index.RichTextEditor,
1009
- {
1010
- ref: editorRef,
1011
- onChange: (html, text) => {
1012
- setReplyHtml(html);
1013
- setReplyBody(text);
1014
- },
1015
- placeholder: isInternal ? t("composer.placeholderInternal") : t("composer.placeholderReplyTo", { name: client?.firstName || "client" }),
1016
- minHeight: 100,
1017
- borderColor: "transparent",
1018
- onFileUpload: async (file) => {
1019
- try {
1020
- const formData = new FormData();
1021
- formData.append("file", file);
1022
- formData.append("_payload", JSON.stringify({ alt: file.name }));
1023
- const ur = await fetch("/api/media", { method: "POST", credentials: "include", body: formData });
1024
- if (!ur.ok) return null;
1025
- const ud = await ur.json();
1026
- return ud.doc?.url || null;
1027
- } catch {
1028
- return null;
1021
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: s__default.default.composerBox, children: [
1022
+ /* @__PURE__ */ jsxRuntime.jsx(
1023
+ index.RichTextEditor,
1024
+ {
1025
+ ref: editorRef,
1026
+ onChange: (html, text) => {
1027
+ setReplyHtml(html);
1028
+ setReplyBody(text);
1029
+ },
1030
+ placeholder: isInternal ? t("composer.placeholderInternal") : t("composer.placeholderReplyTo", { name: client?.firstName || "client" }),
1031
+ minHeight: 100,
1032
+ borderColor: "transparent",
1033
+ onFileUpload: async (file) => {
1034
+ try {
1035
+ const formData = new FormData();
1036
+ formData.append("file", file);
1037
+ formData.append("_payload", JSON.stringify({ alt: file.name }));
1038
+ const ur = await fetch("/api/media", { method: "POST", credentials: "include", body: formData });
1039
+ if (!ur.ok) return null;
1040
+ const ud = await ur.json();
1041
+ return ud.doc?.url || null;
1042
+ } catch {
1043
+ return null;
1044
+ }
1029
1045
  }
1030
1046
  }
1031
- }
1032
- ),
1033
- 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: [
1034
- /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
1035
- "PJ ",
1036
- f.name
1037
- ] }),
1038
- /* @__PURE__ */ jsxRuntime.jsx("button", { className: s__default.default.uploadRemoveBtn, "aria-label": `Retirer ${f.name}`, onClick: () => setPendingFiles((prev) => prev.filter((_, j) => j !== i)), children: "\xD7" })
1039
- ] }, i)) }),
1047
+ ),
1048
+ 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" })
1054
+ ] }, i)) })
1055
+ ] }),
1040
1056
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: s__default.default.composerFooter, children: [
1041
1057
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: s__default.default.composerOptions, children: [
1042
1058
  /* @__PURE__ */ jsxRuntime.jsxs(
@@ -1232,9 +1248,8 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
1232
1248
  ] }),
1233
1249
  features.timeTracking && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: s__default.default.sideSection, children: [
1234
1250
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: s__default.default.sideSectionTitle, children: [
1235
- t("detail.time"),
1236
- " ",
1237
- /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontWeight: 700, fontSize: 13, color: "#d97706" }, children: totalMin > 0 ? `${Math.floor(totalMin / 60)}h${String(totalMin % 60).padStart(2, "0")} ${t("detail.total")}` : "0min" })
1251
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: t("detail.time") }),
1252
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "var(--theme-text)", fontWeight: 600, textTransform: "none", letterSpacing: 0 }, children: totalMin > 0 ? `${Math.floor(totalMin / 60)}h${String(totalMin % 60).padStart(2, "0")} ${t("detail.total")}` : "0min" })
1238
1253
  ] }),
1239
1254
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: s__default.default.timer, children: [
1240
1255
  /* @__PURE__ */ jsxRuntime.jsxs("span", { className: `${s__default.default.timerDisplay} ${timerRunning ? s__default.default.timerActive : ""}`, children: [
@@ -1242,17 +1257,18 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
1242
1257
  ":",
1243
1258
  String(timerSeconds % 60).padStart(2, "0")
1244
1259
  ] }),
1245
- !timerRunning ? /* @__PURE__ */ jsxRuntime.jsx("button", { className: s__default.default.timerBtn, onClick: () => setTimerRunning(true), style: { color: "#dc2626", borderColor: "#dc2626" }, "aria-label": "D\xE9marrer le timer", children: timerSeconds > 0 ? "\u25B6" : "\u25B6 Go" }) : /* @__PURE__ */ jsxRuntime.jsx("button", { className: s__default.default.timerBtn, onClick: () => setTimerRunning(false), "aria-label": "Mettre en pause le timer", children: "\u23F8" }),
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, onClick: () => setTimerRunning(false), "aria-label": "Mettre en pause le timer", children: "\u23F8 Pause" }),
1246
1261
  timerSeconds >= 60 && !timerRunning && /* @__PURE__ */ jsxRuntime.jsxs("button", { className: s__default.default.timerBtn, onClick: () => {
1247
1262
  handleTimerSave();
1248
1263
  localStorage.removeItem(`timer-sec-${ticketId}`);
1249
1264
  localStorage.removeItem(`timer-run-${ticketId}`);
1250
- }, style: { color: "#16a34a", borderColor: "#16a34a" }, "aria-label": "Sauvegarder le temps", children: [
1265
+ }, "aria-label": "Sauvegarder le temps", children: [
1251
1266
  "\u{1F4BE} ",
1252
1267
  Math.round(timerSeconds / 60),
1253
1268
  "m"
1254
1269
  ] })
1255
1270
  ] }),
1271
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: s__default.default.timerBar, "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: s__default.default.timerBarFill, style: { width: `${Math.min(100, (totalMin + Math.floor(timerSeconds / 60)) / 120 * 100)}%` } }) }),
1256
1272
  /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", gap: 6, marginTop: 8, alignItems: "center" }, children: [
1257
1273
  /* @__PURE__ */ jsxRuntime.jsx("input", { type: "number", min: "1", placeholder: "min", style: { width: 60, padding: "4px 8px", borderRadius: 6, border: "1px solid var(--theme-elevation-200)", fontSize: 12, color: "var(--theme-text)", background: "var(--theme-elevation-0)" }, id: "manual-time-input" }),
1258
1274
  /* @__PURE__ */ jsxRuntime.jsx("button", { className: s__default.default.timerBtn, onClick: async () => {
@@ -705,8 +705,22 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
705
705
  /* @__PURE__ */ jsxs("div", { className: s.topBar, children: [
706
706
  /* @__PURE__ */ jsx(Link, { href: "/admin/support/inbox", className: s.backLink, "aria-label": "Retour \xE0 la bo\xEEte de r\xE9ception", children: "\u2190" }),
707
707
  /* @__PURE__ */ jsxs("div", { className: s.ticketMeta, children: [
708
- /* @__PURE__ */ jsx("span", { className: s.ticketNumber, children: ticket.ticketNumber }),
709
- /* @__PURE__ */ jsx("span", { className: s.ticketSubject, children: ticket.subject })
708
+ /* @__PURE__ */ jsxs("span", { className: s.ticketNumber, children: [
709
+ /* @__PURE__ */ jsx("span", { children: ticket.ticketNumber }),
710
+ ticket.category ? /* @__PURE__ */ jsxs(Fragment, { children: [
711
+ /* @__PURE__ */ jsx("span", { className: s.ticketNumberSep, children: "\xB7" }),
712
+ /* @__PURE__ */ jsx("span", { className: s.ticketNumberCat, children: ticket.category })
713
+ ] }) : null,
714
+ /* @__PURE__ */ jsx("span", { className: s.ticketNumberSep, children: "\xB7" }),
715
+ /* @__PURE__ */ jsxs("span", { className: s.ticketNumberSource, "aria-label": t("detail.source"), children: [
716
+ /* @__PURE__ */ jsxs("svg", { width: "11", height: "11", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
717
+ /* @__PURE__ */ jsx("rect", { x: "3", y: "5", width: "18", height: "14", rx: "2" }),
718
+ /* @__PURE__ */ jsx("path", { d: "m3 7 9 6 9-6" })
719
+ ] }),
720
+ ticket.source === "email" ? "Email" : ticket.source || t("ticket.source.portal")
721
+ ] })
722
+ ] }),
723
+ /* @__PURE__ */ jsx("h1", { className: s.ticketSubject, children: ticket.subject })
710
724
  ] }),
711
725
  /* @__PURE__ */ jsxs("div", { className: s.topBarRight, children: [
712
726
  /* @__PURE__ */ jsxs("select", { className: s.statusChip, style: { background: st.bg, color: st.color }, value: ticket.status || "open", onChange: (e) => handleStatusChange(e.target.value), disabled: statusUpdating, "aria-label": t("ticket.status.label"), children: [
@@ -997,39 +1011,41 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
997
1011
  cannedResponses.map((cr) => /* @__PURE__ */ jsx("option", { value: String(cr.id), children: cr.title }, cr.id))
998
1012
  ] })
999
1013
  ] }),
1000
- /* @__PURE__ */ jsx(
1001
- RichTextEditor,
1002
- {
1003
- ref: editorRef,
1004
- onChange: (html, text) => {
1005
- setReplyHtml(html);
1006
- setReplyBody(text);
1007
- },
1008
- placeholder: isInternal ? t("composer.placeholderInternal") : t("composer.placeholderReplyTo", { name: client?.firstName || "client" }),
1009
- minHeight: 100,
1010
- borderColor: "transparent",
1011
- onFileUpload: async (file) => {
1012
- try {
1013
- const formData = new FormData();
1014
- formData.append("file", file);
1015
- formData.append("_payload", JSON.stringify({ alt: file.name }));
1016
- const ur = await fetch("/api/media", { method: "POST", credentials: "include", body: formData });
1017
- if (!ur.ok) return null;
1018
- const ud = await ur.json();
1019
- return ud.doc?.url || null;
1020
- } catch {
1021
- return null;
1014
+ /* @__PURE__ */ jsxs("div", { className: s.composerBox, children: [
1015
+ /* @__PURE__ */ jsx(
1016
+ RichTextEditor,
1017
+ {
1018
+ ref: editorRef,
1019
+ onChange: (html, text) => {
1020
+ setReplyHtml(html);
1021
+ setReplyBody(text);
1022
+ },
1023
+ placeholder: isInternal ? t("composer.placeholderInternal") : t("composer.placeholderReplyTo", { name: client?.firstName || "client" }),
1024
+ minHeight: 100,
1025
+ borderColor: "transparent",
1026
+ onFileUpload: async (file) => {
1027
+ try {
1028
+ const formData = new FormData();
1029
+ formData.append("file", file);
1030
+ formData.append("_payload", JSON.stringify({ alt: file.name }));
1031
+ const ur = await fetch("/api/media", { method: "POST", credentials: "include", body: formData });
1032
+ if (!ur.ok) return null;
1033
+ const ud = await ur.json();
1034
+ return ud.doc?.url || null;
1035
+ } catch {
1036
+ return null;
1037
+ }
1022
1038
  }
1023
1039
  }
1024
- }
1025
- ),
1026
- pendingFiles.length > 0 && /* @__PURE__ */ jsx("div", { className: s.uploadPreview, children: pendingFiles.map((f, i) => /* @__PURE__ */ jsxs("div", { className: s.uploadPreviewItem, children: [
1027
- /* @__PURE__ */ jsxs("span", { children: [
1028
- "PJ ",
1029
- f.name
1030
- ] }),
1031
- /* @__PURE__ */ jsx("button", { className: s.uploadRemoveBtn, "aria-label": `Retirer ${f.name}`, onClick: () => setPendingFiles((prev) => prev.filter((_, j) => j !== i)), children: "\xD7" })
1032
- ] }, i)) }),
1040
+ ),
1041
+ 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" })
1047
+ ] }, i)) })
1048
+ ] }),
1033
1049
  /* @__PURE__ */ jsxs("div", { className: s.composerFooter, children: [
1034
1050
  /* @__PURE__ */ jsxs("div", { className: s.composerOptions, children: [
1035
1051
  /* @__PURE__ */ jsxs(
@@ -1225,9 +1241,8 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
1225
1241
  ] }),
1226
1242
  features.timeTracking && /* @__PURE__ */ jsxs("div", { className: s.sideSection, children: [
1227
1243
  /* @__PURE__ */ jsxs("div", { className: s.sideSectionTitle, children: [
1228
- t("detail.time"),
1229
- " ",
1230
- /* @__PURE__ */ jsx("span", { style: { fontWeight: 700, fontSize: 13, color: "#d97706" }, children: totalMin > 0 ? `${Math.floor(totalMin / 60)}h${String(totalMin % 60).padStart(2, "0")} ${t("detail.total")}` : "0min" })
1244
+ /* @__PURE__ */ jsx("span", { children: t("detail.time") }),
1245
+ /* @__PURE__ */ jsx("span", { style: { color: "var(--theme-text)", fontWeight: 600, textTransform: "none", letterSpacing: 0 }, children: totalMin > 0 ? `${Math.floor(totalMin / 60)}h${String(totalMin % 60).padStart(2, "0")} ${t("detail.total")}` : "0min" })
1231
1246
  ] }),
1232
1247
  /* @__PURE__ */ jsxs("div", { className: s.timer, children: [
1233
1248
  /* @__PURE__ */ jsxs("span", { className: `${s.timerDisplay} ${timerRunning ? s.timerActive : ""}`, children: [
@@ -1235,17 +1250,18 @@ ${uploadedLinks.join("\n")}` : replyBody.trim() || "[Contenu enrichi]";
1235
1250
  ":",
1236
1251
  String(timerSeconds % 60).padStart(2, "0")
1237
1252
  ] }),
1238
- !timerRunning ? /* @__PURE__ */ jsx("button", { className: s.timerBtn, onClick: () => setTimerRunning(true), style: { color: "#dc2626", borderColor: "#dc2626" }, "aria-label": "D\xE9marrer le timer", children: timerSeconds > 0 ? "\u25B6" : "\u25B6 Go" }) : /* @__PURE__ */ jsx("button", { className: s.timerBtn, onClick: () => setTimerRunning(false), "aria-label": "Mettre en pause le timer", children: "\u23F8" }),
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, onClick: () => setTimerRunning(false), "aria-label": "Mettre en pause le timer", children: "\u23F8 Pause" }),
1239
1254
  timerSeconds >= 60 && !timerRunning && /* @__PURE__ */ jsxs("button", { className: s.timerBtn, onClick: () => {
1240
1255
  handleTimerSave();
1241
1256
  localStorage.removeItem(`timer-sec-${ticketId}`);
1242
1257
  localStorage.removeItem(`timer-run-${ticketId}`);
1243
- }, style: { color: "#16a34a", borderColor: "#16a34a" }, "aria-label": "Sauvegarder le temps", children: [
1258
+ }, "aria-label": "Sauvegarder le temps", children: [
1244
1259
  "\u{1F4BE} ",
1245
1260
  Math.round(timerSeconds / 60),
1246
1261
  "m"
1247
1262
  ] })
1248
1263
  ] }),
1264
+ /* @__PURE__ */ jsx("div", { className: s.timerBar, "aria-hidden": true, children: /* @__PURE__ */ jsx("div", { className: s.timerBarFill, style: { width: `${Math.min(100, (totalMin + Math.floor(timerSeconds / 60)) / 120 * 100)}%` } }) }),
1249
1265
  /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: 6, marginTop: 8, alignItems: "center" }, children: [
1250
1266
  /* @__PURE__ */ jsx("input", { type: "number", min: "1", placeholder: "min", style: { width: 60, padding: "4px 8px", borderRadius: 6, border: "1px solid var(--theme-elevation-200)", fontSize: 12, color: "var(--theme-text)", background: "var(--theme-elevation-0)" }, id: "manual-time-input" }),
1251
1267
  /* @__PURE__ */ jsx("button", { className: s.timerBtn, onClick: async () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@consilioweb/payload-support",
3
- "version": "0.11.0",
3
+ "version": "0.12.0",
4
4
  "description": "Payload CMS plugin — professional support & ticketing system with AI, SLA, time tracking, live chat, and more",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",