@adyen/react-native
Version:
Wraps Adyen Checkout Drop-In and Components for iOS and Android for convenient use with React Native
164 lines (156 loc) • 6.64 kB
JavaScript
;
import React, { useRef, useCallback, useEffect, useState, useMemo } from 'react';
import { NativeEventEmitter } from 'react-native';
import { Event, ErrorCode } from '../core';
import { AdyenCheckoutContext } from '../hooks/useAdyenCheckout';
import { getWrapper } from '../modules/base/getWrapper';
import { SessionHelper } from '../modules/session/SessionHelperModule';
import { checkConfiguration, checkPaymentMethodsResponse } from './utils';
/**
* Props for AdyenCheckout
*/
import { jsx as _jsx } from "react/jsx-runtime";
export const AdyenCheckout = ({
config,
paymentMethods,
session,
onSubmit,
onError,
onAdditionalDetails,
onComplete,
children
}) => {
const subscriptions = useRef([]);
const onCompleteRef = useRef(onComplete);
const onErrorRef = useRef(onError);
const [sessionContext, setSessionContext] = useState(undefined);
const currentPaymentMethods = useMemo(() => {
return paymentMethods ?? sessionContext?.paymentMethods;
}, [paymentMethods, sessionContext]);
function removeEventListeners() {
subscriptions.current.forEach(s => s.remove());
}
useEffect(() => {
onCompleteRef.current = onComplete;
}, [onComplete]);
useEffect(() => {
onErrorRef.current = onError;
}, [onError]);
useEffect(() => {
SessionHelper.removeAllListeners();
const completeHandler = result => onCompleteRef.current?.(result, SessionHelper);
const errorHandler = error => onErrorRef.current?.(error, SessionHelper);
SessionHelper.assignCompletionHandler(completeHandler);
SessionHelper.assignErrorHandler(errorHandler);
return () => {
removeEventListeners();
SessionHelper.removeAllListeners();
SessionHelper.hide(true);
};
}, []);
useEffect(() => {
if (session && !sessionContext) {
SessionHelper.createSession(session, config).then(sessionResponse => setSessionContext(sessionResponse)).catch(error => {
const errorDTO = {
message: String(error),
errorCode: ErrorCode.sessionError
};
onErrorRef.current?.(errorDTO, SessionHelper);
});
}
}, [session, sessionContext, config, setSessionContext]);
const startEventListeners = useCallback(nativeComponent => {
removeEventListeners();
const eventEmitter = new NativeEventEmitter(nativeComponent.eventEmitterTarget);
subscriptions.current = [];
/** Subscribe to an event if supported by native module */
function subscribeIfSupported(event, handler) {
if (nativeComponent.isSupported(event)) {
subscriptions.current.push(eventEmitter.addListener(event, handler));
}
}
function submitPayment(data, extra) {
const payload = {
...data,
returnUrl: data.returnUrl ?? config.returnUrl
};
onSubmit?.(payload, nativeComponent, extra);
}
// Core events
subscribeIfSupported(Event.onSubmit, response => submitPayment(response.paymentData, response.extra));
subscribeIfSupported(Event.onError, error => onError?.(error, nativeComponent));
subscribeIfSupported(Event.onComplete, data => onComplete?.(data, nativeComponent));
subscribeIfSupported(Event.onAdditionalDetails, data => onAdditionalDetails?.(data, nativeComponent));
// Stored payment method removal
const onDisableStoredPaymentMethodCallback = config.dropin?.onDisableStoredPaymentMethod;
if (onDisableStoredPaymentMethodCallback) {
const nativeModule = nativeComponent;
subscribeIfSupported(Event.onDisableStoredPaymentMethod, data => onDisableStoredPaymentMethodCallback(data, () => nativeModule.removeStored(true), () => nativeModule.removeStored(false)));
}
// Address lookup
const onUpdateAddressCallback = config.card?.onUpdateAddress;
const onConfirmAddressCallback = config.card?.onConfirmAddress;
if (onUpdateAddressCallback && onConfirmAddressCallback) {
const nativeModule = nativeComponent;
subscribeIfSupported(Event.onAddressUpdate, async prompt => onUpdateAddressCallback(prompt, nativeModule));
subscribeIfSupported(Event.onAddressConfirm, address => onConfirmAddressCallback(address, nativeModule));
}
// Partial payments
const onBalanceCheckCallback = config.partialPayment?.onBalanceCheck;
const onOrderRequestCallback = config.partialPayment?.onOrderRequest;
const onOrderCancelCallback = config.partialPayment?.onOrderCancel;
if (onBalanceCheckCallback && onOrderRequestCallback && onOrderCancelCallback) {
const component = nativeComponent;
subscribeIfSupported(Event.onCheckBalance, async paymentData => onBalanceCheckCallback(paymentData, balance => component.provideBalance(true, balance, undefined), error => component.provideBalance(false, undefined, error)));
subscribeIfSupported(Event.onRequestOrder, () => {
onOrderRequestCallback(order => component.provideOrder(true, order, undefined), error => component.provideOrder(false, undefined, error));
});
subscribeIfSupported(Event.onCancelOrder, ({
order,
shouldUpdatePaymentMethods
}) => onOrderCancelCallback(order, shouldUpdatePaymentMethods, component));
}
// BIN lookup and value
const onBinLookupCallback = config.card?.onBinLookup;
if (onBinLookupCallback) {
subscribeIfSupported(Event.onBinLookup, onBinLookupCallback);
}
const onBinValueCallback = config.card?.onBinValue;
if (onBinValueCallback) {
subscribeIfSupported(Event.onBinValue, onBinValueCallback);
}
}, [onSubmit, onAdditionalDetails, onComplete, onError, config]);
const start = useCallback(typeName => {
const validPaymentMethods = checkPaymentMethodsResponse(currentPaymentMethods);
const {
nativeComponent,
paymentMethod
} = getWrapper(typeName, validPaymentMethods);
checkConfiguration(config);
startEventListeners(nativeComponent);
if (paymentMethod) {
const singlePaymentMethods = {
paymentMethods: [paymentMethod]
};
const singlePaymentConfig = {
...config,
dropin: {
skipListWhenSinglePaymentMethod: true
}
};
nativeComponent.open(singlePaymentMethods, singlePaymentConfig);
} else {
nativeComponent.open(validPaymentMethods, config);
}
}, [config, currentPaymentMethods, startEventListeners]);
return /*#__PURE__*/_jsx(AdyenCheckoutContext.Provider, {
value: {
start,
config,
paymentMethods: currentPaymentMethods,
isReady: currentPaymentMethods !== undefined
},
children: children
});
};
//# sourceMappingURL=AdyenCheckout.js.map