import React, { useEffect } from "react"; import { View, Text, TouchableOpacity, StyleSheet, SafeAreaView, Alert, Share, Clipboard, Platform, Linking, ActivityIndicator, } 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"; import { Image } from "expo-image"; import { useSelector, useDispatch } from "react-redux"; import { RootState } from "@/store"; // Adjust path as needed import { updatePaymentStatus } from "@/store/paymentSlice"; interface UpiPaymentScreenProps { onBack?: () => void; onPaymentSuccess?: () => void; onPaymentFailure?: () => void; } const UpiPaymentScreen: React.FC = ({ onBack, onPaymentSuccess, onPaymentFailure, }) => { const dispatch = useDispatch(); const paymentOrder = useSelector( (state: RootState) => state.payments.paymentOrder ); useEffect(() => { // Check if payment order exists if (!paymentOrder) { Alert.alert( "Error", "No payment order found. Please create a payment order first.", [{ text: "OK", onPress: onBack }] ); } }, [paymentOrder]); // Show loading if no payment data if (!paymentOrder) { return ( Loading payment details... ); } // Format amount with currency symbol const formatAmount = (amount: number): string => { 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); 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"); }; // Generate UPI payment URL from the API response const getUpiUrl = (): string => { // Use the UPI string from the API response const upiString = paymentOrder.ppayment_link; // Extract the UPI URL from the deep link const upiMatch = upiString.match(/upi_string=([^&]+)/); if (upiMatch) { return decodeURIComponent(upiMatch[1]); } // Fallback: construct UPI URL manually return `upi://pay?pa=${paymentOrder.upi_handle}&am=${paymentOrder.amount}&cu=INR&tr=${paymentOrder.order_id}`; }; const payUsingUpiApp = async (): Promise => { try { // Check if payment is expired if (isPaymentExpired()) { Alert.alert( "Payment Expired", "This payment order has expired. Please create a new payment order.", [{ text: "OK", onPress: onBack }] ); return; } // Check if payment is already completed if ( paymentOrder.status === "completed" || paymentOrder.status === "success" ) { Alert.alert( "Payment Already Completed", "This payment has already been completed.", [{ text: "OK", onPress: onPaymentSuccess }] ); return; } const upiUrl = getUpiUrl(); console.log("Opening UPI URL:", upiUrl); // Update payment status to processing dispatch(updatePaymentStatus("processing")); // Check if device can handle UPI URLs const canOpenUrl = await Linking.canOpenURL(upiUrl); if (canOpenUrl) { await Linking.openURL(upiUrl); // Show payment status dialog Alert.alert( "Payment Initiated", "Payment has been initiated. Please complete the payment in your UPI app.", [ { text: "Payment Completed", onPress: () => { dispatch(updatePaymentStatus("completed")); onPaymentSuccess?.(); }, }, { text: "Payment Failed", style: "cancel", onPress: () => { dispatch(updatePaymentStatus("failed")); onPaymentFailure?.(); }, }, ] ); } else { // Fallback: Show available UPI apps or general share 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 copyUpiId = async (): Promise => { try { await Clipboard.setString(paymentOrder.upi_handle); Alert.alert("Copied!", "UPI ID copied to clipboard"); } catch (error) { Alert.alert("Error", "Failed to copy UPI ID"); } }; 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"); } }; 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 ( Pay EMI Amount to be paid {formatAmount(paymentOrder.amount)} {/* Payment Status */} {paymentOrder.status.toUpperCase()} {/* UPI ID Section */} {paymentOrder.upi_handle} {/* Expiry Info */} Expires: {getExpiryTime()} Share QR Download QR {paymentOrder.status === "completed" ? "Payment Completed" : isPaymentExpired() ? "Payment Expired" : "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: 248, height: 248, justifyContent: "center", alignItems: "center", marginBottom: 16, }, 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;