@reqdesk/widget 0.1.0 → 0.3.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 +334 -334
- package/dist/{index-2oPxlN4_.d.cts → index-C4jNMODn.d.cts} +2 -2
- package/dist/{index-2oPxlN4_.d.cts.map → index-C4jNMODn.d.cts.map} +1 -1
- package/dist/{index-B8fhsCuv.d.ts → index-CgLsyyP9.d.ts} +2 -2
- package/dist/{index-B8fhsCuv.d.ts.map → index-CgLsyyP9.d.ts.map} +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.iife.js +17 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/{react-D69QlAm1.d.ts → react-BLAoKiUb.d.ts} +8 -8
- package/dist/{react-D69QlAm1.d.ts.map → react-BLAoKiUb.d.ts.map} +1 -1
- package/dist/{react-8GCnIHnw.d.cts → react-SJ0r-FEh.d.cts} +8 -8
- package/dist/{react-8GCnIHnw.d.cts.map → react-SJ0r-FEh.d.cts.map} +1 -1
- package/dist/react.cjs +293 -45
- package/dist/react.d.cts +1 -1
- package/dist/react.d.ts +1 -1
- package/dist/react.js +293 -45
- package/dist/react.js.map +1 -1
- package/dist/{storage-CC5BCsxP.js → storage-BG7rsgWE.js} +102 -5
- package/dist/storage-BG7rsgWE.js.map +1 -0
- package/dist/{storage-Db9XjupR.cjs → storage-Cx5p1yP-.cjs} +118 -3
- package/dist/{types-gPfzZQw5.d.ts → types-i3IgBEjw.d.cts} +2 -1
- package/dist/{types-CRxzGfna.d.cts.map → types-i3IgBEjw.d.cts.map} +1 -1
- package/dist/{types-CRxzGfna.d.cts → types-rPiXlS0A.d.ts} +2 -1
- package/dist/{types-gPfzZQw5.d.ts.map → types-rPiXlS0A.d.ts.map} +1 -1
- package/package.json +81 -81
- package/dist/storage-CC5BCsxP.js.map +0 -1
package/dist/react.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { _ as
|
|
1
|
+
import { C as configureWidgetClient, S as uploadAttachment, _ as resolveWidgetUser, a as saveTrackingToken, b as submitTrackingReply, c as getWidgetStyles, d as ar, f as en, g as listMyTickets, h as getTicketDetail, i as loadWidgetEmail, l as themeToStyle, m as getCategories, n as getTrackingTokens, o as saveWidgetConfig, p as closeTicket, r as loadWidgetConfig, s as saveWidgetEmail, t as clearWidgetEmail, v as submitReply, w as setOidcTokenProvider, x as trackTicket, y as submitTicket } from "./storage-BG7rsgWE.js";
|
|
2
2
|
import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
|
|
3
3
|
import { QueryClient, QueryClientProvider, keepPreviousData, queryOptions, useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
|
4
4
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -31,7 +31,11 @@ function onAuthStateChange(listener) {
|
|
|
31
31
|
listeners = listeners.filter((l) => l !== listener);
|
|
32
32
|
};
|
|
33
33
|
}
|
|
34
|
-
|
|
34
|
+
function initWidgetAuth(config) {
|
|
35
|
+
initPromise = _initWidgetAuth(config);
|
|
36
|
+
return initPromise;
|
|
37
|
+
}
|
|
38
|
+
async function _initWidgetAuth(config) {
|
|
35
39
|
setState({ isLoading: true });
|
|
36
40
|
try {
|
|
37
41
|
const { createOidc } = await import("oidc-spa/core");
|
|
@@ -68,8 +72,13 @@ async function initWidgetAuth(config) {
|
|
|
68
72
|
});
|
|
69
73
|
}
|
|
70
74
|
}
|
|
75
|
+
let initPromise = null;
|
|
71
76
|
async function login() {
|
|
72
|
-
if (!oidcInstance)
|
|
77
|
+
if (!oidcInstance && initPromise) await initPromise;
|
|
78
|
+
if (!oidcInstance) {
|
|
79
|
+
console.warn("[reqdesk-widget] Cannot login: OIDC not initialized. Check auth config.");
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
73
82
|
await oidcInstance.login({ doesCurrentHrefRequiresAuth: false });
|
|
74
83
|
}
|
|
75
84
|
async function logout() {
|
|
@@ -297,7 +306,7 @@ function TicketForm({ mode = "inline", onTicketCreated, onError, className, styl
|
|
|
297
306
|
onError,
|
|
298
307
|
t
|
|
299
308
|
]);
|
|
300
|
-
const cssVars =
|
|
309
|
+
const cssVars = themeToStyle(ctx.theme);
|
|
301
310
|
const content = success ? /* @__PURE__ */ jsxs("div", {
|
|
302
311
|
className: "rqd-success",
|
|
303
312
|
style: {
|
|
@@ -435,7 +444,7 @@ function TicketForm({ mode = "inline", onTicketCreated, onError, className, styl
|
|
|
435
444
|
className,
|
|
436
445
|
style: {
|
|
437
446
|
...style,
|
|
438
|
-
|
|
447
|
+
...cssVars
|
|
439
448
|
},
|
|
440
449
|
children: /* @__PURE__ */ jsx("div", {
|
|
441
450
|
className: "rqd-body",
|
|
@@ -444,7 +453,7 @@ function TicketForm({ mode = "inline", onTicketCreated, onError, className, styl
|
|
|
444
453
|
}) });
|
|
445
454
|
return /* @__PURE__ */ jsx(ShadowRoot, { children: /* @__PURE__ */ jsx("div", {
|
|
446
455
|
className: `rqd-inline ${className ?? ""}`,
|
|
447
|
-
style:
|
|
456
|
+
style: cssVars,
|
|
448
457
|
children: /* @__PURE__ */ jsx("div", {
|
|
449
458
|
className: "rqd-body",
|
|
450
459
|
children: content
|
|
@@ -456,10 +465,10 @@ function TicketForm({ mode = "inline", onTicketCreated, onError, className, styl
|
|
|
456
465
|
function SupportPortal({ className }) {
|
|
457
466
|
const ctx = useReqdeskContext();
|
|
458
467
|
const { isLoading } = useReqdesk();
|
|
459
|
-
const cssVars =
|
|
468
|
+
const cssVars = themeToStyle(ctx.theme);
|
|
460
469
|
return /* @__PURE__ */ jsx(ShadowRoot, { children: /* @__PURE__ */ jsx("div", {
|
|
461
470
|
className: `rqd-inline ${className ?? ""}`,
|
|
462
|
-
style:
|
|
471
|
+
style: cssVars,
|
|
463
472
|
children: /* @__PURE__ */ jsx("div", {
|
|
464
473
|
className: "rqd-body",
|
|
465
474
|
children: isLoading ? /* @__PURE__ */ jsx("p", {
|
|
@@ -480,6 +489,132 @@ function SupportPortal({ className }) {
|
|
|
480
489
|
}) });
|
|
481
490
|
}
|
|
482
491
|
//#endregion
|
|
492
|
+
//#region src/react/queries.ts
|
|
493
|
+
const widgetTicketDetailOptions = (ticketId) => queryOptions({
|
|
494
|
+
queryKey: ["widget-ticket", ticketId],
|
|
495
|
+
queryFn: () => getTicketDetail(ticketId),
|
|
496
|
+
staleTime: 6e4,
|
|
497
|
+
enabled: !!ticketId
|
|
498
|
+
});
|
|
499
|
+
const widgetMyTicketsOptions = (projectId, userId) => queryOptions({
|
|
500
|
+
queryKey: [
|
|
501
|
+
"widget-tickets",
|
|
502
|
+
projectId,
|
|
503
|
+
userId
|
|
504
|
+
],
|
|
505
|
+
queryFn: () => listMyTickets(projectId, userId),
|
|
506
|
+
staleTime: 3e4,
|
|
507
|
+
placeholderData: keepPreviousData,
|
|
508
|
+
enabled: !!userId
|
|
509
|
+
});
|
|
510
|
+
const widgetUserOptions = (projectId, email) => queryOptions({
|
|
511
|
+
queryKey: [
|
|
512
|
+
"widget-user",
|
|
513
|
+
projectId,
|
|
514
|
+
email
|
|
515
|
+
],
|
|
516
|
+
queryFn: () => resolveWidgetUser(projectId, email),
|
|
517
|
+
staleTime: 5 * 6e4,
|
|
518
|
+
enabled: !!email
|
|
519
|
+
});
|
|
520
|
+
const widgetCategoriesOptions = (projectId, parentId) => queryOptions({
|
|
521
|
+
queryKey: [
|
|
522
|
+
"widget-categories",
|
|
523
|
+
projectId,
|
|
524
|
+
parentId ?? "root"
|
|
525
|
+
],
|
|
526
|
+
queryFn: () => getCategories(projectId, parentId),
|
|
527
|
+
staleTime: 5 * 6e4
|
|
528
|
+
});
|
|
529
|
+
//#endregion
|
|
530
|
+
//#region src/client-metadata.ts
|
|
531
|
+
const STORAGE_PREFIX = "reqdesk_diag_";
|
|
532
|
+
const DEFAULT_PREFS = {
|
|
533
|
+
screenResolution: false,
|
|
534
|
+
deviceType: false,
|
|
535
|
+
timezone: false,
|
|
536
|
+
referrerUrl: false,
|
|
537
|
+
language: false,
|
|
538
|
+
platform: false
|
|
539
|
+
};
|
|
540
|
+
/** Always collected — minimal, non-sensitive */
|
|
541
|
+
function collectMinimalMetadata() {
|
|
542
|
+
const meta = {};
|
|
543
|
+
try {
|
|
544
|
+
meta.pageUrl = window.location.href;
|
|
545
|
+
meta.userAgent = navigator.userAgent;
|
|
546
|
+
} catch {}
|
|
547
|
+
return meta;
|
|
548
|
+
}
|
|
549
|
+
/** Full diagnostic set — only included for opted-in fields */
|
|
550
|
+
function collectDiagnosticMetadata(prefs) {
|
|
551
|
+
const meta = {};
|
|
552
|
+
try {
|
|
553
|
+
if (prefs.screenResolution) meta.screenResolution = `${screen.width}x${screen.height}`;
|
|
554
|
+
if (prefs.deviceType) meta.deviceType = detectDeviceType();
|
|
555
|
+
if (prefs.timezone) meta.timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
556
|
+
if (prefs.referrerUrl && document.referrer) meta.referrerUrl = document.referrer;
|
|
557
|
+
if (prefs.language) meta.language = navigator.language;
|
|
558
|
+
if (prefs.platform) meta.platform = navigator.platform;
|
|
559
|
+
} catch {}
|
|
560
|
+
return meta;
|
|
561
|
+
}
|
|
562
|
+
/** Combine minimal + opted-in diagnostic metadata */
|
|
563
|
+
function collectAllMetadata(apiKey) {
|
|
564
|
+
const prefs = getMetadataPreferences(apiKey);
|
|
565
|
+
return {
|
|
566
|
+
...collectMinimalMetadata(),
|
|
567
|
+
...collectDiagnosticMetadata(prefs)
|
|
568
|
+
};
|
|
569
|
+
}
|
|
570
|
+
function getMetadataPreferences(apiKey) {
|
|
571
|
+
try {
|
|
572
|
+
const raw = localStorage.getItem(`${STORAGE_PREFIX}${apiKey}`);
|
|
573
|
+
if (raw) return {
|
|
574
|
+
...DEFAULT_PREFS,
|
|
575
|
+
...JSON.parse(raw)
|
|
576
|
+
};
|
|
577
|
+
} catch {}
|
|
578
|
+
return { ...DEFAULT_PREFS };
|
|
579
|
+
}
|
|
580
|
+
function saveMetadataPreferences(apiKey, prefs) {
|
|
581
|
+
try {
|
|
582
|
+
localStorage.setItem(`${STORAGE_PREFIX}${apiKey}`, JSON.stringify(prefs));
|
|
583
|
+
} catch {}
|
|
584
|
+
}
|
|
585
|
+
function detectDeviceType() {
|
|
586
|
+
const ua = navigator.userAgent.toLowerCase();
|
|
587
|
+
if (/tablet|ipad|playbook|silk/i.test(ua)) return "tablet";
|
|
588
|
+
if (/mobile|iphone|ipod|android.*mobile|windows phone/i.test(ua)) return "mobile";
|
|
589
|
+
return "desktop";
|
|
590
|
+
}
|
|
591
|
+
const DIAGNOSTIC_FIELDS = [
|
|
592
|
+
{
|
|
593
|
+
key: "screenResolution",
|
|
594
|
+
labelKey: "diag.screenResolution"
|
|
595
|
+
},
|
|
596
|
+
{
|
|
597
|
+
key: "deviceType",
|
|
598
|
+
labelKey: "diag.deviceType"
|
|
599
|
+
},
|
|
600
|
+
{
|
|
601
|
+
key: "timezone",
|
|
602
|
+
labelKey: "diag.timezone"
|
|
603
|
+
},
|
|
604
|
+
{
|
|
605
|
+
key: "referrerUrl",
|
|
606
|
+
labelKey: "diag.referrerUrl"
|
|
607
|
+
},
|
|
608
|
+
{
|
|
609
|
+
key: "language",
|
|
610
|
+
labelKey: "diag.language"
|
|
611
|
+
},
|
|
612
|
+
{
|
|
613
|
+
key: "platform",
|
|
614
|
+
labelKey: "diag.platform"
|
|
615
|
+
}
|
|
616
|
+
];
|
|
617
|
+
//#endregion
|
|
483
618
|
//#region src/react/views/SubmitTicketView.tsx
|
|
484
619
|
const translations$4 = {
|
|
485
620
|
en,
|
|
@@ -529,6 +664,19 @@ function SubmitTicketView({ projectId, onSuccess, onError, isAuthenticated, user
|
|
|
529
664
|
const [uploadProgress, setUploadProgress] = useState(null);
|
|
530
665
|
const [success, setSuccess] = useState(null);
|
|
531
666
|
const [rememberEmail, setRememberEmail] = useState(!!savedEmail);
|
|
667
|
+
const [categoryPath, setCategoryPath] = useState([]);
|
|
668
|
+
const [selectedCategory, setSelectedCategory] = useState(null);
|
|
669
|
+
const { data: categories = [] } = useQuery(widgetCategoriesOptions(projectId, categoryPath.length > 0 ? categoryPath[categoryPath.length - 1].id : null));
|
|
670
|
+
const [diagOpen, setDiagOpen] = useState(false);
|
|
671
|
+
const [diagPrefs, setDiagPrefs] = useState(getMetadataPreferences(ctx.apiKey));
|
|
672
|
+
const diagValues = collectDiagnosticMetadata({
|
|
673
|
+
screenResolution: true,
|
|
674
|
+
deviceType: true,
|
|
675
|
+
timezone: true,
|
|
676
|
+
referrerUrl: true,
|
|
677
|
+
language: true,
|
|
678
|
+
platform: true
|
|
679
|
+
});
|
|
532
680
|
const t = useCallback((key) => {
|
|
533
681
|
if (ctx.translations?.[key]) return ctx.translations[key];
|
|
534
682
|
return (translations$4[ctx.language] ?? translations$4.en)[key] ?? key;
|
|
@@ -615,12 +763,15 @@ function SubmitTicketView({ projectId, onSuccess, onError, isAuthenticated, user
|
|
|
615
763
|
}
|
|
616
764
|
setErrors({});
|
|
617
765
|
if (rememberEmail && email) saveWidgetEmail(ctx.apiKey, email);
|
|
766
|
+
saveMetadataPreferences(ctx.apiKey, diagPrefs);
|
|
618
767
|
const validFiles = files.filter((f) => !f.error);
|
|
619
768
|
const data = {
|
|
620
769
|
title,
|
|
621
770
|
description: formData.get("description")?.trim() || void 0,
|
|
622
771
|
email,
|
|
623
|
-
priority: formData.get("priority") ?? "medium"
|
|
772
|
+
priority: formData.get("priority") ?? "medium",
|
|
773
|
+
categoryId: selectedCategory?.id,
|
|
774
|
+
clientMetadata: collectAllMetadata(ctx.apiKey)
|
|
624
775
|
};
|
|
625
776
|
submitMutation.mutate({
|
|
626
777
|
data,
|
|
@@ -801,6 +952,97 @@ function SubmitTicketView({ projectId, onSuccess, onError, isAuthenticated, user
|
|
|
801
952
|
]
|
|
802
953
|
})]
|
|
803
954
|
}),
|
|
955
|
+
/* @__PURE__ */ jsxs("div", {
|
|
956
|
+
className: "rqd-form-group",
|
|
957
|
+
children: [/* @__PURE__ */ jsx("label", {
|
|
958
|
+
className: "rqd-label",
|
|
959
|
+
children: t("form.categorySelected")
|
|
960
|
+
}), selectedCategory ? /* @__PURE__ */ jsxs("div", {
|
|
961
|
+
className: "rqd-category-selected",
|
|
962
|
+
children: [/* @__PURE__ */ jsxs("span", { children: [
|
|
963
|
+
categoryPath.map((c) => c.name).join(" > "),
|
|
964
|
+
categoryPath.length > 0 ? " > " : "",
|
|
965
|
+
selectedCategory.name
|
|
966
|
+
] }), /* @__PURE__ */ jsx("button", {
|
|
967
|
+
type: "button",
|
|
968
|
+
onClick: () => {
|
|
969
|
+
setSelectedCategory(null);
|
|
970
|
+
setCategoryPath([]);
|
|
971
|
+
},
|
|
972
|
+
children: "×"
|
|
973
|
+
})]
|
|
974
|
+
}) : /* @__PURE__ */ jsxs(Fragment, { children: [categoryPath.length > 0 && /* @__PURE__ */ jsxs("div", {
|
|
975
|
+
className: "rqd-category-breadcrumb",
|
|
976
|
+
children: [/* @__PURE__ */ jsx("button", {
|
|
977
|
+
type: "button",
|
|
978
|
+
onClick: () => setCategoryPath([]),
|
|
979
|
+
children: t("form.categoryPlaceholder")
|
|
980
|
+
}), categoryPath.map((c, i) => /* @__PURE__ */ jsxs("span", { children: [/* @__PURE__ */ jsx("span", {
|
|
981
|
+
className: "rqd-category-breadcrumb-sep",
|
|
982
|
+
children: "›"
|
|
983
|
+
}), /* @__PURE__ */ jsx("button", {
|
|
984
|
+
type: "button",
|
|
985
|
+
onClick: () => setCategoryPath((prev) => prev.slice(0, i + 1)),
|
|
986
|
+
children: c.name
|
|
987
|
+
})] }, c.id))]
|
|
988
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
989
|
+
className: "rqd-category-list",
|
|
990
|
+
children: [categories.map((cat) => /* @__PURE__ */ jsxs("button", {
|
|
991
|
+
type: "button",
|
|
992
|
+
className: "rqd-category-item",
|
|
993
|
+
onClick: () => {
|
|
994
|
+
if (cat.hasChildren) setCategoryPath((prev) => [...prev, cat]);
|
|
995
|
+
else setSelectedCategory(cat);
|
|
996
|
+
},
|
|
997
|
+
children: [cat.name, cat.hasChildren && /* @__PURE__ */ jsx("span", {
|
|
998
|
+
className: "rqd-category-item-chevron",
|
|
999
|
+
children: "›"
|
|
1000
|
+
})]
|
|
1001
|
+
}, cat.id)), categories.length === 0 && categoryPath.length === 0 && /* @__PURE__ */ jsx("span", {
|
|
1002
|
+
style: {
|
|
1003
|
+
fontSize: 13,
|
|
1004
|
+
color: "var(--rqd-text-secondary)"
|
|
1005
|
+
},
|
|
1006
|
+
children: t("form.categoryPlaceholder")
|
|
1007
|
+
})]
|
|
1008
|
+
})] })]
|
|
1009
|
+
}),
|
|
1010
|
+
/* @__PURE__ */ jsxs("div", {
|
|
1011
|
+
className: "rqd-form-group",
|
|
1012
|
+
children: [/* @__PURE__ */ jsxs("button", {
|
|
1013
|
+
type: "button",
|
|
1014
|
+
className: "rqd-diag-toggle",
|
|
1015
|
+
onClick: () => setDiagOpen((prev) => !prev),
|
|
1016
|
+
children: [/* @__PURE__ */ jsx("span", { children: t("diag.title") }), /* @__PURE__ */ jsx("span", { children: diagOpen ? "▲" : "▼" })]
|
|
1017
|
+
}), diagOpen && /* @__PURE__ */ jsxs("div", {
|
|
1018
|
+
className: "rqd-diag-panel",
|
|
1019
|
+
children: [/* @__PURE__ */ jsx("p", {
|
|
1020
|
+
style: {
|
|
1021
|
+
fontSize: 12,
|
|
1022
|
+
color: "var(--rqd-text-secondary)",
|
|
1023
|
+
margin: "0 0 6px"
|
|
1024
|
+
},
|
|
1025
|
+
children: t("diag.hint")
|
|
1026
|
+
}), DIAGNOSTIC_FIELDS.map((field) => /* @__PURE__ */ jsxs("label", {
|
|
1027
|
+
className: "rqd-diag-item",
|
|
1028
|
+
children: [
|
|
1029
|
+
/* @__PURE__ */ jsx("input", {
|
|
1030
|
+
type: "checkbox",
|
|
1031
|
+
checked: diagPrefs[field.key],
|
|
1032
|
+
onChange: (e) => setDiagPrefs((prev) => ({
|
|
1033
|
+
...prev,
|
|
1034
|
+
[field.key]: e.target.checked
|
|
1035
|
+
}))
|
|
1036
|
+
}),
|
|
1037
|
+
/* @__PURE__ */ jsx("span", { children: t(field.labelKey) }),
|
|
1038
|
+
/* @__PURE__ */ jsx("span", {
|
|
1039
|
+
className: "rqd-diag-item-value",
|
|
1040
|
+
children: diagValues[field.key] ?? "—"
|
|
1041
|
+
})
|
|
1042
|
+
]
|
|
1043
|
+
}, field.key))]
|
|
1044
|
+
})]
|
|
1045
|
+
}),
|
|
804
1046
|
/* @__PURE__ */ jsxs("div", {
|
|
805
1047
|
className: "rqd-form-group",
|
|
806
1048
|
children: [
|
|
@@ -864,35 +1106,6 @@ function SubmitTicketView({ projectId, onSuccess, onError, isAuthenticated, user
|
|
|
864
1106
|
});
|
|
865
1107
|
}
|
|
866
1108
|
//#endregion
|
|
867
|
-
//#region src/react/queries.ts
|
|
868
|
-
const widgetTicketDetailOptions = (ticketId) => queryOptions({
|
|
869
|
-
queryKey: ["widget-ticket", ticketId],
|
|
870
|
-
queryFn: () => getTicketDetail(ticketId),
|
|
871
|
-
staleTime: 6e4,
|
|
872
|
-
enabled: !!ticketId
|
|
873
|
-
});
|
|
874
|
-
const widgetMyTicketsOptions = (projectId, userId) => queryOptions({
|
|
875
|
-
queryKey: [
|
|
876
|
-
"widget-tickets",
|
|
877
|
-
projectId,
|
|
878
|
-
userId
|
|
879
|
-
],
|
|
880
|
-
queryFn: () => listMyTickets(projectId, userId),
|
|
881
|
-
staleTime: 3e4,
|
|
882
|
-
placeholderData: keepPreviousData,
|
|
883
|
-
enabled: !!userId
|
|
884
|
-
});
|
|
885
|
-
const widgetUserOptions = (projectId, email) => queryOptions({
|
|
886
|
-
queryKey: [
|
|
887
|
-
"widget-user",
|
|
888
|
-
projectId,
|
|
889
|
-
email
|
|
890
|
-
],
|
|
891
|
-
queryFn: () => resolveWidgetUser(projectId, email),
|
|
892
|
-
staleTime: 5 * 6e4,
|
|
893
|
-
enabled: !!email
|
|
894
|
-
});
|
|
895
|
-
//#endregion
|
|
896
1109
|
//#region src/react/views/MyTicketsView.tsx
|
|
897
1110
|
const translations$3 = {
|
|
898
1111
|
en,
|
|
@@ -1074,6 +1287,24 @@ function TicketDetailView({ ticketId, onBack }) {
|
|
|
1074
1287
|
if (context?.previous) queryClient.setQueryData(["widget-ticket", ticketId], context.previous);
|
|
1075
1288
|
}
|
|
1076
1289
|
});
|
|
1290
|
+
const resolveMutation = useMutation({
|
|
1291
|
+
mutationFn: () => closeTicket(ticketId),
|
|
1292
|
+
onMutate: async () => {
|
|
1293
|
+
await queryClient.cancelQueries({ queryKey: ["widget-ticket", ticketId] });
|
|
1294
|
+
const previous = queryClient.getQueryData(["widget-ticket", ticketId]);
|
|
1295
|
+
if (previous) queryClient.setQueryData(["widget-ticket", ticketId], {
|
|
1296
|
+
...previous,
|
|
1297
|
+
status: "resolved"
|
|
1298
|
+
});
|
|
1299
|
+
return { previous };
|
|
1300
|
+
},
|
|
1301
|
+
onSuccess: () => {
|
|
1302
|
+
queryClient.invalidateQueries({ queryKey: ["widget-ticket", ticketId] });
|
|
1303
|
+
},
|
|
1304
|
+
onError: (_err, _vars, context) => {
|
|
1305
|
+
if (context?.previous) queryClient.setQueryData(["widget-ticket", ticketId], context.previous);
|
|
1306
|
+
}
|
|
1307
|
+
});
|
|
1077
1308
|
if (isLoading) return /* @__PURE__ */ jsx("div", {
|
|
1078
1309
|
className: "rqd-loading",
|
|
1079
1310
|
children: t("detail.loading")
|
|
@@ -1182,11 +1413,28 @@ function TicketDetailView({ ticketId, onBack }) {
|
|
|
1182
1413
|
onChange: (e) => setReplyBody(e.target.value),
|
|
1183
1414
|
placeholder: t("detail.replyPlaceholder"),
|
|
1184
1415
|
rows: 3
|
|
1185
|
-
}), /* @__PURE__ */
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1416
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
1417
|
+
style: {
|
|
1418
|
+
display: "flex",
|
|
1419
|
+
gap: 8
|
|
1420
|
+
},
|
|
1421
|
+
children: [/* @__PURE__ */ jsx("button", {
|
|
1422
|
+
className: "rqd-btn rqd-btn-primary",
|
|
1423
|
+
style: { flex: 1 },
|
|
1424
|
+
onClick: () => replyMutation.mutate(replyBody.trim()),
|
|
1425
|
+
disabled: !replyBody.trim() || replyMutation.isPending,
|
|
1426
|
+
children: replyMutation.isPending ? t("detail.sending") : t("detail.sendReply")
|
|
1427
|
+
}), ticket.status !== "resolved" && ticket.status !== "closed" && /* @__PURE__ */ jsx("button", {
|
|
1428
|
+
className: "rqd-btn rqd-btn-secondary",
|
|
1429
|
+
style: {
|
|
1430
|
+
flex: 0,
|
|
1431
|
+
whiteSpace: "nowrap",
|
|
1432
|
+
padding: "10px 16px"
|
|
1433
|
+
},
|
|
1434
|
+
onClick: () => resolveMutation.mutate(),
|
|
1435
|
+
disabled: resolveMutation.isPending,
|
|
1436
|
+
children: resolveMutation.isPending ? t("detail.resolving") : t("detail.resolve")
|
|
1437
|
+
})]
|
|
1190
1438
|
})]
|
|
1191
1439
|
})
|
|
1192
1440
|
] });
|
|
@@ -1313,7 +1561,7 @@ function FloatingWidget({ position = "bottom-right", contained = false, onTicket
|
|
|
1313
1561
|
return (translations[activeLang] ?? translations.en)[key] ?? key;
|
|
1314
1562
|
}, [activeLang, ctx.translations]);
|
|
1315
1563
|
const isRtl = activeLang === "ar";
|
|
1316
|
-
const cssVars =
|
|
1564
|
+
const cssVars = themeToStyle(activeTheme);
|
|
1317
1565
|
const posClass = `rqd-${position}`;
|
|
1318
1566
|
const containedClass = contained ? " rqd-contained" : "";
|
|
1319
1567
|
const brandName = ctx.theme?.brandName;
|
|
@@ -1555,7 +1803,7 @@ function FloatingWidget({ position = "bottom-right", contained = false, onTicket
|
|
|
1555
1803
|
const canGoBack = view !== "home";
|
|
1556
1804
|
const goBackTarget = view === "ticket-detail" ? "my-tickets" : "home";
|
|
1557
1805
|
return /* @__PURE__ */ jsx(ShadowRoot, { children: /* @__PURE__ */ jsxs("div", {
|
|
1558
|
-
style:
|
|
1806
|
+
style: cssVars,
|
|
1559
1807
|
...isRtl ? { dir: "rtl" } : {},
|
|
1560
1808
|
children: [/* @__PURE__ */ jsx("button", {
|
|
1561
1809
|
className: `rqd-fab ${posClass}${containedClass}`,
|