import ErrorModal from "@components/modals/ErrorModal"; import LoadingModal from "@components/modals/LoadingModal"; import { LOG } from "@logger"; import type { NativeStackNavigationProp } from "@react-navigation/native-stack"; import { useMutation, useQueryClient } from "@tanstack/react-query"; import { AxiosError } from "axios"; import * as WebBrowser from "expo-web-browser"; import { useRef, useState } from "react"; import { AppState, Platform } from "react-native"; import { useModalsManagerContext } from "@/contexts/ModalsManagerContext"; import type { IpaymentStackNavigator } from "@/navigations/types"; import { getTransactionStatus, getTransactionsData, type IorangePaymentStarter, } from "@/utils/requests/orangePayment"; const log = LOG.extend("useOrangeMoney"); const paymentObjectDefault: IorangePaymentStarter = { // biome-ignore lint/style/useNamingConvention: type_paiement: 1, marchand: "1", service: "2", montant: 0, numero: "0707070707", commentaire: "Un commentaire", }; const useOrangeMoney = ( navigation?: NativeStackNavigationProp< IpaymentStackNavigator, "paymentAmountInputScreen", "IpaymentStackNavigator" >, ) => { const queryClient = useQueryClient(); const [isBrowserOpen, setIsBrowserOpen] = useState(false); const { showModal, closeModal } = useModalsManagerContext(); const appState = useRef(AppState.currentState); const [_appStateVisible, _setAppStateVisiblee] = useState(appState.current); const handlePaymentUsingBrowser = async (url: string) => { setIsBrowserOpen(true); const result = await WebBrowser.openBrowserAsync(url); // setResult(result); log.debug("handlePaymentUsingBrowser | Result ::", result); setIsBrowserOpen(false); }; const orangeTransactionInitializerMutation = useMutation({ mutationFn: (amount: number) => getTransactionsData({ ...paymentObjectDefault, montant: amount, }), onSuccess: (_data) => { // return data.payment_url log.debug("orangeTransactionInitializerMutation request success, opening browser..."); queryClient.invalidateQueries({ queryKey: ["transactionsHistory"] }); // await handlePaymentUsingBrowser(data.payment_url); // await transactionsStatusMutation.mutate(data.order_id); // setResult(result); }, onError: (err) => { log.error("orangeTransactionInitializerMutation |", err); }, }); const _maxRetry = 3; const _retryDelay = 5000; const transactionsStatusMutation = useMutation({ mutationFn: (orderId: string) => getTransactionStatus(orderId), onSuccess: (data) => { log.debug("transactionsStatusMutation request success"); queryClient.invalidateQueries({ queryKey: ["transactionsHistory"] }); return data.status; }, onError: (err) => { log.error("transactionsStatusMutation |", err); queryClient.invalidateQueries({ queryKey: ["transactionsHistory"] }); }, // retry: (failureCount, error) => { // log.warn("transactionsStatusMutation | retrying", failureCount, error); // return failureCount < maxRetry; // }, // retryDelay(_failureCount, _error) { // return retryDelay; // }, }); // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: const checkStatus = async (orderId: string, retry = 0): Promise => { // Check the transactions 'retry' time. let numberOfTries = 0; while (numberOfTries <= retry) { log.verbose("useOrangePayment | checkStatus | Try No.", numberOfTries + 1); try { await transactionsStatusMutation.mutateAsync(orderId); return; } catch (error) { // errors are throwned from getTransactions status when the staus is either initiated or failed. if (error instanceof AxiosError && error.response?.status === 404) { log.error("useOrangeMoney | checkStatus | Transaction not found"); return error.response.data.error || `Transaction ${orderId} not found !!`; } if (error instanceof AxiosError && error.name === "ORANGE_PAYMENT_FAILED") { return "La transaction à échoué."; } if (error instanceof AxiosError && error.name === "ORANGE_UNKNOWN_PAYMENT_ERROR") { return "Une erreur est survenue."; } } numberOfTries += 1; } return "La transaction est toujours en cours."; }; const openBrowserThenCheckStatus = async (paymentUrl: string, orderId: string) => { try { await handlePaymentUsingBrowser(paymentUrl); if (Platform.OS === "android") { log.debug( "useOrangeMoney | openBrowserThenCheckStatus | Android device. Setup listener for browser close event.", ); const sub = AppState.addEventListener("change", async (nextAppState) => { log.debug( "useOrangeMoney | openBrowserThenCheckStatus | Android device. Browser state :", nextAppState, ); if (nextAppState === "active") { log.debug( "useOrangeMoney | openBrowserThenCheckStatus | Android device. Browser is closed. Removing listener. Checking for transaction State.", ); sub.remove(); log.info("openBrowserThenCheckStatus | Verifying transaction status..."); showModal( , ); // await transactionsStatusMutation.mutateAsync(orderId); const message = await checkStatus(orderId); if (message) { showModal(); } else { navigation?.getParent()?.navigate("paymentResultScreen"); } } }); } else { log.info("openBrowserThenCheckStatus | Verifying transaction status..."); showModal(); // await transactionsStatusMutation.mutateAsync(orderId); const message = await checkStatus(orderId); if (message) { showModal(); } else { navigation?.getParent()?.navigate("paymentResultScreen"); } } // closeModal(); } catch (error: unknown) { log.verbose("Error catching"); if (error instanceof AxiosError) { log.error("openBrowserThenCheckStatus Catch Block|", error); showModal( , ); } else { showModal(); } // log.error("openBrowserThenCheckStatus Catch Block|", error); // if (error instanceof Error) { // log.debug("1"); // if (error.name === "ORANGE_PAYMENT_IN_PROGRESS") { // log.debug("2"); // log.warn("openBrowserThenCheckStatus | ORANGE_PAYMENT_IN_PROGRESS"); // await showModal( // openBrowserThenCheckStatus(paymentUrl, orderId)} // />, // ); // log.debug("3"); // } else if (error.name === "ORANGE_PAYMENT_FAILED") { // showModal(); // log.error("openBrowserThenCheckStatus | ORANGE_PAYMENT_FAILED"); // } // log.debug("4 --", error.name); // } else { // log.error("openBrowserThenCheckStatus Else Block|", error); // closeModal(); // throw error; // } } }; const orangePaymentTransactionHandler = async (amount: number) => { try { showModal(); const { payment_url, order_id } = await orangeTransactionInitializerMutation.mutateAsync(amount); log.info("orangePaymentTransactionHandler |", payment_url, order_id); log.info("Opening browser for payment..."); await openBrowserThenCheckStatus(payment_url, order_id); // biome-ignore lint/suspicious/noExplicitAny: } catch (error: any) { log.error("makePayment |", error); showModal( , ); throw error; } finally { //closeModal(); // just to be ultra sure that the modal is closed } }; return { orangeTransactionInitializerMutation: orangeTransactionInitializerMutation, handlePaymentUsingBrowser, isBrowserOpen, isWaitingForOmPaymentUrl: orangeTransactionInitializerMutation.isPending, isCheckingForTransactionStatus: transactionsStatusMutation.isPending, transactionsStatusMutation, orangePaymentTransactionHandler, }; }; export default useOrangeMoney;