@blocklet/payment-react 1.25.10 → 1.26.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.
Files changed (160) hide show
  1. package/es/checkout-v2/checkout-v2.d.ts +2 -0
  2. package/es/checkout-v2/checkout-v2.js +121 -0
  3. package/es/checkout-v2/components/dialogs/checkout-dialogs.d.ts +1 -0
  4. package/es/checkout-v2/components/dialogs/checkout-dialogs.js +106 -0
  5. package/es/checkout-v2/components/left/billing-toggle.d.ts +6 -0
  6. package/es/checkout-v2/components/left/billing-toggle.js +118 -0
  7. package/es/checkout-v2/components/left/cross-sell-card.d.ts +10 -0
  8. package/es/checkout-v2/components/left/cross-sell-card.js +167 -0
  9. package/es/checkout-v2/components/left/product-item-card.d.ts +26 -0
  10. package/es/checkout-v2/components/left/product-item-card.js +571 -0
  11. package/es/checkout-v2/components/left/promotion-input.d.ts +19 -0
  12. package/es/checkout-v2/components/left/promotion-input.js +178 -0
  13. package/es/checkout-v2/components/left/staking-breakdown.d.ts +9 -0
  14. package/es/checkout-v2/components/left/staking-breakdown.js +48 -0
  15. package/es/checkout-v2/components/left/trial-info.d.ts +13 -0
  16. package/es/checkout-v2/components/left/trial-info.js +48 -0
  17. package/es/checkout-v2/components/right/currency-grid.d.ts +8 -0
  18. package/es/checkout-v2/components/right/currency-grid.js +48 -0
  19. package/es/checkout-v2/components/right/customer-info-card.d.ts +17 -0
  20. package/es/checkout-v2/components/right/customer-info-card.js +156 -0
  21. package/es/checkout-v2/components/right/status-feedback.d.ts +7 -0
  22. package/es/checkout-v2/components/right/status-feedback.js +17 -0
  23. package/es/checkout-v2/components/right/submit-button.d.ts +10 -0
  24. package/es/checkout-v2/components/right/submit-button.js +29 -0
  25. package/es/checkout-v2/components/right/subscription-disclaimer.d.ts +11 -0
  26. package/es/checkout-v2/components/right/subscription-disclaimer.js +8 -0
  27. package/es/checkout-v2/components/shared/exchange-rate-footer.d.ts +23 -0
  28. package/es/checkout-v2/components/shared/exchange-rate-footer.js +182 -0
  29. package/es/checkout-v2/components/shared/scenario-badge.d.ts +6 -0
  30. package/es/checkout-v2/components/shared/scenario-badge.js +47 -0
  31. package/es/checkout-v2/components/shared/total-display.d.ts +7 -0
  32. package/es/checkout-v2/components/shared/total-display.js +84 -0
  33. package/es/checkout-v2/index.d.ts +2 -0
  34. package/es/checkout-v2/index.js +1 -0
  35. package/es/checkout-v2/layouts/checkout-layout.d.ts +7 -0
  36. package/es/checkout-v2/layouts/checkout-layout.js +226 -0
  37. package/es/checkout-v2/panels/left/composite-panel.d.ts +1 -0
  38. package/es/checkout-v2/panels/left/composite-panel.js +423 -0
  39. package/es/checkout-v2/panels/left/credit-topup-panel.d.ts +1 -0
  40. package/es/checkout-v2/panels/left/credit-topup-panel.js +611 -0
  41. package/es/checkout-v2/panels/left/scenario-router.d.ts +1 -0
  42. package/es/checkout-v2/panels/left/scenario-router.js +19 -0
  43. package/es/checkout-v2/panels/right/payment-panel.d.ts +1 -0
  44. package/es/checkout-v2/panels/right/payment-panel.js +644 -0
  45. package/es/checkout-v2/types.d.ts +15 -0
  46. package/es/checkout-v2/types.js +0 -0
  47. package/es/checkout-v2/utils/format.d.ts +59 -0
  48. package/es/checkout-v2/utils/format.js +125 -0
  49. package/es/checkout-v2/utils/scenario-detector.d.ts +3 -0
  50. package/es/checkout-v2/utils/scenario-detector.js +17 -0
  51. package/es/checkout-v2/views/error-view.d.ts +7 -0
  52. package/es/checkout-v2/views/error-view.js +269 -0
  53. package/es/checkout-v2/views/loading-view.d.ts +5 -0
  54. package/es/checkout-v2/views/loading-view.js +158 -0
  55. package/es/checkout-v2/views/success-view.d.ts +29 -0
  56. package/es/checkout-v2/views/success-view.js +614 -0
  57. package/es/components/phone-field.d.ts +14 -0
  58. package/es/components/phone-field.js +96 -0
  59. package/es/index.d.ts +3 -1
  60. package/es/index.js +3 -1
  61. package/es/locales/en.js +45 -6
  62. package/es/locales/zh.js +45 -6
  63. package/es/payment/form/index.js +10 -1
  64. package/lib/checkout-v2/checkout-v2.d.ts +2 -0
  65. package/lib/checkout-v2/checkout-v2.js +151 -0
  66. package/lib/checkout-v2/components/dialogs/checkout-dialogs.d.ts +1 -0
  67. package/lib/checkout-v2/components/dialogs/checkout-dialogs.js +131 -0
  68. package/lib/checkout-v2/components/left/billing-toggle.d.ts +6 -0
  69. package/lib/checkout-v2/components/left/billing-toggle.js +126 -0
  70. package/lib/checkout-v2/components/left/cross-sell-card.d.ts +10 -0
  71. package/lib/checkout-v2/components/left/cross-sell-card.js +257 -0
  72. package/lib/checkout-v2/components/left/product-item-card.d.ts +26 -0
  73. package/lib/checkout-v2/components/left/product-item-card.js +738 -0
  74. package/lib/checkout-v2/components/left/promotion-input.d.ts +19 -0
  75. package/lib/checkout-v2/components/left/promotion-input.js +220 -0
  76. package/lib/checkout-v2/components/left/staking-breakdown.d.ts +9 -0
  77. package/lib/checkout-v2/components/left/staking-breakdown.js +96 -0
  78. package/lib/checkout-v2/components/left/trial-info.d.ts +13 -0
  79. package/lib/checkout-v2/components/left/trial-info.js +82 -0
  80. package/lib/checkout-v2/components/right/currency-grid.d.ts +8 -0
  81. package/lib/checkout-v2/components/right/currency-grid.js +96 -0
  82. package/lib/checkout-v2/components/right/customer-info-card.d.ts +17 -0
  83. package/lib/checkout-v2/components/right/customer-info-card.js +246 -0
  84. package/lib/checkout-v2/components/right/status-feedback.d.ts +7 -0
  85. package/lib/checkout-v2/components/right/status-feedback.js +30 -0
  86. package/lib/checkout-v2/components/right/submit-button.d.ts +10 -0
  87. package/lib/checkout-v2/components/right/submit-button.js +35 -0
  88. package/lib/checkout-v2/components/right/subscription-disclaimer.d.ts +11 -0
  89. package/lib/checkout-v2/components/right/subscription-disclaimer.js +33 -0
  90. package/lib/checkout-v2/components/shared/exchange-rate-footer.d.ts +23 -0
  91. package/lib/checkout-v2/components/shared/exchange-rate-footer.js +282 -0
  92. package/lib/checkout-v2/components/shared/scenario-badge.d.ts +6 -0
  93. package/lib/checkout-v2/components/shared/scenario-badge.js +57 -0
  94. package/lib/checkout-v2/components/shared/total-display.d.ts +7 -0
  95. package/lib/checkout-v2/components/shared/total-display.js +154 -0
  96. package/lib/checkout-v2/index.d.ts +2 -0
  97. package/lib/checkout-v2/index.js +13 -0
  98. package/lib/checkout-v2/layouts/checkout-layout.d.ts +7 -0
  99. package/lib/checkout-v2/layouts/checkout-layout.js +308 -0
  100. package/lib/checkout-v2/panels/left/composite-panel.d.ts +1 -0
  101. package/lib/checkout-v2/panels/left/composite-panel.js +515 -0
  102. package/lib/checkout-v2/panels/left/credit-topup-panel.d.ts +1 -0
  103. package/lib/checkout-v2/panels/left/credit-topup-panel.js +795 -0
  104. package/lib/checkout-v2/panels/left/scenario-router.d.ts +1 -0
  105. package/lib/checkout-v2/panels/left/scenario-router.js +29 -0
  106. package/lib/checkout-v2/panels/right/payment-panel.d.ts +1 -0
  107. package/lib/checkout-v2/panels/right/payment-panel.js +906 -0
  108. package/lib/checkout-v2/types.d.ts +15 -0
  109. package/lib/checkout-v2/types.js +1 -0
  110. package/lib/checkout-v2/utils/format.d.ts +59 -0
  111. package/lib/checkout-v2/utils/format.js +158 -0
  112. package/lib/checkout-v2/utils/scenario-detector.d.ts +3 -0
  113. package/lib/checkout-v2/utils/scenario-detector.js +23 -0
  114. package/lib/checkout-v2/views/error-view.d.ts +7 -0
  115. package/lib/checkout-v2/views/error-view.js +321 -0
  116. package/lib/checkout-v2/views/loading-view.d.ts +5 -0
  117. package/lib/checkout-v2/views/loading-view.js +168 -0
  118. package/lib/checkout-v2/views/success-view.d.ts +29 -0
  119. package/lib/checkout-v2/views/success-view.js +735 -0
  120. package/lib/components/phone-field.d.ts +14 -0
  121. package/lib/components/phone-field.js +130 -0
  122. package/lib/index.d.ts +3 -1
  123. package/lib/index.js +8 -0
  124. package/lib/locales/en.js +45 -6
  125. package/lib/locales/zh.js +45 -6
  126. package/lib/payment/form/index.js +10 -1
  127. package/package.json +4 -3
  128. package/src/checkout-v2/checkout-v2.tsx +155 -0
  129. package/src/checkout-v2/components/dialogs/checkout-dialogs.tsx +134 -0
  130. package/src/checkout-v2/components/left/billing-toggle.tsx +122 -0
  131. package/src/checkout-v2/components/left/cross-sell-card.tsx +170 -0
  132. package/src/checkout-v2/components/left/product-item-card.tsx +642 -0
  133. package/src/checkout-v2/components/left/promotion-input.tsx +207 -0
  134. package/src/checkout-v2/components/left/staking-breakdown.tsx +57 -0
  135. package/src/checkout-v2/components/left/trial-info.tsx +63 -0
  136. package/src/checkout-v2/components/right/currency-grid.tsx +59 -0
  137. package/src/checkout-v2/components/right/customer-info-card.tsx +214 -0
  138. package/src/checkout-v2/components/right/status-feedback.tsx +35 -0
  139. package/src/checkout-v2/components/right/submit-button.tsx +37 -0
  140. package/src/checkout-v2/components/right/subscription-disclaimer.tsx +27 -0
  141. package/src/checkout-v2/components/shared/exchange-rate-footer.tsx +221 -0
  142. package/src/checkout-v2/components/shared/scenario-badge.tsx +51 -0
  143. package/src/checkout-v2/components/shared/total-display.tsx +112 -0
  144. package/src/checkout-v2/index.ts +2 -0
  145. package/src/checkout-v2/layouts/checkout-layout.tsx +232 -0
  146. package/src/checkout-v2/panels/left/composite-panel.tsx +465 -0
  147. package/src/checkout-v2/panels/left/credit-topup-panel.tsx +677 -0
  148. package/src/checkout-v2/panels/left/scenario-router.tsx +22 -0
  149. package/src/checkout-v2/panels/right/payment-panel.tsx +703 -0
  150. package/src/checkout-v2/types.ts +18 -0
  151. package/src/checkout-v2/utils/format.ts +205 -0
  152. package/src/checkout-v2/utils/scenario-detector.ts +30 -0
  153. package/src/checkout-v2/views/error-view.tsx +293 -0
  154. package/src/checkout-v2/views/loading-view.tsx +162 -0
  155. package/src/checkout-v2/views/success-view.tsx +770 -0
  156. package/src/components/phone-field.tsx +119 -0
  157. package/src/index.ts +3 -0
  158. package/src/locales/en.tsx +45 -4
  159. package/src/locales/zh.tsx +43 -4
  160. package/src/payment/form/index.tsx +16 -1
@@ -0,0 +1,178 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { useState } from "react";
3
+ import AddIcon from "@mui/icons-material/Add";
4
+ import CloseIcon from "@mui/icons-material/Close";
5
+ import LocalOfferIcon from "@mui/icons-material/LocalOffer";
6
+ import {
7
+ Alert,
8
+ Box,
9
+ Button,
10
+ CircularProgress,
11
+ IconButton,
12
+ InputAdornment,
13
+ Stack,
14
+ TextField,
15
+ Typography
16
+ } from "@mui/material";
17
+ import { useLocaleContext } from "@arcblock/ux/lib/Locale/context";
18
+ export default function PromotionInput({
19
+ promotion,
20
+ discounts,
21
+ discountAmount,
22
+ initialShowInput = false
23
+ }) {
24
+ const { t } = useLocaleContext();
25
+ const [showInput, setShowInput] = useState(false);
26
+ const [code, setCode] = useState("");
27
+ const [applying, setApplying] = useState(false);
28
+ const [error, setError] = useState("");
29
+ const effectiveShowInput = initialShowInput || showInput;
30
+ const handleApply = async () => {
31
+ if (!code.trim()) return;
32
+ setApplying(true);
33
+ setError("");
34
+ const result = await promotion.apply(code.trim());
35
+ if (!result.success) {
36
+ setError(result.error || "Invalid code");
37
+ } else {
38
+ setCode("");
39
+ setShowInput(false);
40
+ }
41
+ setApplying(false);
42
+ };
43
+ const handleKeyPress = (event) => {
44
+ if (event.key === "Enter" && !applying && code.trim()) {
45
+ handleApply();
46
+ }
47
+ };
48
+ if (discounts?.length > 0) {
49
+ return /* @__PURE__ */ jsx(Box, { children: discounts.map((disc, i) => {
50
+ const discCode = disc.promotion_code_details?.code || disc.verification_data?.code || disc.promotion_code || "";
51
+ const coupon = disc.coupon_details || {};
52
+ const couponOff = coupon.percent_off > 0 ? t("payment.checkout.coupon.percentage", { percent: coupon.percent_off }) : `${coupon.percent_off || 0}%`;
53
+ let description = "";
54
+ if (coupon.duration === "repeating" && coupon.duration_in_months) {
55
+ const months = coupon.duration_in_months;
56
+ description = `${couponOff} for ${months} month${months > 1 ? "s" : ""}`;
57
+ } else if (coupon.duration === "forever") {
58
+ description = t("payment.checkout.coupon.terms.forever", { couponOff });
59
+ } else if (coupon.duration === "once") {
60
+ description = t("payment.checkout.coupon.terms.once", { couponOff });
61
+ }
62
+ return /* @__PURE__ */ jsxs(
63
+ Stack,
64
+ {
65
+ direction: "row",
66
+ justifyContent: "space-between",
67
+ alignItems: "center",
68
+ children: [
69
+ /* @__PURE__ */ jsxs(
70
+ Stack,
71
+ {
72
+ direction: "row",
73
+ alignItems: "center",
74
+ spacing: 0.5,
75
+ sx: {
76
+ bgcolor: (theme) => theme.palette.mode === "dark" ? "rgba(18,184,134,0.1)" : "#ebfef5",
77
+ px: 1.5,
78
+ py: 0.5,
79
+ borderRadius: "8px",
80
+ border: "1px solid",
81
+ borderColor: (theme) => theme.palette.mode === "dark" ? "rgba(18,184,134,0.2)" : "#d3f9e8"
82
+ },
83
+ children: [
84
+ /* @__PURE__ */ jsx(LocalOfferIcon, { sx: { color: "#12b886", fontSize: 14 } }),
85
+ /* @__PURE__ */ jsx(Typography, { sx: { fontWeight: 700, fontSize: 13, color: "#12b886" }, children: discCode }),
86
+ description && /* @__PURE__ */ jsxs(Typography, { sx: { fontSize: 12, color: "#12b886", fontWeight: 500, opacity: 0.8 }, children: [
87
+ "\xB7 ",
88
+ description
89
+ ] }),
90
+ /* @__PURE__ */ jsx(IconButton, { size: "small", onClick: promotion.remove, sx: { width: 18, height: 18, ml: 0.25 }, children: /* @__PURE__ */ jsx(CloseIcon, { sx: { fontSize: 12, color: "#12b886" } }) })
91
+ ]
92
+ }
93
+ ),
94
+ /* @__PURE__ */ jsxs(Typography, { sx: { color: "text.primary", fontWeight: 600, fontSize: 14 }, children: [
95
+ "-",
96
+ discountAmount || "0"
97
+ ] })
98
+ ]
99
+ },
100
+ disc.promotion_code || disc.coupon || i
101
+ );
102
+ }) });
103
+ }
104
+ if (!promotion.active) return null;
105
+ return /* @__PURE__ */ jsx(Box, { sx: { minHeight: 36 }, children: effectiveShowInput ? /* @__PURE__ */ jsxs(
106
+ Box,
107
+ {
108
+ onBlur: (e) => {
109
+ if (initialShowInput) return;
110
+ if (!e.currentTarget.contains(e.relatedTarget) && !code.trim()) {
111
+ setShowInput(false);
112
+ }
113
+ },
114
+ children: [
115
+ /* @__PURE__ */ jsx(
116
+ TextField,
117
+ {
118
+ fullWidth: true,
119
+ size: "small",
120
+ value: code,
121
+ onChange: (e) => setCode(e.target.value),
122
+ onKeyPress: handleKeyPress,
123
+ placeholder: t("payment.checkout.promotion.placeholder"),
124
+ disabled: applying,
125
+ autoFocus: true,
126
+ slotProps: {
127
+ input: {
128
+ endAdornment: /* @__PURE__ */ jsx(InputAdornment, { position: "end", children: /* @__PURE__ */ jsx(
129
+ Button,
130
+ {
131
+ size: "small",
132
+ onClick: handleApply,
133
+ disabled: !code.trim() || applying,
134
+ variant: "text",
135
+ sx: {
136
+ color: "primary.main",
137
+ fontSize: 13,
138
+ textTransform: "none",
139
+ minWidth: "auto",
140
+ fontWeight: 600
141
+ },
142
+ children: applying ? /* @__PURE__ */ jsx(CircularProgress, { size: 16 }) : t("payment.checkout.promotion.apply")
143
+ }
144
+ ) })
145
+ }
146
+ },
147
+ sx: {
148
+ "& .MuiOutlinedInput-root": { pr: 1, borderRadius: "8px", height: 36 },
149
+ "& .MuiOutlinedInput-input": { py: "6px", fontSize: 13 }
150
+ }
151
+ }
152
+ ),
153
+ error && /* @__PURE__ */ jsx(Alert, { severity: "error", sx: { mt: 0.5, py: 0, fontSize: 12, borderRadius: "6px" }, children: error })
154
+ ]
155
+ }
156
+ ) : /* @__PURE__ */ jsx(
157
+ Button,
158
+ {
159
+ onClick: () => setShowInput(true),
160
+ startIcon: /* @__PURE__ */ jsx(AddIcon, { sx: { fontSize: 18 } }),
161
+ variant: "text",
162
+ sx: {
163
+ fontWeight: 600,
164
+ fontSize: 13,
165
+ textTransform: "none",
166
+ justifyContent: "flex-start",
167
+ p: 0,
168
+ height: 36,
169
+ color: "primary.main",
170
+ "&:hover": {
171
+ backgroundColor: "transparent",
172
+ textDecoration: "underline"
173
+ }
174
+ },
175
+ children: t("payment.checkout.promotion.add_code")
176
+ }
177
+ ) });
178
+ }
@@ -0,0 +1,9 @@
1
+ interface StakingBreakdownProps {
2
+ staking: string;
3
+ paymentAmount: string;
4
+ trialActive: boolean;
5
+ trialDays: number;
6
+ afterTrialInterval: string | null;
7
+ }
8
+ export default function StakingBreakdown({ staking, paymentAmount, trialActive, trialDays, afterTrialInterval, }: StakingBreakdownProps): import("react").JSX.Element;
9
+ export {};
@@ -0,0 +1,48 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import HelpOutline from "@mui/icons-material/HelpOutline";
3
+ import { Stack, Tooltip, Typography } from "@mui/material";
4
+ import { useLocaleContext } from "@arcblock/ux/lib/Locale/context";
5
+ import { formatTrialText, whiteTooltipSx } from "../../utils/format.js";
6
+ export default function StakingBreakdown({
7
+ staking,
8
+ paymentAmount,
9
+ trialActive,
10
+ trialDays,
11
+ afterTrialInterval
12
+ }) {
13
+ const { t } = useLocaleContext();
14
+ return /* @__PURE__ */ jsxs(Stack, { spacing: 1, sx: { mb: 1 }, children: [
15
+ /* @__PURE__ */ jsxs(Stack, { direction: "row", justifyContent: "space-between", alignItems: "center", children: [
16
+ /* @__PURE__ */ jsxs(Stack, { direction: "row", spacing: 0.5, alignItems: "center", children: [
17
+ /* @__PURE__ */ jsx(Typography, { sx: { color: "text.secondary", fontSize: 14 }, children: t("payment.checkout.paymentRequired") }),
18
+ /* @__PURE__ */ jsx(
19
+ Tooltip,
20
+ {
21
+ title: t("payment.checkout.stakingConfirm"),
22
+ placement: "top",
23
+ arrow: true,
24
+ slotProps: { popper: { sx: whiteTooltipSx } },
25
+ children: /* @__PURE__ */ jsx(HelpOutline, { sx: { fontSize: 16, color: "text.disabled" } })
26
+ }
27
+ )
28
+ ] }),
29
+ /* @__PURE__ */ jsx(Typography, { children: trialActive ? formatTrialText(t, trialDays, afterTrialInterval || "day") : paymentAmount })
30
+ ] }),
31
+ /* @__PURE__ */ jsxs(Stack, { direction: "row", justifyContent: "space-between", alignItems: "center", children: [
32
+ /* @__PURE__ */ jsxs(Stack, { direction: "row", spacing: 0.5, alignItems: "center", children: [
33
+ /* @__PURE__ */ jsx(Typography, { sx: { color: "text.secondary", fontSize: 14 }, children: t("payment.checkout.staking.title") }),
34
+ /* @__PURE__ */ jsx(
35
+ Tooltip,
36
+ {
37
+ title: t("payment.checkout.staking.tooltip"),
38
+ placement: "top",
39
+ arrow: true,
40
+ slotProps: { popper: { sx: whiteTooltipSx } },
41
+ children: /* @__PURE__ */ jsx(HelpOutline, { sx: { fontSize: 16, color: "text.disabled" } })
42
+ }
43
+ )
44
+ ] }),
45
+ /* @__PURE__ */ jsx(Typography, { children: staking })
46
+ ] })
47
+ ] });
48
+ }
@@ -0,0 +1,13 @@
1
+ import type { TLineItemExpanded } from '@blocklet/payment-types';
2
+ interface TrialInfoProps {
3
+ trial: {
4
+ active: boolean;
5
+ days: number;
6
+ afterTrialPrice: string | null;
7
+ afterTrialInterval: string | null;
8
+ };
9
+ mode: string;
10
+ items: TLineItemExpanded[];
11
+ }
12
+ export default function TrialInfo({ trial, mode, items }: TrialInfoProps): import("react").JSX.Element | null;
13
+ export {};
@@ -0,0 +1,48 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { Stack, Typography } from "@mui/material";
3
+ import { useLocaleContext } from "@arcblock/ux/lib/Locale/context";
4
+ import { INTERVAL_LOCALE_KEY } from "../../utils/format.js";
5
+ export default function TrialInfo({ trial, mode, items }) {
6
+ const { t } = useLocaleContext();
7
+ if (trial.active && trial.afterTrialPrice) {
8
+ return /* @__PURE__ */ jsxs(
9
+ Stack,
10
+ {
11
+ direction: "row",
12
+ justifyContent: "space-between",
13
+ alignItems: "center",
14
+ sx: { borderTop: "1px solid", borderColor: "divider", pt: 1, mt: 1 },
15
+ children: [
16
+ /* @__PURE__ */ jsx(Typography, { sx: { color: "text.secondary", fontSize: 14 }, children: t("common.nextCharge") }),
17
+ /* @__PURE__ */ jsxs(Typography, { sx: { fontSize: 16, color: "text.secondary" }, children: [
18
+ trial.afterTrialPrice,
19
+ trial.afterTrialInterval ? ` ${t(INTERVAL_LOCALE_KEY[trial.afterTrialInterval] || "")}` : ""
20
+ ] })
21
+ ]
22
+ }
23
+ );
24
+ }
25
+ if (!trial.active && ["subscription", "setup"].includes(mode)) {
26
+ const meteredItem = items.find(
27
+ (item) => (item.upsell_price || item.price)?.recurring?.usage_type === "metered"
28
+ );
29
+ if (!meteredItem) return null;
30
+ const meteredInterval = (meteredItem.upsell_price || meteredItem.price)?.recurring?.interval;
31
+ if (!meteredInterval) return null;
32
+ const recurringText = t("common.per", { interval: t(`common.${meteredInterval}`) });
33
+ return /* @__PURE__ */ jsxs(
34
+ Stack,
35
+ {
36
+ direction: "row",
37
+ justifyContent: "space-between",
38
+ alignItems: "center",
39
+ sx: { borderTop: "1px solid", borderColor: "divider", pt: 1, mt: 1 },
40
+ children: [
41
+ /* @__PURE__ */ jsx(Typography, { sx: { color: "text.secondary", fontSize: 14, fontWeight: 600 }, children: t("common.nextCharge") }),
42
+ /* @__PURE__ */ jsx(Typography, { sx: { fontSize: 16, color: "text.secondary" }, children: t("payment.checkout.metered", { recurring: recurringText }) })
43
+ ]
44
+ }
45
+ );
46
+ }
47
+ return null;
48
+ }
@@ -0,0 +1,8 @@
1
+ import type { TPaymentCurrency } from '@blocklet/payment-types';
2
+ interface CurrencyGridProps {
3
+ currencies: TPaymentCurrency[];
4
+ selectedId: string | undefined;
5
+ onSelect: (id: string) => Promise<void>;
6
+ }
7
+ export default function CurrencyGrid({ currencies, selectedId, onSelect }: CurrencyGridProps): import("react").JSX.Element | null;
8
+ export {};
@@ -0,0 +1,48 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { Avatar, Card, Radio, Stack, Typography } from "@mui/material";
3
+ import { styled } from "@mui/material/styles";
4
+ const CurrencyRoot = styled("section")`
5
+ display: grid;
6
+ width: 100%;
7
+ gap: 12px;
8
+ grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
9
+
10
+ .cko-payment-card {
11
+ position: relative;
12
+ border: 1px solid ${({ theme }) => theme.palette.primary.main};
13
+ padding: 4px 8px;
14
+ cursor: pointer;
15
+ background: ${({ theme }) => theme.palette.grey[50]};
16
+ }
17
+
18
+ .cko-payment-card-unselect {
19
+ border: 1px solid ${({ theme }) => theme.palette.divider};
20
+ padding: 4px 8px;
21
+ cursor: pointer;
22
+ background: ${({ theme }) => theme.palette.grey[50]};
23
+ }
24
+ `;
25
+ export default function CurrencyGrid({ currencies, selectedId, onSelect }) {
26
+ if (!currencies?.length) return null;
27
+ return /* @__PURE__ */ jsx(CurrencyRoot, { style: { display: currencies.length > 1 ? "grid" : "block" }, children: currencies.map((cur) => {
28
+ const selected = cur.id === selectedId;
29
+ const methodName = cur.method?.name || cur.name || "";
30
+ return /* @__PURE__ */ jsx(
31
+ Card,
32
+ {
33
+ variant: "outlined",
34
+ onClick: () => onSelect(cur.id),
35
+ className: selected ? "cko-payment-card" : "cko-payment-card-unselect",
36
+ children: /* @__PURE__ */ jsxs(Stack, { direction: "row", sx: { alignItems: "center", position: "relative" }, children: [
37
+ /* @__PURE__ */ jsx(Avatar, { src: cur.logo, alt: cur.name, sx: { width: 40, height: 40, mr: "12px" } }),
38
+ /* @__PURE__ */ jsxs("div", { children: [
39
+ /* @__PURE__ */ jsx(Typography, { sx: { fontSize: 16, color: "text.primary", fontWeight: 500 }, children: cur.symbol }),
40
+ /* @__PURE__ */ jsx(Typography, { sx: { color: "text.secondary", fontSize: 14 }, children: methodName })
41
+ ] }),
42
+ /* @__PURE__ */ jsx(Radio, { checked: selected, sx: { position: "absolute", right: 0 } })
43
+ ] })
44
+ },
45
+ cur.id
46
+ );
47
+ }) });
48
+ }
@@ -0,0 +1,17 @@
1
+ interface FieldConfig {
2
+ name: string;
3
+ type: string;
4
+ required: boolean;
5
+ }
6
+ interface CustomerInfoCardProps {
7
+ form: {
8
+ fields: FieldConfig[];
9
+ values: Record<string, any>;
10
+ onChange: (field: string, value: string | boolean | Record<string, string>) => void;
11
+ errors: Partial<Record<string, string>>;
12
+ validateField: (field: string) => Promise<void>;
13
+ };
14
+ isLoggedIn: boolean;
15
+ }
16
+ export default function CustomerInfoCard({ form, isLoggedIn }: CustomerInfoCardProps): import("react").JSX.Element | null;
17
+ export {};
@@ -0,0 +1,156 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { useState, useEffect, useRef } from "react";
3
+ import { Box, Button, InputBase, InputAdornment, Stack, Typography } from "@mui/material";
4
+ import { useLocaleContext } from "@arcblock/ux/lib/Locale/context";
5
+ import CountrySelect from "../../../components/country-select.js";
6
+ import PhoneField from "../../../components/phone-field.js";
7
+ import { countryCodeToFlag } from "../../utils/format.js";
8
+ const fieldLabelMap = (t) => ({
9
+ customer_name: t("payment.checkout.customer.name"),
10
+ customer_email: t("payment.checkout.customer.email"),
11
+ customer_phone: t("payment.checkout.customer.phone"),
12
+ "billing_address.country": t("payment.checkout.billing.country"),
13
+ "billing_address.state": t("payment.checkout.billing.state"),
14
+ "billing_address.city": t("payment.checkout.billing.city"),
15
+ "billing_address.line1": t("payment.checkout.billing.line1"),
16
+ "billing_address.line2": t("payment.checkout.billing.line2"),
17
+ "billing_address.postal_code": t("payment.checkout.billing.postal_code")
18
+ });
19
+ export default function CustomerInfoCard({ form, isLoggedIn }) {
20
+ const { t } = useLocaleContext();
21
+ const labels = fieldLabelMap(t);
22
+ const hasRequiredData = !!(form.values.customer_name && form.values.customer_email);
23
+ const [showEditForm, setShowEditForm] = useState(!hasRequiredData);
24
+ const autoConfirmedRef = useRef(false);
25
+ useEffect(() => {
26
+ if (!autoConfirmedRef.current && form.values.customer_name && form.values.customer_email) {
27
+ autoConfirmedRef.current = true;
28
+ setShowEditForm(false);
29
+ }
30
+ }, [form.values.customer_name, form.values.customer_email]);
31
+ if (!isLoggedIn) return null;
32
+ if (!showEditForm) {
33
+ return /* @__PURE__ */ jsxs(Box, { sx: { mt: 2 }, children: [
34
+ /* @__PURE__ */ jsxs(Stack, { direction: "row", justifyContent: "space-between", alignItems: "center", sx: { mb: 1 }, children: [
35
+ /* @__PURE__ */ jsx(Typography, { sx: { fontSize: 13, fontWeight: 600, color: "text.secondary" }, children: t("payment.checkout.customerInfo") }),
36
+ /* @__PURE__ */ jsx(
37
+ Button,
38
+ {
39
+ size: "small",
40
+ variant: "text",
41
+ onClick: () => setShowEditForm(true),
42
+ sx: { minWidth: 0, fontSize: 13, fontWeight: 600, p: 0 },
43
+ children: t("common.edit")
44
+ }
45
+ )
46
+ ] }),
47
+ /* @__PURE__ */ jsxs(
48
+ Stack,
49
+ {
50
+ spacing: 0.5,
51
+ sx: {
52
+ p: 2,
53
+ backgroundColor: "background.paper",
54
+ borderRadius: 1,
55
+ border: "1px solid",
56
+ borderColor: "divider"
57
+ },
58
+ children: [
59
+ form.values.customer_name && /* @__PURE__ */ jsx(Typography, { variant: "body2", sx: { color: "text.primary", fontWeight: 600, fontSize: "0.9375rem" }, children: form.values.customer_name }),
60
+ form.values.customer_email && /* @__PURE__ */ jsx(Typography, { variant: "body2", sx: { color: "text.secondary", fontSize: "0.8125rem" }, children: form.values.customer_email }),
61
+ form.fields.some((f) => f.name === "customer_phone") && form.values.customer_phone && /* @__PURE__ */ jsx(Typography, { variant: "body2", sx: { color: "text.secondary", fontSize: "0.8125rem" }, children: form.values.customer_phone }),
62
+ (form.values.billing_address?.country || form.values.billing_address?.state || form.values.billing_address?.postal_code) && /* @__PURE__ */ jsxs(Stack, { direction: "row", alignItems: "center", spacing: 0.75, children: [
63
+ form.values.billing_address?.country && /* @__PURE__ */ jsx(Box, { component: "span", sx: { fontSize: 14, lineHeight: 1 }, children: countryCodeToFlag(form.values.billing_address.country) }),
64
+ /* @__PURE__ */ jsxs(Typography, { variant: "body2", sx: { color: "text.secondary", fontSize: "0.8125rem" }, children: [
65
+ form.values.billing_address?.state || "",
66
+ form.values.billing_address?.postal_code ? ` [ ${t("payment.checkout.billing.postal_code")}: ${form.values.billing_address.postal_code} ]` : ""
67
+ ] })
68
+ ] })
69
+ ]
70
+ }
71
+ )
72
+ ] });
73
+ }
74
+ return /* @__PURE__ */ jsxs(Box, { sx: { mt: 2 }, children: [
75
+ /* @__PURE__ */ jsxs(Stack, { direction: "row", justifyContent: "space-between", alignItems: "center", sx: { mb: 1 }, children: [
76
+ /* @__PURE__ */ jsx(Typography, { sx: { fontSize: 13, fontWeight: 600, color: "text.secondary" }, children: t("payment.checkout.customerInfo") }),
77
+ /* @__PURE__ */ jsx(
78
+ Button,
79
+ {
80
+ size: "small",
81
+ variant: "text",
82
+ onClick: () => setShowEditForm(false),
83
+ sx: { minWidth: 0, fontSize: 13, fontWeight: 600, p: 0 },
84
+ children: t("common.confirm")
85
+ }
86
+ )
87
+ ] }),
88
+ /* @__PURE__ */ jsx(
89
+ Stack,
90
+ {
91
+ spacing: 0,
92
+ sx: {
93
+ p: 2,
94
+ backgroundColor: "background.paper",
95
+ borderRadius: 1,
96
+ border: "1px solid",
97
+ borderColor: "divider"
98
+ },
99
+ children: form.fields.filter((f) => f.name !== "billing_address.country").map((field) => {
100
+ const { name } = field;
101
+ const label = labels[name] || name;
102
+ const value = name.includes(".") ? name.split(".").reduce((o, k) => o?.[k], form.values) : form.values[name];
103
+ const isPostalCode = name === "billing_address.postal_code";
104
+ const isPhone = name === "customer_phone";
105
+ if (isPhone) {
106
+ return /* @__PURE__ */ jsx(
107
+ PhoneField,
108
+ {
109
+ value: value || "",
110
+ country: form.values.billing_address?.country || "",
111
+ onChange: (phone) => form.onChange("customer_phone", phone),
112
+ onCountryChange: (c) => form.onChange("billing_address.country", c),
113
+ onBlur: () => form.validateField(name),
114
+ label,
115
+ error: form.errors[name]
116
+ },
117
+ name
118
+ );
119
+ }
120
+ return /* @__PURE__ */ jsxs(Box, { sx: { mb: 1.5 }, children: [
121
+ /* @__PURE__ */ jsx(Typography, { sx: { fontSize: 13, fontWeight: 600, color: "text.primary", mb: 0.5 }, children: label }),
122
+ /* @__PURE__ */ jsx(
123
+ InputBase,
124
+ {
125
+ fullWidth: true,
126
+ value: value || "",
127
+ onChange: (e) => form.onChange(name, e.target.value),
128
+ onBlur: () => form.validateField(name),
129
+ startAdornment: isPostalCode ? /* @__PURE__ */ jsx(InputAdornment, { position: "start", sx: { mr: 0.5, ml: -0.5 }, children: /* @__PURE__ */ jsx(
130
+ CountrySelect,
131
+ {
132
+ value: form.values.billing_address?.country || "",
133
+ onChange: (v) => form.onChange("billing_address.country", v),
134
+ sx: {
135
+ ".MuiOutlinedInput-notchedOutline": { borderColor: "transparent !important" },
136
+ "& .MuiSelect-select": { py: 0, pr: "20px !important" }
137
+ }
138
+ }
139
+ ) }) : void 0,
140
+ sx: {
141
+ bgcolor: (theme) => theme.palette.mode === "dark" ? "rgba(255,255,255,0.06)" : "grey.50",
142
+ borderRadius: "8px",
143
+ px: 1.5,
144
+ py: 0.75,
145
+ fontSize: 14,
146
+ "& .MuiInputBase-input": { p: 0 }
147
+ }
148
+ }
149
+ ),
150
+ form.errors[name] && /* @__PURE__ */ jsx(Typography, { sx: { fontSize: 12, color: "error.main", mt: 0.25 }, children: form.errors[name] })
151
+ ] }, name);
152
+ })
153
+ }
154
+ )
155
+ ] });
156
+ }
@@ -0,0 +1,7 @@
1
+ interface StatusFeedbackProps {
2
+ status: string;
3
+ context: any;
4
+ onReset: () => void;
5
+ }
6
+ export default function StatusFeedback({ status, context, onReset }: StatusFeedbackProps): null;
7
+ export {};
@@ -0,0 +1,17 @@
1
+ import { useEffect, useRef } from "react";
2
+ import { useLocaleContext } from "@arcblock/ux/lib/Locale/context";
3
+ import Toast from "@arcblock/ux/lib/Toast";
4
+ export default function StatusFeedback({ status, context, onReset }) {
5
+ const { t } = useLocaleContext();
6
+ const prevStatusRef = useRef(status);
7
+ useEffect(() => {
8
+ if (status === prevStatusRef.current) return;
9
+ prevStatusRef.current = status;
10
+ if (status === "failed" && context?.type === "error") {
11
+ if (context.code === "CUSTOMER_LIMITED") return;
12
+ Toast.error(context.message || "Payment failed");
13
+ onReset();
14
+ }
15
+ }, [status, context, t, onReset]);
16
+ return null;
17
+ }
@@ -0,0 +1,10 @@
1
+ interface SubmitButtonProps {
2
+ canSubmit: boolean;
3
+ isProcessing: boolean;
4
+ isWaitingStripe: boolean;
5
+ label: string;
6
+ processingLabel: string;
7
+ onSubmit: () => Promise<void>;
8
+ }
9
+ export default function SubmitButton({ canSubmit, isProcessing, isWaitingStripe, label, processingLabel, onSubmit, }: SubmitButtonProps): import("react").JSX.Element;
10
+ export {};
@@ -0,0 +1,29 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { Button, CircularProgress } from "@mui/material";
3
+ export default function SubmitButton({
4
+ canSubmit,
5
+ isProcessing,
6
+ isWaitingStripe,
7
+ label,
8
+ processingLabel,
9
+ onSubmit
10
+ }) {
11
+ return /* @__PURE__ */ jsx(
12
+ Button,
13
+ {
14
+ variant: "contained",
15
+ size: "large",
16
+ fullWidth: true,
17
+ disabled: !canSubmit || isWaitingStripe,
18
+ onClick: onSubmit,
19
+ startIcon: isProcessing ? /* @__PURE__ */ jsx(CircularProgress, { size: 20, color: "inherit" }) : null,
20
+ sx: {
21
+ py: 1.5,
22
+ fontSize: "1.3rem",
23
+ fontWeight: 600,
24
+ textTransform: "none"
25
+ },
26
+ children: isProcessing ? processingLabel : label
27
+ }
28
+ );
29
+ }
@@ -0,0 +1,11 @@
1
+ interface SubscriptionDisclaimerProps {
2
+ mode: string;
3
+ subscription: {
4
+ confirmMessage: string;
5
+ showStake: boolean;
6
+ } | null;
7
+ staking: string | null;
8
+ appName: string;
9
+ }
10
+ export default function SubscriptionDisclaimer({ mode, subscription, staking, appName }: SubscriptionDisclaimerProps): import("react").JSX.Element | null;
11
+ export {};
@@ -0,0 +1,8 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { Typography } from "@mui/material";
3
+ import { useLocaleContext } from "@arcblock/ux/lib/Locale/context";
4
+ export default function SubscriptionDisclaimer({ mode, subscription, staking, appName }) {
5
+ const { t } = useLocaleContext();
6
+ if (!["subscription", "setup"].includes(mode) || !subscription) return null;
7
+ return /* @__PURE__ */ jsx(Typography, { sx: { mt: 2.5, color: "text.secondary", fontSize: "0.7875rem", lineHeight: "0.9625rem" }, children: subscription.confirmMessage || (subscription.showStake && staking ? t("payment.checkout.confirm.withStake", { payee: appName || "New Payment Kit" }) : t("payment.checkout.confirm.withoutStake", { payee: appName || "New Payment Kit" })) });
8
+ }
@@ -0,0 +1,23 @@
1
+ interface ExchangeRateFooterProps {
2
+ hasDynamicPricing: boolean;
3
+ rate: {
4
+ value: string | null;
5
+ display: string | null;
6
+ provider: string | null;
7
+ providerDisplay: string | null;
8
+ fetchedAt: number | null;
9
+ status: 'loading' | 'available' | 'unavailable';
10
+ };
11
+ slippage: {
12
+ percent: number;
13
+ set: (config: {
14
+ mode: string;
15
+ percent: number;
16
+ base_currency?: string;
17
+ }) => Promise<void>;
18
+ };
19
+ currencySymbol: string;
20
+ isSubscription: boolean;
21
+ }
22
+ export default function ExchangeRateFooter({ hasDynamicPricing, rate, slippage, currencySymbol, isSubscription, }: ExchangeRateFooterProps): import("react").JSX.Element | null;
23
+ export {};