-
Notifications
You must be signed in to change notification settings - Fork 101
/
PayPalScriptProvider.tsx
86 lines (77 loc) · 2.83 KB
/
PayPalScriptProvider.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
import React, { useEffect, useReducer } from "react";
import { loadScript } from "@paypal/paypal-js";
import {
getScriptID,
ScriptContext,
scriptReducer,
} from "../context/scriptProviderContext";
import { SCRIPT_ID, SDK_SETTINGS, LOAD_SCRIPT_ERROR } from "../constants";
import { SCRIPT_LOADING_STATE, DISPATCH_ACTION } from "../types";
import type { FC } from "react";
import type { ScriptProviderProps } from "../types";
/**
This `<PayPalScriptProvider />` component takes care of loading the JS SDK `<script>`.
It manages state for script loading so children components like `<PayPalButtons />` know when it's safe to use the `window.paypal` global namespace.
Note: You always should use this component as a wrapper for `PayPalButtons`, `PayPalMarks`, `PayPalMessages` and `BraintreePayPalButtons` components.
*/
export const PayPalScriptProvider: FC<ScriptProviderProps> = ({
options = { clientId: "test" },
children,
deferLoading = false,
}: ScriptProviderProps) => {
const [state, dispatch] = useReducer(scriptReducer, {
options: {
...options,
[SCRIPT_ID]: `${getScriptID(options)}`,
[SDK_SETTINGS.DATA_SDK_INTEGRATION_SOURCE]:
SDK_SETTINGS.DATA_SDK_INTEGRATION_SOURCE_VALUE,
},
loadingStatus: deferLoading
? SCRIPT_LOADING_STATE.INITIAL
: SCRIPT_LOADING_STATE.PENDING,
});
useEffect(() => {
if (
deferLoading === false &&
state.loadingStatus === SCRIPT_LOADING_STATE.INITIAL
) {
return dispatch({
type: DISPATCH_ACTION.LOADING_STATUS,
value: SCRIPT_LOADING_STATE.PENDING,
});
}
if (state.loadingStatus !== SCRIPT_LOADING_STATE.PENDING) {
return;
}
let isSubscribed = true;
loadScript(state.options)
.then(() => {
if (isSubscribed) {
dispatch({
type: DISPATCH_ACTION.LOADING_STATUS,
value: SCRIPT_LOADING_STATE.RESOLVED,
});
}
})
.catch((err) => {
console.error(`${LOAD_SCRIPT_ERROR} ${err}`);
if (isSubscribed) {
dispatch({
type: DISPATCH_ACTION.LOADING_STATUS,
value: {
state: SCRIPT_LOADING_STATE.REJECTED,
message: String(err),
},
});
}
});
return () => {
isSubscribed = false;
};
}, [state.options, deferLoading, state.loadingStatus]);
return (
<ScriptContext.Provider value={{ ...state, dispatch }}>
{children}
</ScriptContext.Provider>
);
};