@consilioweb/payload-support 0.16.0 → 1.0.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.
- package/README.md +347 -435
- package/dist/components/TicketConversation/RewriteDropdown.cjs +98 -0
- package/dist/components/TicketConversation/RewriteDropdown.js +93 -0
- package/dist/components/TicketConversation/SkeletonText.cjs +21 -0
- package/dist/components/TicketConversation/SkeletonText.js +20 -0
- package/dist/components/TicketConversation/constants.cjs +27 -0
- package/dist/components/TicketConversation/constants.js +26 -1
- package/dist/components/TicketConversation/hooks/useDocumentIdFromUrl.cjs +20 -0
- package/dist/components/TicketConversation/hooks/useDocumentIdFromUrl.js +19 -0
- package/dist/components/TicketConversation/index.cjs +10 -147
- package/dist/components/TicketConversation/index.js +4 -141
- package/dist/index.cjs +1604 -671
- package/dist/index.d.cts +3 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +1602 -671
- package/dist/views/BillingView/client.cjs +40 -54
- package/dist/views/BillingView/client.js +40 -54
- package/dist/views/ChatView/client.cjs +4 -3
- package/dist/views/ChatView/client.js +4 -3
- package/dist/views/CrmView/client.cjs +7 -7
- package/dist/views/CrmView/client.js +7 -7
- package/dist/views/EmailTrackingView/client.cjs +6 -5
- package/dist/views/EmailTrackingView/client.js +6 -5
- package/dist/views/ImportConversationView/client.cjs +4 -4
- package/dist/views/ImportConversationView/client.js +4 -4
- package/dist/views/LogsView/client.cjs +3 -2
- package/dist/views/LogsView/client.js +3 -2
- package/dist/views/NewTicketView/client.cjs +1 -1
- package/dist/views/NewTicketView/client.js +1 -1
- package/dist/views/PendingEmailsView/client.cjs +7 -6
- package/dist/views/PendingEmailsView/client.js +7 -6
- package/dist/views/SupportDashboardView/client.cjs +19 -22
- package/dist/views/SupportDashboardView/client.js +19 -22
- package/dist/views/TicketDetailView/NextActionItem.cjs +40 -0
- package/dist/views/TicketDetailView/NextActionItem.js +34 -0
- package/dist/views/TicketDetailView/RewriteDropdown.cjs +80 -0
- package/dist/views/TicketDetailView/RewriteDropdown.js +78 -0
- package/dist/views/TicketDetailView/client.cjs +59 -190
- package/dist/views/TicketDetailView/client.js +52 -183
- package/dist/views/TicketDetailView/constants.cjs +20 -0
- package/dist/views/TicketDetailView/constants.js +16 -0
- package/dist/views/TicketDetailView/helpers.cjs +23 -0
- package/dist/views/TicketDetailView/helpers.js +20 -0
- package/dist/views/TicketDetailView/types.cjs +2 -0
- package/dist/views/TicketDetailView/types.js +1 -0
- package/dist/views/TicketInboxView/client.cjs +14 -10
- package/dist/views/TicketInboxView/client.js +14 -10
- package/dist/views/TicketingSettingsView/client.cjs +101 -96
- package/dist/views/TicketingSettingsView/client.js +92 -88
- package/dist/views/TimeDashboardView/client.cjs +2 -2
- package/dist/views/TimeDashboardView/client.js +2 -2
- package/dist/views/shared/StatusPill.cjs +23 -12
- package/dist/views/shared/StatusPill.js +23 -12
- package/dist/views/shared/dateLocale.cjs +5 -0
- package/dist/views/shared/dateLocale.js +3 -0
- package/package.json +23 -15
- package/src/__tests__/generateTrackingToken.test.ts +53 -0
- package/src/__tests__/integration/ai-agent.test.ts +46 -0
- package/src/__tests__/integration/auth.test.ts +43 -0
- package/src/__tests__/integration/automation-rules.test.ts +68 -0
- package/src/__tests__/integration/buildTestPayload.ts +52 -0
- package/src/__tests__/integration/channels.test.ts +52 -0
- package/src/__tests__/integration/core-behaviors.test.ts +58 -0
- package/src/__tests__/integration/dashboard-volume.test.ts +31 -0
- package/src/__tests__/integration/digest.test.ts +48 -0
- package/src/__tests__/integration/invoice-pdf.test.ts +30 -0
- package/src/__tests__/integration/isolation.test.ts +81 -0
- package/src/__tests__/integration/mentions-invoice.test.ts +50 -0
- package/src/__tests__/integration/nps.test.ts +37 -0
- package/src/__tests__/integration/sanitization.test.ts +35 -0
- package/src/__tests__/integration/sla-pause.test.ts +39 -0
- package/src/__tests__/integration/smoke.test.ts +26 -0
- package/src/__tests__/integration/snooze.test.ts +68 -0
- package/src/__tests__/integration/teams.test.ts +38 -0
- package/src/__tests__/rateLimiter.test.ts +89 -0
- package/src/__tests__/sanitizeHtml.test.ts +165 -0
- package/src/__tests__/sla.test.ts +258 -0
- package/src/collections/AutomationRules.ts +66 -0
- package/src/collections/NotificationQueue.ts +30 -0
- package/src/collections/SatisfactionSurveys.ts +11 -2
- package/src/collections/SupportClients.ts +58 -1
- package/src/collections/SupportTeam.ts +27 -0
- package/src/collections/TicketActivityLog.ts +9 -4
- package/src/collections/TicketMessages.ts +129 -31
- package/src/collections/Tickets.ts +31 -73
- package/src/collections/index.ts +3 -0
- package/src/components/TicketConversation/RewriteDropdown.tsx +86 -0
- package/src/components/TicketConversation/SkeletonText.tsx +23 -0
- package/src/components/TicketConversation/constants.ts +29 -0
- package/src/components/TicketConversation/hooks/useDocumentIdFromUrl.ts +21 -0
- package/src/components/TicketConversation/index.tsx +4 -152
- package/src/endpoints/admin-chat-stream.ts +3 -4
- package/src/endpoints/admin-chat.ts +11 -20
- package/src/endpoints/admin-stats.ts +70 -32
- package/src/endpoints/ai-agent.ts +36 -0
- package/src/endpoints/apply-macro.ts +8 -14
- package/src/endpoints/auth-2fa.ts +12 -12
- package/src/endpoints/auto-close.ts +6 -10
- package/src/endpoints/billing.ts +17 -4
- package/src/endpoints/bulk-action.ts +7 -12
- package/src/endpoints/channels.ts +89 -0
- package/src/endpoints/chat-stream.ts +3 -4
- package/src/endpoints/chat.ts +7 -12
- package/src/endpoints/chatbot.ts +2 -2
- package/src/endpoints/client-intelligence.ts +4 -4
- package/src/endpoints/delete-account.ts +9 -16
- package/src/endpoints/email-stats.ts +2 -2
- package/src/endpoints/escalate.ts +2 -2
- package/src/endpoints/export-csv.ts +2 -2
- package/src/endpoints/export-data.ts +5 -8
- package/src/endpoints/import-conversation.ts +6 -10
- package/src/endpoints/index.ts +18 -1
- package/src/endpoints/invite-collaborator.ts +30 -15
- package/src/endpoints/invoice.ts +127 -0
- package/src/endpoints/kb-search.ts +2 -2
- package/src/endpoints/login.ts +12 -4
- package/src/endpoints/merge-clients.ts +14 -19
- package/src/endpoints/merge-tickets.ts +11 -18
- package/src/endpoints/oauth-google.ts +86 -39
- package/src/endpoints/pending-emails-process.ts +15 -25
- package/src/endpoints/process-digests.ts +93 -0
- package/src/endpoints/process-scheduled.ts +6 -10
- package/src/endpoints/process-snooze.ts +78 -0
- package/src/endpoints/purge-logs.ts +2 -2
- package/src/endpoints/resend-notification.ts +3 -4
- package/src/endpoints/round-robin-config.ts +3 -4
- package/src/endpoints/satisfaction.ts +21 -14
- package/src/endpoints/search.ts +5 -8
- package/src/endpoints/seed-kb.ts +3 -4
- package/src/endpoints/send-reminder.ts +6 -9
- package/src/endpoints/settings.ts +5 -2
- package/src/endpoints/signature.ts +3 -4
- package/src/endpoints/sla-check.ts +2 -2
- package/src/endpoints/split-ticket.ts +7 -12
- package/src/endpoints/statuses.ts +2 -2
- package/src/endpoints/ticket-feedback.ts +4 -6
- package/src/endpoints/ticket-synthesis.ts +2 -2
- package/src/endpoints/track-open.ts +16 -28
- package/src/endpoints/transfer-ticket.ts +21 -9
- package/src/endpoints/user-prefs.ts +3 -4
- package/src/hooks/automationRules.ts +84 -0
- package/src/hooks/checkSLA.ts +48 -16
- package/src/plugin.ts +6 -0
- package/src/portal/LiveChat.tsx +2 -63
- package/src/portal/auth/tickets/detail/CloseTicketButton.tsx +10 -0
- package/src/portal/auth/tickets/detail/MarkSolutionButton.tsx +14 -2
- package/src/portal/auth/tickets/detail/MessageActions.tsx +37 -18
- package/src/portal/auth/tickets/detail/ReopenTicketButton.tsx +10 -0
- package/src/portal/auth/tickets/detail/TransferAndInviteActions.tsx +3 -2
- package/src/portal/auth/tickets/detail/page.tsx +2 -2
- package/src/portal/helpers.ts +46 -0
- package/src/portal/login/page.tsx +3 -8
- package/src/portal/types.ts +15 -0
- package/src/types/lucide-react.d.ts +34 -0
- package/src/types/payload-config.d.ts +10 -0
- package/src/utils/adminNotification.ts +2 -2
- package/src/utils/aiAgent.ts +147 -0
- package/src/utils/auth.ts +5 -4
- package/src/utils/channels.ts +36 -0
- package/src/utils/db.ts +73 -0
- package/src/utils/emailTemplate.ts +8 -1
- package/src/utils/fireWebhooks.ts +4 -6
- package/src/utils/generateTicketSynthesis.ts +7 -12
- package/src/utils/invoicePdf.ts +88 -0
- package/src/utils/notificationQueue.ts +36 -0
- package/src/utils/readSettings.ts +22 -6
- package/src/utils/sanitizeHtml.ts +57 -0
- package/src/utils/slugs.ts +6 -0
- package/src/utils/teamAccess.ts +27 -0
- package/src/utils/ticketAccess.ts +53 -0
- package/src/utils/webhookDispatcher.ts +4 -6
- package/src/views/BillingView/client.tsx +49 -37
- package/src/views/ChatView/client.tsx +4 -3
- package/src/views/CrmView/client.tsx +7 -7
- package/src/views/EmailTrackingView/client.tsx +7 -6
- package/src/views/ImportConversationView/client.tsx +4 -4
- package/src/views/LogsView/client.tsx +3 -2
- package/src/views/NewTicketView/client.tsx +1 -1
- package/src/views/PendingEmailsView/client.tsx +7 -6
- package/src/views/SupportDashboardView/client.tsx +21 -21
- package/src/views/TicketDetailView/NextActionItem.tsx +30 -0
- package/src/views/TicketDetailView/RewriteDropdown.tsx +63 -0
- package/src/views/TicketDetailView/client.tsx +54 -179
- package/src/views/TicketDetailView/constants.ts +23 -0
- package/src/views/TicketDetailView/helpers.ts +17 -0
- package/src/views/TicketDetailView/types.ts +10 -0
- package/src/views/TicketInboxView/client.tsx +16 -10
- package/src/views/TicketingSettingsView/client.tsx +90 -87
- package/src/views/TimeDashboardView/client.tsx +2 -2
- package/src/views/shared/StatusPill.tsx +24 -12
- package/src/views/shared/dateLocale.ts +5 -0
- package/src/views/shared/locales/en.json +708 -0
- package/src/views/shared/locales/fr.json +708 -0
|
@@ -5,6 +5,7 @@ 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 dateLocale = require('../shared/dateLocale');
|
|
8
9
|
var StatusPill = require('../shared/StatusPill');
|
|
9
10
|
var sla = require('../shared/sla');
|
|
10
11
|
var s = require('../../styles/TicketInbox.module.scss');
|
|
@@ -27,16 +28,16 @@ const STATUS_VARIANT = {
|
|
|
27
28
|
resolved: "resolved",
|
|
28
29
|
closed: "closed"
|
|
29
30
|
};
|
|
30
|
-
function relativeTime(dateStr) {
|
|
31
|
+
function relativeTime(dateStr, tFn) {
|
|
31
32
|
const diff = Date.now() - new Date(dateStr).getTime();
|
|
32
33
|
const mins = Math.floor(diff / 6e4);
|
|
33
|
-
if (mins < 1) return "
|
|
34
|
+
if (mins < 1) return tFn("inbox.timeAgo.now");
|
|
34
35
|
if (mins < 60) return `${mins}m`;
|
|
35
36
|
const hours = Math.floor(mins / 60);
|
|
36
37
|
if (hours < 24) return `${hours}h`;
|
|
37
38
|
const days = Math.floor(hours / 24);
|
|
38
39
|
if (days < 7) return `${days}j`;
|
|
39
|
-
return new Date(dateStr).toLocaleDateString(
|
|
40
|
+
return new Date(dateStr).toLocaleDateString(dateLocale.DATE_LOCALE, { day: "numeric", month: "short" });
|
|
40
41
|
}
|
|
41
42
|
const TicketInboxClient = () => {
|
|
42
43
|
const { t } = useTranslation.useTranslation();
|
|
@@ -121,6 +122,8 @@ const TicketInboxClient = () => {
|
|
|
121
122
|
params.push(`where[or][0][subject][contains]=${encodeURIComponent(search)}`);
|
|
122
123
|
params.push(`where[or][1][ticketNumber][contains]=${encodeURIComponent(search)}`);
|
|
123
124
|
}
|
|
125
|
+
params.push(`where[and][0][or][0][snoozeUntil][exists]=false`);
|
|
126
|
+
params.push(`where[and][0][or][1][snoozeUntil][less_than_equal]=${encodeURIComponent((/* @__PURE__ */ new Date()).toISOString())}`);
|
|
124
127
|
try {
|
|
125
128
|
const url = `/api/tickets?${params.join("&")}`;
|
|
126
129
|
const res = await fetch(url, { credentials: "include" });
|
|
@@ -142,12 +145,13 @@ const TicketInboxClient = () => {
|
|
|
142
145
|
react.useEffect(() => {
|
|
143
146
|
const fetchCounts = async () => {
|
|
144
147
|
try {
|
|
148
|
+
const sn = `where[and][0][or][0][snoozeUntil][exists]=false&where[and][0][or][1][snoozeUntil][less_than_equal]=${encodeURIComponent((/* @__PURE__ */ new Date()).toISOString())}`;
|
|
145
149
|
const [all, openRes, waiting, resolved, breach] = await Promise.all([
|
|
146
|
-
fetch(
|
|
147
|
-
fetch(
|
|
148
|
-
fetch(
|
|
149
|
-
fetch(
|
|
150
|
-
fetch(
|
|
150
|
+
fetch(`/api/tickets?limit=0&depth=0&${sn}`, { credentials: "include" }),
|
|
151
|
+
fetch(`/api/tickets?limit=0&depth=0&where[status][equals]=open&${sn}`, { credentials: "include" }),
|
|
152
|
+
fetch(`/api/tickets?limit=0&depth=0&where[status][equals]=waiting_client&${sn}`, { credentials: "include" }),
|
|
153
|
+
fetch(`/api/tickets?limit=0&depth=0&where[status][equals]=resolved&${sn}`, { credentials: "include" }),
|
|
154
|
+
fetch(`/api/tickets?limit=0&depth=0&where[or][0][slaFirstResponseBreached][equals]=true&where[or][1][slaResolutionBreached][equals]=true&${sn}`, { credentials: "include" })
|
|
151
155
|
]);
|
|
152
156
|
const [a, o, w, r, b] = await Promise.all([all.json(), openRes.json(), waiting.json(), resolved.json(), breach.json()]);
|
|
153
157
|
setCounts({
|
|
@@ -325,11 +329,11 @@ const TicketInboxClient = () => {
|
|
|
325
329
|
sla$1.state === "warn" ? s__default.default.slaWarn : "",
|
|
326
330
|
sla$1.state === "ok" ? s__default.default.slaOk : ""
|
|
327
331
|
].filter(Boolean).join(" "),
|
|
328
|
-
title: sla$1.due ? new Date(sla$1.due).toLocaleString(
|
|
332
|
+
title: sla$1.due ? new Date(sla$1.due).toLocaleString(dateLocale.DATE_LOCALE) : "",
|
|
329
333
|
children: sla.formatSlaRemaining(sla$1.remainingMs)
|
|
330
334
|
}
|
|
331
335
|
),
|
|
332
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: s__default.default.timeAgo, children: relativeTime(tk.updatedAt) }),
|
|
336
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: s__default.default.timeAgo, children: relativeTime(tk.updatedAt, t) }),
|
|
333
337
|
isUnread ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: s__default.default.unreadDot }) : /* @__PURE__ */ jsxRuntime.jsx("span", {})
|
|
334
338
|
]
|
|
335
339
|
},
|
|
@@ -4,6 +4,7 @@ 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 { DATE_LOCALE } from '../shared/dateLocale.js';
|
|
7
8
|
import { StatusPill } from '../shared/StatusPill.js';
|
|
8
9
|
import { computeSlaState, formatSlaRemaining } from '../shared/sla.js';
|
|
9
10
|
import s from '../../styles/TicketInbox.module.scss';
|
|
@@ -21,16 +22,16 @@ const STATUS_VARIANT = {
|
|
|
21
22
|
resolved: "resolved",
|
|
22
23
|
closed: "closed"
|
|
23
24
|
};
|
|
24
|
-
function relativeTime(dateStr) {
|
|
25
|
+
function relativeTime(dateStr, tFn) {
|
|
25
26
|
const diff = Date.now() - new Date(dateStr).getTime();
|
|
26
27
|
const mins = Math.floor(diff / 6e4);
|
|
27
|
-
if (mins < 1) return "
|
|
28
|
+
if (mins < 1) return tFn("inbox.timeAgo.now");
|
|
28
29
|
if (mins < 60) return `${mins}m`;
|
|
29
30
|
const hours = Math.floor(mins / 60);
|
|
30
31
|
if (hours < 24) return `${hours}h`;
|
|
31
32
|
const days = Math.floor(hours / 24);
|
|
32
33
|
if (days < 7) return `${days}j`;
|
|
33
|
-
return new Date(dateStr).toLocaleDateString(
|
|
34
|
+
return new Date(dateStr).toLocaleDateString(DATE_LOCALE, { day: "numeric", month: "short" });
|
|
34
35
|
}
|
|
35
36
|
const TicketInboxClient = () => {
|
|
36
37
|
const { t } = useTranslation();
|
|
@@ -115,6 +116,8 @@ const TicketInboxClient = () => {
|
|
|
115
116
|
params.push(`where[or][0][subject][contains]=${encodeURIComponent(search)}`);
|
|
116
117
|
params.push(`where[or][1][ticketNumber][contains]=${encodeURIComponent(search)}`);
|
|
117
118
|
}
|
|
119
|
+
params.push(`where[and][0][or][0][snoozeUntil][exists]=false`);
|
|
120
|
+
params.push(`where[and][0][or][1][snoozeUntil][less_than_equal]=${encodeURIComponent((/* @__PURE__ */ new Date()).toISOString())}`);
|
|
118
121
|
try {
|
|
119
122
|
const url = `/api/tickets?${params.join("&")}`;
|
|
120
123
|
const res = await fetch(url, { credentials: "include" });
|
|
@@ -136,12 +139,13 @@ const TicketInboxClient = () => {
|
|
|
136
139
|
useEffect(() => {
|
|
137
140
|
const fetchCounts = async () => {
|
|
138
141
|
try {
|
|
142
|
+
const sn = `where[and][0][or][0][snoozeUntil][exists]=false&where[and][0][or][1][snoozeUntil][less_than_equal]=${encodeURIComponent((/* @__PURE__ */ new Date()).toISOString())}`;
|
|
139
143
|
const [all, openRes, waiting, resolved, breach] = await Promise.all([
|
|
140
|
-
fetch(
|
|
141
|
-
fetch(
|
|
142
|
-
fetch(
|
|
143
|
-
fetch(
|
|
144
|
-
fetch(
|
|
144
|
+
fetch(`/api/tickets?limit=0&depth=0&${sn}`, { credentials: "include" }),
|
|
145
|
+
fetch(`/api/tickets?limit=0&depth=0&where[status][equals]=open&${sn}`, { credentials: "include" }),
|
|
146
|
+
fetch(`/api/tickets?limit=0&depth=0&where[status][equals]=waiting_client&${sn}`, { credentials: "include" }),
|
|
147
|
+
fetch(`/api/tickets?limit=0&depth=0&where[status][equals]=resolved&${sn}`, { credentials: "include" }),
|
|
148
|
+
fetch(`/api/tickets?limit=0&depth=0&where[or][0][slaFirstResponseBreached][equals]=true&where[or][1][slaResolutionBreached][equals]=true&${sn}`, { credentials: "include" })
|
|
145
149
|
]);
|
|
146
150
|
const [a, o, w, r, b] = await Promise.all([all.json(), openRes.json(), waiting.json(), resolved.json(), breach.json()]);
|
|
147
151
|
setCounts({
|
|
@@ -319,11 +323,11 @@ const TicketInboxClient = () => {
|
|
|
319
323
|
sla.state === "warn" ? s.slaWarn : "",
|
|
320
324
|
sla.state === "ok" ? s.slaOk : ""
|
|
321
325
|
].filter(Boolean).join(" "),
|
|
322
|
-
title: sla.due ? new Date(sla.due).toLocaleString(
|
|
326
|
+
title: sla.due ? new Date(sla.due).toLocaleString(DATE_LOCALE) : "",
|
|
323
327
|
children: formatSlaRemaining(sla.remainingMs)
|
|
324
328
|
}
|
|
325
329
|
),
|
|
326
|
-
/* @__PURE__ */ jsx("span", { className: s.timeAgo, children: relativeTime(tk.updatedAt) }),
|
|
330
|
+
/* @__PURE__ */ jsx("span", { className: s.timeAgo, children: relativeTime(tk.updatedAt, t) }),
|
|
327
331
|
isUnread ? /* @__PURE__ */ jsx("div", { className: s.unreadDot }) : /* @__PURE__ */ jsx("span", {})
|
|
328
332
|
]
|
|
329
333
|
},
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var jsxRuntime = require('react/jsx-runtime');
|
|
4
|
-
var
|
|
4
|
+
var React = require('react');
|
|
5
5
|
var lucideReact = require('lucide-react');
|
|
6
6
|
var adminTokens = require('../shared/adminTokens');
|
|
7
7
|
var AdminViewHeader = require('../shared/AdminViewHeader');
|
|
@@ -11,6 +11,7 @@ var ts = require('../../styles/TicketingSettings.module.scss');
|
|
|
11
11
|
|
|
12
12
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
13
13
|
|
|
14
|
+
var React__default = /*#__PURE__*/_interopDefault(React);
|
|
14
15
|
var ts__default = /*#__PURE__*/_interopDefault(ts);
|
|
15
16
|
|
|
16
17
|
const DEFAULT_SETTINGS = {
|
|
@@ -102,31 +103,35 @@ async function saveUserPrefs(prefs) {
|
|
|
102
103
|
return false;
|
|
103
104
|
}
|
|
104
105
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
106
|
+
function getFeatureList(t) {
|
|
107
|
+
return [
|
|
108
|
+
// Core
|
|
109
|
+
{ key: "canned", label: t("settingsView.features.canned.label"), description: t("settingsView.features.canned.description"), category: "core" },
|
|
110
|
+
{ key: "scheduledReplies", label: t("settingsView.features.scheduledReplies.label"), description: t("settingsView.features.scheduledReplies.description"), category: "core" },
|
|
111
|
+
{ key: "activityLog", label: t("settingsView.features.activityLog.label"), description: t("settingsView.features.activityLog.description"), category: "core" },
|
|
112
|
+
// Communication
|
|
113
|
+
{ key: "emailTracking", label: t("settingsView.features.emailTracking.label"), description: t("settingsView.features.emailTracking.description"), category: "communication" },
|
|
114
|
+
{ key: "chat", label: t("settingsView.features.chat.label"), description: t("settingsView.features.chat.description"), category: "communication" },
|
|
115
|
+
{ key: "externalMessages", label: t("settingsView.features.externalMessages.label"), description: t("settingsView.features.externalMessages.description"), category: "communication" },
|
|
116
|
+
// Productivity
|
|
117
|
+
{ key: "ai", label: t("settingsView.features.ai.label"), description: t("settingsView.features.ai.description"), category: "productivity" },
|
|
118
|
+
{ key: "timeTracking", label: t("settingsView.features.timeTracking.label"), description: t("settingsView.features.timeTracking.description"), category: "productivity" },
|
|
119
|
+
{ key: "satisfaction", label: t("settingsView.features.satisfaction.label"), description: t("settingsView.features.satisfaction.description"), category: "productivity" },
|
|
120
|
+
// Advanced
|
|
121
|
+
{ key: "merge", label: t("settingsView.features.merge.label"), description: t("settingsView.features.merge.description"), category: "advanced" },
|
|
122
|
+
{ key: "splitTicket", label: t("settingsView.features.splitTicket.label"), description: t("settingsView.features.splitTicket.description"), category: "advanced" },
|
|
123
|
+
{ key: "snooze", label: t("settingsView.features.snooze.label"), description: t("settingsView.features.snooze.description"), category: "advanced" },
|
|
124
|
+
{ key: "clientHistory", label: t("settingsView.features.clientHistory.label"), description: t("settingsView.features.clientHistory.description"), category: "advanced" }
|
|
125
|
+
];
|
|
126
|
+
}
|
|
127
|
+
function getCategories(t) {
|
|
128
|
+
return [
|
|
129
|
+
{ key: "core", label: t("settingsView.categories.core"), color: adminTokens.V.blue },
|
|
130
|
+
{ key: "communication", label: t("settingsView.categories.communication"), color: adminTokens.V.green },
|
|
131
|
+
{ key: "productivity", label: t("settingsView.categories.productivity"), color: adminTokens.V.amber },
|
|
132
|
+
{ key: "advanced", label: t("settingsView.categories.advanced"), color: "#7c3aed" }
|
|
133
|
+
];
|
|
134
|
+
}
|
|
130
135
|
const Toggle = ({ checked, onChange, color = adminTokens.V.blue, size = "md" }) => {
|
|
131
136
|
const w = size === "sm" ? 36 : 40;
|
|
132
137
|
const h = size === "sm" ? 20 : 22;
|
|
@@ -169,7 +174,7 @@ const Toggle = ({ checked, onChange, color = adminTokens.V.blue, size = "md" })
|
|
|
169
174
|
);
|
|
170
175
|
};
|
|
171
176
|
const CollapsibleSection = ({ title, icon, color, defaultOpen = true, children, badge }) => {
|
|
172
|
-
const [open, setOpen] =
|
|
177
|
+
const [open, setOpen] = React.useState(defaultOpen);
|
|
173
178
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ts__default.default.sectionWrapper, children: [
|
|
174
179
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
175
180
|
"div",
|
|
@@ -205,14 +210,16 @@ const FieldRow = ({ label, description, children }) => /* @__PURE__ */ jsxRuntim
|
|
|
205
210
|
] });
|
|
206
211
|
const TicketingSettingsClient = () => {
|
|
207
212
|
const { t } = useTranslation.useTranslation();
|
|
208
|
-
const
|
|
209
|
-
const
|
|
210
|
-
const [
|
|
211
|
-
const [
|
|
212
|
-
const [
|
|
213
|
-
const [
|
|
214
|
-
const [
|
|
215
|
-
|
|
213
|
+
const FEATURE_LIST = React__default.default.useMemo(() => getFeatureList(t), [t]);
|
|
214
|
+
const CATEGORIES = React__default.default.useMemo(() => getCategories(t), [t]);
|
|
215
|
+
const [features, setFeatures] = React.useState(() => config.getFeatures());
|
|
216
|
+
const [settings, setSettings] = React.useState(DEFAULT_SETTINGS);
|
|
217
|
+
const [signature, setSignature] = React.useState("");
|
|
218
|
+
const [saved, setSaved] = React.useState(false);
|
|
219
|
+
const [saving, setSaving] = React.useState(false);
|
|
220
|
+
const [showApiKey, setShowApiKey] = React.useState(false);
|
|
221
|
+
const [loadingSettings, setLoadingSettings] = React.useState(true);
|
|
222
|
+
React.useEffect(() => {
|
|
216
223
|
let cancelled = false;
|
|
217
224
|
Promise.all([fetchSettingsFromAPI(), fetchUserPrefs()]).then(([s, prefs]) => {
|
|
218
225
|
if (!cancelled) {
|
|
@@ -350,13 +357,13 @@ const TicketingSettingsClient = () => {
|
|
|
350
357
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
351
358
|
CollapsibleSection,
|
|
352
359
|
{
|
|
353
|
-
title: "
|
|
360
|
+
title: t("settingsView.emailConfig"),
|
|
354
361
|
icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Mail, { size: 16 }),
|
|
355
362
|
color: "#ea580c",
|
|
356
363
|
defaultOpen: false,
|
|
357
364
|
children: [
|
|
358
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: ts__default.default.sectionDescription, children: "
|
|
359
|
-
/* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: "
|
|
365
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: ts__default.default.sectionDescription, children: t("settingsView.emailDescription") }),
|
|
366
|
+
/* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: t("settingsView.senderAddress"), description: t("settingsView.senderAddressDesc"), children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
360
367
|
"input",
|
|
361
368
|
{
|
|
362
369
|
type: "email",
|
|
@@ -366,7 +373,7 @@ const TicketingSettingsClient = () => {
|
|
|
366
373
|
className: ts__default.default.input
|
|
367
374
|
}
|
|
368
375
|
) }),
|
|
369
|
-
/* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: "
|
|
376
|
+
/* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: t("settingsView.senderName"), description: t("settingsView.senderNameDesc"), children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
370
377
|
"input",
|
|
371
378
|
{
|
|
372
379
|
type: "text",
|
|
@@ -376,7 +383,7 @@ const TicketingSettingsClient = () => {
|
|
|
376
383
|
className: ts__default.default.input
|
|
377
384
|
}
|
|
378
385
|
) }),
|
|
379
|
-
/* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: "
|
|
386
|
+
/* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: t("settingsView.replyTo"), description: t("settingsView.replyToDesc"), children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
380
387
|
"input",
|
|
381
388
|
{
|
|
382
389
|
type: "email",
|
|
@@ -387,7 +394,7 @@ const TicketingSettingsClient = () => {
|
|
|
387
394
|
}
|
|
388
395
|
) }),
|
|
389
396
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: ts__default.default.separator }),
|
|
390
|
-
/* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: "
|
|
397
|
+
/* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: t("settingsView.smtpServer"), description: t("settingsView.smtpServerDesc"), children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
391
398
|
"input",
|
|
392
399
|
{
|
|
393
400
|
type: "text",
|
|
@@ -396,7 +403,7 @@ const TicketingSettingsClient = () => {
|
|
|
396
403
|
className: ts__default.default.inputReadonly
|
|
397
404
|
}
|
|
398
405
|
) }),
|
|
399
|
-
/* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: "
|
|
406
|
+
/* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: t("settingsView.smtpPort"), children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
400
407
|
"input",
|
|
401
408
|
{
|
|
402
409
|
type: "text",
|
|
@@ -412,14 +419,14 @@ const TicketingSettingsClient = () => {
|
|
|
412
419
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
413
420
|
CollapsibleSection,
|
|
414
421
|
{
|
|
415
|
-
title: "
|
|
422
|
+
title: t("settingsView.aiTitle"),
|
|
416
423
|
icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Bot, { size: 16 }),
|
|
417
424
|
color: "#7c3aed",
|
|
418
425
|
defaultOpen: false,
|
|
419
|
-
badge: features.ai ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: ts__default.default.badge, style: { backgroundColor: "#dcfce7", color: "#166534" }, children: "
|
|
426
|
+
badge: features.ai ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: ts__default.default.badge, style: { backgroundColor: "#dcfce7", color: "#166534" }, children: t("settingsView.aiBadgeActive") }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: ts__default.default.badge, style: { backgroundColor: "#fee2e2", color: "#991b1b" }, children: t("settingsView.aiBadgeInactive") }),
|
|
420
427
|
children: [
|
|
421
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: ts__default.default.sectionDescription, children:
|
|
422
|
-
/* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: "
|
|
428
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: ts__default.default.sectionDescription, children: t("settingsView.aiDescription") }),
|
|
429
|
+
/* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: t("settingsView.aiProvider"), description: t("settingsView.aiProviderDesc"), children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
423
430
|
"select",
|
|
424
431
|
{
|
|
425
432
|
value: settings.ai.provider,
|
|
@@ -433,7 +440,7 @@ const TicketingSettingsClient = () => {
|
|
|
433
440
|
]
|
|
434
441
|
}
|
|
435
442
|
) }),
|
|
436
|
-
settings.ai.provider !== "ollama" && /* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: "
|
|
443
|
+
settings.ai.provider !== "ollama" && /* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: t("settingsView.aiApiKey"), description: t("settingsView.aiApiKeyDesc"), children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ts__default.default.apiKeyRow, children: [
|
|
437
444
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
438
445
|
"input",
|
|
439
446
|
{
|
|
@@ -450,11 +457,11 @@ const TicketingSettingsClient = () => {
|
|
|
450
457
|
{
|
|
451
458
|
onClick: () => setShowApiKey(!showApiKey),
|
|
452
459
|
className: ts__default.default.apiKeyToggle,
|
|
453
|
-
children: showApiKey ? "
|
|
460
|
+
children: showApiKey ? t("settingsView.hideKey") : t("settingsView.showKey")
|
|
454
461
|
}
|
|
455
462
|
)
|
|
456
463
|
] }) }),
|
|
457
|
-
/* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: "
|
|
464
|
+
/* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: t("settingsView.aiModel"), description: t("settingsView.aiModelDesc"), children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
458
465
|
"input",
|
|
459
466
|
{
|
|
460
467
|
type: "text",
|
|
@@ -465,12 +472,12 @@ const TicketingSettingsClient = () => {
|
|
|
465
472
|
}
|
|
466
473
|
) }),
|
|
467
474
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: ts__default.default.separator }),
|
|
468
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: ts__default.default.aiSubFeaturesLabel, children: "
|
|
475
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: ts__default.default.aiSubFeaturesLabel, children: t("settingsView.aiSubFeatures") }),
|
|
469
476
|
[
|
|
470
|
-
{ key: "enableSentiment", label: "
|
|
471
|
-
{ key: "enableSynthesis", label: "
|
|
472
|
-
{ key: "enableSuggestion", label: "
|
|
473
|
-
{ key: "enableRewrite", label: "
|
|
477
|
+
{ key: "enableSentiment", label: t("settingsView.aiSentiment"), desc: t("settingsView.aiSentimentDesc") },
|
|
478
|
+
{ key: "enableSynthesis", label: t("settingsView.aiSynthesis"), desc: t("settingsView.aiSynthesisDesc") },
|
|
479
|
+
{ key: "enableSuggestion", label: t("settingsView.aiSuggestion"), desc: t("settingsView.aiSuggestionDesc") },
|
|
480
|
+
{ key: "enableRewrite", label: t("settingsView.aiRewrite"), desc: t("settingsView.aiRewriteDesc") }
|
|
474
481
|
].map((item) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ts__default.default.aiToggleRow, children: [
|
|
475
482
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
476
483
|
Toggle,
|
|
@@ -492,13 +499,13 @@ const TicketingSettingsClient = () => {
|
|
|
492
499
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
493
500
|
CollapsibleSection,
|
|
494
501
|
{
|
|
495
|
-
title: "
|
|
502
|
+
title: t("settingsView.slaTitle"),
|
|
496
503
|
icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Clock, { size: 16 }),
|
|
497
504
|
color: "#0891b2",
|
|
498
505
|
defaultOpen: false,
|
|
499
506
|
children: [
|
|
500
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: ts__default.default.sectionDescription, children: "
|
|
501
|
-
/* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: "
|
|
507
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: ts__default.default.sectionDescription, children: t("settingsView.slaDescription") }),
|
|
508
|
+
/* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: t("settingsView.slaFirstResponse"), description: t("settingsView.slaFirstResponseDesc"), children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ts__default.default.slaInline, children: [
|
|
502
509
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
503
510
|
"input",
|
|
504
511
|
{
|
|
@@ -510,14 +517,15 @@ const TicketingSettingsClient = () => {
|
|
|
510
517
|
}
|
|
511
518
|
),
|
|
512
519
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: ts__default.default.slaHint, children: [
|
|
513
|
-
"minutes
|
|
520
|
+
t("settingsView.minutes"),
|
|
521
|
+
" (",
|
|
514
522
|
Math.floor(settings.sla.firstResponseMinutes / 60),
|
|
515
523
|
"h",
|
|
516
524
|
String(settings.sla.firstResponseMinutes % 60).padStart(2, "0"),
|
|
517
525
|
")"
|
|
518
526
|
] })
|
|
519
527
|
] }) }),
|
|
520
|
-
/* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: "
|
|
528
|
+
/* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: t("settingsView.slaResolution"), description: t("settingsView.slaResolutionDesc"), children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ts__default.default.slaInline, children: [
|
|
521
529
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
522
530
|
"input",
|
|
523
531
|
{
|
|
@@ -529,7 +537,8 @@ const TicketingSettingsClient = () => {
|
|
|
529
537
|
}
|
|
530
538
|
),
|
|
531
539
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: ts__default.default.slaHint, children: [
|
|
532
|
-
"minutes
|
|
540
|
+
t("settingsView.minutes"),
|
|
541
|
+
" (",
|
|
533
542
|
Math.floor(settings.sla.resolutionMinutes / 60),
|
|
534
543
|
"h",
|
|
535
544
|
String(settings.sla.resolutionMinutes % 60).padStart(2, "0"),
|
|
@@ -547,12 +556,12 @@ const TicketingSettingsClient = () => {
|
|
|
547
556
|
}
|
|
548
557
|
),
|
|
549
558
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
550
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: ts__default.default.inlineLabel, children: "
|
|
551
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: ts__default.default.inlineDesc, children: "
|
|
559
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: ts__default.default.inlineLabel, children: t("settingsView.businessHoursOnly") }),
|
|
560
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: ts__default.default.inlineDesc, children: t("settingsView.businessHoursDesc") })
|
|
552
561
|
] })
|
|
553
562
|
] }),
|
|
554
563
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: ts__default.default.separator }),
|
|
555
|
-
/* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: "
|
|
564
|
+
/* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: t("settingsView.escalationEmail"), description: t("settingsView.escalationEmailDesc"), children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
556
565
|
"input",
|
|
557
566
|
{
|
|
558
567
|
type: "email",
|
|
@@ -568,7 +577,7 @@ const TicketingSettingsClient = () => {
|
|
|
568
577
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
569
578
|
CollapsibleSection,
|
|
570
579
|
{
|
|
571
|
-
title: "
|
|
580
|
+
title: t("settingsView.autoCloseTitle"),
|
|
572
581
|
icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Timer, { size: 16 }),
|
|
573
582
|
color: "#d97706",
|
|
574
583
|
defaultOpen: false,
|
|
@@ -577,7 +586,7 @@ const TicketingSettingsClient = () => {
|
|
|
577
586
|
"j"
|
|
578
587
|
] }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: ts__default.default.badge, style: { backgroundColor: "#e5e7eb", color: "#374151" }, children: "Off" }),
|
|
579
588
|
children: [
|
|
580
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: ts__default.default.sectionDescription, children: "
|
|
589
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: ts__default.default.sectionDescription, children: t("settingsView.autoCloseDescription") }),
|
|
581
590
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: ts__default.default.toggleRow, style: { paddingBottom: 14 }, children: [
|
|
582
591
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
583
592
|
Toggle,
|
|
@@ -587,10 +596,10 @@ const TicketingSettingsClient = () => {
|
|
|
587
596
|
color: "#d97706"
|
|
588
597
|
}
|
|
589
598
|
),
|
|
590
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: ts__default.default.inlineLabel, children: "
|
|
599
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: ts__default.default.inlineLabel, children: t("settingsView.autoCloseEnable") })
|
|
591
600
|
] }),
|
|
592
601
|
settings.autoClose.enabled && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
593
|
-
/* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: "
|
|
602
|
+
/* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: t("settingsView.autoCloseDelay"), description: t("settingsView.autoCloseDelayDesc"), children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ts__default.default.slaInline, children: [
|
|
594
603
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
595
604
|
"input",
|
|
596
605
|
{
|
|
@@ -602,9 +611,9 @@ const TicketingSettingsClient = () => {
|
|
|
602
611
|
className: ts__default.default.numberInput
|
|
603
612
|
}
|
|
604
613
|
),
|
|
605
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: ts__default.default.slaHint, children: "
|
|
614
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: ts__default.default.slaHint, children: t("settingsView.days") })
|
|
606
615
|
] }) }),
|
|
607
|
-
/* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: "
|
|
616
|
+
/* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: t("settingsView.autoCloseReminder"), description: t("settingsView.autoCloseReminderDesc"), children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ts__default.default.slaInline, children: [
|
|
608
617
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
609
618
|
"input",
|
|
610
619
|
{
|
|
@@ -616,11 +625,7 @@ const TicketingSettingsClient = () => {
|
|
|
616
625
|
className: ts__default.default.numberInput
|
|
617
626
|
}
|
|
618
627
|
),
|
|
619
|
-
/* @__PURE__ */ jsxRuntime.
|
|
620
|
-
"jours avant (rappel a J-",
|
|
621
|
-
settings.autoClose.reminderDaysBefore,
|
|
622
|
-
")"
|
|
623
|
-
] })
|
|
628
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: ts__default.default.slaHint, children: t("settingsView.autoCloseDaysBeforeReminder", { count: String(settings.autoClose.reminderDaysBefore) }) })
|
|
624
629
|
] }) })
|
|
625
630
|
] })
|
|
626
631
|
]
|
|
@@ -634,27 +639,27 @@ const TicketingSettingsClient = () => {
|
|
|
634
639
|
background: "linear-gradient(135deg, #dbeafe 0%, #ede9fe 100%)",
|
|
635
640
|
border: "1px solid #c7d2fe"
|
|
636
641
|
}, children: [
|
|
637
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontWeight: 700, fontSize: 15, color: "#1e293b" }, children: "
|
|
638
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: 13, color: "#64748b", marginTop: 2 }, children: "
|
|
642
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontWeight: 700, fontSize: 15, color: "#1e293b" }, children: t("settingsView.myPreferences") }),
|
|
643
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: 13, color: "#64748b", marginTop: 2 }, children: t("settingsView.myPreferencesDesc") })
|
|
639
644
|
] }),
|
|
640
645
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
641
646
|
CollapsibleSection,
|
|
642
647
|
{
|
|
643
|
-
title: "
|
|
648
|
+
title: t("settingsView.localeTitle"),
|
|
644
649
|
icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Globe, { size: 16 }),
|
|
645
650
|
color: "#16a34a",
|
|
646
651
|
defaultOpen: false,
|
|
647
652
|
children: [
|
|
648
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: ts__default.default.sectionDescription, children: "
|
|
649
|
-
/* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: "
|
|
653
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: ts__default.default.sectionDescription, children: t("settingsView.localeDescription") }),
|
|
654
|
+
/* @__PURE__ */ jsxRuntime.jsx(FieldRow, { label: t("settingsView.language"), description: t("settingsView.languageDesc"), children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
650
655
|
"select",
|
|
651
656
|
{
|
|
652
657
|
value: settings.locale.language,
|
|
653
658
|
onChange: (e) => updateLocale("language", e.target.value),
|
|
654
659
|
className: ts__default.default.select,
|
|
655
660
|
children: [
|
|
656
|
-
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "fr", children: "
|
|
657
|
-
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "en", children: "
|
|
661
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "fr", children: t("settingsView.french") }),
|
|
662
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "en", children: t("settingsView.english") })
|
|
658
663
|
]
|
|
659
664
|
}
|
|
660
665
|
) })
|
|
@@ -664,12 +669,12 @@ const TicketingSettingsClient = () => {
|
|
|
664
669
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
665
670
|
CollapsibleSection,
|
|
666
671
|
{
|
|
667
|
-
title: "
|
|
672
|
+
title: t("settingsView.signatureTitle"),
|
|
668
673
|
icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileSignature, { size: 16 }),
|
|
669
674
|
color: "#6366f1",
|
|
670
675
|
defaultOpen: false,
|
|
671
676
|
children: [
|
|
672
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: ts__default.default.sectionDescription, children: "
|
|
677
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: ts__default.default.sectionDescription, children: t("settingsView.signatureDescription") }),
|
|
673
678
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
674
679
|
"textarea",
|
|
675
680
|
{
|
|
@@ -678,7 +683,7 @@ const TicketingSettingsClient = () => {
|
|
|
678
683
|
setSignature(e.target.value);
|
|
679
684
|
setSaved(false);
|
|
680
685
|
},
|
|
681
|
-
placeholder: "
|
|
686
|
+
placeholder: t("settingsView.signaturePlaceholder"),
|
|
682
687
|
rows: 6,
|
|
683
688
|
className: ts__default.default.signatureTextarea
|
|
684
689
|
}
|
|
@@ -686,28 +691,28 @@ const TicketingSettingsClient = () => {
|
|
|
686
691
|
]
|
|
687
692
|
}
|
|
688
693
|
),
|
|
689
|
-
/* @__PURE__ */ jsxRuntime.jsxs(CollapsibleSection, { title: "
|
|
690
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: ts__default.default.sectionDescription, children: "
|
|
694
|
+
/* @__PURE__ */ jsxRuntime.jsxs(CollapsibleSection, { title: t("settingsView.purgeTitle"), icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Settings, { size: 18 }), color: "#ef4444", defaultOpen: false, children: [
|
|
695
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: ts__default.default.sectionDescription, children: t("settingsView.purgeDescription") }),
|
|
691
696
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: ts__default.default.purgeGroup, children: ["email-logs", "auth-logs"].map((col) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ts__default.default.purgeCategory, children: [
|
|
692
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: ts__default.default.purgeCategoryLabel, children: col === "email-logs" ? "
|
|
697
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: ts__default.default.purgeCategoryLabel, children: col === "email-logs" ? t("settingsView.purgeEmailLogs") : t("settingsView.purgeAuthLogs") }),
|
|
693
698
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: ts__default.default.purgeButtons, children: [
|
|
694
|
-
{ label: "
|
|
695
|
-
{ label: "
|
|
696
|
-
{ label: "
|
|
697
|
-
{ label: "
|
|
699
|
+
{ label: t("settingsView.purge7days"), days: 7 },
|
|
700
|
+
{ label: t("settingsView.purge30days"), days: 30 },
|
|
701
|
+
{ label: t("settingsView.purge90days"), days: 90 },
|
|
702
|
+
{ label: t("settingsView.purgeAllLabel"), days: 0 }
|
|
698
703
|
].map((opt) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
699
704
|
"button",
|
|
700
705
|
{
|
|
701
706
|
onClick: async () => {
|
|
702
|
-
if (!window.confirm(
|
|
707
|
+
if (!window.confirm(t("settingsView.purgeConfirm", { collection: col, days: opt.days === 0 ? t("settingsView.purgeAllLabel") : String(opt.days) }))) return;
|
|
703
708
|
try {
|
|
704
709
|
const res = await fetch(`/api/support/purge-logs?collection=${col}&days=${opt.days}`, { method: "DELETE", credentials: "include" });
|
|
705
710
|
if (res.ok) {
|
|
706
711
|
const d = await res.json();
|
|
707
|
-
alert(`${d.purged}
|
|
712
|
+
alert(`${d.purged} ${t("settingsView.purgeDone")}`);
|
|
708
713
|
}
|
|
709
714
|
} catch {
|
|
710
|
-
alert("
|
|
715
|
+
alert(t("import.errorTitle"));
|
|
711
716
|
}
|
|
712
717
|
},
|
|
713
718
|
style: { ...adminTokens.btnStyle(opt.days === 0 ? "#ef4444" : "var(--theme-elevation-500)", { small: true }), fontSize: 11 },
|
|
@@ -718,14 +723,14 @@ const TicketingSettingsClient = () => {
|
|
|
718
723
|
] }, col)) })
|
|
719
724
|
] }),
|
|
720
725
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: ts__default.default.bottomBar, children: [
|
|
721
|
-
/* @__PURE__ */ jsxRuntime.jsx("button", { onClick: handleReset, style: adminTokens.btnStyle("var(--theme-elevation-400)", { small: true }), children: "
|
|
726
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { onClick: handleReset, style: adminTokens.btnStyle("var(--theme-elevation-400)", { small: true }), children: t("settingsView.resetAll") }),
|
|
722
727
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
723
728
|
"button",
|
|
724
729
|
{
|
|
725
730
|
onClick: handleSave,
|
|
726
731
|
disabled: saving,
|
|
727
732
|
style: adminTokens.btnStyle(saved ? adminTokens.V.green : adminTokens.V.blue, { small: true }),
|
|
728
|
-
children: saving ? "
|
|
733
|
+
children: saving ? t("settingsView.saving") : saved ? t("settingsView.saved2") : t("settingsView.saveChanges")
|
|
729
734
|
}
|
|
730
735
|
)
|
|
731
736
|
] })
|