PluginProbe
Yatra – Travel Booking & Tour Operator Software / 3.0.2.6
Yatra – Travel Booking & Tour Operator Software v3.0.2.6
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.2.6, at resources/js/components/dashboard/PendingPayments.tsx

197 lines 6.5 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 { getCurrencySymbol } from "../../data/currencies";
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 // Get global currency settings
43 const globalCurrency = (window as any)?.yatraAdmin?.currency || "USD";
44 const currencyPosition =
45 (window as any)?.yatraAdmin?.currencyPosition ||
46 (window as any)?.yatraAdmin?.currency_position ||
47 "before";
48 const decimalPlaces = Number(
49 (window as any)?.yatraAdmin?.decimalPlaces ||
50 (window as any)?.yatraAdmin?.currency_decimals ||
51 2,
52 );
53 const thousandSeparator =
54 (window as any)?.yatraAdmin?.thousandSeparator || ",";
55 const decimalSeparator = (window as any)?.yatraAdmin?.decimalSeparator || ".";
56
57 const formatCurrency = (amount: number) => {
58 if (!amount || amount === 0) return getCurrencySymbol(globalCurrency) + "0";
59
60 const numPrice = Number(amount) || 0;
61
62 // Format the number with proper separators
63 const formattedAmount = new Intl.NumberFormat(undefined, {
64 minimumFractionDigits: decimalPlaces,
65 maximumFractionDigits: decimalPlaces,
66 })
67 .format(numPrice)
68 .replace(/,/g, "TEMP_THOUSAND")
69 .replace(/\./g, decimalSeparator)
70 .replace(/TEMP_THOUSAND/g, thousandSeparator);
71
72 // Get currency symbol
73 const currencySymbol = getCurrencySymbol(globalCurrency);
74
75 // Apply currency position
76 if (currencyPosition === "after" || currencyPosition === "right") {
77 return `${formattedAmount} ${currencySymbol}`;
78 } else {
79 return `${currencySymbol}${formattedAmount}`;
80 }
81 };
82
83 const formatDate = (dateString: string) => {
84 return new Date(dateString).toLocaleDateString();
85 };
86
87 const totalPending = payments?.reduce((sum, p) => sum + p.amount, 0) || 0;
88
89 if (loading) {
90 return (
91 <Card>
92 <CardHeader>
93 <CardTitle>{__("Pending Payments", "yatra")}</CardTitle>
94 </CardHeader>
95 <CardContent>
96 <div className="text-sm text-gray-500 dark:text-gray-400">
97 {__("Loading...", "yatra")}
98 </div>
99 </CardContent>
100 </Card>
101 );
102 }
103
104 return (
105 <Card>
106 <CardHeader>
107 <div className="flex items-center justify-between">
108 <CardTitle>{__("Pending Payments", "yatra")}</CardTitle>
109 {totalPending > 0 && (
110 <Badge variant="warning" className="text-sm">
111 {formatCurrency(totalPending)}
112 </Badge>
113 )}
114 </div>
115 </CardHeader>
116 <CardContent>
117 {payments && payments.length > 0 ? (
118 <div className="space-y-2">
119 {payments.slice(0, 2).map((payment) => (
120 <div
121 key={payment.id}
122 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"
123 >
124 <div className="flex items-start justify-between mb-2">
125 <div className="flex-1">
126 <div className="flex items-center gap-2 mb-1">
127 <h4 className="text-sm font-medium text-gray-900 dark:text-white">
128 {payment.trip_title}
129 </h4>
130 {payment.days_overdue && payment.days_overdue > 0 && (
131 <Badge variant="error" className="text-xs">
132 {payment.days_overdue} {__("days overdue", "yatra")}
133 </Badge>
134 )}
135 </div>
136 <div className="flex items-center gap-1 text-sm text-gray-500 dark:text-gray-400 mb-1">
137 <User className="w-3 h-3" />
138 <span>{payment.customer_name}</span>
139 </div>
140 <div className="flex items-center gap-1 text-sm text-gray-500 dark:text-gray-400">
141 <Clock className="w-3 h-3" />
142 <span>
143 {__("Due", "yatra")}: {formatDate(payment.due_date)}
144 </span>
145 </div>
146 </div>
147 <div className="text-right">
148 <p className="text-base font-semibold text-gray-900 dark:text-white">
149 {formatCurrency(payment.amount)}
150 </p>
151 {payment.payment_method && (
152 <p className="text-xs text-gray-500 dark:text-gray-400">
153 {payment.payment_method}
154 </p>
155 )}
156 </div>
157 </div>
158
159 <ConditionalRender capability="yatra_edit_bookings">
160 <div className="flex gap-2 mt-2">
161 {onView && (
162 <Button
163 variant="outline"
164 size="sm"
165 onClick={() => onView(payment)}
166 className="flex-1"
167 >
168 {__("View", "yatra")}
169 </Button>
170 )}
171 {onCollect && (
172 <Button
173 size="sm"
174 onClick={() => onCollect(payment)}
175 className="flex-1"
176 >
177 <DollarSign className="w-4 h-4 mr-1" />
178 {__("Collect", "yatra")}
179 </Button>
180 )}
181 </div>
182 </ConditionalRender>
183 </div>
184 ))}
185 </div>
186 ) : (
187 <p className="text-sm text-gray-500 dark:text-gray-400">
188 {__("No pending payments", "yatra")}
189 </p>
190 )}
191 </CardContent>
192 </Card>
193 );
194 };
195
196 export default PendingPayments;
197