@blocklet/payment-react 1.18.3 → 1.18.4
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/es/checkout/donate.d.ts +5 -3
- package/es/checkout/donate.js +109 -36
- package/es/contexts/donate.d.ts +41 -0
- package/es/contexts/donate.js +164 -0
- package/es/contexts/payment.js +3 -16
- package/es/index.d.ts +2 -0
- package/es/index.js +2 -0
- package/es/libs/cache.d.ts +14 -0
- package/es/libs/cache.js +23 -0
- package/es/libs/cached-request.d.ts +17 -0
- package/es/libs/cached-request.js +79 -0
- package/es/libs/util.d.ts +2 -0
- package/es/libs/util.js +13 -0
- package/es/locales/en.js +8 -1
- package/es/locales/zh.js +8 -1
- package/es/payment/skeleton/donation.js +1 -1
- package/lib/checkout/donate.d.ts +5 -3
- package/lib/checkout/donate.js +107 -36
- package/lib/contexts/donate.d.ts +41 -0
- package/lib/contexts/donate.js +181 -0
- package/lib/contexts/payment.js +7 -22
- package/lib/index.d.ts +2 -0
- package/lib/index.js +24 -0
- package/lib/libs/cache.d.ts +14 -0
- package/lib/libs/cache.js +29 -0
- package/lib/libs/cached-request.d.ts +17 -0
- package/lib/libs/cached-request.js +90 -0
- package/lib/libs/util.d.ts +2 -0
- package/lib/libs/util.js +12 -0
- package/lib/locales/en.js +8 -1
- package/lib/locales/zh.js +8 -1
- package/lib/payment/skeleton/donation.js +1 -1
- package/package.json +6 -6
- package/src/checkout/donate.tsx +135 -45
- package/src/contexts/donate.tsx +226 -0
- package/src/contexts/payment.tsx +5 -20
- package/src/index.ts +2 -0
- package/src/libs/cache.ts +33 -0
- package/src/libs/cached-request.ts +103 -0
- package/src/libs/util.ts +15 -0
- package/src/locales/en.tsx +7 -0
- package/src/locales/zh.tsx +7 -0
- package/src/payment/skeleton/donation.tsx +1 -1
package/es/checkout/donate.d.ts
CHANGED
|
@@ -7,12 +7,14 @@ export type DonateHistory = {
|
|
|
7
7
|
method: TPaymentMethod;
|
|
8
8
|
totalAmount: string;
|
|
9
9
|
};
|
|
10
|
+
export type RequiredDonationSettings = Pick<DonationSettings, 'target' | 'title' | 'description' | 'reference' | 'beneficiaries'>;
|
|
11
|
+
type OptionalDonationSettings = Partial<Omit<DonationSettings, keyof RequiredDonationSettings>>;
|
|
10
12
|
export interface ButtonType extends Omit<MUIButtonProps, 'text' | 'icon'> {
|
|
11
|
-
text
|
|
13
|
+
text?: string | React.ReactNode;
|
|
12
14
|
icon: React.ReactNode;
|
|
13
15
|
}
|
|
14
16
|
export type DonateProps = Pick<CheckoutProps, 'onPaid' | 'onError'> & {
|
|
15
|
-
settings:
|
|
17
|
+
settings: RequiredDonationSettings & OptionalDonationSettings;
|
|
16
18
|
livemode?: boolean;
|
|
17
19
|
timeout?: number;
|
|
18
20
|
mode?: 'inline' | 'default' | 'custom';
|
|
@@ -20,7 +22,7 @@ export type DonateProps = Pick<CheckoutProps, 'onPaid' | 'onError'> & {
|
|
|
20
22
|
button?: ButtonType;
|
|
21
23
|
};
|
|
22
24
|
theme?: 'default' | 'inherit' | PaymentThemeOptions;
|
|
23
|
-
children?: (openDialog: () => void, donateTotalAmount: string, supporters: DonateHistory, loading?: boolean) => React.ReactNode;
|
|
25
|
+
children?: (openDialog: () => void, donateTotalAmount: string, supporters: DonateHistory, loading?: boolean, donateSettings?: DonationSettings) => React.ReactNode;
|
|
24
26
|
};
|
|
25
27
|
declare function CheckoutDonate(props: DonateProps): import("react").JSX.Element;
|
|
26
28
|
declare namespace CheckoutDonate {
|
package/es/checkout/donate.js
CHANGED
|
@@ -9,26 +9,38 @@ import {
|
|
|
9
9
|
Button,
|
|
10
10
|
CircularProgress,
|
|
11
11
|
Hidden,
|
|
12
|
+
IconButton,
|
|
12
13
|
Popover,
|
|
13
14
|
Stack,
|
|
14
15
|
Table,
|
|
15
16
|
TableBody,
|
|
16
17
|
TableCell,
|
|
17
18
|
TableRow,
|
|
18
|
-
Typography
|
|
19
|
+
Typography,
|
|
20
|
+
Tooltip
|
|
19
21
|
} from "@mui/material";
|
|
20
|
-
import {
|
|
22
|
+
import { useRequest, useSetState } from "ahooks";
|
|
21
23
|
import omit from "lodash/omit";
|
|
22
24
|
import uniqBy from "lodash/unionBy";
|
|
23
|
-
import { useEffect, useState } from "react";
|
|
25
|
+
import { useEffect, useRef, useState } from "react";
|
|
26
|
+
import { Settings } from "@mui/icons-material";
|
|
24
27
|
import TxLink from "../components/blockchain/tx.js";
|
|
25
28
|
import api from "../libs/api.js";
|
|
26
|
-
import {
|
|
29
|
+
import {
|
|
30
|
+
formatAmount,
|
|
31
|
+
formatBNStr,
|
|
32
|
+
formatDateTime,
|
|
33
|
+
formatError,
|
|
34
|
+
getCustomerAvatar,
|
|
35
|
+
lazyLoad,
|
|
36
|
+
openDonationSettings
|
|
37
|
+
} from "../libs/util.js";
|
|
27
38
|
import CheckoutForm from "./form.js";
|
|
28
39
|
import { PaymentThemeProvider } from "../theme/index.js";
|
|
29
40
|
import { usePaymentContext } from "../contexts/payment.js";
|
|
30
41
|
import Livemode from "../components/livemode.js";
|
|
31
42
|
import { useMobile } from "../hooks/mobile.js";
|
|
43
|
+
import { useDonateContext } from "../contexts/donate.js";
|
|
32
44
|
const donationCache = {};
|
|
33
45
|
const createOrUpdateDonation = (settings, livemode = true) => {
|
|
34
46
|
const donationKey = `${settings.target}-${livemode}`;
|
|
@@ -184,13 +196,39 @@ function SupporterSimple({ supporters = [], totalAmount = "0", currency, method
|
|
|
184
196
|
}
|
|
185
197
|
);
|
|
186
198
|
}
|
|
199
|
+
const defaultDonateAmount = {
|
|
200
|
+
presets: ["1", "5", "10"],
|
|
201
|
+
preset: "1",
|
|
202
|
+
minimum: "0.01",
|
|
203
|
+
maximum: "100",
|
|
204
|
+
custom: true
|
|
205
|
+
};
|
|
187
206
|
function useDonation(settings, livemode, mode = "default") {
|
|
188
207
|
const [state, setState] = useSetState({
|
|
189
208
|
open: false,
|
|
190
209
|
supporterLoaded: false,
|
|
191
210
|
exist: false
|
|
192
211
|
});
|
|
193
|
-
const
|
|
212
|
+
const donateContext = useDonateContext();
|
|
213
|
+
const { isMobile } = useMobile();
|
|
214
|
+
const { settings: donateConfig = {} } = donateContext || {};
|
|
215
|
+
const donateSettings = {
|
|
216
|
+
...settings,
|
|
217
|
+
amount: settings.amount || donateConfig?.settings?.amount || defaultDonateAmount,
|
|
218
|
+
appearance: {
|
|
219
|
+
button: {
|
|
220
|
+
...settings?.appearance?.button || {},
|
|
221
|
+
text: settings?.appearance?.button?.text || donateConfig?.settings?.btnText || "Donate",
|
|
222
|
+
icon: settings?.appearance?.button?.icon || donateConfig?.settings?.icon || null
|
|
223
|
+
},
|
|
224
|
+
history: {
|
|
225
|
+
variant: settings?.appearance?.history?.variant || donateConfig?.settings?.historyType || "avatar"
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
};
|
|
229
|
+
const hasRequestedRef = useRef(false);
|
|
230
|
+
const containerRef = useRef(null);
|
|
231
|
+
const donation = useRequest(() => createOrUpdateDonation(donateSettings, livemode), {
|
|
194
232
|
manual: true,
|
|
195
233
|
loadingDelay: 300
|
|
196
234
|
});
|
|
@@ -201,14 +239,28 @@ function useDonation(settings, livemode, mode = "default") {
|
|
|
201
239
|
loadingDelay: 300
|
|
202
240
|
}
|
|
203
241
|
);
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
242
|
+
const rootMargin = isMobile ? "50px" : `${Math.min(window.innerHeight / 2, 300)}px`;
|
|
243
|
+
useEffect(() => {
|
|
244
|
+
if (mode === "inline")
|
|
245
|
+
return;
|
|
246
|
+
const element = containerRef.current;
|
|
247
|
+
if (!element)
|
|
248
|
+
return;
|
|
249
|
+
const observer = new IntersectionObserver(
|
|
250
|
+
([entry]) => {
|
|
251
|
+
if (entry.isIntersecting && !hasRequestedRef.current) {
|
|
252
|
+
hasRequestedRef.current = true;
|
|
253
|
+
lazyLoad(() => {
|
|
254
|
+
donation.run();
|
|
255
|
+
supporters.run();
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
},
|
|
259
|
+
{ threshold: 0, rootMargin }
|
|
260
|
+
);
|
|
261
|
+
observer.observe(element);
|
|
262
|
+
return () => observer.unobserve(element);
|
|
263
|
+
}, [mode]);
|
|
212
264
|
useEffect(() => {
|
|
213
265
|
if (donation.data && state.supporterLoaded === false) {
|
|
214
266
|
setState({ supporterLoaded: true });
|
|
@@ -216,10 +268,13 @@ function useDonation(settings, livemode, mode = "default") {
|
|
|
216
268
|
}
|
|
217
269
|
}, [donation.data]);
|
|
218
270
|
return {
|
|
271
|
+
containerRef,
|
|
219
272
|
donation,
|
|
220
273
|
supporters,
|
|
221
274
|
state,
|
|
222
|
-
setState
|
|
275
|
+
setState,
|
|
276
|
+
donateSettings,
|
|
277
|
+
supportUpdateSettings: !!donateContext
|
|
223
278
|
};
|
|
224
279
|
}
|
|
225
280
|
function CheckoutDonateInner({
|
|
@@ -233,13 +288,17 @@ function CheckoutDonateInner({
|
|
|
233
288
|
theme,
|
|
234
289
|
children
|
|
235
290
|
}) {
|
|
236
|
-
const { state, setState, donation, supporters } = useDonation(
|
|
291
|
+
const { containerRef, state, setState, donation, supporters, donateSettings, supportUpdateSettings } = useDonation(
|
|
292
|
+
settings,
|
|
293
|
+
livemode,
|
|
294
|
+
mode
|
|
295
|
+
);
|
|
237
296
|
const customers = uniqBy(supporters?.data?.supporters || [], "customer_did");
|
|
238
297
|
const { t } = useLocaleContext();
|
|
239
298
|
const [anchorEl, setAnchorEl] = useState(null);
|
|
240
299
|
const [popoverOpen, setPopoverOpen] = useState(false);
|
|
241
300
|
const { isMobile } = useMobile();
|
|
242
|
-
const { connect } = usePaymentContext();
|
|
301
|
+
const { connect, session } = usePaymentContext();
|
|
243
302
|
const handlePaid = (...args) => {
|
|
244
303
|
if (onPaid) {
|
|
245
304
|
onPaid(...args);
|
|
@@ -264,18 +323,19 @@ function CheckoutDonateInner({
|
|
|
264
323
|
const startDonate = () => {
|
|
265
324
|
setState({ open: true });
|
|
266
325
|
};
|
|
326
|
+
const inlineText = inlineOptions?.button?.text || donateSettings.appearance.button.text;
|
|
267
327
|
const inlineRender = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
268
328
|
/* @__PURE__ */ jsx(
|
|
269
329
|
Button,
|
|
270
330
|
{
|
|
271
|
-
size:
|
|
272
|
-
color:
|
|
273
|
-
variant:
|
|
274
|
-
...
|
|
331
|
+
size: donateSettings.appearance?.button?.size || "medium",
|
|
332
|
+
color: donateSettings.appearance?.button?.color || "primary",
|
|
333
|
+
variant: donateSettings.appearance?.button?.variant || "contained",
|
|
334
|
+
...donateSettings.appearance?.button,
|
|
275
335
|
onClick: handlePopoverOpen,
|
|
276
336
|
children: /* @__PURE__ */ jsxs(Stack, { direction: "row", alignItems: "center", spacing: 0.5, children: [
|
|
277
|
-
|
|
278
|
-
typeof
|
|
337
|
+
donateSettings.appearance.button.icon,
|
|
338
|
+
typeof donateSettings.appearance.button.text === "string" ? /* @__PURE__ */ jsx(Typography, { sx: { whiteSpace: "nowrap" }, children: donateSettings.appearance.button.text }) : donateSettings.appearance.button.text
|
|
279
339
|
] })
|
|
280
340
|
}
|
|
281
341
|
),
|
|
@@ -322,7 +382,7 @@ function CheckoutDonateInner({
|
|
|
322
382
|
/* @__PURE__ */ jsxs(Box, { display: "flex", alignItems: "center", flexDirection: "column", gap: 2, children: [
|
|
323
383
|
/* @__PURE__ */ jsx(Button, { ...inlineOptions.button, onClick: () => startDonate(), children: /* @__PURE__ */ jsxs(Stack, { direction: "row", alignItems: "center", spacing: 0.5, children: [
|
|
324
384
|
inlineOptions?.button?.icon,
|
|
325
|
-
typeof
|
|
385
|
+
typeof inlineText === "string" ? /* @__PURE__ */ jsx(Typography, { sx: { whiteSpace: "nowrap" }, children: inlineText }) : inlineText
|
|
326
386
|
] }) }),
|
|
327
387
|
/* @__PURE__ */ jsx(SupporterSimple, { ...supporters.data })
|
|
328
388
|
] })
|
|
@@ -344,19 +404,19 @@ function CheckoutDonateInner({
|
|
|
344
404
|
/* @__PURE__ */ jsx(
|
|
345
405
|
Button,
|
|
346
406
|
{
|
|
347
|
-
size:
|
|
348
|
-
color:
|
|
349
|
-
variant:
|
|
350
|
-
...
|
|
407
|
+
size: donateSettings.appearance?.button?.size || "medium",
|
|
408
|
+
color: donateSettings.appearance?.button?.color || "primary",
|
|
409
|
+
variant: donateSettings.appearance?.button?.variant || "contained",
|
|
410
|
+
...donateSettings.appearance?.button,
|
|
351
411
|
onClick: () => startDonate(),
|
|
352
412
|
children: /* @__PURE__ */ jsxs(Stack, { direction: "row", alignItems: "center", spacing: 0.5, children: [
|
|
353
|
-
|
|
354
|
-
typeof
|
|
413
|
+
donateSettings.appearance.button.icon,
|
|
414
|
+
typeof donateSettings.appearance.button.text === "string" ? /* @__PURE__ */ jsx(Typography, { children: donateSettings.appearance.button.text }) : donateSettings.appearance.button.text
|
|
355
415
|
] })
|
|
356
416
|
}
|
|
357
417
|
),
|
|
358
|
-
supporters.data &&
|
|
359
|
-
supporters.data &&
|
|
418
|
+
supporters.data && donateSettings.appearance.history.variant === "avatar" && /* @__PURE__ */ jsx(SupporterAvatar, { ...supporters.data }),
|
|
419
|
+
supporters.data && donateSettings.appearance.history.variant === "table" && /* @__PURE__ */ jsx(SupporterTable, { ...supporters.data })
|
|
360
420
|
]
|
|
361
421
|
}
|
|
362
422
|
);
|
|
@@ -372,7 +432,8 @@ function CheckoutDonateInner({
|
|
|
372
432
|
supporters.data?.currency?.decimal
|
|
373
433
|
)} ${supporters.data?.currency?.symbol}`,
|
|
374
434
|
supporters.data || {},
|
|
375
|
-
!!supporters.loading
|
|
435
|
+
!!supporters.loading,
|
|
436
|
+
donateSettings
|
|
376
437
|
) }) : /* @__PURE__ */ jsxs(Typography, { children: [
|
|
377
438
|
"Please provide a valid render function ",
|
|
378
439
|
/* @__PURE__ */ jsx("pre", { children: "(openDonate, donateTotalAmount, supporters) => ReactNode" })
|
|
@@ -380,15 +441,27 @@ function CheckoutDonateInner({
|
|
|
380
441
|
}
|
|
381
442
|
return defaultRender;
|
|
382
443
|
};
|
|
383
|
-
|
|
444
|
+
const isAdmin = ["owner", "admin"].includes(session?.user?.role);
|
|
445
|
+
return /* @__PURE__ */ jsxs("div", { ref: containerRef, children: [
|
|
384
446
|
renderInnerView(),
|
|
385
447
|
donation.data && /* @__PURE__ */ jsx(
|
|
386
448
|
Dialog,
|
|
387
449
|
{
|
|
388
450
|
open: state.open,
|
|
389
451
|
title: /* @__PURE__ */ jsxs(Box, { display: "flex", alignItems: "center", gap: 0.5, children: [
|
|
390
|
-
/* @__PURE__ */ jsx(Typography, { variant: "h3", sx: { maxWidth: 320, textOverflow: "ellipsis", overflow: "hidden" }, children:
|
|
391
|
-
|
|
452
|
+
/* @__PURE__ */ jsx(Typography, { variant: "h3", sx: { maxWidth: 320, textOverflow: "ellipsis", overflow: "hidden" }, children: donateSettings.title }),
|
|
453
|
+
supportUpdateSettings && isAdmin && /* @__PURE__ */ jsx(Tooltip, { title: t("payment.checkout.donation.configTip"), placement: "bottom", children: /* @__PURE__ */ jsx(
|
|
454
|
+
IconButton,
|
|
455
|
+
{
|
|
456
|
+
size: "small",
|
|
457
|
+
onClick: (e) => {
|
|
458
|
+
e.stopPropagation();
|
|
459
|
+
openDonationSettings(true);
|
|
460
|
+
},
|
|
461
|
+
children: /* @__PURE__ */ jsx(Settings, { fontSize: "small", sx: { ml: -0.5 } })
|
|
462
|
+
}
|
|
463
|
+
) }),
|
|
464
|
+
!donation.data.livemode && /* @__PURE__ */ jsx(Livemode, { sx: { width: "fit-content", ml: 0.5 } })
|
|
392
465
|
] }),
|
|
393
466
|
maxWidth: "md",
|
|
394
467
|
toolbar: isMobile ? null : /* @__PURE__ */ jsxs(Box, { display: "flex", alignItems: "center", gap: 1, sx: { color: "text.secondary" }, children: [
|
|
@@ -430,7 +503,7 @@ function CheckoutDonateInner({
|
|
|
430
503
|
id: donation.data?.id,
|
|
431
504
|
onPaid: handlePaid,
|
|
432
505
|
onError,
|
|
433
|
-
action:
|
|
506
|
+
action: donateSettings.appearance?.button?.text,
|
|
434
507
|
mode: "inline",
|
|
435
508
|
theme,
|
|
436
509
|
formType: "donation",
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { TSetting } from '@blocklet/payment-types';
|
|
2
|
+
import type { Axios } from 'axios';
|
|
3
|
+
export interface DonateConfigSettings {
|
|
4
|
+
amount?: {
|
|
5
|
+
presets?: string[];
|
|
6
|
+
preset?: string;
|
|
7
|
+
custom: boolean;
|
|
8
|
+
minimum?: string;
|
|
9
|
+
maximum?: string;
|
|
10
|
+
};
|
|
11
|
+
btnText?: string;
|
|
12
|
+
historyType?: 'table' | 'avatar';
|
|
13
|
+
}
|
|
14
|
+
export type DonateContextType = {
|
|
15
|
+
settings: TSetting;
|
|
16
|
+
refresh: (forceRefresh?: boolean) => void;
|
|
17
|
+
updateSettings: (newSettings: DonateConfigSettings) => Promise<void>;
|
|
18
|
+
api: Axios;
|
|
19
|
+
};
|
|
20
|
+
export type DonateContextProps = {
|
|
21
|
+
mountLocation: string;
|
|
22
|
+
description: string;
|
|
23
|
+
defaultSettings?: DonateConfigSettings;
|
|
24
|
+
children: any;
|
|
25
|
+
active?: boolean;
|
|
26
|
+
enableDonate?: boolean;
|
|
27
|
+
};
|
|
28
|
+
declare const DonateContext: import("react").Context<DonateContextType>;
|
|
29
|
+
declare const Consumer: import("react").Consumer<DonateContextType>;
|
|
30
|
+
declare function DonateProvider({ mountLocation, description, defaultSettings, children, active, enableDonate, }: DonateContextProps): import("react").JSX.Element | null;
|
|
31
|
+
declare namespace DonateProvider {
|
|
32
|
+
var defaultProps: {
|
|
33
|
+
defaultSettings: {};
|
|
34
|
+
active: boolean;
|
|
35
|
+
enableDonate: boolean;
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
declare function useDonateContext(): DonateContextType;
|
|
39
|
+
export declare const clearDonateCache: (mountLocation: string) => void;
|
|
40
|
+
export declare const clearDonateSettings: (mountLocation: string) => Promise<void>;
|
|
41
|
+
export { DonateContext, DonateProvider, Consumer as DonateConsumer, useDonateContext };
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useRequest } from "ahooks";
|
|
3
|
+
import { createContext, useContext, useState } from "react";
|
|
4
|
+
import Toast from "@arcblock/ux/lib/Toast";
|
|
5
|
+
import { useLocaleContext } from "@arcblock/ux/lib/Locale/context";
|
|
6
|
+
import { Button, Stack, Typography } from "@mui/material";
|
|
7
|
+
import api from "../libs/api.js";
|
|
8
|
+
import { formatError, getPaymentKitComponent, openDonationSettings } from "../libs/util.js";
|
|
9
|
+
import { CachedRequest } from "../libs/cached-request.js";
|
|
10
|
+
import ConfirmDialog from "../components/confirm.js";
|
|
11
|
+
const DonateContext = createContext({ api });
|
|
12
|
+
const { Provider, Consumer } = DonateContext;
|
|
13
|
+
const fetchDonateSetting = (params, forceRefresh = false) => {
|
|
14
|
+
const livemode = localStorage.getItem("livemode") !== "false";
|
|
15
|
+
const cacheKey = `donate-settings-${params.mountLocation}-${livemode}`;
|
|
16
|
+
const cachedRequest = new CachedRequest(
|
|
17
|
+
cacheKey,
|
|
18
|
+
() => api.post("/api/settings", {
|
|
19
|
+
...params,
|
|
20
|
+
type: "donate",
|
|
21
|
+
livemode,
|
|
22
|
+
settings: params.defaultSettings
|
|
23
|
+
}),
|
|
24
|
+
{
|
|
25
|
+
ttl: 1e3 * 60 * 60,
|
|
26
|
+
strategy: "local"
|
|
27
|
+
}
|
|
28
|
+
);
|
|
29
|
+
return cachedRequest.fetch(forceRefresh);
|
|
30
|
+
};
|
|
31
|
+
function DonateProvider({
|
|
32
|
+
mountLocation,
|
|
33
|
+
description,
|
|
34
|
+
defaultSettings = {},
|
|
35
|
+
children,
|
|
36
|
+
active = true,
|
|
37
|
+
enableDonate = false
|
|
38
|
+
}) {
|
|
39
|
+
const { t } = useLocaleContext();
|
|
40
|
+
const [showConfirm, setShowConfirm] = useState(false);
|
|
41
|
+
const {
|
|
42
|
+
data = {
|
|
43
|
+
settings: {},
|
|
44
|
+
active: true
|
|
45
|
+
},
|
|
46
|
+
error,
|
|
47
|
+
run,
|
|
48
|
+
loading
|
|
49
|
+
} = useRequest(
|
|
50
|
+
(forceRender) => fetchDonateSetting(
|
|
51
|
+
{
|
|
52
|
+
mountLocation,
|
|
53
|
+
description,
|
|
54
|
+
defaultSettings,
|
|
55
|
+
active,
|
|
56
|
+
componentDid: window.blocklet?.componentId?.split("/").pop()
|
|
57
|
+
},
|
|
58
|
+
forceRender
|
|
59
|
+
),
|
|
60
|
+
{
|
|
61
|
+
refreshDeps: [mountLocation],
|
|
62
|
+
onError: (err) => {
|
|
63
|
+
Toast.error(formatError(err));
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
);
|
|
67
|
+
const updateSettings = async (newSettings) => {
|
|
68
|
+
try {
|
|
69
|
+
const livemode = localStorage.getItem("livemode") !== "false";
|
|
70
|
+
await api.put(`/api/settings/${mountLocation}`, {
|
|
71
|
+
livemode,
|
|
72
|
+
settings: newSettings
|
|
73
|
+
});
|
|
74
|
+
run(true);
|
|
75
|
+
Toast.success(t("common.saved"));
|
|
76
|
+
} catch (err) {
|
|
77
|
+
Toast.error(formatError(err));
|
|
78
|
+
throw err;
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
const supportPaymentKit = getPaymentKitComponent();
|
|
82
|
+
const handleEnable = async () => {
|
|
83
|
+
if (!enableDonate || !data || data?.active)
|
|
84
|
+
return;
|
|
85
|
+
try {
|
|
86
|
+
await api.put(`/api/settings/${data.id}`, { active: true });
|
|
87
|
+
if (supportPaymentKit) {
|
|
88
|
+
setShowConfirm(true);
|
|
89
|
+
} else {
|
|
90
|
+
Toast.success(t("payment.checkout.donation.enableSuccess"));
|
|
91
|
+
run(true);
|
|
92
|
+
}
|
|
93
|
+
} catch (err) {
|
|
94
|
+
Toast.error(formatError(err));
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
if (loading || error) {
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
return /* @__PURE__ */ jsx(
|
|
101
|
+
Provider,
|
|
102
|
+
{
|
|
103
|
+
value: {
|
|
104
|
+
settings: data,
|
|
105
|
+
refresh: run,
|
|
106
|
+
updateSettings,
|
|
107
|
+
api
|
|
108
|
+
},
|
|
109
|
+
children: data?.active === false ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
110
|
+
enableDonate && /* @__PURE__ */ jsxs(Stack, { spacing: 1, sx: { p: 2, bgcolor: "background.neutral", borderRadius: 1 }, children: [
|
|
111
|
+
/* @__PURE__ */ jsx(Typography, { color: "text.secondary", children: t("payment.checkout.donation.inactive") }),
|
|
112
|
+
/* @__PURE__ */ jsx(Button, { size: "small", variant: "outlined", color: "primary", onClick: handleEnable, children: t("payment.checkout.donation.enable") })
|
|
113
|
+
] }),
|
|
114
|
+
showConfirm && /* @__PURE__ */ jsx(
|
|
115
|
+
ConfirmDialog,
|
|
116
|
+
{
|
|
117
|
+
title: t("payment.checkout.donation.enableSuccess"),
|
|
118
|
+
message: t("payment.checkout.donation.configPrompt"),
|
|
119
|
+
cancel: t("payment.checkout.donation.later"),
|
|
120
|
+
confirm: t("payment.checkout.donation.configNow"),
|
|
121
|
+
onCancel: () => {
|
|
122
|
+
setShowConfirm(false);
|
|
123
|
+
run(true);
|
|
124
|
+
},
|
|
125
|
+
color: "primary",
|
|
126
|
+
onConfirm: () => {
|
|
127
|
+
run(true);
|
|
128
|
+
openDonationSettings(false);
|
|
129
|
+
setShowConfirm(false);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
)
|
|
133
|
+
] }) : children
|
|
134
|
+
}
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
function useDonateContext() {
|
|
138
|
+
const context = useContext(DonateContext);
|
|
139
|
+
return context;
|
|
140
|
+
}
|
|
141
|
+
DonateProvider.defaultProps = {
|
|
142
|
+
defaultSettings: {},
|
|
143
|
+
active: true,
|
|
144
|
+
enableDonate: false
|
|
145
|
+
};
|
|
146
|
+
export const clearDonateCache = (mountLocation) => {
|
|
147
|
+
const livemode = localStorage.getItem("livemode") !== "false";
|
|
148
|
+
const cacheKey = `donate-settings-${mountLocation}-${livemode}`;
|
|
149
|
+
localStorage.removeItem(cacheKey);
|
|
150
|
+
};
|
|
151
|
+
export const clearDonateSettings = async (mountLocation) => {
|
|
152
|
+
try {
|
|
153
|
+
const livemode = localStorage.getItem("livemode") !== "false";
|
|
154
|
+
await api.delete(`/api/settings/${mountLocation}`, {
|
|
155
|
+
params: {
|
|
156
|
+
livemode
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
clearDonateCache(mountLocation);
|
|
160
|
+
} catch (err) {
|
|
161
|
+
Toast.error(formatError(err));
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
export { DonateContext, DonateProvider, Consumer as DonateConsumer, useDonateContext };
|
package/es/contexts/payment.js
CHANGED
|
@@ -4,27 +4,14 @@ import { useLocalStorageState, useRequest } from "ahooks";
|
|
|
4
4
|
import { createContext, useContext, useState } from "react";
|
|
5
5
|
import api from "../libs/api.js";
|
|
6
6
|
import { getPrefix } from "../libs/util.js";
|
|
7
|
+
import { CachedRequest } from "../libs/cached-request.js";
|
|
7
8
|
const PaymentContext = createContext({ api });
|
|
8
9
|
const { Provider, Consumer } = PaymentContext;
|
|
9
|
-
let settingsPromise = null;
|
|
10
10
|
const getSettings = (forceRefresh = false) => {
|
|
11
11
|
const livemode = localStorage.getItem("livemode") !== "false";
|
|
12
12
|
const cacheKey = `payment-settings-${window.location.pathname}-${livemode}`;
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
return JSON.parse(cachedData);
|
|
16
|
-
}
|
|
17
|
-
if (!settingsPromise) {
|
|
18
|
-
settingsPromise = api.get("/api/settings", { params: { livemode } }).then(({ data }) => {
|
|
19
|
-
sessionStorage.setItem(cacheKey, JSON.stringify(data));
|
|
20
|
-
return data;
|
|
21
|
-
}).catch((error) => {
|
|
22
|
-
throw error;
|
|
23
|
-
}).finally(() => {
|
|
24
|
-
settingsPromise = null;
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
return settingsPromise;
|
|
13
|
+
const cachedRequest = new CachedRequest(cacheKey, () => api.get("/api/settings", { params: { livemode } }));
|
|
14
|
+
return cachedRequest.fetch(forceRefresh);
|
|
28
15
|
};
|
|
29
16
|
const getCurrency = (currencyId, methods) => {
|
|
30
17
|
const currencies = methods.reduce((acc, x) => acc.concat(x.payment_currencies), []);
|
package/es/index.d.ts
CHANGED
|
@@ -34,7 +34,9 @@ export { PaymentThemeProvider } from './theme';
|
|
|
34
34
|
export * from './libs/util';
|
|
35
35
|
export * from './libs/connect';
|
|
36
36
|
export * from './libs/phone-validator';
|
|
37
|
+
export * from './libs/cached-request';
|
|
37
38
|
export * from './contexts/payment';
|
|
39
|
+
export * from './contexts/donate';
|
|
38
40
|
export * from './hooks/subscription';
|
|
39
41
|
export * from './hooks/mobile';
|
|
40
42
|
export * from './hooks/table';
|
package/es/index.js
CHANGED
|
@@ -34,7 +34,9 @@ export { PaymentThemeProvider } from "./theme/index.js";
|
|
|
34
34
|
export * from "./libs/util.js";
|
|
35
35
|
export * from "./libs/connect.js";
|
|
36
36
|
export * from "./libs/phone-validator.js";
|
|
37
|
+
export * from "./libs/cached-request.js";
|
|
37
38
|
export * from "./contexts/payment.js";
|
|
39
|
+
export * from "./contexts/donate.js";
|
|
38
40
|
export * from "./hooks/subscription.js";
|
|
39
41
|
export * from "./hooks/mobile.js";
|
|
40
42
|
export * from "./hooks/table.js";
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
type CacheItem = {
|
|
2
|
+
promise: Promise<any> | null;
|
|
3
|
+
};
|
|
4
|
+
declare class GlobalCacheManager {
|
|
5
|
+
private static instance;
|
|
6
|
+
private cacheMap;
|
|
7
|
+
private constructor();
|
|
8
|
+
static getInstance(): GlobalCacheManager;
|
|
9
|
+
get(cacheKey: string): CacheItem | undefined;
|
|
10
|
+
set(cacheKey: string, item: CacheItem): void;
|
|
11
|
+
delete(cacheKey: string): void;
|
|
12
|
+
}
|
|
13
|
+
export declare const globalCache: GlobalCacheManager;
|
|
14
|
+
export {};
|
package/es/libs/cache.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
class GlobalCacheManager {
|
|
2
|
+
static instance;
|
|
3
|
+
cacheMap;
|
|
4
|
+
constructor() {
|
|
5
|
+
this.cacheMap = /* @__PURE__ */ new Map();
|
|
6
|
+
}
|
|
7
|
+
static getInstance() {
|
|
8
|
+
if (!GlobalCacheManager.instance) {
|
|
9
|
+
GlobalCacheManager.instance = new GlobalCacheManager();
|
|
10
|
+
}
|
|
11
|
+
return GlobalCacheManager.instance;
|
|
12
|
+
}
|
|
13
|
+
get(cacheKey) {
|
|
14
|
+
return this.cacheMap.get(cacheKey);
|
|
15
|
+
}
|
|
16
|
+
set(cacheKey, item) {
|
|
17
|
+
this.cacheMap.set(cacheKey, item);
|
|
18
|
+
}
|
|
19
|
+
delete(cacheKey) {
|
|
20
|
+
this.cacheMap.delete(cacheKey);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export const globalCache = GlobalCacheManager.getInstance();
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
type CacheStrategy = 'session' | 'local' | 'memory';
|
|
2
|
+
interface CacheOptions {
|
|
3
|
+
strategy?: CacheStrategy;
|
|
4
|
+
ttl?: number;
|
|
5
|
+
}
|
|
6
|
+
export declare class CachedRequest {
|
|
7
|
+
private cacheKey;
|
|
8
|
+
private fetchData;
|
|
9
|
+
private options;
|
|
10
|
+
constructor(cacheKey: string, fetchData: () => Promise<any>, options?: CacheOptions);
|
|
11
|
+
private getCache;
|
|
12
|
+
private getCachedData;
|
|
13
|
+
private setCachedData;
|
|
14
|
+
private clearCache;
|
|
15
|
+
fetch(forceRefresh?: boolean): Promise<any>;
|
|
16
|
+
}
|
|
17
|
+
export {};
|