BaaS_Driver_Android_App/app/payments/TransactionDetails.tsx

373 lines
8.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import React, { useState, useEffect, useLayoutEffect } from "react";
import {
View,
Text,
StyleSheet,
TouchableOpacity,
ActivityIndicator,
} from "react-native";
import { useNavigation, useRoute } from "@react-navigation/native";
import { useRouter } from "expo-router";
import api from "@/services/axiosClient";
import { BASE_URL } from "@/constants/config";
import { useSnackbar } from "@/contexts/Snackbar";
import { SafeAreaView } from "react-native-safe-area-context";
// Import your success/failure icons
import SuccessIcon from "@/assets/icons/check_circle.svg";
import FailureIcon from "@/assets/icons/cancel.svg";
import PendingIcon from "@/assets/icons/pending.svg";
interface TransactionDetailData {
id: number;
amount: string;
status: string;
transaction_date: string | null;
upi_handle: string;
payment_mode: string[];
paid_by_upi_handle: string | null;
order_id: string;
payment_reference_id: string | null;
transaction_order_id: string;
}
interface TransactionResponse {
success: boolean;
data: {
payments: TransactionDetailData[];
pagination: {
total_records: number;
page_number: number;
page_size: number;
};
};
}
export default function TransactionDetailScreen() {
const navigation = useNavigation();
const route = useRoute();
const router = useRouter();
const { showSnackbar } = useSnackbar();
// Get payment ID from route params
const { paymentId } = route.params as { paymentId: number };
const [transactionData, setTransactionData] =
useState<TransactionDetailData | null>(null);
const [isLoading, setIsLoading] = useState(true);
useLayoutEffect(() => {
navigation.setOptions({
headerStyle: {
backgroundColor: "#F3F5F8",
},
headerTitle: "Transaction Detail",
headerTitleStyle: {
fontSize: 18,
fontWeight: "600",
color: "#111827",
},
headerLeft: () => (
<TouchableOpacity
onPress={() => router.back()}
style={styles.backButton}
>
<Text style={styles.backText}></Text>
</TouchableOpacity>
),
});
}, [navigation, router]);
useEffect(() => {
fetchTransactionDetail();
}, [paymentId]);
const fetchTransactionDetail = async () => {
try {
setIsLoading(true);
const response = await api.get(
`${BASE_URL}/api/v1/payment-history?id=${paymentId}`
);
const result: TransactionResponse = response.data;
if (result.success && result.data.payments.length > 0) {
setTransactionData(result.data.payments[0]);
} else {
showSnackbar("Transaction details not found", "error");
router.back();
}
} catch (err) {
console.error("Error fetching transaction details:", err);
const errorMessage =
err instanceof Error ? err.message : "Something went wrong";
showSnackbar(errorMessage, "error");
router.back();
} finally {
setIsLoading(false);
}
};
const formatCurrency = (amount: string) => {
return `${parseFloat(amount).toLocaleString()}`;
};
const formatDateTime = (dateString: string | null) => {
if (!dateString) return "--";
const date = new Date(dateString);
const dateStr = date.toLocaleDateString("en-IN", {
day: "2-digit",
month: "long",
year: "numeric",
});
const timeStr = date.toLocaleTimeString("en-US", {
hour: "numeric",
minute: "2-digit",
hour12: true,
});
const dayStr = date.toLocaleDateString("en-US", { weekday: "long" });
return `${dateStr}, ${timeStr}, ${dayStr}`;
};
const getStatusIcon = (status: string) => {
if (status.toLowerCase() === "confirmed") {
return <SuccessIcon width={80} height={80} />;
} else if (status.toLowerCase() === "pending") {
return <PendingIcon width={80} height={80} />;
} else {
return <FailureIcon width={80} height={80} />;
}
};
const getStatusText = (status: string) => {
switch (status.toLowerCase()) {
case "success":
case "completed":
case "confirmed":
return "Payment successful";
case "failure":
case "failed":
return "Payment failed";
case "pending":
return "Payment pending";
default:
return `Payment ${status}`;
}
};
if (isLoading) {
return (
<SafeAreaView style={styles.container}>
<View style={styles.loadingContainer}>
<ActivityIndicator size="large" color="#00BE88" />
</View>
</SafeAreaView>
);
}
if (!transactionData) {
return (
<SafeAreaView style={styles.container}>
<View style={styles.errorContainer}>
<Text style={styles.errorText}>Transaction not found</Text>
</View>
</SafeAreaView>
);
}
return (
<SafeAreaView style={styles.container}>
<View style={styles.content}>
{/* Status Icon */}
<View style={styles.iconContainer}>
{getStatusIcon(transactionData.status)}
</View>
{/* Amount */}
<Text style={styles.amount}>
{formatCurrency(transactionData.amount)}
</Text>
{/* Status Text */}
<Text style={styles.statusText}>
{getStatusText(transactionData.status)}
</Text>
{/* Date Time */}
<Text style={styles.dateTime}>
{formatDateTime(transactionData.transaction_date)}
</Text>
{/* Transaction Details Card */}
<View style={styles.detailsCard}>
<Text style={styles.detailsTitle}>Transaction Details</Text>
<DetailRow
label="Payment mode"
value={transactionData.payment_mode.join(", ") || "--"}
/>
<DetailRow
label="Paid to"
value={transactionData.upi_handle || "--"}
/>
<DetailRow
label="Paid by"
value={transactionData.paid_by_upi_handle || "--"}
/>
<DetailRow
label="Order ID"
value={transactionData.order_id || "--"}
/>
<DetailRow
label="Transaction ID"
value={transactionData.transaction_order_id || "--"}
/>
<DetailRow
label="RRN"
value={transactionData.payment_reference_id || "--"}
isLast={true}
/>
</View>
</View>
</SafeAreaView>
);
}
const DetailRow = ({
label,
value,
isLast = false,
}: {
label: string;
value: string;
isLast?: boolean;
}) => (
<View style={[styles.detailRow, isLast && styles.detailRowLast]}>
<Text style={styles.detailLabel}>{label}</Text>
<Text style={styles.detailValue}>{value}</Text>
</View>
);
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#F3F5F8",
},
loadingContainer: {
flex: 1,
justifyContent: "center",
alignItems: "center",
},
errorContainer: {
flex: 1,
justifyContent: "center",
alignItems: "center",
},
errorText: {
fontSize: 16,
color: "#6B7280",
},
content: {
flex: 1,
padding: 16,
alignItems: "center",
},
backButton: {
paddingLeft: 16,
paddingRight: 8,
paddingVertical: 8,
},
backText: {
fontSize: 24,
color: "#111827",
fontWeight: "300",
},
iconContainer: {
marginTop: 32,
marginBottom: 16,
},
successIcon: {
width: 60,
height: 60,
borderRadius: 30,
backgroundColor: "#00BE88",
justifyContent: "center",
alignItems: "center",
},
failureIcon: {
width: 60,
height: 60,
borderRadius: 30,
backgroundColor: "#EF4444",
justifyContent: "center",
alignItems: "center",
},
checkmark: {
color: "white",
fontSize: 24,
fontWeight: "bold",
},
xmark: {
color: "white",
fontSize: 20,
fontWeight: "bold",
},
amount: {
fontSize: 20,
fontWeight: "600",
color: "#252A34",
marginBottom: 16,
},
statusText: {
fontSize: 14,
fontWeight: "400",
color: "#252A34",
marginBottom: 4,
},
dateTime: {
fontSize: 14,
color: "#252A34",
textAlign: "center",
marginBottom: 24,
},
detailsCard: {
backgroundColor: "#FCFCFC",
borderRadius: 8,
padding: 16,
width: "100%",
},
detailsTitle: {
fontSize: 14,
fontWeight: "600",
color: "#252A34",
marginBottom: 8,
},
detailRow: {
flexDirection: "row",
justifyContent: "space-between",
alignItems: "flex-start",
paddingVertical: 8,
borderBottomWidth: 1,
borderBottomColor: "#E5E9F0",
},
detailRowLast: {
borderBottomWidth: 0,
},
detailLabel: {
fontSize: 14,
color: "#252A34",
flex: 1,
},
detailValue: {
fontSize: 14,
fontWeight: "600",
color: "#252A34",
flex: 1,
textAlign: "right",
},
});