Skip to content

Commit 88522db

Browse files
Merge pull request #57 from Flutterwave/dev
[Hotfix] Checkout optimization
2 parents 36d8b67 + cbcac49 commit 88522db

10 files changed

+344
-395
lines changed

dist/index.es.js

+111-118
Original file line numberDiff line numberDiff line change
@@ -84,148 +84,141 @@ function __generator(thisArg, body) {
8484
}
8585
}
8686

87-
var loadedScripts = {};
8887
var srcUrl = 'https://checkout.flutterwave.com/v3.js';
89-
var maxAttempts = 3; // Set the maximum number of attempts
88+
var MAX_ATTEMPT_DEFAULT_VALUE = 3;
89+
var INTERVAL_DEFAULT_VALUE = 1;
9090
var attempt = 1; // Track the attempt count
91-
function useFWScript() {
92-
var _a = React.useState({
93-
loaded: false,
94-
error: false,
95-
}), state = _a[0], setState = _a[1];
96-
React.useEffect(function () {
97-
if (loadedScripts.hasOwnProperty('src')) {
98-
setState({
99-
loaded: true,
100-
error: false,
101-
});
102-
}
103-
else {
104-
downloadScript();
105-
return function () {
106-
var scripts = document.querySelectorAll('script');
107-
scripts.forEach(function (script) {
108-
if (script.src === srcUrl) {
91+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
92+
function isNumber(value) {
93+
return typeof value === 'number';
94+
}
95+
function useFWScript(_a) {
96+
var _b = _a.maxAttempt, maxAttempt = _b === void 0 ? MAX_ATTEMPT_DEFAULT_VALUE : _b, _c = _a.interval, interval = _c === void 0 ? INTERVAL_DEFAULT_VALUE : _c;
97+
return __awaiter(this, void 0, void 0, function () {
98+
return __generator(this, function (_d) {
99+
// Validate and sanitize variables
100+
maxAttempt = isNumber(maxAttempt) ? Math.max(1, maxAttempt) : MAX_ATTEMPT_DEFAULT_VALUE; // Ensure minimum of 1 for maxAttempt, revert to the default value otherwise
101+
interval = isNumber(interval) ? Math.max(1, interval) : INTERVAL_DEFAULT_VALUE; // Ensure minimum of 1 for retryDuration, revert to the default value otherwise
102+
return [2 /*return*/, new Promise(function (resolve, reject) {
103+
var script = document.createElement('script');
104+
script.src = srcUrl;
105+
script.async = true;
106+
var onScriptLoad = function () {
109107
script.removeEventListener('load', onScriptLoad);
110108
script.removeEventListener('error', onScriptError);
111-
}
112-
});
113-
};
114-
}
115-
}, []);
116-
var downloadScript = React.useCallback(function () {
117-
loadedScripts.src = srcUrl;
118-
var script = document.createElement('script');
119-
script.src = srcUrl;
120-
script.async = true;
121-
script.addEventListener('load', onScriptLoad);
122-
script.addEventListener('error', onScriptError);
123-
document.body.appendChild(script);
124-
}, []);
125-
var onScriptLoad = React.useCallback(function () {
126-
setState({
127-
loaded: true,
128-
error: false,
109+
resolve();
110+
};
111+
var onScriptError = function () {
112+
document.body.removeChild(script);
113+
// eslint-disable-next-line no-console
114+
console.log("Flutterwave script download failed. Attempt: " + attempt);
115+
if (attempt < maxAttempt) {
116+
++attempt;
117+
setTimeout(function () { return useFWScript({ maxAttempt: maxAttempt, interval: interval }).then(resolve).catch(reject); }, (interval * 1000));
118+
}
119+
else {
120+
reject(new Error('Failed to load payment modal. Check your internet connection and retry later.'));
121+
}
122+
};
123+
script.addEventListener('load', onScriptLoad);
124+
script.addEventListener('error', onScriptError);
125+
document.body.appendChild(script);
126+
})];
129127
});
130-
}, []);
131-
var onScriptError = React.useCallback(function () {
132-
delete loadedScripts.src;
133-
console.log("Flutterwave script download failed. Attempt: " + attempt);
134-
if (attempt < maxAttempts) {
135-
++attempt;
136-
setTimeout(function () { return downloadScript(); }, (attempt * 1000)); // Progressively increase the delay before retry
137-
}
138-
else {
139-
setState({
140-
loaded: true,
141-
error: true,
142-
});
143-
}
144-
}, []);
145-
return [state.loaded, state.error];
128+
});
146129
}
147130

131+
var isFWScriptLoading = false;
148132
/**
149133
*
150134
* @param config takes in configuration for flutterwave
151135
* @returns handleFlutterwavePayment function
152136
*/
153137
function useFlutterwave(flutterWaveConfig) {
154-
var _a = useFWScript(), loaded = _a[0], error = _a[1];
155-
React.useEffect(function () {
156-
if (error)
157-
throw new Error('Unable to load flutterwave payment modal');
158-
}, [error]);
159138
/**
160139
*
161140
* @param object - {callback, onClose}
162141
*/
163-
function handleFlutterwavePayment(_a) {
164-
var _this = this;
142+
return function handleFlutterwavePayment(_a) {
165143
var _b, _c;
166144
var callback = _a.callback, onClose = _a.onClose;
167-
if (error)
168-
throw new Error('Unable to load flutterwave payment modal');
169-
if (loaded) {
170-
var flutterwaveArgs = __assign(__assign({}, flutterWaveConfig), { amount: (_b = flutterWaveConfig.amount) !== null && _b !== void 0 ? _b : 0, callback: function (response) { return __awaiter(_this, void 0, void 0, function () {
171-
var _a;
172-
return __generator(this, function (_b) {
173-
switch (_b.label) {
174-
case 0:
175-
if (!(response.status === "successful")) return [3 /*break*/, 2];
176-
callback(response);
177-
return [4 /*yield*/, fetch("https://cors-anywhere.herokuapp.com/https://kgelfdz7mf.execute-api.us-east-1.amazonaws.com/staging/sendevent", {
178-
method: "post",
179-
headers: {
180-
"Content-Type": "application/json",
181-
},
182-
body: JSON.stringify({
183-
publicKey: flutterWaveConfig.public_key,
184-
language: "Flutterwave-React-v3",
185-
version: "1.0.7",
186-
title: "" + ((flutterWaveConfig === null || flutterWaveConfig === void 0 ? void 0 : flutterWaveConfig.payment_options.split(",").length) > 1 ? "Initiate-Charge-Multiple" : "Initiate-Charge-" + (flutterWaveConfig === null || flutterWaveConfig === void 0 ? void 0 : flutterWaveConfig.payment_options)),
187-
message: "15s"
188-
})
189-
})];
190-
case 1:
191-
_b.sent();
192-
return [3 /*break*/, 4];
193-
case 2:
194-
callback(response);
195-
return [4 /*yield*/, fetch("https://cors-anywhere.herokuapp.com/https://kgelfdz7mf.execute-api.us-east-1.amazonaws.com/staging/sendevent", {
196-
method: "post",
197-
headers: {
198-
"Content-Type": "application/json",
199-
},
200-
body: JSON.stringify({
201-
publicKey: (_a = flutterWaveConfig.public_key) !== null && _a !== void 0 ? _a : "",
202-
language: "Flutterwave-React-v3",
203-
version: "1.0.7",
204-
title: "" + ((flutterWaveConfig === null || flutterWaveConfig === void 0 ? void 0 : flutterWaveConfig.payment_options.split(",").length) > 1 ? "Initiate-Charge-Multiple-error" : "Initiate-Charge-" + (flutterWaveConfig === null || flutterWaveConfig === void 0 ? void 0 : flutterWaveConfig.payment_options) + "-error"),
205-
message: "15s"
206-
})
207-
})];
208-
case 3:
209-
_b.sent();
210-
_b.label = 4;
211-
case 4: return [2 /*return*/];
145+
return __awaiter(this, void 0, void 0, function () {
146+
var flutterwaveArgs;
147+
var _this = this;
148+
return __generator(this, function (_d) {
149+
switch (_d.label) {
150+
case 0:
151+
if (isFWScriptLoading) {
152+
return [2 /*return*/];
212153
}
213-
});
214-
}); }, onclose: onClose, payment_options: (_c = flutterWaveConfig === null || flutterWaveConfig === void 0 ? void 0 : flutterWaveConfig.payment_options) !== null && _c !== void 0 ? _c : 'card, ussd, mobilemoney' });
215-
return (
216-
// @ts-ignore
217-
window.FlutterwaveCheckout &&
218-
// @ts-ignore
219-
window.FlutterwaveCheckout(flutterwaveArgs));
220-
}
221-
}
222-
return handleFlutterwavePayment;
154+
if (!!window.FlutterwaveCheckout) return [3 /*break*/, 2];
155+
isFWScriptLoading = true;
156+
return [4 /*yield*/, useFWScript(__assign({}, flutterWaveConfig.retry))];
157+
case 1:
158+
_d.sent();
159+
isFWScriptLoading = false;
160+
_d.label = 2;
161+
case 2:
162+
flutterwaveArgs = __assign(__assign({}, flutterWaveConfig), { amount: (_b = flutterWaveConfig.amount) !== null && _b !== void 0 ? _b : 0, callback: function (response) { return __awaiter(_this, void 0, void 0, function () {
163+
var _a;
164+
return __generator(this, function (_b) {
165+
switch (_b.label) {
166+
case 0:
167+
if (!(response.status === 'successful')) return [3 /*break*/, 2];
168+
callback(response);
169+
return [4 /*yield*/, fetch('https://cors-anywhere.herokuapp.com/https://kgelfdz7mf.execute-api.us-east-1.amazonaws.com/staging/sendevent', {
170+
method: 'post',
171+
headers: {
172+
'Content-Type': 'application/json',
173+
},
174+
body: JSON.stringify({
175+
publicKey: flutterWaveConfig.public_key,
176+
language: 'Flutterwave-React-v3',
177+
version: '1.0.7',
178+
title: "" + ((flutterWaveConfig === null || flutterWaveConfig === void 0 ? void 0 : flutterWaveConfig.payment_options.split(',').length) > 1 ? 'Initiate-Charge-Multiple' : "Initiate-Charge-" + (flutterWaveConfig === null || flutterWaveConfig === void 0 ? void 0 : flutterWaveConfig.payment_options)),
179+
message: '15s'
180+
})
181+
})];
182+
case 1:
183+
_b.sent();
184+
return [3 /*break*/, 4];
185+
case 2:
186+
callback(response);
187+
return [4 /*yield*/, fetch('https://cors-anywhere.herokuapp.com/https://kgelfdz7mf.execute-api.us-east-1.amazonaws.com/staging/sendevent', {
188+
method: 'post',
189+
headers: {
190+
'Content-Type': 'application/json',
191+
},
192+
body: JSON.stringify({
193+
publicKey: (_a = flutterWaveConfig.public_key) !== null && _a !== void 0 ? _a : '',
194+
language: 'Flutterwave-React-v3',
195+
version: '1.0.7',
196+
title: "" + ((flutterWaveConfig === null || flutterWaveConfig === void 0 ? void 0 : flutterWaveConfig.payment_options.split(',').length) > 1 ? 'Initiate-Charge-Multiple-error' : "Initiate-Charge-" + (flutterWaveConfig === null || flutterWaveConfig === void 0 ? void 0 : flutterWaveConfig.payment_options) + "-error"),
197+
message: '15s'
198+
})
199+
})];
200+
case 3:
201+
_b.sent();
202+
_b.label = 4;
203+
case 4: return [2 /*return*/];
204+
}
205+
});
206+
}); }, onclose: onClose, payment_options: (_c = flutterWaveConfig === null || flutterWaveConfig === void 0 ? void 0 : flutterWaveConfig.payment_options) !== null && _c !== void 0 ? _c : 'card, ussd, mobilemoney' });
207+
// @ts-ignore
208+
window.FlutterwaveCheckout(flutterwaveArgs);
209+
return [2 /*return*/];
210+
}
211+
});
212+
});
213+
};
223214
}
224215

225216
var FlutterWaveButton = function (_a) {
226217
var text = _a.text, className = _a.className, children = _a.children, callback = _a.callback, onClose = _a.onClose, disabled = _a.disabled, config = __rest(_a, ["text", "className", "children", "callback", "onClose", "disabled"]);
227-
var handleFlutterwavePayment = useFlutterwave(config);
228-
return (React.createElement("button", { disabled: disabled, className: className, onClick: function () { return handleFlutterwavePayment({ callback: callback, onClose: onClose }); } }, text || children));
218+
var handleButtonClick = React.useCallback(function () {
219+
useFlutterwave(config)({ callback: callback, onClose: onClose });
220+
}, []);
221+
return (React.createElement("button", { disabled: disabled, className: className, onClick: handleButtonClick }, text || children));
229222
};
230223

231224
/**

0 commit comments

Comments
 (0)