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.
- package/.eslintrc.js +6 -0
- package/api/src/crons/index.ts +8 -0
- package/api/src/index.ts +4 -0
- package/api/src/libs/credit-grant.ts +146 -0
- package/api/src/libs/env.ts +1 -0
- package/api/src/libs/invoice.ts +4 -3
- package/api/src/libs/notification/template/base.ts +388 -2
- package/api/src/libs/notification/template/customer-credit-grant-granted.ts +149 -0
- package/api/src/libs/notification/template/customer-credit-grant-low-balance.ts +151 -0
- package/api/src/libs/notification/template/customer-credit-insufficient.ts +254 -0
- package/api/src/libs/notification/template/subscription-canceled.ts +193 -202
- package/api/src/libs/notification/template/subscription-refund-succeeded.ts +215 -237
- package/api/src/libs/notification/template/subscription-renewed.ts +130 -200
- package/api/src/libs/notification/template/subscription-succeeded.ts +100 -202
- package/api/src/libs/notification/template/subscription-trial-start.ts +142 -188
- package/api/src/libs/notification/template/subscription-trial-will-end.ts +146 -174
- package/api/src/libs/notification/template/subscription-upgraded.ts +96 -192
- package/api/src/libs/notification/template/subscription-will-canceled.ts +94 -135
- package/api/src/libs/notification/template/subscription-will-renew.ts +220 -245
- package/api/src/libs/payment.ts +69 -0
- package/api/src/libs/queue/index.ts +3 -2
- package/api/src/libs/session.ts +8 -0
- package/api/src/libs/subscription.ts +74 -3
- package/api/src/libs/ws.ts +23 -1
- package/api/src/locales/en.ts +33 -0
- package/api/src/locales/zh.ts +31 -0
- package/api/src/queues/credit-consume.ts +715 -0
- package/api/src/queues/credit-grant.ts +572 -0
- package/api/src/queues/notification.ts +173 -128
- package/api/src/queues/payment.ts +210 -122
- package/api/src/queues/subscription.ts +179 -0
- package/api/src/routes/checkout-sessions.ts +157 -9
- package/api/src/routes/connect/shared.ts +3 -2
- package/api/src/routes/credit-grants.ts +241 -0
- package/api/src/routes/credit-transactions.ts +208 -0
- package/api/src/routes/index.ts +8 -0
- package/api/src/routes/meter-events.ts +347 -0
- package/api/src/routes/meters.ts +219 -0
- package/api/src/routes/payment-currencies.ts +14 -2
- package/api/src/routes/payment-links.ts +1 -1
- package/api/src/routes/payment-methods.ts +14 -2
- package/api/src/routes/prices.ts +43 -0
- package/api/src/routes/pricing-table.ts +13 -7
- package/api/src/routes/products.ts +63 -4
- package/api/src/routes/settings.ts +1 -1
- package/api/src/routes/subscriptions.ts +4 -0
- package/api/src/store/migrations/20250610-billing-credit.ts +43 -0
- package/api/src/store/models/credit-grant.ts +486 -0
- package/api/src/store/models/credit-transaction.ts +268 -0
- package/api/src/store/models/customer.ts +8 -0
- package/api/src/store/models/index.ts +52 -1
- package/api/src/store/models/meter-event.ts +423 -0
- package/api/src/store/models/meter.ts +176 -0
- package/api/src/store/models/payment-currency.ts +66 -14
- package/api/src/store/models/price.ts +6 -0
- package/api/src/store/models/product.ts +2 -2
- package/api/src/store/models/subscription.ts +24 -0
- package/api/src/store/models/types.ts +28 -2
- package/api/tests/libs/subscription.spec.ts +53 -0
- package/blocklet.yml +9 -1
- package/package.json +57 -58
- package/scripts/sdk.js +233 -1
- package/src/app.tsx +10 -0
- package/src/components/actions.tsx +22 -9
- package/src/components/balance-list.tsx +40 -12
- package/src/components/collapse.tsx +33 -15
- package/src/components/copyable.tsx +8 -7
- package/src/components/currency.tsx +15 -7
- package/src/components/customer/actions.tsx +1 -5
- package/src/components/customer/credit-grant-item-list.tsx +99 -0
- package/src/components/customer/credit-overview.tsx +233 -0
- package/src/components/customer/form.tsx +7 -2
- package/src/components/customer/link.tsx +4 -12
- package/src/components/customer/notification-preference.tsx +18 -9
- package/src/components/customer/overdraft-protection.tsx +112 -41
- package/src/components/drawer-form.tsx +42 -18
- package/src/components/error.tsx +1 -5
- package/src/components/event/list.tsx +9 -10
- package/src/components/filter-toolbar.tsx +20 -19
- package/src/components/info-card.tsx +32 -18
- package/src/components/info-metric.tsx +16 -6
- package/src/components/info-row-group.tsx +1 -7
- package/src/components/info-row.tsx +30 -24
- package/src/components/invoice/action.tsx +1 -7
- package/src/components/invoice/list.tsx +34 -26
- package/src/components/invoice/recharge.tsx +5 -7
- package/src/components/invoice/table.tsx +17 -12
- package/src/components/layout/user.tsx +1 -1
- package/src/components/metadata/form.tsx +290 -94
- package/src/components/metadata/list.tsx +11 -3
- package/src/components/meter/actions.tsx +101 -0
- package/src/components/meter/add-usage-dialog.tsx +239 -0
- package/src/components/meter/events-list.tsx +657 -0
- package/src/components/meter/form.tsx +245 -0
- package/src/components/meter/products.tsx +264 -0
- package/src/components/meter/usage-guide.tsx +174 -0
- package/src/components/passport/actions.tsx +9 -4
- package/src/components/payment-currency/add.tsx +16 -3
- package/src/components/payment-currency/form.tsx +14 -6
- package/src/components/payment-intent/actions.tsx +24 -16
- package/src/components/payment-intent/list.tsx +30 -9
- package/src/components/payment-link/actions.tsx +1 -5
- package/src/components/payment-link/after-pay.tsx +4 -2
- package/src/components/payment-link/before-pay.tsx +14 -4
- package/src/components/payment-link/item.tsx +27 -6
- package/src/components/payment-link/preview.tsx +9 -9
- package/src/components/payment-link/product-select.tsx +69 -15
- package/src/components/payment-method/arcblock.tsx +8 -1
- package/src/components/payment-method/base.tsx +8 -1
- package/src/components/payment-method/bitcoin.tsx +8 -1
- package/src/components/payment-method/ethereum.tsx +8 -1
- package/src/components/payment-method/evm-rpc-input.tsx +11 -7
- package/src/components/payment-method/form.tsx +2 -7
- package/src/components/payment-method/stripe.tsx +2 -0
- package/src/components/payouts/actions.tsx +1 -5
- package/src/components/payouts/list.tsx +30 -10
- package/src/components/payouts/portal/list.tsx +11 -9
- package/src/components/price/currency-select.tsx +63 -32
- package/src/components/price/form.tsx +895 -370
- package/src/components/price/upsell-select.tsx +10 -2
- package/src/components/price/upsell.tsx +7 -2
- package/src/components/pricing-table/actions.tsx +1 -5
- package/src/components/pricing-table/customer-settings.tsx +5 -1
- package/src/components/pricing-table/payment-settings.tsx +14 -4
- package/src/components/pricing-table/preview.tsx +9 -9
- package/src/components/pricing-table/price-item.tsx +6 -1
- package/src/components/pricing-table/product-item.tsx +6 -1
- package/src/components/pricing-table/product-settings.tsx +17 -4
- package/src/components/product/actions.tsx +1 -5
- package/src/components/product/add-price.tsx +9 -7
- package/src/components/product/create.tsx +8 -9
- package/src/components/product/cross-sell-select.tsx +5 -1
- package/src/components/product/cross-sell.tsx +7 -2
- package/src/components/product/edit-price.tsx +21 -12
- package/src/components/product/features.tsx +26 -6
- package/src/components/product/form.tsx +115 -72
- package/src/components/progress-bar.tsx +1 -1
- package/src/components/refund/actions.tsx +1 -7
- package/src/components/refund/list.tsx +31 -18
- package/src/components/section/header.tsx +12 -14
- package/src/components/subscription/actions/cancel.tsx +22 -5
- package/src/components/subscription/actions/index.tsx +9 -10
- package/src/components/subscription/actions/pause.tsx +32 -6
- package/src/components/subscription/actions/slash-stake.tsx +5 -3
- package/src/components/subscription/description.tsx +12 -8
- package/src/components/subscription/items/index.tsx +31 -16
- package/src/components/subscription/items/usage-records.tsx +19 -5
- package/src/components/subscription/list.tsx +5 -7
- package/src/components/subscription/metrics.tsx +62 -15
- package/src/components/subscription/portal/actions.tsx +78 -71
- package/src/components/subscription/portal/cancel.tsx +10 -3
- package/src/components/subscription/portal/list.tsx +48 -26
- package/src/components/uploader.tsx +5 -13
- package/src/components/webhook/attempts.tsx +51 -16
- package/src/components/webhook/request-info.tsx +8 -6
- package/src/contexts/products.tsx +27 -10
- package/src/hooks/subscription.ts +34 -0
- package/src/libs/meter-utils.ts +196 -0
- package/src/libs/util.ts +4 -0
- package/src/locales/en.tsx +385 -4
- package/src/locales/zh.tsx +364 -0
- package/src/pages/admin/billing/index.tsx +61 -33
- package/src/pages/admin/billing/invoices/detail.tsx +49 -13
- package/src/pages/admin/billing/meters/create.tsx +60 -0
- package/src/pages/admin/billing/meters/detail.tsx +435 -0
- package/src/pages/admin/billing/meters/index.tsx +210 -0
- package/src/pages/admin/billing/meters/meter-event.tsx +346 -0
- package/src/pages/admin/billing/subscriptions/detail.tsx +90 -25
- package/src/pages/admin/customers/customers/credit-grant/detail.tsx +391 -0
- package/src/pages/admin/customers/customers/detail.tsx +67 -14
- package/src/pages/admin/customers/customers/index.tsx +6 -1
- package/src/pages/admin/customers/index.tsx +5 -0
- package/src/pages/admin/developers/events/detail.tsx +37 -11
- package/src/pages/admin/developers/index.tsx +1 -1
- package/src/pages/admin/developers/webhooks/detail.tsx +41 -11
- package/src/pages/admin/index.tsx +15 -2
- package/src/pages/admin/overview.tsx +107 -19
- package/src/pages/admin/payments/intents/detail.tsx +58 -14
- package/src/pages/admin/payments/payouts/detail.tsx +63 -15
- package/src/pages/admin/payments/refunds/detail.tsx +58 -14
- package/src/pages/admin/products/index.tsx +11 -4
- package/src/pages/admin/products/links/create.tsx +22 -4
- package/src/pages/admin/products/links/detail.tsx +43 -14
- package/src/pages/admin/products/passports/index.tsx +23 -4
- package/src/pages/admin/products/prices/actions.tsx +16 -9
- package/src/pages/admin/products/prices/detail.tsx +73 -14
- package/src/pages/admin/products/prices/list.tsx +15 -3
- package/src/pages/admin/products/pricing-tables/create.tsx +45 -12
- package/src/pages/admin/products/pricing-tables/detail.tsx +45 -14
- package/src/pages/admin/products/products/create.tsx +233 -54
- package/src/pages/admin/products/products/detail.tsx +74 -18
- package/src/pages/admin/settings/index.tsx +8 -1
- package/src/pages/admin/settings/payment-methods/index.tsx +87 -19
- package/src/pages/admin/settings/vault-config/edit-form.tsx +42 -28
- package/src/pages/admin/settings/vault-config/index.tsx +57 -10
- package/src/pages/customer/credit-grant/detail.tsx +308 -0
- package/src/pages/customer/index.tsx +76 -17
- package/src/pages/customer/invoice/detail.tsx +63 -14
- package/src/pages/customer/invoice/past-due.tsx +11 -3
- package/src/pages/customer/payout/detail.tsx +56 -13
- package/src/pages/customer/recharge/account.tsx +78 -18
- package/src/pages/customer/recharge/subscription.tsx +86 -25
- package/src/pages/customer/refund/list.tsx +60 -24
- package/src/pages/customer/subscription/change-payment.tsx +17 -6
- package/src/pages/customer/subscription/change-plan.tsx +34 -7
- package/src/pages/customer/subscription/detail.tsx +134 -34
- package/src/pages/customer/subscription/embed.tsx +25 -5
- package/src/pages/home.tsx +26 -4
- package/src/pages/integrations/donations/edit-form.tsx +25 -9
- package/src/pages/integrations/donations/index.tsx +26 -9
- package/src/pages/integrations/donations/preview.tsx +59 -15
- package/src/pages/integrations/index.tsx +10 -1
- package/src/pages/integrations/overview.tsx +78 -17
- package/vite.config.ts +60 -30
|
@@ -11,11 +11,14 @@ type Props = {
|
|
|
11
11
|
variant?: string;
|
|
12
12
|
};
|
|
13
13
|
|
|
14
|
-
PassportActions
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
export default function PassportActions(rawProps: Props) {
|
|
15
|
+
const props = Object.assign(
|
|
16
|
+
{
|
|
17
|
+
variant: 'compact',
|
|
18
|
+
},
|
|
19
|
+
rawProps
|
|
20
|
+
);
|
|
17
21
|
|
|
18
|
-
export default function PassportActions(props: Props) {
|
|
19
22
|
const { t } = useLocaleContext();
|
|
20
23
|
|
|
21
24
|
const [state, setState] = useSetState({
|
|
@@ -26,6 +29,7 @@ export default function PassportActions(props: Props) {
|
|
|
26
29
|
const onUnassign = async () => {
|
|
27
30
|
try {
|
|
28
31
|
setState({ loading: true });
|
|
32
|
+
// eslint-disable-next-line react/prop-types
|
|
29
33
|
await api.delete(`/api/passports/assign/${props.data.name}`).then((res) => res.data);
|
|
30
34
|
Toast.success(t('common.saved'));
|
|
31
35
|
} catch (err) {
|
|
@@ -46,6 +50,7 @@ export default function PassportActions(props: Props) {
|
|
|
46
50
|
|
|
47
51
|
return (
|
|
48
52
|
<ClickBoundary>
|
|
53
|
+
{/* eslint-disable-next-line react/prop-types */}
|
|
49
54
|
<Actions variant={props.variant} actions={actions} />
|
|
50
55
|
{state.action === 'unassign' && (
|
|
51
56
|
<ConfirmDialog
|
|
@@ -179,8 +179,17 @@ export default function PaymentCurrencyAdd({
|
|
|
179
179
|
}}
|
|
180
180
|
/>
|
|
181
181
|
<Stack>
|
|
182
|
-
<Typography
|
|
183
|
-
|
|
182
|
+
<Typography
|
|
183
|
+
sx={{
|
|
184
|
+
fontWeight: 500,
|
|
185
|
+
}}>
|
|
186
|
+
{option.name}
|
|
187
|
+
</Typography>
|
|
188
|
+
<Typography
|
|
189
|
+
variant="caption"
|
|
190
|
+
sx={{
|
|
191
|
+
color: 'text.secondary',
|
|
192
|
+
}}>
|
|
184
193
|
{option.symbol}
|
|
185
194
|
</Typography>
|
|
186
195
|
</Stack>
|
|
@@ -189,7 +198,11 @@ export default function PaymentCurrencyAdd({
|
|
|
189
198
|
isOptionEqualToValue={(option, value) => option.address === value.address}
|
|
190
199
|
/>
|
|
191
200
|
<Divider sx={{ my: 3 }}>
|
|
192
|
-
<Typography
|
|
201
|
+
<Typography
|
|
202
|
+
variant="caption"
|
|
203
|
+
sx={{
|
|
204
|
+
color: 'text.secondary',
|
|
205
|
+
}}>
|
|
193
206
|
{t('admin.paymentCurrency.orManualInput')}
|
|
194
207
|
</Typography>
|
|
195
208
|
</Divider>
|
|
@@ -10,10 +10,6 @@ type TPaymentCurrencyFormProps = {
|
|
|
10
10
|
disableKeys?: string[];
|
|
11
11
|
};
|
|
12
12
|
|
|
13
|
-
PaymentCurrencyForm.defaultProps = {
|
|
14
|
-
disableKeys: [],
|
|
15
|
-
};
|
|
16
|
-
|
|
17
13
|
export default function PaymentCurrencyForm({ disableKeys = [] }: TPaymentCurrencyFormProps) {
|
|
18
14
|
const { t } = useLocaleContext();
|
|
19
15
|
const { control, setValue } = useFormContext();
|
|
@@ -29,7 +25,12 @@ export default function PaymentCurrencyForm({ disableKeys = [] }: TPaymentCurren
|
|
|
29
25
|
};
|
|
30
26
|
|
|
31
27
|
return (
|
|
32
|
-
<Stack
|
|
28
|
+
<Stack
|
|
29
|
+
direction="column"
|
|
30
|
+
spacing={2}
|
|
31
|
+
sx={{
|
|
32
|
+
alignItems: 'flex-start',
|
|
33
|
+
}}>
|
|
33
34
|
<FormInput
|
|
34
35
|
key="name"
|
|
35
36
|
name="name"
|
|
@@ -38,6 +39,7 @@ export default function PaymentCurrencyForm({ disableKeys = [] }: TPaymentCurren
|
|
|
38
39
|
label={t('admin.paymentMethod.name.label')}
|
|
39
40
|
placeholder={t('admin.paymentMethod.name.tip')}
|
|
40
41
|
disabled={disableKeys.includes('name')}
|
|
42
|
+
inputProps={{ maxLength: 32 }}
|
|
41
43
|
/>
|
|
42
44
|
<FormInput
|
|
43
45
|
key="description"
|
|
@@ -47,6 +49,7 @@ export default function PaymentCurrencyForm({ disableKeys = [] }: TPaymentCurren
|
|
|
47
49
|
label={t('admin.paymentMethod.description.label')}
|
|
48
50
|
placeholder={t('admin.paymentMethod.description.tip')}
|
|
49
51
|
disabled={disableKeys.includes('description')}
|
|
52
|
+
inputProps={{ maxLength: 255 }}
|
|
50
53
|
/>
|
|
51
54
|
<FormInput
|
|
52
55
|
key="contract"
|
|
@@ -58,7 +61,12 @@ export default function PaymentCurrencyForm({ disableKeys = [] }: TPaymentCurren
|
|
|
58
61
|
disabled={disableKeys.includes('contract')}
|
|
59
62
|
/>
|
|
60
63
|
<Stack direction="column">
|
|
61
|
-
<Typography
|
|
64
|
+
<Typography
|
|
65
|
+
sx={{
|
|
66
|
+
mb: 1,
|
|
67
|
+
}}>
|
|
68
|
+
{t('admin.paymentCurrency.logo.label')}
|
|
69
|
+
</Typography>
|
|
62
70
|
<Uploader onUploaded={onUploaded} preview={logo} />
|
|
63
71
|
</Stack>
|
|
64
72
|
</Stack>
|
|
@@ -27,13 +27,6 @@ type Props = {
|
|
|
27
27
|
onChange: (action: string) => void;
|
|
28
28
|
};
|
|
29
29
|
|
|
30
|
-
PaymentIntentActionsInner.defaultProps = {
|
|
31
|
-
variant: 'compact',
|
|
32
|
-
};
|
|
33
|
-
PaymentIntentActions.defaultProps = {
|
|
34
|
-
variant: 'compact',
|
|
35
|
-
};
|
|
36
|
-
|
|
37
30
|
const fetchRefundData = (id: string) => {
|
|
38
31
|
return api.get(`/api/payment-intents/${id}/refundable-amount`).then((res) => res.data);
|
|
39
32
|
};
|
|
@@ -64,7 +57,13 @@ function RefundForm({ data, refundMaxAmount }: { data: TPaymentIntentExpanded; r
|
|
|
64
57
|
return true;
|
|
65
58
|
};
|
|
66
59
|
return (
|
|
67
|
-
<Stack
|
|
60
|
+
<Stack
|
|
61
|
+
direction="column"
|
|
62
|
+
spacing={1}
|
|
63
|
+
sx={{
|
|
64
|
+
alignItems: 'flex-start',
|
|
65
|
+
width: 400,
|
|
66
|
+
}}>
|
|
68
67
|
<Controller
|
|
69
68
|
name="refund.reason"
|
|
70
69
|
control={control}
|
|
@@ -103,7 +102,6 @@ function RefundForm({ data, refundMaxAmount }: { data: TPaymentIntentExpanded; r
|
|
|
103
102
|
</RadioGroup>
|
|
104
103
|
)}
|
|
105
104
|
/>
|
|
106
|
-
|
|
107
105
|
<FormControl fullWidth component="fieldset" variant="outlined">
|
|
108
106
|
<Controller
|
|
109
107
|
name="refund.amount"
|
|
@@ -121,8 +119,10 @@ function RefundForm({ data, refundMaxAmount }: { data: TPaymentIntentExpanded; r
|
|
|
121
119
|
placeholder={t('admin.paymentIntent.refundForm.amount')}
|
|
122
120
|
error={!!(errors as any)?.refund?.amount}
|
|
123
121
|
helperText={(errors as any)?.refund?.amount?.message}
|
|
124
|
-
|
|
125
|
-
|
|
122
|
+
slotProps={{
|
|
123
|
+
input: {
|
|
124
|
+
endAdornment: <InputAdornment position="end">{data.paymentCurrency.symbol}</InputAdornment>,
|
|
125
|
+
},
|
|
126
126
|
}}
|
|
127
127
|
/>
|
|
128
128
|
)}
|
|
@@ -135,7 +135,6 @@ function RefundForm({ data, refundMaxAmount }: { data: TPaymentIntentExpanded; r
|
|
|
135
135
|
})}
|
|
136
136
|
</FormHelperText>
|
|
137
137
|
</FormControl>
|
|
138
|
-
|
|
139
138
|
<Controller
|
|
140
139
|
name="refund.description"
|
|
141
140
|
control={control}
|
|
@@ -155,8 +154,10 @@ function RefundForm({ data, refundMaxAmount }: { data: TPaymentIntentExpanded; r
|
|
|
155
154
|
placeholder={t('admin.paymentIntent.refundForm.description')}
|
|
156
155
|
error={!!(errors as any)?.refund?.description}
|
|
157
156
|
helperText={(errors as any)?.refund?.description?.message}
|
|
158
|
-
|
|
159
|
-
|
|
157
|
+
slotProps={{
|
|
158
|
+
htmlInput: {
|
|
159
|
+
maxLength: 200,
|
|
160
|
+
},
|
|
160
161
|
}}
|
|
161
162
|
/>
|
|
162
163
|
)}
|
|
@@ -165,7 +166,7 @@ function RefundForm({ data, refundMaxAmount }: { data: TPaymentIntentExpanded; r
|
|
|
165
166
|
);
|
|
166
167
|
}
|
|
167
168
|
|
|
168
|
-
export function PaymentIntentActionsInner({ data, variant, onChange }: Props) {
|
|
169
|
+
export function PaymentIntentActionsInner({ data, variant = 'compact', onChange }: Props) {
|
|
169
170
|
const { t } = useLocaleContext();
|
|
170
171
|
const navigate = useNavigate();
|
|
171
172
|
const { reset, getValues, setValue, handleSubmit } = useFormContext();
|
|
@@ -262,7 +263,14 @@ export function PaymentIntentActionsInner({ data, variant, onChange }: Props) {
|
|
|
262
263
|
);
|
|
263
264
|
}
|
|
264
265
|
|
|
265
|
-
export default function PaymentIntentActions(
|
|
266
|
+
export default function PaymentIntentActions(rawProps: Props) {
|
|
267
|
+
const props = Object.assign(
|
|
268
|
+
{
|
|
269
|
+
variant: 'compact',
|
|
270
|
+
},
|
|
271
|
+
rawProps
|
|
272
|
+
);
|
|
273
|
+
|
|
266
274
|
const methods = useForm({
|
|
267
275
|
mode: 'onChange',
|
|
268
276
|
defaultValues: {
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
useDefaultPageSize,
|
|
11
11
|
} from '@blocklet/payment-react';
|
|
12
12
|
import type { TPaymentIntentExpanded } from '@blocklet/payment-types';
|
|
13
|
-
import { CircularProgress, Typography } from '@mui/material';
|
|
13
|
+
import { Avatar, CircularProgress, Typography } from '@mui/material';
|
|
14
14
|
import { useLocalStorageState } from 'ahooks';
|
|
15
15
|
import { useEffect, useState } from 'react';
|
|
16
16
|
import { Link } from 'react-router-dom';
|
|
@@ -66,16 +66,14 @@ const getListKey = (props: ListProps) => {
|
|
|
66
66
|
return 'payments';
|
|
67
67
|
};
|
|
68
68
|
|
|
69
|
-
|
|
70
|
-
|
|
69
|
+
export default function PaymentList({
|
|
70
|
+
customer_id = '',
|
|
71
|
+
invoice_id = '',
|
|
72
|
+
features = {
|
|
71
73
|
customer: true,
|
|
72
74
|
filter: true,
|
|
73
75
|
},
|
|
74
|
-
|
|
75
|
-
invoice_id: '',
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
export default function PaymentList({ customer_id, invoice_id, features }: ListProps) {
|
|
76
|
+
}: ListProps) {
|
|
79
77
|
const { t } = useLocaleContext();
|
|
80
78
|
|
|
81
79
|
const listKey = getListKey({ customer_id, invoice_id });
|
|
@@ -120,7 +118,12 @@ export default function PaymentList({ customer_id, invoice_id, features }: ListP
|
|
|
120
118
|
const highlight = item.amount_received === '0' && item.status !== 'canceled';
|
|
121
119
|
return (
|
|
122
120
|
<Link to={`/admin/payments/${item.id}`}>
|
|
123
|
-
<Typography
|
|
121
|
+
<Typography
|
|
122
|
+
component="strong"
|
|
123
|
+
sx={{
|
|
124
|
+
fontWeight: 600,
|
|
125
|
+
color: highlight ? 'warning.main' : 'inherit',
|
|
126
|
+
}}>
|
|
124
127
|
{formatBNStr(
|
|
125
128
|
item.amount_received === '0' ? item.amount : item.amount_received,
|
|
126
129
|
item?.paymentCurrency.decimal
|
|
@@ -133,6 +136,24 @@ export default function PaymentList({ customer_id, invoice_id, features }: ListP
|
|
|
133
136
|
},
|
|
134
137
|
},
|
|
135
138
|
},
|
|
139
|
+
{
|
|
140
|
+
label: t('common.paymentMethod'),
|
|
141
|
+
name: 'paymentMethod',
|
|
142
|
+
width: 120,
|
|
143
|
+
options: {
|
|
144
|
+
customBodyRenderLite: (_: string, index: number) => {
|
|
145
|
+
const item = data.list[index] as TPaymentIntentExpanded;
|
|
146
|
+
return (
|
|
147
|
+
<Link to={`/admin/payments/${item.id}`}>
|
|
148
|
+
<Typography sx={{ display: 'flex', alignItems: 'center', whiteSpace: 'nowrap' }}>
|
|
149
|
+
<Avatar src={item.paymentMethod.logo} sx={{ width: 18, height: 18, mr: 1 }} />
|
|
150
|
+
{item.paymentMethod.name}
|
|
151
|
+
</Typography>
|
|
152
|
+
</Link>
|
|
153
|
+
);
|
|
154
|
+
},
|
|
155
|
+
},
|
|
156
|
+
},
|
|
136
157
|
{
|
|
137
158
|
label: t('common.status'),
|
|
138
159
|
name: 'status',
|
|
@@ -18,11 +18,7 @@ type Props = {
|
|
|
18
18
|
variant?: LiteralUnion<'compact' | 'normal', string>;
|
|
19
19
|
};
|
|
20
20
|
|
|
21
|
-
PaymentLinkActions
|
|
22
|
-
variant: 'compact',
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
export default function PaymentLinkActions({ data, variant, onChange }: Props) {
|
|
21
|
+
export default function PaymentLinkActions({ data, variant = 'compact', onChange }: Props) {
|
|
26
22
|
const { t } = useLocaleContext();
|
|
27
23
|
const [state, setState] = useSetState({
|
|
28
24
|
action: '',
|
|
@@ -16,7 +16,7 @@ import ProductSelect from './product-select';
|
|
|
16
16
|
export default function BeforePay({
|
|
17
17
|
triggerError = () => {},
|
|
18
18
|
}: {
|
|
19
|
-
triggerError
|
|
19
|
+
triggerError?: (keys: { [key: string]: boolean }) => void;
|
|
20
20
|
}) {
|
|
21
21
|
const { t } = useLocaleContext();
|
|
22
22
|
const [params, setParams] = useSearchParams();
|
|
@@ -123,12 +123,20 @@ export default function BeforePay({
|
|
|
123
123
|
);
|
|
124
124
|
})}
|
|
125
125
|
{items.fields.some((_, index) => !isPriceAligned(items.fields as any[], products, index).recurring) && (
|
|
126
|
-
<Typography
|
|
126
|
+
<Typography
|
|
127
|
+
color="error"
|
|
128
|
+
sx={{
|
|
129
|
+
fontSize: 'small',
|
|
130
|
+
}}>
|
|
127
131
|
{t('admin.paymentLink.recurringNotAligned')}
|
|
128
132
|
</Typography>
|
|
129
133
|
)}
|
|
130
134
|
{items.fields.some((_, index) => !isPriceAligned(items.fields as any[], products, index).currency) && (
|
|
131
|
-
<Typography
|
|
135
|
+
<Typography
|
|
136
|
+
color="error"
|
|
137
|
+
sx={{
|
|
138
|
+
fontSize: 'small',
|
|
139
|
+
}}>
|
|
132
140
|
{t('admin.paymentLink.currencyNotAligned')}
|
|
133
141
|
</Typography>
|
|
134
142
|
)}
|
|
@@ -248,9 +256,11 @@ export default function BeforePay({
|
|
|
248
256
|
<TextField
|
|
249
257
|
{...field}
|
|
250
258
|
size="small"
|
|
251
|
-
InputProps={{ endAdornment: t('common.days') }}
|
|
252
259
|
helperText={get(errors, 'subscription_data.trial_period_days')?.message as string}
|
|
253
260
|
error={!!get(errors, 'subscription_data.trial_period_days')}
|
|
261
|
+
slotProps={{
|
|
262
|
+
input: { endAdornment: t('common.days') },
|
|
263
|
+
}}
|
|
254
264
|
/>
|
|
255
265
|
)}
|
|
256
266
|
/>
|
|
@@ -75,7 +75,11 @@ export default function LineItem({ prefix, product, valid, onUpdate, onRemove }:
|
|
|
75
75
|
]}
|
|
76
76
|
/>
|
|
77
77
|
</ClickBoundary>
|
|
78
|
-
<Stack
|
|
78
|
+
<Stack
|
|
79
|
+
direction="column"
|
|
80
|
+
sx={{
|
|
81
|
+
alignItems: 'flex-start',
|
|
82
|
+
}}>
|
|
79
83
|
<InfoCard
|
|
80
84
|
logo={product.images[0]}
|
|
81
85
|
name={product.name}
|
|
@@ -85,10 +89,14 @@ export default function LineItem({ prefix, product, valid, onUpdate, onRemove }:
|
|
|
85
89
|
name={getFieldName('quantity')}
|
|
86
90
|
control={control}
|
|
87
91
|
render={({ field }) => (
|
|
88
|
-
<Stack
|
|
92
|
+
<Stack
|
|
93
|
+
direction="row"
|
|
94
|
+
sx={{
|
|
95
|
+
alignItems: 'center',
|
|
96
|
+
mt: 1,
|
|
97
|
+
}}>
|
|
89
98
|
<TextField
|
|
90
99
|
sx={{ width: 80, mr: 1 }}
|
|
91
|
-
inputProps={{ style: { padding: '4px 8px' } }}
|
|
92
100
|
size="small"
|
|
93
101
|
type="number"
|
|
94
102
|
{...field}
|
|
@@ -98,6 +106,9 @@ export default function LineItem({ prefix, product, valid, onUpdate, onRemove }:
|
|
|
98
106
|
field.onChange(intValue);
|
|
99
107
|
}
|
|
100
108
|
}}
|
|
109
|
+
slotProps={{
|
|
110
|
+
htmlInput: { style: { padding: '4px 8px' } },
|
|
111
|
+
}}
|
|
101
112
|
/>
|
|
102
113
|
<FormLabel style={{ marginBottom: 0 }}>{t('common.quantity')}</FormLabel>
|
|
103
114
|
</Stack>
|
|
@@ -118,7 +129,13 @@ export default function LineItem({ prefix, product, valid, onUpdate, onRemove }:
|
|
|
118
129
|
/>
|
|
119
130
|
{adjustable && (
|
|
120
131
|
<>
|
|
121
|
-
<Stack
|
|
132
|
+
<Stack
|
|
133
|
+
direction="row"
|
|
134
|
+
sx={{
|
|
135
|
+
alignItems: 'center',
|
|
136
|
+
mt: 1,
|
|
137
|
+
ml: 6,
|
|
138
|
+
}}>
|
|
122
139
|
<Typography sx={{ mr: 0.5 }}>Between</Typography>
|
|
123
140
|
<Controller
|
|
124
141
|
name={getFieldName('adjustable_quantity.minimum')}
|
|
@@ -131,10 +148,12 @@ export default function LineItem({ prefix, product, valid, onUpdate, onRemove }:
|
|
|
131
148
|
render={({ field }) => (
|
|
132
149
|
<TextField
|
|
133
150
|
sx={{ width: 40 }}
|
|
134
|
-
inputProps={{ style: { padding: '4px 8px' } }}
|
|
135
151
|
size="small"
|
|
136
152
|
error={!!adjustableError}
|
|
137
153
|
{...field}
|
|
154
|
+
slotProps={{
|
|
155
|
+
htmlInput: { style: { padding: '4px 8px' } },
|
|
156
|
+
}}
|
|
138
157
|
/>
|
|
139
158
|
)}
|
|
140
159
|
/>
|
|
@@ -152,10 +171,12 @@ export default function LineItem({ prefix, product, valid, onUpdate, onRemove }:
|
|
|
152
171
|
render={({ field }) => (
|
|
153
172
|
<TextField
|
|
154
173
|
sx={{ width: 40 }}
|
|
155
|
-
inputProps={{ style: { padding: '4px 8px' } }}
|
|
156
174
|
size="small"
|
|
157
175
|
error={!!adjustableError}
|
|
158
176
|
{...field}
|
|
177
|
+
slotProps={{
|
|
178
|
+
htmlInput: { style: { padding: '4px 8px' } },
|
|
179
|
+
}}
|
|
159
180
|
/>
|
|
160
181
|
)}
|
|
161
182
|
/>
|
|
@@ -1,10 +1,16 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useEffect, useImperativeHandle, useRef, useState } from 'react';
|
|
2
2
|
import { useFullscreen, useSize } from 'ahooks';
|
|
3
3
|
import IframeResizer from 'iframe-resizer-react';
|
|
4
4
|
import { useTheme } from '@mui/material';
|
|
5
5
|
import Chrome from './chrome';
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
export default function PaymentLinkPreview({
|
|
8
|
+
ref = undefined,
|
|
9
|
+
id,
|
|
10
|
+
version = 1,
|
|
11
|
+
}: { id: string; version?: number } & {
|
|
12
|
+
ref?: React.RefObject<unknown | null>;
|
|
13
|
+
}) {
|
|
8
14
|
const theme = useTheme();
|
|
9
15
|
const innerRef = useRef(null);
|
|
10
16
|
const size = useSize(innerRef);
|
|
@@ -50,10 +56,4 @@ const PaymentLinkPreview = forwardRef(({ id, version = 1 }: { id: string; versio
|
|
|
50
56
|
)}
|
|
51
57
|
</div>
|
|
52
58
|
);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
PaymentLinkPreview.defaultProps = {
|
|
56
|
-
version: 1,
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
export default PaymentLinkPreview;
|
|
59
|
+
}
|
|
@@ -7,40 +7,75 @@ import cloneDeep from 'lodash/cloneDeep';
|
|
|
7
7
|
import { useState } from 'react';
|
|
8
8
|
import type { LiteralUnion } from 'type-fest';
|
|
9
9
|
|
|
10
|
+
import Empty from '@arcblock/ux/lib/Empty';
|
|
10
11
|
import { useProductsContext } from '../../contexts/products';
|
|
11
12
|
|
|
12
13
|
type Props = {
|
|
13
14
|
mode: LiteralUnion<'waiting' | 'selecting' | 'inline', string>;
|
|
14
15
|
hasSelected: (price: any) => boolean;
|
|
15
16
|
onSelect: (priceId: string) => void;
|
|
17
|
+
addProduct?: boolean;
|
|
18
|
+
filterPrice?: (price: any) => boolean;
|
|
16
19
|
};
|
|
17
20
|
|
|
18
|
-
const filterPrices = (
|
|
19
|
-
product
|
|
21
|
+
const filterPrices = (
|
|
22
|
+
product: TProductExpanded,
|
|
23
|
+
hasSelected: (price: any) => boolean,
|
|
24
|
+
filterPrice?: (price: any) => boolean
|
|
25
|
+
) => {
|
|
26
|
+
product.prices = product.prices.filter((x) => {
|
|
27
|
+
const isActive = x.active;
|
|
28
|
+
const notSelected = !hasSelected(x);
|
|
29
|
+
const customFilter = filterPrice ? filterPrice(x) : true;
|
|
30
|
+
return isActive && notSelected && customFilter;
|
|
31
|
+
});
|
|
20
32
|
return product;
|
|
21
33
|
};
|
|
22
34
|
|
|
23
|
-
const filterProducts = (
|
|
24
|
-
|
|
35
|
+
const filterProducts = (
|
|
36
|
+
products: TProductExpanded[],
|
|
37
|
+
hasSelected: (price: any) => boolean,
|
|
38
|
+
filterPrice?: (price: any) => boolean
|
|
39
|
+
) => {
|
|
40
|
+
const filtered = cloneDeep(products).map((x) => filterPrices(x, hasSelected, filterPrice));
|
|
25
41
|
return filtered.filter((x) => x.prices.length);
|
|
26
42
|
};
|
|
27
43
|
|
|
28
|
-
export default function ProductSelect({
|
|
44
|
+
export default function ProductSelect({
|
|
45
|
+
mode: initialMode,
|
|
46
|
+
hasSelected,
|
|
47
|
+
onSelect,
|
|
48
|
+
addProduct = true,
|
|
49
|
+
filterPrice = () => true,
|
|
50
|
+
}: Props) {
|
|
29
51
|
const { t } = useLocaleContext();
|
|
30
52
|
const [mode, setMode] = useState(initialMode);
|
|
31
53
|
const { products } = useProductsContext();
|
|
32
54
|
const { settings } = usePaymentContext();
|
|
55
|
+
const [value, setValue] = useState('');
|
|
33
56
|
const size = { width: 16, height: 16 };
|
|
34
57
|
|
|
35
58
|
const handleSelect = (e: any) => {
|
|
59
|
+
setValue(e.target.value);
|
|
36
60
|
setMode('waiting');
|
|
37
61
|
onSelect(e.target.value);
|
|
38
62
|
};
|
|
39
63
|
|
|
40
|
-
const items = (callback?: any) =>
|
|
41
|
-
filterProducts(products, hasSelected)
|
|
64
|
+
const items = (callback?: any) => {
|
|
65
|
+
const filteredProducts = filterProducts(products, hasSelected, filterPrice);
|
|
66
|
+
|
|
67
|
+
if (filteredProducts.length === 0) {
|
|
68
|
+
return <Empty>{t('admin.product.empty')}</Empty>;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return filteredProducts.map((product) => [
|
|
42
72
|
<ListSubheader key={product.id} sx={{ fontSize: '0.875rem', color: 'text.secondary', lineHeight: '2.1875rem' }}>
|
|
43
|
-
<Stack
|
|
73
|
+
<Stack
|
|
74
|
+
direction="row"
|
|
75
|
+
spacing={0.5}
|
|
76
|
+
sx={{
|
|
77
|
+
alignItems: 'center',
|
|
78
|
+
}}>
|
|
44
79
|
{product.images[0] ? (
|
|
45
80
|
<Avatar src={product.images[0]} alt={product.name} variant="square" sx={size} />
|
|
46
81
|
) : (
|
|
@@ -65,8 +100,17 @@ export default function ProductSelect({ mode: initialMode, hasSelected, onSelect
|
|
|
65
100
|
callback(price);
|
|
66
101
|
}
|
|
67
102
|
}}>
|
|
68
|
-
<Typography
|
|
69
|
-
|
|
103
|
+
<Typography
|
|
104
|
+
sx={{
|
|
105
|
+
color: 'text.primary',
|
|
106
|
+
}}>
|
|
107
|
+
{formatPrice(price, currency!)}
|
|
108
|
+
</Typography>
|
|
109
|
+
<Typography
|
|
110
|
+
sx={{
|
|
111
|
+
color: 'text.secondary',
|
|
112
|
+
ml: 2,
|
|
113
|
+
}}>
|
|
70
114
|
{getPriceCurrencyOptions(price).length > 1
|
|
71
115
|
? ` +${getPriceCurrencyOptions(price).length - 1} more currencies`
|
|
72
116
|
: ''}
|
|
@@ -75,6 +119,7 @@ export default function ProductSelect({ mode: initialMode, hasSelected, onSelect
|
|
|
75
119
|
);
|
|
76
120
|
}),
|
|
77
121
|
]);
|
|
122
|
+
};
|
|
78
123
|
|
|
79
124
|
if (mode === 'inline') {
|
|
80
125
|
return <>{items(onSelect)}</>;
|
|
@@ -82,11 +127,20 @@ export default function ProductSelect({ mode: initialMode, hasSelected, onSelect
|
|
|
82
127
|
|
|
83
128
|
if (mode === 'selecting') {
|
|
84
129
|
return (
|
|
85
|
-
<Select
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
130
|
+
<Select
|
|
131
|
+
fullWidth
|
|
132
|
+
size="small"
|
|
133
|
+
onChange={handleSelect}
|
|
134
|
+
value={value}
|
|
135
|
+
MenuProps={{
|
|
136
|
+
style: { maxHeight: 480 },
|
|
137
|
+
}}>
|
|
138
|
+
{addProduct && (
|
|
139
|
+
<MenuItem value="add">
|
|
140
|
+
<AddOutlined />
|
|
141
|
+
{t('admin.product.add')}
|
|
142
|
+
</MenuItem>
|
|
143
|
+
)}
|
|
90
144
|
{items()}
|
|
91
145
|
</Select>
|
|
92
146
|
);
|
|
@@ -30,6 +30,7 @@ export default function ArcBlockMethodForm({ checkDisabled }: { checkDisabled: (
|
|
|
30
30
|
label={t('admin.paymentMethod.name.label')}
|
|
31
31
|
placeholder={t('admin.paymentMethod.name.tip')}
|
|
32
32
|
disabled={checkDisabled('name')}
|
|
33
|
+
inputProps={{ maxLength: 32 }}
|
|
33
34
|
/>
|
|
34
35
|
<FormInput
|
|
35
36
|
key="description"
|
|
@@ -39,6 +40,7 @@ export default function ArcBlockMethodForm({ checkDisabled }: { checkDisabled: (
|
|
|
39
40
|
label={t('admin.paymentMethod.description.label')}
|
|
40
41
|
placeholder={t('admin.paymentMethod.description.tip')}
|
|
41
42
|
disabled={checkDisabled('description')}
|
|
43
|
+
inputProps={{ maxLength: 255 }}
|
|
42
44
|
/>
|
|
43
45
|
<FormInput
|
|
44
46
|
key="secret_key"
|
|
@@ -68,7 +70,12 @@ export default function ArcBlockMethodForm({ checkDisabled }: { checkDisabled: (
|
|
|
68
70
|
disabled={checkDisabled('settings.arcblock.explorer_host')}
|
|
69
71
|
/>
|
|
70
72
|
<Stack direction="column">
|
|
71
|
-
<Typography
|
|
73
|
+
<Typography
|
|
74
|
+
sx={{
|
|
75
|
+
mb: 1,
|
|
76
|
+
}}>
|
|
77
|
+
{t('admin.paymentCurrency.logo.label')}
|
|
78
|
+
</Typography>
|
|
72
79
|
<Uploader onUploaded={onUploaded} preview={logo} disabled={checkDisabled('logo')} />
|
|
73
80
|
</Stack>
|
|
74
81
|
</>
|
|
@@ -31,6 +31,7 @@ export default function BaseMethodForm({ checkDisabled }: { checkDisabled: (key:
|
|
|
31
31
|
label={t('admin.paymentMethod.name.label')}
|
|
32
32
|
placeholder={t('admin.paymentMethod.name.tip')}
|
|
33
33
|
disabled={checkDisabled('name')}
|
|
34
|
+
inputProps={{ maxLength: 32 }}
|
|
34
35
|
/>
|
|
35
36
|
<FormInput
|
|
36
37
|
key="description"
|
|
@@ -40,6 +41,7 @@ export default function BaseMethodForm({ checkDisabled }: { checkDisabled: (key:
|
|
|
40
41
|
label={t('admin.paymentMethod.description.label')}
|
|
41
42
|
placeholder={t('admin.paymentMethod.description.tip')}
|
|
42
43
|
disabled={checkDisabled('description')}
|
|
44
|
+
inputProps={{ maxLength: 255 }}
|
|
43
45
|
/>
|
|
44
46
|
<EvmRpcInput
|
|
45
47
|
name="settings.base.api_host"
|
|
@@ -75,7 +77,12 @@ export default function BaseMethodForm({ checkDisabled }: { checkDisabled: (key:
|
|
|
75
77
|
disabled={checkDisabled('settings.base.confirmation')}
|
|
76
78
|
/>
|
|
77
79
|
<Stack direction="column">
|
|
78
|
-
<Typography
|
|
80
|
+
<Typography
|
|
81
|
+
sx={{
|
|
82
|
+
mb: 1,
|
|
83
|
+
}}>
|
|
84
|
+
{t('admin.paymentCurrency.logo.label')}
|
|
85
|
+
</Typography>
|
|
79
86
|
<Uploader onUploaded={onUploaded} preview={logo} disabled={checkDisabled('logo')} />
|
|
80
87
|
</Stack>
|
|
81
88
|
</>
|