@blocklet/payment-react 1.14.21 → 1.14.22

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 (136) hide show
  1. package/es/checkout/donate.d.ts +2 -1
  2. package/es/checkout/donate.js +9 -10
  3. package/es/checkout/form.d.ts +1 -1
  4. package/es/checkout/form.js +23 -1
  5. package/es/checkout/table.d.ts +1 -1
  6. package/es/checkout/table.js +8 -1
  7. package/es/components/blockchain/tx.js +2 -1
  8. package/es/components/country-select.d.ts +16 -0
  9. package/es/components/country-select.js +82 -0
  10. package/es/components/input.d.ts +21 -21
  11. package/es/components/input.js +43 -42
  12. package/es/components/livemode.js +1 -0
  13. package/es/components/pricing-table.js +0 -2
  14. package/es/components/status.js +2 -3
  15. package/es/components/table.d.ts +2 -0
  16. package/es/components/table.js +186 -0
  17. package/es/contexts/payment.d.ts +2 -0
  18. package/es/contexts/payment.js +5 -2
  19. package/es/history/invoice/list.d.ts +3 -1
  20. package/es/history/invoice/list.js +215 -48
  21. package/es/hooks/mobile.d.ts +4 -0
  22. package/es/hooks/mobile.js +10 -0
  23. package/es/index.d.ts +5 -1
  24. package/es/index.js +7 -1
  25. package/es/libs/util.d.ts +15 -2
  26. package/es/libs/util.js +92 -28
  27. package/es/locales/en.js +22 -7
  28. package/es/locales/index.d.ts +0 -1
  29. package/es/locales/index.js +10 -1
  30. package/es/locales/zh.js +21 -6
  31. package/es/payment/error.js +2 -2
  32. package/es/payment/footer.js +1 -1
  33. package/es/payment/form/address.d.ts +9 -2
  34. package/es/payment/form/address.js +69 -69
  35. package/es/payment/form/currency.js +39 -25
  36. package/es/payment/form/index.d.ts +1 -1
  37. package/es/payment/form/index.js +83 -81
  38. package/es/payment/form/phone.js +15 -51
  39. package/es/payment/index.d.ts +1 -10
  40. package/es/payment/index.js +274 -219
  41. package/es/payment/product-card.js +4 -4
  42. package/es/payment/product-donation.js +7 -2
  43. package/es/payment/product-item.d.ts +2 -2
  44. package/es/payment/product-item.js +120 -81
  45. package/es/payment/summary.js +188 -118
  46. package/es/theme/index.css +240 -0
  47. package/es/theme/index.d.ts +9 -0
  48. package/es/theme/index.js +243 -0
  49. package/es/theme/typography.d.ts +2 -0
  50. package/es/theme/typography.js +53 -0
  51. package/es/types/index.d.ts +11 -0
  52. package/lib/checkout/donate.d.ts +2 -1
  53. package/lib/checkout/donate.js +14 -2
  54. package/lib/checkout/form.d.ts +1 -1
  55. package/lib/checkout/form.js +22 -1
  56. package/lib/checkout/table.d.ts +1 -1
  57. package/lib/checkout/table.js +14 -1
  58. package/lib/components/blockchain/tx.js +4 -1
  59. package/lib/components/country-select.d.ts +16 -0
  60. package/lib/components/country-select.js +115 -0
  61. package/lib/components/input.d.ts +21 -21
  62. package/lib/components/input.js +21 -12
  63. package/lib/components/livemode.js +1 -0
  64. package/lib/components/pricing-table.js +0 -2
  65. package/lib/components/status.js +2 -3
  66. package/lib/components/table.d.ts +2 -0
  67. package/lib/components/table.js +220 -0
  68. package/lib/contexts/payment.d.ts +2 -0
  69. package/lib/contexts/payment.js +4 -1
  70. package/lib/history/invoice/list.d.ts +3 -1
  71. package/lib/history/invoice/list.js +290 -62
  72. package/lib/hooks/mobile.d.ts +4 -0
  73. package/lib/hooks/mobile.js +17 -0
  74. package/lib/index.d.ts +5 -1
  75. package/lib/index.js +36 -0
  76. package/lib/libs/util.d.ts +15 -2
  77. package/lib/libs/util.js +115 -37
  78. package/lib/locales/en.js +22 -7
  79. package/lib/locales/index.d.ts +0 -1
  80. package/lib/locales/index.js +14 -3
  81. package/lib/locales/zh.js +21 -6
  82. package/lib/payment/error.js +5 -1
  83. package/lib/payment/footer.js +1 -1
  84. package/lib/payment/form/address.d.ts +9 -2
  85. package/lib/payment/form/address.js +67 -59
  86. package/lib/payment/form/currency.js +31 -24
  87. package/lib/payment/form/index.d.ts +1 -1
  88. package/lib/payment/form/index.js +92 -93
  89. package/lib/payment/form/phone.js +11 -59
  90. package/lib/payment/index.d.ts +1 -10
  91. package/lib/payment/index.js +291 -219
  92. package/lib/payment/product-card.js +5 -4
  93. package/lib/payment/product-donation.js +9 -2
  94. package/lib/payment/product-item.d.ts +2 -2
  95. package/lib/payment/product-item.js +38 -19
  96. package/lib/payment/summary.js +219 -127
  97. package/lib/theme/index.css +240 -0
  98. package/lib/theme/index.d.ts +9 -0
  99. package/lib/theme/index.js +259 -0
  100. package/lib/theme/typography.d.ts +2 -0
  101. package/lib/theme/typography.js +59 -0
  102. package/lib/types/index.d.ts +11 -0
  103. package/package.json +14 -11
  104. package/src/checkout/donate.tsx +16 -10
  105. package/src/checkout/form.tsx +23 -0
  106. package/src/checkout/table.tsx +13 -1
  107. package/src/components/blockchain/tx.tsx +2 -1
  108. package/src/components/country-select.tsx +93 -0
  109. package/src/components/input.tsx +49 -46
  110. package/src/components/livemode.tsx +1 -0
  111. package/src/components/pricing-table.tsx +0 -2
  112. package/src/components/status.tsx +1 -2
  113. package/src/components/table.tsx +200 -0
  114. package/src/contexts/payment.tsx +6 -1
  115. package/src/history/invoice/list.tsx +254 -49
  116. package/src/hooks/mobile.ts +13 -0
  117. package/src/index.ts +7 -0
  118. package/src/libs/util.ts +120 -31
  119. package/src/locales/en.tsx +18 -4
  120. package/src/locales/index.tsx +10 -3
  121. package/src/locales/zh.tsx +17 -3
  122. package/src/payment/error.tsx +2 -2
  123. package/src/payment/footer.tsx +1 -1
  124. package/src/payment/form/address.tsx +56 -47
  125. package/src/payment/form/currency.tsx +29 -23
  126. package/src/payment/form/index.tsx +89 -76
  127. package/src/payment/form/phone.tsx +14 -51
  128. package/src/payment/index.tsx +294 -242
  129. package/src/payment/product-card.tsx +4 -4
  130. package/src/payment/product-donation.tsx +7 -3
  131. package/src/payment/product-item.tsx +49 -20
  132. package/src/payment/summary.tsx +191 -108
  133. package/src/theme/index.css +240 -0
  134. package/src/theme/index.tsx +250 -0
  135. package/src/theme/typography.ts +56 -0
  136. package/src/types/index.ts +12 -0
@@ -1,3 +1,7 @@
1
+ /* eslint-disable @typescript-eslint/indent */
2
+ /* eslint-disable react/require-default-props */
3
+ /* eslint-disable react/no-unused-prop-types */
4
+ /* eslint-disable @typescript-eslint/naming-convention */
1
5
  /* eslint-disable no-nested-ternary */
2
6
  /* eslint-disable react/no-unstable-nested-components */
3
7
  import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
@@ -6,8 +10,8 @@ import type { Paginated, TInvoiceExpanded, TSubscription } from '@blocklet/payme
6
10
  import { OpenInNewOutlined } from '@mui/icons-material';
7
11
  import { Box, Button, CircularProgress, Hidden, Stack, Typography } from '@mui/material';
8
12
  import { styled } from '@mui/system';
9
- import { useInfiniteScroll, useSetState } from 'ahooks';
10
- import { useEffect } from 'react';
13
+ import { useInfiniteScroll, useRequest, useSetState } from 'ahooks';
14
+ import React, { useEffect, useState } from 'react';
11
15
  import { joinURL } from 'ufo';
12
16
 
13
17
  import Status from '../../components/status';
@@ -23,6 +27,7 @@ import {
23
27
  getPrefix,
24
28
  getTxLink,
25
29
  } from '../../libs/util';
30
+ import Table from '../../components/table';
26
31
 
27
32
  type Result = Paginated<TInvoiceExpanded> & { subscription: TSubscription };
28
33
 
@@ -58,6 +63,7 @@ type Props = {
58
63
  pageSize?: number;
59
64
  target?: string;
60
65
  action?: string;
66
+ type?: 'list' | 'table';
61
67
  };
62
68
 
63
69
  const getInvoiceLink = (invoice: TInvoiceExpanded, action?: string) => {
@@ -79,23 +85,210 @@ const getInvoiceLink = (invoice: TInvoiceExpanded, action?: string) => {
79
85
  };
80
86
  };
81
87
 
82
- export default function CustomerInvoiceList({
83
- customer_id,
84
- subscription_id,
85
- currency_id,
86
- include_staking,
87
- include_recovered_from,
88
- status,
89
- pageSize,
90
- target,
91
- action,
92
- }: Props) {
88
+ const InvoiceTable = React.memo((props: Props & { onPay: (invoiceId: string) => void }) => {
89
+ const {
90
+ pageSize,
91
+ target,
92
+ action,
93
+ onPay,
94
+ status,
95
+ customer_id,
96
+ currency_id,
97
+ subscription_id,
98
+ include_staking,
99
+ include_recovered_from,
100
+ } = props;
101
+ const listKey = 'invoice-table';
102
+ const { t, locale } = useLocaleContext();
103
+
104
+ const [search, setSearch] = useState<{ pageSize: number; page: number }>({
105
+ pageSize: pageSize || 10,
106
+ page: 1,
107
+ });
108
+ const { loading, data = { list: [], count: 0 } } = useRequest(
109
+ () =>
110
+ fetchData({
111
+ ...search,
112
+ status,
113
+ customer_id,
114
+ currency_id,
115
+ subscription_id,
116
+ include_staking,
117
+ include_recovered_from,
118
+ ignore_zero: true,
119
+ }),
120
+ {
121
+ refreshDeps: [search],
122
+ }
123
+ );
124
+
125
+ const columns = [
126
+ {
127
+ label: t('payment.customer.invoice.invoiceNumber'),
128
+ name: 'number',
129
+ options: {
130
+ customBodyRenderLite: (_: string, index: number) => {
131
+ const invoice = data?.list[index] as TInvoiceExpanded;
132
+ const link = getInvoiceLink(invoice, action);
133
+ return (
134
+ <a href={link.url} target={link.external ? '_blank' : target} rel="noreferrer">
135
+ {invoice?.number}
136
+ </a>
137
+ );
138
+ },
139
+ },
140
+ },
141
+ {
142
+ label: t('common.amount'),
143
+ name: 'total',
144
+ options: {
145
+ customBodyRenderLite: (_: string, index: number) => {
146
+ const invoice = data?.list[index] as TInvoiceExpanded;
147
+ const link = getInvoiceLink(invoice, action);
148
+ return (
149
+ <a href={link.url} target={link.external ? '_blank' : target} rel="noreferrer">
150
+ <Typography>
151
+ {formatBNStr(invoice.total, invoice.paymentCurrency.decimal)}&nbsp;
152
+ {invoice.paymentCurrency.symbol}
153
+ </Typography>
154
+ </a>
155
+ );
156
+ },
157
+ },
158
+ },
159
+
160
+ {
161
+ label: t('common.updatedAt'),
162
+ name: 'name',
163
+ options: {
164
+ customBodyRenderLite: (val: string, index: number) => {
165
+ const invoice = data?.list[index] as TInvoiceExpanded;
166
+ const link = getInvoiceLink(invoice, action);
167
+ return (
168
+ <a href={link.url} target={link.external ? '_blank' : target} rel="noreferrer">
169
+ {formatToDate(invoice.created_at, locale, 'YYYY-MM-DD HH:mm:ss')}
170
+ </a>
171
+ );
172
+ },
173
+ },
174
+ },
175
+ {
176
+ label: t('common.description'),
177
+ name: '',
178
+ options: {
179
+ sort: false,
180
+ customBodyRenderLite: (val: string, index: number) => {
181
+ const invoice = data?.list[index] as TInvoiceExpanded;
182
+ const link = getInvoiceLink(invoice, action);
183
+ return (
184
+ <a href={link.url} target={link.external ? '_blank' : target} rel="noreferrer">
185
+ {invoice.description || invoice.id}
186
+ </a>
187
+ );
188
+ },
189
+ },
190
+ },
191
+ {
192
+ label: t('common.status'),
193
+ name: 'created_at',
194
+ options: {
195
+ sort: true,
196
+ customBodyRenderLite: (val: string, index: number) => {
197
+ const invoice = data?.list[index] as TInvoiceExpanded;
198
+ const link = getInvoiceLink(invoice, action);
199
+ if (action) {
200
+ return link.connect ? (
201
+ <Button variant="text" size="small" onClick={() => onPay(invoice.id)} sx={{ color: 'text.link' }}>
202
+ {t('payment.customer.invoice.pay')}
203
+ </Button>
204
+ ) : (
205
+ <Button
206
+ component="a"
207
+ variant="text"
208
+ size="small"
209
+ href={link.url}
210
+ target={link.external ? '_blank' : target}
211
+ sx={{ color: 'var(--foregrounds-fg-interactive, #0086FF) !important' }}
212
+ rel="noreferrer">
213
+ {t('payment.customer.invoice.pay')}
214
+ </Button>
215
+ );
216
+ }
217
+ return (
218
+ <a href={link.url} target={link.external ? '_blank' : target} rel="noreferrer">
219
+ <Status label={invoice.status} color={getInvoiceStatusColor(invoice.status)} />
220
+ </a>
221
+ );
222
+ },
223
+ },
224
+ },
225
+ ];
226
+
227
+ const onTableChange = ({ page, rowsPerPage }: any) => {
228
+ if (search.pageSize !== rowsPerPage) {
229
+ setSearch((x) => ({ ...x, pageSize: rowsPerPage, page: 1 }));
230
+ } else if (search.page !== page + 1) {
231
+ setSearch((x) => ({ ...x, page: page + 1 }));
232
+ }
233
+ };
234
+
235
+ return (
236
+ <InvoiceTableRoot>
237
+ <Table
238
+ hasRowLink
239
+ durable={`__${listKey}__`}
240
+ durableKeys={['page', 'rowsPerPage', 'searchText']}
241
+ data={data.list}
242
+ columns={columns}
243
+ options={{
244
+ count: data.count,
245
+ page: search.page - 1,
246
+ rowsPerPage: search.pageSize,
247
+ }}
248
+ loading={loading}
249
+ onChange={onTableChange}
250
+ toolbar={false}
251
+ sx={{ mt: 2 }}
252
+ showMobile={false}
253
+ mobileTDFlexDirection="row"
254
+ emptyNodeText={t('payment.customer.invoice.emptyList')}
255
+ />
256
+ </InvoiceTableRoot>
257
+ );
258
+ });
259
+
260
+ const InvoiceTableRoot = styled(Box)`
261
+ @media (max-width: ${({ theme }) => theme.breakpoints.values.md}px) {
262
+ .MuiTable-root > .MuiTableBody-root > .MuiTableRow-root > td.MuiTableCell-root {
263
+ > div {
264
+ width: fit-content;
265
+ flex: inherit;
266
+ font-size: 14px;
267
+ }
268
+ }
269
+ .invoice-summary {
270
+ padding-right: 20px;
271
+ }
272
+ }
273
+ `;
274
+
275
+ const InvoiceList = React.memo((props: Props & { onPay: (invoiceId: string) => void }) => {
276
+ const {
277
+ customer_id,
278
+ subscription_id,
279
+ include_recovered_from,
280
+ currency_id,
281
+ include_staking,
282
+ status,
283
+ pageSize,
284
+ target,
285
+ action,
286
+ onPay,
287
+ } = props;
93
288
  const size = pageSize || 10;
94
289
 
95
290
  const subscription = useSubscription('events');
96
291
  const { t, locale } = useLocaleContext();
97
- const { connect } = usePaymentContext();
98
- const [state, setState] = useSetState({ paying: '' });
99
292
 
100
293
  const { data, loadMore, loadingMore, loading, reloadAsync } = useInfiniteScroll<Result>(
101
294
  (d) => {
@@ -128,38 +321,6 @@ export default function CustomerInvoiceList({
128
321
  }
129
322
  }, [subscription]); // eslint-disable-line react-hooks/exhaustive-deps
130
323
 
131
- const onPay = (invoiceId: string) => {
132
- if (state.paying) {
133
- return;
134
- }
135
-
136
- setState({ paying: invoiceId });
137
- connect.open({
138
- action: 'collect',
139
- saveConnect: false,
140
- messages: {
141
- scan: '',
142
- title: t(`payment.customer.invoice.${action || 'pay'}`),
143
- success: t(`payment.customer.invoice.${action || 'pay'}Success`),
144
- error: t(`payment.customer.invoice.${action || 'pay'}Error`),
145
- confirm: '',
146
- } as any,
147
- extraParams: { invoiceId, action },
148
- onSuccess: () => {
149
- connect.close();
150
- setState({ paying: '' });
151
- },
152
- onClose: () => {
153
- connect.close();
154
- setState({ paying: '' });
155
- },
156
- onError: (err: any) => {
157
- setState({ paying: '' });
158
- Toast.error(formatError(err));
159
- },
160
- });
161
- };
162
-
163
324
  if (loading || !data) {
164
325
  return <CircularProgress />;
165
326
  }
@@ -241,7 +402,6 @@ export default function CustomerInvoiceList({
241
402
  <Button
242
403
  component="a"
243
404
  variant="contained"
244
- color="primary"
245
405
  size="small"
246
406
  href={link.url}
247
407
  target={link.external ? '_blank' : target}
@@ -274,6 +434,50 @@ export default function CustomerInvoiceList({
274
434
  </Box>
275
435
  </Root>
276
436
  );
437
+ });
438
+
439
+ export default function CustomerInvoiceList(props: Props) {
440
+ const { action, type } = props;
441
+ const { t } = useLocaleContext();
442
+ const { connect } = usePaymentContext();
443
+ const [state, setState] = useSetState({ paying: '' });
444
+
445
+ const onPay = (invoiceId: string) => {
446
+ if (state.paying) {
447
+ return;
448
+ }
449
+
450
+ setState({ paying: invoiceId });
451
+ connect.open({
452
+ action: 'collect',
453
+ saveConnect: false,
454
+ messages: {
455
+ scan: '',
456
+ title: t(`payment.customer.invoice.${action || 'pay'}`),
457
+ success: t(`payment.customer.invoice.${action || 'pay'}Success`),
458
+ error: t(`payment.customer.invoice.${action || 'pay'}Error`),
459
+ confirm: '',
460
+ } as any,
461
+ extraParams: { invoiceId, action },
462
+ onSuccess: () => {
463
+ connect.close();
464
+ setState({ paying: '' });
465
+ },
466
+ onClose: () => {
467
+ connect.close();
468
+ setState({ paying: '' });
469
+ },
470
+ onError: (err: any) => {
471
+ setState({ paying: '' });
472
+ Toast.error(formatError(err));
473
+ },
474
+ });
475
+ };
476
+
477
+ if (type === 'table') {
478
+ return <InvoiceTable {...props} onPay={onPay} />;
479
+ }
480
+ return <InvoiceList {...props} onPay={onPay} />;
277
481
  }
278
482
 
279
483
  CustomerInvoiceList.defaultProps = {
@@ -286,10 +490,11 @@ CustomerInvoiceList.defaultProps = {
286
490
  pageSize: 10,
287
491
  target: '_self',
288
492
  action: '',
493
+ type: 'list',
289
494
  };
290
495
 
291
496
  const Root = styled(Stack)`
292
- @media (max-width: 600px) {
497
+ @media (max-width: ${({ theme }) => theme.breakpoints.values.md}px) {
293
498
  .invoice-description {
294
499
  display: none !important;
295
500
  }
@@ -0,0 +1,13 @@
1
+ import { useTheme } from '@mui/material/styles';
2
+ import useMediaQuery from '@mui/material/useMediaQuery';
3
+
4
+ const MOBILE_POINT = 'md';
5
+
6
+ export function useMobile(mobilePoint: 'md' | 'sm' | 'lg' | 'xl' | 'xs' = MOBILE_POINT) {
7
+ const theme = useTheme();
8
+
9
+ return {
10
+ isMobile: useMediaQuery(theme.breakpoints.down(mobilePoint)),
11
+ mobileSize: `${theme.breakpoints.values[mobilePoint]}px`,
12
+ };
13
+ }
package/src/index.ts CHANGED
@@ -7,6 +7,7 @@ import ConfirmDialog from './components/confirm';
7
7
  import FormInput from './components/input';
8
8
  import Livemode from './components/livemode';
9
9
  import PricingTable from './components/pricing-table';
10
+ import Table from './components/table';
10
11
  import SafeGuard from './components/safe-guard';
11
12
  import Status from './components/status';
12
13
  import Switch from './components/switch-button';
@@ -23,11 +24,15 @@ import Payment from './payment/index';
23
24
  import ProductSkeleton from './payment/product-skeleton';
24
25
  import PaymentSummary from './payment/summary';
25
26
  import PricingItem from './components/pricing-item';
27
+ import CountrySelect from './components/country-select';
28
+
29
+ export { PaymentThemeProvider } from './theme';
26
30
 
27
31
  export * from './libs/util';
28
32
  export * from './libs/connect';
29
33
  export * from './contexts/payment';
30
34
  export * from './hooks/subscription';
35
+ export * from './hooks/mobile';
31
36
 
32
37
  export { translations, createTranslator } from './locales';
33
38
 
@@ -57,4 +62,6 @@ export {
57
62
  TxGas,
58
63
  SafeGuard,
59
64
  PricingItem,
65
+ CountrySelect,
66
+ Table,
60
67
  };
package/src/libs/util.ts CHANGED
@@ -24,7 +24,7 @@ import { joinURL } from 'ufo';
24
24
 
25
25
  import { t } from '../locales';
26
26
  import dayjs from './dayjs';
27
- import { PricingRenderProps } from '../types';
27
+ import { ActionProps, PricingRenderProps } from '../types';
28
28
 
29
29
  export const PAYMENT_KIT_DID = 'z2qaCNvKMv5GjouKdcDWexv6WqtHbpNPQDnAk';
30
30
 
@@ -533,6 +533,32 @@ export function formatUpsellSaving(items: TLineItemExpanded[], currency: TPaymen
533
533
  return Number(before.sub(after).mul(new BN(100)).div(before).toString()).toFixed(0);
534
534
  }
535
535
 
536
+ export function formatMeteredThen(
537
+ subscription: string,
538
+ recurring: string,
539
+ hasMetered: boolean,
540
+ locale: string = 'en'
541
+ ): string {
542
+ if (hasMetered) {
543
+ return t('payment.checkout.meteredThen', locale, { subscription, recurring });
544
+ }
545
+ return t('payment.checkout.then', locale, { subscription, recurring });
546
+ }
547
+
548
+ export function formatPriceDisplay(
549
+ { amount, then, actualAmount, showThen }: { amount: string; then?: string; actualAmount: string; showThen?: boolean },
550
+ recurring: string,
551
+ hasMetered: boolean,
552
+ locale: string = 'en'
553
+ ) {
554
+ if (Number(actualAmount) === 0 && hasMetered) {
555
+ return t('payment.checkout.metered', locale, { recurring });
556
+ }
557
+ if (showThen) {
558
+ return [amount, then].filter(Boolean).join(', ');
559
+ }
560
+ return [amount, then].filter(Boolean).join(' ');
561
+ }
536
562
  export function formatCheckoutHeadlines(
537
563
  items: TLineItemExpanded[],
538
564
  currency: TPaymentCurrency,
@@ -543,9 +569,13 @@ export function formatCheckoutHeadlines(
543
569
  amount: string;
544
570
  then?: string;
545
571
  secondary?: string;
572
+ showThen?: boolean;
573
+ actualAmount: string;
574
+ priceDisplay: string;
546
575
  } {
547
576
  const brand = getStatementDescriptor(items);
548
577
  const { total } = getCheckoutAmount(items, currency, trialInDays > 0);
578
+ const actualAmount = fromUnitToToken(total, currency.decimal);
549
579
  const amount = `${fromUnitToToken(total, currency.decimal)} ${currency.symbol}`;
550
580
 
551
581
  // empty
@@ -554,6 +584,8 @@ export function formatCheckoutHeadlines(
554
584
  action: t('payment.checkout.empty', locale),
555
585
  amount: '0',
556
586
  then: '',
587
+ actualAmount: '0',
588
+ priceDisplay: '0',
557
589
  };
558
590
  }
559
591
 
@@ -563,10 +595,10 @@ export function formatCheckoutHeadlines(
563
595
  if (items.every((x) => x.price.type === 'one_time')) {
564
596
  const action = t('payment.checkout.pay', locale, { payee: brand });
565
597
  if (items.length > 1) {
566
- return { action, amount };
598
+ return { action, amount, actualAmount, priceDisplay: amount };
567
599
  }
568
600
 
569
- return { action, amount, then: '' };
601
+ return { action, amount, then: '', actualAmount, priceDisplay: amount };
570
602
  }
571
603
 
572
604
  const item = items.find((x) => x.price.type === 'recurring');
@@ -576,10 +608,9 @@ export function formatCheckoutHeadlines(
576
608
  'per',
577
609
  locale
578
610
  );
579
-
611
+ const hasMetered = items.some((x) => x.price.type === 'recurring' && x.price.recurring?.usage_type === 'metered');
580
612
  // all recurring
581
613
  if (items.every((x) => x.price.type === 'recurring')) {
582
- const hasMetered = items.some((x) => x.price.type === 'recurring' && x.price.recurring?.usage_type === 'metered');
583
614
  const subscription = [
584
615
  hasMetered ? t('payment.checkout.least', locale) : '',
585
616
  fromUnitToToken(
@@ -597,32 +628,54 @@ export function formatCheckoutHeadlines(
597
628
  .join(' ');
598
629
  if (items.length > 1) {
599
630
  if (trialInDays > 0) {
600
- return {
631
+ const result = {
601
632
  action: t('payment.checkout.try2', locale, { name, count: items.length - 1 }),
602
633
  amount: t('payment.checkout.free', locale, { count: trialInDays }),
603
- then: t('payment.checkout.then', locale, { subscription, recurring }),
634
+ then: formatMeteredThen(subscription, recurring, hasMetered && Number(subscription) === 0, locale),
635
+ showThen: true,
636
+ actualAmount: '0',
637
+ };
638
+ return {
639
+ ...result,
640
+ priceDisplay: formatPriceDisplay(result, recurring, hasMetered, locale),
604
641
  };
605
642
  }
606
-
607
- return {
643
+ const result = {
608
644
  action: t('payment.checkout.sub2', locale, { name, count: items.length - 1 }),
609
645
  amount,
610
- then: recurring,
646
+ then: hasMetered ? t('payment.checkout.meteredThen', locale, { recurring }) : recurring,
647
+ showThen: hasMetered,
648
+ actualAmount,
649
+ };
650
+ return {
651
+ ...result,
652
+ priceDisplay: formatPriceDisplay(result, recurring, hasMetered, locale),
611
653
  };
612
654
  }
613
655
 
614
656
  if (trialInDays > 0) {
615
- return {
657
+ const result = {
616
658
  action: t('payment.checkout.try1', locale, { name }),
617
659
  amount: t('payment.checkout.free', locale, { count: trialInDays }),
618
- then: t('payment.checkout.then', locale, { subscription, recurring }),
660
+ then: formatMeteredThen(subscription, recurring, hasMetered && Number(subscription) === 0, locale),
661
+ showThen: true,
662
+ actualAmount: '0',
663
+ };
664
+ return {
665
+ ...result,
666
+ priceDisplay: formatPriceDisplay(result, recurring, hasMetered, locale),
619
667
  };
620
668
  }
621
-
622
- return {
669
+ const result = {
623
670
  action: t('payment.checkout.sub1', locale, { name }),
624
671
  amount,
625
- then: recurring,
672
+ then: hasMetered ? t('payment.checkout.meteredThen', locale, { recurring }) : recurring,
673
+ showThen: hasMetered,
674
+ actualAmount,
675
+ };
676
+ return {
677
+ ...result,
678
+ priceDisplay: formatPriceDisplay(result, recurring, hasMetered, locale),
626
679
  };
627
680
  }
628
681
 
@@ -639,10 +692,22 @@ export function formatCheckoutHeadlines(
639
692
  currency.decimal
640
693
  );
641
694
 
642
- return {
695
+ const result = {
643
696
  action: t('payment.checkout.pay', locale, { payee: brand }),
644
697
  amount,
645
- then: t('payment.checkout.then', locale, { subscription: `${subscription} ${currency.symbol}`, recurring }),
698
+ then: formatMeteredThen(
699
+ `${subscription} ${currency.symbol}`,
700
+ recurring,
701
+ hasMetered && Number(subscription) === 0,
702
+ locale
703
+ ),
704
+ showThen: true,
705
+ actualAmount,
706
+ };
707
+
708
+ return {
709
+ ...result,
710
+ priceDisplay: formatPriceDisplay(result, recurring, hasMetered, locale),
646
711
  };
647
712
  }
648
713
 
@@ -690,48 +755,65 @@ export function formatSubscriptionProduct(items: TSubscriptionItemExpanded[], ma
690
755
  }
691
756
 
692
757
  export const getSubscriptionTimeSummary = (subscription: TSubscriptionExpanded) => {
693
- const lines = [`Started on ${formatToDate(subscription.start_date * 1000)}`];
758
+ const lines = [`Start on ${formatToDate(subscription.start_date * 1000, 'en', 'YYYY-MM-DD')}`];
759
+
760
+ const getLineTimeMessage = (time: number) => {
761
+ const curDay = dayjs().isSame(dayjs(time), 'day');
762
+ const timeFormat = curDay ? 'HH:mm:ss' : 'YYYY-MM-DD';
763
+ return `${curDay ? 'in' : 'on'} ${formatToDate(time, 'en', timeFormat)}`;
764
+ };
765
+
694
766
  if (subscription.status === 'active' || subscription.status === 'trialing') {
695
767
  if (subscription.cancel_at) {
696
- lines.push(`will cancel on ${formatToDate(subscription.cancel_at * 1000)}`);
768
+ lines.push(`Ended ${getLineTimeMessage(subscription.cancel_at * 1000)}`);
697
769
  } else if (subscription.cancel_at_period_end) {
698
- lines.push(`will cancel on ${formatToDate(subscription.current_period_end * 1000)}`);
770
+ lines.push(`Ended ${getLineTimeMessage(subscription.current_period_end * 1000)}`);
699
771
  } else {
700
- lines.push(`will renew on ${formatToDate(subscription.current_period_end * 1000)}`);
772
+ lines.push(`Renew ${getLineTimeMessage(subscription.current_period_end * 1000)}`);
701
773
  }
702
774
  } else if (subscription.status === 'past_due') {
703
- lines.push(`will cancel on ${formatToDate((subscription.cancel_at || subscription.current_period_end) * 1000)}`);
775
+ lines.push(`Ended ${getLineTimeMessage((subscription.cancel_at || subscription.current_period_end) * 1000)}`);
704
776
  } else if (subscription.status === 'canceled') {
705
- lines.push(`canceled on ${formatToDate(subscription.canceled_at * 1000)}`);
777
+ lines.push(`Ended ${getLineTimeMessage(subscription.canceled_at * 1000)}`);
706
778
  }
707
779
 
708
- return lines.join(', ');
780
+ return lines.join(',');
709
781
  };
710
782
 
711
- export const getSubscriptionAction = (subscription: TSubscriptionExpanded) => {
783
+ export const getSubscriptionAction = (
784
+ subscription: TSubscriptionExpanded,
785
+ actionProps: ActionProps
786
+ ): {
787
+ action: string;
788
+ variant: string;
789
+ color: string;
790
+ canRenew: boolean;
791
+ text?: string;
792
+ sx?: any;
793
+ } | null => {
712
794
  if (subscription.status === 'active' || subscription.status === 'trialing') {
713
795
  if (subscription.cancel_at_period_end) {
714
796
  if (subscription.cancelation_details?.reason === 'payment_failed') {
715
797
  return null;
716
798
  }
717
799
 
718
- return { action: 'recover', variant: 'contained', color: 'primary', canRenew: false };
800
+ return { action: 'recover', variant: 'contained', color: 'primary', canRenew: false, ...actionProps?.recover };
719
801
  }
720
802
 
721
803
  if (subscription.cancel_at && subscription.cancel_at !== subscription.current_period_end) {
722
804
  return null;
723
805
  }
724
806
 
725
- return { action: 'cancel', variant: 'outlined', color: 'inherit', canRenew: false };
807
+ return { action: 'cancel', variant: 'outlined', color: 'inherit', canRenew: false, ...actionProps?.cancel };
726
808
  }
727
809
 
728
810
  if (subscription.status === 'past_due') {
729
811
  const canRenew = subscription.cancel_at && subscription.cancel_at !== subscription.current_period_end;
730
- return { action: 'pastDue', variant: 'contained', color: 'primary', canRenew };
812
+ return { action: 'pastDue', variant: 'contained', color: 'primary', canRenew, ...actionProps?.pastDue };
731
813
  }
732
814
 
733
815
  if (subscription.status !== 'canceled' && subscription.cancel_at_period_end) {
734
- return { action: 'recover', variant: 'contained', color: 'primary', canRenew: false };
816
+ return { action: 'recover', variant: 'contained', color: 'primary', canRenew: false, ...actionProps?.recover };
735
817
  }
736
818
 
737
819
  return null;
@@ -855,9 +937,9 @@ export function formatTotalPrice({
855
937
  const unitValue = new BN(price.custom_unit_amount || price.unit_amount);
856
938
  const currency: TPaymentCurrency = price?.currency ?? {};
857
939
 
858
- const total = `${fromUnitToToken(unitValue.mul(new BN(quantity)), currency.decimal)} ${currency.symbol}`;
940
+ const total = `${fromUnitToToken(unitValue.mul(new BN(quantity)), currency.decimal)} ${currency.symbol} `;
859
941
 
860
- const unit = `${fromUnitToToken(unitValue, currency.decimal)} ${currency.symbol}`;
942
+ const unit = `${fromUnitToToken(unitValue, currency.decimal)} ${currency.symbol} `;
861
943
 
862
944
  const appendUnit = (v: string, alt: string) => {
863
945
  if (product.unit_label) {
@@ -893,6 +975,13 @@ export function formatQuantityInventory(price: TPrice, quantity: string | number
893
975
  return '';
894
976
  }
895
977
 
978
+ export function formatSubscriptionStatus(status: string) {
979
+ if (status === 'canceled') {
980
+ return 'Ended';
981
+ }
982
+ return status;
983
+ }
984
+
896
985
  export function formatAmountPrecisionLimit(amount: string, locale = 'en', precision: number = 6) {
897
986
  if (!amount) {
898
987
  return '';