diff --git a/app/(tabs)/payments.tsx b/app/(tabs)/payments.tsx index ae937b1..9823c2f 100644 --- a/app/(tabs)/payments.tsx +++ b/app/(tabs)/payments.tsx @@ -72,7 +72,6 @@ interface PaymentHistoryResponse { } const formatPaymentDate = (dateString: string) => { - console.log(dateString.split(",")[0], "datestring"); try { return dateString.split(",")[0]; } catch { @@ -82,7 +81,6 @@ const formatPaymentDate = (dateString: string) => { // Format time for payment history const formatPaymentTime = (dateString: string) => { - console.log(dateString, "formattime"); try { // Expected: "12 Aug 2025, 12:38:23 pm" const [datePart, timePart] = dateString.split(","); @@ -452,7 +450,6 @@ export default function PaymentsTabScreen() { )} - ); } diff --git a/app/payments/payEmi.tsx b/app/payments/payEmi.tsx index 9cae28c..312cc6e 100644 --- a/app/payments/payEmi.tsx +++ b/app/payments/payEmi.tsx @@ -7,12 +7,9 @@ import { SafeAreaView, Alert, Share, - Clipboard, Linking, - ActivityIndicator, BackHandler, } from "react-native"; -import { Ionicons } from "@expo/vector-icons"; import * as FileSystem from "expo-file-system"; import * as MediaLibrary from "expo-media-library"; import * as Sharing from "expo-sharing"; @@ -43,23 +40,11 @@ const UpiPaymentScreen = () => { const { showSnackbar } = useSnackbar(); const insets = useSafeAreaInsets(); - if (!paymentOrder) { - return ( - - - - Loading payment details... - - - ); - } useEffect(() => { - // Set up payment confirmation listener const handlePaymentConfirmation = (data: any) => { console.log("Payment confirmation received:", data); - // Show success message Alert.alert( "Payment Successful!", "Your payment has been confirmed successfully.", @@ -75,11 +60,9 @@ const UpiPaymentScreen = () => { ); }; - // Start listening for payment confirmation onPaymentConfirmation(handlePaymentConfirmation); setIsListening(true); - // Handle Android back button const backAction = () => { Alert.alert( "Cancel Payment?", @@ -120,11 +103,6 @@ const UpiPaymentScreen = () => { return `₹${amount.toLocaleString("en-IN")}`; }; - // Extract numeric amount from the amount - const getNumericAmount = (): string => { - return paymentOrder.amount.toString(); - }; - // Check if payment is expired const isPaymentExpired = (): boolean => { const expiryDate = new Date(paymentOrder.expiry_date); @@ -261,23 +239,9 @@ const UpiPaymentScreen = () => { } }; - const getStatusColor = (status: string): string => { - switch (status) { - case "completed": - case "success": - return "#00876F"; - case "failed": - return "#E74C3C"; - case "processing": - return "#F39C12"; - default: - return "#6C757D"; - } - }; - return ( -
+
diff --git a/app/payments/selectAmount.tsx b/app/payments/selectAmount.tsx index cb86af6..442aaba 100644 --- a/app/payments/selectAmount.tsx +++ b/app/payments/selectAmount.tsx @@ -19,10 +19,10 @@ import { BASE_URL, payments } from "@/constants/config"; import api from "@/services/axiosClient"; import { setPaymentOrder } from "@/store/paymentSlice"; import { Overlay } from "@/components/common/Overlay"; -import { useRouter } from "expo-router"; +import { useFocusEffect, useRouter } from "expo-router"; import { useSocket } from "@/contexts/SocketContext"; +import { useSnackbar } from "@/contexts/Snackbar"; -// Validation schema const validationSchema = Yup.object().shape({ paymentType: Yup.string().required("Please select a payment option"), customAmount: Yup.string().when("paymentType", { @@ -47,11 +47,12 @@ const validationSchema = Yup.object().shape({ }); const SelectAmountScreen = () => { - // Fetch due amount from Redux const dueAmount = useSelector( (state: RootState) => state.payments?.due_amount || 0 ); + const { showSnackbar } = useSnackbar(); + const router = useRouter(); const [isFetching, setIsFetching] = useState(false); @@ -64,41 +65,72 @@ const SelectAmountScreen = () => { customAmount: "", }; + const existingPaymentOrder = useSelector( + (state: RootState) => state.payments?.paymentOrder + ); + const dispatch = useDispatch(); + useFocusEffect( + React.useCallback(() => { + console.log( + "SelectAmountScreen focused - clearing paymentOrder and remounting" + ); + // Clear the payment order + dispatch(setPaymentOrder(null)); + setIsFetching(false); + }, [dispatch]) + ); + const handleSubmit = async (values: any) => { setIsFetching(true); const paymentAmount = values.paymentType === "due" ? dueAmount : parseFloat(values.customAmount); - console.log(values, "values"); + try { - const res = await api.post(`/api/v1/create-order`, { - amount: paymentAmount, - }); + let orderData = existingPaymentOrder; - console.log(res.data, "response from select amount"); - if (res.data && res.data.success) { - dispatch(setPaymentOrder(res.data.data)); - try { - await registerTransaction(res.data.data.transaction_id); - console.log("Transaction registered successfully"); - - // Navigate to payment screen - router.push("/payments/payEmi"); - } catch (socketError) { - throw socketError; - } + if ( + existingPaymentOrder && + existingPaymentOrder.amount === paymentAmount + ) { + console.log( + "Order for current amount already exists, using existing order" + ); + orderData = existingPaymentOrder; } else { - throw new Error("Failed to create order"); + console.log("Creating new order for amount:", paymentAmount); + const res = await api.post(`/api/v1/create-order`, { + amount: paymentAmount, + }); + + console.log(res.data, "response from select amount"); + + if (res.data && res.data.success) { + orderData = res.data.data; + dispatch(setPaymentOrder(orderData)); + } else { + throw new Error("Failed to create order"); + } + } + + try { + await registerTransaction(orderData?.transaction_id); + console.log("Transaction registered successfully"); + + router.push("/payments/payEmi"); + } catch (socketError) { + console.error("Socket connection failed:", socketError); + throw socketError; } } catch (err) { console.error(err, "Error in creating order."); + showSnackbar("Something went wrong.", "error"); } finally { setIsFetching(false); } - console.log("Payment Amount:", paymentAmount); }; @@ -263,7 +295,6 @@ const SelectAmountScreen = () => { - {/* Pay Button */} Promise; + registerTransaction: ( + transactionId: string | null | undefined + ) => Promise; onPaymentConfirmation: (callback: (data: any) => void) => void; offPaymentConfirmation: () => void; disconnect: () => void; @@ -26,25 +28,6 @@ interface SocketProviderProps { export const SocketProvider: React.FC = ({ children }) => { const [isConnected, setIsConnected] = useState(false); - // useEffect(() => { - // const initSocket = async () => { - // try { - // await SocketService.connect(); - // setIsConnected(true); - // } catch (error) { - // console.error("Failed to connect socket:", error); - // setIsConnected(false); - // } - // }; - - // initSocket(); - - // return () => { - // SocketService.disconnect(); - // setIsConnected(false); - // }; - // }, []); - const connectSocket = async () => { try { await SocketService.connect(); @@ -56,7 +39,9 @@ export const SocketProvider: React.FC = ({ children }) => { } }; - const registerTransaction = async (transactionId: string) => { + const registerTransaction = async ( + transactionId: string | null | undefined + ) => { try { if (!transactionId) { throw new Error("Transaction Id missing in register transaction"); diff --git a/services/paymentSocket.ts b/services/paymentSocket.ts index 17f78b5..8c17ab5 100644 --- a/services/paymentSocket.ts +++ b/services/paymentSocket.ts @@ -1,5 +1,9 @@ // services/socketService.ts -import { PAYMENT_SOCKET_BASE_URL, STORAGE_KEYS } from "@/constants/config"; +import { + PAYMENT_SOCKET_BASE_URL, + payments, + STORAGE_KEYS, +} from "@/constants/config"; import AsyncStorage from "@react-native-async-storage/async-storage"; import io, { Socket } from "socket.io-client"; @@ -66,19 +70,17 @@ class SocketService { return; } - const timeoutMs = 5000; + const timeoutSecs = payments.SOCKET_CONNECTION_TIMEOUT_IN_SECS * 1000; const timeoutId = setTimeout(() => { socket.off("registration-ack", onRegistrationAck); reject(new Error("Timeout: No registration-ack received")); - }, timeoutMs); + }, timeoutSecs); const onRegistrationAck = (data: any) => { - console.log("inside onRegisterAck"); if (data.transactionId === transactionId) { clearTimeout(timeoutId); - // socket.off("registration-ack", onRegistrationAck); - + socket.off("registration-ack", onRegistrationAck); if (data.success) { resolve(); } else { @@ -87,33 +89,30 @@ class SocketService { } }; - socket.on("registration-ack", onRegistrationAck); - - socket.on("register-transaction", this.onPaymentConfirm); - socket.onAny((eventName, ...args) => { - console.log(eventName, "eventname", JSON.stringify(args), "✅✅✅✅✅"); + //register the transaction with the specific 'transactionId' + socket.emit(payments.REGISTER_TRANSACTION_EMIT_EVENT_NAME, { + transactionId, }); - - socket.emit("register-transaction", { transactionId }); + socket.on( + payments.REGISTER_TRANSACTION_LISTEN_EVENT_NAME, + onRegistrationAck + ); }); } - private onPaymentConfirm(eventname: string, ...args: any[]): void { - console.log(eventname, "eventName", JSON.stringify(args)); - } - + //payment confirmation is received on 'register-transaction' eventName public onPaymentConfirmation(callback: (data: any) => void): void { if (!this.socket) { console.error("Socket not connected"); return; } - this.socket.on("register-transaction", callback); + this.socket.on(payments.PAYMENT_CONFIRMATION_EVENT_NAME, callback); } public offPaymentConfirmation(): void { if (this.socket) { - this.socket.off("payment-confirmation"); + this.socket.off(payments.PAYMENT_CONFIRMATION_EVENT_NAME); } }