PluginProbe
Yatra – Travel Booking & Tour Operator Software / 3.0.5.1
Yatra – Travel Booking & Tour Operator Software v3.0.5.1
3.0.16 3.0.15 3.0.14 3.0.14.1 3.0.14.2 3.0.12 3.0.13 3.0.11 3.0.10 3.0.9 3.0.8 3.0.7 3.0.6 3.0.5 3.0.5.1 3.0.4 3.0.3 3.0.2.9 3.0.2.7 3.0.2.8 3.0.2.6 trunk 1.0.0 2.0.0 2.0.1 All 84 releases
yatra / resources / js / components / dashboard / PendingPayments.tsx

PendingPayments.tsx in Yatra – Travel Booking & Tour Operator Software 3.0.5.1, at resources/js/components/dashboard/PendingPayments.tsx

162 lines 5.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /**
2 * Pending Payments Widget
3 * Displays bookings with pending payments
4 */
5
6 import React from "react";
7 import { __ } from "../../lib/i18n";
8 import { Card, CardContent, CardHeader, CardTitle } from "../ui/card";
9 import { Badge } from "../ui/badge";
10 import { Button } from "../ui/button";
11 import { DollarSign, Clock, User } from "lucide-react";
12 import { ConditionalRender } from "../ui/conditional-render";
13 import { formatYatraMoney } from "../../lib/currency-display";
14
15 interface PendingPayment {
16 id: number;
17 booking_id: number;
18 customer_name: string;
19 trip_title: string;
20 amount: number;
21 due_date: string;
22 days_overdue?: number;
23 payment_method?: string;
24 }
25
26 interface PendingPaymentsProps {
27 payments: PendingPayment[];
28 loading?: boolean;
29 onView?: (payment: PendingPayment) => void;
30 onCollect?: (payment: PendingPayment) => void;
31 }
32
33 /**
34 * Pending Payments Widget
35 */
36 export const PendingPayments: React.FC<PendingPaymentsProps> = ({
37 payments,
38 loading = false,
39 onView,
40 onCollect,
41 }) => {
42 const globalCurrency = (window as any)?.yatraAdmin?.currency || "USD";
43 const formatCurrency = (amount: number) =>
44 formatYatraMoney(Number(amount) || 0, globalCurrency, {
45 zeroAsUnknown: false,
46 });
47
48 const formatDate = (dateString: string) => {
49 return new Date(dateString).toLocaleDateString();
50 };
51
52 const totalPending = payments?.reduce((sum, p) => sum + p.amount, 0) || 0;
53
54 if (loading) {
55 return (
56 <Card>
57 <CardHeader>
58 <CardTitle>{__("Pending Payments", "yatra")}</CardTitle>
59 </CardHeader>
60 <CardContent>
61 <div className="text-sm text-gray-500 dark:text-gray-400">
62 {__("Loading...", "yatra")}
63 </div>
64 </CardContent>
65 </Card>
66 );
67 }
68
69 return (
70 <Card>
71 <CardHeader>
72 <div className="flex items-center justify-between">
73 <CardTitle>{__("Pending Payments", "yatra")}</CardTitle>
74 {totalPending > 0 && (
75 <Badge variant="warning" className="text-sm">
76 {formatCurrency(totalPending)}
77 </Badge>
78 )}
79 </div>
80 </CardHeader>
81 <CardContent>
82 {payments && payments.length > 0 ? (
83 <div className="space-y-2">
84 {payments.slice(0, 2).map((payment) => (
85 <div
86 key={payment.id}
87 className="p-3 rounded-lg border border-gray-200 dark:border-gray-700 hover:bg-gray-50 dark:hover:bg-gray-700/50 transition-colors"
88 >
89 <div className="flex items-start justify-between mb-2">
90 <div className="flex-1">
91 <div className="flex items-center gap-2 mb-1">
92 <h4 className="text-sm font-medium text-gray-900 dark:text-white">
93 {payment.trip_title}
94 </h4>
95 {payment.days_overdue && payment.days_overdue > 0 && (
96 <Badge variant="error" className="text-xs">
97 {payment.days_overdue} {__("days overdue", "yatra")}
98 </Badge>
99 )}
100 </div>
101 <div className="flex items-center gap-1 text-sm text-gray-500 dark:text-gray-400 mb-1">
102 <User className="w-3 h-3" />
103 <span>{payment.customer_name}</span>
104 </div>
105 <div className="flex items-center gap-1 text-sm text-gray-500 dark:text-gray-400">
106 <Clock className="w-3 h-3" />
107 <span>
108 {__("Due", "yatra")}: {formatDate(payment.due_date)}
109 </span>
110 </div>
111 </div>
112 <div className="text-right">
113 <p className="text-base font-semibold text-gray-900 dark:text-white">
114 {formatCurrency(payment.amount)}
115 </p>
116 {payment.payment_method && (
117 <p className="text-xs text-gray-500 dark:text-gray-400">
118 {payment.payment_method}
119 </p>
120 )}
121 </div>
122 </div>
123
124 <ConditionalRender capability="yatra_edit_bookings">
125 <div className="flex gap-2 mt-2">
126 {onView && (
127 <Button
128 variant="outline"
129 size="sm"
130 onClick={() => onView(payment)}
131 className="flex-1"
132 >
133 {__("View", "yatra")}
134 </Button>
135 )}
136 {onCollect && (
137 <Button
138 size="sm"
139 onClick={() => onCollect(payment)}
140 className="flex-1"
141 >
142 <DollarSign className="w-4 h-4 mr-1" />
143 {__("Collect", "yatra")}
144 </Button>
145 )}
146 </div>
147 </ConditionalRender>
148 </div>
149 ))}
150 </div>
151 ) : (
152 <p className="text-sm text-gray-500 dark:text-gray-400">
153 {__("No pending payments", "yatra")}
154 </p>
155 )}
156 </CardContent>
157 </Card>
158 );
159 };
160
161 export default PendingPayments;
162