@blocklet/payment-react 1.19.17 → 1.19.19

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.
Files changed (55) hide show
  1. package/README.md +313 -0
  2. package/es/checkout/form.js +2 -2
  3. package/es/components/auto-topup/index.d.ts +14 -0
  4. package/es/components/auto-topup/index.js +417 -0
  5. package/es/components/auto-topup/modal.d.ts +35 -0
  6. package/es/components/auto-topup/modal.js +734 -0
  7. package/es/components/auto-topup/product-card.d.ts +13 -0
  8. package/es/components/auto-topup/product-card.js +173 -0
  9. package/es/components/collapse.d.ts +13 -0
  10. package/es/components/collapse.js +76 -0
  11. package/es/components/input.d.ts +2 -1
  12. package/es/components/input.js +64 -13
  13. package/es/components/label.d.ts +2 -1
  14. package/es/components/label.js +2 -1
  15. package/es/index.d.ts +4 -1
  16. package/es/index.js +7 -1
  17. package/es/libs/util.js +2 -1
  18. package/es/locales/en.js +56 -0
  19. package/es/locales/zh.js +56 -0
  20. package/es/payment/form/index.js +6 -0
  21. package/es/payment/product-item.js +19 -12
  22. package/lib/checkout/form.js +2 -2
  23. package/lib/components/auto-topup/index.d.ts +14 -0
  24. package/lib/components/auto-topup/index.js +451 -0
  25. package/lib/components/auto-topup/modal.d.ts +35 -0
  26. package/lib/components/auto-topup/modal.js +803 -0
  27. package/lib/components/auto-topup/product-card.d.ts +13 -0
  28. package/lib/components/auto-topup/product-card.js +149 -0
  29. package/lib/components/collapse.d.ts +13 -0
  30. package/lib/components/collapse.js +74 -0
  31. package/lib/components/input.d.ts +2 -1
  32. package/lib/components/input.js +66 -24
  33. package/lib/components/label.d.ts +2 -1
  34. package/lib/components/label.js +3 -1
  35. package/lib/index.d.ts +4 -1
  36. package/lib/index.js +24 -0
  37. package/lib/libs/util.js +2 -1
  38. package/lib/locales/en.js +56 -0
  39. package/lib/locales/zh.js +56 -0
  40. package/lib/payment/form/index.js +6 -0
  41. package/lib/payment/product-item.js +21 -12
  42. package/package.json +9 -9
  43. package/src/checkout/form.tsx +2 -2
  44. package/src/components/auto-topup/index.tsx +449 -0
  45. package/src/components/auto-topup/modal.tsx +773 -0
  46. package/src/components/auto-topup/product-card.tsx +156 -0
  47. package/src/components/collapse.tsx +82 -0
  48. package/src/components/input.tsx +71 -22
  49. package/src/components/label.tsx +8 -2
  50. package/src/index.ts +7 -0
  51. package/src/libs/util.ts +1 -0
  52. package/src/locales/en.tsx +59 -0
  53. package/src/locales/zh.tsx +57 -0
  54. package/src/payment/form/index.tsx +6 -0
  55. package/src/payment/product-item.tsx +20 -13
@@ -0,0 +1,417 @@
1
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
+ import { useState, useCallback } from "react";
3
+ import {
4
+ Box,
5
+ Typography,
6
+ Stack,
7
+ Button,
8
+ CircularProgress,
9
+ Card,
10
+ CardContent,
11
+ IconButton,
12
+ Tooltip,
13
+ Collapse
14
+ } from "@mui/material";
15
+ import { AddOutlined, CreditCard, SettingsOutlined, AccountBalanceWalletOutlined } from "@mui/icons-material";
16
+ import { useLocaleContext } from "@arcblock/ux/lib/Locale/context";
17
+ import { useNavigate } from "react-router-dom";
18
+ import { joinURL } from "ufo";
19
+ import { useRequest } from "ahooks";
20
+ import { getPrefix, formatBNStr, formatNumber, formatPrice } from "../../libs/util.js";
21
+ import { createLink, handleNavigation } from "../../libs/navigation.js";
22
+ import { usePaymentContext } from "../../contexts/payment.js";
23
+ import api from "../../libs/api.js";
24
+ import AutoTopupModal from "./modal.js";
25
+ const fetchConfig = async (customerId, currencyId) => {
26
+ const { data } = await api.get(`/api/auto-recharge-configs/customer/${customerId}`, {
27
+ params: { currency_id: currencyId }
28
+ });
29
+ return data;
30
+ };
31
+ const fetchCurrencyBalance = async (currencyId, payerAddress) => {
32
+ const { data } = await api.get("/api/customers/payer-token", {
33
+ params: { currencyId, payerAddress }
34
+ });
35
+ return data;
36
+ };
37
+ const cardStyle = {
38
+ height: "100%",
39
+ width: "100%",
40
+ border: "1px solid",
41
+ borderColor: "divider",
42
+ boxShadow: 1,
43
+ borderRadius: 1,
44
+ backgroundColor: "background.default"
45
+ };
46
+ export default function AutoTopupCard({
47
+ currencyId,
48
+ onConfigChange = () => {
49
+ },
50
+ sx = {},
51
+ mode = "default",
52
+ children = void 0
53
+ }) {
54
+ const { t } = useLocaleContext();
55
+ const navigate = useNavigate();
56
+ const { session } = usePaymentContext();
57
+ const [modalOpen, setModalOpen] = useState(false);
58
+ const [paymentData, setPaymentData] = useState(null);
59
+ const [quickSetupMode, setQuickSetupMode] = useState(false);
60
+ const [expanded, setExpanded] = useState(mode === "default");
61
+ const customerId = session?.user?.did || "";
62
+ const {
63
+ data: config,
64
+ loading,
65
+ refresh
66
+ } = useRequest(() => fetchConfig(customerId, currencyId), {
67
+ refreshDeps: [customerId, currencyId],
68
+ ready: !!customerId && !!currencyId,
69
+ onSuccess: (data) => {
70
+ loadPaymentInfo(data);
71
+ }
72
+ });
73
+ const loadPaymentInfo = useCallback(async (data) => {
74
+ if (!data?.recharge_currency_id) return;
75
+ try {
76
+ const paymentMethodType = data?.paymentMethod?.type;
77
+ const paymentInfo = data?.payment_settings?.payment_method_options?.[paymentMethodType];
78
+ const balanceInfo = paymentInfo?.payer && paymentMethodType !== "stripe" ? await fetchCurrencyBalance(data.recharge_currency_id, paymentInfo.payer) : null;
79
+ setPaymentData({
80
+ paymentInfo,
81
+ balanceInfo
82
+ });
83
+ } catch (error) {
84
+ console.error("Failed to load payment info:", error);
85
+ }
86
+ }, []);
87
+ const handleRecharge = (e) => {
88
+ if (!paymentData?.paymentInfo?.payer) return;
89
+ const url = joinURL(
90
+ getPrefix(),
91
+ `/customer/recharge/${config?.recharge_currency_id}?rechargeAddress=${paymentData.paymentInfo.payer}`
92
+ );
93
+ const link = createLink(url, true);
94
+ handleNavigation(e, link, navigate);
95
+ };
96
+ const handleConfigSuccess = (newConfig) => {
97
+ refresh();
98
+ onConfigChange?.(newConfig);
99
+ setModalOpen(false);
100
+ setQuickSetupMode(false);
101
+ };
102
+ const handleToggleExpanded = () => {
103
+ setExpanded(!expanded);
104
+ };
105
+ if (loading) {
106
+ return /* @__PURE__ */ jsx(Card, { sx: { ...cardStyle, ...sx }, children: /* @__PURE__ */ jsx(CardContent, { children: /* @__PURE__ */ jsx(Box, { sx: { display: "flex", justifyContent: "center", alignItems: "center", minHeight: 80 }, children: /* @__PURE__ */ jsx(CircularProgress, { size: 24 }) }) }) });
107
+ }
108
+ if (!config) {
109
+ return null;
110
+ }
111
+ const renderPurchaseDetails = () => {
112
+ const { paymentInfo, balanceInfo } = paymentData || {};
113
+ if (!paymentInfo) {
114
+ return /* @__PURE__ */ jsx(
115
+ Typography,
116
+ {
117
+ variant: "body2",
118
+ sx: {
119
+ color: "text.secondary"
120
+ },
121
+ children: t("payment.autoTopup.notConfigured")
122
+ }
123
+ );
124
+ }
125
+ const purchaseAmount = formatPrice(
126
+ config.price,
127
+ config.rechargeCurrency,
128
+ config.price.product?.unit_label,
129
+ config.quantity,
130
+ true
131
+ );
132
+ if (config?.paymentMethod?.type === "stripe") {
133
+ const cardBrand = (paymentInfo?.card_brand || "Card").charAt(0).toUpperCase() + (paymentInfo?.card_brand || "Card").slice(1).toLowerCase();
134
+ const last4 = paymentInfo?.card_last4;
135
+ return /* @__PURE__ */ jsxs(Stack, { spacing: 1, children: [
136
+ /* @__PURE__ */ jsxs(Box, { sx: { display: "flex", alignItems: "center", gap: 0.5 }, children: [
137
+ /* @__PURE__ */ jsxs(
138
+ Typography,
139
+ {
140
+ variant: "body2",
141
+ sx: {
142
+ color: "text.secondary"
143
+ },
144
+ children: [
145
+ t("payment.autoTopup.purchaseAmount"),
146
+ "\uFF1A"
147
+ ]
148
+ }
149
+ ),
150
+ /* @__PURE__ */ jsx(Typography, { variant: "body2", sx: { fontWeight: 600, color: "text.primary" }, children: purchaseAmount })
151
+ ] }),
152
+ /* @__PURE__ */ jsxs(Box, { sx: { display: "flex", alignItems: "center", gap: 0.5 }, children: [
153
+ /* @__PURE__ */ jsxs(
154
+ Typography,
155
+ {
156
+ variant: "body2",
157
+ sx: {
158
+ color: "text.secondary"
159
+ },
160
+ children: [
161
+ t("payment.autoTopup.paymentMethod"),
162
+ "\uFF1A"
163
+ ]
164
+ }
165
+ ),
166
+ /* @__PURE__ */ jsxs(
167
+ Stack,
168
+ {
169
+ direction: "row",
170
+ spacing: 1,
171
+ sx: {
172
+ alignItems: "center"
173
+ },
174
+ children: [
175
+ /* @__PURE__ */ jsx(CreditCard, { fontSize: "small", sx: { color: "text.secondary" } }),
176
+ /* @__PURE__ */ jsxs(Typography, { variant: "body2", sx: { color: "text.primary", fontWeight: 500 }, children: [
177
+ cardBrand,
178
+ "(",
179
+ last4,
180
+ ")"
181
+ ] })
182
+ ]
183
+ }
184
+ )
185
+ ] })
186
+ ] });
187
+ }
188
+ return /* @__PURE__ */ jsxs(Stack, { spacing: 1, children: [
189
+ /* @__PURE__ */ jsxs(Box, { sx: { display: "flex", alignItems: "center", gap: 0.5 }, children: [
190
+ /* @__PURE__ */ jsxs(
191
+ Typography,
192
+ {
193
+ variant: "body2",
194
+ sx: {
195
+ color: "text.secondary"
196
+ },
197
+ children: [
198
+ t("payment.autoTopup.purchaseAmount"),
199
+ "\uFF1A"
200
+ ]
201
+ }
202
+ ),
203
+ /* @__PURE__ */ jsx(Typography, { variant: "body2", sx: { fontWeight: 600, color: "text.primary" }, children: purchaseAmount })
204
+ ] }),
205
+ /* @__PURE__ */ jsx(Box, { sx: { display: "flex", alignItems: "center", justifyContent: "space-between" }, children: /* @__PURE__ */ jsxs(Box, { sx: { display: "flex", alignItems: "center", gap: 0.5 }, children: [
206
+ /* @__PURE__ */ jsxs(
207
+ Typography,
208
+ {
209
+ variant: "body2",
210
+ sx: {
211
+ color: "text.secondary"
212
+ },
213
+ children: [
214
+ t("payment.autoTopup.walletBalance"),
215
+ "\uFF1A"
216
+ ]
217
+ }
218
+ ),
219
+ /* @__PURE__ */ jsx(
220
+ Tooltip,
221
+ {
222
+ title: paymentInfo?.payer ? `${t("payment.autoTopup.paymentAddress")}: ${paymentInfo.payer}` : "",
223
+ placement: "top",
224
+ children: /* @__PURE__ */ jsxs(Box, { sx: { display: "flex", alignItems: "center", gap: 0.5 }, children: [
225
+ /* @__PURE__ */ jsx(AccountBalanceWalletOutlined, { sx: { fontSize: 16, color: "text.secondary" } }),
226
+ /* @__PURE__ */ jsx(Typography, { variant: "body2", sx: { fontWeight: 600, color: "text.primary" }, children: balanceInfo ? `${formatBNStr(balanceInfo?.token || "0", config?.rechargeCurrency?.decimal || 18)} ${config?.rechargeCurrency?.symbol || ""}` : "--" })
227
+ ] })
228
+ }
229
+ ),
230
+ balanceInfo && /* @__PURE__ */ jsxs(
231
+ Button,
232
+ {
233
+ size: "small",
234
+ variant: "text",
235
+ onClick: handleRecharge,
236
+ sx: {
237
+ color: "primary.main",
238
+ display: "flex",
239
+ alignItems: "center"
240
+ },
241
+ children: [
242
+ /* @__PURE__ */ jsx(AddOutlined, { fontSize: "small" }),
243
+ t("payment.autoTopup.addFunds")
244
+ ]
245
+ }
246
+ )
247
+ ] }) })
248
+ ] });
249
+ };
250
+ const openModal = () => setModalOpen(true);
251
+ const renderInnerView = () => {
252
+ if (mode === "custom") {
253
+ return children && typeof children === "function" ? /* @__PURE__ */ jsx(Fragment, { children: children(openModal, config, paymentData, loading) }) : /* @__PURE__ */ jsxs(Typography, { children: [
254
+ "Please provide a valid render function",
255
+ /* @__PURE__ */ jsx("pre", { children: "(openModal, config, paymentData, loading) => ReactNode" })
256
+ ] });
257
+ }
258
+ return /* @__PURE__ */ jsx(Card, { sx: { ...cardStyle, ...sx }, children: /* @__PURE__ */ jsxs(CardContent, { children: [
259
+ /* @__PURE__ */ jsxs(
260
+ Stack,
261
+ {
262
+ direction: "row",
263
+ className: "auto-topup-header",
264
+ sx: {
265
+ justifyContent: "space-between",
266
+ alignItems: "center",
267
+ borderBottom: "1px solid",
268
+ borderColor: "divider",
269
+ pb: 1.5
270
+ },
271
+ children: [
272
+ /* @__PURE__ */ jsx(Typography, { variant: "subtitle2", sx: { fontWeight: 600, color: "text.primary" }, children: t("payment.autoTopup.title") }),
273
+ /* @__PURE__ */ jsx(Box, { sx: { display: "flex", alignItems: "center", gap: 0.5 }, children: /* @__PURE__ */ jsx(
274
+ IconButton,
275
+ {
276
+ size: "small",
277
+ onClick: openModal,
278
+ sx: {
279
+ p: 0.5,
280
+ color: "text.secondary",
281
+ "&:hover": {
282
+ bgcolor: "grey.50",
283
+ color: "text.primary"
284
+ }
285
+ },
286
+ children: /* @__PURE__ */ jsx(SettingsOutlined, { fontSize: "small" })
287
+ }
288
+ ) })
289
+ ]
290
+ }
291
+ ),
292
+ config?.enabled ? /* @__PURE__ */ jsxs(Stack, { spacing: 1.5, className: "auto-topup-content", sx: { pt: 1.5 }, children: [
293
+ (() => {
294
+ const threshold = `${formatNumber(config.threshold)} ${config.currency?.symbol || ""}`;
295
+ const credits = `${formatNumber(
296
+ Number(config.price.metadata?.credit_config?.credit_amount || 0) * Number(config.quantity)
297
+ )} ${config.currency?.name || ""}`;
298
+ return /* @__PURE__ */ jsxs(
299
+ Typography,
300
+ {
301
+ variant: "body2",
302
+ sx: {
303
+ color: "text.secondary"
304
+ },
305
+ children: [
306
+ t("payment.autoTopup.activeDescriptionWithCredits", { threshold, credits }),
307
+ mode === "simple" && /* @__PURE__ */ jsx(
308
+ Button,
309
+ {
310
+ component: "span",
311
+ size: "small",
312
+ variant: "text",
313
+ onClick: handleToggleExpanded,
314
+ sx: {
315
+ color: "primary.main",
316
+ minWidth: "auto",
317
+ ml: 1,
318
+ p: 0,
319
+ fontSize: "inherit",
320
+ textTransform: "none",
321
+ "&:hover": {
322
+ backgroundColor: "transparent",
323
+ textDecoration: "underline"
324
+ }
325
+ },
326
+ children: expanded ? t("payment.autoTopup.hideDetails") : t("payment.autoTopup.showDetails")
327
+ }
328
+ )
329
+ ]
330
+ }
331
+ );
332
+ })(),
333
+ /* @__PURE__ */ jsx(Collapse, { in: mode === "default" || expanded, children: /* @__PURE__ */ jsx(
334
+ Box,
335
+ {
336
+ sx: {
337
+ bgcolor: "grey.50",
338
+ borderRadius: 1,
339
+ p: 1.5
340
+ },
341
+ children: renderPurchaseDetails()
342
+ }
343
+ ) })
344
+ ] }) : /* @__PURE__ */ jsx(
345
+ Stack,
346
+ {
347
+ className: "auto-topup-content",
348
+ sx: {
349
+ minHeight: 80,
350
+ display: "flex",
351
+ flexDirection: "column",
352
+ alignItems: "center",
353
+ justifyContent: "center",
354
+ pt: 1.5,
355
+ gap: 2
356
+ },
357
+ children: /* @__PURE__ */ jsxs(
358
+ Typography,
359
+ {
360
+ variant: "body2",
361
+ sx: {
362
+ color: "text.secondary",
363
+ textAlign: "left"
364
+ },
365
+ children: [
366
+ t("payment.autoTopup.inactiveDescription", {
367
+ name: config?.currency?.name
368
+ }),
369
+ /* @__PURE__ */ jsx(
370
+ Button,
371
+ {
372
+ component: "span",
373
+ variant: "text",
374
+ size: "small",
375
+ onClick: () => {
376
+ setQuickSetupMode(true);
377
+ setModalOpen(true);
378
+ },
379
+ sx: {
380
+ color: "primary.main",
381
+ minWidth: "auto",
382
+ ml: 1,
383
+ p: 0,
384
+ fontSize: "inherit",
385
+ textTransform: "none",
386
+ "&:hover": {
387
+ backgroundColor: "transparent",
388
+ textDecoration: "underline"
389
+ }
390
+ },
391
+ children: t("payment.autoTopup.setup")
392
+ }
393
+ )
394
+ ]
395
+ }
396
+ )
397
+ }
398
+ )
399
+ ] }) });
400
+ };
401
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
402
+ renderInnerView(),
403
+ modalOpen && /* @__PURE__ */ jsx(
404
+ AutoTopupModal,
405
+ {
406
+ open: modalOpen,
407
+ onClose: () => {
408
+ setModalOpen(false);
409
+ setQuickSetupMode(false);
410
+ },
411
+ currencyId,
412
+ onSuccess: handleConfigSuccess,
413
+ defaultEnabled: quickSetupMode
414
+ }
415
+ )
416
+ ] });
417
+ }
@@ -0,0 +1,35 @@
1
+ import type { AutoRechargeConfig } from '@blocklet/payment-types';
2
+ export interface AutoTopupFormData {
3
+ enabled: boolean;
4
+ threshold: string;
5
+ quantity: number;
6
+ payment_method_id: string;
7
+ recharge_currency_id: string;
8
+ price_id: string;
9
+ change_payment_method?: boolean;
10
+ customer_name?: string;
11
+ customer_email?: string;
12
+ daily_limits: {
13
+ max_attempts: number;
14
+ max_amount: number;
15
+ };
16
+ billing_address?: {
17
+ country?: string;
18
+ state?: string;
19
+ line1?: string;
20
+ line2?: string;
21
+ city?: string;
22
+ postal_code?: string;
23
+ };
24
+ }
25
+ export interface AutoTopupModalProps {
26
+ open: boolean;
27
+ onClose: () => void;
28
+ customerId?: string;
29
+ currencyId: string;
30
+ onSuccess?: (config: AutoRechargeConfig) => void;
31
+ onError?: (error: any) => void;
32
+ defaultEnabled?: boolean;
33
+ }
34
+ export declare const waitForAutoRechargeComplete: (configId: string) => Promise<any>;
35
+ export default function AutoTopup({ open, onClose, currencyId, onSuccess, onError, defaultEnabled, }: AutoTopupModalProps): JSX.Element;