/** * View Payment Page * Display payment details in a clean, minimal SaaS-style design */ import React, { useMemo } from "react"; import { useQuery } from "@tanstack/react-query"; import { ArrowLeft, Mail, Phone, Calendar, CreditCard, Edit, ExternalLink, Download, } from "lucide-react"; import { __ } from "../lib/i18n"; import { apiService } from "../lib/api-client"; import { downloadAdminInvoice } from "../lib/invoice-download"; import { useToast } from "../components/ui/toast"; import { usePermissions } from "../hooks/usePermissions"; import { Button } from "../components/ui/button"; import { PageHeader } from "../components/common/PageHeader"; import { Card, CardContent, CardHeader, CardTitle, } from "../components/ui/card"; import { ConditionalRender } from "../components/ui/conditional-render"; import { Skeleton } from "../components/ui/skeleton"; import { formatYatraMoney } from "../lib/currency-display"; function paymentStr(v: unknown, fallback = ""): string { if (v == null || v === "") return fallback; return String(v); } function paymentNum(v: unknown): number { if (typeof v === "number" && !Number.isNaN(v)) return v; const n = typeof v === "string" ? parseFloat(v) : NaN; return Number.isNaN(n) ? 0 : n; } interface ViewPaymentRow { id: number; payment_number: string; booking_id: number; booking_number: string; customer_name: string; customer_email: string; customer_phone: string; trip_id: number; trip_title: string; amount: number; payment_method: string; payment_status: string; transaction_id: string; payment_date: string; notes: string; created_at: string; updated_at: string; } const ViewPayment: React.FC = () => { const { can } = usePermissions(); const { showToast } = useToast(); const [isDownloadingInvoice, setIsDownloadingInvoice] = React.useState(false); // Get payment id from URL const paymentId = useMemo(() => { const params = new URLSearchParams(window.location.search); return params.get("id") ? parseInt(params.get("id") || "0") : null; }, []); // Fetch payment data const { data: payment, isLoading, error, } = useQuery({ queryKey: ["payment", paymentId], queryFn: async () => { if (!paymentId) return null; const result = await apiService.getPayment(paymentId); if (!result) { throw new Error("Failed to fetch payment"); } if (!result.success) { throw new Error(result.message || "Payment not found"); } const data = result.data; const idNum = paymentNum(data.id); const bookingId = paymentNum(data.booking_id); const ref = paymentStr(data.booking_reference); const row: ViewPaymentRow = { id: idNum, payment_number: `PAY-${String(idNum).padStart(6, "0")}`, booking_id: bookingId, booking_number: ref || `#${bookingId}`, customer_name: paymentStr(data.customer_name, "N/A"), customer_email: paymentStr(data.customer_email), customer_phone: paymentStr(data.customer_phone), trip_id: paymentNum(data.trip_id), trip_title: paymentStr(data.trip_title), amount: paymentNum(data.amount), payment_method: paymentStr(data.gateway), payment_status: paymentStr(data.status, "pending"), transaction_id: paymentStr(data.transaction_id), payment_date: paymentStr(data.processed_at || data.created_at), notes: paymentStr(data.notes), created_at: paymentStr(data.created_at), updated_at: paymentStr(data.updated_at), }; return row; }, enabled: !!paymentId && can("yatra_view_bookings"), }); const formatDate = (dateString: string) => { return new Date(dateString).toLocaleDateString("en-US", { weekday: "long", year: "numeric", month: "long", day: "numeric", }); }; const formatPrice = (price: number, currencyCode: string = "USD") => formatYatraMoney(Number(price) || 0, currencyCode, { zeroAsUnknown: false, }); const getPaymentStatusBadge = (status: string) => { const statusMap: Record = { completed: { className: "bg-green-100 text-green-700 dark:bg-green-900/20 dark:text-green-400", label: __("Completed", "yatra"), }, pending: { className: "bg-yellow-100 text-yellow-700 dark:bg-yellow-900/20 dark:text-yellow-400", label: __("Pending", "yatra"), }, partial: { className: "bg-blue-100 text-blue-700 dark:bg-blue-900/20 dark:text-blue-400", label: __("Partial", "yatra"), }, failed: { className: "bg-red-100 text-red-700 dark:bg-red-900/20 dark:text-red-400", label: __("Failed", "yatra"), }, refunded: { className: "bg-gray-100 text-gray-700 dark:bg-gray-700 dark:text-gray-400", label: __("Refunded", "yatra"), }, }; const statusInfo = statusMap[status] || { className: "bg-gray-100 text-gray-700 dark:bg-gray-700 dark:text-gray-400", label: status, }; return ( {statusInfo.label} ); }; const handleBack = () => { window.location.href = `${window.yatraAdmin?.siteUrl || ""}/wp-admin/admin.php?page=yatra&subpage=payments`; }; const handleEdit = () => { window.location.href = `${window.yatraAdmin?.siteUrl || ""}/wp-admin/admin.php?page=yatra&subpage=payments&action=edit&id=${paymentId}`; }; const handleViewBooking = () => { if (payment?.booking_id) { window.location.href = `${window.yatraAdmin?.siteUrl || ""}/wp-admin/admin.php?page=yatra&subpage=bookings&action=view&id=${payment.booking_id}`; } }; const handleDownloadInvoice = async () => { if (!paymentId) return; setIsDownloadingInvoice(true); try { await downloadAdminInvoice(paymentId); } catch (e: any) { showToast( e?.message || __("Failed to download invoice", "yatra"), "error", ); } finally { setIsDownloadingInvoice(false); } }; const canDownloadInvoice = !!payment && ["completed", "paid"].includes( String(payment.payment_status).toLowerCase(), ); if (isLoading) { return (
{__("Back", "yatra")} } />
); } if (error || !payment) { return (
{__("Back to Payments", "yatra")} } /> {__( "Payment not found or you do not have permission to view it.", "yatra", )}
); } return (
{canDownloadInvoice && ( )}
} />
{/* Main Content */}
{/* Payment Information */}
{__("Payment Information", "yatra")} {getPaymentStatusBadge(payment.payment_status)}

{payment.payment_number}

{formatPrice(payment.amount)}

{payment.payment_method}

{formatDate(payment.payment_date)}

{payment.transaction_id && (

{payment.transaction_id}

)}
{payment.notes && (

{payment.notes}

)}
{/* Booking Information */}
{__("Related Booking", "yatra")}

{payment.booking_number}

{payment.trip_title}

{/* Sidebar */}
{/* Customer Information */} {__("Customer", "yatra")}

{payment.customer_name}

{payment.customer_email}
{payment.customer_phone && (
{payment.customer_phone}
)}
{/* Payment Timeline */} {__("Timeline", "yatra")}

{formatDate(payment.created_at)}

{payment.updated_at && payment.updated_at !== payment.created_at && (

{formatDate(payment.updated_at)}

)}
); }; export default ViewPayment;