@consilioweb/payload-support 0.5.1 → 0.6.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 (86) hide show
  1. package/dist/components/TicketConversation/components/AISummaryPanel.js +76 -0
  2. package/dist/components/TicketConversation/components/ActionPanels.js +118 -0
  3. package/dist/components/TicketConversation/components/ActivityLog.js +23 -0
  4. package/dist/components/TicketConversation/components/ClientBar.js +42 -0
  5. package/dist/components/TicketConversation/components/ClientHistory.js +137 -0
  6. package/dist/components/TicketConversation/components/CodeBlock.js +152 -0
  7. package/dist/components/TicketConversation/components/CodeBlockInserter.js +155 -0
  8. package/dist/components/TicketConversation/components/QuickActions.js +65 -0
  9. package/dist/components/TicketConversation/components/TicketHeader.js +92 -0
  10. package/dist/components/TicketConversation/components/TimeTrackingPanel.js +133 -0
  11. package/dist/components/TicketConversation/config.js +41 -0
  12. package/dist/components/TicketConversation/constants.js +96 -0
  13. package/dist/components/TicketConversation/context.js +11 -0
  14. package/dist/components/TicketConversation/hooks/useAI.js +176 -0
  15. package/dist/components/TicketConversation/hooks/useMessageActions.js +135 -0
  16. package/dist/components/TicketConversation/hooks/useReply.js +187 -0
  17. package/dist/components/TicketConversation/hooks/useTicketActions.js +230 -0
  18. package/dist/components/TicketConversation/hooks/useTimeTracking.js +122 -0
  19. package/dist/components/TicketConversation/hooks/useTranslation.js +70 -0
  20. package/dist/components/TicketConversation/index.js +1123 -0
  21. package/dist/components/TicketConversation/locales/en.json +878 -0
  22. package/dist/components/TicketConversation/locales/fr.json +878 -0
  23. package/dist/components/TicketConversation/types.js +2 -0
  24. package/dist/components/TicketConversation/utils.js +25 -0
  25. package/dist/index.cjs +2 -2
  26. package/dist/index.js +2 -2
  27. package/dist/styles/BillingView.module.scss +311 -0
  28. package/dist/styles/ChatView.module.scss +438 -0
  29. package/dist/styles/CommandPalette.module.scss +160 -0
  30. package/dist/styles/CrmView.module.scss +554 -0
  31. package/dist/styles/EmailTracking.module.scss +238 -0
  32. package/dist/styles/ImportConversation.module.scss +267 -0
  33. package/dist/styles/Layout.module.scss +55 -0
  34. package/dist/styles/Logs.module.scss +164 -0
  35. package/dist/styles/NewTicket.module.scss +143 -0
  36. package/dist/styles/PendingEmails.module.scss +629 -0
  37. package/dist/styles/SupportDashboard.module.scss +649 -0
  38. package/dist/styles/TicketDetail.module.scss +1050 -0
  39. package/dist/styles/TicketInbox.module.scss +296 -0
  40. package/dist/styles/TicketingSettings.module.scss +358 -0
  41. package/dist/styles/TimeDashboard.module.scss +287 -0
  42. package/dist/styles/_tokens.scss +78 -0
  43. package/dist/styles/theme.css +633 -0
  44. package/dist/views/BillingView/client.js +204 -0
  45. package/dist/views/BillingView/index.js +29 -0
  46. package/dist/views/ChatView/client.js +252 -0
  47. package/dist/views/ChatView/index.js +29 -0
  48. package/dist/views/CrmView/client.js +232 -0
  49. package/dist/views/CrmView/index.js +29 -0
  50. package/dist/views/EmailTrackingView/client.js +154 -0
  51. package/dist/views/EmailTrackingView/index.js +29 -0
  52. package/dist/views/ImportConversationView/client.js +204 -0
  53. package/dist/views/ImportConversationView/index.js +29 -0
  54. package/dist/views/LogsView/client.js +148 -0
  55. package/dist/views/LogsView/index.js +27 -0
  56. package/dist/views/NewTicketView/client.js +224 -0
  57. package/dist/views/NewTicketView/index.js +27 -0
  58. package/dist/views/PendingEmailsView/client.js +172 -0
  59. package/dist/views/PendingEmailsView/index.js +29 -0
  60. package/dist/views/SupportDashboardView/client.js +296 -0
  61. package/dist/views/SupportDashboardView/index.js +29 -0
  62. package/dist/views/TicketDetailView/client.js +844 -0
  63. package/dist/views/TicketDetailView/index.js +29 -0
  64. package/dist/views/TicketInboxView/client.js +294 -0
  65. package/dist/views/TicketInboxView/index.js +27 -0
  66. package/dist/views/TicketingSettingsView/TicketingSettings.module.scss +350 -0
  67. package/dist/views/TicketingSettingsView/client.js +728 -0
  68. package/dist/views/TicketingSettingsView/index.js +29 -0
  69. package/dist/views/TimeDashboardView/client.js +164 -0
  70. package/dist/views/TimeDashboardView/index.js +29 -0
  71. package/dist/views/shared/AdminViewHeader.js +67 -0
  72. package/dist/views/shared/ErrorBoundary.js +50 -0
  73. package/dist/views/shared/Skeleton.js +72 -0
  74. package/dist/views/shared/adminTokens.js +32 -0
  75. package/dist/views/shared/config.js +41 -0
  76. package/dist/views/shared/index.js +6 -0
  77. package/package.json +9 -12
  78. package/src/collections/Tickets.ts +1 -1
  79. package/src/components/TicketConversation/index.tsx +21 -2
  80. package/src/plugin.ts +3 -2
  81. package/src/styles/TicketDetail.module.scss +8 -1
  82. package/src/views/TicketingSettingsView/TicketingSettings.module.scss +350 -0
  83. package/src/views/TicketingSettingsView/client.tsx +1 -1
  84. package/dist/views.d.cts +0 -30
  85. package/dist/views.d.ts +0 -30
  86. package/src/views.ts +0 -16
@@ -0,0 +1,27 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import { DefaultTemplate } from '@payloadcms/next/templates';
3
+ import { redirect } from 'next/navigation';
4
+ import { AdminErrorBoundary } from '../shared/ErrorBoundary';
5
+ import { NewTicketClient } from './client';
6
+
7
+ const NewTicketView = ({ initPageResult }) => {
8
+ const { req, visibleEntities } = initPageResult;
9
+ if (!req.user) redirect("/admin/login");
10
+ return /* @__PURE__ */ jsx(
11
+ DefaultTemplate,
12
+ {
13
+ i18n: req.i18n,
14
+ locale: initPageResult.locale,
15
+ params: {},
16
+ payload: req.payload,
17
+ permissions: initPageResult.permissions,
18
+ searchParams: {},
19
+ user: req.user,
20
+ visibleEntities,
21
+ children: /* @__PURE__ */ jsx(AdminErrorBoundary, { viewName: "NewTicketView", children: /* @__PURE__ */ jsx(NewTicketClient, {}) })
22
+ }
23
+ );
24
+ };
25
+ var NewTicketView_default = NewTicketView;
26
+
27
+ export { NewTicketView, NewTicketView_default as default };
@@ -0,0 +1,172 @@
1
+ "use client";
2
+ import { jsxs, jsx } from 'react/jsx-runtime';
3
+ import { useState, useCallback, useEffect } from 'react';
4
+ import { useTranslation } from '../../components/TicketConversation/hooks/useTranslation';
5
+
6
+ function timeAgo(dateStr) {
7
+ const diff = Date.now() - new Date(dateStr).getTime();
8
+ const mins = Math.floor(diff / 6e4);
9
+ if (mins < 1) return "a l'instant";
10
+ if (mins < 60) return `il y a ${mins}min`;
11
+ const hours = Math.floor(mins / 60);
12
+ if (hours < 24) return `il y a ${hours}h`;
13
+ return `il y a ${Math.floor(hours / 24)}j`;
14
+ }
15
+ function EmailCard({ email, onProcess, processing, t }) {
16
+ const [expanded, setExpanded] = useState(false);
17
+ const [showLinkModal, setShowLinkModal] = useState(false);
18
+ const [linkSearch, setLinkSearch] = useState("");
19
+ const [linkResults, setLinkResults] = useState([]);
20
+ const isPending = email.status === "pending";
21
+ const preview = email.body.slice(0, 200) + (email.body.length > 200 ? "..." : "");
22
+ const suggestions = email.suggestedTickets || [];
23
+ useEffect(() => {
24
+ if (!linkSearch || linkSearch.length < 2) {
25
+ setLinkResults([]);
26
+ return;
27
+ }
28
+ const timer = setTimeout(async () => {
29
+ try {
30
+ const res = await fetch(`/api/tickets?where[or][0][ticketNumber][contains]=${encodeURIComponent(linkSearch)}&where[or][1][subject][contains]=${encodeURIComponent(linkSearch)}&limit=10&sort=-updatedAt&depth=0`);
31
+ if (res.ok) {
32
+ const data = await res.json();
33
+ setLinkResults(data.docs.map((d) => ({ id: d.id, ticketNumber: d.ticketNumber, subject: d.subject })));
34
+ }
35
+ } catch (err) {
36
+ console.warn("[support] ticket search error:", err);
37
+ }
38
+ }, 300);
39
+ return () => clearTimeout(timer);
40
+ }, [linkSearch]);
41
+ const S = {
42
+ card: { padding: 16, borderRadius: 10, border: "1px solid var(--theme-elevation-150)", marginBottom: 12, opacity: processing ? 0.5 : 1 },
43
+ senderName: { fontWeight: 600, fontSize: 14 },
44
+ senderEmail: { fontSize: 12, color: "var(--theme-elevation-500)" },
45
+ subject: { fontWeight: 600, fontSize: 13, marginTop: 4 },
46
+ meta: { fontSize: 12, color: "var(--theme-elevation-400)", marginTop: 2 },
47
+ body: { fontSize: 13, color: "var(--theme-text)", padding: "8px 0", whiteSpace: "pre-wrap", lineHeight: 1.5 },
48
+ actions: { display: "flex", gap: 8, marginTop: 8 },
49
+ btn: { padding: "6px 14px", borderRadius: 6, border: "1px solid var(--theme-elevation-200)", fontSize: 12, fontWeight: 600, cursor: "pointer", background: "var(--theme-elevation-0)", color: "var(--theme-text)" },
50
+ btnCreate: { background: "#2563eb", color: "#fff", border: "none" },
51
+ btnIgnore: { color: "#dc2626", borderColor: "#dc2626" },
52
+ overlay: { position: "fixed", inset: 0, background: "rgba(0,0,0,0.5)", display: "flex", alignItems: "center", justifyContent: "center", zIndex: 100 },
53
+ modal: { background: "var(--theme-elevation-0)", borderRadius: 12, padding: 24, maxWidth: 480, width: "100%", maxHeight: "80vh", overflowY: "auto" }
54
+ };
55
+ return /* @__PURE__ */ jsxs("div", { style: S.card, children: [
56
+ /* @__PURE__ */ jsxs("div", { children: [
57
+ /* @__PURE__ */ jsx("span", { style: S.senderName, children: email.senderName || email.senderEmail }),
58
+ email.senderName && /* @__PURE__ */ jsxs("span", { style: S.senderEmail, children: [
59
+ " <",
60
+ email.senderEmail,
61
+ ">"
62
+ ] })
63
+ ] }),
64
+ /* @__PURE__ */ jsx("div", { style: S.subject, children: email.subject }),
65
+ /* @__PURE__ */ jsxs("div", { style: S.meta, children: [
66
+ timeAgo(email.createdAt),
67
+ " ",
68
+ email.attachments?.length ? `-- ${email.attachments.length} PJ` : ""
69
+ ] }),
70
+ suggestions.length > 0 && isPending && /* @__PURE__ */ jsx("div", { style: { display: "flex", gap: 6, marginTop: 6, flexWrap: "wrap" }, children: suggestions.map((s2) => /* @__PURE__ */ jsxs("span", { style: { padding: "2px 8px", borderRadius: 4, fontSize: 11, background: s2.score >= 0.7 ? "#dcfce7" : "#fef3c7", color: s2.score >= 0.7 ? "#166534" : "#92400e" }, children: [
71
+ "Similaire a ",
72
+ s2.ticketNumber,
73
+ " (",
74
+ Math.round(s2.score * 100),
75
+ "%)"
76
+ ] }, s2.id)) }),
77
+ /* @__PURE__ */ jsx("div", { style: S.body, children: expanded ? email.body : preview }),
78
+ email.body.length > 200 && /* @__PURE__ */ jsx("button", { onClick: () => setExpanded(!expanded), style: { ...S.btn, fontSize: 11, padding: "2px 8px" }, children: expanded ? t("pendingEmails.collapse") : t("pendingEmails.expand") }),
79
+ isPending && /* @__PURE__ */ jsxs("div", { style: S.actions, children: [
80
+ /* @__PURE__ */ jsx("button", { onClick: () => {
81
+ const clientId = typeof email.client === "object" && email.client ? email.client.id : void 0;
82
+ onProcess("create_ticket", void 0, clientId);
83
+ }, disabled: processing, style: { ...S.btn, ...S.btnCreate }, children: t("pendingEmails.actions.createTicket") }),
84
+ /* @__PURE__ */ jsx("button", { onClick: () => setShowLinkModal(true), disabled: processing, style: S.btn, children: t("pendingEmails.actions.linkToTicket") }),
85
+ /* @__PURE__ */ jsx("button", { onClick: () => onProcess("ignore"), disabled: processing, style: { ...S.btn, ...S.btnIgnore }, children: t("pendingEmails.actions.ignore") })
86
+ ] }),
87
+ showLinkModal && /* @__PURE__ */ jsx("div", { style: S.overlay, onClick: () => setShowLinkModal(false), children: /* @__PURE__ */ jsxs("div", { style: S.modal, onClick: (e) => e.stopPropagation(), children: [
88
+ /* @__PURE__ */ jsx("h3", { style: { margin: "0 0 12px", fontSize: 16, fontWeight: 700 }, children: t("pendingEmails.linkModal.title") }),
89
+ suggestions.length > 0 && /* @__PURE__ */ jsxs("div", { style: { marginBottom: 12 }, children: [
90
+ /* @__PURE__ */ jsx("div", { style: { fontSize: 12, fontWeight: 600, marginBottom: 4, color: "var(--theme-elevation-500)" }, children: t("pendingEmails.linkModal.suggestions") }),
91
+ suggestions.map((s2) => /* @__PURE__ */ jsxs("button", { onClick: () => {
92
+ setShowLinkModal(false);
93
+ onProcess("add_to_ticket", s2.id);
94
+ }, style: { display: "block", width: "100%", padding: "8px 12px", border: "1px solid var(--theme-elevation-200)", borderRadius: 6, background: "var(--theme-elevation-0)", cursor: "pointer", textAlign: "left", marginBottom: 4, fontSize: 13 }, children: [
95
+ /* @__PURE__ */ jsx("strong", { children: s2.ticketNumber }),
96
+ " ",
97
+ s2.subject,
98
+ " ",
99
+ /* @__PURE__ */ jsxs("span", { style: { fontSize: 11, color: "#16a34a" }, children: [
100
+ Math.round(s2.score * 100),
101
+ "%"
102
+ ] })
103
+ ] }, s2.id))
104
+ ] }),
105
+ /* @__PURE__ */ jsx("input", { type: "text", placeholder: t("pendingEmails.linkModal.searchPlaceholder"), value: linkSearch, onChange: (e) => setLinkSearch(e.target.value), style: { width: "100%", padding: "8px 12px", borderRadius: 6, border: "1px solid var(--theme-elevation-200)", fontSize: 13, marginBottom: 8, color: "var(--theme-text)", background: "var(--theme-elevation-0)" } }),
106
+ linkResults.map((r) => /* @__PURE__ */ jsxs("button", { onClick: () => {
107
+ setShowLinkModal(false);
108
+ onProcess("add_to_ticket", r.id);
109
+ }, style: { display: "block", width: "100%", padding: "8px 12px", border: "1px solid var(--theme-elevation-200)", borderRadius: 6, background: "var(--theme-elevation-0)", cursor: "pointer", textAlign: "left", marginBottom: 4, fontSize: 13 }, children: [
110
+ /* @__PURE__ */ jsx("strong", { children: r.ticketNumber }),
111
+ " ",
112
+ r.subject
113
+ ] }, r.id))
114
+ ] }) })
115
+ ] });
116
+ }
117
+ const PendingEmailsClient = () => {
118
+ const { t } = useTranslation();
119
+ const [emails, setEmails] = useState([]);
120
+ const [loading, setLoading] = useState(true);
121
+ const [tab, setTab] = useState("pending");
122
+ const [processing, setProcessing] = useState(null);
123
+ const fetchEmails = useCallback(async () => {
124
+ try {
125
+ const res = await fetch(`/api/pending-emails?where[status][equals]=${tab}&sort=-createdAt&limit=50&depth=1`);
126
+ if (res.ok) {
127
+ const data = await res.json();
128
+ setEmails(data.docs);
129
+ }
130
+ } catch {
131
+ }
132
+ setLoading(false);
133
+ }, [tab]);
134
+ useEffect(() => {
135
+ setLoading(true);
136
+ fetchEmails();
137
+ }, [fetchEmails]);
138
+ useEffect(() => {
139
+ if (tab !== "pending") return;
140
+ const iv = setInterval(fetchEmails, 3e4);
141
+ return () => clearInterval(iv);
142
+ }, [fetchEmails, tab]);
143
+ const handleProcess = async (emailId, action, ticketId, clientId) => {
144
+ setProcessing(emailId);
145
+ try {
146
+ const res = await fetch(`/api/support/pending-emails/${emailId}/process`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ action, ticketId, clientId }) });
147
+ if (res.ok) {
148
+ setEmails((prev) => prev.filter((e) => e.id !== emailId));
149
+ } else {
150
+ const err = await res.json().catch(() => ({ error: "Unknown error" }));
151
+ alert(`Erreur : ${err.error || res.statusText}`);
152
+ }
153
+ } catch {
154
+ alert("Erreur reseau");
155
+ }
156
+ setProcessing(null);
157
+ };
158
+ const tabs = [{ key: "pending", label: t("pendingEmails.tabs.pending") }, { key: "processed", label: t("pendingEmails.tabs.processed") }, { key: "ignored", label: t("pendingEmails.tabs.ignored") }];
159
+ return /* @__PURE__ */ jsxs("div", { style: { padding: "20px 30px", maxWidth: 900, margin: "0 auto" }, children: [
160
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 16 }, children: [
161
+ /* @__PURE__ */ jsxs("div", { children: [
162
+ /* @__PURE__ */ jsx("h1", { style: { fontSize: 22, fontWeight: 700, margin: 0, color: "var(--theme-text)" }, children: t("pendingEmails.title") }),
163
+ /* @__PURE__ */ jsx("p", { style: { fontSize: 13, color: "var(--theme-elevation-500)", margin: "4px 0 0" }, children: t("pendingEmails.subtitle") })
164
+ ] }),
165
+ tab === "pending" && emails.length > 0 && /* @__PURE__ */ jsx("span", { style: { padding: "4px 10px", borderRadius: 10, background: "#fef2f2", color: "#dc2626", fontSize: 12, fontWeight: 700 }, children: t("pendingEmails.pendingCount", { count: String(emails.length) }) })
166
+ ] }),
167
+ /* @__PURE__ */ jsx("div", { style: { display: "flex", gap: 4, marginBottom: 16 }, children: tabs.map((tb) => /* @__PURE__ */ jsx("button", { onClick: () => setTab(tb.key), style: { padding: "6px 12px", borderRadius: 6, border: "none", background: tab === tb.key ? "var(--theme-elevation-100)" : "none", cursor: "pointer", fontSize: 13, fontWeight: tab === tb.key ? 700 : 500, color: tab === tb.key ? "var(--theme-text)" : "var(--theme-elevation-500)" }, children: tb.label }, tb.key)) }),
168
+ loading ? /* @__PURE__ */ jsx("div", { style: { padding: 40, textAlign: "center", color: "#94a3b8" }, children: t("common.loading") }) : emails.length === 0 ? /* @__PURE__ */ jsx("div", { style: { padding: 40, textAlign: "center", color: "#94a3b8" }, children: t(`pendingEmails.empty.${tab}`) }) : emails.map((email) => /* @__PURE__ */ jsx(EmailCard, { email, onProcess: (action, ticketId, clientId) => handleProcess(email.id, action, ticketId, clientId), processing: processing === email.id, t }, email.id))
169
+ ] });
170
+ };
171
+
172
+ export { PendingEmailsClient };
@@ -0,0 +1,29 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import { DefaultTemplate } from '@payloadcms/next/templates';
3
+ import { redirect } from 'next/navigation';
4
+ import { AdminErrorBoundary } from '../shared/ErrorBoundary';
5
+ import { PendingEmailsClient } from './client';
6
+
7
+ const PendingEmailsView = ({ initPageResult }) => {
8
+ const { req, visibleEntities } = initPageResult;
9
+ if (!req.user) {
10
+ redirect("/admin/login");
11
+ }
12
+ return /* @__PURE__ */ jsx(
13
+ DefaultTemplate,
14
+ {
15
+ i18n: req.i18n,
16
+ locale: initPageResult.locale,
17
+ params: {},
18
+ payload: req.payload,
19
+ permissions: initPageResult.permissions,
20
+ searchParams: {},
21
+ user: req.user,
22
+ visibleEntities,
23
+ children: /* @__PURE__ */ jsx(AdminErrorBoundary, { viewName: "PendingEmailsView", children: /* @__PURE__ */ jsx(PendingEmailsClient, {}) })
24
+ }
25
+ );
26
+ };
27
+ var PendingEmailsView_default = PendingEmailsView;
28
+
29
+ export { PendingEmailsView, PendingEmailsView_default as default };
@@ -0,0 +1,296 @@
1
+ "use client";
2
+ import { jsxs, jsx } from 'react/jsx-runtime';
3
+ import { useState, useCallback, useEffect, useMemo } from 'react';
4
+ import Link from 'next/link';
5
+ import { useTranslation } from '../../components/TicketConversation/hooks/useTranslation';
6
+
7
+ function formatResponseTime(hours) {
8
+ if (hours == null) return "--";
9
+ const h = Math.floor(hours);
10
+ const m = Math.round((hours - h) * 60);
11
+ if (h === 0) return `${m}m`;
12
+ if (m === 0) return `${h}h`;
13
+ return `${h}h${m.toString().padStart(2, "0")}m`;
14
+ }
15
+ function timeAgo(dateStr) {
16
+ const diff = Date.now() - new Date(dateStr).getTime();
17
+ const mins = Math.floor(diff / 6e4);
18
+ if (mins < 1) return "a l'instant";
19
+ if (mins < 60) return `${mins}min`;
20
+ const hours = Math.floor(mins / 60);
21
+ if (hours < 24) return `${hours}h`;
22
+ const days = Math.floor(hours / 24);
23
+ if (days < 7) return `${days}j`;
24
+ return `${Math.floor(days / 7)}sem`;
25
+ }
26
+ function computeTrend(current, previous) {
27
+ if (previous === 0 && current === 0) return { pct: 0, dir: "neutral" };
28
+ if (previous === 0) return { pct: 100, dir: "up" };
29
+ const pct = Math.round((current - previous) / previous * 100);
30
+ if (pct === 0) return { pct: 0, dir: "neutral" };
31
+ return { pct: Math.abs(pct), dir: pct > 0 ? "up" : "down" };
32
+ }
33
+ function StatCard({ label, value, trend, accentColor }) {
34
+ return /* @__PURE__ */ jsxs("div", { style: { padding: "16px 20px", borderRadius: 10, border: "1px solid var(--theme-elevation-150)", background: "var(--theme-elevation-0)", borderLeft: `3px solid ${accentColor || "#2563eb"}` }, children: [
35
+ /* @__PURE__ */ jsx("div", { style: { fontSize: 12, color: "var(--theme-elevation-500)", marginBottom: 4 }, children: label }),
36
+ /* @__PURE__ */ jsx("div", { style: { fontSize: 24, fontWeight: 700, color: "var(--theme-text)" }, children: value }),
37
+ trend && trend.dir !== "neutral" && /* @__PURE__ */ jsxs("div", { style: { fontSize: 11, color: trend.dir === "up" ? "#dc2626" : "#16a34a", marginTop: 4 }, children: [
38
+ trend.dir === "up" ? "\u2191" : "\u2193",
39
+ " ",
40
+ trend.pct,
41
+ "%"
42
+ ] }),
43
+ trend && trend.dir === "neutral" && /* @__PURE__ */ jsx("div", { style: { fontSize: 11, color: "#6b7280", marginTop: 4 }, children: "-- stable" })
44
+ ] });
45
+ }
46
+ function formatSlaTime(minutes) {
47
+ const absMin = Math.abs(minutes);
48
+ if (absMin < 60) return `${Math.round(absMin)}min`;
49
+ const h = Math.floor(absMin / 60);
50
+ const m = Math.round(absMin % 60);
51
+ if (h < 24) return m > 0 ? `${h}h${m.toString().padStart(2, "0")}` : `${h}h`;
52
+ const d = Math.floor(h / 24);
53
+ const remainH = h % 24;
54
+ return remainH > 0 ? `${d}j ${remainH}h` : `${d}j`;
55
+ }
56
+ function SlaSection() {
57
+ const { t } = useTranslation();
58
+ const [sla, setSla] = useState(null);
59
+ const [slaLoading, setSlaLoading] = useState(true);
60
+ useEffect(() => {
61
+ const fetchSla = async () => {
62
+ try {
63
+ const res = await fetch("/api/support/sla-check");
64
+ if (res.ok) setSla(await res.json());
65
+ } catch {
66
+ }
67
+ setSlaLoading(false);
68
+ };
69
+ fetchSla();
70
+ const interval = setInterval(fetchSla, 6e4);
71
+ return () => clearInterval(interval);
72
+ }, []);
73
+ if (slaLoading) return /* @__PURE__ */ jsx("div", { style: { padding: 16, color: "#94a3b8", fontSize: 13 }, children: t("sla.loading") });
74
+ if (!sla) return null;
75
+ return /* @__PURE__ */ jsxs("div", { style: { marginTop: 24 }, children: [
76
+ /* @__PURE__ */ jsx("h2", { style: { fontSize: 16, fontWeight: 700, marginBottom: 12, color: "var(--theme-text)" }, children: t("sla.title") }),
77
+ /* @__PURE__ */ jsxs("div", { style: { display: "grid", gridTemplateColumns: "1fr 1fr", gap: 16 }, children: [
78
+ /* @__PURE__ */ jsxs("div", { style: { padding: 16, borderRadius: 10, border: "1px solid #fecaca", background: "#fef2f2" }, children: [
79
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between", marginBottom: 8 }, children: [
80
+ /* @__PURE__ */ jsx("h3", { style: { fontSize: 14, fontWeight: 700, color: "#dc2626", margin: 0 }, children: t("sla.breached") }),
81
+ /* @__PURE__ */ jsx("span", { style: { padding: "2px 8px", borderRadius: 10, background: "#fecaca", color: "#dc2626", fontSize: 12, fontWeight: 700 }, children: sla.breached.length })
82
+ ] }),
83
+ sla.breached.length === 0 ? /* @__PURE__ */ jsx("div", { style: { fontSize: 13, color: "#6b7280" }, children: t("sla.noBreached") }) : /* @__PURE__ */ jsx("ul", { style: { listStyle: "none", margin: 0, padding: 0 }, children: sla.breached.map((ticket) => {
84
+ const overdueMin = Math.round((Date.now() - new Date(ticket.createdAt).getTime()) / 6e4);
85
+ return /* @__PURE__ */ jsxs("li", { style: { padding: "6px 0", borderBottom: "1px solid #fecaca", cursor: "pointer", display: "flex", justifyContent: "space-between", alignItems: "center", fontSize: 13 }, onClick: () => {
86
+ window.location.href = `/admin/support/ticket?id=${ticket.id}`;
87
+ }, children: [
88
+ /* @__PURE__ */ jsxs("div", { children: [
89
+ /* @__PURE__ */ jsxs("span", { style: { fontWeight: 600 }, children: [
90
+ "#",
91
+ ticket.ticketNumber
92
+ ] }),
93
+ " ",
94
+ /* @__PURE__ */ jsx("span", { style: { color: "#6b7280" }, children: ticket.subject })
95
+ ] }),
96
+ /* @__PURE__ */ jsxs("span", { style: { color: "#dc2626", fontWeight: 600, fontSize: 12 }, children: [
97
+ "+",
98
+ formatSlaTime(overdueMin)
99
+ ] })
100
+ ] }, ticket.id);
101
+ }) })
102
+ ] }),
103
+ /* @__PURE__ */ jsxs("div", { style: { padding: 16, borderRadius: 10, border: "1px solid #fde68a", background: "#fefce8" }, children: [
104
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between", marginBottom: 8 }, children: [
105
+ /* @__PURE__ */ jsx("h3", { style: { fontSize: 14, fontWeight: 700, color: "#d97706", margin: 0 }, children: t("sla.atRisk") }),
106
+ /* @__PURE__ */ jsx("span", { style: { padding: "2px 8px", borderRadius: 10, background: "#fde68a", color: "#d97706", fontSize: 12, fontWeight: 700 }, children: sla.atRisk.length })
107
+ ] }),
108
+ sla.atRisk.length === 0 ? /* @__PURE__ */ jsx("div", { style: { fontSize: 13, color: "#6b7280" }, children: t("sla.noAtRisk") }) : /* @__PURE__ */ jsx("ul", { style: { listStyle: "none", margin: 0, padding: 0 }, children: sla.atRisk.map((ticket) => {
109
+ const elapsedMin = Math.round((Date.now() - new Date(ticket.createdAt).getTime()) / 6e4);
110
+ const estimatedTotalMin = Math.round(elapsedMin / 0.8);
111
+ const remainingMin = Math.max(estimatedTotalMin - elapsedMin, 0);
112
+ return /* @__PURE__ */ jsxs("li", { style: { padding: "6px 0", borderBottom: "1px solid #fde68a", cursor: "pointer", display: "flex", justifyContent: "space-between", alignItems: "center", fontSize: 13 }, onClick: () => {
113
+ window.location.href = `/admin/support/ticket?id=${ticket.id}`;
114
+ }, children: [
115
+ /* @__PURE__ */ jsxs("div", { children: [
116
+ /* @__PURE__ */ jsxs("span", { style: { fontWeight: 600 }, children: [
117
+ "#",
118
+ ticket.ticketNumber
119
+ ] }),
120
+ " ",
121
+ /* @__PURE__ */ jsx("span", { style: { color: "#6b7280" }, children: ticket.subject })
122
+ ] }),
123
+ /* @__PURE__ */ jsx("span", { style: { color: "#d97706", fontWeight: 600, fontSize: 12 }, children: t("sla.remaining", { time: formatSlaTime(remainingMin) }) })
124
+ ] }, ticket.id);
125
+ }) })
126
+ ] })
127
+ ] })
128
+ ] });
129
+ }
130
+ const SupportDashboardClient = () => {
131
+ const { t } = useTranslation();
132
+ const [stats, setStats] = useState(null);
133
+ const [tickets, setTickets] = useState([]);
134
+ const [loading, setLoading] = useState(true);
135
+ const [sessionExpired, setSessionExpired] = useState(false);
136
+ const fetchData = useCallback(async () => {
137
+ try {
138
+ const [statsRes, ticketsRes] = await Promise.all([
139
+ fetch("/api/support/admin-stats"),
140
+ fetch("/api/tickets?where[status][not_equals]=resolved&sort=-updatedAt&limit=8&depth=1")
141
+ ]);
142
+ if (statsRes.ok) {
143
+ setStats(await statsRes.json());
144
+ } else if (statsRes.status === 401 || statsRes.status === 403) {
145
+ setSessionExpired(true);
146
+ return;
147
+ }
148
+ if (ticketsRes.ok) {
149
+ const data = await ticketsRes.json();
150
+ setTickets(data.docs || []);
151
+ }
152
+ } catch {
153
+ }
154
+ setLoading(false);
155
+ }, []);
156
+ useEffect(() => {
157
+ fetchData();
158
+ if (sessionExpired) return;
159
+ const interval = setInterval(fetchData, 3e4);
160
+ return () => clearInterval(interval);
161
+ }, [fetchData, sessionExpired]);
162
+ useEffect(() => {
163
+ if (sessionExpired) return;
164
+ const onFocus = () => fetchData();
165
+ window.addEventListener("focus", onFocus);
166
+ return () => window.removeEventListener("focus", onFocus);
167
+ }, [fetchData, sessionExpired]);
168
+ const volumeData = useMemo(() => {
169
+ if (!stats) return [];
170
+ const avg = stats.createdLast7Days;
171
+ const days = [t("dashboard.weekDays.mon"), t("dashboard.weekDays.tue"), t("dashboard.weekDays.wed"), t("dashboard.weekDays.thu"), t("dashboard.weekDays.fri"), t("dashboard.weekDays.sat"), t("dashboard.weekDays.sun")];
172
+ const base = Math.max(Math.floor(avg / 7), 0);
173
+ return days.map((label, i) => ({
174
+ label,
175
+ value: Math.max(base + (i * 3 + 1) % 5 - 2, 0)
176
+ }));
177
+ }, [stats, t]);
178
+ if (loading) {
179
+ return /* @__PURE__ */ jsxs("div", { style: { padding: "20px 30px", maxWidth: 1100, margin: "0 auto" }, children: [
180
+ /* @__PURE__ */ jsx("h1", { style: { fontSize: 24, fontWeight: 700 }, children: t("dashboard.title") }),
181
+ /* @__PURE__ */ jsx("p", { style: { color: "#94a3b8" }, children: t("dashboard.loadingMetrics") }),
182
+ /* @__PURE__ */ jsx("div", { style: { display: "grid", gridTemplateColumns: "repeat(4, 1fr)", gap: 16, marginTop: 20 }, children: [0, 1, 2, 3].map((i) => /* @__PURE__ */ jsx("div", { style: { height: 80, borderRadius: 10, background: "#f1f5f9" } }, i)) })
183
+ ] });
184
+ }
185
+ if (!stats) {
186
+ return /* @__PURE__ */ jsx("div", { style: { padding: "20px 30px", maxWidth: 1100, margin: "0 auto" }, children: /* @__PURE__ */ jsxs("div", { style: { padding: 40, textAlign: "center", color: "#dc2626" }, children: [
187
+ /* @__PURE__ */ jsx("strong", { children: t("dashboard.loadError") }),
188
+ /* @__PURE__ */ jsx("p", { children: sessionExpired ? t("common.sessionExpired") : t("dashboard.cannotLoadStats") })
189
+ ] }) });
190
+ }
191
+ const openCount = stats.byStatus.open || 0;
192
+ const waitingCount = stats.byStatus.waiting_client || 0;
193
+ const trendOpen = computeTrend(stats.createdLast7Days, Math.round(stats.createdLast30Days / 4));
194
+ const waitingTrend = waitingCount === 0 ? { pct: 0, dir: "neutral" } : waitingCount > openCount * 0.5 ? { pct: Math.round(waitingCount / Math.max(openCount, 1) * 100), dir: "up" } : { pct: Math.round(100 - waitingCount / Math.max(openCount, 1) * 100), dir: "down" };
195
+ const getClientName = (ticket) => {
196
+ if (!ticket.client) return "--";
197
+ if (typeof ticket.client === "string") return ticket.client;
198
+ return ticket.client.company || ticket.client.firstName || "--";
199
+ };
200
+ const statusDotColor = (status) => {
201
+ switch (status) {
202
+ case "open":
203
+ return "#22c55e";
204
+ case "waiting_client":
205
+ return "#eab308";
206
+ case "resolved":
207
+ return "#94a3b8";
208
+ default:
209
+ return "#94a3b8";
210
+ }
211
+ };
212
+ const maxVolume = Math.max(...volumeData.map((d) => d.value), 1);
213
+ const csatScore = stats.satisfactionAvg;
214
+ const csatPct = csatScore > 0 ? csatScore / 5 * 100 : 0;
215
+ const csatRadius = 42;
216
+ const csatCircumference = 2 * Math.PI * csatRadius;
217
+ const csatStrokeDashoffset = csatCircumference - csatPct / 100 * csatCircumference;
218
+ const csatColor = csatScore >= 4 ? "#22c55e" : csatScore >= 3 ? "#f59e0b" : csatScore > 0 ? "#ef4444" : "#94a3b8";
219
+ return /* @__PURE__ */ jsxs("div", { style: { padding: "20px 30px", maxWidth: 1100, margin: "0 auto" }, children: [
220
+ /* @__PURE__ */ jsxs("div", { style: { marginBottom: 20 }, children: [
221
+ /* @__PURE__ */ jsx("h1", { style: { fontSize: 24, fontWeight: 700, margin: 0, color: "var(--theme-text)" }, children: t("dashboard.title") }),
222
+ /* @__PURE__ */ jsx("p", { style: { color: "var(--theme-elevation-500)", margin: "4px 0 0", fontSize: 14 }, children: t("dashboard.subtitle") })
223
+ ] }),
224
+ /* @__PURE__ */ jsxs("div", { style: { display: "grid", gridTemplateColumns: "repeat(4, 1fr)", gap: 16, marginBottom: 24 }, children: [
225
+ /* @__PURE__ */ jsx(StatCard, { label: t("dashboard.openTickets"), value: String(openCount), trend: trendOpen, accentColor: "#3b82f6" }),
226
+ /* @__PURE__ */ jsx(StatCard, { label: t("dashboard.waitingClient"), value: String(waitingCount), trend: waitingTrend, accentColor: "#f59e0b" }),
227
+ /* @__PURE__ */ jsx(StatCard, { label: t("dashboard.responseTime"), value: formatResponseTime(stats.avgResponseTimeHours), accentColor: stats.avgResponseTimeHours != null && stats.avgResponseTimeHours > 24 ? "#ef4444" : "#22c55e" }),
228
+ /* @__PURE__ */ jsx(StatCard, { label: t("dashboard.satisfaction"), value: stats.satisfactionAvg > 0 ? `${stats.satisfactionAvg}/5` : "--", accentColor: stats.satisfactionAvg >= 4 ? "#22c55e" : stats.satisfactionAvg >= 3 ? "#f59e0b" : "#94a3b8" })
229
+ ] }),
230
+ /* @__PURE__ */ jsxs("div", { style: { display: "grid", gridTemplateColumns: "1fr 320px", gap: 20, marginBottom: 24 }, children: [
231
+ /* @__PURE__ */ jsxs("div", { style: { padding: 16, borderRadius: 10, border: "1px solid var(--theme-elevation-150)" }, children: [
232
+ /* @__PURE__ */ jsx("h2", { style: { fontSize: 15, fontWeight: 700, margin: "0 0 12px", color: "var(--theme-text)" }, children: t("dashboard.activeTickets") }),
233
+ tickets.length === 0 ? /* @__PURE__ */ jsx("div", { style: { padding: 20, textAlign: "center", color: "#94a3b8" }, children: t("dashboard.noActiveTickets") }) : /* @__PURE__ */ jsxs("table", { style: { width: "100%", borderCollapse: "collapse", fontSize: 13 }, children: [
234
+ /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { children: [
235
+ /* @__PURE__ */ jsx("th", { style: { textAlign: "left", padding: "6px 8px", borderBottom: "1px solid var(--theme-elevation-200)", fontSize: 11, color: "var(--theme-elevation-500)" }, children: t("dashboard.tableHeaders.status") }),
236
+ /* @__PURE__ */ jsx("th", { style: { textAlign: "left", padding: "6px 8px", borderBottom: "1px solid var(--theme-elevation-200)", fontSize: 11, color: "var(--theme-elevation-500)" }, children: t("dashboard.tableHeaders.number") }),
237
+ /* @__PURE__ */ jsx("th", { style: { textAlign: "left", padding: "6px 8px", borderBottom: "1px solid var(--theme-elevation-200)", fontSize: 11, color: "var(--theme-elevation-500)" }, children: t("dashboard.tableHeaders.subject") }),
238
+ /* @__PURE__ */ jsx("th", { style: { textAlign: "left", padding: "6px 8px", borderBottom: "1px solid var(--theme-elevation-200)", fontSize: 11, color: "var(--theme-elevation-500)" }, children: t("dashboard.tableHeaders.client") }),
239
+ /* @__PURE__ */ jsx("th", { style: { textAlign: "left", padding: "6px 8px", borderBottom: "1px solid var(--theme-elevation-200)", fontSize: 11, color: "var(--theme-elevation-500)" }, children: t("dashboard.tableHeaders.modified") })
240
+ ] }) }),
241
+ /* @__PURE__ */ jsx("tbody", { children: tickets.map((tk) => /* @__PURE__ */ jsxs("tr", { style: { cursor: "pointer" }, onClick: () => {
242
+ window.location.href = `/admin/support/ticket?id=${tk.id}`;
243
+ }, children: [
244
+ /* @__PURE__ */ jsx("td", { style: { padding: "8px" }, children: /* @__PURE__ */ jsx("span", { style: { width: 8, height: 8, borderRadius: "50%", display: "inline-block", backgroundColor: statusDotColor(tk.status) } }) }),
245
+ /* @__PURE__ */ jsxs("td", { style: { padding: "8px", fontWeight: 600, fontSize: 12 }, children: [
246
+ "#",
247
+ tk.ticketNumber
248
+ ] }),
249
+ /* @__PURE__ */ jsx("td", { style: { padding: "8px", maxWidth: 250, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }, children: tk.subject }),
250
+ /* @__PURE__ */ jsx("td", { style: { padding: "8px", color: "var(--theme-elevation-500)", fontSize: 12 }, children: getClientName(tk) }),
251
+ /* @__PURE__ */ jsx("td", { style: { padding: "8px", color: "var(--theme-elevation-400)", fontSize: 12 }, children: timeAgo(tk.updatedAt) })
252
+ ] }, tk.id)) })
253
+ ] })
254
+ ] }),
255
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: 16 }, children: [
256
+ /* @__PURE__ */ jsxs("div", { style: { padding: 16, borderRadius: 10, border: "1px solid var(--theme-elevation-150)" }, children: [
257
+ /* @__PURE__ */ jsx("h2", { style: { fontSize: 15, fontWeight: 700, margin: "0 0 12px", color: "var(--theme-text)" }, children: t("dashboard.volume7days") }),
258
+ /* @__PURE__ */ jsx("div", { style: { display: "flex", alignItems: "flex-end", gap: 4, height: 80 }, children: volumeData.map((d, i) => /* @__PURE__ */ jsx("div", { style: { flex: 1, background: "#3b82f6", borderRadius: "3px 3px 0 0", height: `${Math.max(d.value / maxVolume * 100, 5)}%` }, title: `${d.label}: ${d.value}` }, i)) }),
259
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between", fontSize: 10, color: "var(--theme-elevation-400)", marginTop: 4 }, children: [
260
+ /* @__PURE__ */ jsx("span", { children: volumeData[0]?.label }),
261
+ /* @__PURE__ */ jsx("span", { children: volumeData[volumeData.length - 1]?.label })
262
+ ] })
263
+ ] }),
264
+ /* @__PURE__ */ jsxs("div", { style: { padding: 16, borderRadius: 10, border: "1px solid var(--theme-elevation-150)" }, children: [
265
+ /* @__PURE__ */ jsx("h2", { style: { fontSize: 15, fontWeight: 700, margin: "0 0 12px", color: "var(--theme-text)" }, children: t("dashboard.csat") }),
266
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: 16 }, children: [
267
+ /* @__PURE__ */ jsxs("div", { style: { position: "relative", width: 80, height: 80 }, children: [
268
+ /* @__PURE__ */ jsxs("svg", { width: "80", height: "80", viewBox: "0 0 100 100", children: [
269
+ /* @__PURE__ */ jsx("circle", { cx: "50", cy: "50", r: csatRadius, fill: "none", stroke: "var(--theme-elevation-150, #e2e8f0)", strokeWidth: "6" }),
270
+ /* @__PURE__ */ jsx("circle", { cx: "50", cy: "50", r: csatRadius, fill: "none", stroke: csatColor, strokeWidth: "6", strokeLinecap: "round", strokeDasharray: csatCircumference, strokeDashoffset: csatStrokeDashoffset, transform: "rotate(-90 50 50)", style: { transition: "stroke-dashoffset 600ms ease" } })
271
+ ] }),
272
+ /* @__PURE__ */ jsx("div", { style: { position: "absolute", inset: 0, display: "flex", alignItems: "center", justifyContent: "center", fontWeight: 700, fontSize: 16 }, children: csatScore > 0 ? csatScore.toFixed(1) : "--" })
273
+ ] }),
274
+ /* @__PURE__ */ jsxs("div", { children: [
275
+ /* @__PURE__ */ jsx("div", { style: { fontSize: 13, fontWeight: 600 }, children: csatScore > 0 ? `${csatScore.toFixed(1)} / 5` : t("dashboard.csatNoData") }),
276
+ /* @__PURE__ */ jsx("div", { style: { fontSize: 12, color: "var(--theme-elevation-500)" }, children: stats.satisfactionCount > 0 ? t("dashboard.csatReviews", { count: String(stats.satisfactionCount) }) : t("dashboard.csatNoReviews") })
277
+ ] })
278
+ ] })
279
+ ] })
280
+ ] })
281
+ ] }),
282
+ /* @__PURE__ */ jsx(SlaSection, {}),
283
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: 10, marginTop: 24, flexWrap: "wrap" }, children: [
284
+ /* @__PURE__ */ jsx(Link, { href: "/admin/support/new-ticket", style: { padding: "8px 16px", borderRadius: 8, background: "#2563eb", color: "#fff", fontSize: 13, fontWeight: 600, textDecoration: "none" }, children: t("dashboard.newTicketAction") }),
285
+ /* @__PURE__ */ jsxs(Link, { href: "/admin/support/emails", style: { padding: "8px 16px", borderRadius: 8, border: "1px solid var(--theme-elevation-200)", fontSize: 13, fontWeight: 500, textDecoration: "none", color: "var(--theme-text)", display: "flex", alignItems: "center", gap: 6 }, children: [
286
+ t("dashboard.pendingEmails"),
287
+ stats.pendingEmailsCount > 0 ? /* @__PURE__ */ jsx("span", { style: { padding: "1px 6px", borderRadius: 10, background: "#fef2f2", color: "#dc2626", fontSize: 11, fontWeight: 700 }, children: stats.pendingEmailsCount }) : /* @__PURE__ */ jsx("span", { style: { padding: "1px 6px", borderRadius: 10, background: "#dcfce7", color: "#16a34a", fontSize: 11, fontWeight: 700 }, children: "0" })
288
+ ] }),
289
+ /* @__PURE__ */ jsx(Link, { href: "/admin/support/crm", style: { padding: "8px 16px", borderRadius: 8, border: "1px solid var(--theme-elevation-200)", fontSize: 13, fontWeight: 500, textDecoration: "none", color: "var(--theme-text)" }, children: t("dashboard.crm") }),
290
+ /* @__PURE__ */ jsx(Link, { href: "/admin/support/billing", style: { padding: "8px 16px", borderRadius: 8, border: "1px solid var(--theme-elevation-200)", fontSize: 13, fontWeight: 500, textDecoration: "none", color: "var(--theme-text)" }, children: t("dashboard.preBilling") }),
291
+ /* @__PURE__ */ jsx("a", { href: "/api/support/export-csv", style: { padding: "8px 16px", borderRadius: 8, border: "1px solid var(--theme-elevation-200)", fontSize: 13, fontWeight: 500, textDecoration: "none", color: "var(--theme-text)" }, target: "_blank", rel: "noopener noreferrer", children: t("dashboard.exportCsv") })
292
+ ] })
293
+ ] });
294
+ };
295
+
296
+ export { SupportDashboardClient };
@@ -0,0 +1,29 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import { DefaultTemplate } from '@payloadcms/next/templates';
3
+ import { redirect } from 'next/navigation';
4
+ import { AdminErrorBoundary } from '../shared/ErrorBoundary';
5
+ import { SupportDashboardClient } from './client';
6
+
7
+ const SupportDashboardView = ({ initPageResult }) => {
8
+ const { req, visibleEntities } = initPageResult;
9
+ if (!req.user) {
10
+ redirect("/admin/login");
11
+ }
12
+ return /* @__PURE__ */ jsx(
13
+ DefaultTemplate,
14
+ {
15
+ i18n: req.i18n,
16
+ locale: initPageResult.locale,
17
+ params: {},
18
+ payload: req.payload,
19
+ permissions: initPageResult.permissions,
20
+ searchParams: {},
21
+ user: req.user,
22
+ visibleEntities,
23
+ children: /* @__PURE__ */ jsx(AdminErrorBoundary, { viewName: "SupportDashboardView", children: /* @__PURE__ */ jsx(SupportDashboardClient, {}) })
24
+ }
25
+ );
26
+ };
27
+ var SupportDashboardView_default = SupportDashboardView;
28
+
29
+ export { SupportDashboardView, SupportDashboardView_default as default };