@blocklet/payment-react 1.13.113

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 (173) hide show
  1. package/LICENSE +13 -0
  2. package/README.md +29 -0
  3. package/babel.config.es.js +8 -0
  4. package/build.config.ts +29 -0
  5. package/es/api.d.ts +2 -0
  6. package/es/api.js +18 -0
  7. package/es/checkout/index.d.ts +15 -0
  8. package/es/checkout/index.js +61 -0
  9. package/es/components/input.d.ts +23 -0
  10. package/es/components/input.js +44 -0
  11. package/es/components/livemode.d.ts +2 -0
  12. package/es/components/livemode.js +24 -0
  13. package/es/components/pricing-table.d.ts +18 -0
  14. package/es/components/pricing-table.js +175 -0
  15. package/es/components/status.d.ts +3 -0
  16. package/es/components/status.js +20 -0
  17. package/es/components/switch.d.ts +6 -0
  18. package/es/components/switch.js +42 -0
  19. package/es/contexts/payment.d.ts +29 -0
  20. package/es/contexts/payment.js +45 -0
  21. package/es/dayjs.d.ts +2 -0
  22. package/es/dayjs.js +14 -0
  23. package/es/index.d.ts +16 -0
  24. package/es/index.js +29 -0
  25. package/es/locales/en.d.ts +2 -0
  26. package/es/locales/en.js +213 -0
  27. package/es/locales/index.d.ts +10 -0
  28. package/es/locales/index.js +20 -0
  29. package/es/locales/zh.d.ts +2 -0
  30. package/es/locales/zh.js +213 -0
  31. package/es/payment/amount.d.ts +12 -0
  32. package/es/payment/amount.js +22 -0
  33. package/es/payment/error.d.ts +13 -0
  34. package/es/payment/error.js +12 -0
  35. package/es/payment/footer.d.ts +4 -0
  36. package/es/payment/footer.js +9 -0
  37. package/es/payment/form/addon.d.ts +2 -0
  38. package/es/payment/form/addon.js +14 -0
  39. package/es/payment/form/address.d.ts +7 -0
  40. package/es/payment/form/address.js +119 -0
  41. package/es/payment/form/index.d.ts +9 -0
  42. package/es/payment/form/index.js +337 -0
  43. package/es/payment/form/phone.d.ts +4 -0
  44. package/es/payment/form/phone.js +97 -0
  45. package/es/payment/form/stripe.d.ts +13 -0
  46. package/es/payment/form/stripe.js +158 -0
  47. package/es/payment/header.d.ts +7 -0
  48. package/es/payment/header.js +29 -0
  49. package/es/payment/index.d.ts +28 -0
  50. package/es/payment/index.js +327 -0
  51. package/es/payment/product-card.d.ts +21 -0
  52. package/es/payment/product-card.js +34 -0
  53. package/es/payment/product-item.d.ts +19 -0
  54. package/es/payment/product-item.js +107 -0
  55. package/es/payment/product-skeleton.d.ts +4 -0
  56. package/es/payment/product-skeleton.js +34 -0
  57. package/es/payment/skeleton/overview.d.ts +2 -0
  58. package/es/payment/skeleton/overview.js +13 -0
  59. package/es/payment/skeleton/payment.d.ts +2 -0
  60. package/es/payment/skeleton/payment.js +19 -0
  61. package/es/payment/success.d.ts +8 -0
  62. package/es/payment/success.js +164 -0
  63. package/es/payment/summary.d.ts +12 -0
  64. package/es/payment/summary.js +178 -0
  65. package/es/theme.d.ts +1 -0
  66. package/es/theme.js +17 -0
  67. package/es/types/index.d.ts +19 -0
  68. package/es/types/index.js +0 -0
  69. package/es/types/shims.d.ts +18 -0
  70. package/es/util.d.ts +52 -0
  71. package/es/util.js +390 -0
  72. package/lib/api.d.ts +2 -0
  73. package/lib/api.js +26 -0
  74. package/lib/checkout/index.d.ts +15 -0
  75. package/lib/checkout/index.js +83 -0
  76. package/lib/components/input.d.ts +23 -0
  77. package/lib/components/input.js +72 -0
  78. package/lib/components/livemode.d.ts +2 -0
  79. package/lib/components/livemode.js +29 -0
  80. package/lib/components/pricing-table.d.ts +18 -0
  81. package/lib/components/pricing-table.js +232 -0
  82. package/lib/components/status.d.ts +3 -0
  83. package/lib/components/status.js +23 -0
  84. package/lib/components/switch.d.ts +6 -0
  85. package/lib/components/switch.js +51 -0
  86. package/lib/contexts/payment.d.ts +29 -0
  87. package/lib/contexts/payment.js +73 -0
  88. package/lib/dayjs.d.ts +2 -0
  89. package/lib/dayjs.js +21 -0
  90. package/lib/index.d.ts +16 -0
  91. package/lib/index.js +143 -0
  92. package/lib/locales/en.d.ts +2 -0
  93. package/lib/locales/en.js +220 -0
  94. package/lib/locales/index.d.ts +10 -0
  95. package/lib/locales/index.js +33 -0
  96. package/lib/locales/zh.d.ts +2 -0
  97. package/lib/locales/zh.js +220 -0
  98. package/lib/payment/amount.d.ts +12 -0
  99. package/lib/payment/amount.js +28 -0
  100. package/lib/payment/error.d.ts +13 -0
  101. package/lib/payment/error.js +52 -0
  102. package/lib/payment/footer.d.ts +4 -0
  103. package/lib/payment/footer.js +25 -0
  104. package/lib/payment/form/addon.d.ts +2 -0
  105. package/lib/payment/form/addon.js +37 -0
  106. package/lib/payment/form/address.d.ts +7 -0
  107. package/lib/payment/form/address.js +152 -0
  108. package/lib/payment/form/index.d.ts +9 -0
  109. package/lib/payment/form/index.js +464 -0
  110. package/lib/payment/form/phone.d.ts +4 -0
  111. package/lib/payment/form/phone.js +133 -0
  112. package/lib/payment/form/stripe.d.ts +13 -0
  113. package/lib/payment/form/stripe.js +213 -0
  114. package/lib/payment/header.d.ts +7 -0
  115. package/lib/payment/header.js +58 -0
  116. package/lib/payment/index.d.ts +28 -0
  117. package/lib/payment/index.js +382 -0
  118. package/lib/payment/product-card.d.ts +21 -0
  119. package/lib/payment/product-card.js +81 -0
  120. package/lib/payment/product-item.d.ts +19 -0
  121. package/lib/payment/product-item.js +160 -0
  122. package/lib/payment/product-skeleton.d.ts +4 -0
  123. package/lib/payment/product-skeleton.js +71 -0
  124. package/lib/payment/skeleton/overview.d.ts +2 -0
  125. package/lib/payment/skeleton/overview.js +48 -0
  126. package/lib/payment/skeleton/payment.d.ts +2 -0
  127. package/lib/payment/skeleton/payment.js +54 -0
  128. package/lib/payment/success.d.ts +8 -0
  129. package/lib/payment/success.js +215 -0
  130. package/lib/payment/summary.d.ts +12 -0
  131. package/lib/payment/summary.js +225 -0
  132. package/lib/theme.d.ts +1 -0
  133. package/lib/theme.js +19 -0
  134. package/lib/types/index.d.ts +19 -0
  135. package/lib/types/index.js +1 -0
  136. package/lib/types/shims.d.ts +18 -0
  137. package/lib/util.d.ts +52 -0
  138. package/lib/util.js +487 -0
  139. package/package.json +104 -0
  140. package/src/api.ts +24 -0
  141. package/src/checkout/index.tsx +74 -0
  142. package/src/components/input.tsx +58 -0
  143. package/src/components/livemode.tsx +23 -0
  144. package/src/components/pricing-table.tsx +207 -0
  145. package/src/components/status.tsx +19 -0
  146. package/src/components/switch.tsx +48 -0
  147. package/src/contexts/payment.tsx +74 -0
  148. package/src/dayjs.ts +17 -0
  149. package/src/index.ts +32 -0
  150. package/src/locales/en.tsx +218 -0
  151. package/src/locales/index.tsx +30 -0
  152. package/src/locales/zh.tsx +214 -0
  153. package/src/payment/amount.tsx +24 -0
  154. package/src/payment/error.tsx +29 -0
  155. package/src/payment/footer.tsx +12 -0
  156. package/src/payment/form/addon.tsx +24 -0
  157. package/src/payment/form/address.tsx +119 -0
  158. package/src/payment/form/index.tsx +401 -0
  159. package/src/payment/form/phone.tsx +103 -0
  160. package/src/payment/form/stripe.tsx +195 -0
  161. package/src/payment/header.tsx +40 -0
  162. package/src/payment/index.tsx +367 -0
  163. package/src/payment/product-card.tsx +55 -0
  164. package/src/payment/product-item.tsx +121 -0
  165. package/src/payment/product-skeleton.tsx +39 -0
  166. package/src/payment/skeleton/overview.tsx +21 -0
  167. package/src/payment/skeleton/payment.tsx +35 -0
  168. package/src/payment/success.tsx +186 -0
  169. package/src/payment/summary.tsx +198 -0
  170. package/src/theme.ts +18 -0
  171. package/src/types/index.ts +29 -0
  172. package/src/types/shims.d.ts +18 -0
  173. package/src/util.ts +543 -0
@@ -0,0 +1,186 @@
1
+ import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
2
+ import { Grow, Link, Stack, Typography } from '@mui/material';
3
+ import { styled } from '@mui/system';
4
+ import { joinURL } from 'ufo';
5
+
6
+ import { usePaymentContext } from '../contexts/payment';
7
+
8
+ type Props = {
9
+ message: string;
10
+ action: string;
11
+ payee: string;
12
+ };
13
+
14
+ export default function PaymentSuccess({ message, action, payee }: Props) {
15
+ const { t } = useLocaleContext();
16
+ const { prefix } = usePaymentContext();
17
+ return (
18
+ <Grow in>
19
+ <Stack direction="column" alignItems="center" justifyContent="center" sx={{ height: 360 }}>
20
+ <Div>
21
+ <div className="check-icon">
22
+ <span className="icon-line line-tip" />
23
+ <span className="icon-line line-long" />
24
+ <div className="icon-circle" />
25
+ <div className="icon-fix" />
26
+ </div>
27
+ </Div>
28
+ <Typography variant="h5" color="text.primary" mb={3}>
29
+ {message}
30
+ </Typography>
31
+ <Typography variant="body1" color="text.secondary" textAlign="center">
32
+ {t('payment.checkout.completed.tip', { payee })}
33
+ </Typography>
34
+ {['subscription', 'setup'].includes(action) && (
35
+ <Typography textAlign="center" sx={{ mt: 2 }}>
36
+ <Link href={joinURL(prefix, '/customer')}>{t('payment.checkout.portal', { payee })}</Link>
37
+ </Typography>
38
+ )}
39
+ </Stack>
40
+ </Grow>
41
+ );
42
+ }
43
+
44
+ const Div = styled('div')`
45
+ width: 80px;
46
+ height: 115px;
47
+
48
+ .check-icon {
49
+ width: 80px;
50
+ height: 80px;
51
+ position: relative;
52
+ border-radius: 50%;
53
+ box-sizing: content-box;
54
+ border: 4px solid ${(props) => props.theme.palette.success.main};
55
+ }
56
+ .check-icon::before {
57
+ top: 3px;
58
+ left: -2px;
59
+ width: 30px;
60
+ transform-origin: 100% 50%;
61
+ border-radius: 100px 0 0 100px;
62
+ }
63
+ .check-icon::after {
64
+ top: 0;
65
+ left: 30px;
66
+ width: 60px;
67
+ transform-origin: 0 50%;
68
+ border-radius: 0 100px 100px 0;
69
+ animation: rotate-circle 4.25s ease-in;
70
+ }
71
+ .check-icon::before,
72
+ .check-icon::after {
73
+ content: '';
74
+ height: 100px;
75
+ position: absolute;
76
+ background: #ffffff;
77
+ transform: rotate(-45deg);
78
+ }
79
+ .check-icon .icon-line {
80
+ height: 5px;
81
+ background-color: ${(props) => props.theme.palette.success.main};
82
+ display: block;
83
+ border-radius: 2px;
84
+ position: absolute;
85
+ z-index: 10;
86
+ }
87
+ .check-icon .icon-line.line-tip {
88
+ top: 46px;
89
+ left: 14px;
90
+ width: 25px;
91
+ transform: rotate(45deg);
92
+ animation: icon-line-tip 0.75s;
93
+ }
94
+ .check-icon .icon-line.line-long {
95
+ top: 38px;
96
+ right: 8px;
97
+ width: 47px;
98
+ transform: rotate(-45deg);
99
+ animation: icon-line-long 0.75s;
100
+ }
101
+ .check-icon .icon-circle {
102
+ top: -4px;
103
+ left: -4px;
104
+ z-index: 10;
105
+ width: 80px;
106
+ height: 80px;
107
+ border-radius: 50%;
108
+ position: absolute;
109
+ box-sizing: content-box;
110
+ border: 4px solid rgba(76, 175, 80, 0.5);
111
+ }
112
+ .check-icon .icon-fix {
113
+ top: 8px;
114
+ width: 5px;
115
+ left: 26px;
116
+ z-index: 1;
117
+ height: 85px;
118
+ position: absolute;
119
+ transform: rotate(-45deg);
120
+ background-color: #ffffff;
121
+ }
122
+
123
+ @keyframes rotate-circle {
124
+ 0% {
125
+ transform: rotate(-45deg);
126
+ }
127
+ 5% {
128
+ transform: rotate(-45deg);
129
+ }
130
+ 12% {
131
+ transform: rotate(-405deg);
132
+ }
133
+ 100% {
134
+ transform: rotate(-405deg);
135
+ }
136
+ }
137
+ @keyframes icon-line-tip {
138
+ 0% {
139
+ width: 0;
140
+ left: 1px;
141
+ top: 19px;
142
+ }
143
+ 54% {
144
+ width: 0;
145
+ left: 1px;
146
+ top: 19px;
147
+ }
148
+ 70% {
149
+ width: 50px;
150
+ left: -8px;
151
+ top: 37px;
152
+ }
153
+ 84% {
154
+ width: 17px;
155
+ left: 21px;
156
+ top: 48px;
157
+ }
158
+ 100% {
159
+ width: 25px;
160
+ left: 14px;
161
+ top: 45px;
162
+ }
163
+ }
164
+ @keyframes icon-line-long {
165
+ 0% {
166
+ width: 0;
167
+ right: 46px;
168
+ top: 54px;
169
+ }
170
+ 65% {
171
+ width: 0;
172
+ right: 46px;
173
+ top: 54px;
174
+ }
175
+ 84% {
176
+ width: 55px;
177
+ right: 0px;
178
+ top: 35px;
179
+ }
180
+ 100% {
181
+ width: 47px;
182
+ right: 8px;
183
+ top: 38px;
184
+ }
185
+ }
186
+ `;
@@ -0,0 +1,198 @@
1
+ import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
2
+ import type { TCheckoutSessionExpanded, TLineItemExpanded, TPaymentCurrency } from '@blocklet/payment-types';
3
+ import { LoadingButton } from '@mui/lab';
4
+ import { Fade, Grow, Stack, Typography, keyframes } from '@mui/material';
5
+ import { useRequest, useSetState } from 'ahooks';
6
+ import noop from 'lodash/noop';
7
+ import useBus from 'use-bus';
8
+
9
+ import api from '../api';
10
+ import Status from '../components/status';
11
+ import { formatCheckoutHeadlines } from '../util';
12
+ import PaymentAmount from './amount';
13
+ import ProductItem from './product-item';
14
+
15
+ const shake = keyframes`
16
+ 0% {
17
+ transform: rotate(0deg);
18
+ }
19
+ 25% {
20
+ transform: rotate(2deg);
21
+ }
22
+ 50% {
23
+ transform: rotate(0eg);
24
+ }
25
+ 75% {
26
+ transform: rotate(-2deg);
27
+ }
28
+ 100% {
29
+ transform: rotate(0deg);
30
+ }
31
+ `;
32
+
33
+ type Props = {
34
+ checkoutSession: TCheckoutSessionExpanded;
35
+ currency: TPaymentCurrency;
36
+ onUpsell: Function;
37
+ onDownsell: Function;
38
+ onApplyCrossSell: Function;
39
+ onCancelCrossSell: Function;
40
+ };
41
+
42
+ async function fetchCrossSell(id: string) {
43
+ try {
44
+ const { data } = await api.get(`/api/checkout-sessions/${id}/cross-sell`);
45
+ if (!data.error) {
46
+ return data;
47
+ }
48
+
49
+ return null;
50
+ } catch (err) {
51
+ return null;
52
+ }
53
+ }
54
+
55
+ export default function PaymentSummary({
56
+ checkoutSession,
57
+ currency,
58
+ onUpsell,
59
+ onDownsell,
60
+ onApplyCrossSell,
61
+ onCancelCrossSell,
62
+ }: Props) {
63
+ const { t, locale } = useLocaleContext();
64
+ const [state, setState] = useSetState({ loading: false, shake: false });
65
+ const { data, runAsync } = useRequest(() => fetchCrossSell(checkoutSession.id));
66
+ const headlines = formatCheckoutHeadlines(checkoutSession, currency, locale);
67
+
68
+ useBus(
69
+ 'error.REQUIRE_CROSS_SELL',
70
+ () => {
71
+ setState({ shake: true });
72
+ setTimeout(() => {
73
+ setState({ shake: false });
74
+ }, 1000);
75
+ },
76
+ []
77
+ );
78
+
79
+ const handleUpsell = async (from: string, to: string) => {
80
+ await onUpsell(from, to);
81
+ runAsync();
82
+ };
83
+
84
+ const handleDownsell = async (from: string) => {
85
+ await onDownsell(from);
86
+ runAsync();
87
+ };
88
+
89
+ const handleApplyCrossSell = async () => {
90
+ if (data) {
91
+ try {
92
+ setState({ loading: true });
93
+ await onApplyCrossSell(data.id);
94
+ } catch (err) {
95
+ console.error(err);
96
+ } finally {
97
+ setState({ loading: false });
98
+ }
99
+ }
100
+ };
101
+
102
+ const handleCancelCrossSell = async () => {
103
+ try {
104
+ setState({ loading: true });
105
+ await onCancelCrossSell();
106
+ } catch (err) {
107
+ console.error(err);
108
+ } finally {
109
+ setState({ loading: false });
110
+ }
111
+ };
112
+
113
+ return (
114
+ <Fade in>
115
+ <Stack
116
+ className="cko-product"
117
+ direction="column"
118
+ sx={{
119
+ mt: 8,
120
+ }}>
121
+ <Stack className="cko-product-summary" direction="column" alignItems="flex-start" sx={{ mb: 4 }}>
122
+ <Typography sx={{ fontWeight: 500, fontSize: '1.15rem', color: 'text.secondary' }}>
123
+ {headlines.action}
124
+ </Typography>
125
+ <PaymentAmount amount={headlines.amount} />
126
+ {headlines.then && (
127
+ <Typography sx={{ fontSize: '0.9rem', color: 'text.secondary' }}>{headlines.then}</Typography>
128
+ )}
129
+ </Stack>
130
+ <Stack spacing={2}>
131
+ {checkoutSession.line_items.map((x: TLineItemExpanded) => (
132
+ <ProductItem
133
+ key={x.price_id}
134
+ item={x}
135
+ session={checkoutSession}
136
+ currency={currency}
137
+ onUpsell={handleUpsell}
138
+ onDownsell={handleDownsell}>
139
+ {x.cross_sell && (
140
+ <LoadingButton
141
+ size="small"
142
+ loadingPosition="end"
143
+ color="error"
144
+ variant="text"
145
+ loading={state.loading}
146
+ onClick={handleCancelCrossSell}>
147
+ {t('payment.checkout.cross_sell.remove')}
148
+ </LoadingButton>
149
+ )}
150
+ </ProductItem>
151
+ ))}
152
+ </Stack>
153
+ {data && checkoutSession.line_items.some((x) => x.price_id === data.id) === false && (
154
+ <Grow in>
155
+ <Stack
156
+ direction="column"
157
+ alignItems="flex-end"
158
+ spacing={0.5}
159
+ sx={{
160
+ border: '1px solid #eee',
161
+ borderRadius: 1,
162
+ padding: 1,
163
+ animation: state.shake ? `${shake} 0.2s 5 ease-in-out` : 'none',
164
+ mt: {
165
+ xs: 4,
166
+ md: 8,
167
+ },
168
+ }}>
169
+ <ProductItem
170
+ item={{ quantity: 1, price: data, price_id: data.id, cross_sell: true } as TLineItemExpanded}
171
+ session={checkoutSession}
172
+ currency={currency}
173
+ onUpsell={noop}
174
+ onDownsell={noop}
175
+ />
176
+ <Stack direction="row" alignItems="center" justifyContent="space-between" sx={{ width: 1 }}>
177
+ <Typography>
178
+ {checkoutSession.cross_sell_behavior === 'required' && (
179
+ <Status label={t('payment.checkout.required')} color="info" variant="outlined" sx={{ mr: 1 }} />
180
+ )}
181
+ </Typography>
182
+ <LoadingButton
183
+ size="small"
184
+ loadingPosition="end"
185
+ color={checkoutSession.cross_sell_behavior === 'required' ? 'info' : 'info'}
186
+ variant={checkoutSession.cross_sell_behavior === 'required' ? 'text' : 'text'}
187
+ loading={state.loading}
188
+ onClick={handleApplyCrossSell}>
189
+ {t('payment.checkout.cross_sell.add')}
190
+ </LoadingButton>
191
+ </Stack>
192
+ </Stack>
193
+ </Grow>
194
+ )}
195
+ </Stack>
196
+ </Fade>
197
+ );
198
+ }
package/src/theme.ts ADDED
@@ -0,0 +1,18 @@
1
+ import { createTheme } from '@arcblock/ux/lib/Theme';
2
+ import merge from 'lodash/merge';
3
+
4
+ export default function create(settings: any = {}) {
5
+ return createTheme(
6
+ merge(
7
+ {
8
+ typography: {
9
+ fontSize: 14,
10
+ allVariants: {
11
+ textTransform: 'none',
12
+ },
13
+ },
14
+ },
15
+ settings
16
+ )
17
+ );
18
+ }
@@ -0,0 +1,29 @@
1
+ /* eslint-disable import/no-extraneous-dependencies */
2
+ import type {
3
+ TCheckoutSessionExpanded,
4
+ TCustomer,
5
+ TPaymentIntent,
6
+ TPaymentLink,
7
+ TPaymentMethodExpanded,
8
+ } from '@blocklet/payment-types';
9
+ import { LiteralUnion } from 'type-fest';
10
+
11
+ export type CheckoutContext = {
12
+ checkoutSession: TCheckoutSessionExpanded;
13
+ paymentMethods: TPaymentMethodExpanded[];
14
+ paymentLink?: TPaymentLink;
15
+ paymentIntent?: TPaymentIntent;
16
+ customer?: TCustomer;
17
+ mode: LiteralUnion<'standalone' | 'inline' | 'popup', string>;
18
+ };
19
+
20
+ export type CheckoutProps = Partial<CheckoutCallbacks> & {
21
+ id: string;
22
+ extraParams?: Record<string, any>;
23
+ mode?: LiteralUnion<'standalone' | 'inline' | 'popup', string>;
24
+ };
25
+
26
+ export type CheckoutCallbacks = {
27
+ onPaid: (res: CheckoutContext) => void;
28
+ onError: (err: Error) => void;
29
+ };
@@ -0,0 +1,18 @@
1
+ declare module '@arcblock/ux/*';
2
+ declare module '@arcblock/did-connect/*';
3
+
4
+ declare module '*.png';
5
+
6
+ declare module 'google-libphonenumber';
7
+
8
+ declare module 'flat';
9
+
10
+ declare module '@arcblock/*';
11
+
12
+ declare module '@blocklet/*';
13
+
14
+ declare module 'pretty-ms-i18n';
15
+
16
+ declare interface Window {
17
+ blocklet: any;
18
+ }