@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,74 @@
1
+ // eslint-disable-next-line import/no-extraneous-dependencies
2
+ import { TCheckoutSessionExpanded, TPaymentMethodExpanded } from '@blocklet/payment-types';
3
+ import { useRequest, useSetState } from 'ahooks';
4
+ import noop from 'lodash/noop';
5
+ import { useEffect } from 'react';
6
+ import { joinURL } from 'ufo';
7
+
8
+ import api from '../api';
9
+ import Payment from '../payment';
10
+ import { CheckoutContext, CheckoutProps } from '../types';
11
+ import { getPrefix, mergeExtraParams } from '../util';
12
+
13
+ const startFromPaymentLink = async (id: string, params?: Record<string, any>): Promise<CheckoutContext> => {
14
+ const { data } = await api.post(`/api/checkout-sessions/start/${id}?${mergeExtraParams(params)}`);
15
+ return data;
16
+ };
17
+
18
+ const fetchCheckoutSession = async (id: string): Promise<CheckoutContext> => {
19
+ const { data } = await api.get(`/api/checkout-sessions/retrieve/${id}`);
20
+ return data;
21
+ };
22
+
23
+ export default function Checkout({ id, onPaid, onError, mode, extraParams }: CheckoutProps) {
24
+ if (!id.startsWith('plink_') && !id.startsWith('cs_')) {
25
+ throw new Error('Either a checkout session or a payment link id is required.');
26
+ }
27
+
28
+ const type = id.startsWith('plink_') ? 'paymentLink' : 'checkoutSession';
29
+
30
+ const [state, setState] = useSetState({ completed: false, appError: null });
31
+
32
+ const { error: apiError, data } = useRequest(() =>
33
+ type === 'paymentLink' ? startFromPaymentLink(id, extraParams) : fetchCheckoutSession(id)
34
+ );
35
+
36
+ useEffect(() => {
37
+ if (type === 'paymentLink' && mode === 'standalone' && data) {
38
+ window.location.replace(joinURL(getPrefix(), `/checkout/pay/${data.checkoutSession.id}`));
39
+ }
40
+ }, [type, mode, data]);
41
+
42
+ const handlePaid = () => {
43
+ setState({ completed: true });
44
+ onPaid?.(data as CheckoutContext);
45
+ };
46
+
47
+ const handleError = (err: any) => {
48
+ console.error(err);
49
+ setState({ appError: err });
50
+ onError?.(err);
51
+ };
52
+
53
+ return (
54
+ <Payment
55
+ checkoutSession={data?.checkoutSession as TCheckoutSessionExpanded}
56
+ paymentMethods={data?.paymentMethods as TPaymentMethodExpanded[]}
57
+ paymentIntent={data?.paymentIntent}
58
+ paymentLink={data?.paymentLink}
59
+ customer={data?.customer}
60
+ completed={state.completed}
61
+ error={apiError || state.appError}
62
+ onPaid={handlePaid}
63
+ onError={handleError}
64
+ mode={mode as string}
65
+ />
66
+ );
67
+ }
68
+
69
+ Checkout.defaultProps = {
70
+ onPaid: noop,
71
+ onError: console.error,
72
+ mode: 'inline',
73
+ extraParams: {},
74
+ };
@@ -0,0 +1,58 @@
1
+ import { Box, FormLabel, InputAdornment, TextField, TextFieldProps, Typography } from '@mui/material';
2
+ import get from 'lodash/get';
3
+ import { Controller, RegisterOptions, useFormContext } from 'react-hook-form';
4
+
5
+ type InputProps = TextFieldProps & {
6
+ name: string;
7
+ label?: string;
8
+ placeholder?: string;
9
+ errorPosition?: 'right' | 'bottom';
10
+ rules?: RegisterOptions;
11
+ };
12
+
13
+ FormInput.defaultProps = {
14
+ label: '',
15
+ placeholder: '',
16
+ errorPosition: 'bottom',
17
+ rules: {},
18
+ };
19
+
20
+ export function FormInputError({ error }: { error: string }) {
21
+ return (
22
+ <InputAdornment position="end">
23
+ <Typography component="span" color="error">
24
+ {error}
25
+ </Typography>
26
+ </InputAdornment>
27
+ );
28
+ }
29
+
30
+ export default function FormInput({ name, label, placeholder, rules, errorPosition, ...rest }: InputProps) {
31
+ const { control, formState } = useFormContext();
32
+ const error = get(formState.errors, name)?.message as string;
33
+ return (
34
+ <Controller
35
+ name={name}
36
+ control={control}
37
+ rules={rules}
38
+ render={({ field }) => (
39
+ <Box sx={{ width: '100%' }}>
40
+ {!!label && <FormLabel>{label}</FormLabel>}
41
+ <TextField
42
+ fullWidth
43
+ error={!!get(formState.errors, name)}
44
+ helperText={errorPosition === 'bottom' && error ? error : ''}
45
+ placeholder={placeholder}
46
+ size="small"
47
+ {...field}
48
+ {...rest}
49
+ InputProps={Object.assign(
50
+ rest.InputProps || {},
51
+ errorPosition === 'right' && error ? { endAdornment: <FormInputError error={error} /> } : {}
52
+ )}
53
+ />
54
+ </Box>
55
+ )}
56
+ />
57
+ );
58
+ }
@@ -0,0 +1,23 @@
1
+ import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
2
+ import { Chip } from '@mui/material';
3
+
4
+ export default function Livemode() {
5
+ const { t } = useLocaleContext();
6
+ return (
7
+ <Chip
8
+ label={t('common.livemode')}
9
+ size="small"
10
+ sx={{
11
+ ml: 2,
12
+ height: 18,
13
+ lineHeight: 1,
14
+ textTransform: 'uppercase',
15
+ fontSize: '0.8rem',
16
+ fontWeight: 'bold',
17
+ borderRadius: '4px',
18
+ backgroundColor: '#ffde92',
19
+ color: '#bb5504',
20
+ }}
21
+ />
22
+ );
23
+ }
@@ -0,0 +1,207 @@
1
+ /* eslint-disable no-nested-ternary */
2
+ import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
3
+ import Toast from '@arcblock/ux/lib/Toast';
4
+ import type { PriceRecurring, TPricingTableExpanded, TPricingTableItem } from '@blocklet/payment-types';
5
+ import { CheckOutlined } from '@mui/icons-material';
6
+ import { LoadingButton } from '@mui/lab';
7
+ import {
8
+ Box,
9
+ Chip,
10
+ Fade,
11
+ List,
12
+ ListItem,
13
+ ListItemIcon,
14
+ ListItemText,
15
+ Stack,
16
+ ToggleButton,
17
+ ToggleButtonGroup,
18
+ Typography,
19
+ } from '@mui/material';
20
+ import { useSetState } from 'ahooks';
21
+ import { useEffect } from 'react';
22
+
23
+ import Amount from '../payment/amount';
24
+ import { formatError, formatPriceAmount, formatRecurring } from '../util';
25
+
26
+ const groupItemsByRecurring = (items: TPricingTableItem[]) => {
27
+ const grouped: { [key: string]: TPricingTableItem[] } = {};
28
+ const recurring: { [key: string]: PriceRecurring } = {};
29
+
30
+ items.forEach((x) => {
31
+ const key = [x.price.recurring?.interval, x.price.recurring?.interval_count].join('-');
32
+ recurring[key] = x.price.recurring as PriceRecurring;
33
+
34
+ if (!grouped[key]) {
35
+ grouped[key] = [];
36
+ }
37
+
38
+ // @ts-ignore
39
+ grouped[key].push(x);
40
+ });
41
+
42
+ return { recurring, grouped };
43
+ };
44
+
45
+ type Props = {
46
+ table: TPricingTableExpanded;
47
+ onSelect: (priceId: string) => void;
48
+ alignItems?: 'center' | 'left';
49
+ mode?: 'checkout' | 'select';
50
+ interval?: string;
51
+ };
52
+
53
+ PricingTable.defaultProps = {
54
+ alignItems: 'center',
55
+ mode: 'checkout',
56
+ interval: '',
57
+ };
58
+
59
+ export default function PricingTable({ table, alignItems, interval, mode, onSelect }: Props) {
60
+ const { t, locale } = useLocaleContext();
61
+ const [state, setState] = useSetState({ interval, loading: '' });
62
+ const { recurring, grouped } = groupItemsByRecurring(table.items);
63
+
64
+ useEffect(() => {
65
+ if (table) {
66
+ if (!state.interval || !grouped[state.interval]) {
67
+ const keys = Object.keys(recurring);
68
+ if (keys[0]) {
69
+ setState({ interval: keys[0] });
70
+ }
71
+ }
72
+ }
73
+ // eslint-disable-next-line react-hooks/exhaustive-deps
74
+ }, [table]);
75
+
76
+ const handleSelect = async (priceId: string) => {
77
+ try {
78
+ setState({ loading: priceId });
79
+ await onSelect(priceId);
80
+ } catch (err) {
81
+ console.error(err);
82
+ Toast.error(formatError(err));
83
+ } finally {
84
+ setState({ loading: '' });
85
+ }
86
+ };
87
+
88
+ return (
89
+ <Stack
90
+ direction="column"
91
+ alignItems={alignItems === 'center' ? 'center' : 'flex-start'}
92
+ sx={{
93
+ pt: {
94
+ xs: 4,
95
+ sm: 2,
96
+ },
97
+ gap: {
98
+ xs: 3,
99
+ sm: mode === 'select' ? 3 : 5,
100
+ },
101
+ }}>
102
+ {Object.keys(recurring).length > 1 && (
103
+ <ToggleButtonGroup
104
+ color="primary"
105
+ value={state.interval}
106
+ onChange={(_, value) => {
107
+ if (value !== null) {
108
+ setState({ interval: value });
109
+ }
110
+ }}
111
+ exclusive>
112
+ {Object.keys(recurring).map((x) => (
113
+ <ToggleButton key={x} value={x} sx={{ textTransform: 'capitalize' }}>
114
+ {formatRecurring(recurring[x] as PriceRecurring, true, '', locale)}
115
+ </ToggleButton>
116
+ ))}
117
+ </ToggleButtonGroup>
118
+ )}
119
+ <Stack
120
+ flexWrap="wrap"
121
+ direction="row"
122
+ gap={{ xs: 3, sm: 5, md: mode === 'checkout' ? 10 : 5 }}
123
+ justifyContent={alignItems === 'center' ? 'center' : 'flex-start'}>
124
+ {grouped[state.interval as string]?.map((x: TPricingTableItem) => {
125
+ let action = x.subscription_data?.trial_period_days
126
+ ? t('payment.checkout.try')
127
+ : t('payment.checkout.subscription');
128
+ if (mode === 'select') {
129
+ action = x.is_selected ? t('payment.checkout.selected') : t('payment.checkout.select');
130
+ }
131
+
132
+ return (
133
+ <Fade key={x.price_id} in>
134
+ <Stack
135
+ padding={4}
136
+ spacing={2}
137
+ direction="column"
138
+ alignItems="center"
139
+ sx={{
140
+ width: 320,
141
+ cursor: 'pointer',
142
+ borderWidth: '1px',
143
+ borderStyle: 'solid',
144
+ borderColor: mode === 'select' && x.is_selected ? 'primary.main' : '#eee',
145
+ borderRadius: 1,
146
+ transition: 'border-color 0.3s ease 0s, box-shadow 0.3s ease 0s',
147
+ boxShadow: '0 4px 8px rgba(0, 0, 0, 20%)',
148
+ '&:hover': {
149
+ borderColor: mode === 'select' && x.is_selected ? 'primary.main' : '#ddd',
150
+ boxShadow: '0 8px 16px rgba(0, 0, 0, 20%)',
151
+ },
152
+ }}>
153
+ <Box textAlign="center">
154
+ <Stack direction="row" alignItems="center" spacing={1}>
155
+ <Typography variant="h5" color="text.primary" fontWeight={600}>
156
+ {x.product.name}
157
+ </Typography>
158
+ {x.is_highlight && <Chip label={x.highlight_text} color="default" size="small" />}
159
+ </Stack>
160
+ <Typography color="text.secondary">{x.product.description}</Typography>
161
+ </Box>
162
+ <Stack direction="row" alignItems="center" spacing={1}>
163
+ <Amount amount={formatPriceAmount(x.price, table.currency, x.product.unit_label)} />
164
+ <Stack direction="column" alignItems="flex-start">
165
+ <Typography component="span" color="text.secondary" fontSize="0.8rem">
166
+ {t('payment.checkout.per')}
167
+ </Typography>
168
+ <Typography component="span" color="text.secondary" fontSize="0.8rem">
169
+ {formatRecurring(x.price.recurring as PriceRecurring, false, '', locale)}
170
+ </Typography>
171
+ </Stack>
172
+ </Stack>
173
+ <LoadingButton
174
+ fullWidth
175
+ size="large"
176
+ loadingPosition="end"
177
+ variant={x.is_highlight || x.is_selected ? 'contained' : 'outlined'}
178
+ color={x.is_highlight || x.is_selected ? 'primary' : 'info'}
179
+ sx={{ fontSize: '1.2rem' }}
180
+ loading={state.loading === x.price_id}
181
+ disabled={x.is_disabled}
182
+ onClick={() => handleSelect(x.price_id)}>
183
+ {action}
184
+ </LoadingButton>
185
+ {x.product.features.length > 0 && (
186
+ <Box>
187
+ <Typography>{t('payment.checkout.include')}</Typography>
188
+ <List dense>
189
+ {x.product.features.map((f: any) => (
190
+ <ListItem key={f.name} disableGutters disablePadding>
191
+ <ListItemIcon sx={{ minWidth: 25 }}>
192
+ <CheckOutlined color="success" fontSize="small" />
193
+ </ListItemIcon>
194
+ <ListItemText primary={f.name} />
195
+ </ListItem>
196
+ ))}
197
+ </List>
198
+ </Box>
199
+ )}
200
+ </Stack>
201
+ </Fade>
202
+ );
203
+ })}
204
+ </Stack>
205
+ </Stack>
206
+ );
207
+ }
@@ -0,0 +1,19 @@
1
+ import { Chip, ChipProps } from '@mui/material';
2
+
3
+ export default function Status(props: ChipProps) {
4
+ return (
5
+ <Chip
6
+ size="small"
7
+ variant="outlined"
8
+ {...props}
9
+ sx={{
10
+ ...(props.sx || {}),
11
+ borderRadius: '4px',
12
+ height: 20,
13
+ lineHeight: 1,
14
+ textTransform: 'capitalize',
15
+ marginRight: '10px',
16
+ }}
17
+ />
18
+ );
19
+ }
@@ -0,0 +1,48 @@
1
+ import { Switch } from '@mui/material';
2
+ import { styled } from '@mui/system';
3
+ import type { LiteralUnion } from 'type-fest';
4
+
5
+ type SwitchProps = {
6
+ variant?: LiteralUnion<'success' | 'error' | 'warning' | 'info' | 'primary' | 'secondary', string>;
7
+ };
8
+
9
+ export default styled(Switch)<SwitchProps>(({ variant = 'success', theme }) => ({
10
+ width: 28,
11
+ height: 16,
12
+ padding: 0,
13
+ display: 'inline-flex',
14
+ '&:active': {
15
+ '& .MuiSwitch-thumb': {
16
+ width: 15,
17
+ },
18
+ '& .MuiSwitch-switchBase.Mui-checked': {
19
+ transform: 'translateX(9px)',
20
+ },
21
+ },
22
+ '& .MuiSwitch-switchBase': {
23
+ padding: 2,
24
+ '&.Mui-checked': {
25
+ transform: 'translateX(12px)',
26
+ color: '#fff',
27
+ '& + .MuiSwitch-track': {
28
+ opacity: 1,
29
+ backgroundColor: theme.palette[variant].light,
30
+ },
31
+ },
32
+ },
33
+ '& .MuiSwitch-thumb': {
34
+ boxShadow: '0 2px 4px 0 rgb(0 35 11 / 20%)',
35
+ width: 12,
36
+ height: 12,
37
+ borderRadius: 6,
38
+ transition: (theme.transitions as any).create(['width'], {
39
+ duration: 200,
40
+ }),
41
+ },
42
+ '& .MuiSwitch-track': {
43
+ borderRadius: 16 / 2,
44
+ opacity: 1,
45
+ backgroundColor: theme.palette.mode === 'dark' ? 'rgba(255,255,255,.35)' : 'rgba(0,0,0,.25)',
46
+ boxSizing: 'border-box',
47
+ },
48
+ }));
@@ -0,0 +1,74 @@
1
+ import type { TPaymentCurrency, TPaymentMethodExpanded } from '@blocklet/payment-types';
2
+ import { Alert, CircularProgress } from '@mui/material';
3
+ import { useLocalStorageState, useRequest } from 'ahooks';
4
+ import type { Axios } from 'axios';
5
+ import { createContext, useContext } from 'react';
6
+
7
+ import api from '../api';
8
+ import { getPrefix } from '../util';
9
+
10
+ const prefix = getPrefix();
11
+
12
+ export interface Settings {
13
+ paymentMethods: TPaymentMethodExpanded[];
14
+ baseCurrency: TPaymentCurrency;
15
+ }
16
+
17
+ export type PaymentContextType = {
18
+ livemode: boolean;
19
+ session: any;
20
+ connect: any;
21
+ prefix: string;
22
+ settings: Settings;
23
+ refresh: () => void;
24
+ setLivemode: (livemode: boolean) => void;
25
+ api: Axios;
26
+ };
27
+
28
+ // @ts-ignore
29
+ const PaymentContext = createContext<PaymentContextType>({ api });
30
+ const { Provider, Consumer } = PaymentContext;
31
+
32
+ const getSettings = async () => {
33
+ const { data } = await api.get('/api/settings');
34
+ return data;
35
+ };
36
+
37
+ // eslint-disable-next-line react/prop-types
38
+ function PaymentProvider({ children, session, connect }: { children: any; session: any; connect: any }): JSX.Element {
39
+ const { data, error, run, loading } = useRequest(getSettings);
40
+ const [livemode, setLivemode] = useLocalStorageState('livemode', { defaultValue: true });
41
+
42
+ if (error) {
43
+ return <Alert severity="error">{error.message}</Alert>;
44
+ }
45
+
46
+ if (loading) {
47
+ return <CircularProgress />;
48
+ }
49
+
50
+ return (
51
+ <Provider
52
+ value={{
53
+ session,
54
+ connect,
55
+ prefix,
56
+ livemode: !!livemode,
57
+ settings: data,
58
+ refresh: run,
59
+ setLivemode,
60
+ api,
61
+ }}>
62
+ {children}
63
+ </Provider>
64
+ );
65
+ }
66
+
67
+ function usePaymentContext() {
68
+ const context = useContext(PaymentContext);
69
+ return context;
70
+ }
71
+
72
+ PaymentProvider.defaultProps = {};
73
+
74
+ export { PaymentContext, PaymentProvider, Consumer as SettingsConsumer, usePaymentContext };
package/src/dayjs.ts ADDED
@@ -0,0 +1,17 @@
1
+ import dayjs from 'dayjs';
2
+ import duration from 'dayjs/plugin/duration';
3
+ import localizedFormat from 'dayjs/plugin/localizedFormat';
4
+ import relativeTime from 'dayjs/plugin/relativeTime';
5
+ import timezone from 'dayjs/plugin/timezone'; // dependent on utc plugin
6
+ import utc from 'dayjs/plugin/utc';
7
+
8
+ import('dayjs/locale/en');
9
+ import('dayjs/locale/zh');
10
+
11
+ dayjs.extend(relativeTime);
12
+ dayjs.extend(localizedFormat);
13
+ dayjs.extend(duration);
14
+ dayjs.extend(utc);
15
+ dayjs.extend(timezone);
16
+
17
+ export default dayjs;
package/src/index.ts ADDED
@@ -0,0 +1,32 @@
1
+ import api from './api';
2
+ import Checkout from './checkout';
3
+ import FormInput from './components/input';
4
+ import Livemode from './components/livemode';
5
+ import PricingTable from './components/pricing-table';
6
+ import Status from './components/status';
7
+ import Switch from './components/switch';
8
+ import dayjs from './dayjs';
9
+ import Amount from './payment/amount';
10
+ import PhoneInput from './payment/form/phone';
11
+ import Payment from './payment/index';
12
+ import ProductSkeleton from './payment/product-skeleton';
13
+
14
+ export * from './util';
15
+ export * from './contexts/payment';
16
+
17
+ export { translations, createTranslator } from './locales';
18
+
19
+ export {
20
+ api,
21
+ dayjs,
22
+ FormInput,
23
+ PhoneInput,
24
+ Status,
25
+ Livemode,
26
+ Switch,
27
+ Checkout,
28
+ Payment,
29
+ PricingTable,
30
+ ProductSkeleton,
31
+ Amount,
32
+ };