@consilioweb/payload-support 0.16.0 → 1.1.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 (199) hide show
  1. package/README.md +357 -435
  2. package/dist/components/TicketConversation/RewriteDropdown.cjs +98 -0
  3. package/dist/components/TicketConversation/RewriteDropdown.js +93 -0
  4. package/dist/components/TicketConversation/SkeletonText.cjs +21 -0
  5. package/dist/components/TicketConversation/SkeletonText.js +20 -0
  6. package/dist/components/TicketConversation/constants.cjs +27 -0
  7. package/dist/components/TicketConversation/constants.js +26 -1
  8. package/dist/components/TicketConversation/hooks/useDocumentIdFromUrl.cjs +20 -0
  9. package/dist/components/TicketConversation/hooks/useDocumentIdFromUrl.js +19 -0
  10. package/dist/components/TicketConversation/index.cjs +10 -147
  11. package/dist/components/TicketConversation/index.js +4 -141
  12. package/dist/index.cjs +1763 -677
  13. package/dist/index.d.cts +4 -0
  14. package/dist/index.d.ts +4 -0
  15. package/dist/index.js +1760 -677
  16. package/dist/views/BillingView/client.cjs +40 -54
  17. package/dist/views/BillingView/client.js +40 -54
  18. package/dist/views/ChatView/client.cjs +4 -3
  19. package/dist/views/ChatView/client.js +4 -3
  20. package/dist/views/CrmView/client.cjs +7 -7
  21. package/dist/views/CrmView/client.js +7 -7
  22. package/dist/views/EmailTrackingView/client.cjs +6 -5
  23. package/dist/views/EmailTrackingView/client.js +6 -5
  24. package/dist/views/ImportConversationView/client.cjs +4 -4
  25. package/dist/views/ImportConversationView/client.js +4 -4
  26. package/dist/views/LogsView/client.cjs +3 -2
  27. package/dist/views/LogsView/client.js +3 -2
  28. package/dist/views/NewTicketView/client.cjs +1 -1
  29. package/dist/views/NewTicketView/client.js +1 -1
  30. package/dist/views/PendingEmailsView/client.cjs +7 -6
  31. package/dist/views/PendingEmailsView/client.js +7 -6
  32. package/dist/views/SupportDashboardView/client.cjs +19 -22
  33. package/dist/views/SupportDashboardView/client.js +19 -22
  34. package/dist/views/TicketDetailView/NextActionItem.cjs +40 -0
  35. package/dist/views/TicketDetailView/NextActionItem.js +34 -0
  36. package/dist/views/TicketDetailView/RewriteDropdown.cjs +80 -0
  37. package/dist/views/TicketDetailView/RewriteDropdown.js +78 -0
  38. package/dist/views/TicketDetailView/client.cjs +59 -190
  39. package/dist/views/TicketDetailView/client.js +52 -183
  40. package/dist/views/TicketDetailView/constants.cjs +20 -0
  41. package/dist/views/TicketDetailView/constants.js +16 -0
  42. package/dist/views/TicketDetailView/helpers.cjs +23 -0
  43. package/dist/views/TicketDetailView/helpers.js +20 -0
  44. package/dist/views/TicketDetailView/types.cjs +2 -0
  45. package/dist/views/TicketDetailView/types.js +1 -0
  46. package/dist/views/TicketInboxView/client.cjs +14 -10
  47. package/dist/views/TicketInboxView/client.js +14 -10
  48. package/dist/views/TicketingSettingsView/client.cjs +101 -96
  49. package/dist/views/TicketingSettingsView/client.js +92 -88
  50. package/dist/views/TimeDashboardView/client.cjs +2 -2
  51. package/dist/views/TimeDashboardView/client.js +2 -2
  52. package/dist/views/shared/StatusPill.cjs +23 -12
  53. package/dist/views/shared/StatusPill.js +23 -12
  54. package/dist/views/shared/dateLocale.cjs +5 -0
  55. package/dist/views/shared/dateLocale.js +3 -0
  56. package/package.json +28 -15
  57. package/src/__tests__/generateTrackingToken.test.ts +53 -0
  58. package/src/__tests__/integration/ai-agent.test.ts +46 -0
  59. package/src/__tests__/integration/auth.test.ts +43 -0
  60. package/src/__tests__/integration/automation-rules.test.ts +68 -0
  61. package/src/__tests__/integration/buildTestPayload.ts +52 -0
  62. package/src/__tests__/integration/channels.test.ts +52 -0
  63. package/src/__tests__/integration/core-behaviors.test.ts +58 -0
  64. package/src/__tests__/integration/dashboard-volume.test.ts +31 -0
  65. package/src/__tests__/integration/digest.test.ts +48 -0
  66. package/src/__tests__/integration/invoice-pdf.test.ts +30 -0
  67. package/src/__tests__/integration/isolation.test.ts +81 -0
  68. package/src/__tests__/integration/mentions-invoice.test.ts +50 -0
  69. package/src/__tests__/integration/nps.test.ts +37 -0
  70. package/src/__tests__/integration/per-team-sla.test.ts +44 -0
  71. package/src/__tests__/integration/push.test.ts +75 -0
  72. package/src/__tests__/integration/sanitization.test.ts +35 -0
  73. package/src/__tests__/integration/sla-pause.test.ts +39 -0
  74. package/src/__tests__/integration/smoke.test.ts +26 -0
  75. package/src/__tests__/integration/snooze.test.ts +68 -0
  76. package/src/__tests__/integration/teams.test.ts +38 -0
  77. package/src/__tests__/rateLimiter.test.ts +89 -0
  78. package/src/__tests__/sanitizeHtml.test.ts +165 -0
  79. package/src/__tests__/sla.test.ts +258 -0
  80. package/src/collections/AutomationRules.ts +66 -0
  81. package/src/collections/NotificationQueue.ts +30 -0
  82. package/src/collections/PushSubscription.ts +28 -0
  83. package/src/collections/SatisfactionSurveys.ts +11 -2
  84. package/src/collections/SlaPolicies.ts +10 -0
  85. package/src/collections/SupportClients.ts +58 -1
  86. package/src/collections/SupportTeam.ts +27 -0
  87. package/src/collections/TicketActivityLog.ts +9 -4
  88. package/src/collections/TicketMessages.ts +140 -31
  89. package/src/collections/Tickets.ts +31 -73
  90. package/src/collections/index.ts +4 -0
  91. package/src/components/TicketConversation/RewriteDropdown.tsx +86 -0
  92. package/src/components/TicketConversation/SkeletonText.tsx +23 -0
  93. package/src/components/TicketConversation/constants.ts +29 -0
  94. package/src/components/TicketConversation/hooks/useDocumentIdFromUrl.ts +21 -0
  95. package/src/components/TicketConversation/index.tsx +4 -152
  96. package/src/endpoints/admin-chat-stream.ts +3 -4
  97. package/src/endpoints/admin-chat.ts +11 -20
  98. package/src/endpoints/admin-stats.ts +77 -35
  99. package/src/endpoints/ai-agent.ts +36 -0
  100. package/src/endpoints/apply-macro.ts +8 -14
  101. package/src/endpoints/auth-2fa.ts +12 -12
  102. package/src/endpoints/auto-close.ts +6 -10
  103. package/src/endpoints/billing.ts +17 -4
  104. package/src/endpoints/bulk-action.ts +7 -12
  105. package/src/endpoints/channels.ts +89 -0
  106. package/src/endpoints/chat-stream.ts +3 -4
  107. package/src/endpoints/chat.ts +7 -12
  108. package/src/endpoints/chatbot.ts +2 -2
  109. package/src/endpoints/client-intelligence.ts +4 -4
  110. package/src/endpoints/delete-account.ts +9 -16
  111. package/src/endpoints/email-stats.ts +2 -2
  112. package/src/endpoints/escalate.ts +2 -2
  113. package/src/endpoints/export-csv.ts +2 -2
  114. package/src/endpoints/export-data.ts +5 -8
  115. package/src/endpoints/import-conversation.ts +6 -10
  116. package/src/endpoints/index.ts +22 -1
  117. package/src/endpoints/invite-collaborator.ts +30 -15
  118. package/src/endpoints/invoice.ts +127 -0
  119. package/src/endpoints/kb-search.ts +2 -2
  120. package/src/endpoints/login.ts +12 -4
  121. package/src/endpoints/merge-clients.ts +14 -19
  122. package/src/endpoints/merge-tickets.ts +11 -18
  123. package/src/endpoints/oauth-google.ts +86 -39
  124. package/src/endpoints/pending-emails-process.ts +15 -25
  125. package/src/endpoints/process-digests.ts +93 -0
  126. package/src/endpoints/process-scheduled.ts +6 -10
  127. package/src/endpoints/process-snooze.ts +78 -0
  128. package/src/endpoints/purge-logs.ts +2 -2
  129. package/src/endpoints/push.ts +49 -0
  130. package/src/endpoints/resend-notification.ts +3 -4
  131. package/src/endpoints/round-robin-config.ts +3 -4
  132. package/src/endpoints/satisfaction.ts +21 -14
  133. package/src/endpoints/search.ts +5 -8
  134. package/src/endpoints/seed-kb.ts +3 -4
  135. package/src/endpoints/send-reminder.ts +6 -9
  136. package/src/endpoints/settings.ts +5 -2
  137. package/src/endpoints/signature.ts +3 -4
  138. package/src/endpoints/sla-check.ts +2 -2
  139. package/src/endpoints/split-ticket.ts +7 -12
  140. package/src/endpoints/statuses.ts +2 -2
  141. package/src/endpoints/ticket-feedback.ts +4 -6
  142. package/src/endpoints/ticket-synthesis.ts +2 -2
  143. package/src/endpoints/track-open.ts +16 -28
  144. package/src/endpoints/transfer-ticket.ts +21 -9
  145. package/src/endpoints/user-prefs.ts +3 -4
  146. package/src/hooks/automationRules.ts +84 -0
  147. package/src/hooks/checkSLA.ts +63 -17
  148. package/src/plugin.ts +8 -0
  149. package/src/portal/LiveChat.tsx +2 -63
  150. package/src/portal/auth/tickets/detail/CloseTicketButton.tsx +10 -0
  151. package/src/portal/auth/tickets/detail/MarkSolutionButton.tsx +14 -2
  152. package/src/portal/auth/tickets/detail/MessageActions.tsx +37 -18
  153. package/src/portal/auth/tickets/detail/ReopenTicketButton.tsx +10 -0
  154. package/src/portal/auth/tickets/detail/TransferAndInviteActions.tsx +3 -2
  155. package/src/portal/auth/tickets/detail/page.tsx +2 -2
  156. package/src/portal/helpers.ts +46 -0
  157. package/src/portal/login/page.tsx +3 -8
  158. package/src/portal/types.ts +15 -0
  159. package/src/types/lucide-react.d.ts +34 -0
  160. package/src/types/payload-config.d.ts +10 -0
  161. package/src/utils/adminNotification.ts +2 -2
  162. package/src/utils/aiAgent.ts +147 -0
  163. package/src/utils/auth.ts +5 -4
  164. package/src/utils/channels.ts +36 -0
  165. package/src/utils/db.ts +73 -0
  166. package/src/utils/emailTemplate.ts +8 -1
  167. package/src/utils/fireWebhooks.ts +4 -6
  168. package/src/utils/generateTicketSynthesis.ts +7 -12
  169. package/src/utils/invoicePdf.ts +88 -0
  170. package/src/utils/notificationQueue.ts +36 -0
  171. package/src/utils/push.ts +63 -0
  172. package/src/utils/readSettings.ts +22 -6
  173. package/src/utils/sanitizeHtml.ts +57 -0
  174. package/src/utils/slugs.ts +8 -0
  175. package/src/utils/teamAccess.ts +27 -0
  176. package/src/utils/ticketAccess.ts +53 -0
  177. package/src/utils/webhookDispatcher.ts +4 -6
  178. package/src/views/BillingView/client.tsx +49 -37
  179. package/src/views/ChatView/client.tsx +4 -3
  180. package/src/views/CrmView/client.tsx +7 -7
  181. package/src/views/EmailTrackingView/client.tsx +7 -6
  182. package/src/views/ImportConversationView/client.tsx +4 -4
  183. package/src/views/LogsView/client.tsx +3 -2
  184. package/src/views/NewTicketView/client.tsx +1 -1
  185. package/src/views/PendingEmailsView/client.tsx +7 -6
  186. package/src/views/SupportDashboardView/client.tsx +21 -21
  187. package/src/views/TicketDetailView/NextActionItem.tsx +30 -0
  188. package/src/views/TicketDetailView/RewriteDropdown.tsx +63 -0
  189. package/src/views/TicketDetailView/client.tsx +54 -179
  190. package/src/views/TicketDetailView/constants.ts +23 -0
  191. package/src/views/TicketDetailView/helpers.ts +17 -0
  192. package/src/views/TicketDetailView/types.ts +10 -0
  193. package/src/views/TicketInboxView/client.tsx +16 -10
  194. package/src/views/TicketingSettingsView/client.tsx +90 -87
  195. package/src/views/TimeDashboardView/client.tsx +2 -2
  196. package/src/views/shared/StatusPill.tsx +24 -12
  197. package/src/views/shared/dateLocale.ts +5 -0
  198. package/src/views/shared/locales/en.json +708 -0
  199. package/src/views/shared/locales/fr.json +708 -0
@@ -0,0 +1,98 @@
1
+ 'use strict';
2
+
3
+ var jsxRuntime = require('react/jsx-runtime');
4
+ var React = require('react');
5
+ var constants = require('./constants');
6
+
7
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
8
+
9
+ var React__default = /*#__PURE__*/_interopDefault(React);
10
+
11
+ const RewriteDropdown = ({ disabled, loading, onSelect }) => {
12
+ const [open, setOpen] = React.useState(false);
13
+ const ref = React__default.default.useRef(null);
14
+ React__default.default.useEffect(() => {
15
+ if (!open) return;
16
+ const close = (e) => {
17
+ if (ref.current && !ref.current.contains(e.target)) setOpen(false);
18
+ };
19
+ document.addEventListener("mousedown", close);
20
+ return () => document.removeEventListener("mousedown", close);
21
+ }, [open]);
22
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref, style: { position: "relative", display: "inline-block" }, children: [
23
+ /* @__PURE__ */ jsxRuntime.jsxs(
24
+ "button",
25
+ {
26
+ type: "button",
27
+ onClick: () => setOpen(!open),
28
+ disabled,
29
+ style: {
30
+ ...constants.s.outlineBtn("#0891b2", disabled),
31
+ fontSize: "11px",
32
+ padding: "3px 10px",
33
+ borderRadius: "14px",
34
+ display: "flex",
35
+ alignItems: "center",
36
+ gap: "4px"
37
+ },
38
+ children: [
39
+ loading ? "Reformulation..." : "\u270F\uFE0F Reformuler",
40
+ !loading && /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: 9, opacity: 0.7 }, children: "\u25BC" })
41
+ ]
42
+ }
43
+ ),
44
+ open && !disabled && !loading && /* @__PURE__ */ jsxRuntime.jsx(
45
+ "div",
46
+ {
47
+ style: {
48
+ position: "absolute",
49
+ bottom: "100%",
50
+ left: 0,
51
+ marginBottom: 4,
52
+ background: "var(--theme-elevation-0, #fff)",
53
+ border: "1px solid var(--theme-elevation-200, #e5e7eb)",
54
+ borderRadius: 8,
55
+ boxShadow: "0 4px 16px rgba(0,0,0,0.12)",
56
+ zIndex: 100,
57
+ minWidth: 180,
58
+ overflow: "hidden"
59
+ },
60
+ children: constants.REWRITE_STYLES.map((style) => /* @__PURE__ */ jsxRuntime.jsxs(
61
+ "button",
62
+ {
63
+ type: "button",
64
+ onClick: () => {
65
+ setOpen(false);
66
+ onSelect(style.id);
67
+ },
68
+ style: {
69
+ display: "flex",
70
+ flexDirection: "column",
71
+ width: "100%",
72
+ padding: "8px 12px",
73
+ border: "none",
74
+ background: "transparent",
75
+ cursor: "pointer",
76
+ textAlign: "left",
77
+ borderBottom: "1px solid var(--theme-elevation-100, #f3f4f6)",
78
+ transition: "background 120ms"
79
+ },
80
+ onMouseEnter: (e) => {
81
+ e.target.style.background = "var(--theme-elevation-50, #f9fafb)";
82
+ },
83
+ onMouseLeave: (e) => {
84
+ e.target.style.background = "transparent";
85
+ },
86
+ children: [
87
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: 12, fontWeight: 600, color: "var(--theme-text, #111)" }, children: style.label }),
88
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: 10, color: "var(--theme-elevation-500, #6b7280)" }, children: style.desc })
89
+ ]
90
+ },
91
+ style.id
92
+ ))
93
+ }
94
+ )
95
+ ] });
96
+ };
97
+
98
+ exports.RewriteDropdown = RewriteDropdown;
@@ -0,0 +1,93 @@
1
+ "use client";
2
+ import { jsxs, jsx } from 'react/jsx-runtime';
3
+ import React, { useState } from 'react';
4
+ import { s, REWRITE_STYLES } from './constants.js';
5
+
6
+ const RewriteDropdown = ({ disabled, loading, onSelect }) => {
7
+ const [open, setOpen] = useState(false);
8
+ const ref = React.useRef(null);
9
+ React.useEffect(() => {
10
+ if (!open) return;
11
+ const close = (e) => {
12
+ if (ref.current && !ref.current.contains(e.target)) setOpen(false);
13
+ };
14
+ document.addEventListener("mousedown", close);
15
+ return () => document.removeEventListener("mousedown", close);
16
+ }, [open]);
17
+ return /* @__PURE__ */ jsxs("div", { ref, style: { position: "relative", display: "inline-block" }, children: [
18
+ /* @__PURE__ */ jsxs(
19
+ "button",
20
+ {
21
+ type: "button",
22
+ onClick: () => setOpen(!open),
23
+ disabled,
24
+ style: {
25
+ ...s.outlineBtn("#0891b2", disabled),
26
+ fontSize: "11px",
27
+ padding: "3px 10px",
28
+ borderRadius: "14px",
29
+ display: "flex",
30
+ alignItems: "center",
31
+ gap: "4px"
32
+ },
33
+ children: [
34
+ loading ? "Reformulation..." : "\u270F\uFE0F Reformuler",
35
+ !loading && /* @__PURE__ */ jsx("span", { style: { fontSize: 9, opacity: 0.7 }, children: "\u25BC" })
36
+ ]
37
+ }
38
+ ),
39
+ open && !disabled && !loading && /* @__PURE__ */ jsx(
40
+ "div",
41
+ {
42
+ style: {
43
+ position: "absolute",
44
+ bottom: "100%",
45
+ left: 0,
46
+ marginBottom: 4,
47
+ background: "var(--theme-elevation-0, #fff)",
48
+ border: "1px solid var(--theme-elevation-200, #e5e7eb)",
49
+ borderRadius: 8,
50
+ boxShadow: "0 4px 16px rgba(0,0,0,0.12)",
51
+ zIndex: 100,
52
+ minWidth: 180,
53
+ overflow: "hidden"
54
+ },
55
+ children: REWRITE_STYLES.map((style) => /* @__PURE__ */ jsxs(
56
+ "button",
57
+ {
58
+ type: "button",
59
+ onClick: () => {
60
+ setOpen(false);
61
+ onSelect(style.id);
62
+ },
63
+ style: {
64
+ display: "flex",
65
+ flexDirection: "column",
66
+ width: "100%",
67
+ padding: "8px 12px",
68
+ border: "none",
69
+ background: "transparent",
70
+ cursor: "pointer",
71
+ textAlign: "left",
72
+ borderBottom: "1px solid var(--theme-elevation-100, #f3f4f6)",
73
+ transition: "background 120ms"
74
+ },
75
+ onMouseEnter: (e) => {
76
+ e.target.style.background = "var(--theme-elevation-50, #f9fafb)";
77
+ },
78
+ onMouseLeave: (e) => {
79
+ e.target.style.background = "transparent";
80
+ },
81
+ children: [
82
+ /* @__PURE__ */ jsx("span", { style: { fontSize: 12, fontWeight: 600, color: "var(--theme-text, #111)" }, children: style.label }),
83
+ /* @__PURE__ */ jsx("span", { style: { fontSize: 10, color: "var(--theme-elevation-500, #6b7280)" }, children: style.desc })
84
+ ]
85
+ },
86
+ style.id
87
+ ))
88
+ }
89
+ )
90
+ ] });
91
+ };
92
+
93
+ export { RewriteDropdown };
@@ -0,0 +1,21 @@
1
+ 'use strict';
2
+
3
+ var jsxRuntime = require('react/jsx-runtime');
4
+
5
+ function SkeletonText({ lines = 3 }) {
6
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", flexDirection: "column", gap: "8px", padding: "12px 0" }, children: Array.from({ length: lines }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsx(
7
+ "div",
8
+ {
9
+ style: {
10
+ height: "14px",
11
+ borderRadius: "4px",
12
+ backgroundColor: "#e2e8f0",
13
+ width: i === lines - 1 ? "60%" : "100%",
14
+ animation: "pulse 1.5s ease-in-out infinite"
15
+ }
16
+ },
17
+ i
18
+ )) });
19
+ }
20
+
21
+ exports.SkeletonText = SkeletonText;
@@ -0,0 +1,20 @@
1
+ "use client";
2
+ import { jsx } from 'react/jsx-runtime';
3
+
4
+ function SkeletonText({ lines = 3 }) {
5
+ return /* @__PURE__ */ jsx("div", { style: { display: "flex", flexDirection: "column", gap: "8px", padding: "12px 0" }, children: Array.from({ length: lines }).map((_, i) => /* @__PURE__ */ jsx(
6
+ "div",
7
+ {
8
+ style: {
9
+ height: "14px",
10
+ borderRadius: "4px",
11
+ backgroundColor: "#e2e8f0",
12
+ width: i === lines - 1 ? "60%" : "100%",
13
+ animation: "pulse 1.5s ease-in-out infinite"
14
+ }
15
+ },
16
+ i
17
+ )) });
18
+ }
19
+
20
+ export { SkeletonText };
@@ -1,5 +1,30 @@
1
1
  'use strict';
2
2
 
3
+ const REWRITE_STYLES = [
4
+ { id: "auto", label: "\u270F\uFE0F Auto", desc: "Garde le ton actuel" },
5
+ { id: "tutoyer", label: "\u{1F44B} Tutoyer", desc: "Passe en tu" },
6
+ { id: "vouvoyer", label: "\u{1F3A9} Vouvoyer", desc: "Passe en vous" },
7
+ { id: "formel", label: "\u{1F4BC} Formel", desc: "Ton professionnel" },
8
+ { id: "amical", label: "\u{1F60A} Amical", desc: "Ton chaleureux" },
9
+ { id: "court", label: "\u26A1 Court", desc: "Version concise" }
10
+ ];
11
+ const layoutStyles = {
12
+ root: { padding: "12px 0" },
13
+ twoColumns: {
14
+ display: "grid",
15
+ gridTemplateColumns: "1fr 320px",
16
+ gap: "16px",
17
+ alignItems: "start"
18
+ },
19
+ mainColumn: { minWidth: 0 },
20
+ sideColumn: {
21
+ display: "flex",
22
+ flexDirection: "column",
23
+ gap: "12px",
24
+ position: "sticky",
25
+ top: "80px"
26
+ }
27
+ };
3
28
  const statusLabels = {
4
29
  open: { label: "Ouvert", bg: "#dbeafe", color: "#1e40af" },
5
30
  waiting_client: { label: "Attente", bg: "#fef3c7", color: "#92400e" },
@@ -95,6 +120,8 @@ const s = {
95
120
  };
96
121
 
97
122
  exports.C = C;
123
+ exports.REWRITE_STYLES = REWRITE_STYLES;
124
+ exports.layoutStyles = layoutStyles;
98
125
  exports.projectStatusLabels = projectStatusLabels;
99
126
  exports.s = s;
100
127
  exports.statusLabels = statusLabels;
@@ -1,4 +1,29 @@
1
1
  "use client";
2
+ const REWRITE_STYLES = [
3
+ { id: "auto", label: "\u270F\uFE0F Auto", desc: "Garde le ton actuel" },
4
+ { id: "tutoyer", label: "\u{1F44B} Tutoyer", desc: "Passe en tu" },
5
+ { id: "vouvoyer", label: "\u{1F3A9} Vouvoyer", desc: "Passe en vous" },
6
+ { id: "formel", label: "\u{1F4BC} Formel", desc: "Ton professionnel" },
7
+ { id: "amical", label: "\u{1F60A} Amical", desc: "Ton chaleureux" },
8
+ { id: "court", label: "\u26A1 Court", desc: "Version concise" }
9
+ ];
10
+ const layoutStyles = {
11
+ root: { padding: "12px 0" },
12
+ twoColumns: {
13
+ display: "grid",
14
+ gridTemplateColumns: "1fr 320px",
15
+ gap: "16px",
16
+ alignItems: "start"
17
+ },
18
+ mainColumn: { minWidth: 0 },
19
+ sideColumn: {
20
+ display: "flex",
21
+ flexDirection: "column",
22
+ gap: "12px",
23
+ position: "sticky",
24
+ top: "80px"
25
+ }
26
+ };
2
27
  const statusLabels = {
3
28
  open: { label: "Ouvert", bg: "#dbeafe", color: "#1e40af" },
4
29
  waiting_client: { label: "Attente", bg: "#fef3c7", color: "#92400e" },
@@ -93,4 +118,4 @@ const s = {
93
118
  })
94
119
  };
95
120
 
96
- export { C, projectStatusLabels, s, statusLabels };
121
+ export { C, REWRITE_STYLES, layoutStyles, projectStatusLabels, s, statusLabels };
@@ -0,0 +1,20 @@
1
+ 'use strict';
2
+
3
+ var react = require('react');
4
+
5
+ function useDocumentIdFromUrl() {
6
+ const [id, setId] = react.useState(void 0);
7
+ react.useEffect(() => {
8
+ const match = window.location.pathname.match(
9
+ /\/admin\/collections\/[^/]+\/([^/?#]+)/
10
+ );
11
+ if (match && match[1] !== "create") {
12
+ const raw = match[1];
13
+ const num = Number(raw);
14
+ setId(Number.isFinite(num) && String(num) === raw ? num : raw);
15
+ }
16
+ }, []);
17
+ return { id };
18
+ }
19
+
20
+ exports.useDocumentIdFromUrl = useDocumentIdFromUrl;
@@ -0,0 +1,19 @@
1
+ "use client";
2
+ import { useState, useEffect } from 'react';
3
+
4
+ function useDocumentIdFromUrl() {
5
+ const [id, setId] = useState(void 0);
6
+ useEffect(() => {
7
+ const match = window.location.pathname.match(
8
+ /\/admin\/collections\/[^/]+\/([^/?#]+)/
9
+ );
10
+ if (match && match[1] !== "create") {
11
+ const raw = match[1];
12
+ const num = Number(raw);
13
+ setId(Number.isFinite(num) && String(num) === raw ? num : raw);
14
+ }
15
+ }, []);
16
+ return { id };
17
+ }
18
+
19
+ export { useDocumentIdFromUrl };
@@ -19,155 +19,18 @@ var useMessageActions = require('./hooks/useMessageActions');
19
19
  var useTicketActions = require('./hooks/useTicketActions');
20
20
  var useReply = require('./hooks/useReply');
21
21
  var useAI = require('./hooks/useAI');
22
+ var useDocumentIdFromUrl = require('./hooks/useDocumentIdFromUrl');
22
23
  var config = require('./config');
24
+ var SkeletonText = require('./SkeletonText');
25
+ var RewriteDropdown = require('./RewriteDropdown');
23
26
  require('../../styles/theme.css');
24
27
 
25
28
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
26
29
 
27
30
  var React__default = /*#__PURE__*/_interopDefault(React);
28
31
 
29
- function useDocumentIdFromUrl() {
30
- const [id, setId] = React.useState(void 0);
31
- React.useEffect(() => {
32
- const match = window.location.pathname.match(
33
- /\/admin\/collections\/[^/]+\/([^/?#]+)/
34
- );
35
- if (match && match[1] !== "create") {
36
- const raw = match[1];
37
- const num = Number(raw);
38
- setId(Number.isFinite(num) && String(num) === raw ? num : raw);
39
- }
40
- }, []);
41
- return { id };
42
- }
43
- function SkeletonText({ lines = 3 }) {
44
- return /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", flexDirection: "column", gap: "8px", padding: "12px 0" }, children: Array.from({ length: lines }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsx(
45
- "div",
46
- {
47
- style: {
48
- height: "14px",
49
- borderRadius: "4px",
50
- backgroundColor: "#e2e8f0",
51
- width: i === lines - 1 ? "60%" : "100%",
52
- animation: "pulse 1.5s ease-in-out infinite"
53
- }
54
- },
55
- i
56
- )) });
57
- }
58
- const layoutStyles = {
59
- root: { padding: "12px 0" },
60
- twoColumns: {
61
- display: "grid",
62
- gridTemplateColumns: "1fr 320px",
63
- gap: "16px",
64
- alignItems: "start"
65
- },
66
- mainColumn: { minWidth: 0 },
67
- sideColumn: {
68
- display: "flex",
69
- flexDirection: "column",
70
- gap: "12px",
71
- position: "sticky",
72
- top: "80px"
73
- }
74
- };
75
- const REWRITE_STYLES = [
76
- { id: "auto", label: "\u270F\uFE0F Auto", desc: "Garde le ton actuel" },
77
- { id: "tutoyer", label: "\u{1F44B} Tutoyer", desc: "Passe en tu" },
78
- { id: "vouvoyer", label: "\u{1F3A9} Vouvoyer", desc: "Passe en vous" },
79
- { id: "formel", label: "\u{1F4BC} Formel", desc: "Ton professionnel" },
80
- { id: "amical", label: "\u{1F60A} Amical", desc: "Ton chaleureux" },
81
- { id: "court", label: "\u26A1 Court", desc: "Version concise" }
82
- ];
83
- const RewriteDropdown = ({ disabled, loading, onSelect }) => {
84
- const [open, setOpen] = React.useState(false);
85
- const ref = React__default.default.useRef(null);
86
- React__default.default.useEffect(() => {
87
- if (!open) return;
88
- const close = (e) => {
89
- if (ref.current && !ref.current.contains(e.target)) setOpen(false);
90
- };
91
- document.addEventListener("mousedown", close);
92
- return () => document.removeEventListener("mousedown", close);
93
- }, [open]);
94
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref, style: { position: "relative", display: "inline-block" }, children: [
95
- /* @__PURE__ */ jsxRuntime.jsxs(
96
- "button",
97
- {
98
- type: "button",
99
- onClick: () => setOpen(!open),
100
- disabled,
101
- style: {
102
- ...constants.s.outlineBtn("#0891b2", disabled),
103
- fontSize: "11px",
104
- padding: "3px 10px",
105
- borderRadius: "14px",
106
- display: "flex",
107
- alignItems: "center",
108
- gap: "4px"
109
- },
110
- children: [
111
- loading ? "Reformulation..." : "\u270F\uFE0F Reformuler",
112
- !loading && /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: 9, opacity: 0.7 }, children: "\u25BC" })
113
- ]
114
- }
115
- ),
116
- open && !disabled && !loading && /* @__PURE__ */ jsxRuntime.jsx(
117
- "div",
118
- {
119
- style: {
120
- position: "absolute",
121
- bottom: "100%",
122
- left: 0,
123
- marginBottom: 4,
124
- background: "var(--theme-elevation-0, #fff)",
125
- border: "1px solid var(--theme-elevation-200, #e5e7eb)",
126
- borderRadius: 8,
127
- boxShadow: "0 4px 16px rgba(0,0,0,0.12)",
128
- zIndex: 100,
129
- minWidth: 180,
130
- overflow: "hidden"
131
- },
132
- children: REWRITE_STYLES.map((style) => /* @__PURE__ */ jsxRuntime.jsxs(
133
- "button",
134
- {
135
- type: "button",
136
- onClick: () => {
137
- setOpen(false);
138
- onSelect(style.id);
139
- },
140
- style: {
141
- display: "flex",
142
- flexDirection: "column",
143
- width: "100%",
144
- padding: "8px 12px",
145
- border: "none",
146
- background: "transparent",
147
- cursor: "pointer",
148
- textAlign: "left",
149
- borderBottom: "1px solid var(--theme-elevation-100, #f3f4f6)",
150
- transition: "background 120ms"
151
- },
152
- onMouseEnter: (e) => {
153
- e.target.style.background = "var(--theme-elevation-50, #f9fafb)";
154
- },
155
- onMouseLeave: (e) => {
156
- e.target.style.background = "transparent";
157
- },
158
- children: [
159
- /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: 12, fontWeight: 600, color: "var(--theme-text, #111)" }, children: style.label }),
160
- /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: 10, color: "var(--theme-elevation-500, #6b7280)" }, children: style.desc })
161
- ]
162
- },
163
- style.id
164
- ))
165
- }
166
- )
167
- ] });
168
- };
169
32
  const TicketConversation = () => {
170
- const { id } = useDocumentIdFromUrl();
33
+ const { id } = useDocumentIdFromUrl.useDocumentIdFromUrl();
171
34
  const [features] = React.useState(() => config.getFeatures());
172
35
  const [messages, setMessages] = React.useState([]);
173
36
  const [timeEntries, setTimeEntries] = React.useState([]);
@@ -483,7 +346,7 @@ const TicketConversation = () => {
483
346
  ];
484
347
  }
485
348
  })();
486
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: layoutStyles.root, children: [
349
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: constants.layoutStyles.root, children: [
487
350
  /* @__PURE__ */ jsxRuntime.jsx(
488
351
  TicketHeader.TicketHeader,
489
352
  {
@@ -499,8 +362,8 @@ const TicketConversation = () => {
499
362
  }
500
363
  ),
501
364
  client && /* @__PURE__ */ jsxRuntime.jsx(ClientBar.ClientBar, { client }),
502
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: layoutStyles.twoColumns, children: [
503
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: layoutStyles.mainColumn, children: [
365
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: constants.layoutStyles.twoColumns, children: [
366
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: constants.layoutStyles.mainColumn, children: [
504
367
  /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { marginBottom: "4px", display: "flex", alignItems: "center", gap: "10px" }, children: [
505
368
  /* @__PURE__ */ jsxRuntime.jsxs("h3", { style: { fontSize: "14px", fontWeight: 600, margin: 0, display: "flex", alignItems: "center", gap: "8px" }, children: [
506
369
  "Conversation ",
@@ -517,7 +380,7 @@ const TicketConversation = () => {
517
380
  }
518
381
  ) })
519
382
  ] }),
520
- loading ? /* @__PURE__ */ jsxRuntime.jsx(SkeletonText, { lines: 4 }) : messages.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("p", { style: { color: "#999", fontStyle: "italic", padding: "12px 0" }, children: "Aucun message." }) : /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", flexDirection: "column", gap: "10px", marginBottom: "16px", paddingRight: "4px" }, children: (() => {
383
+ loading ? /* @__PURE__ */ jsxRuntime.jsx(SkeletonText.SkeletonText, { lines: 4 }) : messages.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("p", { style: { color: "#999", fontStyle: "italic", padding: "12px 0" }, children: "Aucun message." }) : /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", flexDirection: "column", gap: "10px", marginBottom: "16px", paddingRight: "4px" }, children: (() => {
521
384
  const filtered = messages.filter((msg) => !searchQuery.trim() || msg.body.toLowerCase().includes(searchQuery.toLowerCase()));
522
385
  const isSearching = searchQuery.trim().length > 0;
523
386
  const VISIBLE_COUNT = 3;
@@ -902,7 +765,7 @@ const TicketConversation = () => {
902
765
  }
903
766
  ),
904
767
  features.ai && /* @__PURE__ */ jsxRuntime.jsx(
905
- RewriteDropdown,
768
+ RewriteDropdown.RewriteDropdown,
906
769
  {
907
770
  disabled: aiRewriting || !replyBody.trim(),
908
771
  loading: aiRewriting,
@@ -1173,7 +1036,7 @@ const TicketConversation = () => {
1173
1036
  }
1174
1037
  )
1175
1038
  ] }),
1176
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: layoutStyles.sideColumn, children: [
1039
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: constants.layoutStyles.sideColumn, children: [
1177
1040
  /* @__PURE__ */ jsxRuntime.jsx(
1178
1041
  TimeTrackingPanel.TimeTrackingPanel,
1179
1042
  {