@blocklet/payment-react 1.18.15 → 1.18.17

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.
@@ -28,7 +28,7 @@ import {
28
28
  } from '@mui/material';
29
29
  import { useRequest, useSetState } from 'ahooks';
30
30
  import omit from 'lodash/omit';
31
- import uniqBy from 'lodash/unionBy';
31
+ import uniqBy from 'lodash/uniqBy';
32
32
  import { useEffect, useRef, useState } from 'react';
33
33
  import { Settings } from '@mui/icons-material';
34
34
 
@@ -190,11 +190,14 @@ export function DonateDetails({ supporters = [], currency, method }: DonateHisto
190
190
  <Avatar
191
191
  key={x.id}
192
192
  src={getCustomerAvatar(x.customer?.did, x?.updated_at ? new Date(x.updated_at).toISOString() : '', 20)}
193
- alt={x.customer?.name}
193
+ alt={x.customer?.metadata?.anonymous ? '' : x.customer?.name}
194
194
  variant="circular"
195
195
  sx={{ width: 20, height: 20 }}
196
196
  onClick={(e) => {
197
197
  e.stopPropagation();
198
+ if (x.customer?.metadata?.anonymous) {
199
+ return;
200
+ }
198
201
  if (x.customer?.did) {
199
202
  window.open(getUserProfileLink(x.customer?.did, locale), '_blank');
200
203
  }
@@ -210,6 +213,9 @@ export function DonateDetails({ supporters = [], currency, method }: DonateHisto
210
213
  textOverflow: 'ellipsis',
211
214
  }}
212
215
  onClick={(e) => {
216
+ if (x.customer?.metadata?.anonymous) {
217
+ return;
218
+ }
213
219
  e.stopPropagation();
214
220
  if (x.customer?.did) {
215
221
  window.open(getUserProfileLink(x.customer?.did, locale), '_blank');
@@ -244,7 +250,7 @@ function SupporterAvatar({
244
250
  showDonateDetails = false,
245
251
  }: DonateHistory & { showDonateDetails?: boolean }) {
246
252
  const [open, setOpen] = useState(false);
247
- const customers = uniqBy(supporters, 'customer_did');
253
+ const customers = uniqBy(supporters, 'customer_id');
248
254
  const customersNum = customers.length;
249
255
  if (customersNum === 0) return null;
250
256
  return (
@@ -254,6 +260,9 @@ function SupporterAvatar({
254
260
  sx={{
255
261
  '& .MuiAvatar-root': {
256
262
  backgroundColor: 'background.paper',
263
+ '&.MuiAvatar-colorDefault': {
264
+ backgroundColor: '#bdbdbd',
265
+ },
257
266
  },
258
267
  }}>
259
268
  {customers.slice(0, 5).map((supporter) => (
@@ -263,7 +272,7 @@ function SupporterAvatar({
263
272
  supporter?.updated_at ? new Date(supporter.updated_at).toISOString() : '',
264
273
  24
265
274
  )}
266
- alt={supporter.customer?.name}
275
+ alt={supporter.customer?.metadata?.anonymous ? '' : supporter.customer?.name}
267
276
  key={supporter.customer?.id}
268
277
  sx={{
269
278
  width: '24px',
@@ -312,7 +321,7 @@ function SupporterAvatar({
312
321
 
313
322
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
314
323
  function SupporterTable({ supporters = [], totalAmount = '0', currency, method }: DonateHistory) {
315
- const customers = uniqBy(supporters, 'customer_did');
324
+ const customers = uniqBy(supporters, 'customer_id');
316
325
  const customersNum = customers.length;
317
326
  if (customersNum === 0) return null;
318
327
  return (
@@ -326,7 +335,7 @@ function SupporterTable({ supporters = [], totalAmount = '0', currency, method }
326
335
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
327
336
  function SupporterSimple({ supporters = [], totalAmount = '0', currency, method }: DonateHistory) {
328
337
  const { t } = useLocaleContext();
329
- const customers = uniqBy(supporters, 'customer_did');
338
+ const customers = uniqBy(supporters, 'customer_id');
330
339
  const customersNum = customers.length;
331
340
 
332
341
  return (
@@ -354,7 +363,7 @@ function SupporterSimple({ supporters = [], totalAmount = '0', currency, method
354
363
  <Avatar
355
364
  key={x.id}
356
365
  title={x.customer?.name}
357
- alt={x.customer?.name}
366
+ alt={x.customer?.metadata?.anonymous ? '' : x.customer?.name}
358
367
  src={getCustomerAvatar(x.customer?.did, x?.updated_at ? new Date(x.updated_at).toISOString() : '', 48)}
359
368
  variant="circular"
360
369
  sx={{ width: 24, height: 24 }}
@@ -1,15 +1,19 @@
1
+ /* eslint-disable @typescript-eslint/indent */
1
2
  import { useEffect, useMemo, useState } from 'react';
2
- import { Button, Typography, Stack, CircularProgress, Alert } from '@mui/material';
3
+ import { Button, Typography, Stack, Alert, SxProps } from '@mui/material';
3
4
  import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
4
5
  import Toast from '@arcblock/ux/lib/Toast';
5
6
  import { joinURL } from 'ufo';
6
7
  import type { Invoice, PaymentCurrency, PaymentMethod, Subscription, TInvoiceExpanded } from '@blocklet/payment-types';
7
8
  import { useRequest } from 'ahooks';
8
9
  import { Dialog } from '@arcblock/ux';
10
+ import { CheckCircle as CheckCircleIcon } from '@mui/icons-material';
11
+ import debounce from 'lodash/debounce';
9
12
  import { usePaymentContext } from '../contexts/payment';
10
13
  import { formatAmount, formatError, getPrefix } from '../libs/util';
11
14
  import { useSubscription } from '../hooks/subscription';
12
15
  import api from '../libs/api';
16
+ import LoadingButton from './loading-button';
13
17
 
14
18
  type DialogProps = {
15
19
  open?: boolean;
@@ -17,19 +21,28 @@ type DialogProps = {
17
21
  title?: string;
18
22
  };
19
23
 
24
+ type DetailLinkOptions = {
25
+ enabled?: boolean;
26
+ onClick?: (e: React.MouseEvent) => void;
27
+ title?: string;
28
+ };
29
+
20
30
  type Props = {
21
- subscriptionId: string;
31
+ subscriptionId?: string;
32
+ customerId?: string;
22
33
  mode?: 'default' | 'custom';
23
- onPaid?: (subscriptionId: string, currencyId: string) => void;
34
+ onPaid?: (id: string, currencyId: string, type: 'subscription' | 'customer') => void;
24
35
  dialogProps?: DialogProps;
25
- inSubscriptionDetail?: boolean;
36
+ detailLinkOptions?: DetailLinkOptions;
37
+ successToast?: boolean;
26
38
  children?: (
27
39
  handlePay: (item: SummaryItem) => void,
28
40
  data: {
29
- subscription: Subscription;
41
+ subscription?: Subscription;
30
42
  summary: { [key: string]: SummaryItem };
31
43
  invoices: Invoice[];
32
- subscriptionUrl: string;
44
+ subscriptionCount?: number;
45
+ detailUrl: string;
33
46
  }
34
47
  ) => React.ReactNode;
35
48
  };
@@ -40,24 +53,41 @@ type SummaryItem = {
40
53
  method: PaymentMethod;
41
54
  };
42
55
 
43
- const fetchOverdueInvoices = async (
44
- subscriptionId: string
45
- ): Promise<{
46
- subscription: Subscription;
56
+ type OverdueInvoicesResult = {
57
+ subscription?: Subscription;
47
58
  summary: { [key: string]: SummaryItem };
48
59
  invoices: Invoice[];
49
- }> => {
50
- const res = await api.get(`/api/subscriptions/${subscriptionId}/overdue/invoices`);
60
+ subscriptionCount?: number;
61
+ };
62
+
63
+ const fetchOverdueInvoices = async (params: {
64
+ subscriptionId?: string;
65
+ customerId?: string;
66
+ }): Promise<OverdueInvoicesResult> => {
67
+ if (!params.subscriptionId && !params.customerId) {
68
+ throw new Error('Either subscriptionId or customerId must be provided');
69
+ }
70
+
71
+ let url;
72
+ if (params.subscriptionId) {
73
+ url = `/api/subscriptions/${params.subscriptionId}/overdue/invoices`;
74
+ } else {
75
+ url = `/api/customers/${params.customerId}/overdue/invoices`;
76
+ }
77
+
78
+ const res = await api.get(url);
51
79
  return res.data;
52
80
  };
53
81
 
54
82
  function OverdueInvoicePayment({
55
83
  subscriptionId,
84
+ customerId,
56
85
  mode = 'default',
57
86
  dialogProps = {},
58
87
  children,
59
88
  onPaid = () => {},
60
- inSubscriptionDetail = false,
89
+ detailLinkOptions = { enabled: true },
90
+ successToast = true,
61
91
  }: Props) {
62
92
  const { t } = useLocaleContext();
63
93
  const { connect } = usePaymentContext();
@@ -65,18 +95,33 @@ function OverdueInvoicePayment({
65
95
  const [payLoading, setPayLoading] = useState(false);
66
96
  const [dialogOpen, setDialogOpen] = useState(dialogProps.open || false);
67
97
  const [processedCurrencies, setProcessedCurrencies] = useState<{ [key: string]: number }>({});
98
+ const [paymentStatus, setPaymentStatus] = useState<{ [key: string]: 'success' | 'error' | 'idle' }>({});
99
+
100
+ const sourceType = subscriptionId ? 'subscription' : 'customer';
101
+ const sourceId = subscriptionId || customerId;
102
+
68
103
  const {
69
104
  data = {
70
- subscription: {} as Subscription,
71
105
  summary: {},
72
106
  invoices: [],
73
- },
107
+ } as OverdueInvoicesResult,
74
108
  error,
75
109
  loading,
76
110
  runAsync: refresh,
77
- } = useRequest(() => fetchOverdueInvoices(subscriptionId));
111
+ } = useRequest(() => fetchOverdueInvoices({ subscriptionId, customerId }), {
112
+ ready: !!subscriptionId || !!customerId,
113
+ });
114
+
115
+ const detailUrl = useMemo(() => {
116
+ if (subscriptionId) {
117
+ return joinURL(getPrefix(), `/customer/subscription/${subscriptionId}`);
118
+ }
119
+ if (customerId) {
120
+ return joinURL(getPrefix(), '/customer/invoice/past-due');
121
+ }
122
+ return '';
123
+ }, [subscriptionId, customerId]);
78
124
 
79
- const subscriptionUrl = joinURL(getPrefix(), `/customer/subscription/${subscriptionId}`);
80
125
  const summaryList = useMemo(() => {
81
126
  if (!data?.summary) {
82
127
  return [];
@@ -84,26 +129,47 @@ function OverdueInvoicePayment({
84
129
  return Object.values(data.summary);
85
130
  }, [data?.summary]);
86
131
 
132
+ const debouncedHandleInvoicePaid = debounce(
133
+ async (currencyId: string) => {
134
+ if (successToast) {
135
+ Toast.close();
136
+ Toast.success(t('payment.customer.invoice.paySuccess'));
137
+ }
138
+ setPayLoading(false);
139
+ const res = await refresh();
140
+ if (res.invoices?.length === 0) {
141
+ setDialogOpen(false);
142
+ onPaid(sourceId as string, currencyId, sourceType as 'subscription' | 'customer');
143
+ }
144
+ },
145
+ 1000,
146
+ {
147
+ leading: false,
148
+ trailing: true,
149
+ maxWait: 5000,
150
+ }
151
+ );
152
+
87
153
  const subscription = useSubscription('events');
88
154
  useEffect(() => {
89
155
  if (subscription) {
90
156
  subscription.on('invoice.paid', ({ response }: { response: TInvoiceExpanded }) => {
91
- const uniqueKey = `${response.subscription_id}-${response.currency_id}`;
92
- if (response.subscription_id === subscriptionId && !processedCurrencies[uniqueKey]) {
93
- Toast.success(t('payment.customer.invoice.paySuccess'));
94
- setPayLoading(false);
95
- setProcessedCurrencies({ ...processedCurrencies, [uniqueKey]: 1 });
96
- refresh().then((res) => {
97
- if (res.invoices?.length === 0) {
98
- setDialogOpen(false);
99
- onPaid(subscriptionId, response.currency_id);
100
- }
101
- });
157
+ const relevantId = subscriptionId || response.customer_id;
158
+ const uniqueKey = `${relevantId}-${response.currency_id}`;
159
+
160
+ if (
161
+ (subscriptionId && response.subscription_id === subscriptionId) ||
162
+ (customerId && response.customer_id === customerId)
163
+ ) {
164
+ if (!processedCurrencies[uniqueKey]) {
165
+ setProcessedCurrencies((prev) => ({ ...prev, [uniqueKey]: 1 }));
166
+ debouncedHandleInvoicePaid(response.currency_id);
167
+ }
102
168
  }
103
169
  });
104
170
  }
105
171
  // eslint-disable-next-line react-hooks/exhaustive-deps
106
- }, [subscription]);
172
+ }, [subscription, subscriptionId, customerId]);
107
173
 
108
174
  const handlePay = (item: SummaryItem) => {
109
175
  const { currency, method } = item;
@@ -116,15 +182,33 @@ function OverdueInvoicePayment({
116
182
  }
117
183
  setSelectCurrencyId(currency.id);
118
184
  setPayLoading(true);
185
+ setPaymentStatus((prev) => ({
186
+ ...prev,
187
+ [currency.id]: 'idle',
188
+ }));
189
+
119
190
  if (['arcblock', 'ethereum', 'base'].includes(method.type)) {
191
+ const extraParams: any = { currencyId: currency.id };
192
+
193
+ if (subscriptionId) {
194
+ extraParams.subscriptionId = subscriptionId;
195
+ } else if (customerId) {
196
+ extraParams.customerId = customerId;
197
+ }
198
+
120
199
  connect.open({
121
200
  containerEl: undefined as unknown as Element,
122
201
  saveConnect: false,
123
202
  action: 'collect-batch',
124
203
  prefix: joinURL(getPrefix(), '/api/did'),
125
- extraParams: { currencyId: currency.id, subscriptionId },
204
+ extraParams,
126
205
  onSuccess: () => {
127
206
  connect.close();
207
+ setPayLoading(false);
208
+ setPaymentStatus((prev) => ({
209
+ ...prev,
210
+ [currency.id]: 'success',
211
+ }));
128
212
  },
129
213
  onClose: () => {
130
214
  connect.close();
@@ -132,6 +216,10 @@ function OverdueInvoicePayment({
132
216
  },
133
217
  onError: (err: any) => {
134
218
  Toast.error(formatError(err));
219
+ setPaymentStatus((prev) => ({
220
+ ...prev,
221
+ [currency.id]: 'error',
222
+ }));
135
223
  setPayLoading(false);
136
224
  },
137
225
  });
@@ -144,7 +232,10 @@ function OverdueInvoicePayment({
144
232
  };
145
233
 
146
234
  const handleViewDetailClick = (e: React.MouseEvent) => {
147
- if (inSubscriptionDetail) {
235
+ if (detailLinkOptions.onClick) {
236
+ e.preventDefault();
237
+ detailLinkOptions.onClick(e);
238
+ } else if (!detailLinkOptions.enabled) {
148
239
  e.preventDefault();
149
240
  handleClose();
150
241
  }
@@ -154,37 +245,146 @@ function OverdueInvoicePayment({
154
245
  return null;
155
246
  }
156
247
 
157
- const renderPayButton = (item: SummaryItem, props: any) => {
158
- const isPayLoading = payLoading && item.currency.id === selectCurrencyId;
248
+ const getDetailLinkText = () => {
249
+ if (detailLinkOptions.title) {
250
+ return detailLinkOptions.title;
251
+ }
252
+
253
+ if (subscriptionId) {
254
+ return t('payment.subscription.overdue.view');
255
+ }
256
+
257
+ return t('payment.customer.pastDue.view');
258
+ };
259
+
260
+ const renderPayButton = (
261
+ item: SummaryItem,
262
+ primaryButton = true,
263
+ props: {
264
+ variant?: 'contained' | 'text';
265
+ sx?: SxProps;
266
+ } = {
267
+ variant: 'contained',
268
+ }
269
+ ) => {
270
+ const { currency } = item;
271
+ const inProcess = payLoading && selectCurrencyId === currency.id;
272
+ const status = paymentStatus[currency.id] || 'idle';
273
+
274
+ if (status === 'success') {
275
+ return (
276
+ <Button
277
+ // eslint-disable-next-line react/prop-types
278
+ variant={props?.variant || 'contained'}
279
+ size="small"
280
+ {...(primaryButton
281
+ ? {}
282
+ : {
283
+ color: 'success',
284
+ startIcon: <CheckCircleIcon />,
285
+ })}>
286
+ {t('payment.subscription.overdue.paid')}
287
+ </Button>
288
+ );
289
+ }
290
+
291
+ if (status === 'error') {
292
+ return (
293
+ <Button variant="contained" size="small" onClick={() => handlePay(item)} {...props}>
294
+ {t('payment.subscription.overdue.retry')}
295
+ </Button>
296
+ );
297
+ }
298
+
159
299
  if (item.method.type === 'stripe') {
160
300
  return (
161
- <Button variant="contained" color="primary" onClick={() => window.open(subscriptionUrl, '_blank')} {...props}>
301
+ <Button variant="contained" color="primary" onClick={() => window.open(detailUrl, '_blank')} {...props}>
162
302
  {t('payment.subscription.overdue.viewNow')}
163
303
  </Button>
164
304
  );
165
305
  }
166
306
  return (
167
- <Button variant="contained" color="primary" onClick={() => handlePay(item)} {...props} disabled={isPayLoading}>
168
- {isPayLoading && <CircularProgress size={14} sx={{ mr: 1, color: 'text.lighter' }} />}
307
+ <LoadingButton
308
+ variant="contained"
309
+ size="small"
310
+ disabled={inProcess}
311
+ loading={inProcess}
312
+ onClick={() => handlePay(item)}
313
+ {...props}>
169
314
  {t('payment.subscription.overdue.payNow')}
170
- </Button>
315
+ </LoadingButton>
171
316
  );
172
317
  };
173
318
 
319
+ const getMethodText = (method: PaymentMethod) => {
320
+ if (method.name && method.type !== 'arcblock') {
321
+ return ` (${method.name})`;
322
+ }
323
+ return '';
324
+ };
325
+
326
+ const getOverdueTitle = () => {
327
+ if (subscriptionId && data.subscription) {
328
+ if (summaryList.length === 1) {
329
+ return t('payment.subscription.overdue.title', {
330
+ name: data.subscription?.description,
331
+ count: data.invoices?.length,
332
+ total: formatAmount(summaryList[0]?.amount, summaryList[0]?.currency?.decimal),
333
+ symbol: summaryList[0]?.currency?.symbol,
334
+ method: getMethodText(summaryList[0]?.method),
335
+ });
336
+ }
337
+ return t('payment.subscription.overdue.simpleTitle', {
338
+ name: data.subscription?.description,
339
+ count: data.invoices?.length,
340
+ });
341
+ }
342
+ if (customerId) {
343
+ if (summaryList.length === 1) {
344
+ return t('payment.customer.overdue.title', {
345
+ subscriptionCount: data.subscriptionCount || 0,
346
+ count: data.invoices?.length,
347
+ total: formatAmount(summaryList[0]?.amount, summaryList[0]?.currency?.decimal),
348
+ symbol: summaryList[0]?.currency?.symbol,
349
+ method: getMethodText(summaryList[0]?.method),
350
+ });
351
+ }
352
+ return t('payment.customer.overdue.simpleTitle', {
353
+ subscriptionCount: data.subscriptionCount || 0,
354
+ count: data.invoices?.length,
355
+ });
356
+ }
357
+
358
+ return '';
359
+ };
360
+
361
+ const getEmptyStateMessage = () => {
362
+ if (subscriptionId && data.subscription) {
363
+ return t('payment.subscription.overdue.empty', {
364
+ name: data.subscription?.description,
365
+ });
366
+ }
367
+ if (customerId) {
368
+ return t('payment.customer.overdue.empty');
369
+ }
370
+
371
+ return '';
372
+ };
373
+
174
374
  if (mode === 'custom' && children && typeof children === 'function') {
175
375
  return (
176
376
  <Stack>
177
377
  {children(handlePay, {
178
- subscription: data?.subscription as Subscription,
179
- subscriptionUrl,
378
+ subscription: data?.subscription,
180
379
  summary: data?.summary as { [key: string]: SummaryItem },
181
380
  invoices: data?.invoices as Invoice[],
381
+ subscriptionCount: data?.subscriptionCount,
382
+ detailUrl,
182
383
  })}
183
384
  </Stack>
184
385
  );
185
386
  }
186
387
 
187
- // Default mode
188
388
  return (
189
389
  <Dialog
190
390
  PaperProps={{
@@ -201,12 +401,7 @@ function OverdueInvoicePayment({
201
401
  <Stack gap={1}>
202
402
  {summaryList.length === 0 && (
203
403
  <>
204
- <Alert severity="success">
205
- {t('payment.subscription.overdue.empty', {
206
- // @ts-ignore
207
- name: data?.subscription?.description,
208
- })}
209
- </Alert>
404
+ <Alert severity="success">{getEmptyStateMessage()}</Alert>
210
405
  <Stack direction="row" justifyContent="flex-end" mt={2}>
211
406
  <Button variant="outlined" color="primary" onClick={handleClose} sx={{ width: 'fit-content' }}>
212
407
  {/* @ts-ignore */}
@@ -218,23 +413,21 @@ function OverdueInvoicePayment({
218
413
  {summaryList.length === 1 && (
219
414
  <>
220
415
  <Typography color="text.secondary" variant="body1">
221
- {t('payment.subscription.overdue.title', {
222
- // @ts-ignore
223
- name: data?.subscription?.description,
224
- count: data?.invoices?.length,
225
- total: formatAmount(summaryList[0]?.amount, summaryList[0]?.currency?.decimal),
226
- symbol: summaryList[0]?.currency?.symbol,
227
- })}
228
- <br />
229
- {t('payment.subscription.overdue.description')}
230
- <a
231
- href={subscriptionUrl}
232
- target="_blank"
233
- onClick={handleViewDetailClick}
234
- rel="noreferrer"
235
- style={{ color: 'var(--foregrounds-fg-interactive, 0086FF)' }}>
236
- {t('payment.subscription.overdue.view')}
237
- </a>
416
+ {getOverdueTitle()}
417
+ {detailLinkOptions.enabled && (
418
+ <>
419
+ <br />
420
+ {t('payment.subscription.overdue.description')}
421
+ <a
422
+ href={detailUrl}
423
+ target="_blank"
424
+ onClick={handleViewDetailClick}
425
+ rel="noreferrer"
426
+ style={{ color: 'var(--foregrounds-fg-interactive, 0086FF)' }}>
427
+ {getDetailLinkText()}
428
+ </a>
429
+ </>
430
+ )}
238
431
  </Typography>
239
432
  <Stack direction="row" justifyContent="flex-end" gap={2} mt={2}>
240
433
  <Button variant="outlined" color="primary" onClick={handleClose}>
@@ -249,22 +442,21 @@ function OverdueInvoicePayment({
249
442
  {summaryList.length > 1 && (
250
443
  <>
251
444
  <Typography color="text.secondary" variant="body1">
252
- {/* @ts-ignore */}
253
- {t('payment.subscription.overdue.simpleTitle', {
254
- // @ts-ignore
255
- name: data?.subscription?.description,
256
- count: data?.invoices?.length,
257
- })}
258
- <br />
259
- {t('payment.subscription.overdue.description')}
260
- <a
261
- href={subscriptionUrl}
262
- target="_blank"
263
- rel="noreferrer"
264
- onClick={handleViewDetailClick}
265
- style={{ color: 'var(--foregrounds-fg-interactive, 0086FF)' }}>
266
- {t('payment.subscription.overdue.view')}
267
- </a>
445
+ {getOverdueTitle()}
446
+ {detailLinkOptions.enabled && (
447
+ <>
448
+ <br />
449
+ {t('payment.subscription.overdue.description')}
450
+ <a
451
+ href={detailUrl}
452
+ target="_blank"
453
+ rel="noreferrer"
454
+ onClick={handleViewDetailClick}
455
+ style={{ color: 'var(--foregrounds-fg-interactive, 0086FF)' }}>
456
+ {getDetailLinkText()}
457
+ </a>
458
+ </>
459
+ )}
268
460
  </Typography>
269
461
  <Typography color="text.secondary" variant="body1">
270
462
  {t('payment.subscription.overdue.list')}
@@ -289,9 +481,10 @@ function OverdueInvoicePayment({
289
481
  {t('payment.subscription.overdue.total', {
290
482
  total: formatAmount(item?.amount, item?.currency?.decimal),
291
483
  currency: item?.currency?.symbol,
484
+ method: getMethodText(item?.method),
292
485
  })}
293
486
  </Typography>
294
- {renderPayButton(item, {
487
+ {renderPayButton(item, false, {
295
488
  variant: 'text',
296
489
  sx: {
297
490
  color: 'text.link',
@@ -315,7 +508,10 @@ OverdueInvoicePayment.defaultProps = {
315
508
  open: true,
316
509
  },
317
510
  children: null,
318
- inSubscriptionDetail: false,
511
+ detailLinkOptions: { enabled: true },
512
+ subscriptionId: undefined,
513
+ customerId: undefined,
514
+ successToast: true,
319
515
  };
320
516
 
321
517
  export default OverdueInvoicePayment;
@@ -36,6 +36,20 @@ export type PaymentContextProps = {
36
36
  baseUrl?: string;
37
37
  };
38
38
 
39
+ const formatData = (data: any) => {
40
+ if (!data) {
41
+ return {
42
+ paymentMethods: [],
43
+ baseCurrency: {},
44
+ };
45
+ }
46
+ return {
47
+ ...data,
48
+ paymentMethods: data.paymentMethods || [],
49
+ baseCurrency: data.baseCurrency || {},
50
+ };
51
+ };
52
+
39
53
  // @ts-ignore
40
54
  const PaymentContext = createContext<PaymentContextType>({ api });
41
55
  const { Provider, Consumer } = PaymentContext;
@@ -95,7 +109,7 @@ function PaymentProvider({ session, connect, children, baseUrl }: PaymentContext
95
109
  connect,
96
110
  prefix,
97
111
  livemode: !!livemode,
98
- settings: data as Settings,
112
+ settings: formatData(data) as Settings,
99
113
  getCurrency: (currencyId: string) => getCurrency(currencyId, (data as Settings)?.paymentMethods || []),
100
114
  getMethod: (methodId: string) => getMethod(methodId, (data as Settings)?.paymentMethods || []),
101
115
  refresh: run,