@youidian/sdk 3.3.7 → 3.4.1
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/client.cjs +400 -36
- package/dist/client.cjs.map +1 -1
- package/dist/client.d.cts +41 -5
- package/dist/client.d.ts +41 -5
- package/dist/client.js +399 -36
- package/dist/client.js.map +1 -1
- package/dist/feedback.cjs +682 -0
- package/dist/feedback.cjs.map +1 -0
- package/dist/feedback.d.cts +38 -0
- package/dist/feedback.d.ts +38 -0
- package/dist/feedback.js +656 -0
- package/dist/feedback.js.map +1 -0
- package/dist/index.cjs +1164 -36
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -3
- package/dist/index.d.ts +4 -3
- package/dist/index.js +1161 -36
- package/dist/index.js.map +1 -1
- package/dist/{login-DerOcXcH.d.cts → login-Dqemys65.d.cts} +8 -4
- package/dist/{login-DerOcXcH.d.ts → login-Dqemys65.d.ts} +8 -4
- package/dist/login.cjs +320 -30
- package/dist/login.cjs.map +1 -1
- package/dist/login.d.cts +1 -1
- package/dist/login.d.ts +1 -1
- package/dist/login.js +320 -30
- package/dist/login.js.map +1 -1
- package/dist/server.cjs +108 -0
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts +137 -1
- package/dist/server.d.ts +137 -1
- package/dist/server.js +108 -0
- package/dist/server.js.map +1 -1
- package/package.json +6 -1
package/dist/index.cjs
CHANGED
|
@@ -35,10 +35,13 @@ __export(src_exports, {
|
|
|
35
35
|
LoginUI: () => LoginUI,
|
|
36
36
|
PaymentClient: () => PaymentClient,
|
|
37
37
|
PaymentUI: () => PaymentUI,
|
|
38
|
+
createFeedbackWidget: () => createFeedbackWidget,
|
|
38
39
|
createLoginUI: () => createLoginUI,
|
|
39
40
|
createPaymentUI: () => createPaymentUI,
|
|
41
|
+
detectLoginEnvironment: () => detectLoginEnvironment,
|
|
40
42
|
getCustomAmountRechargeRule: () => getCustomAmountRechargeRule,
|
|
41
43
|
handleLoginCallbackIfPresent: () => handleLoginCallbackIfPresent,
|
|
44
|
+
mountFeedbackWidget: () => mountFeedbackWidget,
|
|
42
45
|
validateCustomAmountRecharge: () => validateCustomAmountRecharge
|
|
43
46
|
});
|
|
44
47
|
module.exports = __toCommonJS(src_exports);
|
|
@@ -245,6 +248,91 @@ var HostedFrameModal = class {
|
|
|
245
248
|
}
|
|
246
249
|
};
|
|
247
250
|
|
|
251
|
+
// src/environment.ts
|
|
252
|
+
function normalizeText(value) {
|
|
253
|
+
return value || "";
|
|
254
|
+
}
|
|
255
|
+
function getRuntimeInput() {
|
|
256
|
+
if (typeof navigator === "undefined") {
|
|
257
|
+
return {};
|
|
258
|
+
}
|
|
259
|
+
const nav = navigator;
|
|
260
|
+
const coarsePointer = typeof window !== "undefined" && typeof window.matchMedia === "function" ? window.matchMedia("(pointer: coarse)").matches : void 0;
|
|
261
|
+
return {
|
|
262
|
+
coarsePointer,
|
|
263
|
+
maxTouchPoints: nav.maxTouchPoints || 0,
|
|
264
|
+
platform: nav.platform || "",
|
|
265
|
+
standalone: nav.standalone,
|
|
266
|
+
userAgent: nav.userAgent || "",
|
|
267
|
+
userAgentDataMobile: nav.userAgentData?.mobile
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
function includesAny(value, patterns) {
|
|
271
|
+
return patterns.some((pattern) => pattern.test(value));
|
|
272
|
+
}
|
|
273
|
+
function detectLoginEnvironment(input = getRuntimeInput()) {
|
|
274
|
+
const userAgent = normalizeText(input.userAgent);
|
|
275
|
+
const platform = normalizeText(input.platform);
|
|
276
|
+
const rawMaxTouchPoints = input.maxTouchPoints ?? 0;
|
|
277
|
+
const maxTouchPoints = Number.isFinite(rawMaxTouchPoints) ? Math.max(0, rawMaxTouchPoints) : 0;
|
|
278
|
+
const isCoarsePointer = input.coarsePointer === true;
|
|
279
|
+
const isTouch = maxTouchPoints > 0 || isCoarsePointer;
|
|
280
|
+
const isWeChat = /micromessenger/i.test(userAgent);
|
|
281
|
+
const isAndroid = /\bandroid\b/i.test(userAgent);
|
|
282
|
+
const hasExplicitIOSDevice = /\b(iPad|iPhone|iPod)\b/i.test(userAgent);
|
|
283
|
+
const hasMacintoshUserAgent = /\bMacintosh\b/i.test(userAgent);
|
|
284
|
+
const hasMacPlatform = /^Mac/i.test(platform);
|
|
285
|
+
const isIPadOS = !hasExplicitIOSDevice && hasMacintoshUserAgent && hasMacPlatform && typeof input.standalone !== "undefined" && maxTouchPoints > 2;
|
|
286
|
+
const isIOS = hasExplicitIOSDevice || isIPadOS;
|
|
287
|
+
const isTabletByUa = includesAny(userAgent, [
|
|
288
|
+
/\biPad\b/i,
|
|
289
|
+
/\btablet\b/i,
|
|
290
|
+
/\bplaybook\b/i,
|
|
291
|
+
/\bsilk\b(?!.*\bmobile\b)/i,
|
|
292
|
+
/\bkindle\b/i,
|
|
293
|
+
/\bnexus 7\b/i,
|
|
294
|
+
/\bnexus 9\b/i,
|
|
295
|
+
/\bxoom\b/i,
|
|
296
|
+
/\bsm-t\d+/i,
|
|
297
|
+
/\bgt-p\d+/i,
|
|
298
|
+
/\bmi pad\b/i
|
|
299
|
+
]);
|
|
300
|
+
const isMobileByUa = includesAny(userAgent, [
|
|
301
|
+
/\bMobile\b/i,
|
|
302
|
+
/\biPhone\b/i,
|
|
303
|
+
/\biPod\b/i,
|
|
304
|
+
/\bWindows Phone\b/i,
|
|
305
|
+
/\bIEMobile\b/i,
|
|
306
|
+
/\bBlackBerry\b/i,
|
|
307
|
+
/\bBB10\b/i,
|
|
308
|
+
/\bOpera Mini\b/i,
|
|
309
|
+
/\bOpera Mobi\b/i,
|
|
310
|
+
/\bwebOS\b/i
|
|
311
|
+
]);
|
|
312
|
+
const isAndroidTablet = isAndroid && !/\bMobile\b/i.test(userAgent);
|
|
313
|
+
const isTablet = isIPadOS || isTabletByUa || isAndroidTablet;
|
|
314
|
+
const isMobile = input.userAgentDataMobile === true || isMobileByUa || isAndroid && !isTablet || isIOS && !isTablet;
|
|
315
|
+
const deviceType = isTablet ? "tablet" : isMobile ? "mobile" : userAgent || platform || isTouch ? "desktop" : "unknown";
|
|
316
|
+
const shouldUseRedirectLogin = deviceType === "mobile" || deviceType === "tablet" || isWeChat;
|
|
317
|
+
return {
|
|
318
|
+
deviceType,
|
|
319
|
+
isAndroid,
|
|
320
|
+
isCoarsePointer,
|
|
321
|
+
isDesktop: deviceType === "desktop",
|
|
322
|
+
isIOS,
|
|
323
|
+
isIPadOS,
|
|
324
|
+
isMobile,
|
|
325
|
+
isStandalone: input.standalone === true,
|
|
326
|
+
isTablet,
|
|
327
|
+
isTouch,
|
|
328
|
+
isWeChat,
|
|
329
|
+
maxTouchPoints,
|
|
330
|
+
platform,
|
|
331
|
+
shouldUseRedirectLogin,
|
|
332
|
+
userAgent
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
|
|
248
336
|
// src/login.ts
|
|
249
337
|
function getOrigin(value) {
|
|
250
338
|
if (!value) return null;
|
|
@@ -254,6 +342,15 @@ function getOrigin(value) {
|
|
|
254
342
|
return null;
|
|
255
343
|
}
|
|
256
344
|
}
|
|
345
|
+
function isValidLoginRedirectUrl(value) {
|
|
346
|
+
if (!value) return false;
|
|
347
|
+
try {
|
|
348
|
+
const url = new URL(value);
|
|
349
|
+
return url.protocol === "https:" || url.protocol === "http:";
|
|
350
|
+
} catch {
|
|
351
|
+
return false;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
257
354
|
function createLoginCallbackState() {
|
|
258
355
|
if (typeof crypto !== "undefined" && crypto.randomUUID) {
|
|
259
356
|
return crypto.randomUUID().replace(/-/g, "");
|
|
@@ -600,6 +697,24 @@ function applyLoginPanelStyle(panel) {
|
|
|
600
697
|
backdropFilter: "blur(16px)"
|
|
601
698
|
});
|
|
602
699
|
}
|
|
700
|
+
function applyLoginLoadingPanelStyle(panel) {
|
|
701
|
+
Object.assign(panel.style, {
|
|
702
|
+
position: "absolute",
|
|
703
|
+
inset: "0",
|
|
704
|
+
display: "flex",
|
|
705
|
+
alignItems: "center",
|
|
706
|
+
justifyContent: "center",
|
|
707
|
+
border: "0",
|
|
708
|
+
borderRadius: "28px",
|
|
709
|
+
background: "rgba(255,255,255,0.94)",
|
|
710
|
+
color: "#0f172a",
|
|
711
|
+
padding: "24px",
|
|
712
|
+
textAlign: "center",
|
|
713
|
+
zIndex: "1",
|
|
714
|
+
boxShadow: "none",
|
|
715
|
+
backdropFilter: "blur(16px)"
|
|
716
|
+
});
|
|
717
|
+
}
|
|
603
718
|
function createLoginPanelContent() {
|
|
604
719
|
const content = document.createElement("div");
|
|
605
720
|
Object.assign(content.style, {
|
|
@@ -624,6 +739,71 @@ function createLoginPanelContent() {
|
|
|
624
739
|
content.appendChild(badge);
|
|
625
740
|
return content;
|
|
626
741
|
}
|
|
742
|
+
function createBrandLoadingMark() {
|
|
743
|
+
const logo = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
744
|
+
logo.setAttribute("viewBox", "0 0 1024 1024");
|
|
745
|
+
logo.setAttribute("fill", "none");
|
|
746
|
+
logo.setAttribute("aria-hidden", "true");
|
|
747
|
+
Object.assign(logo.style, {
|
|
748
|
+
width: "112px",
|
|
749
|
+
height: "112px",
|
|
750
|
+
color: "#22c55e",
|
|
751
|
+
display: "block",
|
|
752
|
+
overflow: "visible"
|
|
753
|
+
});
|
|
754
|
+
const group = document.createElementNS("http://www.w3.org/2000/svg", "g");
|
|
755
|
+
group.setAttribute("fill", "currentColor");
|
|
756
|
+
const ring = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
757
|
+
ring.setAttribute(
|
|
758
|
+
"d",
|
|
759
|
+
"M704.298 679.54A264 264 0 1 1 704.298 309.46A49 49 0 0 1 634.4 378.149A166 166 0 1 0 634.4 610.851A49 49 0 0 1 704.298 679.54Z"
|
|
760
|
+
);
|
|
761
|
+
ring.setAttribute("class", "youidian-sdk-brand-loading__ring");
|
|
762
|
+
const dot = document.createElementNS("http://www.w3.org/2000/svg", "circle");
|
|
763
|
+
dot.setAttribute("class", "youidian-sdk-brand-loading__dot");
|
|
764
|
+
dot.setAttribute("cx", "714.5");
|
|
765
|
+
dot.setAttribute("cy", "490.5");
|
|
766
|
+
dot.setAttribute("r", "68");
|
|
767
|
+
group.appendChild(ring);
|
|
768
|
+
group.appendChild(dot);
|
|
769
|
+
logo.appendChild(group);
|
|
770
|
+
return logo;
|
|
771
|
+
}
|
|
772
|
+
function createBrandLoadingCopy() {
|
|
773
|
+
const brand = document.createElement("div");
|
|
774
|
+
brand.className = "youidian-sdk-brand-loading__copy";
|
|
775
|
+
Object.assign(brand.style, {
|
|
776
|
+
display: "flex",
|
|
777
|
+
flexDirection: "column",
|
|
778
|
+
alignItems: "flex-start",
|
|
779
|
+
justifyContent: "center",
|
|
780
|
+
lineHeight: "1"
|
|
781
|
+
});
|
|
782
|
+
const name = document.createElement("div");
|
|
783
|
+
name.className = "youidian-sdk-brand-loading__name";
|
|
784
|
+
name.textContent = "\u4F18\u6613\u70B9";
|
|
785
|
+
Object.assign(name.style, {
|
|
786
|
+
color: "#0f172a",
|
|
787
|
+
fontSize: "34px",
|
|
788
|
+
fontWeight: "900",
|
|
789
|
+
letterSpacing: "0",
|
|
790
|
+
lineHeight: "1"
|
|
791
|
+
});
|
|
792
|
+
const tagline = document.createElement("div");
|
|
793
|
+
tagline.className = "youidian-sdk-brand-loading__tagline";
|
|
794
|
+
tagline.textContent = "\u5F00\u53D1\u8005\u670D\u52A1\u4E2D\u53F0";
|
|
795
|
+
Object.assign(tagline.style, {
|
|
796
|
+
color: "#64748b",
|
|
797
|
+
fontSize: "16px",
|
|
798
|
+
fontWeight: "700",
|
|
799
|
+
letterSpacing: "0.24em",
|
|
800
|
+
lineHeight: "1",
|
|
801
|
+
marginTop: "6px"
|
|
802
|
+
});
|
|
803
|
+
brand.appendChild(name);
|
|
804
|
+
brand.appendChild(tagline);
|
|
805
|
+
return brand;
|
|
806
|
+
}
|
|
627
807
|
function createLoginPanelTitle(value) {
|
|
628
808
|
const title = document.createElement("div");
|
|
629
809
|
title.textContent = value;
|
|
@@ -653,32 +833,111 @@ function ensureLoginLoadingStyles() {
|
|
|
653
833
|
}
|
|
654
834
|
const style = document.createElement("style");
|
|
655
835
|
style.id = "youidian-login-loading-style";
|
|
656
|
-
style.textContent =
|
|
836
|
+
style.textContent = `
|
|
837
|
+
.youidian-sdk-brand-loading__ring,
|
|
838
|
+
.youidian-sdk-brand-loading__dot {
|
|
839
|
+
transform-box: fill-box;
|
|
840
|
+
transform-origin: center;
|
|
841
|
+
will-change: opacity, transform;
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
.youidian-sdk-brand-loading__ring {
|
|
845
|
+
animation: youidian-sdk-brand-loading-ring 1400ms cubic-bezier(0.4, 0, 0.2, 1) infinite;
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
.youidian-sdk-brand-loading__dot {
|
|
849
|
+
animation: youidian-sdk-brand-loading-dot 1400ms cubic-bezier(0.4, 0, 0.2, 1) infinite;
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
.youidian-sdk-brand-loading__copy {
|
|
853
|
+
will-change: opacity, transform;
|
|
854
|
+
animation: youidian-sdk-brand-loading-copy 1600ms cubic-bezier(0.4, 0, 0.2, 1) infinite;
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
.youidian-sdk-brand-loading__tagline {
|
|
858
|
+
will-change: opacity;
|
|
859
|
+
animation: youidian-sdk-brand-loading-tagline 1600ms cubic-bezier(0.4, 0, 0.2, 1) infinite;
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
@keyframes youidian-sdk-brand-loading-ring {
|
|
863
|
+
0%,
|
|
864
|
+
100% {
|
|
865
|
+
opacity: 0.72;
|
|
866
|
+
transform: rotate(0deg) scale(0.98);
|
|
867
|
+
}
|
|
868
|
+
50% {
|
|
869
|
+
opacity: 1;
|
|
870
|
+
transform: rotate(8deg) scale(1.02);
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
@keyframes youidian-sdk-brand-loading-dot {
|
|
875
|
+
0%,
|
|
876
|
+
100% {
|
|
877
|
+
opacity: 0.55;
|
|
878
|
+
transform: scale(0.9);
|
|
879
|
+
}
|
|
880
|
+
50% {
|
|
881
|
+
opacity: 1;
|
|
882
|
+
transform: scale(1.08);
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
@keyframes youidian-sdk-brand-loading-copy {
|
|
887
|
+
0%,
|
|
888
|
+
100% {
|
|
889
|
+
opacity: 0.86;
|
|
890
|
+
transform: translateY(0);
|
|
891
|
+
}
|
|
892
|
+
50% {
|
|
893
|
+
opacity: 1;
|
|
894
|
+
transform: translateY(-1px);
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
@keyframes youidian-sdk-brand-loading-tagline {
|
|
899
|
+
0%,
|
|
900
|
+
100% {
|
|
901
|
+
opacity: 0.64;
|
|
902
|
+
}
|
|
903
|
+
50% {
|
|
904
|
+
opacity: 0.92;
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
@media (prefers-reduced-motion: reduce) {
|
|
909
|
+
.youidian-sdk-brand-loading__ring,
|
|
910
|
+
.youidian-sdk-brand-loading__dot,
|
|
911
|
+
.youidian-sdk-brand-loading__copy,
|
|
912
|
+
.youidian-sdk-brand-loading__tagline {
|
|
913
|
+
animation: none;
|
|
914
|
+
opacity: 1;
|
|
915
|
+
transform: none;
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
`;
|
|
657
919
|
document.head.appendChild(style);
|
|
658
920
|
}
|
|
659
|
-
function createLoginLoadingPanel(
|
|
921
|
+
function createLoginLoadingPanel() {
|
|
660
922
|
ensureLoginLoadingStyles();
|
|
661
923
|
const panel = document.createElement("div");
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
margin: "0 auto 18px",
|
|
672
|
-
animation: "youidian-login-spin 780ms linear infinite"
|
|
924
|
+
applyLoginLoadingPanelStyle(panel);
|
|
925
|
+
panel.setAttribute("role", "status");
|
|
926
|
+
panel.setAttribute("aria-label", "\u4F18\u6613\u70B9\u5F00\u53D1\u8005\u670D\u52A1\u4E2D\u53F0");
|
|
927
|
+
const content = document.createElement("div");
|
|
928
|
+
Object.assign(content.style, {
|
|
929
|
+
display: "flex",
|
|
930
|
+
alignItems: "center",
|
|
931
|
+
justifyContent: "center",
|
|
932
|
+
gap: "12px"
|
|
673
933
|
});
|
|
674
|
-
content.appendChild(
|
|
675
|
-
content.appendChild(
|
|
676
|
-
content.appendChild(createLoginPanelDescription(options.description));
|
|
934
|
+
content.appendChild(createBrandLoadingMark());
|
|
935
|
+
content.appendChild(createBrandLoadingCopy());
|
|
677
936
|
panel.appendChild(content);
|
|
678
937
|
return panel;
|
|
679
938
|
}
|
|
680
|
-
function createLoginRedirectingPanel(
|
|
681
|
-
return createLoginLoadingPanel(
|
|
939
|
+
function createLoginRedirectingPanel(_options) {
|
|
940
|
+
return createLoginLoadingPanel();
|
|
682
941
|
}
|
|
683
942
|
function createLoginFallbackPanel(options) {
|
|
684
943
|
const panel = document.createElement("div");
|
|
@@ -778,14 +1037,11 @@ var LoginUI = class extends HostedFrameModal {
|
|
|
778
1037
|
this.iframeFallbackPanel = null;
|
|
779
1038
|
this.iframeLoadingPanel = null;
|
|
780
1039
|
}
|
|
781
|
-
showIframeLoading(container
|
|
1040
|
+
showIframeLoading(container) {
|
|
782
1041
|
if (this.iframeLoadingPanel || this.iframeReady) {
|
|
783
1042
|
return;
|
|
784
1043
|
}
|
|
785
|
-
const panel = createLoginLoadingPanel(
|
|
786
|
-
description: options?.loadingDescription || "Please wait while the secure login page opens.",
|
|
787
|
-
title: options?.loadingTitle || "Opening login page"
|
|
788
|
-
});
|
|
1044
|
+
const panel = createLoginLoadingPanel();
|
|
789
1045
|
this.iframeLoadingPanel = panel;
|
|
790
1046
|
container.appendChild(panel);
|
|
791
1047
|
}
|
|
@@ -873,6 +1129,20 @@ var LoginUI = class extends HostedFrameModal {
|
|
|
873
1129
|
break;
|
|
874
1130
|
case "LOGIN_RESIZE":
|
|
875
1131
|
break;
|
|
1132
|
+
case "LOGIN_REDIRECT_REQUIRED":
|
|
1133
|
+
if (!isValidLoginRedirectUrl(data.authUrl)) {
|
|
1134
|
+
logLoginWarn("Login redirect requested with invalid authUrl");
|
|
1135
|
+
options?.onError?.("Login redirect URL is invalid", data);
|
|
1136
|
+
break;
|
|
1137
|
+
}
|
|
1138
|
+
logLoginInfo("Login redirect requested by hosted page", {
|
|
1139
|
+
attemptId: data.attemptId || null,
|
|
1140
|
+
channel: data.channel || null,
|
|
1141
|
+
authUrl: data.authUrl
|
|
1142
|
+
});
|
|
1143
|
+
this.close();
|
|
1144
|
+
window.location.assign(data.authUrl);
|
|
1145
|
+
break;
|
|
876
1146
|
case "LOGIN_ERROR":
|
|
877
1147
|
if (this.completed) {
|
|
878
1148
|
break;
|
|
@@ -896,6 +1166,25 @@ var LoginUI = class extends HostedFrameModal {
|
|
|
896
1166
|
break;
|
|
897
1167
|
}
|
|
898
1168
|
}
|
|
1169
|
+
openLoginRedirect(params, options) {
|
|
1170
|
+
if (typeof window === "undefined") return;
|
|
1171
|
+
const { callbackState, finalUrl, launchPayload } = this.buildOpenContext(
|
|
1172
|
+
params,
|
|
1173
|
+
options
|
|
1174
|
+
);
|
|
1175
|
+
logLoginInfo("Redirecting to hosted login page", {
|
|
1176
|
+
appId: params.appId,
|
|
1177
|
+
callbackState,
|
|
1178
|
+
callbackUrl: launchPayload.callbackUrl || null,
|
|
1179
|
+
hasCallbackUrl: Boolean(launchPayload.callbackUrl),
|
|
1180
|
+
loginUrl: finalUrl,
|
|
1181
|
+
autoClose: options?.autoClose ?? true,
|
|
1182
|
+
displayMode: "redirect",
|
|
1183
|
+
pageUrl: window.location.href,
|
|
1184
|
+
parentOrigin: launchPayload.origin || null
|
|
1185
|
+
});
|
|
1186
|
+
window.location.assign(finalUrl);
|
|
1187
|
+
}
|
|
899
1188
|
listenForLoginCallback(callbackState, options) {
|
|
900
1189
|
try {
|
|
901
1190
|
this.callbackChannel = new BroadcastChannel(
|
|
@@ -972,21 +1261,17 @@ var LoginUI = class extends HostedFrameModal {
|
|
|
972
1261
|
options?.onCancel?.();
|
|
973
1262
|
options?.onClose?.();
|
|
974
1263
|
},
|
|
975
|
-
onMessage: (data,
|
|
1264
|
+
onMessage: (data, _container, event) => {
|
|
976
1265
|
const isIframeEvent = event.source === this.iframe?.contentWindow;
|
|
977
1266
|
if (isIframeEvent && (data.type === "LOGIN_READY" || data.type === "LOGIN_RESIZE") || data.type === "LOGIN_SUCCESS" || data.type === "LOGIN_ERROR") {
|
|
978
1267
|
this.markIframeReady();
|
|
979
1268
|
}
|
|
980
|
-
if (data.type === "LOGIN_RESIZE" && data.height) {
|
|
981
|
-
const maxHeight = window.innerHeight * 0.94;
|
|
982
|
-
container.style.height = `${Math.min(data.height, maxHeight)}px`;
|
|
983
|
-
}
|
|
984
1269
|
this.handleLoginEvent(data, options);
|
|
985
1270
|
},
|
|
986
1271
|
width: "min(520px, 100%)"
|
|
987
1272
|
});
|
|
988
1273
|
if (hostedFrame) {
|
|
989
|
-
this.showIframeLoading(hostedFrame.container
|
|
1274
|
+
this.showIframeLoading(hostedFrame.container);
|
|
990
1275
|
this.startIframeWatchdog({
|
|
991
1276
|
container: hostedFrame.container,
|
|
992
1277
|
finalUrl,
|
|
@@ -1090,11 +1375,19 @@ var LoginUI = class extends HostedFrameModal {
|
|
|
1090
1375
|
}
|
|
1091
1376
|
openLogin(params, options) {
|
|
1092
1377
|
if (typeof window === "undefined") return;
|
|
1093
|
-
const displayMode = options?.displayMode ?? "
|
|
1378
|
+
const displayMode = options?.displayMode ?? "auto";
|
|
1379
|
+
if (displayMode === "redirect") {
|
|
1380
|
+
this.openLoginRedirect(params, options);
|
|
1381
|
+
return;
|
|
1382
|
+
}
|
|
1094
1383
|
if (displayMode === "popup") {
|
|
1095
1384
|
this.openLoginPopup(params, options);
|
|
1096
1385
|
return;
|
|
1097
1386
|
}
|
|
1387
|
+
if (displayMode === "auto" && detectLoginEnvironment().shouldUseRedirectLogin) {
|
|
1388
|
+
this.openLoginRedirect(params, options);
|
|
1389
|
+
return;
|
|
1390
|
+
}
|
|
1098
1391
|
this.openLoginModal(params, options);
|
|
1099
1392
|
}
|
|
1100
1393
|
};
|
|
@@ -1105,6 +1398,43 @@ handleLoginCallbackIfPresent({ autoClose: false });
|
|
|
1105
1398
|
|
|
1106
1399
|
// src/client.ts
|
|
1107
1400
|
var PaymentUI = class extends HostedFrameModal {
|
|
1401
|
+
constructor() {
|
|
1402
|
+
super(...arguments);
|
|
1403
|
+
__publicField(this, "activeCheckoutAppId", null);
|
|
1404
|
+
__publicField(this, "activeCheckoutBaseUrl", null);
|
|
1405
|
+
__publicField(this, "activeOrderId", null);
|
|
1406
|
+
__publicField(this, "paymentCompleted", false);
|
|
1407
|
+
__publicField(this, "cancelRequestedOrderId", null);
|
|
1408
|
+
}
|
|
1409
|
+
cancelHostedOrder(reason = "user_cancel", orderId) {
|
|
1410
|
+
const targetOrderId = orderId || this.activeOrderId;
|
|
1411
|
+
if (!targetOrderId || !this.activeCheckoutAppId || !this.activeCheckoutBaseUrl || this.paymentCompleted || this.cancelRequestedOrderId === targetOrderId) {
|
|
1412
|
+
return;
|
|
1413
|
+
}
|
|
1414
|
+
this.cancelRequestedOrderId = targetOrderId;
|
|
1415
|
+
const url = `${this.activeCheckoutBaseUrl}/api/internal/checkout/cancel-order`;
|
|
1416
|
+
const payload = JSON.stringify({
|
|
1417
|
+
appId: this.activeCheckoutAppId,
|
|
1418
|
+
orderId: targetOrderId,
|
|
1419
|
+
reason
|
|
1420
|
+
});
|
|
1421
|
+
if (typeof navigator !== "undefined" && navigator.sendBeacon) {
|
|
1422
|
+
const sent = navigator.sendBeacon(
|
|
1423
|
+
url,
|
|
1424
|
+
new Blob([payload], { type: "application/json" })
|
|
1425
|
+
);
|
|
1426
|
+
if (sent) return;
|
|
1427
|
+
}
|
|
1428
|
+
void fetch(url, {
|
|
1429
|
+
method: "POST",
|
|
1430
|
+
body: payload,
|
|
1431
|
+
headers: { "Content-Type": "text/plain;charset=UTF-8" },
|
|
1432
|
+
keepalive: true,
|
|
1433
|
+
mode: "no-cors"
|
|
1434
|
+
}).catch(() => {
|
|
1435
|
+
this.cancelRequestedOrderId = null;
|
|
1436
|
+
});
|
|
1437
|
+
}
|
|
1108
1438
|
/**
|
|
1109
1439
|
* Opens the payment checkout page in an iframe modal.
|
|
1110
1440
|
* @param urlOrParams - The checkout page URL or payment parameters
|
|
@@ -1114,11 +1444,25 @@ var PaymentUI = class extends HostedFrameModal {
|
|
|
1114
1444
|
if (typeof document === "undefined") return;
|
|
1115
1445
|
if (this.modal) return;
|
|
1116
1446
|
let checkoutUrl;
|
|
1447
|
+
this.activeOrderId = null;
|
|
1448
|
+
this.paymentCompleted = false;
|
|
1449
|
+
this.cancelRequestedOrderId = null;
|
|
1117
1450
|
if (typeof urlOrParams === "string") {
|
|
1118
1451
|
checkoutUrl = urlOrParams;
|
|
1452
|
+
try {
|
|
1453
|
+
const parsedUrl = new URL(checkoutUrl);
|
|
1454
|
+
this.activeCheckoutBaseUrl = parsedUrl.origin;
|
|
1455
|
+
const parts = parsedUrl.pathname.split("/").filter(Boolean);
|
|
1456
|
+
const checkoutIndex = parts.indexOf("checkout");
|
|
1457
|
+
this.activeCheckoutAppId = checkoutIndex >= 0 ? parts[checkoutIndex + 1] || null : null;
|
|
1458
|
+
} catch {
|
|
1459
|
+
this.activeCheckoutAppId = null;
|
|
1460
|
+
this.activeCheckoutBaseUrl = null;
|
|
1461
|
+
}
|
|
1119
1462
|
} else {
|
|
1120
1463
|
const {
|
|
1121
1464
|
appId,
|
|
1465
|
+
orderId,
|
|
1122
1466
|
productId,
|
|
1123
1467
|
priceId,
|
|
1124
1468
|
productCode,
|
|
@@ -1128,9 +1472,10 @@ var PaymentUI = class extends HostedFrameModal {
|
|
|
1128
1472
|
baseUrl = "https://pay.imgto.link"
|
|
1129
1473
|
} = urlOrParams;
|
|
1130
1474
|
const base = (checkoutUrlParam || baseUrl).replace(/\/$/, "");
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1475
|
+
this.activeCheckoutAppId = appId;
|
|
1476
|
+
this.activeCheckoutBaseUrl = base;
|
|
1477
|
+
const query = new URLSearchParams();
|
|
1478
|
+
if (userId) query.set("userId", userId);
|
|
1134
1479
|
if (customAmount) {
|
|
1135
1480
|
const amount = Number(customAmount.amount);
|
|
1136
1481
|
const currency = customAmount.currency.trim().toUpperCase();
|
|
@@ -1147,13 +1492,22 @@ var PaymentUI = class extends HostedFrameModal {
|
|
|
1147
1492
|
query.set("customAmount", String(amount));
|
|
1148
1493
|
query.set("customCurrency", currency);
|
|
1149
1494
|
}
|
|
1150
|
-
if (
|
|
1495
|
+
if (orderId) {
|
|
1496
|
+
const cleanOrderId = orderId.trim();
|
|
1497
|
+
if (!cleanOrderId) {
|
|
1498
|
+
throw new Error("orderId is required");
|
|
1499
|
+
}
|
|
1500
|
+
this.activeOrderId = cleanOrderId;
|
|
1501
|
+
checkoutUrl = `${base}/checkout/${appId}/orders/${cleanOrderId}`;
|
|
1502
|
+
const queryString = query.toString();
|
|
1503
|
+
if (queryString) checkoutUrl += `?${queryString}`;
|
|
1504
|
+
} else if (productCode) {
|
|
1151
1505
|
checkoutUrl = `${base}/checkout/${appId}/code/${productCode}?${query.toString()}`;
|
|
1152
1506
|
} else if (productId && priceId) {
|
|
1153
1507
|
checkoutUrl = `${base}/checkout/${appId}/${productId}/${priceId}?${query.toString()}`;
|
|
1154
1508
|
} else {
|
|
1155
1509
|
throw new Error(
|
|
1156
|
-
"Either productCode or both productId and priceId are required"
|
|
1510
|
+
"Either orderId, productCode, or both productId and priceId are required"
|
|
1157
1511
|
);
|
|
1158
1512
|
}
|
|
1159
1513
|
}
|
|
@@ -1163,13 +1517,23 @@ var PaymentUI = class extends HostedFrameModal {
|
|
|
1163
1517
|
);
|
|
1164
1518
|
this.openHostedFrame(finalUrl, {
|
|
1165
1519
|
allowedOrigin: options?.allowedOrigin,
|
|
1166
|
-
onCloseButton: () =>
|
|
1520
|
+
onCloseButton: () => {
|
|
1521
|
+
this.cancelHostedOrder("modal_close");
|
|
1522
|
+
options?.onCancel?.(this.activeOrderId || void 0);
|
|
1523
|
+
},
|
|
1167
1524
|
onMessage: (data, container) => {
|
|
1168
1525
|
switch (data.type) {
|
|
1526
|
+
case "PAYMENT_STARTED":
|
|
1527
|
+
if (data.orderId) {
|
|
1528
|
+
this.activeOrderId = data.orderId;
|
|
1529
|
+
}
|
|
1530
|
+
break;
|
|
1169
1531
|
case "PAYMENT_SUCCESS":
|
|
1532
|
+
this.paymentCompleted = true;
|
|
1170
1533
|
options?.onSuccess?.(data.orderId);
|
|
1171
1534
|
break;
|
|
1172
1535
|
case "PAYMENT_CANCELLED":
|
|
1536
|
+
this.cancelHostedOrder("payment_cancelled", data.orderId);
|
|
1173
1537
|
options?.onCancel?.(data.orderId);
|
|
1174
1538
|
break;
|
|
1175
1539
|
case "PAYMENT_RESIZE":
|
|
@@ -1180,6 +1544,7 @@ var PaymentUI = class extends HostedFrameModal {
|
|
|
1180
1544
|
}
|
|
1181
1545
|
break;
|
|
1182
1546
|
case "PAYMENT_CLOSE":
|
|
1547
|
+
this.cancelHostedOrder("payment_close", data.orderId);
|
|
1183
1548
|
this.close();
|
|
1184
1549
|
options?.onClose?.();
|
|
1185
1550
|
break;
|
|
@@ -1235,6 +1600,658 @@ function createPaymentUI() {
|
|
|
1235
1600
|
return new PaymentUI();
|
|
1236
1601
|
}
|
|
1237
1602
|
|
|
1603
|
+
// src/feedback.ts
|
|
1604
|
+
var DEFAULT_CATEGORIES = [
|
|
1605
|
+
{ value: "BUG", label: "\u95EE\u9898\u53CD\u9988" },
|
|
1606
|
+
{ value: "PAYMENT", label: "\u652F\u4ED8\u95EE\u9898" },
|
|
1607
|
+
{ value: "LOGIN", label: "\u767B\u5F55\u95EE\u9898" },
|
|
1608
|
+
{ value: "SUGGESTION", label: "\u529F\u80FD\u5EFA\u8BAE" },
|
|
1609
|
+
{ value: "OTHER", label: "\u5176\u4ED6" }
|
|
1610
|
+
];
|
|
1611
|
+
var STYLE_ID = "youidian-feedback-widget-style";
|
|
1612
|
+
var MAX_IMAGES_PER_MESSAGE = 4;
|
|
1613
|
+
var DEFAULT_PANEL_TITLE = "\u53CD\u9988";
|
|
1614
|
+
var DEFAULT_PANEL_SUBTITLE = "\u63D0\u4EA4\u95EE\u9898\u3001\u5EFA\u8BAE\u6216\u4F7F\u7528\u53CD\u9988\u3002";
|
|
1615
|
+
var DEFAULT_ATTACHMENTS_LABEL = "\u652F\u6301\u7C98\u8D34\u3001\u62D6\u5165\u6216\u4E0A\u4F20\u622A\u56FE\uFF0C\u6700\u591A 4 \u5F20";
|
|
1616
|
+
var FEEDBACK_ICON = `<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M21 11.5a8.4 8.4 0 0 1-.9 3.8 8.6 8.6 0 0 1-7.7 4.7 8.5 8.5 0 0 1-3.8-.9L3 21l1.9-5.2a8.5 8.5 0 0 1-1-4.1 8.6 8.6 0 0 1 8.6-8.6 8.5 8.5 0 0 1 8.5 8.4Z" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"/><path d="M8.4 10.2h7.2M8.4 13.5h4.7" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round"/></svg>`;
|
|
1617
|
+
var BUG_ICON = `<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M8 8.5a4 4 0 0 1 8 0v6a4 4 0 0 1-8 0v-6Z" fill="none" stroke="currentColor" stroke-width="1.8"/><path d="M5 9h3m8 0h3M5.5 15H8m8 0h2.5M7 5.5 5.5 4M17 5.5 18.5 4M12 4.5V2.8M12 20.5v-12" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/></svg>`;
|
|
1618
|
+
var NOTE_ICON = `<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M7 3.5h7l3.5 3.5v13.5H7A2.5 2.5 0 0 1 4.5 18V6A2.5 2.5 0 0 1 7 3.5Z" fill="none" stroke="currentColor" stroke-width="1.8"/><path d="M14 3.8V7h3.2M8 11h8M8 15h6" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/></svg>`;
|
|
1619
|
+
var MAIL_ICON = `<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M4.5 6.5h15v11h-15v-11Z" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linejoin="round"/><path d="m5 7 7 6 7-6" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg>`;
|
|
1620
|
+
var IMAGE_ICON = `<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M5 5h14v14H5V5Z" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linejoin="round"/><path d="m7.5 16 3.2-3.2 2.4 2.4 1.7-1.7L18 16.8" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/><path d="M15.8 8.2h.01" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round"/></svg>`;
|
|
1621
|
+
var CHEVRON_ICON = `<svg viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>`;
|
|
1622
|
+
function ensureStyle() {
|
|
1623
|
+
if (typeof document === "undefined") return;
|
|
1624
|
+
if (document.getElementById(STYLE_ID)) return;
|
|
1625
|
+
const style = document.createElement("style");
|
|
1626
|
+
style.id = STYLE_ID;
|
|
1627
|
+
style.textContent = `
|
|
1628
|
+
.yd-feedback-root,.yd-feedback-root *{box-sizing:border-box}
|
|
1629
|
+
.yd-feedback-root{--yd-feedback-bg:hsl(var(--background,0 0% 100%));--yd-feedback-fg:hsl(var(--foreground,240 10% 3.9%));--yd-feedback-card:hsl(var(--card,0 0% 100%));--yd-feedback-card-fg:hsl(var(--card-foreground,240 10% 3.9%));--yd-feedback-muted:hsl(var(--muted,240 4.8% 95.9%));--yd-feedback-muted-fg:hsl(var(--muted-foreground,240 3.8% 46.1%));--yd-feedback-border:hsl(var(--border,240 5.9% 90%));--yd-feedback-primary:hsl(var(--primary,142 76% 36%));--yd-feedback-primary-fg:hsl(var(--primary-foreground,0 0% 100%));--yd-feedback-ring:hsl(var(--ring,142 76% 36%));font:14px/1.5 Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;color:var(--yd-feedback-fg)}
|
|
1630
|
+
.yd-feedback-root button,.yd-feedback-root input,.yd-feedback-root textarea{font:inherit}
|
|
1631
|
+
.yd-feedback-launcher{position:fixed;right:22px;bottom:22px;z-index:2147483000;width:54px;height:54px;display:grid;place-items:center;border:1px solid color-mix(in srgb,var(--yd-feedback-primary) 24%,var(--yd-feedback-border));border-radius:999px;background:var(--yd-feedback-primary);color:var(--yd-feedback-primary-fg);box-shadow:0 18px 45px color-mix(in srgb,var(--yd-feedback-primary) 22%,transparent);cursor:pointer;transition:transform .18s ease,box-shadow .18s ease,background .18s ease}
|
|
1632
|
+
.yd-feedback-launcher:hover{transform:translateY(-2px);box-shadow:0 22px 56px color-mix(in srgb,var(--yd-feedback-primary) 30%,transparent)}
|
|
1633
|
+
.yd-feedback-launcher:focus-visible{outline:3px solid color-mix(in srgb,var(--yd-feedback-ring) 32%,transparent);outline-offset:3px}
|
|
1634
|
+
.yd-feedback-launcher svg{width:27px;height:27px}
|
|
1635
|
+
.yd-feedback-panel{position:fixed;inset:auto 22px 86px auto;z-index:2147483000;width:min(760px,calc(100vw - 44px));height:min(560px,calc(100vh - 108px));display:none;grid-template-rows:auto minmax(0,1fr);overflow:hidden;border:1px solid var(--yd-feedback-border);border-radius:18px;background:var(--yd-feedback-card);color:var(--yd-feedback-card-fg);box-shadow:0 24px 70px rgba(15,23,42,.18)}
|
|
1636
|
+
.yd-feedback-panel[data-open="true"]{display:grid}
|
|
1637
|
+
.yd-feedback-header{display:flex;align-items:flex-start;justify-content:space-between;gap:16px;padding:18px 20px 16px;border-bottom:1px solid var(--yd-feedback-border);background:var(--yd-feedback-card)}
|
|
1638
|
+
.yd-feedback-title{margin:0;font-size:22px;line-height:1.15;font-weight:760;letter-spacing:0;color:var(--yd-feedback-fg)}
|
|
1639
|
+
.yd-feedback-subtitle{margin:8px 0 0;color:var(--yd-feedback-muted-fg);font-size:13px;line-height:1.45}
|
|
1640
|
+
.yd-feedback-close{display:grid;place-items:center;width:34px;height:34px;border:0;border-radius:10px;background:transparent;color:var(--yd-feedback-muted-fg);cursor:pointer;transition:background .16s ease,color .16s ease}
|
|
1641
|
+
.yd-feedback-close:hover{background:var(--yd-feedback-muted);color:var(--yd-feedback-fg)}
|
|
1642
|
+
.yd-feedback-close svg{width:24px;height:24px}
|
|
1643
|
+
.yd-feedback-shell{display:grid;min-height:0;grid-template-columns:230px minmax(0,1fr)}
|
|
1644
|
+
.yd-feedback-sidebar{min-width:0;border-right:1px solid var(--yd-feedback-border);background:var(--yd-feedback-muted)}
|
|
1645
|
+
.yd-feedback-sidebar-toolbar{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:14px 14px;border-bottom:1px solid var(--yd-feedback-border)}
|
|
1646
|
+
.yd-feedback-sidebar-title{display:flex;align-items:center;gap:9px;color:var(--yd-feedback-fg);font-size:15px;font-weight:720}
|
|
1647
|
+
.yd-feedback-sidebar-title svg{width:20px;height:20px;color:var(--yd-feedback-primary)}
|
|
1648
|
+
.yd-feedback-icon-button{display:grid;place-items:center;width:34px;height:34px;border:1px solid var(--yd-feedback-border);border-radius:999px;background:var(--yd-feedback-card);color:var(--yd-feedback-fg);cursor:pointer;transition:background .16s ease,border-color .16s ease}
|
|
1649
|
+
.yd-feedback-icon-button:hover{background:color-mix(in srgb,var(--yd-feedback-primary) 8%,var(--yd-feedback-card));border-color:color-mix(in srgb,var(--yd-feedback-primary) 38%,var(--yd-feedback-border))}
|
|
1650
|
+
.yd-feedback-icon-button svg{width:18px;height:18px}
|
|
1651
|
+
.yd-feedback-thread-list{padding:12px}
|
|
1652
|
+
.yd-feedback-thread-card{display:none;border:1px solid var(--yd-feedback-border);border-radius:14px;background:var(--yd-feedback-card);padding:12px}
|
|
1653
|
+
.yd-feedback-thread-card[data-visible="true"]{display:block}
|
|
1654
|
+
.yd-feedback-thread-badges{display:flex;flex-wrap:wrap;gap:7px;margin-bottom:10px}
|
|
1655
|
+
.yd-feedback-badge{display:inline-flex;align-items:center;border:1px solid var(--yd-feedback-border);border-radius:999px;background:var(--yd-feedback-muted);color:var(--yd-feedback-fg);padding:4px 9px;font-size:11px;font-weight:700;line-height:1}
|
|
1656
|
+
.yd-feedback-badge[data-status="true"]{border-color:color-mix(in srgb,var(--yd-feedback-primary) 45%,var(--yd-feedback-border));background:color-mix(in srgb,var(--yd-feedback-primary) 12%,var(--yd-feedback-card));color:var(--yd-feedback-primary)}
|
|
1657
|
+
.yd-feedback-thread-preview{margin:0;color:var(--yd-feedback-fg);font-size:13px;line-height:1.45;word-break:break-word}
|
|
1658
|
+
.yd-feedback-thread-meta{display:flex;justify-content:space-between;gap:10px;margin-top:10px;color:var(--yd-feedback-muted-fg);font-size:11px}
|
|
1659
|
+
.yd-feedback-empty-thread{border:1px dashed var(--yd-feedback-border);border-radius:14px;padding:14px;color:var(--yd-feedback-muted-fg);font-size:12px}
|
|
1660
|
+
.yd-feedback-main{min-width:0;min-height:0;background:var(--yd-feedback-card);overflow:hidden}
|
|
1661
|
+
.yd-feedback-form{height:100%;display:grid;grid-template-rows:auto auto auto minmax(0,1fr) auto auto;gap:14px;padding:16px 18px 0}
|
|
1662
|
+
.yd-feedback-row{display:grid;gap:14px;grid-template-columns:180px minmax(0,1fr)}
|
|
1663
|
+
.yd-feedback-field{display:flex;min-width:0;flex-direction:column;gap:8px}
|
|
1664
|
+
.yd-feedback-label{display:flex;align-items:center;gap:8px;color:var(--yd-feedback-fg);font-size:13px;font-weight:720}
|
|
1665
|
+
.yd-feedback-label svg{width:17px;height:17px;color:var(--yd-feedback-fg)}
|
|
1666
|
+
.yd-feedback-input,.yd-feedback-textarea{width:100%;border:1px solid var(--yd-feedback-border);border-radius:13px;background:var(--yd-feedback-card);color:var(--yd-feedback-fg);outline:none;transition:border-color .16s ease,box-shadow .16s ease,background .16s ease}
|
|
1667
|
+
.yd-feedback-input{height:40px;padding:0 13px;font-size:14px}
|
|
1668
|
+
.yd-feedback-textarea{min-height:118px;padding:13px 14px;font-size:14px;resize:none}
|
|
1669
|
+
.yd-feedback-input::placeholder,.yd-feedback-textarea::placeholder{color:var(--yd-feedback-muted-fg)}
|
|
1670
|
+
.yd-feedback-input:focus,.yd-feedback-textarea:focus{border-color:var(--yd-feedback-ring);box-shadow:0 0 0 3px color-mix(in srgb,var(--yd-feedback-ring) 18%,transparent);background:var(--yd-feedback-card)}
|
|
1671
|
+
.yd-feedback-compose-box{overflow:hidden;border:1px solid var(--yd-feedback-border);border-radius:15px;background:var(--yd-feedback-card)}
|
|
1672
|
+
.yd-feedback-compose-box .yd-feedback-textarea{border:0;border-radius:0;box-shadow:none;background:transparent}
|
|
1673
|
+
.yd-feedback-attachment-row{display:flex;align-items:center;justify-content:space-between;gap:12px;border-top:1px solid var(--yd-feedback-border);padding:9px 12px;color:var(--yd-feedback-muted-fg)}
|
|
1674
|
+
.yd-feedback-file-trigger{display:inline-flex;align-items:center;gap:8px;border:0;background:transparent;color:var(--yd-feedback-fg);cursor:pointer;padding:7px 8px;border-radius:10px}
|
|
1675
|
+
.yd-feedback-file-trigger:hover{background:var(--yd-feedback-muted)}
|
|
1676
|
+
.yd-feedback-file-trigger svg{width:18px;height:18px}
|
|
1677
|
+
.yd-feedback-file-input{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;clip-path:inset(50%)}
|
|
1678
|
+
.yd-feedback-files{min-width:0;text-align:right;color:var(--yd-feedback-muted-fg);font-size:12px}
|
|
1679
|
+
.yd-feedback-select{position:relative;width:142px}
|
|
1680
|
+
.yd-feedback-select-button{width:100%;height:40px;display:flex;align-items:center;justify-content:space-between;gap:10px;border:1px solid var(--yd-feedback-border);border-radius:13px;background:var(--yd-feedback-card);color:var(--yd-feedback-fg);padding:0 12px;cursor:pointer}
|
|
1681
|
+
.yd-feedback-select-value{display:flex;align-items:center;gap:8px;font-size:14px;font-weight:700}
|
|
1682
|
+
.yd-feedback-select-value svg{width:18px;height:18px;color:var(--yd-feedback-muted-fg)}
|
|
1683
|
+
.yd-feedback-select-chevron{width:17px;height:17px;color:var(--yd-feedback-muted-fg)}
|
|
1684
|
+
.yd-feedback-select-menu{position:absolute;left:0;top:calc(100% + 7px);z-index:2;display:none;min-width:176px;max-height:220px;overflow:auto;border:1px solid var(--yd-feedback-border);border-radius:13px;background:var(--yd-feedback-card);box-shadow:0 18px 45px rgba(15,23,42,.16);padding:5px}
|
|
1685
|
+
.yd-feedback-select[data-open="true"] .yd-feedback-select-menu{display:block}
|
|
1686
|
+
.yd-feedback-select-option{width:100%;min-height:38px;display:flex;align-items:center;gap:8px;border:0;border-radius:10px;background:transparent;color:var(--yd-feedback-fg);text-align:left;padding:9px 10px;cursor:pointer}
|
|
1687
|
+
.yd-feedback-select-option svg{width:18px;height:18px;flex:0 0 18px;color:var(--yd-feedback-muted-fg)}
|
|
1688
|
+
.yd-feedback-select-option span{line-height:1.2;white-space:nowrap}
|
|
1689
|
+
.yd-feedback-select-option:hover,.yd-feedback-select-option[data-selected="true"]{background:color-mix(in srgb,var(--yd-feedback-primary) 10%,var(--yd-feedback-card));color:var(--yd-feedback-fg)}
|
|
1690
|
+
.yd-feedback-messages{display:flex;min-height:0;flex-direction:column;gap:8px;overflow:auto}
|
|
1691
|
+
.yd-feedback-message{border:1px solid var(--yd-feedback-border);border-radius:12px;padding:9px 10px;background:var(--yd-feedback-muted)}
|
|
1692
|
+
.yd-feedback-message[data-admin="true"]{background:color-mix(in srgb,var(--yd-feedback-primary) 10%,var(--yd-feedback-card));border-color:color-mix(in srgb,var(--yd-feedback-primary) 24%,var(--yd-feedback-border))}
|
|
1693
|
+
.yd-feedback-message-meta{margin-bottom:4px;color:var(--yd-feedback-muted-fg);font-size:11px}
|
|
1694
|
+
.yd-feedback-message-content{color:var(--yd-feedback-fg);font-size:12px;line-height:1.45;word-break:break-word}
|
|
1695
|
+
.yd-feedback-actions{position:sticky;bottom:0;display:flex;align-items:center;justify-content:flex-end;gap:12px;margin:0 -18px;padding:12px 18px 16px;border-top:1px solid var(--yd-feedback-border);background:var(--yd-feedback-card)}
|
|
1696
|
+
.yd-feedback-submit{min-width:104px;height:44px;border:0;border-radius:13px;background:var(--yd-feedback-primary);color:var(--yd-feedback-primary-fg);padding:0 18px;font-size:14px;font-weight:800;cursor:pointer;box-shadow:0 12px 24px color-mix(in srgb,var(--yd-feedback-primary) 18%,transparent);transition:background .16s ease,transform .16s ease}
|
|
1697
|
+
.yd-feedback-submit:hover{transform:translateY(-1px)}
|
|
1698
|
+
.yd-feedback-submit:disabled{opacity:.55;cursor:not-allowed;transform:none}
|
|
1699
|
+
.yd-feedback-secondary{height:38px;border:0;border-radius:12px;background:transparent;color:var(--yd-feedback-fg);padding:0 12px;font-size:14px;font-weight:760;cursor:pointer}
|
|
1700
|
+
.yd-feedback-secondary:hover{background:var(--yd-feedback-muted)}
|
|
1701
|
+
.yd-feedback-error{min-height:18px;color:#fb7185;font-size:13px}
|
|
1702
|
+
@media (max-width:760px){
|
|
1703
|
+
.yd-feedback-panel{inset:auto 14px 78px 14px;width:auto;height:min(560px,calc(100vh - 96px));border-radius:16px}
|
|
1704
|
+
.yd-feedback-header{padding:16px 16px 14px}
|
|
1705
|
+
.yd-feedback-title{font-size:20px}
|
|
1706
|
+
.yd-feedback-shell{grid-template-columns:1fr}
|
|
1707
|
+
.yd-feedback-sidebar{display:none}
|
|
1708
|
+
.yd-feedback-form{padding:14px 14px 0;gap:12px}
|
|
1709
|
+
.yd-feedback-row{grid-template-columns:1fr}
|
|
1710
|
+
.yd-feedback-actions{justify-content:space-between}
|
|
1711
|
+
}
|
|
1712
|
+
`;
|
|
1713
|
+
document.head.appendChild(style);
|
|
1714
|
+
}
|
|
1715
|
+
function getBaseUrl(options) {
|
|
1716
|
+
return (options.apiBaseUrl || "https://pay.imgto.link").replace(/\/$/, "");
|
|
1717
|
+
}
|
|
1718
|
+
function safeJson(value) {
|
|
1719
|
+
try {
|
|
1720
|
+
return JSON.stringify(value);
|
|
1721
|
+
} catch {
|
|
1722
|
+
return "{}";
|
|
1723
|
+
}
|
|
1724
|
+
}
|
|
1725
|
+
function escapeHtml(value) {
|
|
1726
|
+
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
1727
|
+
}
|
|
1728
|
+
function getInitialContact(actor) {
|
|
1729
|
+
return actor?.contactEmail || actor?.contactPhone || "";
|
|
1730
|
+
}
|
|
1731
|
+
function formatCategoryLabel(value, categories = DEFAULT_CATEGORIES) {
|
|
1732
|
+
const matched = categories.find((item) => item.value === value);
|
|
1733
|
+
return matched?.label || value || DEFAULT_CATEGORIES[0]?.label || "\u53CD\u9988";
|
|
1734
|
+
}
|
|
1735
|
+
function formatThreadStatus(value) {
|
|
1736
|
+
const statusMap = {
|
|
1737
|
+
OPEN: "\u5DF2\u63D0\u4EA4",
|
|
1738
|
+
WAITING_ADMIN: "\u7B49\u5F85\u56DE\u590D",
|
|
1739
|
+
WAITING_USER: "\u5F85\u8865\u5145",
|
|
1740
|
+
RESOLVED: "\u5DF2\u5904\u7406",
|
|
1741
|
+
CLOSED: "\u5DF2\u5173\u95ED"
|
|
1742
|
+
};
|
|
1743
|
+
return statusMap[value || ""] || value || "\u5DF2\u63D0\u4EA4";
|
|
1744
|
+
}
|
|
1745
|
+
function formatSenderType(value) {
|
|
1746
|
+
if (value === "END_USER") return "\u7528\u6237";
|
|
1747
|
+
if (value === "ADMIN") return "\u7BA1\u7406\u5458";
|
|
1748
|
+
return "\u7CFB\u7EDF";
|
|
1749
|
+
}
|
|
1750
|
+
function formatThreadTime(value) {
|
|
1751
|
+
if (!value) return "";
|
|
1752
|
+
return new Date(value).toLocaleString();
|
|
1753
|
+
}
|
|
1754
|
+
async function requestJson(url, init) {
|
|
1755
|
+
const response = await fetch(url, {
|
|
1756
|
+
...init,
|
|
1757
|
+
headers: {
|
|
1758
|
+
Accept: "application/json",
|
|
1759
|
+
...init?.body ? { "Content-Type": "application/json" } : {},
|
|
1760
|
+
...init?.headers || {}
|
|
1761
|
+
}
|
|
1762
|
+
});
|
|
1763
|
+
const payload = await response.json().catch(() => null);
|
|
1764
|
+
if (!response.ok || payload?.code !== 200) {
|
|
1765
|
+
throw new Error(payload?.message || response.statusText || "Request failed");
|
|
1766
|
+
}
|
|
1767
|
+
return payload.data;
|
|
1768
|
+
}
|
|
1769
|
+
function collectMetadata(options) {
|
|
1770
|
+
const page = typeof window === "undefined" ? {} : {
|
|
1771
|
+
pageUrl: window.location.href,
|
|
1772
|
+
pageTitle: document.title,
|
|
1773
|
+
userAgent: navigator.userAgent
|
|
1774
|
+
};
|
|
1775
|
+
return { ...page, ...options.metadata || {} };
|
|
1776
|
+
}
|
|
1777
|
+
async function compressImage(file) {
|
|
1778
|
+
if (typeof document === "undefined" || !file.type.startsWith("image/")) {
|
|
1779
|
+
return file;
|
|
1780
|
+
}
|
|
1781
|
+
const bitmap = await createImageBitmap(file);
|
|
1782
|
+
const maxSize = 1600;
|
|
1783
|
+
const scale = Math.min(1, maxSize / Math.max(bitmap.width, bitmap.height));
|
|
1784
|
+
const canvas = document.createElement("canvas");
|
|
1785
|
+
canvas.width = Math.max(1, Math.round(bitmap.width * scale));
|
|
1786
|
+
canvas.height = Math.max(1, Math.round(bitmap.height * scale));
|
|
1787
|
+
const ctx = canvas.getContext("2d");
|
|
1788
|
+
if (!ctx) return file;
|
|
1789
|
+
ctx.drawImage(bitmap, 0, 0, canvas.width, canvas.height);
|
|
1790
|
+
const blob = await new Promise((resolve) => {
|
|
1791
|
+
canvas.toBlob(resolve, "image/webp", 0.82);
|
|
1792
|
+
});
|
|
1793
|
+
if (!blob) return file;
|
|
1794
|
+
return new File([blob], file.name.replace(/\.[^.]+$/, ".webp"), {
|
|
1795
|
+
type: "image/webp",
|
|
1796
|
+
lastModified: Date.now()
|
|
1797
|
+
});
|
|
1798
|
+
}
|
|
1799
|
+
function createFeedbackWidget(container, options) {
|
|
1800
|
+
if (typeof document === "undefined") {
|
|
1801
|
+
return { open() {
|
|
1802
|
+
}, close() {
|
|
1803
|
+
}, destroy() {
|
|
1804
|
+
} };
|
|
1805
|
+
}
|
|
1806
|
+
if (!options.appId) throw new Error("appId is required");
|
|
1807
|
+
ensureStyle();
|
|
1808
|
+
let threadState = null;
|
|
1809
|
+
let pollTimer = null;
|
|
1810
|
+
let panelReady = false;
|
|
1811
|
+
let pendingFiles = [];
|
|
1812
|
+
let renderedMessages = [];
|
|
1813
|
+
let removeLoadListener = null;
|
|
1814
|
+
const root = document.createElement("div");
|
|
1815
|
+
root.className = "yd-feedback-root";
|
|
1816
|
+
const launcher = document.createElement("button");
|
|
1817
|
+
launcher.type = "button";
|
|
1818
|
+
launcher.className = "yd-feedback-launcher";
|
|
1819
|
+
launcher.setAttribute("aria-label", options.launcherText || "\u53CD\u9988");
|
|
1820
|
+
launcher.innerHTML = FEEDBACK_ICON;
|
|
1821
|
+
root.appendChild(launcher);
|
|
1822
|
+
container.appendChild(root);
|
|
1823
|
+
const panel = document.createElement("section");
|
|
1824
|
+
panel.className = "yd-feedback-panel";
|
|
1825
|
+
panel.setAttribute("aria-label", options.panelTitle || DEFAULT_PANEL_TITLE);
|
|
1826
|
+
panel.innerHTML = `
|
|
1827
|
+
<div class="yd-feedback-header">
|
|
1828
|
+
<div>
|
|
1829
|
+
<h2 class="yd-feedback-title">${escapeHtml(options.panelTitle || DEFAULT_PANEL_TITLE)}</h2>
|
|
1830
|
+
<p class="yd-feedback-subtitle">${escapeHtml(options.panelSubtitle || DEFAULT_PANEL_SUBTITLE)}</p>
|
|
1831
|
+
</div>
|
|
1832
|
+
<button type="button" class="yd-feedback-close" aria-label="\u5173\u95ED">
|
|
1833
|
+
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M6 6l12 12M18 6 6 18" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round"/></svg>
|
|
1834
|
+
</button>
|
|
1835
|
+
</div>
|
|
1836
|
+
<div class="yd-feedback-shell">
|
|
1837
|
+
<aside class="yd-feedback-sidebar">
|
|
1838
|
+
<div class="yd-feedback-sidebar-toolbar">
|
|
1839
|
+
<div class="yd-feedback-sidebar-title">${FEEDBACK_ICON}<span>\u53CD\u9988\u8BB0\u5F55</span></div>
|
|
1840
|
+
<button type="button" class="yd-feedback-icon-button" data-role="clear" aria-label="\u65B0\u5EFA\u53CD\u9988">
|
|
1841
|
+
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 5v14M5 12h14" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round"/></svg>
|
|
1842
|
+
</button>
|
|
1843
|
+
</div>
|
|
1844
|
+
<div class="yd-feedback-thread-list">
|
|
1845
|
+
<div class="yd-feedback-thread-card" data-role="thread-card">
|
|
1846
|
+
<div class="yd-feedback-thread-badges">
|
|
1847
|
+
<span class="yd-feedback-badge" data-role="thread-category">\u95EE\u9898\u53CD\u9988</span>
|
|
1848
|
+
<span class="yd-feedback-badge" data-status="true" data-role="thread-status">\u5DF2\u63D0\u4EA4</span>
|
|
1849
|
+
</div>
|
|
1850
|
+
<p class="yd-feedback-thread-preview" data-role="thread-preview"></p>
|
|
1851
|
+
<div class="yd-feedback-thread-meta">
|
|
1852
|
+
<span data-role="thread-time"></span>
|
|
1853
|
+
<span>\u6211\u7684\u53CD\u9988</span>
|
|
1854
|
+
</div>
|
|
1855
|
+
</div>
|
|
1856
|
+
<div class="yd-feedback-empty-thread" data-role="thread-empty">\u63D0\u4EA4\u53CD\u9988\u540E\uFF0C\u8BB0\u5F55\u4F1A\u663E\u793A\u5728\u8FD9\u91CC\u3002</div>
|
|
1857
|
+
</div>
|
|
1858
|
+
</aside>
|
|
1859
|
+
<div class="yd-feedback-main">
|
|
1860
|
+
<div class="yd-feedback-form">
|
|
1861
|
+
<div class="yd-feedback-row">
|
|
1862
|
+
<div class="yd-feedback-field">
|
|
1863
|
+
<label class="yd-feedback-label">\u53CD\u9988\u7C7B\u578B</label>
|
|
1864
|
+
<div class="yd-feedback-select" data-role="category-select">
|
|
1865
|
+
<button type="button" class="yd-feedback-select-button" data-role="category-trigger">
|
|
1866
|
+
<span class="yd-feedback-select-value">${BUG_ICON}<span data-role="category-value">\u95EE\u9898\u53CD\u9988</span></span>
|
|
1867
|
+
<span class="yd-feedback-select-chevron">${CHEVRON_ICON}</span>
|
|
1868
|
+
</button>
|
|
1869
|
+
<div class="yd-feedback-select-menu" data-role="category-menu"></div>
|
|
1870
|
+
</div>
|
|
1871
|
+
</div>
|
|
1872
|
+
</div>
|
|
1873
|
+
<div class="yd-feedback-field">
|
|
1874
|
+
<label class="yd-feedback-label">${NOTE_ICON}<span>\u53CD\u9988\u5185\u5BB9</span></label>
|
|
1875
|
+
<div class="yd-feedback-compose-box">
|
|
1876
|
+
<textarea class="yd-feedback-textarea" data-role="content" placeholder="${escapeHtml(options.placeholder || "\u8BF7\u63CF\u8FF0\u95EE\u9898\u73B0\u8C61\u3001\u64CD\u4F5C\u6B65\u9AA4\u6216\u5EFA\u8BAE\u5185\u5BB9\u3002")}"></textarea>
|
|
1877
|
+
<div class="yd-feedback-attachment-row">
|
|
1878
|
+
<button type="button" class="yd-feedback-file-trigger" data-role="files-trigger">${IMAGE_ICON}<span>\u4E0A\u4F20\u56FE\u7247</span></button>
|
|
1879
|
+
<input class="yd-feedback-file-input" type="file" accept="image/png,image/jpeg,image/webp" multiple data-role="files" />
|
|
1880
|
+
<div class="yd-feedback-files" data-role="files-label">${DEFAULT_ATTACHMENTS_LABEL}</div>
|
|
1881
|
+
</div>
|
|
1882
|
+
</div>
|
|
1883
|
+
</div>
|
|
1884
|
+
<div class="yd-feedback-field">
|
|
1885
|
+
<label class="yd-feedback-label">${MAIL_ICON}<span>\u8054\u7CFB\u65B9\u5F0F\uFF08\u9009\u586B\uFF09</span></label>
|
|
1886
|
+
<input class="yd-feedback-input" data-role="contact" value="${escapeHtml(getInitialContact(options.actor))}" placeholder="${escapeHtml(options.contactPlaceholder || "\u90AE\u7BB1\u6216\u7535\u8BDD\u53F7\u7801\uFF0C\u4EC5\u7528\u4E8E\u53CD\u9988\u8DDF\u8FDB")}" />
|
|
1887
|
+
</div>
|
|
1888
|
+
<div class="yd-feedback-messages" data-role="messages"></div>
|
|
1889
|
+
<div class="yd-feedback-error" data-role="error"></div>
|
|
1890
|
+
<div class="yd-feedback-actions">
|
|
1891
|
+
<button type="button" class="yd-feedback-secondary" data-role="clear-secondary">\u5173\u95ED</button>
|
|
1892
|
+
<button type="button" class="yd-feedback-submit" data-role="submit">\u63D0\u4EA4\u53CD\u9988</button>
|
|
1893
|
+
</div>
|
|
1894
|
+
</div>
|
|
1895
|
+
</div>
|
|
1896
|
+
</div>
|
|
1897
|
+
`;
|
|
1898
|
+
function initPanel() {
|
|
1899
|
+
if (panelReady) return;
|
|
1900
|
+
panelReady = true;
|
|
1901
|
+
root.appendChild(panel);
|
|
1902
|
+
const categorySelect = panel.querySelector(
|
|
1903
|
+
'[data-role="category-select"]'
|
|
1904
|
+
);
|
|
1905
|
+
const categoryMenu = panel.querySelector(
|
|
1906
|
+
'[data-role="category-menu"]'
|
|
1907
|
+
);
|
|
1908
|
+
const categoryValue = panel.querySelector(
|
|
1909
|
+
'[data-role="category-value"]'
|
|
1910
|
+
);
|
|
1911
|
+
if (categoryMenu && categoryValue) {
|
|
1912
|
+
const categories = options.categories || DEFAULT_CATEGORIES;
|
|
1913
|
+
categoryValue.textContent = categories[0]?.label || DEFAULT_CATEGORIES[0]?.label || "\u53CD\u9988";
|
|
1914
|
+
for (const item of categories) {
|
|
1915
|
+
const option = document.createElement("button");
|
|
1916
|
+
option.type = "button";
|
|
1917
|
+
option.className = "yd-feedback-select-option";
|
|
1918
|
+
option.dataset.value = item.value;
|
|
1919
|
+
option.dataset.selected = String(item.value === categories[0]?.value);
|
|
1920
|
+
option.innerHTML = `${BUG_ICON}<span>${escapeHtml(item.label)}</span>`;
|
|
1921
|
+
option.addEventListener("click", () => {
|
|
1922
|
+
for (const node of categoryMenu.querySelectorAll(
|
|
1923
|
+
".yd-feedback-select-option"
|
|
1924
|
+
)) {
|
|
1925
|
+
node.dataset.selected = String(node === option);
|
|
1926
|
+
}
|
|
1927
|
+
categoryValue.textContent = item.label;
|
|
1928
|
+
if (categorySelect) {
|
|
1929
|
+
categorySelect.dataset.value = item.value;
|
|
1930
|
+
categorySelect.dataset.open = "false";
|
|
1931
|
+
}
|
|
1932
|
+
});
|
|
1933
|
+
categoryMenu.appendChild(option);
|
|
1934
|
+
}
|
|
1935
|
+
categorySelect?.setAttribute("data-value", categories[0]?.value || "BUG");
|
|
1936
|
+
}
|
|
1937
|
+
panel.querySelector('[data-role="category-trigger"]')?.addEventListener("click", () => {
|
|
1938
|
+
if (!categorySelect) return;
|
|
1939
|
+
categorySelect.dataset.open = categorySelect.dataset.open === "true" ? "false" : "true";
|
|
1940
|
+
});
|
|
1941
|
+
panel.querySelector(".yd-feedback-close")?.addEventListener("click", close);
|
|
1942
|
+
panel.querySelector('[data-role="clear"]')?.addEventListener("click", resetThread);
|
|
1943
|
+
panel.querySelector('[data-role="clear-secondary"]')?.addEventListener("click", close);
|
|
1944
|
+
panel.querySelector('[data-role="files-trigger"]')?.addEventListener("click", () => {
|
|
1945
|
+
panel.querySelector('[data-role="files"]')?.click();
|
|
1946
|
+
});
|
|
1947
|
+
panel.querySelector('[data-role="files"]')?.addEventListener("change", (event) => {
|
|
1948
|
+
setPendingFiles(event.target.files);
|
|
1949
|
+
});
|
|
1950
|
+
const composeBox = panel.querySelector(
|
|
1951
|
+
".yd-feedback-compose-box"
|
|
1952
|
+
);
|
|
1953
|
+
composeBox?.addEventListener("dragover", (event) => {
|
|
1954
|
+
event.preventDefault();
|
|
1955
|
+
});
|
|
1956
|
+
composeBox?.addEventListener("drop", (event) => {
|
|
1957
|
+
event.preventDefault();
|
|
1958
|
+
setPendingFiles(event.dataTransfer?.files || null);
|
|
1959
|
+
});
|
|
1960
|
+
composeBox?.addEventListener("paste", (event) => {
|
|
1961
|
+
const files = Array.from(event.clipboardData?.files || []).filter(
|
|
1962
|
+
(file) => file.type.startsWith("image/")
|
|
1963
|
+
);
|
|
1964
|
+
if (files.length > 0) {
|
|
1965
|
+
setPendingFiles(files);
|
|
1966
|
+
}
|
|
1967
|
+
});
|
|
1968
|
+
panel.querySelector('[data-role="submit"]')?.addEventListener("click", () => void submit());
|
|
1969
|
+
}
|
|
1970
|
+
function setPendingFiles(files) {
|
|
1971
|
+
pendingFiles = Array.from(files || []).filter((file) => file.type.startsWith("image/")).slice(0, MAX_IMAGES_PER_MESSAGE);
|
|
1972
|
+
const label = panel.querySelector('[data-role="files-label"]');
|
|
1973
|
+
if (label) {
|
|
1974
|
+
label.textContent = pendingFiles.length > 0 ? `\u5DF2\u9009\u62E9 ${pendingFiles.length} \u5F20\u56FE\u7247` : DEFAULT_ATTACHMENTS_LABEL;
|
|
1975
|
+
}
|
|
1976
|
+
}
|
|
1977
|
+
function resetThread() {
|
|
1978
|
+
threadState = null;
|
|
1979
|
+
pendingFiles = [];
|
|
1980
|
+
renderedMessages = [];
|
|
1981
|
+
renderMessages([]);
|
|
1982
|
+
updateThreadCard();
|
|
1983
|
+
setError("");
|
|
1984
|
+
const textarea = panel.querySelector(
|
|
1985
|
+
'[data-role="content"]'
|
|
1986
|
+
);
|
|
1987
|
+
if (textarea) textarea.value = "";
|
|
1988
|
+
const fileInput = panel.querySelector(
|
|
1989
|
+
'[data-role="files"]'
|
|
1990
|
+
);
|
|
1991
|
+
if (fileInput) fileInput.value = "";
|
|
1992
|
+
const filesLabel = panel.querySelector(
|
|
1993
|
+
'[data-role="files-label"]'
|
|
1994
|
+
);
|
|
1995
|
+
if (filesLabel) filesLabel.textContent = DEFAULT_ATTACHMENTS_LABEL;
|
|
1996
|
+
}
|
|
1997
|
+
function updateThreadCard() {
|
|
1998
|
+
const card = panel.querySelector('[data-role="thread-card"]');
|
|
1999
|
+
const empty = panel.querySelector('[data-role="thread-empty"]');
|
|
2000
|
+
if (!card || !empty) return;
|
|
2001
|
+
if (!threadState) {
|
|
2002
|
+
card.dataset.visible = "false";
|
|
2003
|
+
empty.style.display = "block";
|
|
2004
|
+
return;
|
|
2005
|
+
}
|
|
2006
|
+
card.dataset.visible = "true";
|
|
2007
|
+
empty.style.display = "none";
|
|
2008
|
+
const category = card.querySelector(
|
|
2009
|
+
'[data-role="thread-category"]'
|
|
2010
|
+
);
|
|
2011
|
+
const status = card.querySelector(
|
|
2012
|
+
'[data-role="thread-status"]'
|
|
2013
|
+
);
|
|
2014
|
+
const preview = card.querySelector(
|
|
2015
|
+
'[data-role="thread-preview"]'
|
|
2016
|
+
);
|
|
2017
|
+
const time = card.querySelector('[data-role="thread-time"]');
|
|
2018
|
+
if (category) {
|
|
2019
|
+
category.textContent = formatCategoryLabel(
|
|
2020
|
+
threadState.category || DEFAULT_CATEGORIES[0]?.value,
|
|
2021
|
+
options.categories || DEFAULT_CATEGORIES
|
|
2022
|
+
);
|
|
2023
|
+
}
|
|
2024
|
+
if (status) status.textContent = formatThreadStatus(threadState.status);
|
|
2025
|
+
if (preview) preview.textContent = threadState.contentPreview || "";
|
|
2026
|
+
if (time) time.textContent = formatThreadTime(threadState.createdAt);
|
|
2027
|
+
}
|
|
2028
|
+
function setError(message) {
|
|
2029
|
+
const node = panel.querySelector('[data-role="error"]');
|
|
2030
|
+
if (node) node.textContent = message;
|
|
2031
|
+
if (message) options.onError?.(new Error(message));
|
|
2032
|
+
}
|
|
2033
|
+
function setSubmitting(value) {
|
|
2034
|
+
const button = panel.querySelector(
|
|
2035
|
+
'[data-role="submit"]'
|
|
2036
|
+
);
|
|
2037
|
+
if (button) button.disabled = value;
|
|
2038
|
+
}
|
|
2039
|
+
function renderMessages(messages) {
|
|
2040
|
+
const node = panel.querySelector('[data-role="messages"]');
|
|
2041
|
+
if (!node) return;
|
|
2042
|
+
renderedMessages = messages;
|
|
2043
|
+
node.innerHTML = "";
|
|
2044
|
+
for (const message of messages) {
|
|
2045
|
+
const item = document.createElement("div");
|
|
2046
|
+
item.className = "yd-feedback-message";
|
|
2047
|
+
item.dataset.admin = String(message.senderType !== "END_USER");
|
|
2048
|
+
item.innerHTML = `<div class="yd-feedback-message-meta">${formatSenderType(message.senderType)} \xB7 ${new Date(message.createdAt).toLocaleString()}</div><div class="yd-feedback-message-content"></div>`;
|
|
2049
|
+
const content = item.querySelector(".yd-feedback-message-content");
|
|
2050
|
+
if (content) {
|
|
2051
|
+
content.textContent = message.senderType === "END_USER" ? message.content : message.translatedContent || message.content;
|
|
2052
|
+
}
|
|
2053
|
+
node.appendChild(item);
|
|
2054
|
+
}
|
|
2055
|
+
}
|
|
2056
|
+
function appendMessages(messages) {
|
|
2057
|
+
const byId = /* @__PURE__ */ new Map();
|
|
2058
|
+
for (const message of renderedMessages) byId.set(message.id, message);
|
|
2059
|
+
for (const message of messages) byId.set(message.id, message);
|
|
2060
|
+
renderMessages(Array.from(byId.values()));
|
|
2061
|
+
}
|
|
2062
|
+
async function uploadImages(files) {
|
|
2063
|
+
const selected = files.slice(0, MAX_IMAGES_PER_MESSAGE);
|
|
2064
|
+
const ids = [];
|
|
2065
|
+
for (const file of selected) {
|
|
2066
|
+
const compressed = await compressImage(file);
|
|
2067
|
+
const body = new FormData();
|
|
2068
|
+
body.append("file", compressed);
|
|
2069
|
+
if (threadState) body.append("threadId", threadState.threadId);
|
|
2070
|
+
const headers = {};
|
|
2071
|
+
if (threadState) headers["x-feedback-token"] = threadState.clientToken;
|
|
2072
|
+
const response = await fetch(
|
|
2073
|
+
`${getBaseUrl(options)}/api/v1/feedback/${encodeURIComponent(options.appId)}/resources/images`,
|
|
2074
|
+
{ method: "POST", body, headers }
|
|
2075
|
+
);
|
|
2076
|
+
const payload = await response.json();
|
|
2077
|
+
if (!response.ok || payload?.code !== 200) {
|
|
2078
|
+
throw new Error(payload?.message || "Image upload failed");
|
|
2079
|
+
}
|
|
2080
|
+
ids.push(payload.data.resource.id);
|
|
2081
|
+
}
|
|
2082
|
+
return ids;
|
|
2083
|
+
}
|
|
2084
|
+
async function submit() {
|
|
2085
|
+
const content = panel.querySelector('[data-role="content"]')?.value.trim();
|
|
2086
|
+
if (!content) {
|
|
2087
|
+
setError("\u8BF7\u8F93\u5165\u53CD\u9988\u5185\u5BB9\u3002");
|
|
2088
|
+
return;
|
|
2089
|
+
}
|
|
2090
|
+
setSubmitting(true);
|
|
2091
|
+
setError("");
|
|
2092
|
+
try {
|
|
2093
|
+
const category = panel.querySelector('[data-role="category-select"]')?.dataset.value || "OTHER";
|
|
2094
|
+
const contact = panel.querySelector('[data-role="contact"]')?.value || "";
|
|
2095
|
+
const fileInput = panel.querySelector(
|
|
2096
|
+
'[data-role="files"]'
|
|
2097
|
+
);
|
|
2098
|
+
const attachments = await uploadImages(pendingFiles);
|
|
2099
|
+
if (!threadState) {
|
|
2100
|
+
const result = await requestJson(
|
|
2101
|
+
`${getBaseUrl(options)}/api/v1/feedback/${encodeURIComponent(options.appId)}/threads`,
|
|
2102
|
+
{
|
|
2103
|
+
method: "POST",
|
|
2104
|
+
body: safeJson({
|
|
2105
|
+
category,
|
|
2106
|
+
content,
|
|
2107
|
+
attachments,
|
|
2108
|
+
actor: {
|
|
2109
|
+
...options.actor || {},
|
|
2110
|
+
contactEmail: contact.includes("@") ? contact : options.actor?.contactEmail,
|
|
2111
|
+
contactPhone: contact && !contact.includes("@") ? contact : options.actor?.contactPhone
|
|
2112
|
+
},
|
|
2113
|
+
metadata: collectMetadata(options)
|
|
2114
|
+
})
|
|
2115
|
+
}
|
|
2116
|
+
);
|
|
2117
|
+
threadState = {
|
|
2118
|
+
threadId: result.thread.id,
|
|
2119
|
+
clientToken: result.clientToken,
|
|
2120
|
+
lastMessageId: result.message?.id,
|
|
2121
|
+
status: result.thread.status,
|
|
2122
|
+
category,
|
|
2123
|
+
contentPreview: content,
|
|
2124
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
2125
|
+
};
|
|
2126
|
+
updateThreadCard();
|
|
2127
|
+
options.onThreadCreated?.(result.thread.id);
|
|
2128
|
+
options.onMessageSent?.(result.message.id);
|
|
2129
|
+
} else {
|
|
2130
|
+
const result = await requestJson(
|
|
2131
|
+
`${getBaseUrl(options)}/api/v1/feedback/${encodeURIComponent(options.appId)}/threads/${encodeURIComponent(threadState.threadId)}/messages`,
|
|
2132
|
+
{
|
|
2133
|
+
method: "POST",
|
|
2134
|
+
headers: { "x-feedback-token": threadState.clientToken },
|
|
2135
|
+
body: safeJson({
|
|
2136
|
+
content,
|
|
2137
|
+
attachments,
|
|
2138
|
+
metadata: collectMetadata(options)
|
|
2139
|
+
})
|
|
2140
|
+
}
|
|
2141
|
+
);
|
|
2142
|
+
threadState.lastMessageId = result.message.id;
|
|
2143
|
+
threadState.contentPreview = content;
|
|
2144
|
+
options.onMessageSent?.(result.message.id);
|
|
2145
|
+
}
|
|
2146
|
+
const textarea = panel.querySelector(
|
|
2147
|
+
'[data-role="content"]'
|
|
2148
|
+
);
|
|
2149
|
+
if (textarea) textarea.value = "";
|
|
2150
|
+
if (fileInput) fileInput.value = "";
|
|
2151
|
+
pendingFiles = [];
|
|
2152
|
+
const filesLabel = panel.querySelector(
|
|
2153
|
+
'[data-role="files-label"]'
|
|
2154
|
+
);
|
|
2155
|
+
if (filesLabel) filesLabel.textContent = DEFAULT_ATTACHMENTS_LABEL;
|
|
2156
|
+
await pollOnce();
|
|
2157
|
+
startPolling();
|
|
2158
|
+
} catch (error) {
|
|
2159
|
+
setError(error instanceof Error ? error.message : "\u63D0\u4EA4\u5931\u8D25");
|
|
2160
|
+
} finally {
|
|
2161
|
+
setSubmitting(false);
|
|
2162
|
+
}
|
|
2163
|
+
}
|
|
2164
|
+
async function pollOnce() {
|
|
2165
|
+
if (!threadState) return;
|
|
2166
|
+
const currentThread = threadState;
|
|
2167
|
+
const params = new URLSearchParams();
|
|
2168
|
+
if (currentThread.lastMessageId) {
|
|
2169
|
+
params.set("afterMessageId", currentThread.lastMessageId);
|
|
2170
|
+
}
|
|
2171
|
+
params.set("feedbackToken", currentThread.clientToken);
|
|
2172
|
+
const result = await requestJson(
|
|
2173
|
+
`${getBaseUrl(options)}/api/v1/feedback/${encodeURIComponent(options.appId)}/threads/${encodeURIComponent(currentThread.threadId)}/messages?${params.toString()}`
|
|
2174
|
+
);
|
|
2175
|
+
currentThread.status = result.threadStatus;
|
|
2176
|
+
updateThreadCard();
|
|
2177
|
+
if (result.messages.length > 0) {
|
|
2178
|
+
const latestMessage = result.messages.at(-1);
|
|
2179
|
+
if (latestMessage) currentThread.lastMessageId = latestMessage.id;
|
|
2180
|
+
appendMessages(result.messages);
|
|
2181
|
+
}
|
|
2182
|
+
if (result.threadStatus !== "WAITING_ADMIN") stopPolling();
|
|
2183
|
+
else schedulePoll(result.nextPollAfterMs);
|
|
2184
|
+
}
|
|
2185
|
+
function schedulePoll(delay) {
|
|
2186
|
+
stopPolling();
|
|
2187
|
+
if (!delay || delay < 1 || document.hidden || !threadState) return;
|
|
2188
|
+
pollTimer = window.setTimeout(() => void pollOnce(), delay);
|
|
2189
|
+
}
|
|
2190
|
+
function startPolling() {
|
|
2191
|
+
if (!threadState || threadState.status !== "WAITING_ADMIN") return;
|
|
2192
|
+
schedulePoll(1e4);
|
|
2193
|
+
}
|
|
2194
|
+
function stopPolling() {
|
|
2195
|
+
if (pollTimer) window.clearTimeout(pollTimer);
|
|
2196
|
+
pollTimer = null;
|
|
2197
|
+
}
|
|
2198
|
+
function open() {
|
|
2199
|
+
initPanel();
|
|
2200
|
+
panel.dataset.open = "true";
|
|
2201
|
+
window.setTimeout(() => {
|
|
2202
|
+
panel.querySelector('[data-role="content"]')?.focus();
|
|
2203
|
+
}, 0);
|
|
2204
|
+
}
|
|
2205
|
+
function close() {
|
|
2206
|
+
panel.dataset.open = "false";
|
|
2207
|
+
stopPolling();
|
|
2208
|
+
}
|
|
2209
|
+
launcher.addEventListener("click", open);
|
|
2210
|
+
const handleVisibilityChange = () => {
|
|
2211
|
+
if (document.hidden) stopPolling();
|
|
2212
|
+
else startPolling();
|
|
2213
|
+
};
|
|
2214
|
+
const handleDocumentClick = (event) => {
|
|
2215
|
+
const categorySelect = panel.querySelector(
|
|
2216
|
+
'[data-role="category-select"]'
|
|
2217
|
+
);
|
|
2218
|
+
if (categorySelect && event.target instanceof Node && !categorySelect.contains(event.target)) {
|
|
2219
|
+
categorySelect.dataset.open = "false";
|
|
2220
|
+
}
|
|
2221
|
+
};
|
|
2222
|
+
document.addEventListener("visibilitychange", handleVisibilityChange);
|
|
2223
|
+
document.addEventListener("click", handleDocumentClick);
|
|
2224
|
+
if (typeof window !== "undefined") {
|
|
2225
|
+
const preload = () => {
|
|
2226
|
+
if ("requestIdleCallback" in window) {
|
|
2227
|
+
;
|
|
2228
|
+
window.requestIdleCallback(() => initPanel());
|
|
2229
|
+
} else {
|
|
2230
|
+
globalThis.setTimeout(() => initPanel(), 1200);
|
|
2231
|
+
}
|
|
2232
|
+
};
|
|
2233
|
+
if (document.readyState === "complete") preload();
|
|
2234
|
+
else {
|
|
2235
|
+
window.addEventListener("load", preload, { once: true });
|
|
2236
|
+
removeLoadListener = () => window.removeEventListener("load", preload);
|
|
2237
|
+
}
|
|
2238
|
+
}
|
|
2239
|
+
return {
|
|
2240
|
+
open,
|
|
2241
|
+
close,
|
|
2242
|
+
destroy() {
|
|
2243
|
+
stopPolling();
|
|
2244
|
+
document.removeEventListener("visibilitychange", handleVisibilityChange);
|
|
2245
|
+
document.removeEventListener("click", handleDocumentClick);
|
|
2246
|
+
removeLoadListener?.();
|
|
2247
|
+
root.remove();
|
|
2248
|
+
}
|
|
2249
|
+
};
|
|
2250
|
+
}
|
|
2251
|
+
function mountFeedbackWidget(container, options) {
|
|
2252
|
+
return createFeedbackWidget(container, options);
|
|
2253
|
+
}
|
|
2254
|
+
|
|
1238
2255
|
// src/server.ts
|
|
1239
2256
|
var import_crypto = __toESM(require("crypto"), 1);
|
|
1240
2257
|
function getCustomAmountRechargeRule(product, currency) {
|
|
@@ -1396,6 +2413,48 @@ var PaymentClient = class {
|
|
|
1396
2413
|
const path = params.toString() ? `/products?${params.toString()}` : "/products";
|
|
1397
2414
|
return this.request("GET", path);
|
|
1398
2415
|
}
|
|
2416
|
+
/**
|
|
2417
|
+
* Fetch the realtime stock snapshot for a single product.
|
|
2418
|
+
*/
|
|
2419
|
+
async getProductStock(productIdOrCode, options) {
|
|
2420
|
+
const value = productIdOrCode?.trim();
|
|
2421
|
+
if (!value) {
|
|
2422
|
+
throw new Error("productIdOrCode is required");
|
|
2423
|
+
}
|
|
2424
|
+
const params = new URLSearchParams();
|
|
2425
|
+
params.set("productIdOrCode", value);
|
|
2426
|
+
if (options?.lookupBy) params.set("lookupBy", options.lookupBy);
|
|
2427
|
+
if (options?.locale) params.set("locale", options.locale);
|
|
2428
|
+
if (options?.currency) params.set("currency", options.currency);
|
|
2429
|
+
return this.request(
|
|
2430
|
+
"GET",
|
|
2431
|
+
`/products/${encodeURIComponent(value)}/stock?${params.toString()}`
|
|
2432
|
+
);
|
|
2433
|
+
}
|
|
2434
|
+
async getProductStocks(params, options) {
|
|
2435
|
+
const productIds = [
|
|
2436
|
+
...new Set(
|
|
2437
|
+
(params.productIds || []).map((item) => item.trim()).filter(Boolean)
|
|
2438
|
+
)
|
|
2439
|
+
];
|
|
2440
|
+
const productCodes = [
|
|
2441
|
+
...new Set(
|
|
2442
|
+
(params.productCodes || []).map((item) => item.trim()).filter(Boolean)
|
|
2443
|
+
)
|
|
2444
|
+
];
|
|
2445
|
+
if (productIds.length === 0 && productCodes.length === 0) {
|
|
2446
|
+
throw new Error("productIds or productCodes is required");
|
|
2447
|
+
}
|
|
2448
|
+
const queryOptions = options || params;
|
|
2449
|
+
const query = new URLSearchParams();
|
|
2450
|
+
if (productIds.length > 0) query.set("productIds", productIds.join(","));
|
|
2451
|
+
if (productCodes.length > 0)
|
|
2452
|
+
query.set("productCodes", productCodes.join(","));
|
|
2453
|
+
if (queryOptions.lookupBy) query.set("lookupBy", queryOptions.lookupBy);
|
|
2454
|
+
if (queryOptions.locale) query.set("locale", queryOptions.locale);
|
|
2455
|
+
if (queryOptions.currency) query.set("currency", queryOptions.currency);
|
|
2456
|
+
return this.request("GET", `/products/stocks?${query.toString()}`);
|
|
2457
|
+
}
|
|
1399
2458
|
/**
|
|
1400
2459
|
* Create a new order
|
|
1401
2460
|
* @param params - Order creation parameters
|
|
@@ -1404,6 +2463,17 @@ var PaymentClient = class {
|
|
|
1404
2463
|
async createOrder(params) {
|
|
1405
2464
|
return this.request("POST", "/orders", params);
|
|
1406
2465
|
}
|
|
2466
|
+
/**
|
|
2467
|
+
* Create a paid manual bank transfer order.
|
|
2468
|
+
* @param params - Order creation parameters without channel
|
|
2469
|
+
* @returns Paid order details
|
|
2470
|
+
*/
|
|
2471
|
+
async createBankTransferOrder(params) {
|
|
2472
|
+
return this.request("POST", "/orders", {
|
|
2473
|
+
...params,
|
|
2474
|
+
channel: "BANK_TRANSFER"
|
|
2475
|
+
});
|
|
2476
|
+
}
|
|
1407
2477
|
/**
|
|
1408
2478
|
* Create a WeChat Mini Program order (channel fixed to WECHAT_MINI)
|
|
1409
2479
|
* @param params - Mini program order parameters
|
|
@@ -1426,6 +2496,36 @@ var PaymentClient = class {
|
|
|
1426
2496
|
async payOrder(orderId, params) {
|
|
1427
2497
|
return this.request("POST", `/orders/${orderId}/pay`, params);
|
|
1428
2498
|
}
|
|
2499
|
+
/**
|
|
2500
|
+
* Cancel a pending order and release its inventory reservation.
|
|
2501
|
+
* Paid/refunded/failed orders are returned unchanged by the gateway.
|
|
2502
|
+
*/
|
|
2503
|
+
async cancelOrder(orderId, params) {
|
|
2504
|
+
const value = orderId?.trim();
|
|
2505
|
+
if (!value) {
|
|
2506
|
+
throw new Error("orderId is required");
|
|
2507
|
+
}
|
|
2508
|
+
return this.request(
|
|
2509
|
+
"POST",
|
|
2510
|
+
`/orders/${encodeURIComponent(value)}/cancel`,
|
|
2511
|
+
params || {}
|
|
2512
|
+
);
|
|
2513
|
+
}
|
|
2514
|
+
/**
|
|
2515
|
+
* Complete a zero-amount FREE order.
|
|
2516
|
+
* This marks the pending order as paid and triggers normal paid-order side effects.
|
|
2517
|
+
*/
|
|
2518
|
+
async completeFreeOrder(orderId) {
|
|
2519
|
+
const value = orderId?.trim();
|
|
2520
|
+
if (!value) {
|
|
2521
|
+
throw new Error("orderId is required");
|
|
2522
|
+
}
|
|
2523
|
+
return this.request(
|
|
2524
|
+
"POST",
|
|
2525
|
+
`/orders/${encodeURIComponent(value)}/free/complete`,
|
|
2526
|
+
{}
|
|
2527
|
+
);
|
|
2528
|
+
}
|
|
1429
2529
|
/**
|
|
1430
2530
|
* Query order status
|
|
1431
2531
|
* @param orderId - The order ID to query
|
|
@@ -1504,6 +2604,31 @@ var PaymentClient = class {
|
|
|
1504
2604
|
...options
|
|
1505
2605
|
});
|
|
1506
2606
|
}
|
|
2607
|
+
/**
|
|
2608
|
+
* Consume numeric entitlements from an ordered key pool.
|
|
2609
|
+
* Useful when subscription credits and perpetual credits use separate keys.
|
|
2610
|
+
*/
|
|
2611
|
+
async consumeEntitlementPool(userId, keys, amount, options) {
|
|
2612
|
+
return this.request(
|
|
2613
|
+
"POST",
|
|
2614
|
+
`/users/${userId}/entitlements/consume-pool`,
|
|
2615
|
+
{
|
|
2616
|
+
keys,
|
|
2617
|
+
amount,
|
|
2618
|
+
...options
|
|
2619
|
+
}
|
|
2620
|
+
);
|
|
2621
|
+
}
|
|
2622
|
+
/**
|
|
2623
|
+
* Get active numeric entitlement buckets ordered by expiration.
|
|
2624
|
+
*/
|
|
2625
|
+
async getEntitlementCreditBuckets(userId, keys) {
|
|
2626
|
+
const query = keys && keys.length > 0 ? `?keys=${encodeURIComponent(keys.join(","))}` : "";
|
|
2627
|
+
return this.request(
|
|
2628
|
+
"GET",
|
|
2629
|
+
`/users/${userId}/entitlements/credit-buckets${query}`
|
|
2630
|
+
);
|
|
2631
|
+
}
|
|
1507
2632
|
/**
|
|
1508
2633
|
* Add numeric entitlement (e.g. refund)
|
|
1509
2634
|
* @param userId - User ID
|
|
@@ -1590,10 +2715,13 @@ var PaymentClient = class {
|
|
|
1590
2715
|
LoginUI,
|
|
1591
2716
|
PaymentClient,
|
|
1592
2717
|
PaymentUI,
|
|
2718
|
+
createFeedbackWidget,
|
|
1593
2719
|
createLoginUI,
|
|
1594
2720
|
createPaymentUI,
|
|
2721
|
+
detectLoginEnvironment,
|
|
1595
2722
|
getCustomAmountRechargeRule,
|
|
1596
2723
|
handleLoginCallbackIfPresent,
|
|
2724
|
+
mountFeedbackWidget,
|
|
1597
2725
|
validateCustomAmountRecharge
|
|
1598
2726
|
});
|
|
1599
2727
|
//# sourceMappingURL=index.cjs.map
|