@consilioweb/payload-support 0.8.2 → 0.9.5
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.
- package/dist/components/RichTextEditor/index.cjs +233 -0
- package/dist/components/RichTextEditor/index.js +232 -0
- package/dist/components/TicketConversation/components/CodeBlock.cjs +24 -7
- package/dist/components/TicketConversation/components/CodeBlock.js +23 -9
- package/dist/index.cjs +19 -1
- package/dist/index.js +19 -1
- package/dist/views/BillingView/client.cjs +260 -103
- package/dist/views/BillingView/client.js +259 -103
- package/dist/views/ChatView/client.cjs +184 -137
- package/dist/views/ChatView/client.js +180 -137
- package/dist/views/CrmView/client.cjs +270 -122
- package/dist/views/CrmView/client.js +266 -122
- package/dist/views/EmailTrackingView/client.cjs +80 -69
- package/dist/views/EmailTrackingView/client.js +80 -70
- package/dist/views/ImportConversationView/client.cjs +127 -94
- package/dist/views/ImportConversationView/client.js +123 -94
- package/dist/views/LogsView/client.cjs +56 -58
- package/dist/views/LogsView/client.js +52 -58
- package/dist/views/NewTicketView/client.cjs +39 -55
- package/dist/views/NewTicketView/client.js +38 -55
- package/dist/views/PendingEmailsView/client.cjs +399 -102
- package/dist/views/PendingEmailsView/client.js +396 -103
- package/dist/views/SupportDashboardView/client.cjs +276 -137
- package/dist/views/SupportDashboardView/client.js +275 -137
- package/dist/views/TicketDetailView/client.cjs +487 -204
- package/dist/views/TicketDetailView/client.js +486 -204
- package/dist/views/TicketInboxView/client.cjs +62 -65
- package/dist/views/TicketInboxView/client.js +62 -66
- package/dist/views/TicketingSettingsView/client.cjs +10 -8
- package/dist/views/TicketingSettingsView/client.js +10 -8
- package/dist/views/TimeDashboardView/client.cjs +70 -59
- package/dist/views/TimeDashboardView/client.js +69 -59
- package/package.json +7 -3
- package/src/components/RichTextEditor/index.tsx +261 -0
- package/src/components/TicketConversation/components/CodeBlock.tsx +53 -14
- package/src/plugin.ts +2 -0
- package/src/utils/emailTemplate.ts +37 -0
- package/src/views/BillingView/client.tsx +362 -69
- package/src/views/ChatView/client.tsx +225 -140
- package/src/views/CrmView/client.tsx +447 -189
- package/src/views/EmailTrackingView/client.tsx +111 -71
- package/src/views/ImportConversationView/client.tsx +255 -70
- package/src/views/LogsView/client.tsx +85 -50
- package/src/views/NewTicketView/client.tsx +37 -53
- package/src/views/PendingEmailsView/client.tsx +512 -92
- package/src/views/SupportDashboardView/client.tsx +294 -134
- package/src/views/TicketDetailView/client.tsx +486 -213
- package/src/views/TicketInboxView/client.tsx +52 -61
- package/src/views/TicketingSettingsView/client.tsx +10 -9
- package/src/views/TimeDashboardView/client.tsx +184 -69
|
@@ -5,10 +5,12 @@ var react = require('react');
|
|
|
5
5
|
var navigation = require('next/navigation');
|
|
6
6
|
var Link = require('next/link');
|
|
7
7
|
var useTranslation = require('../../components/TicketConversation/hooks/useTranslation');
|
|
8
|
+
var s = require('../../styles/TicketInbox.module.scss');
|
|
8
9
|
|
|
9
10
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
10
11
|
|
|
11
12
|
var Link__default = /*#__PURE__*/_interopDefault(Link);
|
|
13
|
+
var s__default = /*#__PURE__*/_interopDefault(s);
|
|
12
14
|
|
|
13
15
|
const STATUS_DOTS = {
|
|
14
16
|
open: "#22c55e",
|
|
@@ -54,6 +56,14 @@ const TicketInboxClient = () => {
|
|
|
54
56
|
if (urlTab && ["all", "open", "waiting_client", "resolved"].includes(urlTab)) return urlTab;
|
|
55
57
|
return "all";
|
|
56
58
|
});
|
|
59
|
+
react.useEffect(() => {
|
|
60
|
+
const urlTab = searchParams.get("tab");
|
|
61
|
+
if (urlTab && ["all", "open", "waiting_client", "resolved"].includes(urlTab)) {
|
|
62
|
+
setTab(urlTab);
|
|
63
|
+
} else if (!urlTab) {
|
|
64
|
+
setTab("all");
|
|
65
|
+
}
|
|
66
|
+
}, [searchParams]);
|
|
57
67
|
const [search, setSearch] = react.useState("");
|
|
58
68
|
const [sort, setSort] = react.useState("-updatedAt");
|
|
59
69
|
const [counts, setCounts] = react.useState({ all: 0, open: 0, waiting: 0, resolved: 0 });
|
|
@@ -157,70 +167,54 @@ const TicketInboxClient = () => {
|
|
|
157
167
|
{ key: "waiting_client", label: t("inbox.tabs.waiting"), count: counts.waiting },
|
|
158
168
|
{ key: "resolved", label: t("inbox.tabs.resolved"), count: counts.resolved }
|
|
159
169
|
];
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: S.page, children: [
|
|
183
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: S.header, children: [
|
|
184
|
-
/* @__PURE__ */ jsxRuntime.jsx("h1", { style: S.title, children: t("inbox.title") }),
|
|
185
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: S.headerRight, children: [
|
|
186
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { style: S.searchWrap, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
187
|
-
"input",
|
|
188
|
-
{
|
|
189
|
-
type: "text",
|
|
190
|
-
style: S.searchInput,
|
|
191
|
-
placeholder: t("inbox.searchPlaceholder"),
|
|
192
|
-
value: search,
|
|
193
|
-
onChange: (e) => setSearch(e.target.value)
|
|
194
|
-
}
|
|
195
|
-
) }),
|
|
196
|
-
/* @__PURE__ */ jsxRuntime.jsx(Link__default.default, { href: "/admin/support/new-ticket", style: S.newTicketBtn, children: t("inbox.newTicketBtn") })
|
|
170
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: s__default.default.page, children: [
|
|
171
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: s__default.default.header, children: [
|
|
172
|
+
/* @__PURE__ */ jsxRuntime.jsx("h1", { className: s__default.default.title, children: t("inbox.title") }),
|
|
173
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: s__default.default.headerRight, children: [
|
|
174
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: s__default.default.searchWrap, children: [
|
|
175
|
+
/* @__PURE__ */ jsxRuntime.jsxs("svg", { className: s__default.default.searchIcon, width: "14", height: "14", viewBox: "0 0 16 16", fill: "none", children: [
|
|
176
|
+
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "7", cy: "7", r: "5", stroke: "currentColor", strokeWidth: "1.5" }),
|
|
177
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M11 11l3.5 3.5", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" })
|
|
178
|
+
] }),
|
|
179
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
180
|
+
"input",
|
|
181
|
+
{
|
|
182
|
+
type: "text",
|
|
183
|
+
className: s__default.default.searchInput,
|
|
184
|
+
placeholder: t("inbox.searchPlaceholder"),
|
|
185
|
+
value: search,
|
|
186
|
+
onChange: (e) => setSearch(e.target.value)
|
|
187
|
+
}
|
|
188
|
+
),
|
|
189
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: s__default.default.searchHint, children: "\u2318K" })
|
|
190
|
+
] }),
|
|
191
|
+
/* @__PURE__ */ jsxRuntime.jsx(Link__default.default, { href: "/admin/support/new-ticket", className: s__default.default.newTicketBtn, children: t("inbox.newTicketBtn") })
|
|
197
192
|
] })
|
|
198
193
|
] }),
|
|
199
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", {
|
|
194
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: s__default.default.tabs, children: tabs.map((tk) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
200
195
|
"button",
|
|
201
196
|
{
|
|
202
|
-
|
|
197
|
+
className: `${s__default.default.tab} ${tab === tk.key ? s__default.default.tabActive : ""}`,
|
|
203
198
|
onClick: () => {
|
|
204
|
-
setTab(
|
|
199
|
+
setTab(tk.key);
|
|
205
200
|
setSelectedIdx(-1);
|
|
206
201
|
},
|
|
207
202
|
children: [
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { style: { opacity: 0.6 }, children: [
|
|
203
|
+
tk.label,
|
|
204
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: s__default.default.tabCount, children: [
|
|
211
205
|
"(",
|
|
212
|
-
|
|
206
|
+
tk.count,
|
|
213
207
|
")"
|
|
214
208
|
] })
|
|
215
209
|
]
|
|
216
210
|
},
|
|
217
|
-
|
|
211
|
+
tk.key
|
|
218
212
|
)) }),
|
|
219
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", {
|
|
213
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: s__default.default.sortRow, children: checkedIds.size > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", gap: 8, alignItems: "center", flex: 1 }, children: [
|
|
220
214
|
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: 13, fontWeight: 600, color: "var(--theme-text)" }, children: checkedIds.size > 1 ? t("inbox.selectedPlural", { count: String(checkedIds.size) }) : t("inbox.selected", { count: String(checkedIds.size) }) }),
|
|
221
|
-
/* @__PURE__ */ jsxRuntime.jsx("button", {
|
|
222
|
-
/* @__PURE__ */ jsxRuntime.jsx("button", {
|
|
223
|
-
/* @__PURE__ */ jsxRuntime.jsxs("select", {
|
|
215
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { className: s__default.default.sortSelect, onClick: () => handleBulkAction("close"), disabled: bulkProcessing, children: t("inbox.closeAction") }),
|
|
216
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { className: s__default.default.sortSelect, onClick: () => handleBulkAction("reopen"), disabled: bulkProcessing, children: t("inbox.reopenAction") }),
|
|
217
|
+
/* @__PURE__ */ jsxRuntime.jsxs("select", { className: s__default.default.sortSelect, value: bulkAction, onChange: (e) => {
|
|
224
218
|
if (e.target.value) handleBulkAction(e.target.value);
|
|
225
219
|
setBulkAction("");
|
|
226
220
|
}, children: [
|
|
@@ -228,25 +222,28 @@ const TicketInboxClient = () => {
|
|
|
228
222
|
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "set_priority", children: t("inbox.changePriority") }),
|
|
229
223
|
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "delete", children: t("inbox.deleteAction") })
|
|
230
224
|
] }),
|
|
231
|
-
/* @__PURE__ */ jsxRuntime.jsx("button", {
|
|
232
|
-
] }) : /* @__PURE__ */ jsxRuntime.jsxs("select", {
|
|
225
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { className: s__default.default.sortSelect, onClick: () => setCheckedIds(/* @__PURE__ */ new Set()), style: { marginLeft: "auto" }, children: t("inbox.deselect") })
|
|
226
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs("select", { className: s__default.default.sortSelect, value: sort, onChange: (e) => setSort(e.target.value), children: [
|
|
233
227
|
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "-updatedAt", children: t("inbox.sort.newest") }),
|
|
234
228
|
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "updatedAt", children: t("inbox.sort.oldest") }),
|
|
235
229
|
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "-createdAt", children: t("inbox.sort.created") }),
|
|
236
230
|
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "priority", children: t("inbox.sort.priority") })
|
|
237
231
|
] }) }),
|
|
238
|
-
loading ? /* @__PURE__ */ jsxRuntime.jsx("div", {
|
|
232
|
+
loading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: s__default.default.loading, children: t("common.loading") }) : tickets.length === 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: s__default.default.empty, children: [
|
|
233
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: s__default.default.emptyIcon, children: "--" }),
|
|
234
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: s__default.default.emptyText, children: t("inbox.empty") })
|
|
235
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: s__default.default.list, children: tickets.map((tk, idx) => {
|
|
239
236
|
const clientObj = typeof tk.client === "object" ? tk.client : null;
|
|
240
237
|
const clientName = clientObj ? `${clientObj.firstName || ""} ${clientObj.lastName || ""}`.trim() : "";
|
|
241
238
|
const clientCompany = clientObj?.company || "";
|
|
242
|
-
const displayClient = clientName ? `${clientName}${clientCompany ? `, ${clientCompany}` : ""}` : "
|
|
239
|
+
const displayClient = clientName ? `${clientName}${clientCompany ? `, ${clientCompany}` : ""}` : "\u2014";
|
|
243
240
|
const isUnread = tk.lastClientMessageAt && (!tk.lastAdminReadAt || new Date(tk.lastClientMessageAt) > new Date(tk.lastAdminReadAt));
|
|
244
241
|
const priorityColor = PRIORITY_COLORS[tk.priority] || "transparent";
|
|
245
242
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
246
243
|
"a",
|
|
247
244
|
{
|
|
248
245
|
href: `/admin/support/ticket?id=${tk.id}`,
|
|
249
|
-
|
|
246
|
+
className: `${s__default.default.row} ${idx === selectedIdx ? s__default.default.rowSelected : ""}`,
|
|
250
247
|
onClick: (e) => {
|
|
251
248
|
e.preventDefault();
|
|
252
249
|
window.location.href = `/admin/support/ticket?id=${tk.id}`;
|
|
@@ -262,25 +259,25 @@ const TicketInboxClient = () => {
|
|
|
262
259
|
style: { width: 14, height: 14, cursor: "pointer", accentColor: "#2563eb" }
|
|
263
260
|
}
|
|
264
261
|
),
|
|
265
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", {
|
|
266
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", {
|
|
267
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", {
|
|
268
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", {
|
|
269
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", {
|
|
270
|
-
tk.category ? /* @__PURE__ */ jsxRuntime.jsxs("span", {
|
|
262
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: s__default.default.statusDot, style: { backgroundColor: STATUS_DOTS[tk.status] || "#94a3b8" } }),
|
|
263
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: s__default.default.statusText, children: t(STATUS_LABEL_KEYS[tk.status] || "ticket.status.open") }),
|
|
264
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: s__default.default.ticketNum, children: tk.ticketNumber }),
|
|
265
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: s__default.default.subject, children: tk.subject }),
|
|
266
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: s__default.default.client, children: displayClient }),
|
|
267
|
+
tk.category ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: s__default.default.categoryChip, children: [
|
|
271
268
|
"[",
|
|
272
|
-
|
|
269
|
+
t(CATEGORY_LABEL_KEYS[tk.category] || "ticket.category.bug"),
|
|
273
270
|
"]"
|
|
274
271
|
] }) : /* @__PURE__ */ jsxRuntime.jsx("span", {}),
|
|
275
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", {
|
|
276
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", {
|
|
277
|
-
isUnread ? /* @__PURE__ */ jsxRuntime.jsx("div", {
|
|
272
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: s__default.default.priorityBar, style: { backgroundColor: priorityColor } }),
|
|
273
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: s__default.default.timeAgo, children: relativeTime(tk.updatedAt) }),
|
|
274
|
+
isUnread ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: s__default.default.unreadDot }) : /* @__PURE__ */ jsxRuntime.jsx("span", {})
|
|
278
275
|
]
|
|
279
276
|
},
|
|
280
277
|
tk.id
|
|
281
278
|
);
|
|
282
279
|
}) }),
|
|
283
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", {
|
|
280
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: s__default.default.keyboardHints, children: [
|
|
284
281
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
285
282
|
/* @__PURE__ */ jsxRuntime.jsx("kbd", { children: "\u2191" }),
|
|
286
283
|
/* @__PURE__ */ jsxRuntime.jsx("kbd", { children: "\u2193" }),
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
3
|
-
import { useState,
|
|
3
|
+
import { useState, useEffect, useCallback } from 'react';
|
|
4
4
|
import { useSearchParams } from 'next/navigation';
|
|
5
5
|
import Link from 'next/link';
|
|
6
6
|
import { useTranslation } from '../../components/TicketConversation/hooks/useTranslation.js';
|
|
7
|
+
import s from '../../styles/TicketInbox.module.scss';
|
|
7
8
|
|
|
8
9
|
const STATUS_DOTS = {
|
|
9
10
|
open: "#22c55e",
|
|
@@ -49,6 +50,14 @@ const TicketInboxClient = () => {
|
|
|
49
50
|
if (urlTab && ["all", "open", "waiting_client", "resolved"].includes(urlTab)) return urlTab;
|
|
50
51
|
return "all";
|
|
51
52
|
});
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
const urlTab = searchParams.get("tab");
|
|
55
|
+
if (urlTab && ["all", "open", "waiting_client", "resolved"].includes(urlTab)) {
|
|
56
|
+
setTab(urlTab);
|
|
57
|
+
} else if (!urlTab) {
|
|
58
|
+
setTab("all");
|
|
59
|
+
}
|
|
60
|
+
}, [searchParams]);
|
|
52
61
|
const [search, setSearch] = useState("");
|
|
53
62
|
const [sort, setSort] = useState("-updatedAt");
|
|
54
63
|
const [counts, setCounts] = useState({ all: 0, open: 0, waiting: 0, resolved: 0 });
|
|
@@ -152,70 +161,54 @@ const TicketInboxClient = () => {
|
|
|
152
161
|
{ key: "waiting_client", label: t("inbox.tabs.waiting"), count: counts.waiting },
|
|
153
162
|
{ key: "resolved", label: t("inbox.tabs.resolved"), count: counts.resolved }
|
|
154
163
|
];
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
return /* @__PURE__ */ jsxs("div", { style: S.page, children: [
|
|
178
|
-
/* @__PURE__ */ jsxs("div", { style: S.header, children: [
|
|
179
|
-
/* @__PURE__ */ jsx("h1", { style: S.title, children: t("inbox.title") }),
|
|
180
|
-
/* @__PURE__ */ jsxs("div", { style: S.headerRight, children: [
|
|
181
|
-
/* @__PURE__ */ jsx("div", { style: S.searchWrap, children: /* @__PURE__ */ jsx(
|
|
182
|
-
"input",
|
|
183
|
-
{
|
|
184
|
-
type: "text",
|
|
185
|
-
style: S.searchInput,
|
|
186
|
-
placeholder: t("inbox.searchPlaceholder"),
|
|
187
|
-
value: search,
|
|
188
|
-
onChange: (e) => setSearch(e.target.value)
|
|
189
|
-
}
|
|
190
|
-
) }),
|
|
191
|
-
/* @__PURE__ */ jsx(Link, { href: "/admin/support/new-ticket", style: S.newTicketBtn, children: t("inbox.newTicketBtn") })
|
|
164
|
+
return /* @__PURE__ */ jsxs("div", { className: s.page, children: [
|
|
165
|
+
/* @__PURE__ */ jsxs("div", { className: s.header, children: [
|
|
166
|
+
/* @__PURE__ */ jsx("h1", { className: s.title, children: t("inbox.title") }),
|
|
167
|
+
/* @__PURE__ */ jsxs("div", { className: s.headerRight, children: [
|
|
168
|
+
/* @__PURE__ */ jsxs("div", { className: s.searchWrap, children: [
|
|
169
|
+
/* @__PURE__ */ jsxs("svg", { className: s.searchIcon, width: "14", height: "14", viewBox: "0 0 16 16", fill: "none", children: [
|
|
170
|
+
/* @__PURE__ */ jsx("circle", { cx: "7", cy: "7", r: "5", stroke: "currentColor", strokeWidth: "1.5" }),
|
|
171
|
+
/* @__PURE__ */ jsx("path", { d: "M11 11l3.5 3.5", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" })
|
|
172
|
+
] }),
|
|
173
|
+
/* @__PURE__ */ jsx(
|
|
174
|
+
"input",
|
|
175
|
+
{
|
|
176
|
+
type: "text",
|
|
177
|
+
className: s.searchInput,
|
|
178
|
+
placeholder: t("inbox.searchPlaceholder"),
|
|
179
|
+
value: search,
|
|
180
|
+
onChange: (e) => setSearch(e.target.value)
|
|
181
|
+
}
|
|
182
|
+
),
|
|
183
|
+
/* @__PURE__ */ jsx("span", { className: s.searchHint, children: "\u2318K" })
|
|
184
|
+
] }),
|
|
185
|
+
/* @__PURE__ */ jsx(Link, { href: "/admin/support/new-ticket", className: s.newTicketBtn, children: t("inbox.newTicketBtn") })
|
|
192
186
|
] })
|
|
193
187
|
] }),
|
|
194
|
-
/* @__PURE__ */ jsx("div", {
|
|
188
|
+
/* @__PURE__ */ jsx("div", { className: s.tabs, children: tabs.map((tk) => /* @__PURE__ */ jsxs(
|
|
195
189
|
"button",
|
|
196
190
|
{
|
|
197
|
-
|
|
191
|
+
className: `${s.tab} ${tab === tk.key ? s.tabActive : ""}`,
|
|
198
192
|
onClick: () => {
|
|
199
|
-
setTab(
|
|
193
|
+
setTab(tk.key);
|
|
200
194
|
setSelectedIdx(-1);
|
|
201
195
|
},
|
|
202
196
|
children: [
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
/* @__PURE__ */ jsxs("span", { style: { opacity: 0.6 }, children: [
|
|
197
|
+
tk.label,
|
|
198
|
+
/* @__PURE__ */ jsxs("span", { className: s.tabCount, children: [
|
|
206
199
|
"(",
|
|
207
|
-
|
|
200
|
+
tk.count,
|
|
208
201
|
")"
|
|
209
202
|
] })
|
|
210
203
|
]
|
|
211
204
|
},
|
|
212
|
-
|
|
205
|
+
tk.key
|
|
213
206
|
)) }),
|
|
214
|
-
/* @__PURE__ */ jsx("div", {
|
|
207
|
+
/* @__PURE__ */ jsx("div", { className: s.sortRow, children: checkedIds.size > 0 ? /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: 8, alignItems: "center", flex: 1 }, children: [
|
|
215
208
|
/* @__PURE__ */ jsx("span", { style: { fontSize: 13, fontWeight: 600, color: "var(--theme-text)" }, children: checkedIds.size > 1 ? t("inbox.selectedPlural", { count: String(checkedIds.size) }) : t("inbox.selected", { count: String(checkedIds.size) }) }),
|
|
216
|
-
/* @__PURE__ */ jsx("button", {
|
|
217
|
-
/* @__PURE__ */ jsx("button", {
|
|
218
|
-
/* @__PURE__ */ jsxs("select", {
|
|
209
|
+
/* @__PURE__ */ jsx("button", { className: s.sortSelect, onClick: () => handleBulkAction("close"), disabled: bulkProcessing, children: t("inbox.closeAction") }),
|
|
210
|
+
/* @__PURE__ */ jsx("button", { className: s.sortSelect, onClick: () => handleBulkAction("reopen"), disabled: bulkProcessing, children: t("inbox.reopenAction") }),
|
|
211
|
+
/* @__PURE__ */ jsxs("select", { className: s.sortSelect, value: bulkAction, onChange: (e) => {
|
|
219
212
|
if (e.target.value) handleBulkAction(e.target.value);
|
|
220
213
|
setBulkAction("");
|
|
221
214
|
}, children: [
|
|
@@ -223,25 +216,28 @@ const TicketInboxClient = () => {
|
|
|
223
216
|
/* @__PURE__ */ jsx("option", { value: "set_priority", children: t("inbox.changePriority") }),
|
|
224
217
|
/* @__PURE__ */ jsx("option", { value: "delete", children: t("inbox.deleteAction") })
|
|
225
218
|
] }),
|
|
226
|
-
/* @__PURE__ */ jsx("button", {
|
|
227
|
-
] }) : /* @__PURE__ */ jsxs("select", {
|
|
219
|
+
/* @__PURE__ */ jsx("button", { className: s.sortSelect, onClick: () => setCheckedIds(/* @__PURE__ */ new Set()), style: { marginLeft: "auto" }, children: t("inbox.deselect") })
|
|
220
|
+
] }) : /* @__PURE__ */ jsxs("select", { className: s.sortSelect, value: sort, onChange: (e) => setSort(e.target.value), children: [
|
|
228
221
|
/* @__PURE__ */ jsx("option", { value: "-updatedAt", children: t("inbox.sort.newest") }),
|
|
229
222
|
/* @__PURE__ */ jsx("option", { value: "updatedAt", children: t("inbox.sort.oldest") }),
|
|
230
223
|
/* @__PURE__ */ jsx("option", { value: "-createdAt", children: t("inbox.sort.created") }),
|
|
231
224
|
/* @__PURE__ */ jsx("option", { value: "priority", children: t("inbox.sort.priority") })
|
|
232
225
|
] }) }),
|
|
233
|
-
loading ? /* @__PURE__ */ jsx("div", {
|
|
226
|
+
loading ? /* @__PURE__ */ jsx("div", { className: s.loading, children: t("common.loading") }) : tickets.length === 0 ? /* @__PURE__ */ jsxs("div", { className: s.empty, children: [
|
|
227
|
+
/* @__PURE__ */ jsx("div", { className: s.emptyIcon, children: "--" }),
|
|
228
|
+
/* @__PURE__ */ jsx("div", { className: s.emptyText, children: t("inbox.empty") })
|
|
229
|
+
] }) : /* @__PURE__ */ jsx("div", { className: s.list, children: tickets.map((tk, idx) => {
|
|
234
230
|
const clientObj = typeof tk.client === "object" ? tk.client : null;
|
|
235
231
|
const clientName = clientObj ? `${clientObj.firstName || ""} ${clientObj.lastName || ""}`.trim() : "";
|
|
236
232
|
const clientCompany = clientObj?.company || "";
|
|
237
|
-
const displayClient = clientName ? `${clientName}${clientCompany ? `, ${clientCompany}` : ""}` : "
|
|
233
|
+
const displayClient = clientName ? `${clientName}${clientCompany ? `, ${clientCompany}` : ""}` : "\u2014";
|
|
238
234
|
const isUnread = tk.lastClientMessageAt && (!tk.lastAdminReadAt || new Date(tk.lastClientMessageAt) > new Date(tk.lastAdminReadAt));
|
|
239
235
|
const priorityColor = PRIORITY_COLORS[tk.priority] || "transparent";
|
|
240
236
|
return /* @__PURE__ */ jsxs(
|
|
241
237
|
"a",
|
|
242
238
|
{
|
|
243
239
|
href: `/admin/support/ticket?id=${tk.id}`,
|
|
244
|
-
|
|
240
|
+
className: `${s.row} ${idx === selectedIdx ? s.rowSelected : ""}`,
|
|
245
241
|
onClick: (e) => {
|
|
246
242
|
e.preventDefault();
|
|
247
243
|
window.location.href = `/admin/support/ticket?id=${tk.id}`;
|
|
@@ -257,25 +253,25 @@ const TicketInboxClient = () => {
|
|
|
257
253
|
style: { width: 14, height: 14, cursor: "pointer", accentColor: "#2563eb" }
|
|
258
254
|
}
|
|
259
255
|
),
|
|
260
|
-
/* @__PURE__ */ jsx("div", {
|
|
261
|
-
/* @__PURE__ */ jsx("span", {
|
|
262
|
-
/* @__PURE__ */ jsx("span", {
|
|
263
|
-
/* @__PURE__ */ jsx("span", {
|
|
264
|
-
/* @__PURE__ */ jsx("span", {
|
|
265
|
-
tk.category ? /* @__PURE__ */ jsxs("span", {
|
|
256
|
+
/* @__PURE__ */ jsx("div", { className: s.statusDot, style: { backgroundColor: STATUS_DOTS[tk.status] || "#94a3b8" } }),
|
|
257
|
+
/* @__PURE__ */ jsx("span", { className: s.statusText, children: t(STATUS_LABEL_KEYS[tk.status] || "ticket.status.open") }),
|
|
258
|
+
/* @__PURE__ */ jsx("span", { className: s.ticketNum, children: tk.ticketNumber }),
|
|
259
|
+
/* @__PURE__ */ jsx("span", { className: s.subject, children: tk.subject }),
|
|
260
|
+
/* @__PURE__ */ jsx("span", { className: s.client, children: displayClient }),
|
|
261
|
+
tk.category ? /* @__PURE__ */ jsxs("span", { className: s.categoryChip, children: [
|
|
266
262
|
"[",
|
|
267
|
-
|
|
263
|
+
t(CATEGORY_LABEL_KEYS[tk.category] || "ticket.category.bug"),
|
|
268
264
|
"]"
|
|
269
265
|
] }) : /* @__PURE__ */ jsx("span", {}),
|
|
270
|
-
/* @__PURE__ */ jsx("div", {
|
|
271
|
-
/* @__PURE__ */ jsx("span", {
|
|
272
|
-
isUnread ? /* @__PURE__ */ jsx("div", {
|
|
266
|
+
/* @__PURE__ */ jsx("div", { className: s.priorityBar, style: { backgroundColor: priorityColor } }),
|
|
267
|
+
/* @__PURE__ */ jsx("span", { className: s.timeAgo, children: relativeTime(tk.updatedAt) }),
|
|
268
|
+
isUnread ? /* @__PURE__ */ jsx("div", { className: s.unreadDot }) : /* @__PURE__ */ jsx("span", {})
|
|
273
269
|
]
|
|
274
270
|
},
|
|
275
271
|
tk.id
|
|
276
272
|
);
|
|
277
273
|
}) }),
|
|
278
|
-
/* @__PURE__ */ jsxs("div", {
|
|
274
|
+
/* @__PURE__ */ jsxs("div", { className: s.keyboardHints, children: [
|
|
279
275
|
/* @__PURE__ */ jsxs("span", { children: [
|
|
280
276
|
/* @__PURE__ */ jsx("kbd", { children: "\u2191" }),
|
|
281
277
|
/* @__PURE__ */ jsx("kbd", { children: "\u2193" }),
|
|
@@ -6,7 +6,8 @@ var lucideReact = require('lucide-react');
|
|
|
6
6
|
var adminTokens = require('../shared/adminTokens');
|
|
7
7
|
var AdminViewHeader = require('../shared/AdminViewHeader');
|
|
8
8
|
var config = require('../../components/TicketConversation/config');
|
|
9
|
-
var
|
|
9
|
+
var useTranslation = require('../../components/TicketConversation/hooks/useTranslation');
|
|
10
|
+
var ts = require('../../styles/TicketingSettings.module.scss');
|
|
10
11
|
|
|
11
12
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
12
13
|
|
|
@@ -203,6 +204,7 @@ const FieldRow = ({ label, description, children }) => /* @__PURE__ */ jsxRuntim
|
|
|
203
204
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: ts__default.default.fieldContent, children })
|
|
204
205
|
] });
|
|
205
206
|
const TicketingSettingsClient = () => {
|
|
207
|
+
const { t } = useTranslation.useTranslation();
|
|
206
208
|
const [features, setFeatures] = react.useState(() => config.getFeatures());
|
|
207
209
|
const [settings, setSettings] = react.useState(DEFAULT_SETTINGS);
|
|
208
210
|
const [signature, setSignature] = react.useState("");
|
|
@@ -276,27 +278,27 @@ const TicketingSettingsClient = () => {
|
|
|
276
278
|
AdminViewHeader.AdminViewHeader,
|
|
277
279
|
{
|
|
278
280
|
icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Settings, { size: 24 }),
|
|
279
|
-
title: "
|
|
280
|
-
subtitle:
|
|
281
|
+
title: t("settingsView.configTitle"),
|
|
282
|
+
subtitle: t("settings.subtitle", { enabled: String(enabledCount), total: String(totalCount) }),
|
|
281
283
|
actions: /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", gap: 8 }, children: [
|
|
282
|
-
/* @__PURE__ */ jsxRuntime.jsx("button", { onClick: handleReset, style: adminTokens.btnStyle("var(--theme-elevation-400)", { small: true }), children: "
|
|
284
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { onClick: handleReset, style: adminTokens.btnStyle("var(--theme-elevation-400)", { small: true }), children: t("settingsView.reset") }),
|
|
283
285
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
284
286
|
"button",
|
|
285
287
|
{
|
|
286
288
|
onClick: handleSave,
|
|
287
289
|
disabled: saving,
|
|
288
290
|
style: adminTokens.btnStyle(saved ? adminTokens.V.green : adminTokens.V.blue, { small: true }),
|
|
289
|
-
children: saving ? "..." : saved ? "
|
|
291
|
+
children: saving ? "..." : saved ? t("settingsView.saved") : t("common.save")
|
|
290
292
|
}
|
|
291
293
|
)
|
|
292
294
|
] })
|
|
293
295
|
}
|
|
294
296
|
),
|
|
295
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: ts__default.default.intro, children: "
|
|
297
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: ts__default.default.intro, children: t("settingsView.intro") }),
|
|
296
298
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
297
299
|
CollapsibleSection,
|
|
298
300
|
{
|
|
299
|
-
title: "
|
|
301
|
+
title: t("settingsView.features"),
|
|
300
302
|
icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Settings, { size: 16 }),
|
|
301
303
|
color: adminTokens.V.blue,
|
|
302
304
|
badge: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: ts__default.default.badge, style: { backgroundColor: "#dbeafe", color: "#1e40af" }, children: [
|
|
@@ -305,7 +307,7 @@ const TicketingSettingsClient = () => {
|
|
|
305
307
|
totalCount
|
|
306
308
|
] }),
|
|
307
309
|
children: [
|
|
308
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: ts__default.default.sectionDescription, children: "
|
|
310
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: ts__default.default.sectionDescription, children: t("settingsView.featuresDescription") }),
|
|
309
311
|
CATEGORIES.map((cat) => {
|
|
310
312
|
const categoryFeatures = FEATURE_LIST.filter((f) => f.category === cat.key);
|
|
311
313
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ts__default.default.categoryGroup, children: [
|
|
@@ -5,7 +5,8 @@ import { Settings, Mail, Bot, Clock, Timer, Globe, FileSignature } from 'lucide-
|
|
|
5
5
|
import { V, btnStyle } from '../shared/adminTokens.js';
|
|
6
6
|
import { AdminViewHeader } from '../shared/AdminViewHeader.js';
|
|
7
7
|
import { getFeatures, saveFeatures, DEFAULT_FEATURES } from '../../components/TicketConversation/config.js';
|
|
8
|
-
import
|
|
8
|
+
import { useTranslation } from '../../components/TicketConversation/hooks/useTranslation.js';
|
|
9
|
+
import ts from '../../styles/TicketingSettings.module.scss';
|
|
9
10
|
|
|
10
11
|
const DEFAULT_SETTINGS = {
|
|
11
12
|
email: {
|
|
@@ -198,6 +199,7 @@ const FieldRow = ({ label, description, children }) => /* @__PURE__ */ jsxs("div
|
|
|
198
199
|
/* @__PURE__ */ jsx("div", { className: ts.fieldContent, children })
|
|
199
200
|
] });
|
|
200
201
|
const TicketingSettingsClient = () => {
|
|
202
|
+
const { t } = useTranslation();
|
|
201
203
|
const [features, setFeatures] = useState(() => getFeatures());
|
|
202
204
|
const [settings, setSettings] = useState(DEFAULT_SETTINGS);
|
|
203
205
|
const [signature, setSignature] = useState("");
|
|
@@ -271,27 +273,27 @@ const TicketingSettingsClient = () => {
|
|
|
271
273
|
AdminViewHeader,
|
|
272
274
|
{
|
|
273
275
|
icon: /* @__PURE__ */ jsx(Settings, { size: 24 }),
|
|
274
|
-
title: "
|
|
275
|
-
subtitle:
|
|
276
|
+
title: t("settingsView.configTitle"),
|
|
277
|
+
subtitle: t("settings.subtitle", { enabled: String(enabledCount), total: String(totalCount) }),
|
|
276
278
|
actions: /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: 8 }, children: [
|
|
277
|
-
/* @__PURE__ */ jsx("button", { onClick: handleReset, style: btnStyle("var(--theme-elevation-400)", { small: true }), children: "
|
|
279
|
+
/* @__PURE__ */ jsx("button", { onClick: handleReset, style: btnStyle("var(--theme-elevation-400)", { small: true }), children: t("settingsView.reset") }),
|
|
278
280
|
/* @__PURE__ */ jsx(
|
|
279
281
|
"button",
|
|
280
282
|
{
|
|
281
283
|
onClick: handleSave,
|
|
282
284
|
disabled: saving,
|
|
283
285
|
style: btnStyle(saved ? V.green : V.blue, { small: true }),
|
|
284
|
-
children: saving ? "..." : saved ? "
|
|
286
|
+
children: saving ? "..." : saved ? t("settingsView.saved") : t("common.save")
|
|
285
287
|
}
|
|
286
288
|
)
|
|
287
289
|
] })
|
|
288
290
|
}
|
|
289
291
|
),
|
|
290
|
-
/* @__PURE__ */ jsx("p", { className: ts.intro, children: "
|
|
292
|
+
/* @__PURE__ */ jsx("p", { className: ts.intro, children: t("settingsView.intro") }),
|
|
291
293
|
/* @__PURE__ */ jsxs(
|
|
292
294
|
CollapsibleSection,
|
|
293
295
|
{
|
|
294
|
-
title: "
|
|
296
|
+
title: t("settingsView.features"),
|
|
295
297
|
icon: /* @__PURE__ */ jsx(Settings, { size: 16 }),
|
|
296
298
|
color: V.blue,
|
|
297
299
|
badge: /* @__PURE__ */ jsxs("span", { className: ts.badge, style: { backgroundColor: "#dbeafe", color: "#1e40af" }, children: [
|
|
@@ -300,7 +302,7 @@ const TicketingSettingsClient = () => {
|
|
|
300
302
|
totalCount
|
|
301
303
|
] }),
|
|
302
304
|
children: [
|
|
303
|
-
/* @__PURE__ */ jsx("p", { className: ts.sectionDescription, children: "
|
|
305
|
+
/* @__PURE__ */ jsx("p", { className: ts.sectionDescription, children: t("settingsView.featuresDescription") }),
|
|
304
306
|
CATEGORIES.map((cat) => {
|
|
305
307
|
const categoryFeatures = FEATURE_LIST.filter((f) => f.category === cat.key);
|
|
306
308
|
return /* @__PURE__ */ jsxs("div", { className: ts.categoryGroup, children: [
|