@blocklet/payment-react 1.13.210 → 1.13.211

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 (74) hide show
  1. package/es/checkout/donate.d.ts +20 -0
  2. package/es/checkout/donate.js +199 -0
  3. package/es/checkout/form.d.ts +2 -1
  4. package/es/checkout/form.js +13 -2
  5. package/es/components/blockchain/tx.d.ts +2 -0
  6. package/es/components/blockchain/tx.js +16 -5
  7. package/es/index.d.ts +2 -1
  8. package/es/index.js +2 -0
  9. package/es/locales/en.js +8 -0
  10. package/es/locales/zh.js +8 -0
  11. package/es/payment/error.d.ts +3 -1
  12. package/es/payment/error.js +4 -3
  13. package/es/payment/form/currency.js +10 -12
  14. package/es/payment/form/index.d.ts +1 -1
  15. package/es/payment/form/index.js +15 -3
  16. package/es/payment/index.d.ts +3 -3
  17. package/es/payment/index.js +38 -13
  18. package/es/payment/product-donation.d.ts +7 -0
  19. package/es/payment/product-donation.js +99 -0
  20. package/es/payment/skeleton/overview.js +2 -2
  21. package/es/payment/skeleton/payment.js +2 -5
  22. package/es/payment/success.d.ts +2 -1
  23. package/es/payment/success.js +21 -12
  24. package/es/payment/summary.d.ts +8 -2
  25. package/es/payment/summary.js +46 -29
  26. package/es/types/index.d.ts +2 -0
  27. package/es/util.d.ts +1 -0
  28. package/es/util.js +44 -3
  29. package/lib/checkout/donate.d.ts +20 -0
  30. package/lib/checkout/donate.js +284 -0
  31. package/lib/checkout/form.d.ts +2 -1
  32. package/lib/checkout/form.js +5 -2
  33. package/lib/components/blockchain/tx.d.ts +2 -0
  34. package/lib/components/blockchain/tx.js +3 -1
  35. package/lib/index.d.ts +2 -1
  36. package/lib/index.js +8 -0
  37. package/lib/locales/en.js +8 -0
  38. package/lib/locales/zh.js +8 -0
  39. package/lib/payment/error.d.ts +3 -1
  40. package/lib/payment/error.js +5 -3
  41. package/lib/payment/form/currency.js +10 -12
  42. package/lib/payment/form/index.d.ts +1 -1
  43. package/lib/payment/form/index.js +16 -4
  44. package/lib/payment/index.d.ts +3 -3
  45. package/lib/payment/index.js +56 -24
  46. package/lib/payment/product-donation.d.ts +7 -0
  47. package/lib/payment/product-donation.js +169 -0
  48. package/lib/payment/skeleton/overview.js +2 -2
  49. package/lib/payment/skeleton/payment.js +4 -8
  50. package/lib/payment/success.d.ts +2 -1
  51. package/lib/payment/success.js +3 -2
  52. package/lib/payment/summary.d.ts +8 -2
  53. package/lib/payment/summary.js +30 -7
  54. package/lib/types/index.d.ts +2 -0
  55. package/lib/util.d.ts +1 -0
  56. package/lib/util.js +39 -4
  57. package/package.json +6 -6
  58. package/src/checkout/donate.tsx +256 -0
  59. package/src/checkout/form.tsx +13 -4
  60. package/src/components/blockchain/tx.tsx +8 -1
  61. package/src/index.ts +2 -0
  62. package/src/locales/en.tsx +8 -0
  63. package/src/locales/zh.tsx +8 -0
  64. package/src/payment/error.tsx +4 -2
  65. package/src/payment/form/currency.tsx +11 -13
  66. package/src/payment/form/index.tsx +14 -4
  67. package/src/payment/index.tsx +40 -14
  68. package/src/payment/product-donation.tsx +118 -0
  69. package/src/payment/skeleton/overview.tsx +2 -2
  70. package/src/payment/skeleton/payment.tsx +1 -4
  71. package/src/payment/success.tsx +7 -2
  72. package/src/payment/summary.tsx +47 -28
  73. package/src/types/index.ts +2 -0
  74. package/src/util.ts +50 -3
@@ -1,10 +1,10 @@
1
1
  import { jsx, jsxs } from "react/jsx-runtime";
2
- import Center from "@arcblock/ux/lib/Center";
3
2
  import { useLocaleContext } from "@arcblock/ux/lib/Locale/context";
4
3
  import Toast from "@arcblock/ux/lib/Toast";
5
4
  import { ArrowBackOutlined } from "@mui/icons-material";
6
5
  import { Box, Fade, Stack } from "@mui/material";
7
6
  import { styled } from "@mui/system";
7
+ import { fromTokenToUnit } from "@ocap/util";
8
8
  import { useSetState } from "ahooks";
9
9
  import { useEffect, useState } from "react";
10
10
  import { FormProvider, useForm, useWatch } from "react-hook-form";
@@ -35,7 +35,8 @@ export default function Payment({
35
35
  onPaid,
36
36
  onError,
37
37
  onChange,
38
- goBack
38
+ goBack,
39
+ action
39
40
  }) {
40
41
  const { t } = useLocaleContext();
41
42
  const { refresh, livemode, setLivemode } = usePaymentContext();
@@ -56,28 +57,30 @@ export default function Payment({
56
57
  }
57
58
  }, [checkoutSession, livemode, setLivemode, refresh]);
58
59
  if (error) {
59
- return /* @__PURE__ */ jsx(PaymentError, { title: "Oops", description: formatError(error) });
60
+ return /* @__PURE__ */ jsx(PaymentError, { mode, title: "Oops", description: formatError(error) });
60
61
  }
61
62
  if (!checkoutSession || !delay) {
62
63
  return /* @__PURE__ */ jsx(Root, { mode, children: /* @__PURE__ */ jsxs(Stack, { className: "cko-container", sx: { gap: { sm: mode === "standalone" ? 0 : 8 } }, children: [
63
64
  /* @__PURE__ */ jsx(Stack, { className: "cko-overview", children: /* @__PURE__ */ jsx(OverviewSkeleton, {}) }),
64
65
  /* @__PURE__ */ jsx(Stack, { className: "cko-payment", children: /* @__PURE__ */ jsx(PaymentSkeleton, {}) }),
65
- /* @__PURE__ */ jsx(CheckoutFooter, { className: "cko-footer" })
66
+ mode === "standalone" && /* @__PURE__ */ jsx(CheckoutFooter, { className: "cko-footer" })
66
67
  ] }) });
67
68
  }
68
69
  if (checkoutSession.expires_at <= Math.round(Date.now() / 1e3)) {
69
- return /* @__PURE__ */ jsx(Center, { children: /* @__PURE__ */ jsx(
70
+ return /* @__PURE__ */ jsx(
70
71
  PaymentError,
71
72
  {
73
+ mode,
72
74
  title: t("payment.checkout.expired.title"),
73
75
  description: t("payment.checkout.expired.description")
74
76
  }
75
- ) });
77
+ );
76
78
  }
77
79
  if (checkoutSession.status === "complete") {
78
80
  return /* @__PURE__ */ jsx(
79
81
  PaymentError,
80
82
  {
83
+ mode,
81
84
  title: t("payment.checkout.complete.title"),
82
85
  description: t("payment.checkout.complete.description")
83
86
  }
@@ -96,7 +99,8 @@ export default function Payment({
96
99
  onError,
97
100
  onChange,
98
101
  goBack,
99
- mode
102
+ mode,
103
+ action
100
104
  }
101
105
  );
102
106
  }
@@ -114,7 +118,8 @@ export function PaymentInner({
114
118
  onPaid,
115
119
  onError,
116
120
  onChange,
117
- goBack
121
+ goBack,
122
+ action
118
123
  }) {
119
124
  const { t } = useLocaleContext();
120
125
  const { settings, session } = usePaymentContext();
@@ -186,6 +191,18 @@ export function PaymentInner({
186
191
  Toast.error(formatError(err));
187
192
  }
188
193
  };
194
+ const onChangeAmount = async ({ priceId, amount }) => {
195
+ try {
196
+ const { data } = await api.put(`/api/checkout-sessions/${state.checkoutSession.id}/amount`, {
197
+ priceId,
198
+ amount: fromTokenToUnit(amount, currency.decimal).toString()
199
+ });
200
+ setState({ checkoutSession: data });
201
+ } catch (err) {
202
+ console.error(err);
203
+ Toast.error(formatError(err));
204
+ }
205
+ };
189
206
  const handlePaid = (result) => {
190
207
  setState({ checkoutSession: result.checkoutSession });
191
208
  onPaid(result);
@@ -199,7 +216,7 @@ export function PaymentInner({
199
216
  fontSize: "medium"
200
217
  }
201
218
  ),
202
- /* @__PURE__ */ jsxs(Stack, { className: "cko-container", sx: { gap: { sm: mode === "standalone" ? 0 : 8 } }, children: [
219
+ /* @__PURE__ */ jsxs(Stack, { className: "cko-container", sx: { gap: { sm: mode === "standalone" ? 0 : mode === "inline" ? 4 : 8 } }, children: [
203
220
  /* @__PURE__ */ jsx(Fade, { in: true, children: /* @__PURE__ */ jsxs(Stack, { className: "cko-overview", direction: "column", children: [
204
221
  mode === "standalone" ? /* @__PURE__ */ jsx(PaymentHeader, { checkoutSession: state.checkoutSession }) : null,
205
222
  /* @__PURE__ */ jsx(
@@ -214,20 +231,26 @@ export function PaymentInner({
214
231
  onDownsell,
215
232
  onApplyCrossSell,
216
233
  onCancelCrossSell,
234
+ onChangeAmount,
217
235
  checkoutSessionId: state.checkoutSession.id,
218
- crossSellBehavior: state.checkoutSession.cross_sell_behavior
236
+ crossSellBehavior: state.checkoutSession.cross_sell_behavior,
237
+ donationSettings: paymentLink?.donation_settings,
238
+ action
219
239
  }
220
240
  )
221
241
  ] }) }),
222
- /* @__PURE__ */ jsxs(Stack, { className: "cko-payment", direction: "column", spacing: 4, children: [
242
+ /* @__PURE__ */ jsxs(Stack, { className: "cko-payment", direction: "column", spacing: { xs: 2, sm: 4 }, children: [
223
243
  completed && /* @__PURE__ */ jsx(
224
244
  PaymentSuccess,
225
245
  {
246
+ mode,
226
247
  payee: getStatementDescriptor(state.checkoutSession.line_items),
227
248
  action: state.checkoutSession.mode,
228
249
  invoiceId: state.checkoutSession.invoice_id,
229
250
  subscriptionId: state.checkoutSession.subscription_id,
230
- message: paymentLink?.after_completion?.hosted_confirmation?.custom_message || t(`payment.checkout.completed.${state.checkoutSession.mode}`)
251
+ message: paymentLink?.after_completion?.hosted_confirmation?.custom_message || t(
252
+ `payment.checkout.completed.${paymentLink?.donation_settings ? "donate" : state.checkoutSession.mode}`
253
+ )
231
254
  }
232
255
  ),
233
256
  !completed && /* @__PURE__ */ jsx(
@@ -236,10 +259,12 @@ export function PaymentInner({
236
259
  checkoutSession: state.checkoutSession,
237
260
  paymentMethods,
238
261
  paymentIntent,
262
+ paymentLink,
239
263
  customer,
240
264
  onPaid: handlePaid,
241
265
  onError,
242
- mode
266
+ mode,
267
+ action
243
268
  }
244
269
  )
245
270
  ] }),
@@ -0,0 +1,7 @@
1
+ /// <reference types="react" />
2
+ import type { DonationSettings, TLineItemExpanded } from '@blocklet/payment-types';
3
+ export default function ProductDonation({ item, settings, onChange, }: {
4
+ item: TLineItemExpanded;
5
+ settings: DonationSettings;
6
+ onChange: Function;
7
+ }): import("react").JSX.Element;
@@ -0,0 +1,99 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { useLocaleContext } from "@arcblock/ux/lib/Locale/context";
3
+ import { Box, Card, CardActionArea, FormControlLabel, Stack, TextField, Typography } from "@mui/material";
4
+ import { useSetState } from "ahooks";
5
+ import { useEffect } from "react";
6
+ import Switch from "../components/switch-button.js";
7
+ export default function ProductDonation({
8
+ item,
9
+ settings,
10
+ onChange
11
+ }) {
12
+ const { t } = useLocaleContext();
13
+ const preset = settings.amount.preset || settings.amount.presets?.[0] || "0";
14
+ const [state, setState] = useSetState({
15
+ selected: preset,
16
+ input: "",
17
+ custom: settings.amount.presets?.length === 0,
18
+ error: ""
19
+ });
20
+ useEffect(() => {
21
+ if (settings.amount.preset) {
22
+ setState({ selected: settings.amount.preset, custom: false });
23
+ } else if (settings.amount.presets && settings.amount.presets.length > 0) {
24
+ setState({ selected: settings.amount.presets[0], custom: false });
25
+ }
26
+ }, [settings.amount.preset, settings.amount.presets, setState]);
27
+ const handleSelect = (amount) => {
28
+ setState({ selected: amount, custom: false, error: "" });
29
+ onChange({ priceId: item.price_id, amount });
30
+ };
31
+ const handleInput = (event) => {
32
+ const { value } = event.target;
33
+ const min = parseFloat(settings.amount.minimum || "0");
34
+ const max = settings.amount.maximum ? parseFloat(settings.amount.maximum) : Infinity;
35
+ if (value < min || value > max) {
36
+ setState({ input: value, error: t("payment.checkout.donation.between", { min, max }) });
37
+ return;
38
+ }
39
+ setState({ error: "", input: value });
40
+ onChange({ priceId: item.price_id, amount: value });
41
+ };
42
+ const handleToggle = (event) => {
43
+ if (event.target.checked) {
44
+ setState({ custom: true, input: state.selected, error: "" });
45
+ } else {
46
+ setState({ custom: false, input: "", error: "" });
47
+ }
48
+ };
49
+ return /* @__PURE__ */ jsxs(Box, { display: "flex", flexDirection: "column", alignItems: "flex-start", gap: 1.5, children: [
50
+ settings.amount.custom && preset !== "0" && /* @__PURE__ */ jsx(
51
+ FormControlLabel,
52
+ {
53
+ control: /* @__PURE__ */ jsx(Switch, { checked: state.custom, sx: { marginRight: 0.4 }, onChange: handleToggle }),
54
+ label: state.custom ? t("payment.checkout.donation.select") : t("payment.checkout.donation.custom"),
55
+ sx: { marginRight: 2, marginLeft: 0.5, color: "text.secondary" }
56
+ }
57
+ ),
58
+ !state.custom && /* @__PURE__ */ jsx(Box, { display: "flex", flexWrap: "wrap", alignItems: "center", gap: 1.5, children: settings.amount.presets && settings.amount.presets.length > 0 && settings.amount.presets.map((amount) => /* @__PURE__ */ jsx(
59
+ Card,
60
+ {
61
+ variant: "outlined",
62
+ sx: {
63
+ minWidth: 120,
64
+ textAlign: "center",
65
+ ...state.selected === amount && !state.custom ? { borderColor: "primary.main" } : {}
66
+ },
67
+ children: /* @__PURE__ */ jsx(CardActionArea, { onClick: () => handleSelect(amount), children: /* @__PURE__ */ jsxs(Stack, { direction: "row", sx: { py: 1 }, spacing: 0.5, alignItems: "flex-end", justifyContent: "center", children: [
68
+ /* @__PURE__ */ jsx(
69
+ Typography,
70
+ {
71
+ component: "strong",
72
+ lineHeight: 1,
73
+ variant: "h5",
74
+ sx: { fontVariantNumeric: "tabular-nums", fontWeight: 400 },
75
+ children: amount
76
+ }
77
+ ),
78
+ /* @__PURE__ */ jsx(Typography, { component: "small", lineHeight: 1, fontSize: 12, children: "ABT" }),
79
+ " "
80
+ ] }) })
81
+ },
82
+ amount
83
+ )) }),
84
+ state.custom && /* @__PURE__ */ jsx(
85
+ TextField,
86
+ {
87
+ label: preset !== "0" ? null : t("payment.checkout.donation.custom"),
88
+ type: "number",
89
+ value: state.input,
90
+ onChange: handleInput,
91
+ inputProps: { min: settings.amount.minimum, max: settings.amount.maximum },
92
+ margin: "none",
93
+ fullWidth: true,
94
+ error: !!state.error,
95
+ helperText: state.error
96
+ }
97
+ )
98
+ ] });
99
+ }
@@ -6,8 +6,8 @@ export default function OverviewSkeleton() {
6
6
  /* @__PURE__ */ jsx(Skeleton, { variant: "circular", width: 32, height: 32 }),
7
7
  /* @__PURE__ */ jsx(Skeleton, { variant: "text", sx: { fontSize: "2rem", width: "40%" } })
8
8
  ] }),
9
- /* @__PURE__ */ jsx(Typography, { mt: 3, component: "div", variant: "h4", children: /* @__PURE__ */ jsx(Skeleton, {}) }),
9
+ /* @__PURE__ */ jsx(Typography, { mt: 2, component: "div", variant: "h4", children: /* @__PURE__ */ jsx(Skeleton, {}) }),
10
10
  /* @__PURE__ */ jsx(Typography, { component: "div", variant: "h2", children: /* @__PURE__ */ jsx(Skeleton, {}) }),
11
- /* @__PURE__ */ jsx(Skeleton, { sx: { mt: 3 }, variant: "rounded", width: 200, height: 200 })
11
+ /* @__PURE__ */ jsx(Skeleton, { sx: { mt: 2 }, variant: "rounded", width: 200, height: 200 })
12
12
  ] }) });
13
13
  }
@@ -1,7 +1,7 @@
1
1
  import { jsx, jsxs } from "react/jsx-runtime";
2
2
  import { Box, Fade, Skeleton, Stack, Typography } from "@mui/material";
3
3
  export default function PaymentSkeleton() {
4
- return /* @__PURE__ */ jsx(Fade, { in: true, children: /* @__PURE__ */ jsxs(Stack, { direction: "column", spacing: 3, children: [
4
+ return /* @__PURE__ */ jsx(Fade, { in: true, children: /* @__PURE__ */ jsxs(Stack, { direction: "column", spacing: 2, children: [
5
5
  /* @__PURE__ */ jsx(Skeleton, { variant: "text", sx: { fontSize: "2rem", width: "40%" } }),
6
6
  /* @__PURE__ */ jsxs(Box, { children: [
7
7
  /* @__PURE__ */ jsx(Typography, { component: "div", variant: "h4", children: /* @__PURE__ */ jsx(Skeleton, {}) }),
@@ -11,9 +11,6 @@ export default function PaymentSkeleton() {
11
11
  /* @__PURE__ */ jsx(Typography, { component: "div", variant: "h4", children: /* @__PURE__ */ jsx(Skeleton, {}) }),
12
12
  /* @__PURE__ */ jsx(Typography, { component: "div", variant: "h1", children: /* @__PURE__ */ jsx(Skeleton, {}) })
13
13
  ] }),
14
- /* @__PURE__ */ jsxs(Box, { children: [
15
- /* @__PURE__ */ jsx(Typography, { component: "div", variant: "h4", children: /* @__PURE__ */ jsx(Skeleton, {}) }),
16
- /* @__PURE__ */ jsx(Typography, { component: "div", variant: "h1", children: /* @__PURE__ */ jsx(Skeleton, {}) })
17
- ] })
14
+ /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(Typography, { component: "div", variant: "h4", children: /* @__PURE__ */ jsx(Skeleton, {}) }) })
18
15
  ] }) });
19
16
  }
@@ -1,12 +1,13 @@
1
1
  /// <reference types="react" />
2
2
  type Props = {
3
+ mode: string;
3
4
  message: string;
4
5
  action: string;
5
6
  payee: string;
6
7
  invoiceId?: string;
7
8
  subscriptionId?: string;
8
9
  };
9
- declare function PaymentSuccess({ message, action, payee, invoiceId, subscriptionId }: Props): import("react").JSX.Element;
10
+ declare function PaymentSuccess({ mode, message, action, payee, invoiceId, subscriptionId }: Props): import("react").JSX.Element;
10
11
  declare namespace PaymentSuccess {
11
12
  var defaultProps: {
12
13
  invoiceId: string;
@@ -4,7 +4,7 @@ import { Grow, Link, Stack, Typography } from "@mui/material";
4
4
  import { styled } from "@mui/system";
5
5
  import { joinURL } from "ufo";
6
6
  import { usePaymentContext } from "../contexts/payment.js";
7
- export default function PaymentSuccess({ message, action, payee, invoiceId, subscriptionId }) {
7
+ export default function PaymentSuccess({ mode, message, action, payee, invoiceId, subscriptionId }) {
8
8
  const { t } = useLocaleContext();
9
9
  const { prefix } = usePaymentContext();
10
10
  let next = null;
@@ -13,17 +13,26 @@ export default function PaymentSuccess({ message, action, payee, invoiceId, subs
13
13
  } else if (invoiceId) {
14
14
  next = /* @__PURE__ */ jsx(Typography, { textAlign: "center", sx: { mt: 2 }, children: /* @__PURE__ */ jsx(Link, { href: joinURL(prefix, `/customer/invoice/${invoiceId}`), children: t("payment.checkout.next.invoice", { payee }) }) });
15
15
  }
16
- return /* @__PURE__ */ jsx(Grow, { in: true, children: /* @__PURE__ */ jsxs(Stack, { direction: "column", alignItems: "center", justifyContent: "center", sx: { height: 360 }, children: [
17
- /* @__PURE__ */ jsx(Div, { children: /* @__PURE__ */ jsxs("div", { className: "check-icon", children: [
18
- /* @__PURE__ */ jsx("span", { className: "icon-line line-tip" }),
19
- /* @__PURE__ */ jsx("span", { className: "icon-line line-long" }),
20
- /* @__PURE__ */ jsx("div", { className: "icon-circle" }),
21
- /* @__PURE__ */ jsx("div", { className: "icon-fix" })
22
- ] }) }),
23
- /* @__PURE__ */ jsx(Typography, { variant: "h5", color: "text.primary", mb: 3, children: message }),
24
- /* @__PURE__ */ jsx(Typography, { variant: "body1", color: "text.secondary", textAlign: "center", children: t("payment.checkout.completed.tip", { payee }) }),
25
- next
26
- ] }) });
16
+ return /* @__PURE__ */ jsx(Grow, { in: true, children: /* @__PURE__ */ jsxs(
17
+ Stack,
18
+ {
19
+ direction: "column",
20
+ alignItems: "center",
21
+ justifyContent: mode === "standalone" ? "center" : "flex-start",
22
+ sx: { height: mode === "standalone" ? 360 : 300 },
23
+ children: [
24
+ /* @__PURE__ */ jsx(Div, { children: /* @__PURE__ */ jsxs("div", { className: "check-icon", children: [
25
+ /* @__PURE__ */ jsx("span", { className: "icon-line line-tip" }),
26
+ /* @__PURE__ */ jsx("span", { className: "icon-line line-long" }),
27
+ /* @__PURE__ */ jsx("div", { className: "icon-circle" }),
28
+ /* @__PURE__ */ jsx("div", { className: "icon-fix" })
29
+ ] }) }),
30
+ /* @__PURE__ */ jsx(Typography, { variant: "h5", color: "text.primary", mb: 3, children: message }),
31
+ /* @__PURE__ */ jsx(Typography, { variant: "body1", color: "text.secondary", textAlign: "center", children: t("payment.checkout.completed.tip", { payee }) }),
32
+ next
33
+ ]
34
+ }
35
+ ) });
27
36
  }
28
37
  PaymentSuccess.defaultProps = {
29
38
  invoiceId: "",
@@ -1,5 +1,5 @@
1
1
  /// <reference types="react" />
2
- import type { TLineItemExpanded, TPaymentCurrency } from '@blocklet/payment-types';
2
+ import type { DonationSettings, TLineItemExpanded, TPaymentCurrency } from '@blocklet/payment-types';
3
3
  type Props = {
4
4
  items: TLineItemExpanded[];
5
5
  currency: TPaymentCurrency;
@@ -8,21 +8,27 @@ type Props = {
8
8
  showStaking?: boolean;
9
9
  onUpsell?: Function;
10
10
  onDownsell?: Function;
11
+ onChangeAmount?: Function;
11
12
  onApplyCrossSell?: Function;
12
13
  onCancelCrossSell?: Function;
13
14
  checkoutSessionId?: string;
14
15
  crossSellBehavior?: string;
16
+ donationSettings?: DonationSettings;
17
+ action?: string;
15
18
  };
16
- declare function PaymentSummary({ items, currency, trialInDays, billingThreshold, onUpsell, onDownsell, onApplyCrossSell, onCancelCrossSell, checkoutSessionId, crossSellBehavior, showStaking, ...rest }: Props): import("react").JSX.Element;
19
+ declare function PaymentSummary({ items, currency, trialInDays, billingThreshold, onUpsell, onDownsell, onApplyCrossSell, onCancelCrossSell, onChangeAmount, checkoutSessionId, crossSellBehavior, showStaking, donationSettings, action, ...rest }: Props): import("react").JSX.Element;
17
20
  declare namespace PaymentSummary {
18
21
  var defaultProps: {
19
22
  onUpsell: any;
20
23
  onDownsell: any;
21
24
  onApplyCrossSell: any;
22
25
  onCancelCrossSell: any;
26
+ onChangeAmount: any;
23
27
  checkoutSessionId: string;
24
28
  crossSellBehavior: string;
25
29
  showStaking: boolean;
30
+ donationSettings: null;
31
+ action: string;
26
32
  };
27
33
  }
28
34
  export default PaymentSummary;
@@ -11,6 +11,7 @@ import api from "../api.js";
11
11
  import Status from "../components/status.js";
12
12
  import { formatAmount, formatCheckoutHeadlines, getPriceUintAmountByCurrency } from "../util.js";
13
13
  import PaymentAmount from "./amount.js";
14
+ import ProductDonation from "./product-donation.js";
14
15
  import ProductItem from "./product-item.js";
15
16
  const shake = keyframes`
16
17
  0% {
@@ -69,9 +70,12 @@ PaymentSummary.defaultProps = {
69
70
  onDownsell: noop,
70
71
  onApplyCrossSell: noop,
71
72
  onCancelCrossSell: noop,
73
+ onChangeAmount: noop,
72
74
  checkoutSessionId: "",
73
75
  crossSellBehavior: "",
74
- showStaking: false
76
+ showStaking: false,
77
+ donationSettings: null,
78
+ action: ""
75
79
  };
76
80
  export default function PaymentSummary({
77
81
  items,
@@ -82,9 +86,12 @@ export default function PaymentSummary({
82
86
  onDownsell,
83
87
  onApplyCrossSell,
84
88
  onCancelCrossSell,
89
+ onChangeAmount,
85
90
  checkoutSessionId,
86
91
  crossSellBehavior,
87
92
  showStaking,
93
+ donationSettings,
94
+ action,
88
95
  ...rest
89
96
  }) {
90
97
  const { t, locale } = useLocaleContext();
@@ -135,35 +142,45 @@ export default function PaymentSummary({
135
142
  }
136
143
  };
137
144
  return /* @__PURE__ */ jsx(Fade, { in: true, children: /* @__PURE__ */ jsxs(Stack, { className: "cko-product", direction: "column", ...rest, children: [
138
- /* @__PURE__ */ jsxs(Stack, { className: "cko-product-summary", direction: "column", alignItems: "flex-start", sx: { mb: 4 }, children: [
139
- /* @__PURE__ */ jsx(Typography, { sx: { fontWeight: 500, fontSize: "1.15rem", color: "text.secondary" }, children: headlines.action }),
145
+ /* @__PURE__ */ jsxs(Stack, { className: "cko-product-summary", direction: "column", alignItems: "flex-start", sx: { mb: { xs: 0, sm: 3 } }, children: [
146
+ /* @__PURE__ */ jsx(Typography, { sx: { fontWeight: 500, fontSize: "1.15rem", color: "text.secondary" }, children: action || headlines.action }),
140
147
  /* @__PURE__ */ jsx(PaymentAmount, { amount: headlines.amount }),
141
148
  headlines.then && /* @__PURE__ */ jsx(Typography, { sx: { fontSize: "0.9rem", color: "text.secondary" }, children: headlines.then })
142
149
  ] }),
143
- /* @__PURE__ */ jsx(Stack, { spacing: 2, children: items.map((x) => /* @__PURE__ */ jsx(
144
- ProductItem,
145
- {
146
- item: x,
147
- items,
148
- trialInDays,
149
- currency,
150
- onUpsell: handleUpsell,
151
- onDownsell: handleDownsell,
152
- children: x.cross_sell && /* @__PURE__ */ jsx(
153
- LoadingButton,
154
- {
155
- size: "small",
156
- loadingPosition: "end",
157
- color: "error",
158
- variant: "text",
159
- loading: state.loading,
160
- onClick: handleCancelCrossSell,
161
- children: t("payment.checkout.cross_sell.remove")
162
- }
163
- )
164
- },
165
- `${x.price_id}-${currency.id}`
166
- )) }),
150
+ /* @__PURE__ */ jsx(Stack, { spacing: { xs: 1, sm: 2 }, children: items.map(
151
+ (x) => x.price.custom_unit_amount && onChangeAmount && donationSettings ? /* @__PURE__ */ jsx(
152
+ ProductDonation,
153
+ {
154
+ item: x,
155
+ settings: donationSettings,
156
+ onChange: onChangeAmount
157
+ },
158
+ `${x.price_id}-${currency.id}`
159
+ ) : /* @__PURE__ */ jsx(
160
+ ProductItem,
161
+ {
162
+ item: x,
163
+ items,
164
+ trialInDays,
165
+ currency,
166
+ onUpsell: handleUpsell,
167
+ onDownsell: handleDownsell,
168
+ children: x.cross_sell && /* @__PURE__ */ jsx(
169
+ LoadingButton,
170
+ {
171
+ size: "small",
172
+ loadingPosition: "end",
173
+ color: "error",
174
+ variant: "text",
175
+ loading: state.loading,
176
+ onClick: handleCancelCrossSell,
177
+ children: t("payment.checkout.cross_sell.remove")
178
+ }
179
+ )
180
+ },
181
+ `${x.price_id}-${currency.id}`
182
+ )
183
+ ) }),
167
184
  data && items.some((x) => x.price_id === data.id) === false && /* @__PURE__ */ jsx(Grow, { in: true, children: /* @__PURE__ */ jsxs(
168
185
  Stack,
169
186
  {
@@ -175,7 +192,7 @@ export default function PaymentSummary({
175
192
  borderRadius: 1,
176
193
  padding: 1,
177
194
  animation: state.shake ? `${shake} 0.2s 5 ease-in-out` : "none",
178
- mt: 3
195
+ mt: { xs: 1, sm: 2 }
179
196
  },
180
197
  children: [
181
198
  /* @__PURE__ */ jsx(
@@ -218,7 +235,7 @@ export default function PaymentSummary({
218
235
  border: "1px solid #eee",
219
236
  borderRadius: 1,
220
237
  padding: 1,
221
- mt: 3
238
+ mt: { xs: 1, sm: 2 }
222
239
  },
223
240
  children: [
224
241
  /* @__PURE__ */ jsxs(Stack, { direction: "row", alignItems: "center", spacing: 0.5, children: [
@@ -7,6 +7,7 @@ export type CheckoutContext = {
7
7
  paymentIntent?: TPaymentIntent;
8
8
  customer?: TCustomer;
9
9
  mode: LiteralUnion<'standalone' | 'inline' | 'popup', string>;
10
+ action?: string;
10
11
  };
11
12
  export type CheckoutFormData = {
12
13
  customer_name: string;
@@ -26,6 +27,7 @@ export type CheckoutFormData = {
26
27
  export type CheckoutProps = Partial<CheckoutCallbacks> & {
27
28
  id: string;
28
29
  extraParams?: Record<string, any>;
30
+ action?: string;
29
31
  mode?: LiteralUnion<'standalone' | 'inline' | 'popup' | 'inline-minimal' | 'popup-minimal', string>;
30
32
  };
31
33
  export type CheckoutCallbacks = {
package/es/util.d.ts CHANGED
@@ -25,6 +25,7 @@ export declare function formatLineItemPricing(item: TLineItemExpanded, currency:
25
25
  export declare function getSubscriptionStatusColor(status: string): "success" | "primary" | "warning" | "error" | "default";
26
26
  export declare function getPaymentIntentStatusColor(status: string): "success" | "warning" | "default";
27
27
  export declare function getRefundStatusColor(status: string): "success" | "warning" | "default";
28
+ export declare function getPayoutStatusColor(status: string): "success" | "warning" | "default";
28
29
  export declare function getInvoiceStatusColor(status: string): "success" | "warning" | "default" | "secondary";
29
30
  export declare function getWebhookStatusColor(status: string): "success" | "default";
30
31
  export declare function getCheckoutAmount(items: TLineItemExpanded[], currency: TPaymentCurrency, trialing?: boolean, upsell?: boolean): {
package/es/util.js CHANGED
@@ -78,6 +78,9 @@ export function formatNumber(n, precision = 6, trim = true) {
78
78
  return trim ? trimEnd(num.format(options), "0.") : num.format(options);
79
79
  }
80
80
  export const formatPrice = (price, currency, unit_label, quantity = 1, bn = true, locale = "en") => {
81
+ if (price.custom_unit_amount) {
82
+ return `Custom (${currency.symbol})`;
83
+ }
81
84
  const unit = getPriceUintAmountByCurrency(price, currency);
82
85
  const amount = bn ? fromUnitToToken(new BN(unit).mul(new BN(quantity)), currency.decimal).toString() : +unit * quantity;
83
86
  if (price?.type === "recurring" && price.recurring) {
@@ -143,9 +146,15 @@ export function getPriceUintAmountByCurrency(price, currency) {
143
146
  const options = getPriceCurrencyOptions(price);
144
147
  const option = options.find((x) => x.currency_id === currency.id);
145
148
  if (option) {
149
+ if (option.custom_unit_amount) {
150
+ return option.custom_unit_amount.preset || option.custom_unit_amount.presets[0];
151
+ }
146
152
  return option.unit_amount;
147
153
  }
148
154
  if (price.currency_id === currency.id) {
155
+ if (price.custom_unit_amount) {
156
+ return price.custom_unit_amount.preset || price.custom_unit_amount.presets[0];
157
+ }
149
158
  return price.unit_amount;
150
159
  }
151
160
  console.warn(`Currency ${currency.id} not configured for price`, price);
@@ -155,7 +164,14 @@ export function getPriceCurrencyOptions(price) {
155
164
  if (Array.isArray(price.currency_options)) {
156
165
  return price.currency_options;
157
166
  }
158
- return [{ currency_id: price.currency_id, unit_amount: price.unit_amount, tiers: null, custom_unit_amount: null }];
167
+ return [
168
+ {
169
+ currency_id: price.currency_id,
170
+ unit_amount: price.unit_amount,
171
+ custom_unit_amount: price.custom_unit_amount || null,
172
+ tiers: null
173
+ }
174
+ ];
159
175
  }
160
176
  export function formatLineItemPricing(item, currency, trial, locale = "en") {
161
177
  const price = item.upsell_price || item.price;
@@ -242,6 +258,19 @@ export function getRefundStatusColor(status) {
242
258
  return "default";
243
259
  }
244
260
  }
261
+ export function getPayoutStatusColor(status) {
262
+ switch (status) {
263
+ case "paid":
264
+ return "success";
265
+ case "failed":
266
+ return "warning";
267
+ case "canceled":
268
+ case "pending":
269
+ case "in_transit":
270
+ default:
271
+ return "default";
272
+ }
273
+ }
245
274
  export function getInvoiceStatusColor(status) {
246
275
  switch (status) {
247
276
  case "paid":
@@ -266,14 +295,26 @@ export function getWebhookStatusColor(status) {
266
295
  }
267
296
  }
268
297
  export function getCheckoutAmount(items, currency, trialing = false, upsell = true) {
298
+ if (items.find((x) => (x.upsell_price || x.price).custom_unit_amount) && items.length > 1) {
299
+ throw new Error("Multiple items with custom unit amount are not supported");
300
+ }
269
301
  let renew = new BN(0);
270
302
  const total = items.filter((x) => {
271
303
  const price = upsell ? x.upsell_price || x.price : x.price;
272
304
  return price != null;
273
305
  }).reduce((acc, x) => {
306
+ if (x.custom_amount) {
307
+ return acc.add(new BN(x.custom_amount));
308
+ }
274
309
  const price = upsell ? x.upsell_price || x.price : x.price;
310
+ const unitPrice = getPriceUintAmountByCurrency(price, currency);
311
+ if (price.custom_unit_amount) {
312
+ if (unitPrice) {
313
+ return acc.add(new BN(unitPrice).mul(new BN(x.quantity)));
314
+ }
315
+ }
275
316
  if (price?.type === "recurring") {
276
- renew = renew.add(new BN(getPriceUintAmountByCurrency(price, currency)).mul(new BN(x.quantity)));
317
+ renew = renew.add(new BN(unitPrice).mul(new BN(x.quantity)));
277
318
  if (trialing) {
278
319
  return acc;
279
320
  }
@@ -281,7 +322,7 @@ export function getCheckoutAmount(items, currency, trialing = false, upsell = tr
281
322
  return acc;
282
323
  }
283
324
  }
284
- return acc.add(new BN(getPriceUintAmountByCurrency(price, currency)).mul(new BN(x.quantity)));
325
+ return acc.add(new BN(unitPrice).mul(new BN(x.quantity)));
285
326
  }, new BN(0)).toString();
286
327
  return { subtotal: total, total, renew: renew.toString(), discount: "0", shipping: "0", tax: "0" };
287
328
  }
@@ -0,0 +1,20 @@
1
+ /// <reference types="react" />
2
+ import type { DonationSettings, TCheckoutSessionExpanded, TPaymentCurrency, TPaymentMethod } from '@blocklet/payment-types';
3
+ import { CheckoutProps } from '../types';
4
+ export type DonateHistory = {
5
+ supporters: TCheckoutSessionExpanded[];
6
+ currency: TPaymentCurrency;
7
+ method: TPaymentMethod;
8
+ total: number;
9
+ };
10
+ export type DonateProps = Pick<CheckoutProps, 'onPaid' | 'onError'> & {
11
+ settings: DonationSettings;
12
+ livemode?: boolean;
13
+ };
14
+ declare function CheckoutDonate({ settings, livemode, onPaid, onError }: DonateProps): import("react").JSX.Element;
15
+ declare namespace CheckoutDonate {
16
+ var defaultProps: {
17
+ livemode: boolean;
18
+ };
19
+ }
20
+ export default CheckoutDonate;