@blocklet/payment-react 1.13.113 → 1.13.115
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/README.md +49 -8
- package/es/checkout/{index.d.ts → form.d.ts} +3 -3
- package/es/checkout/{index.js → form.js} +3 -3
- package/es/checkout/table.d.ts +3 -0
- package/es/checkout/table.js +71 -0
- package/es/components/pricing-table.js +0 -2
- package/es/index.d.ts +3 -2
- package/es/index.js +4 -2
- package/es/payment/form/addon.js +1 -1
- package/es/payment/form/index.js +5 -5
- package/es/payment/index.d.ts +2 -1
- package/es/payment/index.js +14 -11
- package/es/payment/summary.js +67 -77
- package/lib/checkout/{index.d.ts → form.d.ts} +3 -3
- package/lib/checkout/{index.js → form.js} +4 -4
- package/lib/checkout/table.d.ts +3 -0
- package/lib/checkout/table.js +117 -0
- package/lib/components/pricing-table.js +0 -4
- package/lib/index.d.ts +3 -2
- package/lib/index.js +12 -4
- package/lib/payment/form/addon.js +1 -1
- package/lib/payment/form/index.js +5 -5
- package/lib/payment/index.d.ts +2 -1
- package/lib/payment/index.js +19 -11
- package/lib/payment/summary.js +0 -3
- package/package.json +3 -3
- package/src/checkout/{index.tsx → form.tsx} +4 -3
- package/src/checkout/table.tsx +85 -0
- package/src/components/pricing-table.tsx +0 -2
- package/src/index.ts +4 -2
- package/src/payment/form/addon.tsx +1 -1
- package/src/payment/form/index.tsx +5 -5
- package/src/payment/index.tsx +20 -12
- package/src/payment/summary.tsx +1 -6
package/README.md
CHANGED
|
@@ -1,18 +1,59 @@
|
|
|
1
1
|
# Payment Kit Components
|
|
2
2
|
|
|
3
3
|
```tsx
|
|
4
|
-
import {
|
|
4
|
+
import { CheckoutForm, CheckoutTable, PaymentProvider } from '@blocklet/payment-react';
|
|
5
|
+
import { Paper, Typography } from '@mui/material';
|
|
6
|
+
import React from 'react';
|
|
7
|
+
import { useSearchParams } from 'react-router-dom';
|
|
5
8
|
|
|
6
|
-
|
|
9
|
+
import { useSessionContext } from '../contexts/session';
|
|
10
|
+
|
|
11
|
+
export default function CheckoutPage() {
|
|
12
|
+
const [params] = useSearchParams();
|
|
7
13
|
const { session, connectApi } = useSessionContext();
|
|
8
|
-
const { locale } = useLocaleContext();
|
|
9
14
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
+
if (params.get('type') === 'session') {
|
|
16
|
+
return (
|
|
17
|
+
<PaymentProvider session={session} connect={connectApi}>
|
|
18
|
+
<Typography variant="h4" gutterBottom>
|
|
19
|
+
Checkout with session
|
|
20
|
+
</Typography>
|
|
21
|
+
<Paper sx={{ p: 3, display: 'inline-block' }} elevation={3}>
|
|
22
|
+
<CheckoutForm id="cs_9zeD2yCgPXT9Vit9bab2vVC3V7DFjHiKvyoLzVTVzAf4XSU2oLWY67vKy7" mode="inline" />
|
|
23
|
+
</Paper>
|
|
24
|
+
</PaymentProvider>
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (params.get('type') === 'link') {
|
|
29
|
+
return (
|
|
30
|
+
<PaymentProvider session={session} connect={connectApi}>
|
|
31
|
+
<Typography variant="h4" gutterBottom>
|
|
32
|
+
Checkout with payment link
|
|
33
|
+
</Typography>
|
|
34
|
+
<Paper sx={{ p: 3, display: 'inline-block' }} elevation={3}>
|
|
35
|
+
<CheckoutForm id="plink_oB1I6FNeHKSkuq81fhJy0vIZ" mode="inline" />
|
|
36
|
+
</Paper>
|
|
37
|
+
</PaymentProvider>
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (params.get('type') === 'table') {
|
|
42
|
+
return (
|
|
43
|
+
<PaymentProvider session={session} connect={connectApi}>
|
|
44
|
+
<Typography variant="h4" gutterBottom>
|
|
45
|
+
Checkout with pricing table
|
|
46
|
+
</Typography>
|
|
47
|
+
<Paper sx={{ p: 3, display: 'inline-block' }} elevation={3}>
|
|
48
|
+
<CheckoutTable id="prctbl_kOsaIiPrsHAwwALaKgy17mIl" mode="inline" />
|
|
49
|
+
</Paper>
|
|
50
|
+
</PaymentProvider>
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return null;
|
|
15
55
|
}
|
|
56
|
+
|
|
16
57
|
```
|
|
17
58
|
|
|
18
59
|
## I18n
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/// <reference types="react" />
|
|
2
2
|
import { CheckoutProps } from '../types';
|
|
3
|
-
declare function
|
|
4
|
-
declare namespace
|
|
3
|
+
declare function CheckoutForm({ id, onPaid, onError, mode, extraParams }: CheckoutProps): import("react").JSX.Element;
|
|
4
|
+
declare namespace CheckoutForm {
|
|
5
5
|
var defaultProps: {
|
|
6
6
|
onPaid: any;
|
|
7
7
|
onError: {
|
|
@@ -12,4 +12,4 @@ declare namespace Checkout {
|
|
|
12
12
|
extraParams: {};
|
|
13
13
|
};
|
|
14
14
|
}
|
|
15
|
-
export default
|
|
15
|
+
export default CheckoutForm;
|
|
@@ -14,9 +14,9 @@ const fetchCheckoutSession = async (id) => {
|
|
|
14
14
|
const { data } = await api.get(`/api/checkout-sessions/retrieve/${id}`);
|
|
15
15
|
return data;
|
|
16
16
|
};
|
|
17
|
-
export default function
|
|
17
|
+
export default function CheckoutForm({ id, onPaid, onError, mode, extraParams }) {
|
|
18
18
|
if (!id.startsWith("plink_") && !id.startsWith("cs_")) {
|
|
19
|
-
throw new Error("Either a
|
|
19
|
+
throw new Error("Either a checkoutSession or a paymentLink id is required.");
|
|
20
20
|
}
|
|
21
21
|
const type = id.startsWith("plink_") ? "paymentLink" : "checkoutSession";
|
|
22
22
|
const [state, setState] = useSetState({ completed: false, appError: null });
|
|
@@ -53,7 +53,7 @@ export default function Checkout({ id, onPaid, onError, mode, extraParams }) {
|
|
|
53
53
|
}
|
|
54
54
|
);
|
|
55
55
|
}
|
|
56
|
-
|
|
56
|
+
CheckoutForm.defaultProps = {
|
|
57
57
|
onPaid: noop,
|
|
58
58
|
onError: console.error,
|
|
59
59
|
mode: "inline",
|
|
@@ -0,0 +1,71 @@
|
|
|
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 { Alert, Stack, Typography } from "@mui/material";
|
|
5
|
+
import { useRequest } from "ahooks";
|
|
6
|
+
import { useState } from "react";
|
|
7
|
+
import api from "../api.js";
|
|
8
|
+
import Livemode from "../components/livemode.js";
|
|
9
|
+
import PricingTable from "../components/pricing-table.js";
|
|
10
|
+
import ProductSkeleton from "../payment/product-skeleton.js";
|
|
11
|
+
import { mergeExtraParams } from "../util.js";
|
|
12
|
+
import CheckoutForm from "./form.js";
|
|
13
|
+
const fetchData = async (id) => {
|
|
14
|
+
const { data } = await api.get(`/api/pricing-tables/${id}`);
|
|
15
|
+
return data;
|
|
16
|
+
};
|
|
17
|
+
export default function CheckoutTable({ id, onPaid, onError, mode, extraParams }) {
|
|
18
|
+
if (!id.startsWith("prctbl_")) {
|
|
19
|
+
throw new Error("A valid pricing table id is required.");
|
|
20
|
+
}
|
|
21
|
+
const { t } = useLocaleContext();
|
|
22
|
+
const [sessionId, setSessionId] = useState("");
|
|
23
|
+
const { error, loading, data } = useRequest(() => fetchData(id));
|
|
24
|
+
if (error) {
|
|
25
|
+
return /* @__PURE__ */ jsx(Alert, { severity: "error", children: error.message });
|
|
26
|
+
}
|
|
27
|
+
if (loading || !data) {
|
|
28
|
+
return /* @__PURE__ */ jsxs(
|
|
29
|
+
Stack,
|
|
30
|
+
{
|
|
31
|
+
flexWrap: "wrap",
|
|
32
|
+
direction: "row",
|
|
33
|
+
gap: { xs: 3, sm: 5, md: mode === "checkout" ? 10 : 5 },
|
|
34
|
+
justifyContent: "center",
|
|
35
|
+
children: [
|
|
36
|
+
/* @__PURE__ */ jsx(ProductSkeleton, { count: 2 }, 1),
|
|
37
|
+
/* @__PURE__ */ jsx(ProductSkeleton, { count: 3 }, 2),
|
|
38
|
+
/* @__PURE__ */ jsx(ProductSkeleton, { count: 4 }, 3)
|
|
39
|
+
]
|
|
40
|
+
}
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
if (data.items.length === 0) {
|
|
44
|
+
return /* @__PURE__ */ jsx(Alert, { severity: "warning", children: t("payment.checkout.noPricing") });
|
|
45
|
+
}
|
|
46
|
+
const handleSelect = (priceId) => {
|
|
47
|
+
api.post(`/api/pricing-tables/${data.id}/checkout/${priceId}?${mergeExtraParams(extraParams)}`).then((res) => {
|
|
48
|
+
if (mode === "standalone") {
|
|
49
|
+
window.location.replace(res.data.url);
|
|
50
|
+
} else {
|
|
51
|
+
setSessionId(res.data.id);
|
|
52
|
+
}
|
|
53
|
+
}).catch((err) => {
|
|
54
|
+
console.error(err);
|
|
55
|
+
Toast.error(err.message);
|
|
56
|
+
});
|
|
57
|
+
};
|
|
58
|
+
if (!sessionId) {
|
|
59
|
+
if (mode === "standalone") {
|
|
60
|
+
return /* @__PURE__ */ jsxs(Stack, { direction: "column", alignItems: "center", spacing: 4, children: [
|
|
61
|
+
/* @__PURE__ */ jsxs(Typography, { variant: "h4", color: "text.primary", fontWeight: 600, children: [
|
|
62
|
+
data.name,
|
|
63
|
+
!data.livemode && /* @__PURE__ */ jsx(Livemode, {})
|
|
64
|
+
] }),
|
|
65
|
+
/* @__PURE__ */ jsx(PricingTable, { table: data, onSelect: handleSelect })
|
|
66
|
+
] });
|
|
67
|
+
}
|
|
68
|
+
return /* @__PURE__ */ jsx(PricingTable, { mode: "select", table: data, onSelect: handleSelect });
|
|
69
|
+
}
|
|
70
|
+
return /* @__PURE__ */ jsx(CheckoutForm, { id: sessionId, onPaid, onError, mode });
|
|
71
|
+
}
|
package/es/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import api from './api';
|
|
2
|
-
import
|
|
2
|
+
import CheckoutForm from './checkout/form';
|
|
3
|
+
import CheckoutTable from './checkout/table';
|
|
3
4
|
import FormInput from './components/input';
|
|
4
5
|
import Livemode from './components/livemode';
|
|
5
6
|
import PricingTable from './components/pricing-table';
|
|
@@ -13,4 +14,4 @@ import ProductSkeleton from './payment/product-skeleton';
|
|
|
13
14
|
export * from './util';
|
|
14
15
|
export * from './contexts/payment';
|
|
15
16
|
export { translations, createTranslator } from './locales';
|
|
16
|
-
export { api, dayjs, FormInput, PhoneInput, Status, Livemode, Switch,
|
|
17
|
+
export { api, dayjs, FormInput, PhoneInput, Status, Livemode, Switch, CheckoutForm, CheckoutTable, Payment, PricingTable, ProductSkeleton, Amount, };
|
package/es/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import api from "./api.js";
|
|
2
|
-
import
|
|
2
|
+
import CheckoutForm from "./checkout/form.js";
|
|
3
|
+
import CheckoutTable from "./checkout/table.js";
|
|
3
4
|
import FormInput from "./components/input.js";
|
|
4
5
|
import Livemode from "./components/livemode.js";
|
|
5
6
|
import PricingTable from "./components/pricing-table.js";
|
|
@@ -21,7 +22,8 @@ export {
|
|
|
21
22
|
Status,
|
|
22
23
|
Livemode,
|
|
23
24
|
Switch,
|
|
24
|
-
|
|
25
|
+
CheckoutForm,
|
|
26
|
+
CheckoutTable,
|
|
25
27
|
Payment,
|
|
26
28
|
PricingTable,
|
|
27
29
|
ProductSkeleton,
|
package/es/payment/form/addon.js
CHANGED
|
@@ -9,6 +9,6 @@ export default function UserButtons() {
|
|
|
9
9
|
const { session } = usePaymentContext();
|
|
10
10
|
return /* @__PURE__ */ jsxs(Stack, { direction: "row", alignItems: "center", justifyContent: "space-between", children: [
|
|
11
11
|
/* @__PURE__ */ jsx(LocaleSelector, { showText: false }),
|
|
12
|
-
session
|
|
12
|
+
session?.user ? /* @__PURE__ */ jsx(SessionManager, { session }) : /* @__PURE__ */ jsx(Tooltip, { title: t("payment.checkout.login"), arrow: true, children: /* @__PURE__ */ jsx(SessionManager, { session }) })
|
|
13
13
|
] });
|
|
14
14
|
}
|
package/es/payment/form/index.js
CHANGED
|
@@ -60,7 +60,7 @@ export default function PaymentForm({
|
|
|
60
60
|
stripePaying: false
|
|
61
61
|
});
|
|
62
62
|
useEffect(() => {
|
|
63
|
-
if (session
|
|
63
|
+
if (session?.user) {
|
|
64
64
|
const values = getValues();
|
|
65
65
|
if (!values.customer_name) {
|
|
66
66
|
setValue("customer_name", session.user.fullName);
|
|
@@ -72,7 +72,7 @@ export default function PaymentForm({
|
|
|
72
72
|
setValue("customer_phone", session.user.phone);
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
|
-
}, [session
|
|
75
|
+
}, [session?.user, getValues, setValue]);
|
|
76
76
|
const paymentMethod = useWatch({ control, name: "payment_method" });
|
|
77
77
|
const paymentCurrency = useWatch({ control, name: "payment_currency" });
|
|
78
78
|
const paymentCurrencies = paymentMethods.find((x) => x.id === paymentMethod)?.payment_currencies || [];
|
|
@@ -86,7 +86,7 @@ export default function PaymentForm({
|
|
|
86
86
|
return false;
|
|
87
87
|
}, [domSize, theme]);
|
|
88
88
|
const payee = getStatementDescriptor(checkoutSession.line_items);
|
|
89
|
-
const buttonText = session
|
|
89
|
+
const buttonText = session?.user ? t(`payment.checkout.${checkoutSession.mode}`) : t("payment.checkout.connect", { action: t(`payment.checkout.${checkoutSession.mode}`) });
|
|
90
90
|
const method = paymentMethods.find((x) => x.id === paymentMethod);
|
|
91
91
|
const handleMethodChange = (e) => {
|
|
92
92
|
setValue("payment_method", e.target.value);
|
|
@@ -190,10 +190,10 @@ export default function PaymentForm({
|
|
|
190
190
|
}
|
|
191
191
|
};
|
|
192
192
|
const onAction = () => {
|
|
193
|
-
if (session
|
|
193
|
+
if (session?.user) {
|
|
194
194
|
handleSubmit(onSubmit)();
|
|
195
195
|
} else {
|
|
196
|
-
session
|
|
196
|
+
session?.login({
|
|
197
197
|
onSuccess: onUserLoggedIn,
|
|
198
198
|
extraParams: {}
|
|
199
199
|
});
|
package/es/payment/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
/// <reference types="react" />
|
|
2
|
+
import { LiteralUnion } from 'type-fest';
|
|
2
3
|
import { CheckoutCallbacks, CheckoutContext } from '../types';
|
|
3
4
|
type Props = CheckoutContext & CheckoutCallbacks & {
|
|
4
5
|
completed?: boolean;
|
|
@@ -24,5 +25,5 @@ export declare namespace PaymentInner {
|
|
|
24
25
|
export declare const Root: import("@emotion/styled").StyledComponent<import("@mui/system").BoxOwnProps<import("@mui/material").Theme> & Omit<Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & {
|
|
25
26
|
ref?: ((instance: HTMLDivElement | null) => void) | import("react").RefObject<HTMLDivElement> | null | undefined;
|
|
26
27
|
}, keyof import("@mui/system").BoxOwnProps<import("@mui/material").Theme>> & import("@mui/system").MUIStyledCommonProps<import("@mui/system").Theme> & {
|
|
27
|
-
mode: string
|
|
28
|
+
mode: LiteralUnion<'standalone' | 'inline' | 'popup', string>;
|
|
28
29
|
}, {}, {}>;
|
package/es/payment/index.js
CHANGED
|
@@ -109,9 +109,9 @@ export function PaymentInner({
|
|
|
109
109
|
const defaultMethodId = paymentMethods.find((m) => m.payment_currencies.some((c) => c.id === defaultCurrencyId))?.id;
|
|
110
110
|
const methods = useForm({
|
|
111
111
|
defaultValues: {
|
|
112
|
-
customer_name: customer?.name || session
|
|
113
|
-
customer_email: customer?.email || session
|
|
114
|
-
customer_phone: customer?.phone || session
|
|
112
|
+
customer_name: customer?.name || session?.user?.fullName || "",
|
|
113
|
+
customer_email: customer?.email || session?.user?.email || "",
|
|
114
|
+
customer_phone: customer?.phone || session?.user?.phone || "",
|
|
115
115
|
payment_method: defaultMethodId,
|
|
116
116
|
payment_currency: defaultCurrencyId,
|
|
117
117
|
billing_address: Object.assign(
|
|
@@ -166,9 +166,9 @@ export function PaymentInner({
|
|
|
166
166
|
Toast.error(formatError(err));
|
|
167
167
|
}
|
|
168
168
|
};
|
|
169
|
-
return /* @__PURE__ */ jsx(FormProvider, { ...methods, children: /* @__PURE__ */ jsx(Root, { mode, children: /* @__PURE__ */ jsxs(Stack, { className: "cko-container", children: [
|
|
169
|
+
return /* @__PURE__ */ jsx(FormProvider, { ...methods, children: /* @__PURE__ */ jsx(Root, { mode, children: /* @__PURE__ */ jsxs(Stack, { className: "cko-container", sx: { gap: { sm: mode === "standalone" ? 0 : 8 } }, children: [
|
|
170
170
|
/* @__PURE__ */ jsx(Fade, { in: true, children: /* @__PURE__ */ jsxs(Stack, { className: "cko-overview", direction: "column", children: [
|
|
171
|
-
/* @__PURE__ */ jsx(PaymentHeader, { checkoutSession: state.checkoutSession }),
|
|
171
|
+
mode === "standalone" ? /* @__PURE__ */ jsx(PaymentHeader, { checkoutSession: state.checkoutSession }) : null,
|
|
172
172
|
/* @__PURE__ */ jsx(
|
|
173
173
|
PaymentSummary,
|
|
174
174
|
{
|
|
@@ -203,7 +203,7 @@ export function PaymentInner({
|
|
|
203
203
|
}
|
|
204
204
|
)
|
|
205
205
|
] }),
|
|
206
|
-
/* @__PURE__ */ jsx(CheckoutFooter, { className: "cko-footer" })
|
|
206
|
+
mode === "standalone" && /* @__PURE__ */ jsx(CheckoutFooter, { className: "cko-footer" })
|
|
207
207
|
] }) }) });
|
|
208
208
|
}
|
|
209
209
|
export const Root = styled(Box)`
|
|
@@ -212,10 +212,10 @@ export const Root = styled(Box)`
|
|
|
212
212
|
flex-direction: column;
|
|
213
213
|
justify-content: center;
|
|
214
214
|
align-items: center;
|
|
215
|
-
min-height: 100vh;
|
|
215
|
+
min-height: ${(props) => props.mode === "standalone" ? "100vh" : "auto"};
|
|
216
216
|
position: relative;
|
|
217
217
|
|
|
218
|
-
|
|
218
|
+
${(props) => props.mode === "standalone" ? `&:before {
|
|
219
219
|
animation-fill-mode: both;
|
|
220
220
|
background: #ffffff;
|
|
221
221
|
content: '';
|
|
@@ -226,7 +226,7 @@ export const Root = styled(Box)`
|
|
|
226
226
|
transform-origin: right;
|
|
227
227
|
width: 50%;
|
|
228
228
|
box-shadow: 15px 0 30px 0 rgba(0, 0, 0, 0.18);
|
|
229
|
-
}
|
|
229
|
+
}` : ""}
|
|
230
230
|
|
|
231
231
|
.cko-container {
|
|
232
232
|
width: 100%;
|
|
@@ -235,12 +235,12 @@ export const Root = styled(Box)`
|
|
|
235
235
|
flex-direction: row;
|
|
236
236
|
justify-content: space-between;
|
|
237
237
|
position: relative;
|
|
238
|
-
padding: 0 16px;
|
|
238
|
+
padding: ${(props) => props.mode === "standalone" ? "0 16px" : "0"};
|
|
239
239
|
}
|
|
240
240
|
|
|
241
241
|
.cko-overview {
|
|
242
242
|
width: 400px;
|
|
243
|
-
min-height: 540px;
|
|
243
|
+
min-height: ${(props) => props.mode === "standalone" ? "540px" : "auto"};
|
|
244
244
|
position: relative;
|
|
245
245
|
}
|
|
246
246
|
.cko-header {
|
|
@@ -251,6 +251,9 @@ export const Root = styled(Box)`
|
|
|
251
251
|
top: 0;
|
|
252
252
|
transition: background-color 0.15s ease, box-shadow 0.15s ease-out;
|
|
253
253
|
}
|
|
254
|
+
.cko-product {
|
|
255
|
+
margin-top: ${(props) => props.mode === "standalone" ? "64px" : "0"};
|
|
256
|
+
}
|
|
254
257
|
.cko-product-summary {
|
|
255
258
|
}
|
|
256
259
|
|
package/es/payment/summary.js
CHANGED
|
@@ -90,89 +90,79 @@ export default function PaymentSummary({
|
|
|
90
90
|
setState({ loading: false });
|
|
91
91
|
}
|
|
92
92
|
};
|
|
93
|
-
return /* @__PURE__ */ jsx(Fade, { in: true, children: /* @__PURE__ */ jsxs(
|
|
94
|
-
Stack,
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
93
|
+
return /* @__PURE__ */ jsx(Fade, { in: true, children: /* @__PURE__ */ jsxs(Stack, { className: "cko-product", direction: "column", children: [
|
|
94
|
+
/* @__PURE__ */ jsxs(Stack, { className: "cko-product-summary", direction: "column", alignItems: "flex-start", sx: { mb: 4 }, children: [
|
|
95
|
+
/* @__PURE__ */ jsx(Typography, { sx: { fontWeight: 500, fontSize: "1.15rem", color: "text.secondary" }, children: headlines.action }),
|
|
96
|
+
/* @__PURE__ */ jsx(PaymentAmount, { amount: headlines.amount }),
|
|
97
|
+
headlines.then && /* @__PURE__ */ jsx(Typography, { sx: { fontSize: "0.9rem", color: "text.secondary" }, children: headlines.then })
|
|
98
|
+
] }),
|
|
99
|
+
/* @__PURE__ */ jsx(Stack, { spacing: 2, children: checkoutSession.line_items.map((x) => /* @__PURE__ */ jsx(
|
|
100
|
+
ProductItem,
|
|
101
|
+
{
|
|
102
|
+
item: x,
|
|
103
|
+
session: checkoutSession,
|
|
104
|
+
currency,
|
|
105
|
+
onUpsell: handleUpsell,
|
|
106
|
+
onDownsell: handleDownsell,
|
|
107
|
+
children: x.cross_sell && /* @__PURE__ */ jsx(
|
|
108
|
+
LoadingButton,
|
|
109
109
|
{
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
110
|
+
size: "small",
|
|
111
|
+
loadingPosition: "end",
|
|
112
|
+
color: "error",
|
|
113
|
+
variant: "text",
|
|
114
|
+
loading: state.loading,
|
|
115
|
+
onClick: handleCancelCrossSell,
|
|
116
|
+
children: t("payment.checkout.cross_sell.remove")
|
|
117
|
+
}
|
|
118
|
+
)
|
|
119
|
+
},
|
|
120
|
+
x.price_id
|
|
121
|
+
)) }),
|
|
122
|
+
data && checkoutSession.line_items.some((x) => x.price_id === data.id) === false && /* @__PURE__ */ jsx(Grow, { in: true, children: /* @__PURE__ */ jsxs(
|
|
123
|
+
Stack,
|
|
124
|
+
{
|
|
125
|
+
direction: "column",
|
|
126
|
+
alignItems: "flex-end",
|
|
127
|
+
spacing: 0.5,
|
|
128
|
+
sx: {
|
|
129
|
+
border: "1px solid #eee",
|
|
130
|
+
borderRadius: 1,
|
|
131
|
+
padding: 1,
|
|
132
|
+
animation: state.shake ? `${shake} 0.2s 5 ease-in-out` : "none",
|
|
133
|
+
mt: {
|
|
134
|
+
xs: 4,
|
|
135
|
+
md: 8
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
children: [
|
|
139
|
+
/* @__PURE__ */ jsx(
|
|
140
|
+
ProductItem,
|
|
141
|
+
{
|
|
142
|
+
item: { quantity: 1, price: data, price_id: data.id, cross_sell: true },
|
|
143
|
+
session: checkoutSession,
|
|
144
|
+
currency,
|
|
145
|
+
onUpsell: noop,
|
|
146
|
+
onDownsell: noop
|
|
147
|
+
}
|
|
148
|
+
),
|
|
149
|
+
/* @__PURE__ */ jsxs(Stack, { direction: "row", alignItems: "center", justifyContent: "space-between", sx: { width: 1 }, children: [
|
|
150
|
+
/* @__PURE__ */ jsx(Typography, { children: checkoutSession.cross_sell_behavior === "required" && /* @__PURE__ */ jsx(Status, { label: t("payment.checkout.required"), color: "info", variant: "outlined", sx: { mr: 1 } }) }),
|
|
151
|
+
/* @__PURE__ */ jsx(
|
|
116
152
|
LoadingButton,
|
|
117
153
|
{
|
|
118
154
|
size: "small",
|
|
119
155
|
loadingPosition: "end",
|
|
120
|
-
color: "
|
|
121
|
-
variant: "text",
|
|
156
|
+
color: checkoutSession.cross_sell_behavior === "required" ? "info" : "info",
|
|
157
|
+
variant: checkoutSession.cross_sell_behavior === "required" ? "text" : "text",
|
|
122
158
|
loading: state.loading,
|
|
123
|
-
onClick:
|
|
124
|
-
children: t("payment.checkout.cross_sell.
|
|
159
|
+
onClick: handleApplyCrossSell,
|
|
160
|
+
children: t("payment.checkout.cross_sell.add")
|
|
125
161
|
}
|
|
126
162
|
)
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
{
|
|
133
|
-
direction: "column",
|
|
134
|
-
alignItems: "flex-end",
|
|
135
|
-
spacing: 0.5,
|
|
136
|
-
sx: {
|
|
137
|
-
border: "1px solid #eee",
|
|
138
|
-
borderRadius: 1,
|
|
139
|
-
padding: 1,
|
|
140
|
-
animation: state.shake ? `${shake} 0.2s 5 ease-in-out` : "none",
|
|
141
|
-
mt: {
|
|
142
|
-
xs: 4,
|
|
143
|
-
md: 8
|
|
144
|
-
}
|
|
145
|
-
},
|
|
146
|
-
children: [
|
|
147
|
-
/* @__PURE__ */ jsx(
|
|
148
|
-
ProductItem,
|
|
149
|
-
{
|
|
150
|
-
item: { quantity: 1, price: data, price_id: data.id, cross_sell: true },
|
|
151
|
-
session: checkoutSession,
|
|
152
|
-
currency,
|
|
153
|
-
onUpsell: noop,
|
|
154
|
-
onDownsell: noop
|
|
155
|
-
}
|
|
156
|
-
),
|
|
157
|
-
/* @__PURE__ */ jsxs(Stack, { direction: "row", alignItems: "center", justifyContent: "space-between", sx: { width: 1 }, children: [
|
|
158
|
-
/* @__PURE__ */ jsx(Typography, { children: checkoutSession.cross_sell_behavior === "required" && /* @__PURE__ */ jsx(Status, { label: t("payment.checkout.required"), color: "info", variant: "outlined", sx: { mr: 1 } }) }),
|
|
159
|
-
/* @__PURE__ */ jsx(
|
|
160
|
-
LoadingButton,
|
|
161
|
-
{
|
|
162
|
-
size: "small",
|
|
163
|
-
loadingPosition: "end",
|
|
164
|
-
color: checkoutSession.cross_sell_behavior === "required" ? "info" : "info",
|
|
165
|
-
variant: checkoutSession.cross_sell_behavior === "required" ? "text" : "text",
|
|
166
|
-
loading: state.loading,
|
|
167
|
-
onClick: handleApplyCrossSell,
|
|
168
|
-
children: t("payment.checkout.cross_sell.add")
|
|
169
|
-
}
|
|
170
|
-
)
|
|
171
|
-
] })
|
|
172
|
-
]
|
|
173
|
-
}
|
|
174
|
-
) })
|
|
175
|
-
]
|
|
176
|
-
}
|
|
177
|
-
) });
|
|
163
|
+
] })
|
|
164
|
+
]
|
|
165
|
+
}
|
|
166
|
+
) })
|
|
167
|
+
] }) });
|
|
178
168
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/// <reference types="react" />
|
|
2
2
|
import { CheckoutProps } from '../types';
|
|
3
|
-
declare function
|
|
4
|
-
declare namespace
|
|
3
|
+
declare function CheckoutForm({ id, onPaid, onError, mode, extraParams }: CheckoutProps): import("react").JSX.Element;
|
|
4
|
+
declare namespace CheckoutForm {
|
|
5
5
|
var defaultProps: {
|
|
6
6
|
onPaid: any;
|
|
7
7
|
onError: {
|
|
@@ -12,4 +12,4 @@ declare namespace Checkout {
|
|
|
12
12
|
extraParams: {};
|
|
13
13
|
};
|
|
14
14
|
}
|
|
15
|
-
export default
|
|
15
|
+
export default CheckoutForm;
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
module.exports =
|
|
6
|
+
module.exports = CheckoutForm;
|
|
7
7
|
var _jsxRuntime = require("react/jsx-runtime");
|
|
8
8
|
var _ahooks = require("ahooks");
|
|
9
9
|
var _noop = _interopRequireDefault(require("lodash/noop"));
|
|
@@ -25,7 +25,7 @@ const fetchCheckoutSession = async id => {
|
|
|
25
25
|
} = await _api.default.get(`/api/checkout-sessions/retrieve/${id}`);
|
|
26
26
|
return data;
|
|
27
27
|
};
|
|
28
|
-
function
|
|
28
|
+
function CheckoutForm({
|
|
29
29
|
id,
|
|
30
30
|
onPaid,
|
|
31
31
|
onError,
|
|
@@ -33,7 +33,7 @@ function Checkout({
|
|
|
33
33
|
extraParams
|
|
34
34
|
}) {
|
|
35
35
|
if (!id.startsWith("plink_") && !id.startsWith("cs_")) {
|
|
36
|
-
throw new Error("Either a
|
|
36
|
+
throw new Error("Either a checkoutSession or a paymentLink id is required.");
|
|
37
37
|
}
|
|
38
38
|
const type = id.startsWith("plink_") ? "paymentLink" : "checkoutSession";
|
|
39
39
|
const [state, setState] = (0, _ahooks.useSetState)({
|
|
@@ -75,7 +75,7 @@ function Checkout({
|
|
|
75
75
|
mode
|
|
76
76
|
});
|
|
77
77
|
}
|
|
78
|
-
|
|
78
|
+
CheckoutForm.defaultProps = {
|
|
79
79
|
onPaid: _noop.default,
|
|
80
80
|
onError: console.error,
|
|
81
81
|
mode: "inline",
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
module.exports = CheckoutTable;
|
|
7
|
+
var _jsxRuntime = require("react/jsx-runtime");
|
|
8
|
+
var _context = require("@arcblock/ux/lib/Locale/context");
|
|
9
|
+
var _Toast = _interopRequireDefault(require("@arcblock/ux/lib/Toast"));
|
|
10
|
+
var _material = require("@mui/material");
|
|
11
|
+
var _ahooks = require("ahooks");
|
|
12
|
+
var _react = require("react");
|
|
13
|
+
var _api = _interopRequireDefault(require("../api"));
|
|
14
|
+
var _livemode = _interopRequireDefault(require("../components/livemode"));
|
|
15
|
+
var _pricingTable = _interopRequireDefault(require("../components/pricing-table"));
|
|
16
|
+
var _productSkeleton = _interopRequireDefault(require("../payment/product-skeleton"));
|
|
17
|
+
var _util = require("../util");
|
|
18
|
+
var _form = _interopRequireDefault(require("./form"));
|
|
19
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
20
|
+
const fetchData = async id => {
|
|
21
|
+
const {
|
|
22
|
+
data
|
|
23
|
+
} = await _api.default.get(`/api/pricing-tables/${id}`);
|
|
24
|
+
return data;
|
|
25
|
+
};
|
|
26
|
+
function CheckoutTable({
|
|
27
|
+
id,
|
|
28
|
+
onPaid,
|
|
29
|
+
onError,
|
|
30
|
+
mode,
|
|
31
|
+
extraParams
|
|
32
|
+
}) {
|
|
33
|
+
if (!id.startsWith("prctbl_")) {
|
|
34
|
+
throw new Error("A valid pricing table id is required.");
|
|
35
|
+
}
|
|
36
|
+
const {
|
|
37
|
+
t
|
|
38
|
+
} = (0, _context.useLocaleContext)();
|
|
39
|
+
const [sessionId, setSessionId] = (0, _react.useState)("");
|
|
40
|
+
const {
|
|
41
|
+
error,
|
|
42
|
+
loading,
|
|
43
|
+
data
|
|
44
|
+
} = (0, _ahooks.useRequest)(() => fetchData(id));
|
|
45
|
+
if (error) {
|
|
46
|
+
return /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Alert, {
|
|
47
|
+
severity: "error",
|
|
48
|
+
children: error.message
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
if (loading || !data) {
|
|
52
|
+
return /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Stack, {
|
|
53
|
+
flexWrap: "wrap",
|
|
54
|
+
direction: "row",
|
|
55
|
+
gap: {
|
|
56
|
+
xs: 3,
|
|
57
|
+
sm: 5,
|
|
58
|
+
md: mode === "checkout" ? 10 : 5
|
|
59
|
+
},
|
|
60
|
+
justifyContent: "center",
|
|
61
|
+
children: [/* @__PURE__ */(0, _jsxRuntime.jsx)(_productSkeleton.default, {
|
|
62
|
+
count: 2
|
|
63
|
+
}, 1), /* @__PURE__ */(0, _jsxRuntime.jsx)(_productSkeleton.default, {
|
|
64
|
+
count: 3
|
|
65
|
+
}, 2), /* @__PURE__ */(0, _jsxRuntime.jsx)(_productSkeleton.default, {
|
|
66
|
+
count: 4
|
|
67
|
+
}, 3)]
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
if (data.items.length === 0) {
|
|
71
|
+
return /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Alert, {
|
|
72
|
+
severity: "warning",
|
|
73
|
+
children: t("payment.checkout.noPricing")
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
const handleSelect = priceId => {
|
|
77
|
+
_api.default.post(`/api/pricing-tables/${data.id}/checkout/${priceId}?${(0, _util.mergeExtraParams)(extraParams)}`).then(res => {
|
|
78
|
+
if (mode === "standalone") {
|
|
79
|
+
window.location.replace(res.data.url);
|
|
80
|
+
} else {
|
|
81
|
+
setSessionId(res.data.id);
|
|
82
|
+
}
|
|
83
|
+
}).catch(err => {
|
|
84
|
+
console.error(err);
|
|
85
|
+
_Toast.default.error(err.message);
|
|
86
|
+
});
|
|
87
|
+
};
|
|
88
|
+
if (!sessionId) {
|
|
89
|
+
if (mode === "standalone") {
|
|
90
|
+
return /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Stack, {
|
|
91
|
+
direction: "column",
|
|
92
|
+
alignItems: "center",
|
|
93
|
+
spacing: 4,
|
|
94
|
+
children: [/* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Typography, {
|
|
95
|
+
variant: "h4",
|
|
96
|
+
color: "text.primary",
|
|
97
|
+
fontWeight: 600,
|
|
98
|
+
children: [data.name, !data.livemode && /* @__PURE__ */(0, _jsxRuntime.jsx)(_livemode.default, {})]
|
|
99
|
+
}), /* @__PURE__ */(0, _jsxRuntime.jsx)(_pricingTable.default, {
|
|
100
|
+
table: data,
|
|
101
|
+
onSelect: handleSelect
|
|
102
|
+
})]
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
return /* @__PURE__ */(0, _jsxRuntime.jsx)(_pricingTable.default, {
|
|
106
|
+
mode: "select",
|
|
107
|
+
table: data,
|
|
108
|
+
onSelect: handleSelect
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
return /* @__PURE__ */(0, _jsxRuntime.jsx)(_form.default, {
|
|
112
|
+
id: sessionId,
|
|
113
|
+
onPaid,
|
|
114
|
+
onError,
|
|
115
|
+
mode
|
|
116
|
+
});
|
|
117
|
+
}
|
package/lib/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import api from './api';
|
|
2
|
-
import
|
|
2
|
+
import CheckoutForm from './checkout/form';
|
|
3
|
+
import CheckoutTable from './checkout/table';
|
|
3
4
|
import FormInput from './components/input';
|
|
4
5
|
import Livemode from './components/livemode';
|
|
5
6
|
import PricingTable from './components/pricing-table';
|
|
@@ -13,4 +14,4 @@ import ProductSkeleton from './payment/product-skeleton';
|
|
|
13
14
|
export * from './util';
|
|
14
15
|
export * from './contexts/payment';
|
|
15
16
|
export { translations, createTranslator } from './locales';
|
|
16
|
-
export { api, dayjs, FormInput, PhoneInput, Status, Livemode, Switch,
|
|
17
|
+
export { api, dayjs, FormInput, PhoneInput, Status, Livemode, Switch, CheckoutForm, CheckoutTable, Payment, PricingTable, ProductSkeleton, Amount, };
|
package/lib/index.js
CHANGED
|
@@ -5,7 +5,8 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
var _exportNames = {
|
|
7
7
|
api: true,
|
|
8
|
-
|
|
8
|
+
CheckoutForm: true,
|
|
9
|
+
CheckoutTable: true,
|
|
9
10
|
FormInput: true,
|
|
10
11
|
Livemode: true,
|
|
11
12
|
PricingTable: true,
|
|
@@ -25,10 +26,16 @@ Object.defineProperty(exports, "Amount", {
|
|
|
25
26
|
return _amount.default;
|
|
26
27
|
}
|
|
27
28
|
});
|
|
28
|
-
Object.defineProperty(exports, "
|
|
29
|
+
Object.defineProperty(exports, "CheckoutForm", {
|
|
29
30
|
enumerable: true,
|
|
30
31
|
get: function () {
|
|
31
|
-
return
|
|
32
|
+
return _form.default;
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
Object.defineProperty(exports, "CheckoutTable", {
|
|
36
|
+
enumerable: true,
|
|
37
|
+
get: function () {
|
|
38
|
+
return _table.default;
|
|
32
39
|
}
|
|
33
40
|
});
|
|
34
41
|
Object.defineProperty(exports, "FormInput", {
|
|
@@ -104,7 +111,8 @@ Object.defineProperty(exports, "translations", {
|
|
|
104
111
|
}
|
|
105
112
|
});
|
|
106
113
|
var _api = _interopRequireDefault(require("./api"));
|
|
107
|
-
var
|
|
114
|
+
var _form = _interopRequireDefault(require("./checkout/form"));
|
|
115
|
+
var _table = _interopRequireDefault(require("./checkout/table"));
|
|
108
116
|
var _input = _interopRequireDefault(require("./components/input"));
|
|
109
117
|
var _livemode = _interopRequireDefault(require("./components/livemode"));
|
|
110
118
|
var _pricingTable = _interopRequireDefault(require("./components/pricing-table"));
|
|
@@ -24,7 +24,7 @@ function UserButtons() {
|
|
|
24
24
|
justifyContent: "space-between",
|
|
25
25
|
children: [/* @__PURE__ */(0, _jsxRuntime.jsx)(_selector.default, {
|
|
26
26
|
showText: false
|
|
27
|
-
}), session
|
|
27
|
+
}), session?.user ? /* @__PURE__ */(0, _jsxRuntime.jsx)(_SessionManager.default, {
|
|
28
28
|
session
|
|
29
29
|
}) : /* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Tooltip, {
|
|
30
30
|
title: t("payment.checkout.login"),
|
|
@@ -79,7 +79,7 @@ function PaymentForm({
|
|
|
79
79
|
stripePaying: false
|
|
80
80
|
});
|
|
81
81
|
(0, _react.useEffect)(() => {
|
|
82
|
-
if (session
|
|
82
|
+
if (session?.user) {
|
|
83
83
|
const values = getValues();
|
|
84
84
|
if (!values.customer_name) {
|
|
85
85
|
setValue("customer_name", session.user.fullName);
|
|
@@ -91,7 +91,7 @@ function PaymentForm({
|
|
|
91
91
|
setValue("customer_phone", session.user.phone);
|
|
92
92
|
}
|
|
93
93
|
}
|
|
94
|
-
}, [session
|
|
94
|
+
}, [session?.user, getValues, setValue]);
|
|
95
95
|
const paymentMethod = (0, _reactHookForm.useWatch)({
|
|
96
96
|
control,
|
|
97
97
|
name: "payment_method"
|
|
@@ -111,7 +111,7 @@ function PaymentForm({
|
|
|
111
111
|
return false;
|
|
112
112
|
}, [domSize, theme]);
|
|
113
113
|
const payee = (0, _util.getStatementDescriptor)(checkoutSession.line_items);
|
|
114
|
-
const buttonText = session
|
|
114
|
+
const buttonText = session?.user ? t(`payment.checkout.${checkoutSession.mode}`) : t("payment.checkout.connect", {
|
|
115
115
|
action: t(`payment.checkout.${checkoutSession.mode}`)
|
|
116
116
|
});
|
|
117
117
|
const method = paymentMethods.find(x => x.id === paymentMethod);
|
|
@@ -242,10 +242,10 @@ function PaymentForm({
|
|
|
242
242
|
}
|
|
243
243
|
};
|
|
244
244
|
const onAction = () => {
|
|
245
|
-
if (session
|
|
245
|
+
if (session?.user) {
|
|
246
246
|
handleSubmit(onSubmit)();
|
|
247
247
|
} else {
|
|
248
|
-
session
|
|
248
|
+
session?.login({
|
|
249
249
|
onSuccess: onUserLoggedIn,
|
|
250
250
|
extraParams: {}
|
|
251
251
|
});
|
package/lib/payment/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
/// <reference types="react" />
|
|
2
|
+
import { LiteralUnion } from 'type-fest';
|
|
2
3
|
import { CheckoutCallbacks, CheckoutContext } from '../types';
|
|
3
4
|
type Props = CheckoutContext & CheckoutCallbacks & {
|
|
4
5
|
completed?: boolean;
|
|
@@ -24,5 +25,5 @@ export declare namespace PaymentInner {
|
|
|
24
25
|
export declare const Root: import("@emotion/styled").StyledComponent<import("@mui/system").BoxOwnProps<import("@mui/material").Theme> & Omit<Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & {
|
|
25
26
|
ref?: ((instance: HTMLDivElement | null) => void) | import("react").RefObject<HTMLDivElement> | null | undefined;
|
|
26
27
|
}, keyof import("@mui/system").BoxOwnProps<import("@mui/material").Theme>> & import("@mui/system").MUIStyledCommonProps<import("@mui/system").Theme> & {
|
|
27
|
-
mode: string
|
|
28
|
+
mode: LiteralUnion<'standalone' | 'inline' | 'popup', string>;
|
|
28
29
|
}, {}, {}>;
|
package/lib/payment/index.js
CHANGED
|
@@ -135,9 +135,9 @@ function PaymentInner({
|
|
|
135
135
|
const defaultMethodId = paymentMethods.find(m => m.payment_currencies.some(c => c.id === defaultCurrencyId))?.id;
|
|
136
136
|
const methods = (0, _reactHookForm.useForm)({
|
|
137
137
|
defaultValues: {
|
|
138
|
-
customer_name: customer?.name || session
|
|
139
|
-
customer_email: customer?.email || session
|
|
140
|
-
customer_phone: customer?.phone || session
|
|
138
|
+
customer_name: customer?.name || session?.user?.fullName || "",
|
|
139
|
+
customer_email: customer?.email || session?.user?.email || "",
|
|
140
|
+
customer_phone: customer?.phone || session?.user?.phone || "",
|
|
141
141
|
payment_method: defaultMethodId,
|
|
142
142
|
payment_currency: defaultCurrencyId,
|
|
143
143
|
billing_address: Object.assign({
|
|
@@ -219,14 +219,19 @@ function PaymentInner({
|
|
|
219
219
|
mode,
|
|
220
220
|
children: /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Stack, {
|
|
221
221
|
className: "cko-container",
|
|
222
|
+
sx: {
|
|
223
|
+
gap: {
|
|
224
|
+
sm: mode === "standalone" ? 0 : 8
|
|
225
|
+
}
|
|
226
|
+
},
|
|
222
227
|
children: [/* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Fade, {
|
|
223
228
|
in: true,
|
|
224
229
|
children: /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Stack, {
|
|
225
230
|
className: "cko-overview",
|
|
226
231
|
direction: "column",
|
|
227
|
-
children: [/* @__PURE__ */(0, _jsxRuntime.jsx)(_header.default, {
|
|
232
|
+
children: [mode === "standalone" ? /* @__PURE__ */(0, _jsxRuntime.jsx)(_header.default, {
|
|
228
233
|
checkoutSession: state.checkoutSession
|
|
229
|
-
}), /* @__PURE__ */(0, _jsxRuntime.jsx)(_summary.default, {
|
|
234
|
+
}) : null, /* @__PURE__ */(0, _jsxRuntime.jsx)(_summary.default, {
|
|
230
235
|
checkoutSession: state.checkoutSession,
|
|
231
236
|
currency,
|
|
232
237
|
onUpsell,
|
|
@@ -252,7 +257,7 @@ function PaymentInner({
|
|
|
252
257
|
onError,
|
|
253
258
|
mode
|
|
254
259
|
})]
|
|
255
|
-
}), /* @__PURE__ */(0, _jsxRuntime.jsx)(_footer.default, {
|
|
260
|
+
}), mode === "standalone" && /* @__PURE__ */(0, _jsxRuntime.jsx)(_footer.default, {
|
|
256
261
|
className: "cko-footer"
|
|
257
262
|
})]
|
|
258
263
|
})
|
|
@@ -265,10 +270,10 @@ const Root = exports.Root = (0, _system.styled)(_material.Box)`
|
|
|
265
270
|
flex-direction: column;
|
|
266
271
|
justify-content: center;
|
|
267
272
|
align-items: center;
|
|
268
|
-
min-height: 100vh;
|
|
273
|
+
min-height: ${props => props.mode === "standalone" ? "100vh" : "auto"};
|
|
269
274
|
position: relative;
|
|
270
275
|
|
|
271
|
-
|
|
276
|
+
${props => props.mode === "standalone" ? `&:before {
|
|
272
277
|
animation-fill-mode: both;
|
|
273
278
|
background: #ffffff;
|
|
274
279
|
content: '';
|
|
@@ -279,7 +284,7 @@ const Root = exports.Root = (0, _system.styled)(_material.Box)`
|
|
|
279
284
|
transform-origin: right;
|
|
280
285
|
width: 50%;
|
|
281
286
|
box-shadow: 15px 0 30px 0 rgba(0, 0, 0, 0.18);
|
|
282
|
-
}
|
|
287
|
+
}` : ""}
|
|
283
288
|
|
|
284
289
|
.cko-container {
|
|
285
290
|
width: 100%;
|
|
@@ -288,12 +293,12 @@ const Root = exports.Root = (0, _system.styled)(_material.Box)`
|
|
|
288
293
|
flex-direction: row;
|
|
289
294
|
justify-content: space-between;
|
|
290
295
|
position: relative;
|
|
291
|
-
padding: 0 16px;
|
|
296
|
+
padding: ${props => props.mode === "standalone" ? "0 16px" : "0"};
|
|
292
297
|
}
|
|
293
298
|
|
|
294
299
|
.cko-overview {
|
|
295
300
|
width: 400px;
|
|
296
|
-
min-height: 540px;
|
|
301
|
+
min-height: ${props => props.mode === "standalone" ? "540px" : "auto"};
|
|
297
302
|
position: relative;
|
|
298
303
|
}
|
|
299
304
|
.cko-header {
|
|
@@ -304,6 +309,9 @@ const Root = exports.Root = (0, _system.styled)(_material.Box)`
|
|
|
304
309
|
top: 0;
|
|
305
310
|
transition: background-color 0.15s ease, box-shadow 0.15s ease-out;
|
|
306
311
|
}
|
|
312
|
+
.cko-product {
|
|
313
|
+
margin-top: ${props => props.mode === "standalone" ? "64px" : "0"};
|
|
314
|
+
}
|
|
307
315
|
.cko-product-summary {
|
|
308
316
|
}
|
|
309
317
|
|
package/lib/payment/summary.js
CHANGED
|
@@ -121,9 +121,6 @@ function PaymentSummary({
|
|
|
121
121
|
children: /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Stack, {
|
|
122
122
|
className: "cko-product",
|
|
123
123
|
direction: "column",
|
|
124
|
-
sx: {
|
|
125
|
-
mt: 8
|
|
126
|
-
},
|
|
127
124
|
children: [/* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Stack, {
|
|
128
125
|
className: "cko-product-summary",
|
|
129
126
|
direction: "column",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blocklet/payment-react",
|
|
3
|
-
"version": "1.13.
|
|
3
|
+
"version": "1.13.115",
|
|
4
4
|
"description": "Reusable react components for payment kit v2",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react",
|
|
@@ -86,7 +86,7 @@
|
|
|
86
86
|
"@babel/core": "^7.19.3",
|
|
87
87
|
"@babel/preset-env": "^7.19.3",
|
|
88
88
|
"@babel/preset-react": "^7.18.6",
|
|
89
|
-
"@blocklet/payment-types": "1.13.
|
|
89
|
+
"@blocklet/payment-types": "1.13.115",
|
|
90
90
|
"@types/react": "^18.2.42",
|
|
91
91
|
"@types/react-dom": "^18.2.17",
|
|
92
92
|
"eslint": "^8.56.0",
|
|
@@ -100,5 +100,5 @@
|
|
|
100
100
|
"typescript": "^4.9.5",
|
|
101
101
|
"unbuild": "^2.0.0"
|
|
102
102
|
},
|
|
103
|
-
"gitHead": "
|
|
103
|
+
"gitHead": "60a62f67098162dcba38edb26b6efbacdb98dd00"
|
|
104
104
|
}
|
|
@@ -20,9 +20,10 @@ const fetchCheckoutSession = async (id: string): Promise<CheckoutContext> => {
|
|
|
20
20
|
return data;
|
|
21
21
|
};
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
// FIXME: @wangshijun support popup
|
|
24
|
+
export default function CheckoutForm({ id, onPaid, onError, mode, extraParams }: CheckoutProps) {
|
|
24
25
|
if (!id.startsWith('plink_') && !id.startsWith('cs_')) {
|
|
25
|
-
throw new Error('Either a
|
|
26
|
+
throw new Error('Either a checkoutSession or a paymentLink id is required.');
|
|
26
27
|
}
|
|
27
28
|
|
|
28
29
|
const type = id.startsWith('plink_') ? 'paymentLink' : 'checkoutSession';
|
|
@@ -66,7 +67,7 @@ export default function Checkout({ id, onPaid, onError, mode, extraParams }: Che
|
|
|
66
67
|
);
|
|
67
68
|
}
|
|
68
69
|
|
|
69
|
-
|
|
70
|
+
CheckoutForm.defaultProps = {
|
|
70
71
|
onPaid: noop,
|
|
71
72
|
onError: console.error,
|
|
72
73
|
mode: 'inline',
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
|
|
2
|
+
import Toast from '@arcblock/ux/lib/Toast';
|
|
3
|
+
import type { TPricingTableExpanded } from '@blocklet/payment-types';
|
|
4
|
+
import { Alert, Stack, Typography } from '@mui/material';
|
|
5
|
+
import { useRequest } from 'ahooks';
|
|
6
|
+
import { useState } from 'react';
|
|
7
|
+
|
|
8
|
+
import api from '../api';
|
|
9
|
+
import Livemode from '../components/livemode';
|
|
10
|
+
import PricingTable from '../components/pricing-table';
|
|
11
|
+
import ProductSkeleton from '../payment/product-skeleton';
|
|
12
|
+
import { CheckoutProps } from '../types';
|
|
13
|
+
import { mergeExtraParams } from '../util';
|
|
14
|
+
import CheckoutForm from './form';
|
|
15
|
+
|
|
16
|
+
const fetchData = async (id: string): Promise<TPricingTableExpanded> => {
|
|
17
|
+
const { data } = await api.get(`/api/pricing-tables/${id}`);
|
|
18
|
+
return data;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export default function CheckoutTable({ id, onPaid, onError, mode, extraParams }: CheckoutProps) {
|
|
22
|
+
if (!id.startsWith('prctbl_')) {
|
|
23
|
+
throw new Error('A valid pricing table id is required.');
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const { t } = useLocaleContext();
|
|
27
|
+
const [sessionId, setSessionId] = useState('');
|
|
28
|
+
const { error, loading, data } = useRequest(() => fetchData(id));
|
|
29
|
+
|
|
30
|
+
if (error) {
|
|
31
|
+
return <Alert severity="error">{error.message}</Alert>;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (loading || !data) {
|
|
35
|
+
return (
|
|
36
|
+
<Stack
|
|
37
|
+
flexWrap="wrap"
|
|
38
|
+
direction="row"
|
|
39
|
+
gap={{ xs: 3, sm: 5, md: mode === 'checkout' ? 10 : 5 }}
|
|
40
|
+
justifyContent="center">
|
|
41
|
+
<ProductSkeleton key={1} count={2} />
|
|
42
|
+
<ProductSkeleton key={2} count={3} />
|
|
43
|
+
<ProductSkeleton key={3} count={4} />
|
|
44
|
+
</Stack>
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (data.items.length === 0) {
|
|
49
|
+
return <Alert severity="warning">{t('payment.checkout.noPricing')}</Alert>;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const handleSelect = (priceId: string) => {
|
|
53
|
+
api
|
|
54
|
+
.post(`/api/pricing-tables/${data.id}/checkout/${priceId}?${mergeExtraParams(extraParams)}`)
|
|
55
|
+
.then((res) => {
|
|
56
|
+
if (mode === 'standalone') {
|
|
57
|
+
window.location.replace(res.data.url);
|
|
58
|
+
} else {
|
|
59
|
+
setSessionId(res.data.id);
|
|
60
|
+
}
|
|
61
|
+
})
|
|
62
|
+
.catch((err) => {
|
|
63
|
+
console.error(err);
|
|
64
|
+
Toast.error(err.message);
|
|
65
|
+
});
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
if (!sessionId) {
|
|
69
|
+
if (mode === 'standalone') {
|
|
70
|
+
return (
|
|
71
|
+
<Stack direction="column" alignItems="center" spacing={4}>
|
|
72
|
+
<Typography variant="h4" color="text.primary" fontWeight={600}>
|
|
73
|
+
{data.name}
|
|
74
|
+
{!data.livemode && <Livemode />}
|
|
75
|
+
</Typography>
|
|
76
|
+
<PricingTable table={data} onSelect={handleSelect} />
|
|
77
|
+
</Stack>
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return <PricingTable mode="select" table={data} onSelect={handleSelect} />;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return <CheckoutForm id={sessionId} onPaid={onPaid} onError={onError} mode={mode} />;
|
|
85
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import api from './api';
|
|
2
|
-
import
|
|
2
|
+
import CheckoutForm from './checkout/form';
|
|
3
|
+
import CheckoutTable from './checkout/table';
|
|
3
4
|
import FormInput from './components/input';
|
|
4
5
|
import Livemode from './components/livemode';
|
|
5
6
|
import PricingTable from './components/pricing-table';
|
|
@@ -24,7 +25,8 @@ export {
|
|
|
24
25
|
Status,
|
|
25
26
|
Livemode,
|
|
26
27
|
Switch,
|
|
27
|
-
|
|
28
|
+
CheckoutForm,
|
|
29
|
+
CheckoutTable,
|
|
28
30
|
Payment,
|
|
29
31
|
PricingTable,
|
|
30
32
|
ProductSkeleton,
|
|
@@ -12,7 +12,7 @@ export default function UserButtons() {
|
|
|
12
12
|
return (
|
|
13
13
|
<Stack direction="row" alignItems="center" justifyContent="space-between">
|
|
14
14
|
<LocaleSelector showText={false} />
|
|
15
|
-
{session
|
|
15
|
+
{session?.user ? (
|
|
16
16
|
<SessionManager session={session} />
|
|
17
17
|
) : (
|
|
18
18
|
<Tooltip title={t('payment.checkout.login')} arrow>
|
|
@@ -99,7 +99,7 @@ export default function PaymentForm({
|
|
|
99
99
|
});
|
|
100
100
|
|
|
101
101
|
useEffect(() => {
|
|
102
|
-
if (session
|
|
102
|
+
if (session?.user) {
|
|
103
103
|
const values = getValues();
|
|
104
104
|
if (!values.customer_name) {
|
|
105
105
|
setValue('customer_name', session.user.fullName);
|
|
@@ -111,7 +111,7 @@ export default function PaymentForm({
|
|
|
111
111
|
setValue('customer_phone', session.user.phone);
|
|
112
112
|
}
|
|
113
113
|
}
|
|
114
|
-
}, [session
|
|
114
|
+
}, [session?.user, getValues, setValue]);
|
|
115
115
|
|
|
116
116
|
const paymentMethod = useWatch({ control, name: 'payment_method' });
|
|
117
117
|
const paymentCurrency = useWatch({ control, name: 'payment_currency' });
|
|
@@ -129,7 +129,7 @@ export default function PaymentForm({
|
|
|
129
129
|
}, [domSize, theme]);
|
|
130
130
|
|
|
131
131
|
const payee = getStatementDescriptor(checkoutSession.line_items);
|
|
132
|
-
const buttonText = session
|
|
132
|
+
const buttonText = session?.user
|
|
133
133
|
? t(`payment.checkout.${checkoutSession.mode}`)
|
|
134
134
|
: t('payment.checkout.connect', { action: t(`payment.checkout.${checkoutSession.mode}`) });
|
|
135
135
|
|
|
@@ -243,10 +243,10 @@ export default function PaymentForm({
|
|
|
243
243
|
};
|
|
244
244
|
|
|
245
245
|
const onAction = () => {
|
|
246
|
-
if (session
|
|
246
|
+
if (session?.user) {
|
|
247
247
|
handleSubmit(onSubmit)();
|
|
248
248
|
} else {
|
|
249
|
-
session
|
|
249
|
+
session?.login({
|
|
250
250
|
onSuccess: onUserLoggedIn,
|
|
251
251
|
extraParams: {},
|
|
252
252
|
});
|
package/src/payment/index.tsx
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/* eslint-disable import/no-extraneous-dependencies */
|
|
1
2
|
import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
|
|
2
3
|
import Toast from '@arcblock/ux/lib/Toast';
|
|
3
4
|
import type { TCustomer, TPaymentCurrency, TPaymentMethodExpanded } from '@blocklet/payment-types';
|
|
@@ -6,6 +7,7 @@ import { styled } from '@mui/system';
|
|
|
6
7
|
import { useSetState } from 'ahooks';
|
|
7
8
|
import { useEffect } from 'react';
|
|
8
9
|
import { FormProvider, useForm } from 'react-hook-form';
|
|
10
|
+
import { LiteralUnion } from 'type-fest';
|
|
9
11
|
|
|
10
12
|
import api from '../api';
|
|
11
13
|
import { usePaymentContext } from '../contexts/payment';
|
|
@@ -134,9 +136,9 @@ export function PaymentInner({
|
|
|
134
136
|
|
|
135
137
|
const methods = useForm({
|
|
136
138
|
defaultValues: {
|
|
137
|
-
customer_name: customer?.name || session
|
|
138
|
-
customer_email: customer?.email || session
|
|
139
|
-
customer_phone: customer?.phone || session
|
|
139
|
+
customer_name: customer?.name || session?.user?.fullName || '',
|
|
140
|
+
customer_email: customer?.email || session?.user?.email || '',
|
|
141
|
+
customer_phone: customer?.phone || session?.user?.phone || '',
|
|
140
142
|
payment_method: defaultMethodId,
|
|
141
143
|
payment_currency: defaultCurrencyId,
|
|
142
144
|
billing_address: Object.assign(
|
|
@@ -202,10 +204,10 @@ export function PaymentInner({
|
|
|
202
204
|
return (
|
|
203
205
|
<FormProvider {...methods}>
|
|
204
206
|
<Root mode={mode}>
|
|
205
|
-
<Stack className="cko-container">
|
|
207
|
+
<Stack className="cko-container" sx={{ gap: { sm: mode === 'standalone' ? 0 : 8 } }}>
|
|
206
208
|
<Fade in>
|
|
207
209
|
<Stack className="cko-overview" direction="column">
|
|
208
|
-
<PaymentHeader checkoutSession={state.checkoutSession} />
|
|
210
|
+
{mode === 'standalone' ? <PaymentHeader checkoutSession={state.checkoutSession} /> : null}
|
|
209
211
|
<PaymentSummary
|
|
210
212
|
checkoutSession={state.checkoutSession}
|
|
211
213
|
currency={currency}
|
|
@@ -239,23 +241,25 @@ export function PaymentInner({
|
|
|
239
241
|
/>
|
|
240
242
|
)}
|
|
241
243
|
</Stack>
|
|
242
|
-
<CheckoutFooter className="cko-footer" />
|
|
244
|
+
{mode === 'standalone' && <CheckoutFooter className="cko-footer" />}
|
|
243
245
|
</Stack>
|
|
244
246
|
</Root>
|
|
245
247
|
</FormProvider>
|
|
246
248
|
);
|
|
247
249
|
}
|
|
248
250
|
|
|
249
|
-
export const Root = styled(Box)<{ mode: string }>`
|
|
251
|
+
export const Root = styled(Box)<{ mode: LiteralUnion<'standalone' | 'inline' | 'popup', string> }>`
|
|
250
252
|
box-sizing: border-box;
|
|
251
253
|
display: flex;
|
|
252
254
|
flex-direction: column;
|
|
253
255
|
justify-content: center;
|
|
254
256
|
align-items: center;
|
|
255
|
-
min-height: 100vh;
|
|
257
|
+
min-height: ${(props) => (props.mode === 'standalone' ? '100vh' : 'auto')};
|
|
256
258
|
position: relative;
|
|
257
259
|
|
|
258
|
-
|
|
260
|
+
${(props) =>
|
|
261
|
+
props.mode === 'standalone'
|
|
262
|
+
? `&:before {
|
|
259
263
|
animation-fill-mode: both;
|
|
260
264
|
background: #ffffff;
|
|
261
265
|
content: '';
|
|
@@ -266,7 +270,8 @@ export const Root = styled(Box)<{ mode: string }>`
|
|
|
266
270
|
transform-origin: right;
|
|
267
271
|
width: 50%;
|
|
268
272
|
box-shadow: 15px 0 30px 0 rgba(0, 0, 0, 0.18);
|
|
269
|
-
}
|
|
273
|
+
}`
|
|
274
|
+
: ''}
|
|
270
275
|
|
|
271
276
|
.cko-container {
|
|
272
277
|
width: 100%;
|
|
@@ -275,12 +280,12 @@ export const Root = styled(Box)<{ mode: string }>`
|
|
|
275
280
|
flex-direction: row;
|
|
276
281
|
justify-content: space-between;
|
|
277
282
|
position: relative;
|
|
278
|
-
padding: 0 16px;
|
|
283
|
+
padding: ${(props) => (props.mode === 'standalone' ? '0 16px' : '0')};
|
|
279
284
|
}
|
|
280
285
|
|
|
281
286
|
.cko-overview {
|
|
282
287
|
width: 400px;
|
|
283
|
-
min-height: 540px;
|
|
288
|
+
min-height: ${(props) => (props.mode === 'standalone' ? '540px' : 'auto')};
|
|
284
289
|
position: relative;
|
|
285
290
|
}
|
|
286
291
|
.cko-header {
|
|
@@ -291,6 +296,9 @@ export const Root = styled(Box)<{ mode: string }>`
|
|
|
291
296
|
top: 0;
|
|
292
297
|
transition: background-color 0.15s ease, box-shadow 0.15s ease-out;
|
|
293
298
|
}
|
|
299
|
+
.cko-product {
|
|
300
|
+
margin-top: ${(props) => (props.mode === 'standalone' ? '64px' : '0')};
|
|
301
|
+
}
|
|
294
302
|
.cko-product-summary {
|
|
295
303
|
}
|
|
296
304
|
|
package/src/payment/summary.tsx
CHANGED
|
@@ -112,12 +112,7 @@ export default function PaymentSummary({
|
|
|
112
112
|
|
|
113
113
|
return (
|
|
114
114
|
<Fade in>
|
|
115
|
-
<Stack
|
|
116
|
-
className="cko-product"
|
|
117
|
-
direction="column"
|
|
118
|
-
sx={{
|
|
119
|
-
mt: 8,
|
|
120
|
-
}}>
|
|
115
|
+
<Stack className="cko-product" direction="column">
|
|
121
116
|
<Stack className="cko-product-summary" direction="column" alignItems="flex-start" sx={{ mb: 4 }}>
|
|
122
117
|
<Typography sx={{ fontWeight: 500, fontSize: '1.15rem', color: 'text.secondary' }}>
|
|
123
118
|
{headlines.action}
|