PluginProbe
Yatra – Travel Booking & Tour Operator Software / 3.0.13
Yatra – Travel Booking & Tour Operator Software v3.0.13
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 / RecentBookings.tsx

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

150 lines 5.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /**
2 * Recent Bookings Widget
3 * Displays recent bookings list
4 */
5
6 import React from "react";
7 import { __ } from "../../lib/i18n";
8 import { toDateValue } from "../../lib/dateFormat";
9 import { Card, CardContent, CardHeader, CardTitle } from "../ui/card";
10 import { Badge } from "../ui/badge";
11 import { Calendar, User, ArrowRight } from "lucide-react";
12 import { formatYatraMoney } from "../../lib/currency-display";
13
14 interface Booking {
15 id: number;
16 booking_id: string;
17 customer_name: string;
18 trip_title: string;
19 booking_date: string;
20 total_amount: number;
21 status: "confirmed" | "pending" | "cancelled" | "completed";
22 }
23
24 interface RecentBookingsProps {
25 bookings: Booking[];
26 loading?: boolean;
27 onView?: (booking: Booking) => void;
28 }
29
30 /**
31 * Recent Bookings Widget
32 */
33 export const RecentBookings: React.FC<RecentBookingsProps> = ({
34 bookings,
35 loading = false,
36 onView,
37 }) => {
38 const formatDate = (dateString?: string | null) => {
39 // toDateValue: a date-only booking_date must not roll back a day in behind-UTC zones.
40 const date = toDateValue(dateString);
41 if (isNaN(date.getTime())) return "-";
42 return date.toLocaleDateString("en-US", {
43 month: "short",
44 day: "numeric",
45 year: "numeric",
46 });
47 };
48
49 const globalCurrency = (window as any)?.yatraAdmin?.currency || "USD";
50 const formatCurrency = (amount: number) =>
51 formatYatraMoney(Number(amount) || 0, globalCurrency, {
52 zeroAsUnknown: false,
53 });
54
55 const getStatusColor = (status: string) => {
56 switch (status) {
57 case "confirmed":
58 return "bg-green-100 text-green-700 dark:bg-green-900/20 dark:text-green-400";
59 case "pending":
60 return "bg-yellow-100 text-yellow-700 dark:bg-yellow-900/20 dark:text-yellow-400";
61 case "cancelled":
62 return "bg-red-100 text-red-700 dark:bg-red-900/20 dark:text-red-400";
63 case "completed":
64 return "bg-blue-100 text-blue-700 dark:bg-blue-900/20 dark:text-blue-400";
65 default:
66 return "bg-gray-100 text-gray-700 dark:bg-gray-700 dark:text-gray-400";
67 }
68 };
69
70 if (loading) {
71 return (
72 <Card>
73 <CardHeader>
74 <CardTitle>{__("Recent Bookings", "yatra")}</CardTitle>
75 </CardHeader>
76 <CardContent>
77 <div className="text-sm text-gray-500 dark:text-gray-400">
78 {__("Loading...", "yatra")}
79 </div>
80 </CardContent>
81 </Card>
82 );
83 }
84
85 return (
86 <Card>
87 <CardHeader>
88 <CardTitle>{__("Recent Bookings", "yatra")}</CardTitle>
89 </CardHeader>
90 <CardContent>
91 {bookings && bookings.length > 0 ? (
92 <div className="space-y-2">
93 {bookings.slice(0, 5).map((booking) => (
94 <div
95 key={booking.id}
96 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 cursor-pointer group"
97 onClick={() => onView && onView(booking)}
98 >
99 <div className="flex items-start justify-between mb-2">
100 <div className="flex-1 min-w-0">
101 <div className="flex items-center gap-2 mb-1">
102 <h4 className="text-sm font-medium text-gray-900 dark:text-white truncate">
103 {booking.trip_title}
104 </h4>
105 <Badge
106 className={`text-xs ${getStatusColor(booking.status)}`}
107 >
108 {booking.status}
109 </Badge>
110 </div>
111 <div className="flex items-center gap-3 text-sm text-gray-500 dark:text-gray-400">
112 <div className="flex items-center gap-1">
113 <User className="w-3 h-3" />
114 <span className="truncate">
115 {booking.customer_name}
116 </span>
117 </div>
118 <div className="flex items-center gap-1">
119 <Calendar className="w-3 h-3" />
120 <span>{formatDate(booking.booking_date)}</span>
121 </div>
122 </div>
123 </div>
124 <div className="flex items-center gap-2 ml-2">
125 <div className="text-right">
126 <p className="text-sm font-semibold text-gray-900 dark:text-white">
127 {formatCurrency(booking.total_amount)}
128 </p>
129 <p className="text-xs text-gray-500 dark:text-gray-400">
130 {booking.booking_id}
131 </p>
132 </div>
133 <ArrowRight className="w-4 h-4 text-gray-400 group-hover:text-gray-600 dark:group-hover:text-gray-300 transition-colors" />
134 </div>
135 </div>
136 </div>
137 ))}
138 </div>
139 ) : (
140 <p className="text-sm text-gray-500 dark:text-gray-400">
141 {__("No recent bookings", "yatra")}
142 </p>
143 )}
144 </CardContent>
145 </Card>
146 );
147 };
148
149 export default RecentBookings;
150