payment-kit 1.18.46 → 1.18.48

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.
@@ -5,12 +5,12 @@ import {
5
5
  ConfirmDialog,
6
6
  api,
7
7
  formatError,
8
- formatToDate,
9
8
  getPrefix,
10
9
  getSubscriptionAction,
11
10
  usePaymentContext,
12
11
  OverdueInvoicePayment,
13
12
  formatBNStr,
13
+ ResumeSubscription,
14
14
  } from '@blocklet/payment-react';
15
15
  import type { TSubscriptionExpanded } from '@blocklet/payment-types';
16
16
  import { Button, Link, Stack, Tooltip, Typography, Box, Alert } from '@mui/material';
@@ -27,7 +27,7 @@ import CustomerCancelForm from './cancel';
27
27
  import OverdraftProtectionDialog from '../../customer/overdraft-protection';
28
28
  import Actions from '../../actions';
29
29
  import { useUnpaidInvoicesCheckForSubscription } from '../../../hooks/subscription';
30
- import { isWillCanceled } from '../../../libs/util';
30
+ import { isActive, isWillCanceled } from '../../../libs/util';
31
31
 
32
32
  interface ActionConfig {
33
33
  key: string;
@@ -105,34 +105,26 @@ SubscriptionActions.defaultProps = {
105
105
  forceShowDetailAction: false,
106
106
  buttonSize: 'small',
107
107
  };
108
- const fetchExtraActions = async ({
109
- id,
110
- showExtra,
111
- }: {
112
- id: string;
113
- showExtra: boolean;
114
- }): Promise<{ changePlan: boolean; batchPay: string }> => {
115
- if (!showExtra) {
116
- return Promise.resolve({ changePlan: false, batchPay: '' });
117
- }
118
108
 
119
- const [changePlan, batchPay] = await Promise.all([
120
- api
121
- .get(`/api/subscriptions/${id}/change-plan`)
122
- .then((res) => !!res.data)
123
- .catch(() => false),
124
- api
125
- .get(`/api/subscriptions/${id}/summary`)
126
- .then((res) => {
127
- if (!isEmpty(res.data) && Object.keys(res.data).length === 1) {
128
- return Object.keys(res.data)[0] as string;
129
- }
130
- return '';
131
- })
132
- .catch(() => ''),
133
- ]);
109
+ const fetchChangePlan = async (id: string): Promise<boolean> => {
110
+ try {
111
+ const res = await api.get(`/api/subscriptions/${id}/change-plan`);
112
+ return !!res.data;
113
+ } catch {
114
+ return false;
115
+ }
116
+ };
134
117
 
135
- return { changePlan, batchPay };
118
+ const fetchBatchPay = async (id: string): Promise<string> => {
119
+ try {
120
+ const res = await api.get(`/api/subscriptions/${id}/summary`);
121
+ if (!isEmpty(res.data) && Object.keys(res.data).length === 1) {
122
+ return Object.keys(res.data)[0] as string;
123
+ }
124
+ return '';
125
+ } catch {
126
+ return '';
127
+ }
136
128
  };
137
129
 
138
130
  const supportRecharge = (subscription: TSubscriptionExpanded) => {
@@ -177,7 +169,13 @@ export function SubscriptionActionsInner({
177
169
  return true;
178
170
  };
179
171
 
180
- const { data: extraActions } = useRequest(() => fetchExtraActions({ id: subscription.id, showExtra: !!showExtra }));
172
+ const { data: changePlanAvailable = false } = useRequest(() => fetchChangePlan(subscription.id), {
173
+ ready: !!showExtra && isActive(subscription),
174
+ });
175
+
176
+ const { data: batchPayAvailable = '' } = useRequest(() => fetchBatchPay(subscription.id), {
177
+ ready: !!showExtra,
178
+ });
181
179
 
182
180
  const { data: upcoming = {} } = useRequest(
183
181
  () => api.get(`/api/subscriptions/${subscription.id}/upcoming`).then((res) => res.data),
@@ -269,21 +267,6 @@ export function SubscriptionActionsInner({
269
267
  }
270
268
  };
271
269
 
272
- const handleRecover = async () => {
273
- try {
274
- setState({ loading: true });
275
- const sub = await api.put(`/api/subscriptions/${state.subscription}/recover`).then((res) => res.data);
276
- setSubscription(sub);
277
- Toast.success(t('common.saved'));
278
- if (onChange) onChange(state.action);
279
- } catch (err) {
280
- console.error(err);
281
- Toast.error(formatError(err));
282
- } finally {
283
- setState({ loading: false, action: '', subscription: '' });
284
- }
285
- };
286
-
287
270
  const handleDelegate = () => {
288
271
  connect.open({
289
272
  containerEl: undefined as unknown as Element,
@@ -503,7 +486,7 @@ export function SubscriptionActionsInner({
503
486
  },
504
487
  {
505
488
  key: 'changePlan',
506
- show: !!extraActions?.changePlan,
489
+ show: changePlanAvailable,
507
490
  label: action?.text || t('payment.customer.changePlan.button'),
508
491
  onClick: (e) => {
509
492
  e?.stopPropagation();
@@ -515,7 +498,7 @@ export function SubscriptionActionsInner({
515
498
  },
516
499
  {
517
500
  key: 'batchPay',
518
- show: !!extraActions?.batchPay,
501
+ show: !!batchPayAvailable,
519
502
  label: action?.text || t('admin.subscription.batchPay.button'),
520
503
  onClick: (e) => {
521
504
  e?.stopPropagation();
@@ -530,7 +513,7 @@ export function SubscriptionActionsInner({
530
513
  },
531
514
  {
532
515
  key: 'mainAction',
533
- show: !!(!extraActions?.batchPay && supportAction),
516
+ show: !!(!batchPayAvailable && supportAction),
534
517
  label: action?.text || t(`payment.customer.${action?.action}.button`),
535
518
  onClick: (e) => {
536
519
  e?.stopPropagation();
@@ -660,18 +643,17 @@ export function SubscriptionActionsInner({
660
643
  />
661
644
  )}
662
645
  {state.action === 'recover' && state.subscription && (
663
- <ConfirmDialog
664
- onConfirm={handleRecover}
665
- onCancel={(e) => {
666
- e.stopPropagation();
646
+ <ResumeSubscription
647
+ subscriptionId={state.subscription}
648
+ onResumed={(updatedSubscription) => {
667
649
  setState({ action: '', subscription: '' });
650
+ onChange?.(state.action);
651
+ setSubscription(updatedSubscription as TSubscriptionExpanded);
652
+ }}
653
+ dialogProps={{
654
+ open: true,
655
+ onClose: () => setState({ action: '', subscription: '' }),
668
656
  }}
669
- title={t('payment.customer.recover.title')}
670
- message={t('payment.customer.recover.description', {
671
- date: formatToDate(subscription.current_period_end * 1000),
672
- })}
673
- loading={state.loading}
674
- color="primary"
675
657
  />
676
658
  )}
677
659
 
@@ -21,7 +21,7 @@ import SubscriptionDescription from '../description';
21
21
  import SubscriptionActions from './actions';
22
22
  import SubscriptionStatus from '../status';
23
23
  import useDelayedLoading from '../../../hooks/loading';
24
- import { isWillCanceled } from '../../../libs/util';
24
+ import { formatProxyUrl, isWillCanceled } from '../../../libs/util';
25
25
 
26
26
  type SubscriptionListResponse = {
27
27
  count: number;
@@ -161,31 +161,41 @@ export default function CurrentSubscriptions({
161
161
  justifyContent="space-between"
162
162
  onClick={() => onClickSubscription(subscription)}>
163
163
  <Stack direction="row" spacing={1.5} alignItems="center">
164
- <AvatarGroup
165
- max={2}
166
- sx={{
167
- '& .MuiAvatar-colorDefault': {
168
- ...size,
169
- boxSizing: 'border-box',
170
- },
171
- }}>
172
- {subscription.items.slice(0, 2).map((item) =>
173
- item.price.product.images.length > 0 ? (
174
- // @ts-ignore
175
- <Avatar
176
- key={item.price.product_id}
177
- src={item.price.product.images[0]}
178
- alt={item.price.product.name}
179
- variant="rounded"
180
- sx={size}
181
- />
182
- ) : (
183
- <Avatar key={item.price.product_id} variant="rounded" sx={size}>
184
- {item.price.product.name.slice(0, 1)}
185
- </Avatar>
186
- )
187
- )}
188
- </AvatarGroup>
164
+ {subscription.metadata?.appLogo ? (
165
+ <Avatar
166
+ src={formatProxyUrl(subscription.metadata?.appLogo)}
167
+ alt={subscription.metadata?.appName}
168
+ variant="rounded"
169
+ sx={size}
170
+ />
171
+ ) : (
172
+ <AvatarGroup
173
+ max={2}
174
+ sx={{
175
+ '& .MuiAvatar-colorDefault': {
176
+ ...size,
177
+ boxSizing: 'border-box',
178
+ },
179
+ }}>
180
+ {subscription.items.slice(0, 2).map((item) =>
181
+ item.price.product.images.length > 0 ? (
182
+ // @ts-ignore
183
+ <Avatar
184
+ key={item.price.product_id}
185
+ src={item.price.product.images[0]}
186
+ alt={item.price.product.name}
187
+ variant="rounded"
188
+ sx={size}
189
+ />
190
+ ) : (
191
+ <Avatar key={item.price.product_id} variant="rounded" sx={size}>
192
+ {item.price.product.name.slice(0, 1)}
193
+ </Avatar>
194
+ )
195
+ )}
196
+ </AvatarGroup>
197
+ )}
198
+
189
199
  <Stack direction="column" spacing={0.25}>
190
200
  <SubscriptionDescription
191
201
  subscription={subscription}
package/src/libs/util.ts CHANGED
@@ -348,6 +348,9 @@ export function getAppInfo(address: string): { name: string; avatar: string; typ
348
348
  return null;
349
349
  }
350
350
 
351
+ export function isActive(subscription: TSubscriptionExpanded) {
352
+ return ['active', 'trialing'].includes(subscription.status);
353
+ }
351
354
  export function isWillCanceled(subscription: TSubscriptionExpanded) {
352
355
  const now = Date.now() / 1000;
353
356
  if (
@@ -362,3 +365,14 @@ export function isWillCanceled(subscription: TSubscriptionExpanded) {
362
365
  }
363
366
  return false;
364
367
  }
368
+
369
+ export function formatProxyUrl(url: string) {
370
+ if (url.startsWith('/')) {
371
+ return joinURL(window.location.origin, url);
372
+ }
373
+ const proxyUrl = new URL(url);
374
+ if (proxyUrl.host === window.location.host) {
375
+ return url;
376
+ }
377
+ return `${window.location.origin}/.well-known/service/proxy?url=${url}`;
378
+ }
@@ -1,15 +1,7 @@
1
1
  /* eslint-disable react/no-unstable-nested-components */
2
2
  import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
3
3
  import Toast from '@arcblock/ux/lib/Toast';
4
- import {
5
- TxLink,
6
- api,
7
- formatError,
8
- formatSubscriptionProduct,
9
- formatTime,
10
- useMobile,
11
- hasDelegateTxHash,
12
- } from '@blocklet/payment-react';
4
+ import { TxLink, api, formatError, formatTime, useMobile, hasDelegateTxHash } from '@blocklet/payment-react';
13
5
  import type { TProduct, TSubscriptionExpanded } from '@blocklet/payment-types';
14
6
  import { ArrowBackOutlined } from '@mui/icons-material';
15
7
  import { Alert, Box, Button, CircularProgress, Divider, Stack, Typography } from '@mui/material';
@@ -125,7 +117,7 @@ export default function SubscriptionDetail(props: { id: string }) {
125
117
  <Stack direction="column" gap={1}>
126
118
  <Stack direction="row" alignItems="center">
127
119
  <Typography variant="h2" sx={{ fontWeight: 600 }}>
128
- {data.customer?.name} On {formatSubscriptionProduct(data.items)}
120
+ {data.description}
129
121
  </Typography>
130
122
  </Stack>
131
123
  <Copyable text={props.id} />
@@ -126,6 +126,7 @@ export default function CustomerInvoicePastDue() {
126
126
  {showOverduePayment && (
127
127
  <OverdueInvoicePayment
128
128
  customerId={session.user.did}
129
+ subscriptionId={subscriptionId}
129
130
  onPaid={() => {
130
131
  setShowOverduePayment(false);
131
132
  }}