@blocklet/payment-react 1.13.113
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/LICENSE +13 -0
- package/README.md +29 -0
- package/babel.config.es.js +8 -0
- package/build.config.ts +29 -0
- package/es/api.d.ts +2 -0
- package/es/api.js +18 -0
- package/es/checkout/index.d.ts +15 -0
- package/es/checkout/index.js +61 -0
- package/es/components/input.d.ts +23 -0
- package/es/components/input.js +44 -0
- package/es/components/livemode.d.ts +2 -0
- package/es/components/livemode.js +24 -0
- package/es/components/pricing-table.d.ts +18 -0
- package/es/components/pricing-table.js +175 -0
- package/es/components/status.d.ts +3 -0
- package/es/components/status.js +20 -0
- package/es/components/switch.d.ts +6 -0
- package/es/components/switch.js +42 -0
- package/es/contexts/payment.d.ts +29 -0
- package/es/contexts/payment.js +45 -0
- package/es/dayjs.d.ts +2 -0
- package/es/dayjs.js +14 -0
- package/es/index.d.ts +16 -0
- package/es/index.js +29 -0
- package/es/locales/en.d.ts +2 -0
- package/es/locales/en.js +213 -0
- package/es/locales/index.d.ts +10 -0
- package/es/locales/index.js +20 -0
- package/es/locales/zh.d.ts +2 -0
- package/es/locales/zh.js +213 -0
- package/es/payment/amount.d.ts +12 -0
- package/es/payment/amount.js +22 -0
- package/es/payment/error.d.ts +13 -0
- package/es/payment/error.js +12 -0
- package/es/payment/footer.d.ts +4 -0
- package/es/payment/footer.js +9 -0
- package/es/payment/form/addon.d.ts +2 -0
- package/es/payment/form/addon.js +14 -0
- package/es/payment/form/address.d.ts +7 -0
- package/es/payment/form/address.js +119 -0
- package/es/payment/form/index.d.ts +9 -0
- package/es/payment/form/index.js +337 -0
- package/es/payment/form/phone.d.ts +4 -0
- package/es/payment/form/phone.js +97 -0
- package/es/payment/form/stripe.d.ts +13 -0
- package/es/payment/form/stripe.js +158 -0
- package/es/payment/header.d.ts +7 -0
- package/es/payment/header.js +29 -0
- package/es/payment/index.d.ts +28 -0
- package/es/payment/index.js +327 -0
- package/es/payment/product-card.d.ts +21 -0
- package/es/payment/product-card.js +34 -0
- package/es/payment/product-item.d.ts +19 -0
- package/es/payment/product-item.js +107 -0
- package/es/payment/product-skeleton.d.ts +4 -0
- package/es/payment/product-skeleton.js +34 -0
- package/es/payment/skeleton/overview.d.ts +2 -0
- package/es/payment/skeleton/overview.js +13 -0
- package/es/payment/skeleton/payment.d.ts +2 -0
- package/es/payment/skeleton/payment.js +19 -0
- package/es/payment/success.d.ts +8 -0
- package/es/payment/success.js +164 -0
- package/es/payment/summary.d.ts +12 -0
- package/es/payment/summary.js +178 -0
- package/es/theme.d.ts +1 -0
- package/es/theme.js +17 -0
- package/es/types/index.d.ts +19 -0
- package/es/types/index.js +0 -0
- package/es/types/shims.d.ts +18 -0
- package/es/util.d.ts +52 -0
- package/es/util.js +390 -0
- package/lib/api.d.ts +2 -0
- package/lib/api.js +26 -0
- package/lib/checkout/index.d.ts +15 -0
- package/lib/checkout/index.js +83 -0
- package/lib/components/input.d.ts +23 -0
- package/lib/components/input.js +72 -0
- package/lib/components/livemode.d.ts +2 -0
- package/lib/components/livemode.js +29 -0
- package/lib/components/pricing-table.d.ts +18 -0
- package/lib/components/pricing-table.js +232 -0
- package/lib/components/status.d.ts +3 -0
- package/lib/components/status.js +23 -0
- package/lib/components/switch.d.ts +6 -0
- package/lib/components/switch.js +51 -0
- package/lib/contexts/payment.d.ts +29 -0
- package/lib/contexts/payment.js +73 -0
- package/lib/dayjs.d.ts +2 -0
- package/lib/dayjs.js +21 -0
- package/lib/index.d.ts +16 -0
- package/lib/index.js +143 -0
- package/lib/locales/en.d.ts +2 -0
- package/lib/locales/en.js +220 -0
- package/lib/locales/index.d.ts +10 -0
- package/lib/locales/index.js +33 -0
- package/lib/locales/zh.d.ts +2 -0
- package/lib/locales/zh.js +220 -0
- package/lib/payment/amount.d.ts +12 -0
- package/lib/payment/amount.js +28 -0
- package/lib/payment/error.d.ts +13 -0
- package/lib/payment/error.js +52 -0
- package/lib/payment/footer.d.ts +4 -0
- package/lib/payment/footer.js +25 -0
- package/lib/payment/form/addon.d.ts +2 -0
- package/lib/payment/form/addon.js +37 -0
- package/lib/payment/form/address.d.ts +7 -0
- package/lib/payment/form/address.js +152 -0
- package/lib/payment/form/index.d.ts +9 -0
- package/lib/payment/form/index.js +464 -0
- package/lib/payment/form/phone.d.ts +4 -0
- package/lib/payment/form/phone.js +133 -0
- package/lib/payment/form/stripe.d.ts +13 -0
- package/lib/payment/form/stripe.js +213 -0
- package/lib/payment/header.d.ts +7 -0
- package/lib/payment/header.js +58 -0
- package/lib/payment/index.d.ts +28 -0
- package/lib/payment/index.js +382 -0
- package/lib/payment/product-card.d.ts +21 -0
- package/lib/payment/product-card.js +81 -0
- package/lib/payment/product-item.d.ts +19 -0
- package/lib/payment/product-item.js +160 -0
- package/lib/payment/product-skeleton.d.ts +4 -0
- package/lib/payment/product-skeleton.js +71 -0
- package/lib/payment/skeleton/overview.d.ts +2 -0
- package/lib/payment/skeleton/overview.js +48 -0
- package/lib/payment/skeleton/payment.d.ts +2 -0
- package/lib/payment/skeleton/payment.js +54 -0
- package/lib/payment/success.d.ts +8 -0
- package/lib/payment/success.js +215 -0
- package/lib/payment/summary.d.ts +12 -0
- package/lib/payment/summary.js +225 -0
- package/lib/theme.d.ts +1 -0
- package/lib/theme.js +19 -0
- package/lib/types/index.d.ts +19 -0
- package/lib/types/index.js +1 -0
- package/lib/types/shims.d.ts +18 -0
- package/lib/util.d.ts +52 -0
- package/lib/util.js +487 -0
- package/package.json +104 -0
- package/src/api.ts +24 -0
- package/src/checkout/index.tsx +74 -0
- package/src/components/input.tsx +58 -0
- package/src/components/livemode.tsx +23 -0
- package/src/components/pricing-table.tsx +207 -0
- package/src/components/status.tsx +19 -0
- package/src/components/switch.tsx +48 -0
- package/src/contexts/payment.tsx +74 -0
- package/src/dayjs.ts +17 -0
- package/src/index.ts +32 -0
- package/src/locales/en.tsx +218 -0
- package/src/locales/index.tsx +30 -0
- package/src/locales/zh.tsx +214 -0
- package/src/payment/amount.tsx +24 -0
- package/src/payment/error.tsx +29 -0
- package/src/payment/footer.tsx +12 -0
- package/src/payment/form/addon.tsx +24 -0
- package/src/payment/form/address.tsx +119 -0
- package/src/payment/form/index.tsx +401 -0
- package/src/payment/form/phone.tsx +103 -0
- package/src/payment/form/stripe.tsx +195 -0
- package/src/payment/header.tsx +40 -0
- package/src/payment/index.tsx +367 -0
- package/src/payment/product-card.tsx +55 -0
- package/src/payment/product-item.tsx +121 -0
- package/src/payment/product-skeleton.tsx +39 -0
- package/src/payment/skeleton/overview.tsx +21 -0
- package/src/payment/skeleton/payment.tsx +35 -0
- package/src/payment/success.tsx +186 -0
- package/src/payment/summary.tsx +198 -0
- package/src/theme.ts +18 -0
- package/src/types/index.ts +29 -0
- package/src/types/shims.d.ts +18 -0
- package/src/util.ts +543 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
Copyright 2018-2024 ArcBlock
|
|
2
|
+
|
|
3
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
you may not use this file except in compliance with the License.
|
|
5
|
+
You may obtain a copy of the License at
|
|
6
|
+
|
|
7
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
|
|
9
|
+
Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
See the License for the specific language governing permissions and
|
|
13
|
+
limitations under the License.
|
package/README.md
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Payment Kit Components
|
|
2
|
+
|
|
3
|
+
```tsx
|
|
4
|
+
import { PaymentProvider, Checkout, PricingTable } from '@blocklet/payment-react';
|
|
5
|
+
|
|
6
|
+
export default function Payment() {
|
|
7
|
+
const { session, connectApi } = useSessionContext();
|
|
8
|
+
const { locale } = useLocaleContext();
|
|
9
|
+
|
|
10
|
+
return (<PaymentProvider session={session} connect={connectApi} locale={locale}>
|
|
11
|
+
<Checkout checkoutSessionId="" onComplete={noop} onError={noop} params={{}} />
|
|
12
|
+
<Checkout paymentLinkId="" onComplete={noop} onError={noop} params={{}} />
|
|
13
|
+
<Checkout pricingTableId="" onSelect={noop} onComplete={noop} onError={noop} params={{}} />
|
|
14
|
+
</PaymentProvider>);
|
|
15
|
+
}
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## I18n
|
|
19
|
+
|
|
20
|
+
```tsx
|
|
21
|
+
import { createTranslator, translations as extraTranslations } from '@blocklet/payment-react';
|
|
22
|
+
import merge from 'lodash/merge';
|
|
23
|
+
|
|
24
|
+
import en from './en';
|
|
25
|
+
import zh from './zh';
|
|
26
|
+
|
|
27
|
+
// eslint-disable-next-line import/prefer-default-export
|
|
28
|
+
export const translations = merge({ zh, en }, extraTranslations);
|
|
29
|
+
```
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
presets: [
|
|
3
|
+
['@babel/preset-env', { modules: false, targets: 'chrome 114' }],
|
|
4
|
+
['@babel/preset-react', { useBuiltIns: true, runtime: 'automatic' }],
|
|
5
|
+
],
|
|
6
|
+
plugins: ['babel-plugin-inline-react-svg'],
|
|
7
|
+
ignore: ['src/**/*.stories.js', 'src/**/demo'],
|
|
8
|
+
};
|
package/build.config.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { defineBuildConfig, BuildEntry } from 'unbuild';
|
|
2
|
+
|
|
3
|
+
const pattern = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx', '**/*.png', '!**/*.stories.js', '!**/demo'];
|
|
4
|
+
|
|
5
|
+
const shared: BuildEntry = {
|
|
6
|
+
builder: 'mkdist',
|
|
7
|
+
input: './src',
|
|
8
|
+
pattern,
|
|
9
|
+
ext: 'js',
|
|
10
|
+
esbuild: {
|
|
11
|
+
jsx: 'automatic',
|
|
12
|
+
},
|
|
13
|
+
declaration: true,
|
|
14
|
+
};
|
|
15
|
+
export default defineBuildConfig({
|
|
16
|
+
failOnWarn: false,
|
|
17
|
+
entries: [
|
|
18
|
+
{
|
|
19
|
+
...shared,
|
|
20
|
+
outDir: './es',
|
|
21
|
+
format: 'esm',
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
...shared,
|
|
25
|
+
outDir: './lib',
|
|
26
|
+
format: 'cjs',
|
|
27
|
+
},
|
|
28
|
+
],
|
|
29
|
+
});
|
package/es/api.d.ts
ADDED
package/es/api.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { getLocale } from "@arcblock/ux/lib/Locale/context";
|
|
2
|
+
import axios from "axios";
|
|
3
|
+
import isNull from "lodash/isNull";
|
|
4
|
+
import { getPrefix } from "./util.js";
|
|
5
|
+
const api = axios.create();
|
|
6
|
+
api.interceptors.request.use(
|
|
7
|
+
(config) => {
|
|
8
|
+
const prefix = getPrefix();
|
|
9
|
+
config.baseURL = prefix || "";
|
|
10
|
+
config.timeout = 8e3;
|
|
11
|
+
const livemode = localStorage.getItem("livemode");
|
|
12
|
+
const locale = getLocale(window.blocklet.languages);
|
|
13
|
+
config.params = { ...config.params || {}, livemode: isNull(livemode) ? true : JSON.parse(livemode), locale };
|
|
14
|
+
return config;
|
|
15
|
+
},
|
|
16
|
+
(err) => Promise.reject(err)
|
|
17
|
+
);
|
|
18
|
+
export default api;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
import { CheckoutProps } from '../types';
|
|
3
|
+
declare function Checkout({ id, onPaid, onError, mode, extraParams }: CheckoutProps): import("react").JSX.Element;
|
|
4
|
+
declare namespace Checkout {
|
|
5
|
+
var defaultProps: {
|
|
6
|
+
onPaid: any;
|
|
7
|
+
onError: {
|
|
8
|
+
(...data: any[]): void;
|
|
9
|
+
(message?: any, ...optionalParams: any[]): void;
|
|
10
|
+
};
|
|
11
|
+
mode: string;
|
|
12
|
+
extraParams: {};
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
export default Checkout;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useRequest, useSetState } from "ahooks";
|
|
3
|
+
import noop from "lodash/noop";
|
|
4
|
+
import { useEffect } from "react";
|
|
5
|
+
import { joinURL } from "ufo";
|
|
6
|
+
import api from "../api.js";
|
|
7
|
+
import Payment from "../payment/index.js";
|
|
8
|
+
import { getPrefix, mergeExtraParams } from "../util.js";
|
|
9
|
+
const startFromPaymentLink = async (id, params) => {
|
|
10
|
+
const { data } = await api.post(`/api/checkout-sessions/start/${id}?${mergeExtraParams(params)}`);
|
|
11
|
+
return data;
|
|
12
|
+
};
|
|
13
|
+
const fetchCheckoutSession = async (id) => {
|
|
14
|
+
const { data } = await api.get(`/api/checkout-sessions/retrieve/${id}`);
|
|
15
|
+
return data;
|
|
16
|
+
};
|
|
17
|
+
export default function Checkout({ id, onPaid, onError, mode, extraParams }) {
|
|
18
|
+
if (!id.startsWith("plink_") && !id.startsWith("cs_")) {
|
|
19
|
+
throw new Error("Either a checkout session or a payment link id is required.");
|
|
20
|
+
}
|
|
21
|
+
const type = id.startsWith("plink_") ? "paymentLink" : "checkoutSession";
|
|
22
|
+
const [state, setState] = useSetState({ completed: false, appError: null });
|
|
23
|
+
const { error: apiError, data } = useRequest(
|
|
24
|
+
() => type === "paymentLink" ? startFromPaymentLink(id, extraParams) : fetchCheckoutSession(id)
|
|
25
|
+
);
|
|
26
|
+
useEffect(() => {
|
|
27
|
+
if (type === "paymentLink" && mode === "standalone" && data) {
|
|
28
|
+
window.location.replace(joinURL(getPrefix(), `/checkout/pay/${data.checkoutSession.id}`));
|
|
29
|
+
}
|
|
30
|
+
}, [type, mode, data]);
|
|
31
|
+
const handlePaid = () => {
|
|
32
|
+
setState({ completed: true });
|
|
33
|
+
onPaid?.(data);
|
|
34
|
+
};
|
|
35
|
+
const handleError = (err) => {
|
|
36
|
+
console.error(err);
|
|
37
|
+
setState({ appError: err });
|
|
38
|
+
onError?.(err);
|
|
39
|
+
};
|
|
40
|
+
return /* @__PURE__ */ jsx(
|
|
41
|
+
Payment,
|
|
42
|
+
{
|
|
43
|
+
checkoutSession: data?.checkoutSession,
|
|
44
|
+
paymentMethods: data?.paymentMethods,
|
|
45
|
+
paymentIntent: data?.paymentIntent,
|
|
46
|
+
paymentLink: data?.paymentLink,
|
|
47
|
+
customer: data?.customer,
|
|
48
|
+
completed: state.completed,
|
|
49
|
+
error: apiError || state.appError,
|
|
50
|
+
onPaid: handlePaid,
|
|
51
|
+
onError: handleError,
|
|
52
|
+
mode
|
|
53
|
+
}
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
Checkout.defaultProps = {
|
|
57
|
+
onPaid: noop,
|
|
58
|
+
onError: console.error,
|
|
59
|
+
mode: "inline",
|
|
60
|
+
extraParams: {}
|
|
61
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
import { TextFieldProps } from '@mui/material';
|
|
3
|
+
import { RegisterOptions } from 'react-hook-form';
|
|
4
|
+
type InputProps = TextFieldProps & {
|
|
5
|
+
name: string;
|
|
6
|
+
label?: string;
|
|
7
|
+
placeholder?: string;
|
|
8
|
+
errorPosition?: 'right' | 'bottom';
|
|
9
|
+
rules?: RegisterOptions;
|
|
10
|
+
};
|
|
11
|
+
export declare function FormInputError({ error }: {
|
|
12
|
+
error: string;
|
|
13
|
+
}): import("react").JSX.Element;
|
|
14
|
+
declare function FormInput({ name, label, placeholder, rules, errorPosition, ...rest }: InputProps): import("react").JSX.Element;
|
|
15
|
+
declare namespace FormInput {
|
|
16
|
+
var defaultProps: {
|
|
17
|
+
label: string;
|
|
18
|
+
placeholder: string;
|
|
19
|
+
errorPosition: string;
|
|
20
|
+
rules: {};
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
export default FormInput;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Box, FormLabel, InputAdornment, TextField, Typography } from "@mui/material";
|
|
3
|
+
import get from "lodash/get";
|
|
4
|
+
import { Controller, useFormContext } from "react-hook-form";
|
|
5
|
+
FormInput.defaultProps = {
|
|
6
|
+
label: "",
|
|
7
|
+
placeholder: "",
|
|
8
|
+
errorPosition: "bottom",
|
|
9
|
+
rules: {}
|
|
10
|
+
};
|
|
11
|
+
export function FormInputError({ error }) {
|
|
12
|
+
return /* @__PURE__ */ jsx(InputAdornment, { position: "end", children: /* @__PURE__ */ jsx(Typography, { component: "span", color: "error", children: error }) });
|
|
13
|
+
}
|
|
14
|
+
export default function FormInput({ name, label, placeholder, rules, errorPosition, ...rest }) {
|
|
15
|
+
const { control, formState } = useFormContext();
|
|
16
|
+
const error = get(formState.errors, name)?.message;
|
|
17
|
+
return /* @__PURE__ */ jsx(
|
|
18
|
+
Controller,
|
|
19
|
+
{
|
|
20
|
+
name,
|
|
21
|
+
control,
|
|
22
|
+
rules,
|
|
23
|
+
render: ({ field }) => /* @__PURE__ */ jsxs(Box, { sx: { width: "100%" }, children: [
|
|
24
|
+
!!label && /* @__PURE__ */ jsx(FormLabel, { children: label }),
|
|
25
|
+
/* @__PURE__ */ jsx(
|
|
26
|
+
TextField,
|
|
27
|
+
{
|
|
28
|
+
fullWidth: true,
|
|
29
|
+
error: !!get(formState.errors, name),
|
|
30
|
+
helperText: errorPosition === "bottom" && error ? error : "",
|
|
31
|
+
placeholder,
|
|
32
|
+
size: "small",
|
|
33
|
+
...field,
|
|
34
|
+
...rest,
|
|
35
|
+
InputProps: Object.assign(
|
|
36
|
+
rest.InputProps || {},
|
|
37
|
+
errorPosition === "right" && error ? { endAdornment: /* @__PURE__ */ jsx(FormInputError, { error }) } : {}
|
|
38
|
+
)
|
|
39
|
+
}
|
|
40
|
+
)
|
|
41
|
+
] })
|
|
42
|
+
}
|
|
43
|
+
);
|
|
44
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useLocaleContext } from "@arcblock/ux/lib/Locale/context";
|
|
3
|
+
import { Chip } from "@mui/material";
|
|
4
|
+
export default function Livemode() {
|
|
5
|
+
const { t } = useLocaleContext();
|
|
6
|
+
return /* @__PURE__ */ jsx(
|
|
7
|
+
Chip,
|
|
8
|
+
{
|
|
9
|
+
label: t("common.livemode"),
|
|
10
|
+
size: "small",
|
|
11
|
+
sx: {
|
|
12
|
+
ml: 2,
|
|
13
|
+
height: 18,
|
|
14
|
+
lineHeight: 1,
|
|
15
|
+
textTransform: "uppercase",
|
|
16
|
+
fontSize: "0.8rem",
|
|
17
|
+
fontWeight: "bold",
|
|
18
|
+
borderRadius: "4px",
|
|
19
|
+
backgroundColor: "#ffde92",
|
|
20
|
+
color: "#bb5504"
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
);
|
|
24
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
import type { TPricingTableExpanded } from '@blocklet/payment-types';
|
|
3
|
+
type Props = {
|
|
4
|
+
table: TPricingTableExpanded;
|
|
5
|
+
onSelect: (priceId: string) => void;
|
|
6
|
+
alignItems?: 'center' | 'left';
|
|
7
|
+
mode?: 'checkout' | 'select';
|
|
8
|
+
interval?: string;
|
|
9
|
+
};
|
|
10
|
+
declare function PricingTable({ table, alignItems, interval, mode, onSelect }: Props): import("react").JSX.Element;
|
|
11
|
+
declare namespace PricingTable {
|
|
12
|
+
var defaultProps: {
|
|
13
|
+
alignItems: string;
|
|
14
|
+
mode: string;
|
|
15
|
+
interval: string;
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
export default PricingTable;
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useLocaleContext } from "@arcblock/ux/lib/Locale/context";
|
|
3
|
+
import Toast from "@arcblock/ux/lib/Toast";
|
|
4
|
+
import { CheckOutlined } from "@mui/icons-material";
|
|
5
|
+
import { LoadingButton } from "@mui/lab";
|
|
6
|
+
import {
|
|
7
|
+
Box,
|
|
8
|
+
Chip,
|
|
9
|
+
Fade,
|
|
10
|
+
List,
|
|
11
|
+
ListItem,
|
|
12
|
+
ListItemIcon,
|
|
13
|
+
ListItemText,
|
|
14
|
+
Stack,
|
|
15
|
+
ToggleButton,
|
|
16
|
+
ToggleButtonGroup,
|
|
17
|
+
Typography
|
|
18
|
+
} from "@mui/material";
|
|
19
|
+
import { useSetState } from "ahooks";
|
|
20
|
+
import { useEffect } from "react";
|
|
21
|
+
import Amount from "../payment/amount.js";
|
|
22
|
+
import { formatError, formatPriceAmount, formatRecurring } from "../util.js";
|
|
23
|
+
const groupItemsByRecurring = (items) => {
|
|
24
|
+
const grouped = {};
|
|
25
|
+
const recurring = {};
|
|
26
|
+
items.forEach((x) => {
|
|
27
|
+
const key = [x.price.recurring?.interval, x.price.recurring?.interval_count].join("-");
|
|
28
|
+
recurring[key] = x.price.recurring;
|
|
29
|
+
if (!grouped[key]) {
|
|
30
|
+
grouped[key] = [];
|
|
31
|
+
}
|
|
32
|
+
grouped[key].push(x);
|
|
33
|
+
});
|
|
34
|
+
return { recurring, grouped };
|
|
35
|
+
};
|
|
36
|
+
PricingTable.defaultProps = {
|
|
37
|
+
alignItems: "center",
|
|
38
|
+
mode: "checkout",
|
|
39
|
+
interval: ""
|
|
40
|
+
};
|
|
41
|
+
export default function PricingTable({ table, alignItems, interval, mode, onSelect }) {
|
|
42
|
+
const { t, locale } = useLocaleContext();
|
|
43
|
+
const [state, setState] = useSetState({ interval, loading: "" });
|
|
44
|
+
const { recurring, grouped } = groupItemsByRecurring(table.items);
|
|
45
|
+
useEffect(() => {
|
|
46
|
+
if (table) {
|
|
47
|
+
if (!state.interval || !grouped[state.interval]) {
|
|
48
|
+
const keys = Object.keys(recurring);
|
|
49
|
+
if (keys[0]) {
|
|
50
|
+
setState({ interval: keys[0] });
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}, [table]);
|
|
55
|
+
const handleSelect = async (priceId) => {
|
|
56
|
+
try {
|
|
57
|
+
setState({ loading: priceId });
|
|
58
|
+
await onSelect(priceId);
|
|
59
|
+
} catch (err) {
|
|
60
|
+
console.error(err);
|
|
61
|
+
Toast.error(formatError(err));
|
|
62
|
+
} finally {
|
|
63
|
+
setState({ loading: "" });
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
return /* @__PURE__ */ jsxs(
|
|
67
|
+
Stack,
|
|
68
|
+
{
|
|
69
|
+
direction: "column",
|
|
70
|
+
alignItems: alignItems === "center" ? "center" : "flex-start",
|
|
71
|
+
sx: {
|
|
72
|
+
pt: {
|
|
73
|
+
xs: 4,
|
|
74
|
+
sm: 2
|
|
75
|
+
},
|
|
76
|
+
gap: {
|
|
77
|
+
xs: 3,
|
|
78
|
+
sm: mode === "select" ? 3 : 5
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
children: [
|
|
82
|
+
Object.keys(recurring).length > 1 && /* @__PURE__ */ jsx(
|
|
83
|
+
ToggleButtonGroup,
|
|
84
|
+
{
|
|
85
|
+
color: "primary",
|
|
86
|
+
value: state.interval,
|
|
87
|
+
onChange: (_, value) => {
|
|
88
|
+
if (value !== null) {
|
|
89
|
+
setState({ interval: value });
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
exclusive: true,
|
|
93
|
+
children: Object.keys(recurring).map((x) => /* @__PURE__ */ jsx(ToggleButton, { value: x, sx: { textTransform: "capitalize" }, children: formatRecurring(recurring[x], true, "", locale) }, x))
|
|
94
|
+
}
|
|
95
|
+
),
|
|
96
|
+
/* @__PURE__ */ jsx(
|
|
97
|
+
Stack,
|
|
98
|
+
{
|
|
99
|
+
flexWrap: "wrap",
|
|
100
|
+
direction: "row",
|
|
101
|
+
gap: { xs: 3, sm: 5, md: mode === "checkout" ? 10 : 5 },
|
|
102
|
+
justifyContent: alignItems === "center" ? "center" : "flex-start",
|
|
103
|
+
children: grouped[state.interval]?.map((x) => {
|
|
104
|
+
let action = x.subscription_data?.trial_period_days ? t("payment.checkout.try") : t("payment.checkout.subscription");
|
|
105
|
+
if (mode === "select") {
|
|
106
|
+
action = x.is_selected ? t("payment.checkout.selected") : t("payment.checkout.select");
|
|
107
|
+
}
|
|
108
|
+
return /* @__PURE__ */ jsx(Fade, { in: true, children: /* @__PURE__ */ jsxs(
|
|
109
|
+
Stack,
|
|
110
|
+
{
|
|
111
|
+
padding: 4,
|
|
112
|
+
spacing: 2,
|
|
113
|
+
direction: "column",
|
|
114
|
+
alignItems: "center",
|
|
115
|
+
sx: {
|
|
116
|
+
width: 320,
|
|
117
|
+
cursor: "pointer",
|
|
118
|
+
borderWidth: "1px",
|
|
119
|
+
borderStyle: "solid",
|
|
120
|
+
borderColor: mode === "select" && x.is_selected ? "primary.main" : "#eee",
|
|
121
|
+
borderRadius: 1,
|
|
122
|
+
transition: "border-color 0.3s ease 0s, box-shadow 0.3s ease 0s",
|
|
123
|
+
boxShadow: "0 4px 8px rgba(0, 0, 0, 20%)",
|
|
124
|
+
"&:hover": {
|
|
125
|
+
borderColor: mode === "select" && x.is_selected ? "primary.main" : "#ddd",
|
|
126
|
+
boxShadow: "0 8px 16px rgba(0, 0, 0, 20%)"
|
|
127
|
+
}
|
|
128
|
+
},
|
|
129
|
+
children: [
|
|
130
|
+
/* @__PURE__ */ jsxs(Box, { textAlign: "center", children: [
|
|
131
|
+
/* @__PURE__ */ jsxs(Stack, { direction: "row", alignItems: "center", spacing: 1, children: [
|
|
132
|
+
/* @__PURE__ */ jsx(Typography, { variant: "h5", color: "text.primary", fontWeight: 600, children: x.product.name }),
|
|
133
|
+
x.is_highlight && /* @__PURE__ */ jsx(Chip, { label: x.highlight_text, color: "default", size: "small" })
|
|
134
|
+
] }),
|
|
135
|
+
/* @__PURE__ */ jsx(Typography, { color: "text.secondary", children: x.product.description })
|
|
136
|
+
] }),
|
|
137
|
+
/* @__PURE__ */ jsxs(Stack, { direction: "row", alignItems: "center", spacing: 1, children: [
|
|
138
|
+
/* @__PURE__ */ jsx(Amount, { amount: formatPriceAmount(x.price, table.currency, x.product.unit_label) }),
|
|
139
|
+
/* @__PURE__ */ jsxs(Stack, { direction: "column", alignItems: "flex-start", children: [
|
|
140
|
+
/* @__PURE__ */ jsx(Typography, { component: "span", color: "text.secondary", fontSize: "0.8rem", children: t("payment.checkout.per") }),
|
|
141
|
+
/* @__PURE__ */ jsx(Typography, { component: "span", color: "text.secondary", fontSize: "0.8rem", children: formatRecurring(x.price.recurring, false, "", locale) })
|
|
142
|
+
] })
|
|
143
|
+
] }),
|
|
144
|
+
/* @__PURE__ */ jsx(
|
|
145
|
+
LoadingButton,
|
|
146
|
+
{
|
|
147
|
+
fullWidth: true,
|
|
148
|
+
size: "large",
|
|
149
|
+
loadingPosition: "end",
|
|
150
|
+
variant: x.is_highlight || x.is_selected ? "contained" : "outlined",
|
|
151
|
+
color: x.is_highlight || x.is_selected ? "primary" : "info",
|
|
152
|
+
sx: { fontSize: "1.2rem" },
|
|
153
|
+
loading: state.loading === x.price_id,
|
|
154
|
+
disabled: x.is_disabled,
|
|
155
|
+
onClick: () => handleSelect(x.price_id),
|
|
156
|
+
children: action
|
|
157
|
+
}
|
|
158
|
+
),
|
|
159
|
+
x.product.features.length > 0 && /* @__PURE__ */ jsxs(Box, { children: [
|
|
160
|
+
/* @__PURE__ */ jsx(Typography, { children: t("payment.checkout.include") }),
|
|
161
|
+
/* @__PURE__ */ jsx(List, { dense: true, children: x.product.features.map((f) => /* @__PURE__ */ jsxs(ListItem, { disableGutters: true, disablePadding: true, children: [
|
|
162
|
+
/* @__PURE__ */ jsx(ListItemIcon, { sx: { minWidth: 25 }, children: /* @__PURE__ */ jsx(CheckOutlined, { color: "success", fontSize: "small" }) }),
|
|
163
|
+
/* @__PURE__ */ jsx(ListItemText, { primary: f.name })
|
|
164
|
+
] }, f.name)) })
|
|
165
|
+
] })
|
|
166
|
+
]
|
|
167
|
+
}
|
|
168
|
+
) }, x.price_id);
|
|
169
|
+
})
|
|
170
|
+
}
|
|
171
|
+
)
|
|
172
|
+
]
|
|
173
|
+
}
|
|
174
|
+
);
|
|
175
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Chip } from "@mui/material";
|
|
3
|
+
export default function Status(props) {
|
|
4
|
+
return /* @__PURE__ */ jsx(
|
|
5
|
+
Chip,
|
|
6
|
+
{
|
|
7
|
+
size: "small",
|
|
8
|
+
variant: "outlined",
|
|
9
|
+
...props,
|
|
10
|
+
sx: {
|
|
11
|
+
...props.sx || {},
|
|
12
|
+
borderRadius: "4px",
|
|
13
|
+
height: 20,
|
|
14
|
+
lineHeight: 1,
|
|
15
|
+
textTransform: "capitalize",
|
|
16
|
+
marginRight: "10px"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
);
|
|
20
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { LiteralUnion } from 'type-fest';
|
|
2
|
+
type SwitchProps = {
|
|
3
|
+
variant?: LiteralUnion<'success' | 'error' | 'warning' | 'info' | 'primary' | 'secondary', string>;
|
|
4
|
+
};
|
|
5
|
+
declare const _default: import("@emotion/styled").StyledComponent<import("@mui/material").SwitchProps & import("@mui/system").MUIStyledCommonProps<import("@mui/system").Theme> & SwitchProps, {}, {}>;
|
|
6
|
+
export default _default;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { Switch } from "@mui/material";
|
|
2
|
+
import { styled } from "@mui/system";
|
|
3
|
+
export default styled(Switch)(({ variant = "success", theme }) => ({
|
|
4
|
+
width: 28,
|
|
5
|
+
height: 16,
|
|
6
|
+
padding: 0,
|
|
7
|
+
display: "inline-flex",
|
|
8
|
+
"&:active": {
|
|
9
|
+
"& .MuiSwitch-thumb": {
|
|
10
|
+
width: 15
|
|
11
|
+
},
|
|
12
|
+
"& .MuiSwitch-switchBase.Mui-checked": {
|
|
13
|
+
transform: "translateX(9px)"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"& .MuiSwitch-switchBase": {
|
|
17
|
+
padding: 2,
|
|
18
|
+
"&.Mui-checked": {
|
|
19
|
+
transform: "translateX(12px)",
|
|
20
|
+
color: "#fff",
|
|
21
|
+
"& + .MuiSwitch-track": {
|
|
22
|
+
opacity: 1,
|
|
23
|
+
backgroundColor: theme.palette[variant].light
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"& .MuiSwitch-thumb": {
|
|
28
|
+
boxShadow: "0 2px 4px 0 rgb(0 35 11 / 20%)",
|
|
29
|
+
width: 12,
|
|
30
|
+
height: 12,
|
|
31
|
+
borderRadius: 6,
|
|
32
|
+
transition: theme.transitions.create(["width"], {
|
|
33
|
+
duration: 200
|
|
34
|
+
})
|
|
35
|
+
},
|
|
36
|
+
"& .MuiSwitch-track": {
|
|
37
|
+
borderRadius: 16 / 2,
|
|
38
|
+
opacity: 1,
|
|
39
|
+
backgroundColor: theme.palette.mode === "dark" ? "rgba(255,255,255,.35)" : "rgba(0,0,0,.25)",
|
|
40
|
+
boxSizing: "border-box"
|
|
41
|
+
}
|
|
42
|
+
}));
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
import type { TPaymentCurrency, TPaymentMethodExpanded } from '@blocklet/payment-types';
|
|
3
|
+
import type { Axios } from 'axios';
|
|
4
|
+
export interface Settings {
|
|
5
|
+
paymentMethods: TPaymentMethodExpanded[];
|
|
6
|
+
baseCurrency: TPaymentCurrency;
|
|
7
|
+
}
|
|
8
|
+
export type PaymentContextType = {
|
|
9
|
+
livemode: boolean;
|
|
10
|
+
session: any;
|
|
11
|
+
connect: any;
|
|
12
|
+
prefix: string;
|
|
13
|
+
settings: Settings;
|
|
14
|
+
refresh: () => void;
|
|
15
|
+
setLivemode: (livemode: boolean) => void;
|
|
16
|
+
api: Axios;
|
|
17
|
+
};
|
|
18
|
+
declare const PaymentContext: import("react").Context<PaymentContextType>;
|
|
19
|
+
declare const Consumer: import("react").Consumer<PaymentContextType>;
|
|
20
|
+
declare function PaymentProvider({ children, session, connect }: {
|
|
21
|
+
children: any;
|
|
22
|
+
session: any;
|
|
23
|
+
connect: any;
|
|
24
|
+
}): JSX.Element;
|
|
25
|
+
declare namespace PaymentProvider {
|
|
26
|
+
var defaultProps: {};
|
|
27
|
+
}
|
|
28
|
+
declare function usePaymentContext(): PaymentContextType;
|
|
29
|
+
export { PaymentContext, PaymentProvider, Consumer as SettingsConsumer, usePaymentContext };
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Alert, CircularProgress } from "@mui/material";
|
|
3
|
+
import { useLocalStorageState, useRequest } from "ahooks";
|
|
4
|
+
import { createContext, useContext } from "react";
|
|
5
|
+
import api from "../api.js";
|
|
6
|
+
import { getPrefix } from "../util.js";
|
|
7
|
+
const prefix = getPrefix();
|
|
8
|
+
const PaymentContext = createContext({ api });
|
|
9
|
+
const { Provider, Consumer } = PaymentContext;
|
|
10
|
+
const getSettings = async () => {
|
|
11
|
+
const { data } = await api.get("/api/settings");
|
|
12
|
+
return data;
|
|
13
|
+
};
|
|
14
|
+
function PaymentProvider({ children, session, connect }) {
|
|
15
|
+
const { data, error, run, loading } = useRequest(getSettings);
|
|
16
|
+
const [livemode, setLivemode] = useLocalStorageState("livemode", { defaultValue: true });
|
|
17
|
+
if (error) {
|
|
18
|
+
return /* @__PURE__ */ jsx(Alert, { severity: "error", children: error.message });
|
|
19
|
+
}
|
|
20
|
+
if (loading) {
|
|
21
|
+
return /* @__PURE__ */ jsx(CircularProgress, {});
|
|
22
|
+
}
|
|
23
|
+
return /* @__PURE__ */ jsx(
|
|
24
|
+
Provider,
|
|
25
|
+
{
|
|
26
|
+
value: {
|
|
27
|
+
session,
|
|
28
|
+
connect,
|
|
29
|
+
prefix,
|
|
30
|
+
livemode: !!livemode,
|
|
31
|
+
settings: data,
|
|
32
|
+
refresh: run,
|
|
33
|
+
setLivemode,
|
|
34
|
+
api
|
|
35
|
+
},
|
|
36
|
+
children
|
|
37
|
+
}
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
function usePaymentContext() {
|
|
41
|
+
const context = useContext(PaymentContext);
|
|
42
|
+
return context;
|
|
43
|
+
}
|
|
44
|
+
PaymentProvider.defaultProps = {};
|
|
45
|
+
export { PaymentContext, PaymentProvider, Consumer as SettingsConsumer, usePaymentContext };
|
package/es/dayjs.d.ts
ADDED
package/es/dayjs.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import dayjs from "dayjs";
|
|
2
|
+
import duration from "dayjs/plugin/duration";
|
|
3
|
+
import localizedFormat from "dayjs/plugin/localizedFormat";
|
|
4
|
+
import relativeTime from "dayjs/plugin/relativeTime";
|
|
5
|
+
import timezone from "dayjs/plugin/timezone";
|
|
6
|
+
import utc from "dayjs/plugin/utc";
|
|
7
|
+
import("dayjs/locale/en");
|
|
8
|
+
import("dayjs/locale/zh");
|
|
9
|
+
dayjs.extend(relativeTime);
|
|
10
|
+
dayjs.extend(localizedFormat);
|
|
11
|
+
dayjs.extend(duration);
|
|
12
|
+
dayjs.extend(utc);
|
|
13
|
+
dayjs.extend(timezone);
|
|
14
|
+
export default dayjs;
|
package/es/index.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import api from './api';
|
|
2
|
+
import Checkout from './checkout';
|
|
3
|
+
import FormInput from './components/input';
|
|
4
|
+
import Livemode from './components/livemode';
|
|
5
|
+
import PricingTable from './components/pricing-table';
|
|
6
|
+
import Status from './components/status';
|
|
7
|
+
import Switch from './components/switch';
|
|
8
|
+
import dayjs from './dayjs';
|
|
9
|
+
import Amount from './payment/amount';
|
|
10
|
+
import PhoneInput from './payment/form/phone';
|
|
11
|
+
import Payment from './payment/index';
|
|
12
|
+
import ProductSkeleton from './payment/product-skeleton';
|
|
13
|
+
export * from './util';
|
|
14
|
+
export * from './contexts/payment';
|
|
15
|
+
export { translations, createTranslator } from './locales';
|
|
16
|
+
export { api, dayjs, FormInput, PhoneInput, Status, Livemode, Switch, Checkout, Payment, PricingTable, ProductSkeleton, Amount, };
|