BaaS_Driver_Android_App/app/payments/TransactionDetails.tsx

349 lines
8.6 KiB
TypeScript

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, payments } from "@/constants/config";
import { useSnackbar } from "@/contexts/Snackbar";
import SuccessIcon from "@/assets/icons/check_circle.svg";
import FailureIcon from "@/assets/icons/cancel.svg";
import PendingIcon from "@/assets/icons/pending.svg";
import Header from "@/components/common/Header";
import { useTranslation } from "react-i18next";
import { formatDate } from "@/utils/Payments";
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);
useEffect(() => {
fetchTransactionDetail();
}, [paymentId]);
const { t } = useTranslation();
const fetchTransactionDetail = async () => {
try {
setIsLoading(true);
const response = await api.get(
`${BASE_URL}/api/v1/payment-history?page_number=1&page_size=10&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
: `${t("service.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 "confirmed":
return "Payment successful";
case "failure":
return "Payment failed";
case "pending":
return "Payment pending";
default:
return `Payment ${status}`;
}
};
return (
<>
<Header
title={`${t("payment.transaction-details")}`}
showBackButton={true}
/>
{isLoading ? (
<View style={styles.loadingContainer}>
<ActivityIndicator size="large" color="#00BE88" />
</View>
) : !transactionData ? (
<View style={styles.errorContainer}>
<Text style={styles.errorText}>Transaction not found</Text>
</View>
) : (
<View style={styles.container}>
<View style={styles.content}>
<Text style={styles.statusText}>
{getStatusText(transactionData.status)}
</Text>
<View style={styles.iconContainer}>
{getStatusIcon(transactionData.status)}
</View>
<Text style={styles.amount}>
{formatCurrency(transactionData.amount)}
</Text>
<Text>Payment to {payments.AMOUNT_PAID_TO}</Text>
<Text style={styles.dateTime}>
{formatDate(transactionData?.transaction_date)}
</Text>
<View style={styles.divider} />
<View style={styles.detailsCard}>
<Text style={styles.detailsTitle}>
{`${t("payment.transaction-details")}`}
</Text>
<DetailRow
label={`${t("payment.payment-mode")}`}
value={transactionData.payment_mode.join(", ") || "--"}
/>
<DetailRow
label={`${t("payment.paid-to")}`}
value={transactionData.upi_handle || "--"}
/>
<DetailRow
label={`${t("payment.paid-by")}`}
value={transactionData.paid_by_upi_handle || "--"}
/>
<DetailRow
label={`${t("payment.order-id")}`}
value={transactionData.order_id || "--"}
/>
<DetailRow
label={`${t("payment.transaction-id")}`}
value={transactionData.transaction_order_id || "--"}
/>
<DetailRow
label="RRN"
value={transactionData.payment_reference_id || "--"}
isLast={true}
/>
</View>
</View>
</View>
)}
</>
);
}
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({
divider: {
height: 1,
width: "100%",
backgroundColor: "#E5E9F0",
},
container: {
flex: 1,
backgroundColor: "#F3F5F8",
paddingHorizontal: 16,
},
loadingContainer: {
flex: 1,
justifyContent: "center",
alignItems: "center",
},
errorContainer: {
flex: 1,
justifyContent: "center",
alignItems: "center",
},
errorText: {
fontSize: 16,
color: "#6B7280",
},
content: {
padding: 16,
alignItems: "center",
backgroundColor: "#FCFCFC",
},
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",
},
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,
borderBottomColor: "#E5E9F0",
},
detailRowLast: {
borderBottomWidth: 0,
},
detailLabel: {
fontSize: 14,
color: "#252A34",
flex: 1,
},
detailValue: {
fontSize: 14,
fontWeight: "600",
color: "#252A34",
flex: 1,
textAlign: "left",
},
});