import React, { useEffect, useState } from "react"; import { View, Text, TouchableOpacity, StyleSheet, SafeAreaView, Alert, Share, Linking, BackHandler, } from "react-native"; import * as FileSystem from "expo-file-system"; import * as MediaLibrary from "expo-media-library"; import * as Sharing from "expo-sharing"; import { Image } from "expo-image"; import { useSelector, useDispatch } from "react-redux"; import { RootState } from "@/store"; import { updatePaymentStatus } from "@/store/paymentSlice"; import Header from "@/components/common/Header"; import ShareIcon from "@/assets/icons/share.svg"; import { useSafeAreaInsets } from "react-native-safe-area-context"; import { useSnackbar } from "@/contexts/Snackbar"; import DownloadIcon from "@/assets/icons/download.svg"; import { payments } from "@/constants/config"; import { useRouter } from "expo-router"; import { useSocket } from "@/contexts/SocketContext"; const UpiPaymentScreen = () => { const dispatch = useDispatch(); const paymentOrder = useSelector( (state: RootState) => state.payments.paymentOrder ); const router = useRouter(); const { onPaymentConfirmation, offPaymentConfirmation } = useSocket(); const [isListening, setIsListening] = useState(false); const { showSnackbar } = useSnackbar(); const insets = useSafeAreaInsets(); useEffect(() => { const handlePaymentConfirmation = (data: any) => { console.log("Payment confirmation received:", data); Alert.alert( "Payment Successful!", "Your payment has been confirmed successfully.", [ { text: "Continue", onPress: () => { router.replace("/payments/Confirmation"); }, }, ], { cancelable: false } ); }; onPaymentConfirmation(handlePaymentConfirmation); setIsListening(true); const backAction = () => { Alert.alert( "Cancel Payment?", "Are you sure you want to cancel this payment?", [ { text: "No", onPress: () => null, style: "cancel", }, { text: "Yes", onPress: () => { offPaymentConfirmation(); router.back(); }, }, ] ); return true; }; const backHandler = BackHandler.addEventListener( "hardwareBackPress", backAction ); // Cleanup on unmount return () => { offPaymentConfirmation(); setIsListening(false); backHandler.remove(); }; }, [onPaymentConfirmation, offPaymentConfirmation, router]); // Format amount with currency symbol const formatAmount = (amount: number): string => { return `₹${amount.toLocaleString("en-IN")}`; }; // Check if payment is expired const isPaymentExpired = (): boolean => { const expiryDate = new Date(paymentOrder.expiry_date); const currentDate = new Date(); return currentDate > expiryDate; }; // Get formatted expiry time const getExpiryTime = (): string => { const expiryDate = new Date(paymentOrder.expiry_date); return expiryDate.toLocaleString("en-IN"); }; const getUpiUrl = (): string => { const upiString = paymentOrder.ppayment_link; const upiMatch = upiString.match(/upi_string=([^&]+)/); if (upiMatch) { return decodeURIComponent(upiMatch[1]); } return `upi://pay?pa=${paymentOrder.upi_handle}&am=${paymentOrder.amount}&cu=INR&tr=${paymentOrder.order_id}`; }; const payUsingUpiApp = async (): Promise => { try { if (isPaymentExpired()) { showSnackbar(payments.LINK_EXPIRED, "error"); return; } const upiUrl = getUpiUrl(); console.log("Opening UPI URL:", upiUrl); dispatch(updatePaymentStatus("processing")); const canOpenUrl = await Linking.canOpenURL(upiUrl); if (canOpenUrl) { await Linking.openURL(upiUrl); } else { Alert.alert( "UPI App Required", "Please install a UPI-enabled app like PhonePe, Paytm, Google Pay, or BHIM to make payments.", [ { text: "Share Payment Details", onPress: () => sharePaymentDetails(), }, { text: "Cancel", style: "cancel" }, ] ); } } catch (error) { console.error("Error opening UPI app:", error); dispatch(updatePaymentStatus("failed")); Alert.alert( "Error", "Unable to open UPI app. Would you like to share payment details instead?", [ { text: "Share Details", onPress: () => sharePaymentDetails(), }, { text: "Cancel", style: "cancel" }, ] ); } }; const sharePaymentDetails = async (): Promise => { try { const shareMessage = `Payment Request\n\n` + `Amount: ${formatAmount(paymentOrder.amount)}\n` + `UPI ID: ${paymentOrder.upi_handle}\n` + `Order ID: ${paymentOrder.order_id}\n` + `Transaction ID: ${paymentOrder.transaction_id}\n` + `Expires: ${getExpiryTime()}\n\n` + `UPI Link: ${getUpiUrl()}`; await Share.share({ message: shareMessage, title: "UPI Payment Details", }); } catch (error) { Alert.alert("Error", "Failed to share payment details"); } }; const shareQR = async (): Promise => { try { if (await Sharing.isAvailableAsync()) { await Share.share({ message: `Pay ${formatAmount( paymentOrder.amount )} using this QR code`, url: paymentOrder.qr_code_url, }); } else { Alert.alert("Error", "Sharing is not available on this device"); } } catch (error) { Alert.alert("Error", "Failed to share QR code"); } }; const downloadQR = async (): Promise => { try { const { status } = await MediaLibrary.requestPermissionsAsync(); if (status !== "granted") { Alert.alert( "Permission Required", "Please grant permission to save images" ); return; } const fileUri = FileSystem.documentDirectory + `qr-${paymentOrder.order_id}.png`; const downloadResult = await FileSystem.downloadAsync( paymentOrder.qr_code_url, fileUri ); if (downloadResult.status === 200) { const asset = await MediaLibrary.createAssetAsync(downloadResult.uri); await MediaLibrary.createAlbumAsync("Payment QR Codes", asset, false); Alert.alert("Success", "QR code saved to gallery"); } else { Alert.alert("Error", "Failed to download QR code"); } } catch (error) { Alert.alert("Error", "Failed to download QR code"); } }; return (
Amount to be paid {formatAmount(paymentOrder.amount)} Share QR Download QR Pay using UPI app ); }; const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: "#F3F5F8", }, loadingContainer: { flex: 1, justifyContent: "center", alignItems: "center", }, loadingText: { marginTop: 16, fontSize: 16, color: "#253342", }, header: { flexDirection: "row", alignItems: "center", paddingHorizontal: 16, paddingVertical: 12, backgroundColor: "#FFFFFF", }, backButton: { padding: 8, marginRight: 8, }, headerTitle: { fontSize: 18, fontWeight: "600", color: "#253342", }, content: { flex: 1, justifyContent: "space-between", paddingHorizontal: 16, paddingBottom: 16, }, qrFrame: { backgroundColor: "#FCFCFC", borderRadius: 8, padding: 16, alignItems: "center", marginTop: 16, }, amountSection: { alignItems: "center", marginBottom: 16, }, amountLabel: { fontSize: 14, color: "#253342", textAlign: "center", marginBottom: 4, }, amount: { fontSize: 20, fontWeight: "600", color: "#253342", textAlign: "center", marginBottom: 8, }, statusBadge: { paddingHorizontal: 12, paddingVertical: 4, borderRadius: 12, }, statusText: { fontSize: 12, fontWeight: "600", color: "#FFFFFF", }, qrCodeContainer: { width: 200, height: 200, justifyContent: "center", alignItems: "center", marginBottom: 16, borderWidth: 2, borderColor: "#E5E9F0", padding: 12, borderRadius: 8, }, qrCode: { width: "100%", height: "100%", }, upiIdSection: { flexDirection: "row", alignItems: "center", justifyContent: "center", marginBottom: 12, padding: 8, backgroundColor: "#F3F5F8", borderRadius: 4, }, upiIdText: { fontSize: 14, color: "#253342", marginRight: 8, fontWeight: "500", }, expirySection: { alignItems: "center", marginBottom: 16, }, expiryLabel: { fontSize: 12, color: "#6C757D", marginBottom: 2, }, expiryTime: { fontSize: 14, color: "#253342", fontWeight: "500", }, buttonsContainer: { flexDirection: "row", gap: 8, width: "100%", }, secondaryButton: { flex: 1, flexDirection: "row", alignItems: "center", justifyContent: "center", paddingVertical: 10, paddingHorizontal: 16, backgroundColor: "#F3F5F8", borderColor: "#D8DDE7", borderWidth: 1, borderRadius: 4, gap: 4, }, secondaryButtonText: { fontSize: 14, fontWeight: "500", color: "#253342", }, primaryButton: { backgroundColor: "#00876F", paddingVertical: 12, paddingHorizontal: 16, borderRadius: 4, alignItems: "center", }, primaryButtonText: { fontSize: 14, fontWeight: "500", color: "#FCFCFC", }, disabledButton: { backgroundColor: "#D8DDE7", }, disabledButtonText: { color: "#6C757D", }, }); export default UpiPaymentScreen;