From e66a4d540472b7a291510c7514c4753fcc093580 Mon Sep 17 00:00:00 2001 From: G Date: Sat, 6 Sep 2025 14:45:53 +0000 Subject: [PATCH] feat: Payment processing using Wave as the payment gateway with navigation on QrCode screen upon valid initialization. User is given the possibility to verify the state manually with a button. --- src/features/pay/api.ts | 10 ++++++++++ src/features/pay/types.ts | 24 ++++++++++++++++++++++++ src/navigations/types.ts | 5 ++--- src/screens/PaymentAmountInputScreen.tsx | 16 +++++++++++++++- src/screens/WaveQrCodePaymentScreen.tsx | 162 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------------------------------- 5 files changed, 157 insertions(+), 60 deletions(-) diff --git a/src/features/pay/api.ts b/src/features/pay/api.ts index 34b39f0..fee68df 100644 --- a/src/features/pay/api.ts +++ b/src/features/pay/api.ts @@ -5,6 +5,8 @@ import type { OmInitializationPayload as OmTransactionInitializationPayload, OmInitializationResponse as OmTransactionInitializationResponse, PaymentType, + WaveInitializationPayload, + WaveTransactionInitilizationResponse, } from "./types"; export const getPaymentTypes = () => { @@ -44,3 +46,11 @@ export const omVerifyTransactionStateWithTimeout = async ( await sleep(retryAfter); } }; + +export const waveInitializeTransaction = (payload: WaveInitializationPayload) => { + return axiosInstance.post("/transactions/", payload); +}; + +export const waveGetTransactionStatus = (id: string) => { + return axiosInstance.get(`/wave-session/${id}/`); +}; diff --git a/src/features/pay/types.ts b/src/features/pay/types.ts index 2f6c32c..3f0072a 100644 --- a/src/features/pay/types.ts +++ b/src/features/pay/types.ts @@ -65,3 +65,27 @@ export interface OmTransaction { txnid?: string; }; } + +// WAVE +export type WaveInitializationPayload = { + type_paiement: number; + marchand: string; + service: string; + montant: number; +}; +export interface WaveTransactionInitilizationResponse { + id: string; + amount: string; + checkout_status: string; + client_reference: unknown; + currenfy: string; + error_url: string; + last_payment_errror: unknown; + business_name: string; + payment_status: string; + succes_url: string; + wave_launch_url: string; + when_completed: unknown; + when_created: string; + when_expires: string; +} diff --git a/src/navigations/types.ts b/src/navigations/types.ts index 8d275b1..922d0ee 100644 --- a/src/navigations/types.ts +++ b/src/navigations/types.ts @@ -1,6 +1,5 @@ import type { NativeStackScreenProps } from "@react-navigation/native-stack"; -import type { PaymentType } from "@/features/pay/types"; -import type { IwaveStarterRespone } from "@/utils/requests/wavePayment"; +import type { PaymentType, WaveTransactionInitilizationResponse } from "@/features/pay/types"; export type IpaymentStackNavigator = { homePageWithPaymentOptions: undefined; @@ -26,7 +25,7 @@ export type ImainStackNavigator = { appBottomTabsNavigator: undefined; paymentResultScreen: undefined; waveQrCodePaymentScreen: { - data: IwaveStarterRespone; + data: WaveTransactionInitilizationResponse; }; }; diff --git a/src/screens/PaymentAmountInputScreen.tsx b/src/screens/PaymentAmountInputScreen.tsx index d551f8c..f6ec4da 100644 --- a/src/screens/PaymentAmountInputScreen.tsx +++ b/src/screens/PaymentAmountInputScreen.tsx @@ -10,7 +10,11 @@ import type { AxiosError } from "axios"; import * as WebBrowser from "expo-web-browser"; import { useEffect, useRef, useState } from "react"; import { AppState, Text, View } from "react-native"; -import { omInitializeTransaction, omVerifyTransactionStateWithTimeout } from "@/features/pay/api"; +import { + omInitializeTransaction, + omVerifyTransactionStateWithTimeout, + waveInitializeTransaction, +} from "@/features/pay/api"; import PaymentType from "@/features/pay/components/PaymentType"; import type { PaymentStackScreenComponentProps } from "@/navigations/types"; @@ -39,6 +43,16 @@ const PaymentAmountInputScreen: PaymentStackScreenComponentProps<"paymentAmountI numero: "0707070707", }); WebBrowser.openBrowserAsync(res.data.payment_url); + } else if (code === "WAVE") { + const res = await waveInitializeTransaction({ + type_paiement: 2, + marchand: "1", + service: "1", + montant: amount, + }); + navigation?.getParent()?.navigate("waveQrCodePaymentScreen", { + data: res, + }); } else { navigation.navigate("numberAndOtpForPaymentScreen", { paymentType: route.params.paymentType, diff --git a/src/screens/WaveQrCodePaymentScreen.tsx b/src/screens/WaveQrCodePaymentScreen.tsx index b7c6328..2d59223 100644 --- a/src/screens/WaveQrCodePaymentScreen.tsx +++ b/src/screens/WaveQrCodePaymentScreen.tsx @@ -1,12 +1,16 @@ -import Button from "@components/Button"; -import BackgroundWithBeasyIconAndWhiteContentArea from "@components/backgrounds/BackgroundWithBeasyIconAndWhiteContentArea"; -import Box from "@components/bases/Box"; -import Text from "@components/bases/Text"; -import useWave from "@hooks/useWave"; +import { asp as g } from "@asp/asp"; +import { BarnoinPayBackground } from "@components/BarnoinPayBackground"; +import BeasyLogoIcon from "@components/BeasyLogoIcon"; +import * as Button from "@components/ButtonNew"; +import * as Modal from "@components/Modal"; +import AntDesign from "@expo/vector-icons/AntDesign"; import { LOG } from "@logger"; -import { Dimensions } from "react-native"; -// biome-ignore lint/style/useNamingConvention: -import QRCode from "react-native-qrcode-svg"; +import { useMutation } from "@tanstack/react-query"; +import type { AxiosError } from "axios"; +import { useState } from "react"; +import { Dimensions, ScrollView, Text, View } from "react-native"; +import QrCode from "react-native-qrcode-svg"; +import { waveGetTransactionStatus } from "@/features/pay/api"; import type { MainStackScreenComponentProps } from "@/navigations/types"; const log = LOG.extend("WaveQrCodePaymentScreen"); @@ -16,62 +20,108 @@ const WaveQrCodePaymentScreen: MainStackScreenComponentProps<"waveQrCodePaymentS navigation, }) => { log.verbose("WaveQrCodePaymentScreen"); + const [error, setError] = useState(""); const data = route.params.data; const windowWidth = Dimensions.get("window").width; - const { handlePaymentVerification } = useWave(); + const qrSize = windowWidth * 0.7; + const [isSuccess, setIsSuccess] = useState(false); + + const query = useMutation({ + mutationKey: ["waveTransactionStatus", data.id], + mutationFn: () => waveGetTransactionStatus(data.id), + onError: (err: AxiosError) => { + setError(JSON.stringify(err.response?.data) || err.message); + }, + onSuccess: (_data) => { + setIsSuccess(true); + }, + }); return ( - - + + + navigation.goBack()} + /> + + - - Votre QR Code - + Votre QR Code - - - + + Veuillez scanner le QR Code pour terminer le paiement - -