@reqdesk/widget 0.1.0 → 0.2.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/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/{react-D69QlAm1.d.ts → react-DYAKyC3I.d.ts} +2 -2
- package/dist/{react-D69QlAm1.d.ts.map → react-DYAKyC3I.d.ts.map} +1 -1
- package/dist/{react-8GCnIHnw.d.cts → react-PYPqwxcj.d.cts} +2 -2
- package/dist/{react-8GCnIHnw.d.cts.map → react-PYPqwxcj.d.cts.map} +1 -1
- package/dist/react.cjs +275 -36
- package/dist/react.d.cts +1 -1
- package/dist/react.d.ts +1 -1
- package/dist/react.js +275 -36
- package/dist/react.js.map +1 -1
- package/dist/{storage-Db9XjupR.cjs → storage-DqhhTxeh.cjs} +80 -3
- package/dist/{storage-CC5BCsxP.js → storage-PjDHb5v7.js} +70 -5
- package/dist/storage-PjDHb5v7.js.map +1 -0
- 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 +1 -1
- package/dist/storage-CC5BCsxP.js.map +0 -1
package/dist/react.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { _ as
|
|
1
|
+
import { C as setOidcTokenProvider, S as configureWidgetClient, _ as submitReply, a as saveTrackingToken, b as trackTicket, c as getWidgetStyles, d as en, f as closeTicket, g as resolveWidgetUser, h as listMyTickets, i as loadWidgetEmail, l as themeToVars, m as getTicketDetail, n as getTrackingTokens, o as saveWidgetConfig, p as getCategories, r as loadWidgetConfig, s as saveWidgetEmail, t as clearWidgetEmail, u as ar, v as submitTicket, x as uploadAttachment, y as submitTrackingReply } from "./storage-PjDHb5v7.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";
|
|
@@ -480,6 +480,132 @@ function SupportPortal({ className }) {
|
|
|
480
480
|
}) });
|
|
481
481
|
}
|
|
482
482
|
//#endregion
|
|
483
|
+
//#region src/react/queries.ts
|
|
484
|
+
const widgetTicketDetailOptions = (ticketId) => queryOptions({
|
|
485
|
+
queryKey: ["widget-ticket", ticketId],
|
|
486
|
+
queryFn: () => getTicketDetail(ticketId),
|
|
487
|
+
staleTime: 6e4,
|
|
488
|
+
enabled: !!ticketId
|
|
489
|
+
});
|
|
490
|
+
const widgetMyTicketsOptions = (projectId, userId) => queryOptions({
|
|
491
|
+
queryKey: [
|
|
492
|
+
"widget-tickets",
|
|
493
|
+
projectId,
|
|
494
|
+
userId
|
|
495
|
+
],
|
|
496
|
+
queryFn: () => listMyTickets(projectId, userId),
|
|
497
|
+
staleTime: 3e4,
|
|
498
|
+
placeholderData: keepPreviousData,
|
|
499
|
+
enabled: !!userId
|
|
500
|
+
});
|
|
501
|
+
const widgetUserOptions = (projectId, email) => queryOptions({
|
|
502
|
+
queryKey: [
|
|
503
|
+
"widget-user",
|
|
504
|
+
projectId,
|
|
505
|
+
email
|
|
506
|
+
],
|
|
507
|
+
queryFn: () => resolveWidgetUser(projectId, email),
|
|
508
|
+
staleTime: 5 * 6e4,
|
|
509
|
+
enabled: !!email
|
|
510
|
+
});
|
|
511
|
+
const widgetCategoriesOptions = (projectId, parentId) => queryOptions({
|
|
512
|
+
queryKey: [
|
|
513
|
+
"widget-categories",
|
|
514
|
+
projectId,
|
|
515
|
+
parentId ?? "root"
|
|
516
|
+
],
|
|
517
|
+
queryFn: () => getCategories(projectId, parentId),
|
|
518
|
+
staleTime: 5 * 6e4
|
|
519
|
+
});
|
|
520
|
+
//#endregion
|
|
521
|
+
//#region src/client-metadata.ts
|
|
522
|
+
const STORAGE_PREFIX = "reqdesk_diag_";
|
|
523
|
+
const DEFAULT_PREFS = {
|
|
524
|
+
screenResolution: false,
|
|
525
|
+
deviceType: false,
|
|
526
|
+
timezone: false,
|
|
527
|
+
referrerUrl: false,
|
|
528
|
+
language: false,
|
|
529
|
+
platform: false
|
|
530
|
+
};
|
|
531
|
+
/** Always collected — minimal, non-sensitive */
|
|
532
|
+
function collectMinimalMetadata() {
|
|
533
|
+
const meta = {};
|
|
534
|
+
try {
|
|
535
|
+
meta.pageUrl = window.location.href;
|
|
536
|
+
meta.userAgent = navigator.userAgent;
|
|
537
|
+
} catch {}
|
|
538
|
+
return meta;
|
|
539
|
+
}
|
|
540
|
+
/** Full diagnostic set — only included for opted-in fields */
|
|
541
|
+
function collectDiagnosticMetadata(prefs) {
|
|
542
|
+
const meta = {};
|
|
543
|
+
try {
|
|
544
|
+
if (prefs.screenResolution) meta.screenResolution = `${screen.width}x${screen.height}`;
|
|
545
|
+
if (prefs.deviceType) meta.deviceType = detectDeviceType();
|
|
546
|
+
if (prefs.timezone) meta.timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
547
|
+
if (prefs.referrerUrl && document.referrer) meta.referrerUrl = document.referrer;
|
|
548
|
+
if (prefs.language) meta.language = navigator.language;
|
|
549
|
+
if (prefs.platform) meta.platform = navigator.platform;
|
|
550
|
+
} catch {}
|
|
551
|
+
return meta;
|
|
552
|
+
}
|
|
553
|
+
/** Combine minimal + opted-in diagnostic metadata */
|
|
554
|
+
function collectAllMetadata(apiKey) {
|
|
555
|
+
const prefs = getMetadataPreferences(apiKey);
|
|
556
|
+
return {
|
|
557
|
+
...collectMinimalMetadata(),
|
|
558
|
+
...collectDiagnosticMetadata(prefs)
|
|
559
|
+
};
|
|
560
|
+
}
|
|
561
|
+
function getMetadataPreferences(apiKey) {
|
|
562
|
+
try {
|
|
563
|
+
const raw = localStorage.getItem(`${STORAGE_PREFIX}${apiKey}`);
|
|
564
|
+
if (raw) return {
|
|
565
|
+
...DEFAULT_PREFS,
|
|
566
|
+
...JSON.parse(raw)
|
|
567
|
+
};
|
|
568
|
+
} catch {}
|
|
569
|
+
return { ...DEFAULT_PREFS };
|
|
570
|
+
}
|
|
571
|
+
function saveMetadataPreferences(apiKey, prefs) {
|
|
572
|
+
try {
|
|
573
|
+
localStorage.setItem(`${STORAGE_PREFIX}${apiKey}`, JSON.stringify(prefs));
|
|
574
|
+
} catch {}
|
|
575
|
+
}
|
|
576
|
+
function detectDeviceType() {
|
|
577
|
+
const ua = navigator.userAgent.toLowerCase();
|
|
578
|
+
if (/tablet|ipad|playbook|silk/i.test(ua)) return "tablet";
|
|
579
|
+
if (/mobile|iphone|ipod|android.*mobile|windows phone/i.test(ua)) return "mobile";
|
|
580
|
+
return "desktop";
|
|
581
|
+
}
|
|
582
|
+
const DIAGNOSTIC_FIELDS = [
|
|
583
|
+
{
|
|
584
|
+
key: "screenResolution",
|
|
585
|
+
labelKey: "diag.screenResolution"
|
|
586
|
+
},
|
|
587
|
+
{
|
|
588
|
+
key: "deviceType",
|
|
589
|
+
labelKey: "diag.deviceType"
|
|
590
|
+
},
|
|
591
|
+
{
|
|
592
|
+
key: "timezone",
|
|
593
|
+
labelKey: "diag.timezone"
|
|
594
|
+
},
|
|
595
|
+
{
|
|
596
|
+
key: "referrerUrl",
|
|
597
|
+
labelKey: "diag.referrerUrl"
|
|
598
|
+
},
|
|
599
|
+
{
|
|
600
|
+
key: "language",
|
|
601
|
+
labelKey: "diag.language"
|
|
602
|
+
},
|
|
603
|
+
{
|
|
604
|
+
key: "platform",
|
|
605
|
+
labelKey: "diag.platform"
|
|
606
|
+
}
|
|
607
|
+
];
|
|
608
|
+
//#endregion
|
|
483
609
|
//#region src/react/views/SubmitTicketView.tsx
|
|
484
610
|
const translations$4 = {
|
|
485
611
|
en,
|
|
@@ -529,6 +655,19 @@ function SubmitTicketView({ projectId, onSuccess, onError, isAuthenticated, user
|
|
|
529
655
|
const [uploadProgress, setUploadProgress] = useState(null);
|
|
530
656
|
const [success, setSuccess] = useState(null);
|
|
531
657
|
const [rememberEmail, setRememberEmail] = useState(!!savedEmail);
|
|
658
|
+
const [categoryPath, setCategoryPath] = useState([]);
|
|
659
|
+
const [selectedCategory, setSelectedCategory] = useState(null);
|
|
660
|
+
const { data: categories = [] } = useQuery(widgetCategoriesOptions(projectId, categoryPath.length > 0 ? categoryPath[categoryPath.length - 1].id : null));
|
|
661
|
+
const [diagOpen, setDiagOpen] = useState(false);
|
|
662
|
+
const [diagPrefs, setDiagPrefs] = useState(getMetadataPreferences(ctx.apiKey));
|
|
663
|
+
const diagValues = collectDiagnosticMetadata({
|
|
664
|
+
screenResolution: true,
|
|
665
|
+
deviceType: true,
|
|
666
|
+
timezone: true,
|
|
667
|
+
referrerUrl: true,
|
|
668
|
+
language: true,
|
|
669
|
+
platform: true
|
|
670
|
+
});
|
|
532
671
|
const t = useCallback((key) => {
|
|
533
672
|
if (ctx.translations?.[key]) return ctx.translations[key];
|
|
534
673
|
return (translations$4[ctx.language] ?? translations$4.en)[key] ?? key;
|
|
@@ -615,12 +754,15 @@ function SubmitTicketView({ projectId, onSuccess, onError, isAuthenticated, user
|
|
|
615
754
|
}
|
|
616
755
|
setErrors({});
|
|
617
756
|
if (rememberEmail && email) saveWidgetEmail(ctx.apiKey, email);
|
|
757
|
+
saveMetadataPreferences(ctx.apiKey, diagPrefs);
|
|
618
758
|
const validFiles = files.filter((f) => !f.error);
|
|
619
759
|
const data = {
|
|
620
760
|
title,
|
|
621
761
|
description: formData.get("description")?.trim() || void 0,
|
|
622
762
|
email,
|
|
623
|
-
priority: formData.get("priority") ?? "medium"
|
|
763
|
+
priority: formData.get("priority") ?? "medium",
|
|
764
|
+
categoryId: selectedCategory?.id,
|
|
765
|
+
clientMetadata: collectAllMetadata(ctx.apiKey)
|
|
624
766
|
};
|
|
625
767
|
submitMutation.mutate({
|
|
626
768
|
data,
|
|
@@ -801,6 +943,97 @@ function SubmitTicketView({ projectId, onSuccess, onError, isAuthenticated, user
|
|
|
801
943
|
]
|
|
802
944
|
})]
|
|
803
945
|
}),
|
|
946
|
+
/* @__PURE__ */ jsxs("div", {
|
|
947
|
+
className: "rqd-form-group",
|
|
948
|
+
children: [/* @__PURE__ */ jsx("label", {
|
|
949
|
+
className: "rqd-label",
|
|
950
|
+
children: t("form.categorySelected")
|
|
951
|
+
}), selectedCategory ? /* @__PURE__ */ jsxs("div", {
|
|
952
|
+
className: "rqd-category-selected",
|
|
953
|
+
children: [/* @__PURE__ */ jsxs("span", { children: [
|
|
954
|
+
categoryPath.map((c) => c.name).join(" > "),
|
|
955
|
+
categoryPath.length > 0 ? " > " : "",
|
|
956
|
+
selectedCategory.name
|
|
957
|
+
] }), /* @__PURE__ */ jsx("button", {
|
|
958
|
+
type: "button",
|
|
959
|
+
onClick: () => {
|
|
960
|
+
setSelectedCategory(null);
|
|
961
|
+
setCategoryPath([]);
|
|
962
|
+
},
|
|
963
|
+
children: "×"
|
|
964
|
+
})]
|
|
965
|
+
}) : /* @__PURE__ */ jsxs(Fragment, { children: [categoryPath.length > 0 && /* @__PURE__ */ jsxs("div", {
|
|
966
|
+
className: "rqd-category-breadcrumb",
|
|
967
|
+
children: [/* @__PURE__ */ jsx("button", {
|
|
968
|
+
type: "button",
|
|
969
|
+
onClick: () => setCategoryPath([]),
|
|
970
|
+
children: t("form.categoryPlaceholder")
|
|
971
|
+
}), categoryPath.map((c, i) => /* @__PURE__ */ jsxs("span", { children: [/* @__PURE__ */ jsx("span", {
|
|
972
|
+
className: "rqd-category-breadcrumb-sep",
|
|
973
|
+
children: "›"
|
|
974
|
+
}), /* @__PURE__ */ jsx("button", {
|
|
975
|
+
type: "button",
|
|
976
|
+
onClick: () => setCategoryPath((prev) => prev.slice(0, i + 1)),
|
|
977
|
+
children: c.name
|
|
978
|
+
})] }, c.id))]
|
|
979
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
980
|
+
className: "rqd-category-list",
|
|
981
|
+
children: [categories.map((cat) => /* @__PURE__ */ jsxs("button", {
|
|
982
|
+
type: "button",
|
|
983
|
+
className: "rqd-category-item",
|
|
984
|
+
onClick: () => {
|
|
985
|
+
if (cat.hasChildren) setCategoryPath((prev) => [...prev, cat]);
|
|
986
|
+
else setSelectedCategory(cat);
|
|
987
|
+
},
|
|
988
|
+
children: [cat.name, cat.hasChildren && /* @__PURE__ */ jsx("span", {
|
|
989
|
+
className: "rqd-category-item-chevron",
|
|
990
|
+
children: "›"
|
|
991
|
+
})]
|
|
992
|
+
}, cat.id)), categories.length === 0 && categoryPath.length === 0 && /* @__PURE__ */ jsx("span", {
|
|
993
|
+
style: {
|
|
994
|
+
fontSize: 13,
|
|
995
|
+
color: "var(--rqd-text-secondary)"
|
|
996
|
+
},
|
|
997
|
+
children: t("form.categoryPlaceholder")
|
|
998
|
+
})]
|
|
999
|
+
})] })]
|
|
1000
|
+
}),
|
|
1001
|
+
/* @__PURE__ */ jsxs("div", {
|
|
1002
|
+
className: "rqd-form-group",
|
|
1003
|
+
children: [/* @__PURE__ */ jsxs("button", {
|
|
1004
|
+
type: "button",
|
|
1005
|
+
className: "rqd-diag-toggle",
|
|
1006
|
+
onClick: () => setDiagOpen((prev) => !prev),
|
|
1007
|
+
children: [/* @__PURE__ */ jsx("span", { children: t("diag.title") }), /* @__PURE__ */ jsx("span", { children: diagOpen ? "▲" : "▼" })]
|
|
1008
|
+
}), diagOpen && /* @__PURE__ */ jsxs("div", {
|
|
1009
|
+
className: "rqd-diag-panel",
|
|
1010
|
+
children: [/* @__PURE__ */ jsx("p", {
|
|
1011
|
+
style: {
|
|
1012
|
+
fontSize: 12,
|
|
1013
|
+
color: "var(--rqd-text-secondary)",
|
|
1014
|
+
margin: "0 0 6px"
|
|
1015
|
+
},
|
|
1016
|
+
children: t("diag.hint")
|
|
1017
|
+
}), DIAGNOSTIC_FIELDS.map((field) => /* @__PURE__ */ jsxs("label", {
|
|
1018
|
+
className: "rqd-diag-item",
|
|
1019
|
+
children: [
|
|
1020
|
+
/* @__PURE__ */ jsx("input", {
|
|
1021
|
+
type: "checkbox",
|
|
1022
|
+
checked: diagPrefs[field.key],
|
|
1023
|
+
onChange: (e) => setDiagPrefs((prev) => ({
|
|
1024
|
+
...prev,
|
|
1025
|
+
[field.key]: e.target.checked
|
|
1026
|
+
}))
|
|
1027
|
+
}),
|
|
1028
|
+
/* @__PURE__ */ jsx("span", { children: t(field.labelKey) }),
|
|
1029
|
+
/* @__PURE__ */ jsx("span", {
|
|
1030
|
+
className: "rqd-diag-item-value",
|
|
1031
|
+
children: diagValues[field.key] ?? "—"
|
|
1032
|
+
})
|
|
1033
|
+
]
|
|
1034
|
+
}, field.key))]
|
|
1035
|
+
})]
|
|
1036
|
+
}),
|
|
804
1037
|
/* @__PURE__ */ jsxs("div", {
|
|
805
1038
|
className: "rqd-form-group",
|
|
806
1039
|
children: [
|
|
@@ -864,35 +1097,6 @@ function SubmitTicketView({ projectId, onSuccess, onError, isAuthenticated, user
|
|
|
864
1097
|
});
|
|
865
1098
|
}
|
|
866
1099
|
//#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
1100
|
//#region src/react/views/MyTicketsView.tsx
|
|
897
1101
|
const translations$3 = {
|
|
898
1102
|
en,
|
|
@@ -1074,6 +1278,24 @@ function TicketDetailView({ ticketId, onBack }) {
|
|
|
1074
1278
|
if (context?.previous) queryClient.setQueryData(["widget-ticket", ticketId], context.previous);
|
|
1075
1279
|
}
|
|
1076
1280
|
});
|
|
1281
|
+
const resolveMutation = useMutation({
|
|
1282
|
+
mutationFn: () => closeTicket(ticketId),
|
|
1283
|
+
onMutate: async () => {
|
|
1284
|
+
await queryClient.cancelQueries({ queryKey: ["widget-ticket", ticketId] });
|
|
1285
|
+
const previous = queryClient.getQueryData(["widget-ticket", ticketId]);
|
|
1286
|
+
if (previous) queryClient.setQueryData(["widget-ticket", ticketId], {
|
|
1287
|
+
...previous,
|
|
1288
|
+
status: "resolved"
|
|
1289
|
+
});
|
|
1290
|
+
return { previous };
|
|
1291
|
+
},
|
|
1292
|
+
onSuccess: () => {
|
|
1293
|
+
queryClient.invalidateQueries({ queryKey: ["widget-ticket", ticketId] });
|
|
1294
|
+
},
|
|
1295
|
+
onError: (_err, _vars, context) => {
|
|
1296
|
+
if (context?.previous) queryClient.setQueryData(["widget-ticket", ticketId], context.previous);
|
|
1297
|
+
}
|
|
1298
|
+
});
|
|
1077
1299
|
if (isLoading) return /* @__PURE__ */ jsx("div", {
|
|
1078
1300
|
className: "rqd-loading",
|
|
1079
1301
|
children: t("detail.loading")
|
|
@@ -1182,11 +1404,28 @@ function TicketDetailView({ ticketId, onBack }) {
|
|
|
1182
1404
|
onChange: (e) => setReplyBody(e.target.value),
|
|
1183
1405
|
placeholder: t("detail.replyPlaceholder"),
|
|
1184
1406
|
rows: 3
|
|
1185
|
-
}), /* @__PURE__ */
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1407
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
1408
|
+
style: {
|
|
1409
|
+
display: "flex",
|
|
1410
|
+
gap: 8
|
|
1411
|
+
},
|
|
1412
|
+
children: [/* @__PURE__ */ jsx("button", {
|
|
1413
|
+
className: "rqd-btn rqd-btn-primary",
|
|
1414
|
+
style: { flex: 1 },
|
|
1415
|
+
onClick: () => replyMutation.mutate(replyBody.trim()),
|
|
1416
|
+
disabled: !replyBody.trim() || replyMutation.isPending,
|
|
1417
|
+
children: replyMutation.isPending ? t("detail.sending") : t("detail.sendReply")
|
|
1418
|
+
}), ticket.status !== "resolved" && ticket.status !== "closed" && /* @__PURE__ */ jsx("button", {
|
|
1419
|
+
className: "rqd-btn rqd-btn-secondary",
|
|
1420
|
+
style: {
|
|
1421
|
+
flex: 0,
|
|
1422
|
+
whiteSpace: "nowrap",
|
|
1423
|
+
padding: "10px 16px"
|
|
1424
|
+
},
|
|
1425
|
+
onClick: () => resolveMutation.mutate(),
|
|
1426
|
+
disabled: resolveMutation.isPending,
|
|
1427
|
+
children: resolveMutation.isPending ? t("detail.resolving") : t("detail.resolve")
|
|
1428
|
+
})]
|
|
1190
1429
|
})]
|
|
1191
1430
|
})
|
|
1192
1431
|
] });
|