diff --git a/src/context/MainStateProvider.tsx b/src/context/MainStateProvider.tsx
index 94c134d..8b6289a 100644
--- a/src/context/MainStateProvider.tsx
+++ b/src/context/MainStateProvider.tsx
@@ -1,37 +1,26 @@
import {
useCallback,
useContext,
- useEffect,
useMemo,
useRef,
useState,
} from 'react';
-import { Alert, AppState, AppStateStatus, Linking } from 'react-native';
-
-import i18next from 'i18next';
-
import PaymentModal from '../components/PaymentModal';
import Sheet, { SheetRefProps } from '../components/Sheet';
-import payForSession from '../services/payForSessionService';
-import sessionShow from '../services/sessionShow';
-
-import { parsePaymentMethods } from '../util/helpers';
import {
CreatePaymentFuncType,
initialState,
InitPrams,
- KomojuProviderIprops,
- PaymentStatuses,
- ResponseScreenStatuses,
- sessionPayProps,
- TokenResponseStatuses
-} from '../util/types';
-import { validateSessionResponse } from '../util/validator';
+ KomojuProviderIprops} from '../util/types';
import '../assets/languages/i18n';
import { Actions, DispatchContext, KomojuContext } from './state';
+import useBackgroundHandler from '../hooks/useBackgroundHandler';
+import useDeepLinkHandler from '../hooks/useDeepLinkHandler';
+import usePaymentHandler from '../hooks/usePaymentHandler';
+import useMainStateUtils from '../hooks/useMainStateUtils';
export const MainStateProvider = (props: KomojuProviderIprops) => {
const dispatch = useContext(DispatchContext);
@@ -45,293 +34,65 @@ export const MainStateProvider = (props: KomojuProviderIprops) => {
// ref to hold client provided session Id
const sessionIdRef = useRef('');
- useEffect(() => {
- // Add event listener for deep links
- const subscription = Linking.addEventListener(
- 'url',
- handleDeepLinkStateChange
- );
-
- // Add event listener for deep links
- const windowChangeListener = AppState.addEventListener(
- "change",
- handleBackgroundStateChange
- );
-
- return () => {
- subscription.remove();
- windowChangeListener.remove();
- };
- }, [props]);
-
- // This callback method is used to check the background state
- const handleBackgroundStateChange = async (status: AppStateStatus) => {
- startLoading();
-
- if (status === "active") {
- // if this is a session flow, check until session response changes from 'pending' to 'completed' or 'error'
- const sessionShowPayload = {
- publishableKey: props.publishableKey,
- sessionId: sessionIdRef.current,
- };
-
- // fetch session status to check if the payment is completed
- const sessionResponse = await sessionShow(sessionShowPayload);
-
- // if payment success showing success screen or if failed showing error screen
- if (sessionResponse?.status === PaymentStatuses.SUCCESS) {
- if (
- sessionResponse?.payment?.status === TokenResponseStatuses.CAPTURED
- ) {
- onPaymentSuccess();
- } else {
- onPaymentAwaiting();
- } // calling user passed onComplete method with session response data
- onCompleteCallback.current &&
- // TODO: Fix this type error
- // @ts-expect-error - Argument of type 'PaymentSessionResponse' is not assignable to parameter of type 'string'.
- onCompleteCallback.current(sessionResponse);
- } else if (
- sessionResponse?.payment?.status === PaymentStatuses.CANCELLED
- ) {
- onPaymentCancelled();
- } else if (sessionResponse?.expired) {
- onSessionExpired();
- } else if (
- sessionResponse?.status === PaymentStatuses.ERROR ||
- sessionResponse?.payment?.status === PaymentStatuses.ERROR ||
- sessionResponse?.secure_token?.verification_status ===
- TokenResponseStatuses.ERROR
- ) {
- onPaymentFailed();
- }
- }
-
- // after all api calls are done stopping the loading indicator
- stopLoading();
- };
-
- const openPaymentSheet = () => {
- if (props?.useBottomSheet) {
- sheetRef?.current?.open();
- } else {
- setModalVisible(true);
- }
- };
-
- const closePaymentSheet = () => {
- // TODO: Fix this type error
- // @ts-expect-error - Object is possibly 'null'.
- sheetRef?.current?.close(false);
- setModalVisible(false);
- };
-
- const resetGlobalStates = () =>
- dispatch({
- type: Actions.RESET_STATES,
- payload: initialState,
- });
-
- // when payment is success global state is rest and invoking the success screen
- const onPaymentSuccess = () => {
- resetGlobalStates();
- dispatch({
- type: Actions.SET_PAYMENT_STATE,
- payload: ResponseScreenStatuses.SUCCESS,
- });
- };
-
- // when payment is failed invoking the error screen
- const onPaymentFailed = () =>
- dispatch({
- type: Actions.SET_PAYMENT_STATE,
- payload: ResponseScreenStatuses.FAILED,
- });
-
- // when payment is cancelled by the user
- const onPaymentCancelled = () => {
- resetGlobalStates();
- dispatch({
- type: Actions.SET_PAYMENT_STATE,
- payload: ResponseScreenStatuses.CANCELLED,
- });
- };
-
- // when payment is completed but awaiting payment
- const onPaymentAwaiting = () => {
- resetGlobalStates();
- dispatch({
- type: Actions.SET_PAYMENT_STATE,
- payload: ResponseScreenStatuses.COMPLETE,
- });
- };
-
- // when payment is failed invoking the error screen
- const onSessionExpired = () =>
- dispatch({
- type: Actions.SET_PAYMENT_STATE,
- payload: ResponseScreenStatuses.EXPIRED,
- });
-
- const onUserCancel = async () => {
- if (onDismissCallback.current) {
- const sessionShowPayload = {
- publishableKey: props?.publishableKey,
- sessionId: sessionIdRef.current,
- };
-
- // fetch session status to check if the payment is completed
- const sessionResponse = await sessionShow(sessionShowPayload);
- // invoking client provided onDismiss callback
- // TODO: Fix this type error
- // @ts-expect-error - Argument of type 'PaymentSessionResponse' is not assignable to parameter of type 'string'.
- onDismissCallback.current(sessionResponse);
- }
- };
-
- // showing overlay loading indicator disabling all interactions
- const startLoading = () =>
- dispatch({
- type: Actions.SET_LOADING,
- payload: true,
- });
-
- // Hiding overlay loading indicator
- const stopLoading = () =>
- dispatch({
- type: Actions.SET_LOADING,
- payload: false,
- });
-
- const openURL = async (url: string) => {
- try {
- await Linking.openURL(url);
- } catch (err) {
- Alert.alert('Redirection not working. Please contact support!');
- }
- };
-
- // validating the provided session ID by user before proceeding
- const validateSession = async (sessionId: string) => {
- startLoading();
-
- // Fetching session data from given session ID
- const sessionData = await sessionShow({
- sessionId,
- publishableKey: props.publishableKey,
- });
-
- // validating the session data and closing the payment gateway if data is not valid
- if (validateSessionResponse(sessionData)) {
- closePaymentSheet();
- Alert.alert('Error', 'Invalid Session');
- } else {
- // if explicitly language is not set. set to the localization from session
- if (props?.language) {
- i18next.changeLanguage(props?.language);
- } else {
- i18next.changeLanguage(sessionData?.default_locale);
- }
-
- // if session is valid setting amount, currency type at global store for future use
- dispatch({ type: Actions.SET_AMOUNT, payload: sessionData?.amount });
- dispatch({ type: Actions.SET_CURRENCY, payload: sessionData?.currency });
-
- // if user provided explicitly payments methods via props, will give priority to that over session payment methods
- const paymentMethods = parsePaymentMethods(
- props?.paymentMethods,
- sessionData?.payment_methods
- );
-
- // setting the payment methods in global state
- dispatch({
- type: Actions.SET_PAYMENT_METHODS,
- payload: paymentMethods,
- });
- // setting the current selected payment method as the first payment method on the list
- dispatch({
- type: Actions.SET_PAYMENT_OPTION,
- payload: paymentMethods ? paymentMethods[0]?.type : '',
- });
- }
- stopLoading();
- };
-
- // This callback method is used to intercept Web View urls
- const handleDeepLinkStateChange = async () => {
- startLoading();
-
- // if this is a session flow, check until session response changes from 'pending' to 'completed' or 'error'
- const sessionShowPayload = {
- publishableKey: props.publishableKey,
- sessionId: sessionIdRef.current,
- };
-
- // fetch session status to check if the payment is completed
- let sessionResponse = await sessionShow(sessionShowPayload);
-
- // Polling until session verification status changes
- while (
- sessionResponse?.status === PaymentStatuses.PENDING &&
- sessionResponse?.payment?.status !== PaymentStatuses.CANCELLED &&
- sessionResponse?.secure_token?.verification_status !==
- TokenResponseStatuses.ERROR
- ) {
- sessionResponse = await sessionShow(sessionShowPayload);
- }
-
- // if payment success showing success screen or if failed showing error screen
- if (sessionResponse?.status === PaymentStatuses.SUCCESS) {
- if (sessionResponse?.payment?.status === TokenResponseStatuses.CAPTURED) {
- onPaymentSuccess();
- } else {
- onPaymentAwaiting();
- }
- // calling user passed onComplete method with session response data
- onCompleteCallback.current &&
- // TODO: Fix this type error
- // @ts-expect-error - Argument of type 'PaymentSessionResponse' is not assignable to parameter of type 'string'.
- onCompleteCallback.current(sessionResponse);
- } else if (sessionResponse?.payment?.status === PaymentStatuses.CANCELLED) {
- onPaymentCancelled();
- } else {
- onPaymentFailed();
- }
-
- // after all api calls are done stopping the loading indicator
- stopLoading();
- };
-
- // Session pay callback. this method handles all the payment logic and APIs
- const sessionPay = ({ sessionId }: CreatePaymentFuncType) => {
- return async ({ paymentType, paymentDetails }: sessionPayProps) => {
- // Start of the payment handling method
- startLoading();
-
- // initiate payment for the session ID with payment details
- const response = await payForSession({
- paymentType,
- sessionId,
- publishableKey: props.publishableKey,
- paymentDetails,
- });
-
- stopLoading();
-
- if (response?.status === PaymentStatuses.PENDING) {
- openURL(response.redirect_url);
- } else if (response?.status === PaymentStatuses.SUCCESS) {
- if (response?.payment?.status === TokenResponseStatuses.CAPTURED) {
- onPaymentSuccess();
- } else if (response?.payment?.payment_details?.instructions_url) {
- openURL(response?.payment?.payment_details?.instructions_url);
- onPaymentAwaiting();
- }
- } else {
- onPaymentFailed();
- }
- };
- };
+ // Get all the util functions that needs to function the Main State
+ const {
+ startLoading,
+ stopLoading,
+ onPaymentAwaiting,
+ onPaymentCancelled,
+ onSessionExpired,
+ onPaymentFailed,
+ onPaymentSuccess,
+ closePaymentSheet,
+ onUserCancel,
+ openPaymentSheet,
+ resetGlobalStates
+ } = useMainStateUtils({
+ props: props,
+ sheetRef: sheetRef,
+ sessionIdRef: sessionIdRef,
+ toggleUIVisibility: (value: boolean) => setModalVisible(value),
+ initialState: initialState,
+ onDismissCallback: onDismissCallback,
+ })
+
+ // Handle events when module goes foreground
+ useBackgroundHandler({
+ props: props,
+ startLoading: startLoading,
+ stopLoading: stopLoading,
+ sessionIdRef: sessionIdRef,
+ onCompleteCallback: onCompleteCallback,
+ onPaymentAwaiting: onPaymentAwaiting,
+ onPaymentCancelled: onPaymentCancelled,
+ onSessionExpired: onSessionExpired,
+ onPaymentFailed: onPaymentFailed,
+ onPaymentSuccess: onPaymentSuccess
+ })
+
+ // Handle deep-links of the module
+ useDeepLinkHandler({
+ props: props,
+ startLoading: startLoading,
+ stopLoading: stopLoading,
+ sessionIdRef: sessionIdRef,
+ onCompleteCallback: onCompleteCallback,
+ onPaymentAwaiting: onPaymentAwaiting,
+ onPaymentCancelled: onPaymentCancelled,
+ onPaymentFailed: onPaymentFailed,
+ onPaymentSuccess: onPaymentSuccess
+ })
+
+ // Handle validations of the session and pay for session
+ const { sessionPay, validateSession } = usePaymentHandler({
+ props: props,
+ startLoading: startLoading,
+ stopLoading: stopLoading,
+ onPaymentAwaiting: onPaymentAwaiting,
+ onPaymentFailed: onPaymentFailed,
+ onPaymentSuccess: onPaymentSuccess,
+ closePaymentSheet: closePaymentSheet
+ })
const createPayment = useCallback(
({ sessionId, onComplete, onDismiss }: CreatePaymentFuncType) => {
@@ -366,9 +127,10 @@ export const MainStateProvider = (props: KomojuProviderIprops) => {
}, []);
// TODO: Fix this type error
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
- const initializeKomoju = useCallback((_params: InitPrams) => {}, []);
+
+ const initializeKomoju = useCallback((_params: InitPrams) => { }, []);
+ // Conditionally rendering the payment ui
const renderPaymentUI = useMemo(() => {
const UI = props?.useBottomSheet ? (
diff --git a/src/hooks/useBackgroundHandler.tsx b/src/hooks/useBackgroundHandler.tsx
new file mode 100644
index 0000000..f115686
--- /dev/null
+++ b/src/hooks/useBackgroundHandler.tsx
@@ -0,0 +1,94 @@
+import React, { MutableRefObject, useEffect } from 'react'
+import { View, Text, AppState, AppStateStatus } from 'react-native'
+import { KomojuProviderIprops, PaymentStatuses, TokenResponseStatuses } from '../util/types';
+import sessionShow from '../services/sessionShow';
+
+
+type Props = {
+ props: KomojuProviderIprops,
+ startLoading: () => void
+ stopLoading: () => void
+ sessionIdRef: MutableRefObject
+ onCompleteCallback: MutableRefObject
+ onPaymentSuccess: () => void
+ onPaymentAwaiting: () => void
+ onPaymentCancelled: () => void
+ onSessionExpired: () => void
+ onPaymentFailed: () => void
+}
+
+const useBackgroundHandler = ({
+ props,
+ startLoading,
+ stopLoading,
+ sessionIdRef,
+ onCompleteCallback,
+ onPaymentAwaiting,
+ onPaymentCancelled,
+ onPaymentFailed,
+ onSessionExpired,
+ onPaymentSuccess
+}: Props) => {
+
+ useEffect(() => {
+ // Add event listener for deep links
+ const windowChangeListener = AppState.addEventListener(
+ "change",
+ handleBackgroundStateChange
+ );
+
+ return () => {
+ windowChangeListener.remove();
+ };
+ }, [props]);
+
+ const handleBackgroundStateChange = async (status: AppStateStatus) => {
+ startLoading();
+
+ if (status === "active") {
+ // if this is a session flow, check until session response changes from 'pending' to 'completed' or 'error'
+ const sessionShowPayload = {
+ publishableKey: props.publishableKey,
+ sessionId: sessionIdRef.current,
+ };
+
+ // fetch session status to check if the payment is completed
+ const sessionResponse = await sessionShow(sessionShowPayload);
+
+ // if payment success showing success screen or if failed showing error screen
+ if (sessionResponse?.status === PaymentStatuses.SUCCESS) {
+ if (
+ sessionResponse?.payment?.status === TokenResponseStatuses.CAPTURED
+ ) {
+ onPaymentSuccess();
+ } else {
+ onPaymentAwaiting();
+ } // calling user passed onComplete method with session response data
+ onCompleteCallback.current &&
+ // TODO: Fix this type error
+ // @ts-expect-error - Argument of type 'PaymentSessionResponse' is not assignable to parameter of type 'string'.
+ onCompleteCallback.current(sessionResponse);
+ } else if (
+ sessionResponse?.payment?.status === PaymentStatuses.CANCELLED
+ ) {
+ onPaymentCancelled();
+ } else if (sessionResponse?.expired) {
+ onSessionExpired();
+ } else if (
+ sessionResponse?.status === PaymentStatuses.ERROR ||
+ sessionResponse?.payment?.status === PaymentStatuses.ERROR ||
+ sessionResponse?.secure_token?.verification_status ===
+ TokenResponseStatuses.ERROR
+ ) {
+ onPaymentFailed();
+ }
+ }
+
+ // after all api calls are done stopping the loading indicator
+ stopLoading();
+ };
+
+ return undefined;
+}
+
+export default useBackgroundHandler
\ No newline at end of file
diff --git a/src/hooks/useDeepLinkHandler.tsx b/src/hooks/useDeepLinkHandler.tsx
new file mode 100644
index 0000000..327ac57
--- /dev/null
+++ b/src/hooks/useDeepLinkHandler.tsx
@@ -0,0 +1,89 @@
+import { Linking } from 'react-native'
+import { MutableRefObject, useEffect } from 'react'
+import { KomojuProviderIprops, PaymentStatuses, TokenResponseStatuses } from '../util/types'
+import sessionShow from '../services/sessionShow'
+
+type Props = {
+ props: KomojuProviderIprops,
+ startLoading: () => void
+ stopLoading: () => void
+ sessionIdRef: MutableRefObject
+ onCompleteCallback: MutableRefObject
+ onPaymentSuccess: () => void
+ onPaymentAwaiting: () => void
+ onPaymentCancelled: () => void
+ onPaymentFailed: () => void
+}
+
+const useDeepLinkHandler = ({
+ props,
+ startLoading,
+ stopLoading,
+ sessionIdRef,
+ onCompleteCallback,
+ onPaymentAwaiting,
+ onPaymentCancelled,
+ onPaymentFailed,
+ onPaymentSuccess
+}: Props) => {
+
+ useEffect(() => {
+ // Add event listener for deep links
+ const subscription = Linking.addEventListener(
+ 'url',
+ handleDeepLinkStateChange
+ );
+
+ return () => {
+ subscription.remove();
+ };
+ }, [props]);
+
+ const handleDeepLinkStateChange = async () => {
+ startLoading();
+
+ // if this is a session flow, check until session response changes from 'pending' to 'completed' or 'error'
+ const sessionShowPayload = {
+ publishableKey: props.publishableKey,
+ sessionId: sessionIdRef.current,
+ };
+
+ // fetch session status to check if the payment is completed
+ let sessionResponse = await sessionShow(sessionShowPayload);
+
+ // Polling until session verification status changes
+ while (
+ sessionResponse?.status === PaymentStatuses.PENDING &&
+ sessionResponse?.payment?.status !== PaymentStatuses.CANCELLED &&
+ sessionResponse?.secure_token?.verification_status !==
+ TokenResponseStatuses.ERROR
+ ) {
+ sessionResponse = await sessionShow(sessionShowPayload);
+ }
+
+ // if payment success showing success screen or if failed showing error screen
+ if (sessionResponse?.status === PaymentStatuses.SUCCESS) {
+ if (sessionResponse?.payment?.status === TokenResponseStatuses.CAPTURED) {
+ onPaymentSuccess();
+ } else {
+ onPaymentAwaiting();
+ }
+ // calling user passed onComplete method with session response data
+ onCompleteCallback.current &&
+ // TODO: Fix this type error
+ // @ts-expect-error - Argument of type 'PaymentSessionResponse' is not assignable to parameter of type 'string'.
+ onCompleteCallback.current(sessionResponse);
+ } else if (sessionResponse?.payment?.status === PaymentStatuses.CANCELLED) {
+ onPaymentCancelled();
+ } else {
+ onPaymentFailed();
+ }
+
+ // after all api calls are done stopping the loading indicator
+ stopLoading();
+ };
+
+ return undefined;
+}
+
+export default useDeepLinkHandler
\ No newline at end of file
diff --git a/src/hooks/useMainStateUtils.tsx b/src/hooks/useMainStateUtils.tsx
new file mode 100644
index 0000000..c01457c
--- /dev/null
+++ b/src/hooks/useMainStateUtils.tsx
@@ -0,0 +1,134 @@
+import { MutableRefObject, RefObject, useContext } from 'react'
+
+import { Actions, DispatchContext } from '../context/state';
+import { SheetRefProps } from '../components/Sheet';
+import { KomojuProviderIprops, ResponseScreenStatuses, State } from '../util/types';
+import sessionShow from '../services/sessionShow';
+
+type Props = {
+ props: KomojuProviderIprops,
+ sheetRef: RefObject,
+ sessionIdRef: MutableRefObject
+ toggleUIVisibility: (value: boolean) => void,
+ initialState: State,
+ onDismissCallback: MutableRefObject,
+}
+
+const useMainStateUtils = ({
+ props,
+ sheetRef,
+ sessionIdRef,
+ toggleUIVisibility,
+ initialState,
+ onDismissCallback
+
+}: Props) => {
+ const dispatch = useContext(DispatchContext);
+ const openPaymentSheet = () => {
+ if (props?.useBottomSheet) {
+ sheetRef?.current?.open();
+ } else {
+ toggleUIVisibility(true);
+ }
+ };
+
+ const closePaymentSheet = () => {
+ // TODO: Fix this type error
+ // @ts-expect-error - Object is possibly 'null'.
+ sheetRef?.current?.close(false);
+ toggleUIVisibility(false);
+ };
+
+ const resetGlobalStates = () =>
+ dispatch({
+ type: Actions.RESET_STATES,
+ payload: initialState,
+ });
+
+ // when payment is success global state is rest and invoking the success screen
+ const onPaymentSuccess = () => {
+ resetGlobalStates();
+ dispatch({
+ type: Actions.SET_PAYMENT_STATE,
+ payload: ResponseScreenStatuses.SUCCESS,
+ });
+ };
+
+ // when payment is failed invoking the error screen
+ const onPaymentFailed = () =>
+ dispatch({
+ type: Actions.SET_PAYMENT_STATE,
+ payload: ResponseScreenStatuses.FAILED,
+ });
+
+ // when payment is cancelled by the user
+ const onPaymentCancelled = () => {
+ resetGlobalStates();
+ dispatch({
+ type: Actions.SET_PAYMENT_STATE,
+ payload: ResponseScreenStatuses.CANCELLED,
+ });
+ };
+
+ // when payment is completed but awaiting payment
+ const onPaymentAwaiting = () => {
+ resetGlobalStates();
+ dispatch({
+ type: Actions.SET_PAYMENT_STATE,
+ payload: ResponseScreenStatuses.COMPLETE,
+ });
+ };
+
+ // when payment is failed invoking the error screen
+ const onSessionExpired = () =>
+ dispatch({
+ type: Actions.SET_PAYMENT_STATE,
+ payload: ResponseScreenStatuses.EXPIRED,
+ });
+
+ const onUserCancel = async () => {
+ if (onDismissCallback.current) {
+ const sessionShowPayload = {
+ publishableKey: props?.publishableKey,
+ sessionId: sessionIdRef.current,
+ };
+
+ // fetch session status to check if the payment is completed
+ const sessionResponse = await sessionShow(sessionShowPayload);
+ // invoking client provided onDismiss callback
+ // TODO: Fix this type error
+ // @ts-expect-error - Argument of type 'PaymentSessionResponse' is not assignable to parameter of type 'string'.
+ onDismissCallback.current(sessionResponse);
+ }
+ };
+
+ // showing overlay loading indicator disabling all interactions
+ const startLoading = () =>
+ dispatch({
+ type: Actions.SET_LOADING,
+ payload: true,
+ });
+
+ // Hiding overlay loading indicator
+ const stopLoading = () =>
+ dispatch({
+ type: Actions.SET_LOADING,
+ payload: false,
+ });
+
+ return {
+ openPaymentSheet,
+ closePaymentSheet,
+ onPaymentSuccess,
+ onPaymentFailed,
+ onPaymentCancelled,
+ onPaymentAwaiting,
+ onSessionExpired,
+ onUserCancel,
+ startLoading,
+ stopLoading,
+ resetGlobalStates
+ }
+}
+
+export default useMainStateUtils
\ No newline at end of file
diff --git a/src/hooks/usePaymentHandler.tsx b/src/hooks/usePaymentHandler.tsx
new file mode 100644
index 0000000..368235f
--- /dev/null
+++ b/src/hooks/usePaymentHandler.tsx
@@ -0,0 +1,124 @@
+import { useContext } from 'react'
+import { Alert, Linking } from 'react-native'
+import i18next from 'i18next';
+
+import { CreatePaymentFuncType, KomojuProviderIprops, PaymentStatuses, sessionPayProps, TokenResponseStatuses } from '../util/types'
+import sessionShow from '../services/sessionShow'
+import { validateSessionResponse } from '../util/validator'
+import { Actions, DispatchContext } from '../context/state';
+import { parsePaymentMethods } from '../util/helpers';
+import payForSession from '../services/payForSessionService';
+
+type Props = {
+ props: KomojuProviderIprops,
+ startLoading: () => void
+ stopLoading: () => void
+ onPaymentSuccess: () => void
+ onPaymentAwaiting: () => void
+ onPaymentFailed: () => void
+ closePaymentSheet: () => void
+}
+
+const usePaymentHandler = ({
+ props,
+ startLoading,
+ stopLoading,
+ onPaymentAwaiting,
+ onPaymentFailed,
+ onPaymentSuccess,
+ closePaymentSheet
+}: Props) => {
+ const dispatch = useContext(DispatchContext);
+
+ // validating the provided session ID by user before proceeding
+ const validateSession = async (sessionId: string) => {
+ startLoading();
+
+ // Fetching session data from given session ID
+ const sessionData = await sessionShow({
+ sessionId,
+ publishableKey: props.publishableKey,
+ });
+
+ // validating the session data and closing the payment gateway if data is not valid
+ if (validateSessionResponse(sessionData)) {
+ closePaymentSheet();
+ Alert.alert('Error', 'Invalid Session');
+ } else {
+ // if explicitly language is not set. set to the localization from session
+ if (props?.language) {
+ i18next.changeLanguage(props?.language);
+ } else {
+ i18next.changeLanguage(sessionData?.default_locale);
+ }
+
+ // if session is valid setting amount, currency type at global store for future use
+ dispatch({ type: Actions.SET_AMOUNT, payload: sessionData?.amount });
+ dispatch({ type: Actions.SET_CURRENCY, payload: sessionData?.currency });
+
+ // if user provided explicitly payments methods via props, will give priority to that over session payment methods
+ const paymentMethods = parsePaymentMethods(
+ props?.paymentMethods,
+ sessionData?.payment_methods
+ );
+
+ // setting the payment methods in global state
+ dispatch({
+ type: Actions.SET_PAYMENT_METHODS,
+ payload: paymentMethods,
+ });
+ // setting the current selected payment method as the first payment method on the list
+ dispatch({
+ type: Actions.SET_PAYMENT_OPTION,
+ payload: paymentMethods ? paymentMethods[0]?.type : '',
+ });
+ }
+ stopLoading();
+ };
+
+ // Session pay callback. this method handles all the payment logic and APIs
+ const sessionPay = ({ sessionId }: CreatePaymentFuncType) => {
+ return async ({ paymentType, paymentDetails }: sessionPayProps) => {
+ // Start of the payment handling method
+ startLoading();
+
+ // initiate payment for the session ID with payment details
+ const response = await payForSession({
+ paymentType,
+ sessionId,
+ publishableKey: props.publishableKey,
+ paymentDetails,
+ });
+
+ stopLoading();
+
+ if (response?.status === PaymentStatuses.PENDING) {
+ openURL(response.redirect_url);
+ } else if (response?.status === PaymentStatuses.SUCCESS) {
+ if (response?.payment?.status === TokenResponseStatuses.CAPTURED) {
+ onPaymentSuccess();
+ } else if (response?.payment?.payment_details?.instructions_url) {
+ openURL(response?.payment?.payment_details?.instructions_url);
+ onPaymentAwaiting();
+ }
+ } else {
+ onPaymentFailed();
+ }
+ };
+ };
+
+ const openURL = async (url: string) => {
+ try {
+ await Linking.openURL(url);
+ } catch (err) {
+ Alert.alert('Redirection not working. Please contact support!');
+ }
+ };
+
+ return {
+ sessionPay,
+ validateSession
+ }
+}
+
+export default usePaymentHandler
\ No newline at end of file