@paypal/checkout-components 5.0.295-alpha.201 → 5.0.295-alpha.221
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/package.json
CHANGED
|
@@ -5,6 +5,7 @@ import { getButtonsComponent } from "../zoid/buttons";
|
|
|
5
5
|
import {
|
|
6
6
|
buildHostedButtonCreateOrder,
|
|
7
7
|
buildHostedButtonOnApprove,
|
|
8
|
+
buildOpenPopup,
|
|
8
9
|
getHostedButtonDetails,
|
|
9
10
|
renderForm,
|
|
10
11
|
getMerchantID,
|
|
@@ -24,7 +25,7 @@ export const getHostedButtonsComponent = (): HostedButtonsComponent => {
|
|
|
24
25
|
const merchantId = getMerchantID();
|
|
25
26
|
|
|
26
27
|
getHostedButtonDetails({ hostedButtonId }).then(
|
|
27
|
-
({ html, htmlScript, style }) => {
|
|
28
|
+
({ html, htmlScript, style, popupFallback }) => {
|
|
28
29
|
const { onInit, onClick } = renderForm({
|
|
29
30
|
hostedButtonId,
|
|
30
31
|
html,
|
|
@@ -32,6 +33,8 @@ export const getHostedButtonsComponent = (): HostedButtonsComponent => {
|
|
|
32
33
|
selector,
|
|
33
34
|
});
|
|
34
35
|
|
|
36
|
+
const openPopup = buildOpenPopup({ selector, popupFallback });
|
|
37
|
+
|
|
35
38
|
// $FlowFixMe
|
|
36
39
|
Buttons({
|
|
37
40
|
hostedButtonId,
|
|
@@ -45,6 +48,7 @@ export const getHostedButtonsComponent = (): HostedButtonsComponent => {
|
|
|
45
48
|
onApprove: buildHostedButtonOnApprove({
|
|
46
49
|
hostedButtonId,
|
|
47
50
|
merchantId,
|
|
51
|
+
openPopup,
|
|
48
52
|
}),
|
|
49
53
|
}).render(selector);
|
|
50
54
|
}
|
|
@@ -9,6 +9,7 @@ export type HostedButtonsComponentProps = {|
|
|
|
9
9
|
export type GetCallbackProps = {|
|
|
10
10
|
hostedButtonId: string,
|
|
11
11
|
merchantId?: string,
|
|
12
|
+
openPopup?: (url: string) => void,
|
|
12
13
|
|};
|
|
13
14
|
|
|
14
15
|
export type HostedButtonsInstance = {|
|
|
@@ -25,6 +26,7 @@ export type HostedButtonDetailsParams =
|
|
|
25
26
|
color: string,
|
|
26
27
|
label: string,
|
|
27
28
|
|},
|
|
29
|
+
popupFallback: string,
|
|
28
30
|
|}>;
|
|
29
31
|
|
|
30
32
|
export type ButtonVariables = $ReadOnlyArray<{|
|
|
@@ -34,7 +36,7 @@ export type ButtonVariables = $ReadOnlyArray<{|
|
|
|
34
36
|
|
|
35
37
|
export type CreateOrder = (data: {|
|
|
36
38
|
paymentSource: string,
|
|
37
|
-
|}) => ZalgoPromise<string>;
|
|
39
|
+
|}) => ZalgoPromise<string | void>;
|
|
38
40
|
|
|
39
41
|
export type OnApprove = (data: {|
|
|
40
42
|
orderID: string,
|
|
@@ -55,3 +57,8 @@ export type RenderForm = ({|
|
|
|
55
57
|
onInit: (data: mixed, actions: mixed) => void,
|
|
56
58
|
onClick: (data: mixed, actions: mixed) => void,
|
|
57
59
|
|};
|
|
60
|
+
|
|
61
|
+
export type BuildOpenPopup = ({|
|
|
62
|
+
popupFallback: string,
|
|
63
|
+
selector: string | HTMLElement,
|
|
64
|
+
|}) => (url: string) => void;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/* @flow */
|
|
2
2
|
|
|
3
|
-
import { request, memoize, popup
|
|
3
|
+
import { request, memoize, popup } from "@krakenjs/belter/src";
|
|
4
4
|
import {
|
|
5
5
|
getSDKHost,
|
|
6
6
|
getClientID,
|
|
@@ -11,6 +11,7 @@ import { FUNDING } from "@paypal/sdk-constants/src";
|
|
|
11
11
|
import { DEFAULT_POPUP_SIZE } from "../zoid/checkout";
|
|
12
12
|
|
|
13
13
|
import type {
|
|
14
|
+
BuildOpenPopup,
|
|
14
15
|
ButtonVariables,
|
|
15
16
|
CreateAccessToken,
|
|
16
17
|
CreateOrder,
|
|
@@ -23,6 +24,7 @@ import type {
|
|
|
23
24
|
const entryPoint = "SDK";
|
|
24
25
|
const baseUrl = `https://${getSDKHost()}`;
|
|
25
26
|
const apiUrl = baseUrl.replace("www", "api");
|
|
27
|
+
export const popupFallbackClassName = "paypal-popup-fallback";
|
|
26
28
|
|
|
27
29
|
const getHeaders = (accessToken?: string) => ({
|
|
28
30
|
...(accessToken && { Authorization: `Bearer ${accessToken}` }),
|
|
@@ -75,6 +77,7 @@ export const getHostedButtonDetails: HostedButtonDetailsParams = ({
|
|
|
75
77
|
},
|
|
76
78
|
html: body.html,
|
|
77
79
|
htmlScript: body.html_script,
|
|
80
|
+
popupFallback: body.popup_fallback,
|
|
78
81
|
};
|
|
79
82
|
});
|
|
80
83
|
};
|
|
@@ -115,6 +118,7 @@ export const buildHostedButtonCreateOrder = ({
|
|
|
115
118
|
return (data) => {
|
|
116
119
|
const userInputs =
|
|
117
120
|
window[`__pp_form_fields_${hostedButtonId}`]?.getUserInputs?.() || {};
|
|
121
|
+
const onError = window[`__pp_form_fields_${hostedButtonId}`]?.onError;
|
|
118
122
|
return createAccessToken(getClientID()).then((accessToken) => {
|
|
119
123
|
return request({
|
|
120
124
|
url: `${apiUrl}/v1/checkout/links/${hostedButtonId}/create-context`,
|
|
@@ -126,19 +130,37 @@ export const buildHostedButtonCreateOrder = ({
|
|
|
126
130
|
merchant_id: merchantId,
|
|
127
131
|
...userInputs,
|
|
128
132
|
}),
|
|
129
|
-
})
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
}
|
|
133
|
-
return body.context_id;
|
|
134
|
-
});
|
|
133
|
+
})
|
|
134
|
+
.then(({ body }) => body.context_id || onError(body.name))
|
|
135
|
+
.catch(() => onError("REQUEST_FAILED"));
|
|
135
136
|
});
|
|
136
137
|
};
|
|
137
138
|
};
|
|
138
139
|
|
|
140
|
+
export const buildOpenPopup: BuildOpenPopup = ({ popupFallback, selector }) => {
|
|
141
|
+
return (url) => {
|
|
142
|
+
try {
|
|
143
|
+
popup(url, {
|
|
144
|
+
width: DEFAULT_POPUP_SIZE.WIDTH,
|
|
145
|
+
height: DEFAULT_POPUP_SIZE.HEIGHT,
|
|
146
|
+
});
|
|
147
|
+
} catch (e) {
|
|
148
|
+
const div = document.createElement("div");
|
|
149
|
+
div.classList.add(popupFallbackClassName);
|
|
150
|
+
div.innerHTML = popupFallback.replace("#", url);
|
|
151
|
+
const container =
|
|
152
|
+
typeof selector === "string"
|
|
153
|
+
? document.querySelector(selector)
|
|
154
|
+
: selector;
|
|
155
|
+
container?.appendChild(div);
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
};
|
|
159
|
+
|
|
139
160
|
export const buildHostedButtonOnApprove = ({
|
|
140
161
|
hostedButtonId,
|
|
141
162
|
merchantId,
|
|
163
|
+
openPopup,
|
|
142
164
|
}: GetCallbackProps): OnApprove => {
|
|
143
165
|
return (data) => {
|
|
144
166
|
return createAccessToken(getClientID()).then((accessToken) => {
|
|
@@ -152,19 +174,14 @@ export const buildHostedButtonOnApprove = ({
|
|
|
152
174
|
context_id: data.orderID,
|
|
153
175
|
}),
|
|
154
176
|
}).then((response) => {
|
|
177
|
+
// remove the popup fallback message, if present
|
|
178
|
+
document.querySelector(`.${popupFallbackClassName}`)?.remove();
|
|
155
179
|
// The "Debit or Credit Card" button does not open a popup
|
|
156
180
|
// so we need to open a new popup for buyers who complete
|
|
157
181
|
// a checkout via "Debit or Credit Card".
|
|
158
182
|
if (data.paymentSource === FUNDING.CARD) {
|
|
159
183
|
const url = `${baseUrl}/ncp/payment/${hostedButtonId}/${data.orderID}`;
|
|
160
|
-
|
|
161
|
-
popup(url, {
|
|
162
|
-
width: DEFAULT_POPUP_SIZE.WIDTH,
|
|
163
|
-
height: DEFAULT_POPUP_SIZE.HEIGHT,
|
|
164
|
-
});
|
|
165
|
-
} else {
|
|
166
|
-
window.location = url;
|
|
167
|
-
}
|
|
184
|
+
openPopup?.(url);
|
|
168
185
|
}
|
|
169
186
|
return response;
|
|
170
187
|
});
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
/* @flow */
|
|
2
2
|
|
|
3
3
|
import { test, expect, vi } from "vitest";
|
|
4
|
-
import { request, popup
|
|
4
|
+
import { request, popup } from "@krakenjs/belter/src";
|
|
5
5
|
import { ZalgoPromise } from "@krakenjs/zalgo-promise/src";
|
|
6
6
|
|
|
7
7
|
import {
|
|
8
8
|
buildHostedButtonCreateOrder,
|
|
9
9
|
buildHostedButtonOnApprove,
|
|
10
|
+
buildOpenPopup,
|
|
10
11
|
getHostedButtonDetails,
|
|
12
|
+
popupFallbackClassName,
|
|
11
13
|
} from "./utils";
|
|
12
14
|
|
|
13
15
|
vi.mock("@krakenjs/belter/src", async () => {
|
|
@@ -152,10 +154,20 @@ describe("buildHostedButtonOnApprove", () => {
|
|
|
152
154
|
expect.assertions(1);
|
|
153
155
|
});
|
|
154
156
|
|
|
155
|
-
|
|
157
|
+
describe("inline guest", () => {
|
|
158
|
+
const url = "https://example.com/ncp/payment/B1234567890/EC-1234567890";
|
|
159
|
+
const selector = "buttons-container";
|
|
160
|
+
// $FlowIssue
|
|
161
|
+
document.body.innerHTML = `<div id="${selector}"></div>`; // eslint-disable-line compat/compat
|
|
162
|
+
const popupFallback = `<a href="#">See payment details</a>`;
|
|
163
|
+
const openPopup = buildOpenPopup({
|
|
164
|
+
popupFallback,
|
|
165
|
+
selector: `#${selector}`,
|
|
166
|
+
});
|
|
156
167
|
const onApprove = buildHostedButtonOnApprove({
|
|
157
168
|
hostedButtonId,
|
|
158
169
|
merchantId,
|
|
170
|
+
openPopup,
|
|
159
171
|
});
|
|
160
172
|
// $FlowIssue
|
|
161
173
|
request.mockImplementation(() =>
|
|
@@ -164,19 +176,55 @@ describe("buildHostedButtonOnApprove", () => {
|
|
|
164
176
|
})
|
|
165
177
|
);
|
|
166
178
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
179
|
+
test("provides its own popup", async () => {
|
|
180
|
+
await onApprove({ orderID, paymentSource: "card" });
|
|
181
|
+
expect(popup).toHaveBeenCalledWith(url, expect.anything());
|
|
182
|
+
expect.assertions(1);
|
|
183
|
+
});
|
|
171
184
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
185
|
+
test("appends a link if the popup is blocked", async () => {
|
|
186
|
+
// $FlowIssue
|
|
187
|
+
popup.mockImplementationOnce(() => {
|
|
188
|
+
throw new Error("popup_blocked");
|
|
189
|
+
});
|
|
190
|
+
await onApprove({ orderID, paymentSource: "card" });
|
|
191
|
+
const link = document.querySelector(`.${popupFallbackClassName} a`);
|
|
192
|
+
expect(link?.getAttribute("href")).toBe(url);
|
|
193
|
+
expect.assertions(1);
|
|
194
|
+
});
|
|
179
195
|
|
|
180
|
-
|
|
196
|
+
test("does not append a second link if the popup is blocked a second time", async () => {
|
|
197
|
+
// still present from the previous popup open failure
|
|
198
|
+
expect(
|
|
199
|
+
document.querySelectorAll(`.${popupFallbackClassName}`).length
|
|
200
|
+
).toBe(1);
|
|
201
|
+
// $FlowIssue
|
|
202
|
+
popup.mockImplementationOnce(() => {
|
|
203
|
+
throw new Error("popup_blocked");
|
|
204
|
+
});
|
|
205
|
+
await onApprove({ orderID, paymentSource: "card" });
|
|
206
|
+
expect(
|
|
207
|
+
document.querySelectorAll(`.${popupFallbackClassName}`).length
|
|
208
|
+
).toBe(1);
|
|
209
|
+
expect.assertions(2);
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
test("removes the fallback message if a different payment source is used", async () => {
|
|
213
|
+
// still present from the previous popup open failure
|
|
214
|
+
expect(
|
|
215
|
+
document.querySelectorAll(`.${popupFallbackClassName}`).length
|
|
216
|
+
).toBe(1);
|
|
217
|
+
// $FlowIssue
|
|
218
|
+
popup.mockImplementationOnce(() => {
|
|
219
|
+
throw new Error("popup_blocked");
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
// note new payment source
|
|
223
|
+
await onApprove({ orderID, paymentSource: "paypal" });
|
|
224
|
+
expect(
|
|
225
|
+
document.querySelectorAll(`.${popupFallbackClassName}`).length
|
|
226
|
+
).toBe(0);
|
|
227
|
+
expect.assertions(2);
|
|
228
|
+
});
|
|
181
229
|
});
|
|
182
230
|
});
|