payment-kit 1.18.56 → 1.19.1

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 (214) hide show
  1. package/.eslintrc.js +6 -0
  2. package/api/src/crons/index.ts +8 -0
  3. package/api/src/index.ts +4 -0
  4. package/api/src/libs/credit-grant.ts +146 -0
  5. package/api/src/libs/env.ts +1 -0
  6. package/api/src/libs/invoice.ts +4 -3
  7. package/api/src/libs/notification/template/base.ts +388 -2
  8. package/api/src/libs/notification/template/customer-credit-grant-granted.ts +149 -0
  9. package/api/src/libs/notification/template/customer-credit-grant-low-balance.ts +151 -0
  10. package/api/src/libs/notification/template/customer-credit-insufficient.ts +254 -0
  11. package/api/src/libs/notification/template/subscription-canceled.ts +193 -202
  12. package/api/src/libs/notification/template/subscription-refund-succeeded.ts +215 -237
  13. package/api/src/libs/notification/template/subscription-renewed.ts +130 -200
  14. package/api/src/libs/notification/template/subscription-succeeded.ts +100 -202
  15. package/api/src/libs/notification/template/subscription-trial-start.ts +142 -188
  16. package/api/src/libs/notification/template/subscription-trial-will-end.ts +146 -174
  17. package/api/src/libs/notification/template/subscription-upgraded.ts +96 -192
  18. package/api/src/libs/notification/template/subscription-will-canceled.ts +94 -135
  19. package/api/src/libs/notification/template/subscription-will-renew.ts +220 -245
  20. package/api/src/libs/payment.ts +69 -0
  21. package/api/src/libs/queue/index.ts +3 -2
  22. package/api/src/libs/session.ts +8 -0
  23. package/api/src/libs/subscription.ts +74 -3
  24. package/api/src/libs/ws.ts +23 -1
  25. package/api/src/locales/en.ts +33 -0
  26. package/api/src/locales/zh.ts +31 -0
  27. package/api/src/queues/credit-consume.ts +715 -0
  28. package/api/src/queues/credit-grant.ts +572 -0
  29. package/api/src/queues/notification.ts +173 -128
  30. package/api/src/queues/payment.ts +210 -122
  31. package/api/src/queues/subscription.ts +179 -0
  32. package/api/src/routes/checkout-sessions.ts +157 -9
  33. package/api/src/routes/connect/shared.ts +3 -2
  34. package/api/src/routes/credit-grants.ts +241 -0
  35. package/api/src/routes/credit-transactions.ts +208 -0
  36. package/api/src/routes/index.ts +8 -0
  37. package/api/src/routes/meter-events.ts +347 -0
  38. package/api/src/routes/meters.ts +219 -0
  39. package/api/src/routes/payment-currencies.ts +14 -2
  40. package/api/src/routes/payment-links.ts +1 -1
  41. package/api/src/routes/payment-methods.ts +14 -2
  42. package/api/src/routes/prices.ts +43 -0
  43. package/api/src/routes/pricing-table.ts +13 -7
  44. package/api/src/routes/products.ts +63 -4
  45. package/api/src/routes/settings.ts +1 -1
  46. package/api/src/routes/subscriptions.ts +4 -0
  47. package/api/src/store/migrations/20250610-billing-credit.ts +43 -0
  48. package/api/src/store/models/credit-grant.ts +486 -0
  49. package/api/src/store/models/credit-transaction.ts +268 -0
  50. package/api/src/store/models/customer.ts +8 -0
  51. package/api/src/store/models/index.ts +52 -1
  52. package/api/src/store/models/meter-event.ts +423 -0
  53. package/api/src/store/models/meter.ts +176 -0
  54. package/api/src/store/models/payment-currency.ts +66 -14
  55. package/api/src/store/models/price.ts +6 -0
  56. package/api/src/store/models/product.ts +2 -2
  57. package/api/src/store/models/subscription.ts +24 -0
  58. package/api/src/store/models/types.ts +28 -2
  59. package/api/tests/libs/subscription.spec.ts +53 -0
  60. package/blocklet.yml +9 -1
  61. package/package.json +57 -58
  62. package/scripts/sdk.js +233 -1
  63. package/src/app.tsx +10 -0
  64. package/src/components/actions.tsx +22 -9
  65. package/src/components/balance-list.tsx +40 -12
  66. package/src/components/collapse.tsx +33 -15
  67. package/src/components/copyable.tsx +8 -7
  68. package/src/components/currency.tsx +15 -7
  69. package/src/components/customer/actions.tsx +1 -5
  70. package/src/components/customer/credit-grant-item-list.tsx +99 -0
  71. package/src/components/customer/credit-overview.tsx +233 -0
  72. package/src/components/customer/form.tsx +7 -2
  73. package/src/components/customer/link.tsx +4 -12
  74. package/src/components/customer/notification-preference.tsx +18 -9
  75. package/src/components/customer/overdraft-protection.tsx +112 -41
  76. package/src/components/drawer-form.tsx +42 -18
  77. package/src/components/error.tsx +1 -5
  78. package/src/components/event/list.tsx +9 -10
  79. package/src/components/filter-toolbar.tsx +20 -19
  80. package/src/components/info-card.tsx +32 -18
  81. package/src/components/info-metric.tsx +16 -6
  82. package/src/components/info-row-group.tsx +1 -7
  83. package/src/components/info-row.tsx +30 -24
  84. package/src/components/invoice/action.tsx +1 -7
  85. package/src/components/invoice/list.tsx +34 -26
  86. package/src/components/invoice/recharge.tsx +5 -7
  87. package/src/components/invoice/table.tsx +17 -12
  88. package/src/components/layout/user.tsx +1 -1
  89. package/src/components/metadata/form.tsx +290 -94
  90. package/src/components/metadata/list.tsx +11 -3
  91. package/src/components/meter/actions.tsx +101 -0
  92. package/src/components/meter/add-usage-dialog.tsx +239 -0
  93. package/src/components/meter/events-list.tsx +657 -0
  94. package/src/components/meter/form.tsx +245 -0
  95. package/src/components/meter/products.tsx +264 -0
  96. package/src/components/meter/usage-guide.tsx +174 -0
  97. package/src/components/passport/actions.tsx +9 -4
  98. package/src/components/payment-currency/add.tsx +16 -3
  99. package/src/components/payment-currency/form.tsx +14 -6
  100. package/src/components/payment-intent/actions.tsx +24 -16
  101. package/src/components/payment-intent/list.tsx +30 -9
  102. package/src/components/payment-link/actions.tsx +1 -5
  103. package/src/components/payment-link/after-pay.tsx +4 -2
  104. package/src/components/payment-link/before-pay.tsx +14 -4
  105. package/src/components/payment-link/item.tsx +27 -6
  106. package/src/components/payment-link/preview.tsx +9 -9
  107. package/src/components/payment-link/product-select.tsx +69 -15
  108. package/src/components/payment-method/arcblock.tsx +8 -1
  109. package/src/components/payment-method/base.tsx +8 -1
  110. package/src/components/payment-method/bitcoin.tsx +8 -1
  111. package/src/components/payment-method/ethereum.tsx +8 -1
  112. package/src/components/payment-method/evm-rpc-input.tsx +11 -7
  113. package/src/components/payment-method/form.tsx +2 -7
  114. package/src/components/payment-method/stripe.tsx +2 -0
  115. package/src/components/payouts/actions.tsx +1 -5
  116. package/src/components/payouts/list.tsx +30 -10
  117. package/src/components/payouts/portal/list.tsx +11 -9
  118. package/src/components/price/currency-select.tsx +63 -32
  119. package/src/components/price/form.tsx +895 -370
  120. package/src/components/price/upsell-select.tsx +10 -2
  121. package/src/components/price/upsell.tsx +7 -2
  122. package/src/components/pricing-table/actions.tsx +1 -5
  123. package/src/components/pricing-table/customer-settings.tsx +5 -1
  124. package/src/components/pricing-table/payment-settings.tsx +14 -4
  125. package/src/components/pricing-table/preview.tsx +9 -9
  126. package/src/components/pricing-table/price-item.tsx +6 -1
  127. package/src/components/pricing-table/product-item.tsx +6 -1
  128. package/src/components/pricing-table/product-settings.tsx +17 -4
  129. package/src/components/product/actions.tsx +1 -5
  130. package/src/components/product/add-price.tsx +9 -7
  131. package/src/components/product/create.tsx +8 -9
  132. package/src/components/product/cross-sell-select.tsx +5 -1
  133. package/src/components/product/cross-sell.tsx +7 -2
  134. package/src/components/product/edit-price.tsx +21 -12
  135. package/src/components/product/features.tsx +26 -6
  136. package/src/components/product/form.tsx +115 -72
  137. package/src/components/progress-bar.tsx +1 -1
  138. package/src/components/refund/actions.tsx +1 -7
  139. package/src/components/refund/list.tsx +31 -18
  140. package/src/components/section/header.tsx +12 -14
  141. package/src/components/subscription/actions/cancel.tsx +22 -5
  142. package/src/components/subscription/actions/index.tsx +9 -10
  143. package/src/components/subscription/actions/pause.tsx +32 -6
  144. package/src/components/subscription/actions/slash-stake.tsx +5 -3
  145. package/src/components/subscription/description.tsx +12 -8
  146. package/src/components/subscription/items/index.tsx +31 -16
  147. package/src/components/subscription/items/usage-records.tsx +19 -5
  148. package/src/components/subscription/list.tsx +5 -7
  149. package/src/components/subscription/metrics.tsx +62 -15
  150. package/src/components/subscription/portal/actions.tsx +78 -71
  151. package/src/components/subscription/portal/cancel.tsx +10 -3
  152. package/src/components/subscription/portal/list.tsx +48 -26
  153. package/src/components/uploader.tsx +5 -13
  154. package/src/components/webhook/attempts.tsx +51 -16
  155. package/src/components/webhook/request-info.tsx +8 -6
  156. package/src/contexts/products.tsx +27 -10
  157. package/src/hooks/subscription.ts +34 -0
  158. package/src/libs/meter-utils.ts +196 -0
  159. package/src/libs/util.ts +4 -0
  160. package/src/locales/en.tsx +385 -4
  161. package/src/locales/zh.tsx +364 -0
  162. package/src/pages/admin/billing/index.tsx +61 -33
  163. package/src/pages/admin/billing/invoices/detail.tsx +49 -13
  164. package/src/pages/admin/billing/meters/create.tsx +60 -0
  165. package/src/pages/admin/billing/meters/detail.tsx +435 -0
  166. package/src/pages/admin/billing/meters/index.tsx +210 -0
  167. package/src/pages/admin/billing/meters/meter-event.tsx +346 -0
  168. package/src/pages/admin/billing/subscriptions/detail.tsx +90 -25
  169. package/src/pages/admin/customers/customers/credit-grant/detail.tsx +391 -0
  170. package/src/pages/admin/customers/customers/detail.tsx +67 -14
  171. package/src/pages/admin/customers/customers/index.tsx +6 -1
  172. package/src/pages/admin/customers/index.tsx +5 -0
  173. package/src/pages/admin/developers/events/detail.tsx +37 -11
  174. package/src/pages/admin/developers/index.tsx +1 -1
  175. package/src/pages/admin/developers/webhooks/detail.tsx +41 -11
  176. package/src/pages/admin/index.tsx +15 -2
  177. package/src/pages/admin/overview.tsx +107 -19
  178. package/src/pages/admin/payments/intents/detail.tsx +58 -14
  179. package/src/pages/admin/payments/payouts/detail.tsx +63 -15
  180. package/src/pages/admin/payments/refunds/detail.tsx +58 -14
  181. package/src/pages/admin/products/index.tsx +11 -4
  182. package/src/pages/admin/products/links/create.tsx +22 -4
  183. package/src/pages/admin/products/links/detail.tsx +43 -14
  184. package/src/pages/admin/products/passports/index.tsx +23 -4
  185. package/src/pages/admin/products/prices/actions.tsx +16 -9
  186. package/src/pages/admin/products/prices/detail.tsx +73 -14
  187. package/src/pages/admin/products/prices/list.tsx +15 -3
  188. package/src/pages/admin/products/pricing-tables/create.tsx +45 -12
  189. package/src/pages/admin/products/pricing-tables/detail.tsx +45 -14
  190. package/src/pages/admin/products/products/create.tsx +233 -54
  191. package/src/pages/admin/products/products/detail.tsx +74 -18
  192. package/src/pages/admin/settings/index.tsx +8 -1
  193. package/src/pages/admin/settings/payment-methods/index.tsx +87 -19
  194. package/src/pages/admin/settings/vault-config/edit-form.tsx +42 -28
  195. package/src/pages/admin/settings/vault-config/index.tsx +57 -10
  196. package/src/pages/customer/credit-grant/detail.tsx +308 -0
  197. package/src/pages/customer/index.tsx +76 -17
  198. package/src/pages/customer/invoice/detail.tsx +63 -14
  199. package/src/pages/customer/invoice/past-due.tsx +11 -3
  200. package/src/pages/customer/payout/detail.tsx +56 -13
  201. package/src/pages/customer/recharge/account.tsx +78 -18
  202. package/src/pages/customer/recharge/subscription.tsx +86 -25
  203. package/src/pages/customer/refund/list.tsx +60 -24
  204. package/src/pages/customer/subscription/change-payment.tsx +17 -6
  205. package/src/pages/customer/subscription/change-plan.tsx +34 -7
  206. package/src/pages/customer/subscription/detail.tsx +134 -34
  207. package/src/pages/customer/subscription/embed.tsx +25 -5
  208. package/src/pages/home.tsx +26 -4
  209. package/src/pages/integrations/donations/edit-form.tsx +25 -9
  210. package/src/pages/integrations/donations/index.tsx +26 -9
  211. package/src/pages/integrations/donations/preview.tsx +59 -15
  212. package/src/pages/integrations/index.tsx +10 -1
  213. package/src/pages/integrations/overview.tsx +78 -17
  214. package/vite.config.ts +60 -30
@@ -17,6 +17,7 @@ import {
17
17
  getPriceCurrencyOptions,
18
18
  getStatementDescriptor,
19
19
  isValidCountry,
20
+ showStaking,
20
21
  usePaymentContext,
21
22
  } from '@blocklet/payment-react';
22
23
  import type { TCustomer, TPaymentCurrency, TPaymentMethod, TSubscriptionExpanded } from '@blocklet/payment-types';
@@ -222,14 +223,24 @@ function CustomerSubscriptionChangePayment({ subscription, customer, onComplete
222
223
  setState({ stripePaying: false });
223
224
  };
224
225
 
226
+ const currency = findCurrency(settings.paymentMethods, selectedCurrencyId) as TPaymentCurrency;
225
227
  return (
226
228
  <Stack direction="column" spacing={4} sx={{ maxWidth: '540px' }}>
227
- <Stack className="page-header" direction="row" justifyContent="space-between" alignItems="center">
229
+ <Stack
230
+ className="page-header"
231
+ direction="row"
232
+ sx={{
233
+ justifyContent: 'space-between',
234
+ alignItems: 'center',
235
+ }}>
228
236
  <Stack
229
237
  direction="row"
230
- alignItems="center"
231
- sx={{ fontWeight: 'normal', cursor: 'pointer' }}
232
- onClick={() => goBackOrFallback(`/customer/subscription/${subscription.id}`)}>
238
+ onClick={() => goBackOrFallback(`/customer/subscription/${subscription.id}`)}
239
+ sx={{
240
+ alignItems: 'center',
241
+ fontWeight: 'normal',
242
+ cursor: 'pointer',
243
+ }}>
233
244
  <ArrowBackOutlined fontSize="small" sx={{ mr: 0.5, color: 'text.secondary' }} />
234
245
  <SubscriptionDescription subscription={subscription} variant="h5" />
235
246
  </Stack>
@@ -239,10 +250,10 @@ function CustomerSubscriptionChangePayment({ subscription, customer, onComplete
239
250
  <SectionHeader title={t('payment.customer.changePayment.review')} />
240
251
  <PaymentSummary
241
252
  items={subscription.items as any[]}
242
- currency={findCurrency(settings.paymentMethods, selectedCurrencyId) as TPaymentCurrency}
253
+ currency={currency}
243
254
  trialInDays={0}
244
255
  billingThreshold={0}
245
- showStaking={method.type === 'arcblock' && !subscription.billing_thresholds?.no_stake}
256
+ showStaking={showStaking(method, currency, !!subscription.billing_thresholds?.no_stake)}
246
257
  />
247
258
  </Stack>
248
259
  <Stack direction="column" spacing={2}>
@@ -219,7 +219,12 @@ export default function CustomerSubscriptionChangePlan() {
219
219
 
220
220
  const getInfoRow = (label: string, value: string, prefix?: string) => {
221
221
  return (
222
- <Stack direction="row" justifyContent="space-between" key={value}>
222
+ <Stack
223
+ direction="row"
224
+ key={value}
225
+ sx={{
226
+ justifyContent: 'space-between',
227
+ }}>
223
228
  <Typography variant="h6" sx={{ fontWeight: 'normal' }}>
224
229
  {label}
225
230
  </Typography>
@@ -233,12 +238,21 @@ export default function CustomerSubscriptionChangePlan() {
233
238
 
234
239
  return (
235
240
  <Stack direction="column" spacing={4} sx={{ mb: 4 }}>
236
- <Stack className="page-header" direction="row" justifyContent="space-between" alignItems="center">
241
+ <Stack
242
+ className="page-header"
243
+ direction="row"
244
+ sx={{
245
+ justifyContent: 'space-between',
246
+ alignItems: 'center',
247
+ }}>
237
248
  <Stack
238
249
  direction="row"
239
- alignItems="center"
240
- sx={{ fontWeight: 'normal', cursor: 'pointer' }}
241
- onClick={() => goBackOrFallback(`/customer/subscription/${data.subscription.id}`)}>
250
+ onClick={() => goBackOrFallback(`/customer/subscription/${data.subscription.id}`)}
251
+ sx={{
252
+ alignItems: 'center',
253
+ fontWeight: 'normal',
254
+ cursor: 'pointer',
255
+ }}>
242
256
  <ArrowBackOutlined fontSize="small" sx={{ mr: 0.5, color: 'text.secondary' }} />
243
257
  <SubscriptionDescription subscription={data.subscription} variant="h5" />
244
258
  </Stack>
@@ -268,7 +282,13 @@ export default function CustomerSubscriptionChangePlan() {
268
282
  {state.items.map((x: TLineItemExpanded) => {
269
283
  const { product } = x.price;
270
284
  return (
271
- <Stack key={x.price_id} direction="row" alignItems="center" justifyContent="space-between">
285
+ <Stack
286
+ key={x.price_id}
287
+ direction="row"
288
+ sx={{
289
+ alignItems: 'center',
290
+ justifyContent: 'space-between',
291
+ }}>
272
292
  <InfoCard logo={product.images[0]} name={product.name} description={product.description} />
273
293
  <Typography component="p" style={{ fontWeight: 'bold' }}>
274
294
  {formatPrice(
@@ -294,7 +314,14 @@ export default function CustomerSubscriptionChangePlan() {
294
314
  <Divider />
295
315
  {getInfoRow(t('payment.customer.changePlan.remaining'), state.due)}
296
316
  <Divider />
297
- <Stack direction="row" alignItems="center" justifyContent="flex-end" spacing={2} sx={{ pt: 2 }}>
317
+ <Stack
318
+ direction="row"
319
+ spacing={2}
320
+ sx={{
321
+ alignItems: 'center',
322
+ justifyContent: 'flex-end',
323
+ pt: 2,
324
+ }}>
298
325
  <LoadingButton
299
326
  disabled={state.loading || state.paying}
300
327
  onClick={() => setState({ priceId: '' })}
@@ -1,6 +1,7 @@
1
1
  /* eslint-disable react/no-unstable-nested-components */
2
2
  import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
3
3
  import {
4
+ CreditTransactionsList,
4
5
  CustomerInvoiceList,
5
6
  TxLink,
6
7
  api,
@@ -45,7 +46,7 @@ import SubscriptionActions, { ActionMethods } from '../../../components/subscrip
45
46
  import { canChangePaymentMethod } from '../../../libs/util';
46
47
  import { useSessionContext } from '../../../contexts/session';
47
48
  import InfoMetric from '../../../components/info-metric';
48
- import { useUnpaidInvoicesCheckForSubscription } from '../../../hooks/subscription';
49
+ import { useUnpaidInvoicesCheckForSubscription, usePendingAmountForSubscription } from '../../../hooks/subscription';
49
50
  import { formatSmartDuration, TimeUnit } from '../../../libs/dayjs';
50
51
  import InfoRowGroup from '../../../components/info-row-group';
51
52
 
@@ -74,6 +75,7 @@ export default function CustomerSubscriptionDetail() {
74
75
  const { session } = useSessionContext();
75
76
  const { loading, error, data, refresh } = useRequest(() => fetchData(id));
76
77
  const { hasUnpaid, checkUnpaidInvoices } = useUnpaidInvoicesCheckForSubscription(id);
78
+ const { hasPendingAmount, pendingAmount } = usePendingAmountForSubscription(id, data?.paymentCurrency);
77
79
  const overdraftProtectionReady =
78
80
  ['active', 'trialing', 'past_due'].includes(data?.status || '') && data?.paymentMethod?.type === 'arcblock';
79
81
  const {
@@ -100,7 +102,7 @@ export default function CustomerSubscriptionDetail() {
100
102
  }
101
103
  );
102
104
 
103
- const actionRef = useRef<ActionMethods>();
105
+ const actionRef = useRef<ActionMethods | undefined>(undefined);
104
106
 
105
107
  const enableOverdraftProtection = !!overdraftProtection?.enabled;
106
108
 
@@ -119,11 +121,13 @@ export default function CustomerSubscriptionDetail() {
119
121
  return <CircularProgress />;
120
122
  }
121
123
 
124
+ const isCredit = data?.paymentCurrency?.type === 'credit';
122
125
  const showOverdraftProtection =
123
126
  data?.paymentMethod?.type === 'arcblock' &&
124
127
  !overdraftProtectionLoading &&
125
128
  !!overdraftProtection &&
126
- ['active', 'trialing', 'past_due'].includes(data.status);
129
+ ['active', 'trialing', 'past_due'].includes(data.status) &&
130
+ !isCredit;
127
131
 
128
132
  const renderOverdraftProtectionLabel = () => {
129
133
  const enabled = data?.overdraft_protection?.enabled;
@@ -155,7 +159,12 @@ export default function CustomerSubscriptionDetail() {
155
159
  };
156
160
  if (!enabled) {
157
161
  return (
158
- <Stack direction="row" spacing={1} alignItems="center">
162
+ <Stack
163
+ direction="row"
164
+ spacing={1}
165
+ sx={{
166
+ alignItems: 'center',
167
+ }}>
159
168
  <Typography sx={{ color: 'text.lighter' }}>{t('customer.overdraftProtection.disabled')}</Typography>
160
169
  <Button
161
170
  size="small"
@@ -195,9 +204,23 @@ export default function CustomerSubscriptionDetail() {
195
204
  }
196
205
 
197
206
  return (
198
- <Stack direction="row" alignItems="center">
199
- <Stack direction="row" spacing={1} alignItems="center">
200
- <Stack direction="row" spacing={0.5} alignItems="center">
207
+ <Stack
208
+ direction="row"
209
+ sx={{
210
+ alignItems: 'center',
211
+ }}>
212
+ <Stack
213
+ direction="row"
214
+ spacing={1}
215
+ sx={{
216
+ alignItems: 'center',
217
+ }}>
218
+ <Stack
219
+ direction="row"
220
+ spacing={0.5}
221
+ sx={{
222
+ alignItems: 'center',
223
+ }}>
201
224
  <CheckCircle
202
225
  sx={{
203
226
  fontSize: '16px',
@@ -234,7 +257,11 @@ export default function CustomerSubscriptionDetail() {
234
257
  sx={{ width: 16, height: 16 }}
235
258
  alt={data.paymentCurrency?.symbol}
236
259
  />
237
- <Box display="flex" alignItems="baseline">
260
+ <Box
261
+ sx={{
262
+ display: 'flex',
263
+ alignItems: 'baseline',
264
+ }}>
238
265
  {formatBNStr(overdraftProtection?.unused, data.paymentCurrency.decimal)}
239
266
  <Typography
240
267
  sx={{
@@ -280,23 +307,40 @@ export default function CustomerSubscriptionDetail() {
280
307
  {t('customer.unpaidInvoicesWarningTip')}
281
308
  </Alert>
282
309
  )}
310
+ {hasPendingAmount && pendingAmount && (
311
+ <Alert severity="error" sx={{ mb: 2 }}>
312
+ {t('customer.pendingAmountWarningTip', {
313
+ amount: formatBNStr(pendingAmount, data?.paymentCurrency?.decimal),
314
+ symbol: data?.paymentCurrency?.symbol,
315
+ })}
316
+ </Alert>
317
+ )}
283
318
  <Stack
284
319
  className="page-header"
285
320
  direction="row"
286
- justifyContent="space-between"
287
- alignItems="center"
288
- sx={{ position: 'relative' }}>
321
+ sx={{
322
+ justifyContent: 'space-between',
323
+ alignItems: 'center',
324
+ position: 'relative',
325
+ }}>
289
326
  <Stack
290
327
  direction="row"
291
328
  onClick={() => navigate('/customer', { replace: true })}
292
- alignItems="center"
293
- sx={{ fontWeight: 'normal', cursor: 'pointer' }}>
329
+ sx={{
330
+ alignItems: 'center',
331
+ fontWeight: 'normal',
332
+ cursor: 'pointer',
333
+ }}>
294
334
  <ArrowBackOutlined fontSize="small" sx={{ mr: 0.5, color: 'text.secondary' }} />
295
335
  <Typography variant="h6" sx={{ color: 'text.secondary', fontWeight: 'normal' }}>
296
336
  {t('payment.customer.subscriptions.title')}
297
337
  </Typography>
298
338
  </Stack>
299
- <Stack direction="row" gap={1}>
339
+ <Stack
340
+ direction="row"
341
+ sx={{
342
+ gap: 1,
343
+ }}>
300
344
  <SubscriptionActions
301
345
  subscription={data}
302
346
  onChange={(action) => {
@@ -332,45 +376,64 @@ export default function CustomerSubscriptionDetail() {
332
376
  </Stack>
333
377
  </Stack>
334
378
  <Box
335
- mt={4}
336
379
  sx={{
380
+ mt: 4,
337
381
  display: 'flex',
382
+
338
383
  gap: {
339
384
  xs: 2,
340
385
  sm: 2,
341
386
  md: 5,
342
387
  },
388
+
343
389
  flexWrap: 'wrap',
390
+
344
391
  flexDirection: {
345
392
  xs: 'column',
346
393
  sm: 'column',
347
394
  md: 'row',
348
395
  },
396
+
349
397
  alignItems: {
350
398
  xs: 'flex-start',
351
399
  sm: 'flex-start',
352
400
  md: 'center',
353
401
  },
354
402
  }}>
355
- <Stack direction="row" justifyContent="space-between" alignItems="center">
356
- <Stack direction="row" alignItems="center" flexWrap="wrap" gap={1}>
403
+ <Stack
404
+ direction="row"
405
+ sx={{
406
+ justifyContent: 'space-between',
407
+ alignItems: 'center',
408
+ }}>
409
+ <Stack
410
+ direction="row"
411
+ sx={{
412
+ alignItems: 'center',
413
+ flexWrap: 'wrap',
414
+ gap: 1,
415
+ }}>
357
416
  <SubscriptionDescription subscription={data} variant="h1" />
358
417
  </Stack>
359
418
  </Stack>
360
419
  <Stack
361
420
  className="section-body"
362
- justifyContent="flex-start"
363
- flexWrap="wrap"
364
421
  sx={{
422
+ justifyContent: 'flex-start',
423
+ flexWrap: 'wrap',
424
+
365
425
  'hr.MuiDivider-root:last-child': {
366
426
  display: 'none',
367
427
  },
428
+
368
429
  flexDirection: {
369
430
  xs: 'column',
370
431
  sm: 'column',
371
432
  md: 'row',
372
433
  },
434
+
373
435
  alignItems: 'flex-start',
436
+
374
437
  gap: {
375
438
  xs: 1,
376
439
  sm: 1,
@@ -381,7 +444,12 @@ export default function CustomerSubscriptionDetail() {
381
444
  {showOverdraftProtection && (
382
445
  <InfoMetric
383
446
  label={
384
- <Stack direction="row" alignItems="center" spacing={0.5}>
447
+ <Stack
448
+ direction="row"
449
+ spacing={0.5}
450
+ sx={{
451
+ alignItems: 'center',
452
+ }}>
385
453
  <Typography component="span">{t('customer.overdraftProtection.title')}</Typography>
386
454
  <MuiLink
387
455
  href="https://www.arcblock.io/content/blog/en/payment-kit-v117-sub-guard#listen-to-the-audio-overview"
@@ -435,12 +503,28 @@ export default function CustomerSubscriptionDetail() {
435
503
  value={renderOverdraftProtectionLabel()}
436
504
  />
437
505
  )}
506
+ {isCredit && hasPendingAmount && (
507
+ <InfoMetric
508
+ label={t('admin.customer.creditGrants.pendingAmount')}
509
+ value={
510
+ <Typography
511
+ sx={{
512
+ color: 'error.main',
513
+ }}>{`${formatBNStr(pendingAmount, data?.paymentCurrency?.decimal)} ${data?.paymentCurrency?.symbol}`}</Typography>
514
+ }
515
+ />
516
+ )}
438
517
  </Stack>
439
518
  </Box>
440
519
  </Box>
441
520
  <Divider />
442
521
  <Box className="section" sx={{ containerType: 'inline-size' }}>
443
- <Typography variant="h3" mb={3} className="section-header">
522
+ <Typography
523
+ variant="h3"
524
+ className="section-header"
525
+ sx={{
526
+ mb: 3,
527
+ }}>
444
528
  {t('admin.details')}
445
529
  </Typography>
446
530
  <InfoRowGroup
@@ -568,7 +652,12 @@ export default function CustomerSubscriptionDetail() {
568
652
  </Box>
569
653
  <Divider />
570
654
  <Box className="section">
571
- <Typography variant="h3" mb={1.5} className="section-header">
655
+ <Typography
656
+ variant="h3"
657
+ className="section-header"
658
+ sx={{
659
+ mb: 1.5,
660
+ }}>
572
661
  {t('admin.products')}
573
662
  </Typography>
574
663
  <Box className="section-body">
@@ -576,19 +665,30 @@ export default function CustomerSubscriptionDetail() {
576
665
  </Box>
577
666
  </Box>
578
667
  <Divider />
579
- <Box className="section">
580
- <Typography variant="h3" className="section-header">
581
- {t('customer.invoiceHistory')}
582
- </Typography>
583
- <Box className="section-body">
584
- <CustomerInvoiceList
585
- subscription_id={data.id}
586
- type="table"
587
- include_staking
588
- status="open,paid,uncollectible,void"
589
- />
668
+ {isCredit ? (
669
+ <Box className="section">
670
+ <Typography variant="h3" className="section-header">
671
+ {t('admin.creditTransactions.title')}
672
+ </Typography>
673
+ <Box className="section-body">
674
+ <CreditTransactionsList customer_id={data.customer_id} subscription_id={data.id} showAdminColumns={false} />
675
+ </Box>
590
676
  </Box>
591
- </Box>
677
+ ) : (
678
+ <Box className="section">
679
+ <Typography variant="h3" className="section-header">
680
+ {t('customer.invoiceHistory')}
681
+ </Typography>
682
+ <Box className="section-body">
683
+ <CustomerInvoiceList
684
+ subscription_id={data.id}
685
+ type="table"
686
+ include_staking
687
+ status="open,paid,uncollectible,void"
688
+ />
689
+ </Box>
690
+ </Box>
691
+ )}
592
692
  </Root>
593
693
  );
594
694
  }
@@ -60,7 +60,7 @@ const fetchSubscriptionData = (id: string, authToken: string): Promise<TSubscrip
60
60
  throw new Error('Subscription ID is missing');
61
61
  }
62
62
 
63
- return api.get(`/api/subscriptions/${id}?authToken=${authToken}`).then((res) => res.data);
63
+ return api.get(`/api/subscriptions/${id}?authToken=${authToken}`).then((res: any) => res.data);
64
64
  };
65
65
 
66
66
  const checkHasPastDue = async (subscriptionId: string, authToken: string): Promise<boolean> => {
@@ -153,7 +153,11 @@ export default function SubscriptionEmbed() {
153
153
  {
154
154
  name: t('payment.customer.subscriptions.plan'),
155
155
  value: (
156
- <Typography fontWeight={600} sx={{ marginRight: '10px' }}>
156
+ <Typography
157
+ sx={{
158
+ fontWeight: 600,
159
+ marginRight: '10px',
160
+ }}>
157
161
  {formatSubscriptionProduct(subscription.items)}
158
162
  </Typography>
159
163
  ),
@@ -278,12 +282,22 @@ export default function SubscriptionEmbed() {
278
282
  <Box sx={{ flex: 1, overflow: 'hidden' }}>
279
283
  <List sx={{ height: '100%', display: 'flex', flexDirection: 'column' }} className="mini-invoice-list">
280
284
  <ListSubheader disableGutters sx={{ padding: 0 }}>
281
- <Typography component="h2" variant="h6" fontSize="16px">
285
+ <Typography
286
+ component="h2"
287
+ variant="h6"
288
+ sx={{
289
+ fontSize: '16px',
290
+ }}>
282
291
  {t('payment.customer.invoices')}
283
292
  </Typography>
284
293
  </ListSubheader>
285
294
  {(invoices as any).length === 0 ? (
286
- <Typography color="text.lighter">{t('payment.customer.invoice.empty')}</Typography>
295
+ <Typography
296
+ sx={{
297
+ color: 'text.lighter',
298
+ }}>
299
+ {t('payment.customer.invoice.empty')}
300
+ </Typography>
287
301
  ) : (
288
302
  <Box sx={{ flex: 1, overflow: 'auto' }}>
289
303
  {(invoices as any).map((item: any) => {
@@ -309,7 +323,13 @@ export default function SubscriptionEmbed() {
309
323
  )}
310
324
  </List>
311
325
  </Box>
312
- <Stack direction="row" justifyContent="center" spacing={2} sx={{ mt: 2 }}>
326
+ <Stack
327
+ direction="row"
328
+ spacing={2}
329
+ sx={{
330
+ justifyContent: 'center',
331
+ mt: 2,
332
+ }}>
313
333
  {subscription.service_actions
314
334
  ?.filter((x: any) => x?.type !== 'notification')
315
335
  ?.map((x) => (
@@ -15,17 +15,39 @@ function Home() {
15
15
  hideNavMenu={undefined}
16
16
  maxWidth={false}
17
17
  />
18
- <Stack alignItems="center" justifyContent="center" sx={{ height: '60vh', width: '100vw' }}>
19
- <Stack maxWidth="sm" direction="column" alignItems="center" spacing={3}>
18
+ <Stack
19
+ sx={{
20
+ alignItems: 'center',
21
+ justifyContent: 'center',
22
+ height: '60vh',
23
+ width: '100vw',
24
+ }}>
25
+ <Stack
26
+ direction="column"
27
+ spacing={3}
28
+ sx={{
29
+ maxWidth: 'sm',
30
+ alignItems: 'center',
31
+ }}>
20
32
  <Avatar
21
33
  src={window.blocklet.appLogo}
22
34
  sx={{ width: 80, height: 80 }}
23
35
  variant="square"
24
36
  alt={window.blocklet.appName || 'Payment Kit'}
25
37
  />
26
- <Stack direction="column" alignItems="center" spacing={1}>
38
+ <Stack
39
+ direction="column"
40
+ spacing={1}
41
+ sx={{
42
+ alignItems: 'center',
43
+ }}>
27
44
  <Typography variant="h4">Payment Kit</Typography>
28
- <Typography variant="h5" color="text.secondary" fontWeight="normal">
45
+ <Typography
46
+ variant="h5"
47
+ sx={{
48
+ color: 'text.secondary',
49
+ fontWeight: 'normal',
50
+ }}>
29
51
  <Typewriter
30
52
  options={{
31
53
  strings: ['The decentralized stripe alike payment solution for blocklets'],
@@ -157,11 +157,12 @@ export default function EditDonationForm({
157
157
  minHeight: 0,
158
158
  }}>
159
159
  <Grid
160
- item
161
- xs={12}
162
- md={6}
163
160
  sx={{
164
161
  height: '100%',
162
+ }}
163
+ size={{
164
+ xs: 12,
165
+ md: 6,
165
166
  }}>
166
167
  <Paper
167
168
  elevation={0}
@@ -173,7 +174,13 @@ export default function EditDonationForm({
173
174
  }}>
174
175
  <Stack spacing={4}>
175
176
  <Box>
176
- <Typography variant="h6" gutterBottom color="text.primary" sx={{ mb: 3 }}>
177
+ <Typography
178
+ variant="h6"
179
+ gutterBottom
180
+ sx={{
181
+ color: 'text.primary',
182
+ mb: 3,
183
+ }}>
177
184
  {t('admin.donate.buttonSettings')}
178
185
  </Typography>
179
186
  <Stack spacing={3}>
@@ -190,7 +197,10 @@ export default function EditDonationForm({
190
197
  )}
191
198
  />
192
199
 
193
- <Stack gap={1}>
200
+ <Stack
201
+ sx={{
202
+ gap: 1,
203
+ }}>
194
204
  <Typography variant="subtitle2" gutterBottom>
195
205
  {t('admin.donate.historyType.title')}
196
206
  </Typography>
@@ -219,7 +229,13 @@ export default function EditDonationForm({
219
229
  <Divider />
220
230
 
221
231
  <Box>
222
- <Typography variant="h6" gutterBottom color="text.primary" sx={{ mb: 3 }}>
232
+ <Typography
233
+ variant="h6"
234
+ gutterBottom
235
+ sx={{
236
+ color: 'text.primary',
237
+ mb: 3,
238
+ }}>
223
239
  {t('admin.donate.amountSettings')}
224
240
  </Typography>
225
241
  <Stack spacing={3}>
@@ -297,11 +313,12 @@ export default function EditDonationForm({
297
313
  </Grid>
298
314
 
299
315
  <Grid
300
- item
301
- md={6}
302
316
  sx={{
303
317
  display: { xs: 'none', md: 'block' },
304
318
  height: '100%',
319
+ }}
320
+ size={{
321
+ md: 6,
305
322
  }}>
306
323
  <Paper
307
324
  elevation={0}
@@ -317,7 +334,6 @@ export default function EditDonationForm({
317
334
  </Grid>
318
335
  </FormProvider>
319
336
  </Box>
320
-
321
337
  <Box
322
338
  sx={{
323
339
  mt: 2,