@paypal/checkout-components 5.0.292 → 5.0.293-alpha.11
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/__sdk__.js +4 -0
- package/dist/button.js +1 -1
- package/dist/test/button.js +1 -1
- package/package.json +1 -1
- package/src/api/api.js +14 -1
- package/src/api/shopper-insights/{component.jsx → component.js} +2 -2
- package/src/api/shopper-insights/component.test.js +120 -51
- package/src/api/shopper-insights/interface.js +3 -4
- package/src/connect/component.jsx +38 -4
- package/src/connect/component.test.js +35 -1
- package/src/hosted-buttons/index.js +71 -0
- package/src/hosted-buttons/index.test.js +84 -0
- package/src/hosted-buttons/types.js +53 -0
- package/src/hosted-buttons/utils.js +144 -0
- package/src/hosted-buttons/utils.test.js +121 -0
- package/src/interface/hosted-buttons.js +29 -0
- package/src/zoid/buttons/component.jsx +21 -1
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/* @flow */
|
|
2
|
+
|
|
3
|
+
import { ZalgoPromise } from "@krakenjs/zalgo-promise/src";
|
|
4
|
+
|
|
5
|
+
export type HostedButtonsComponentProps = {|
|
|
6
|
+
hostedButtonId: string,
|
|
7
|
+
|};
|
|
8
|
+
|
|
9
|
+
export type GetCallbackProps = {|
|
|
10
|
+
hostedButtonId: string,
|
|
11
|
+
merchantId: string,
|
|
12
|
+
|};
|
|
13
|
+
|
|
14
|
+
export type HostedButtonsInstance = {|
|
|
15
|
+
render: (string | HTMLElement) => void,
|
|
16
|
+
|};
|
|
17
|
+
|
|
18
|
+
export type HostedButtonDetailsParams =
|
|
19
|
+
(HostedButtonsComponentProps) => ZalgoPromise<{|
|
|
20
|
+
html: string,
|
|
21
|
+
htmlScript: string,
|
|
22
|
+
style: {|
|
|
23
|
+
layout: string,
|
|
24
|
+
shape: string,
|
|
25
|
+
color: string,
|
|
26
|
+
label: string,
|
|
27
|
+
|},
|
|
28
|
+
|}>;
|
|
29
|
+
|
|
30
|
+
export type ButtonVariables = $ReadOnlyArray<{|
|
|
31
|
+
name: string,
|
|
32
|
+
value: string,
|
|
33
|
+
|}>;
|
|
34
|
+
|
|
35
|
+
export type CreateOrder = (data: {|
|
|
36
|
+
paymentSource: string,
|
|
37
|
+
|}) => ZalgoPromise<string>;
|
|
38
|
+
|
|
39
|
+
export type OnApprove = (data: {|
|
|
40
|
+
orderID: string,
|
|
41
|
+
paymentSource: string,
|
|
42
|
+
|}) => ZalgoPromise<void>;
|
|
43
|
+
|
|
44
|
+
export type CreateAccessToken = (clientID: string) => ZalgoPromise<string>;
|
|
45
|
+
|
|
46
|
+
export type HostedButtonsComponent =
|
|
47
|
+
(HostedButtonsComponentProps) => HostedButtonsInstance;
|
|
48
|
+
|
|
49
|
+
export type RenderForm = {|
|
|
50
|
+
html: string,
|
|
51
|
+
htmlScript: string,
|
|
52
|
+
selector: string | HTMLElement,
|
|
53
|
+
|};
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/* @flow */
|
|
2
|
+
|
|
3
|
+
import { request, memoize, popup } from "@krakenjs/belter/src";
|
|
4
|
+
import { getSDKHost, getClientID } from "@paypal/sdk-client/src";
|
|
5
|
+
|
|
6
|
+
import { DEFAULT_POPUP_SIZE } from "../zoid/checkout";
|
|
7
|
+
|
|
8
|
+
import type {
|
|
9
|
+
ButtonVariables,
|
|
10
|
+
CreateAccessToken,
|
|
11
|
+
CreateOrder,
|
|
12
|
+
GetCallbackProps,
|
|
13
|
+
HostedButtonDetailsParams,
|
|
14
|
+
OnApprove,
|
|
15
|
+
RenderForm,
|
|
16
|
+
} from "./types";
|
|
17
|
+
|
|
18
|
+
const entryPoint = "SDK";
|
|
19
|
+
const baseUrl = `https://${getSDKHost()}`;
|
|
20
|
+
const apiUrl = baseUrl.replace("www", "api");
|
|
21
|
+
|
|
22
|
+
const getHeaders = (accessToken?: string) => ({
|
|
23
|
+
...(accessToken && { Authorization: `Bearer ${accessToken}` }),
|
|
24
|
+
"Content-Type": "application/json",
|
|
25
|
+
"PayPal-Entry-Point": entryPoint,
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
export const createAccessToken: CreateAccessToken = memoize<CreateAccessToken>(
|
|
29
|
+
(clientId) => {
|
|
30
|
+
return request({
|
|
31
|
+
url: `${apiUrl}/v1/oauth2/token`,
|
|
32
|
+
method: "POST",
|
|
33
|
+
body: "grant_type=client_credentials",
|
|
34
|
+
headers: {
|
|
35
|
+
Authorization: `Basic ${btoa(clientId)}`,
|
|
36
|
+
"Content-Type": "application/json",
|
|
37
|
+
},
|
|
38
|
+
}).then((response) => response.body.access_token);
|
|
39
|
+
}
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
const getButtonVariable = (variables: ButtonVariables, key: string): string =>
|
|
43
|
+
variables?.find((variable) => variable.name === key)?.value ?? "";
|
|
44
|
+
|
|
45
|
+
const getFundingSource = (paymentSource) => {
|
|
46
|
+
if (paymentSource === "credit") {
|
|
47
|
+
return `CARD`;
|
|
48
|
+
}
|
|
49
|
+
return paymentSource.toUpperCase();
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export const getHostedButtonDetails: HostedButtonDetailsParams = ({
|
|
53
|
+
hostedButtonId,
|
|
54
|
+
}) => {
|
|
55
|
+
return request({
|
|
56
|
+
url: `${baseUrl}/ncp/api/form-fields/${hostedButtonId}`,
|
|
57
|
+
headers: getHeaders(),
|
|
58
|
+
}).then(({ body }) => {
|
|
59
|
+
const variables = body.button_details.link_variables;
|
|
60
|
+
return {
|
|
61
|
+
style: {
|
|
62
|
+
layout: getButtonVariable(variables, "layout"),
|
|
63
|
+
shape: getButtonVariable(variables, "shape"),
|
|
64
|
+
color: getButtonVariable(variables, "color"),
|
|
65
|
+
label: getButtonVariable(variables, "button_text"),
|
|
66
|
+
},
|
|
67
|
+
html: body.html,
|
|
68
|
+
htmlScript: body.html_script,
|
|
69
|
+
};
|
|
70
|
+
});
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Attaches form fields (html) to the given selector, and
|
|
75
|
+
* initializes window.__pp_form_fields (htmlScript).
|
|
76
|
+
*/
|
|
77
|
+
export const renderForm = ({
|
|
78
|
+
html,
|
|
79
|
+
htmlScript,
|
|
80
|
+
selector,
|
|
81
|
+
}: RenderForm): void => {
|
|
82
|
+
const elm =
|
|
83
|
+
typeof selector === "string" ? document.querySelector(selector) : selector;
|
|
84
|
+
if (elm) {
|
|
85
|
+
elm.innerHTML = html + htmlScript;
|
|
86
|
+
const newScriptEl = document.createElement("script");
|
|
87
|
+
const oldScriptEl = elm.querySelector("script");
|
|
88
|
+
newScriptEl.innerHTML = oldScriptEl?.innerHTML ?? "";
|
|
89
|
+
oldScriptEl?.parentNode?.replaceChild(newScriptEl, oldScriptEl);
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
export const buildHostedButtonCreateOrder = ({
|
|
94
|
+
hostedButtonId,
|
|
95
|
+
merchantId,
|
|
96
|
+
}: GetCallbackProps): CreateOrder => {
|
|
97
|
+
return (data) => {
|
|
98
|
+
const userInputs =
|
|
99
|
+
window[`__pp_form_fields_${hostedButtonId}`]?.getUserInputs?.() || {};
|
|
100
|
+
return createAccessToken(getClientID()).then((accessToken) => {
|
|
101
|
+
return request({
|
|
102
|
+
url: `${apiUrl}/v1/checkout/links/${hostedButtonId}/create-context`,
|
|
103
|
+
headers: getHeaders(accessToken),
|
|
104
|
+
method: "POST",
|
|
105
|
+
body: JSON.stringify({
|
|
106
|
+
entry_point: entryPoint,
|
|
107
|
+
funding_source: getFundingSource(data.paymentSource),
|
|
108
|
+
merchant_id: merchantId,
|
|
109
|
+
...userInputs,
|
|
110
|
+
}),
|
|
111
|
+
}).then(({ body }) => {
|
|
112
|
+
return body.context_id;
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
};
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
export const buildHostedButtonOnApprove = ({
|
|
119
|
+
hostedButtonId,
|
|
120
|
+
merchantId,
|
|
121
|
+
}: GetCallbackProps): OnApprove => {
|
|
122
|
+
return (data) => {
|
|
123
|
+
return createAccessToken(getClientID()).then((accessToken) => {
|
|
124
|
+
return request({
|
|
125
|
+
url: `${apiUrl}/v1/checkout/links/${hostedButtonId}/pay`,
|
|
126
|
+
headers: getHeaders(accessToken),
|
|
127
|
+
method: "POST",
|
|
128
|
+
body: JSON.stringify({
|
|
129
|
+
entry_point: entryPoint,
|
|
130
|
+
merchant_id: merchantId,
|
|
131
|
+
context_id: data.orderID,
|
|
132
|
+
}),
|
|
133
|
+
}).then(() => {
|
|
134
|
+
if (data.paymentSource === "card") {
|
|
135
|
+
const url = `${baseUrl}/ncp/payment/${hostedButtonId}/${data.orderID}`;
|
|
136
|
+
popup(url, {
|
|
137
|
+
width: DEFAULT_POPUP_SIZE.WIDTH,
|
|
138
|
+
height: DEFAULT_POPUP_SIZE.HEIGHT,
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
};
|
|
144
|
+
};
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/* @flow */
|
|
2
|
+
|
|
3
|
+
import { test, expect, vi } from "vitest";
|
|
4
|
+
import { request } from "@krakenjs/belter/src";
|
|
5
|
+
import { ZalgoPromise } from "@krakenjs/zalgo-promise/src";
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
getHostedButtonDetails,
|
|
9
|
+
buildHostedButtonCreateOrder,
|
|
10
|
+
buildHostedButtonOnApprove,
|
|
11
|
+
} from "./utils";
|
|
12
|
+
|
|
13
|
+
vi.mock("@krakenjs/belter/src", async () => {
|
|
14
|
+
return {
|
|
15
|
+
...(await vi.importActual("@krakenjs/belter/src")),
|
|
16
|
+
request: vi.fn(),
|
|
17
|
+
};
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
vi.mock("@paypal/sdk-client/src", async () => {
|
|
21
|
+
return {
|
|
22
|
+
...(await vi.importActual("@paypal/sdk-client/src")),
|
|
23
|
+
getSDKHost: () => "example.com",
|
|
24
|
+
getClientID: () => "client_id_123",
|
|
25
|
+
getMerchantID: () => ["merchant_id_123"],
|
|
26
|
+
};
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
const getHostedButtonDetailsResponse = {
|
|
30
|
+
body: {
|
|
31
|
+
button_details: {
|
|
32
|
+
link_variables: [
|
|
33
|
+
{
|
|
34
|
+
name: "business",
|
|
35
|
+
value: "M1234567890",
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
name: "shape",
|
|
39
|
+
value: "rect",
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
name: "layout",
|
|
43
|
+
value: "vertical",
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
name: "color",
|
|
47
|
+
value: "gold",
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
name: "button_text",
|
|
51
|
+
value: "paypal",
|
|
52
|
+
},
|
|
53
|
+
],
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
test("getHostedButtonDetails", async () => {
|
|
59
|
+
// $FlowIssue
|
|
60
|
+
request.mockImplementationOnce(() =>
|
|
61
|
+
ZalgoPromise.resolve(getHostedButtonDetailsResponse)
|
|
62
|
+
);
|
|
63
|
+
await getHostedButtonDetails({
|
|
64
|
+
hostedButtonId: "B1234567890",
|
|
65
|
+
}).then(({ style }) => {
|
|
66
|
+
expect(style).toEqual({
|
|
67
|
+
layout: "vertical",
|
|
68
|
+
shape: "rect",
|
|
69
|
+
color: "gold",
|
|
70
|
+
label: "paypal",
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
expect.assertions(1);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
test("buildHostedButtonCreateOrder", async () => {
|
|
77
|
+
const createOrder = buildHostedButtonCreateOrder({
|
|
78
|
+
hostedButtonId: "B1234567890",
|
|
79
|
+
merchantId: "M1234567890",
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
// $FlowIssue
|
|
83
|
+
request.mockImplementation(() =>
|
|
84
|
+
ZalgoPromise.resolve({
|
|
85
|
+
body: {
|
|
86
|
+
link_id: "B1234567890",
|
|
87
|
+
merchant_id: "M1234567890",
|
|
88
|
+
context_id: "EC-1234567890",
|
|
89
|
+
status: "CREATED",
|
|
90
|
+
},
|
|
91
|
+
})
|
|
92
|
+
);
|
|
93
|
+
const orderID = await createOrder({ paymentSource: "paypal" });
|
|
94
|
+
expect(orderID).toBe("EC-1234567890");
|
|
95
|
+
expect.assertions(1);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
test("buildHostedButtonOnApprove", async () => {
|
|
99
|
+
const onApprove = buildHostedButtonOnApprove({
|
|
100
|
+
hostedButtonId: "B1234567890",
|
|
101
|
+
merchantId: "M1234567890",
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
// $FlowIssue
|
|
105
|
+
request.mockImplementation(() =>
|
|
106
|
+
ZalgoPromise.resolve({
|
|
107
|
+
body: {},
|
|
108
|
+
})
|
|
109
|
+
);
|
|
110
|
+
await onApprove({ orderID: "EC-1234567890", paymentSource: "paypal" });
|
|
111
|
+
expect(request).toHaveBeenCalledWith(
|
|
112
|
+
expect.objectContaining({
|
|
113
|
+
body: JSON.stringify({
|
|
114
|
+
entry_point: "SDK",
|
|
115
|
+
merchant_id: "M1234567890",
|
|
116
|
+
context_id: "EC-1234567890",
|
|
117
|
+
}),
|
|
118
|
+
})
|
|
119
|
+
);
|
|
120
|
+
expect.assertions(1);
|
|
121
|
+
});
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/* @flow */
|
|
2
|
+
|
|
3
|
+
import { getHostedButtonsComponent } from "../hosted-buttons";
|
|
4
|
+
import type { HostedButtonsComponent } from "../hosted-buttons/types";
|
|
5
|
+
import { getButtonsComponent } from "../zoid/buttons";
|
|
6
|
+
import {
|
|
7
|
+
getCardFormComponent,
|
|
8
|
+
type CardFormComponent,
|
|
9
|
+
} from "../zoid/card-form";
|
|
10
|
+
import { getCheckoutComponent, type CheckoutComponent } from "../zoid/checkout";
|
|
11
|
+
import type { LazyExport, LazyProtectedExport } from "../types";
|
|
12
|
+
import { protectedExport } from "../lib";
|
|
13
|
+
|
|
14
|
+
export const HostedButtons: LazyExport<HostedButtonsComponent> = {
|
|
15
|
+
__get__: () => getHostedButtonsComponent(),
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export const Checkout: LazyProtectedExport<CheckoutComponent> = {
|
|
19
|
+
__get__: () => protectedExport(getCheckoutComponent()),
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export const CardForm: LazyProtectedExport<CardFormComponent> = {
|
|
23
|
+
__get__: () => protectedExport(getCardFormComponent()),
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export function setup() {
|
|
27
|
+
getButtonsComponent();
|
|
28
|
+
getCheckoutComponent();
|
|
29
|
+
}
|
|
@@ -719,6 +719,16 @@ export const getButtonsComponent: () => ButtonsComponent = memoize(() => {
|
|
|
719
719
|
},
|
|
720
720
|
},
|
|
721
721
|
|
|
722
|
+
referrerDomain: {
|
|
723
|
+
type: "string",
|
|
724
|
+
required: false,
|
|
725
|
+
value: () => {
|
|
726
|
+
if (window.document.referrer) {
|
|
727
|
+
return new URL(window.document.referrer).host || undefined;
|
|
728
|
+
}
|
|
729
|
+
},
|
|
730
|
+
},
|
|
731
|
+
|
|
722
732
|
userIDToken: {
|
|
723
733
|
type: "string",
|
|
724
734
|
default: getUserIDToken,
|
|
@@ -730,7 +740,12 @@ export const getButtonsComponent: () => ButtonsComponent = memoize(() => {
|
|
|
730
740
|
clientMetadataID: {
|
|
731
741
|
type: "string",
|
|
732
742
|
required: false,
|
|
733
|
-
default:
|
|
743
|
+
default: () => {
|
|
744
|
+
const clientMetadataId = getClientMetadataID();
|
|
745
|
+
const sessionID = getSessionID();
|
|
746
|
+
|
|
747
|
+
return clientMetadataId || sessionID;
|
|
748
|
+
},
|
|
734
749
|
queryParam: true,
|
|
735
750
|
},
|
|
736
751
|
|
|
@@ -834,6 +849,11 @@ export const getButtonsComponent: () => ButtonsComponent = memoize(() => {
|
|
|
834
849
|
value: getExperimentation,
|
|
835
850
|
},
|
|
836
851
|
|
|
852
|
+
hostedButtonId: {
|
|
853
|
+
type: "string",
|
|
854
|
+
required: false,
|
|
855
|
+
},
|
|
856
|
+
|
|
837
857
|
displayOnly: {
|
|
838
858
|
type: "array",
|
|
839
859
|
queryParam: true,
|