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 / pages / account / Dashboard.tsx

Dashboard.tsx in Yatra – Travel Booking & Tour Operator Software 3.0.13, at resources/js/pages/account/Dashboard.tsx

587 lines 27.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import React from "react";
2 import {
3 Calendar,
4 CreditCard,
5 User,
6 LifeBuoy,
7 FileText,
8 Package,
9 MapPin,
10 ChevronRight,
11 ArrowRight,
12 Sparkles,
13 Plane,
14 Clock,
15 CheckCircle2,
16 AlertCircle,
17 Bell,
18 } from "lucide-react";
19 import { __, sprintf } from "../../lib/i18n";
20 import { toDateValue } from "../../lib/dateFormat";
21 import {
22 formatDate,
23 formatTravelDateRange,
24 getBadge,
25 getStatusLabel,
26 currency,
27 phoneToTelHref,
28 } from "./utils";
29 import type { Booking, Payment, CustomerProfile } from "./types";
30
31 interface DashboardProps {
32 bookings: Booking[];
33 payments: Payment[];
34 displayProfile: CustomerProfile | null;
35 stats: Array<{
36 label: string;
37 value: string | number;
38 icon: React.ElementType;
39 badge?: string;
40 }>;
41 notifications: any[];
42 /** From Yatra Settings → General (company phone). */
43 conciergePhone?: string;
44 conciergeEmail?: string;
45 onSectionChange: (section: string) => void;
46 /**
47 * Open a specific booking's detail view. Used by the "Upcoming
48 * Trips" cards so clicking one deep-links to the booking detail
49 * instead of dumping the user on the generic Bookings list.
50 */
51 onBookingOpen?: (bookingId: number) => void;
52 }
53
54 const Dashboard: React.FC<DashboardProps> = ({
55 bookings,
56 payments,
57 displayProfile,
58 stats,
59 notifications,
60 conciergePhone = "",
61 conciergeEmail = "",
62 onSectionChange,
63 onBookingOpen,
64 }) => {
65 const conciergeTel = phoneToTelHref(conciergePhone);
66 const conciergeMail = String(conciergeEmail || "").trim();
67 const upcomingBookings =
68 bookings.filter((b) => toDateValue(b.travel_date) > new Date()).length > 0
69 ? bookings
70 .filter((b) => toDateValue(b.travel_date) > new Date())
71 .slice(0, 3)
72 : bookings
73 .filter((b) => toDateValue(b.travel_date) > new Date())
74 .slice(0, 3);
75
76 const recentBookings = bookings.length > 0 ? bookings.slice(0, 2) : [];
77
78 const pendingPayments =
79 payments.filter((p) => p.status === "pending").length > 0
80 ? payments.filter((p) => p.status === "pending").slice(0, 2)
81 : [];
82
83 const displayNotifications = notifications;
84
85 // Enhanced stats with colors and gradients
86 const enhancedStats = [
87 {
88 ...stats[0],
89 gradient: "from-yatra-primary to-yatra-primary-dark",
90 bgColor: "bg-yatra-soft dark:bg-yatra-surface-dark-muted",
91 iconColor: "text-yatra-primary dark:text-yatra-on-dark",
92 },
93 {
94 ...stats[1],
95 gradient: "from-emerald-500 to-emerald-600",
96 bgColor: "bg-emerald-50 dark:bg-emerald-900/20",
97 iconColor: "text-emerald-600 dark:text-emerald-400",
98 },
99 {
100 ...stats[2],
101 gradient: "from-amber-500 to-amber-600",
102 bgColor: "bg-amber-50 dark:bg-amber-900/20",
103 iconColor: "text-amber-600 dark:text-amber-400",
104 },
105 {
106 ...stats[3],
107 gradient: "from-purple-500 to-purple-600",
108 bgColor: "bg-purple-50 dark:bg-purple-900/20",
109 iconColor: "text-purple-600 dark:text-purple-400",
110 },
111 ];
112
113 return (
114 <div className="space-y-6">
115 {/* Welcome Banner */}
116 <div
117 className="yatra-dashboard-welcome relative overflow-hidden rounded-2xl p-8 shadow-xl"
118 style={{
119 background:
120 "linear-gradient(135deg, var(--yatra-primary, #3b82f6) 0%, var(--yatra-primary-dark, #2563eb) 45%, var(--yatra-primary-darker, #1e40af) 100%)",
121 color: "#ffffff",
122 }}
123 >
124 <div className="relative z-10">
125 <div className="flex items-start justify-between">
126 <div>
127 <h2
128 className="text-lg font-bold mb-2"
129 style={{ color: "#ffffff" }}
130 >
131 {sprintf(
132 // translators: %s: customer first name (or "Traveler" fallback).
133 __("Welcome back, %s!", "yatra"),
134 displayProfile?.name?.split(" ")[0] ||
135 __("Traveler", "yatra"),
136 )}
137 </h2>
138 <p className="text-sm mb-4 text-white/90">
139 {__("You have", "yatra")} {upcomingBookings.length}{" "}
140 {upcomingBookings.length === 1
141 ? __("upcoming adventure", "yatra")
142 : __("upcoming adventures", "yatra")}{" "}
143 {__("coming up", "yatra")}
144 </p>
145 <div className="flex flex-wrap gap-3 mt-4">
146 <div
147 role="button"
148 tabIndex={0}
149 onClick={() => onSectionChange("bookings")}
150 className="px-4 py-2 rounded-lg text-sm font-medium transition-all flex items-center gap-2 hover:opacity-90 cursor-pointer"
151 style={{
152 backgroundColor: "rgba(255, 255, 255, 0.2)",
153 color: "#ffffff",
154 backdropFilter: "blur(8px)",
155 }}
156 >
157 <Calendar className="w-4 h-4" style={{ color: "#ffffff" }} />
158 {__("View Calendar", "yatra")}
159 </div>
160 <div
161 role="button"
162 tabIndex={0}
163 onClick={() => onSectionChange("documents")}
164 className="px-4 py-2 rounded-lg text-sm font-medium transition-all flex items-center gap-2 hover:opacity-90 cursor-pointer"
165 style={{
166 backgroundColor: "rgba(255, 255, 255, 0.2)",
167 color: "#ffffff",
168 backdropFilter: "blur(8px)",
169 }}
170 >
171 <FileText className="w-4 h-4" style={{ color: "#ffffff" }} />
172 {__("My Documents", "yatra")}
173 </div>
174 </div>
175 </div>
176 <div className="hidden md:block">
177 <div
178 className="w-24 h-24 rounded-full flex items-center justify-center"
179 style={{
180 backgroundColor: "rgba(255, 255, 255, 0.1)",
181 backdropFilter: "blur(8px)",
182 }}
183 >
184 <Plane className="w-12 h-12" style={{ color: "#ffffff" }} />
185 </div>
186 </div>
187 </div>
188 </div>
189 <div
190 className="absolute top-0 right-0 w-64 h-64 rounded-full -mr-32 -mt-32"
191 style={{ backgroundColor: "rgba(255, 255, 255, 0.05)" }}
192 ></div>
193 <div
194 className="absolute bottom-0 left-0 w-48 h-48 rounded-full -ml-24 -mb-24"
195 style={{ backgroundColor: "rgba(255, 255, 255, 0.05)" }}
196 ></div>
197 </div>
198
199 {/* Stats Grid */}
200 <div className="yatra-dashboard-stats grid gap-4 sm:grid-cols-2 lg:grid-cols-4">
201 {enhancedStats.map((stat) => (
202 <div
203 key={stat.label}
204 className={`yatra-stat-card yatra-stat-card-${stat.label.toLowerCase().replace(/\s+/g, "-")} group relative bg-white dark:bg-gray-800 border border-gray-100 dark:border-gray-700 rounded-xl shadow-sm hover:shadow-md transition-all overflow-hidden`}
205 >
206 <div className="p-6">
207 <div className="flex items-start justify-between mb-4">
208 <div className={`p-3 rounded-lg ${stat.bgColor}`}>
209 <stat.icon className={`w-6 h-6 ${stat.iconColor}`} />
210 </div>
211 {stat.badge && (
212 <span className="inline-flex text-xs px-2 py-1 rounded-full bg-yatra-chip-bg text-yatra-primary-dark dark:bg-yatra-surface-dark dark:text-yatra-primary-light font-medium">
213 {stat.badge}
214 </span>
215 )}
216 </div>
217 <div>
218 <p className="text-sm text-gray-500 dark:text-gray-400 mb-1">
219 {stat.label}
220 </p>
221 <p className="text-xl font-bold text-gray-900 dark:text-white">
222 {stat.value}
223 </p>
224 </div>
225 </div>
226 <div
227 className={`absolute bottom-0 left-0 right-0 h-1 bg-gradient-to-r ${stat.gradient} opacity-0 group-hover:opacity-100 transition-opacity`}
228 ></div>
229 </div>
230 ))}
231 </div>
232
233 {/* Main Content Grid */}
234 <div className="grid gap-6 lg:grid-cols-3">
235 {/* Upcoming Trips - Takes 2 columns */}
236 <div className="yatra-dashboard-upcoming-trips lg:col-span-2 bg-white dark:bg-gray-800 border border-gray-100 dark:border-gray-700 rounded-xl shadow-sm overflow-hidden">
237 <div className="yatra-dashboard-upcoming-trips-header p-6 border-b border-gray-100 dark:border-gray-700">
238 <div className="flex items-center justify-between">
239 <div className="flex items-center gap-3">
240 <div className="p-2 bg-emerald-50 dark:bg-emerald-900/20 rounded-lg">
241 <Calendar className="w-5 h-5 text-emerald-600 dark:text-emerald-400" />
242 </div>
243 <div>
244 <h3 className="text-base font-semibold text-gray-900 dark:text-white">
245 {__("Upcoming Trips", "yatra")}
246 </h3>
247 <p className="text-sm text-gray-500 dark:text-gray-400">
248 {__("Your next adventures", "yatra")}
249 </p>
250 </div>
251 </div>
252 {upcomingBookings.length > 0 && (
253 <div
254 role="button"
255 tabIndex={0}
256 onClick={() => onSectionChange("bookings")}
257 className="text-sm text-yatra-primary dark:text-yatra-on-dark hover:text-yatra-primary-dark dark:hover:text-yatra-primary-light font-medium flex items-center gap-1 transition-colors cursor-pointer"
258 >
259 {__("View all", "yatra")}
260 <ArrowRight className="w-4 h-4" />
261 </div>
262 )}
263 </div>
264 </div>
265 <div className="p-6">
266 {upcomingBookings.length > 0 ? (
267 <div className="space-y-4">
268 {upcomingBookings.map((booking) => {
269 // Each card was rendered with `cursor-pointer`, a
270 // hover-shadow and a `ChevronRight` affordance — i.e.
271 // styled as a clickable nav element — but had no
272 // onClick handler, so clicking did nothing. Deep-link
273 // into the booking detail view via the parent
274 // AccountPage so the user lands directly on the
275 // selected booking rather than the generic list.
276 const openBooking = () => {
277 const id = Number(booking.id);
278 if (!id) return;
279 if (onBookingOpen) {
280 onBookingOpen(id);
281 } else {
282 onSectionChange("bookings");
283 }
284 };
285 return (
286 <div
287 key={booking.id}
288 role="button"
289 tabIndex={0}
290 onClick={openBooking}
291 onKeyDown={(e) => {
292 if (e.key === "Enter" || e.key === " ") {
293 e.preventDefault();
294 openBooking();
295 }
296 }}
297 className="yatra-booking-card yatra-booking-card-upcoming group relative border border-gray-200 dark:border-gray-700 rounded-xl p-5 hover:border-yatra-border-hover dark:hover:border-yatra-border-hover-dark hover:shadow-md transition-all cursor-pointer bg-gradient-to-r from-white to-gray-50/50 dark:from-gray-800 dark:to-gray-800/50"
298 >
299 <div className="flex items-start gap-4">
300 <div className="flex-shrink-0">
301 <div className="w-12 h-12 bg-gradient-to-br from-yatra-primary to-yatra-primary-darker rounded-lg flex items-center justify-center shadow-sm">
302 <MapPin className="w-6 h-6 text-white" />
303 </div>
304 </div>
305 <div className="flex-1 min-w-0">
306 <div className="flex items-start justify-between gap-2 mb-2">
307 <h4 className="text-sm font-semibold text-gray-900 dark:text-white group-hover:text-yatra-primary dark:group-hover:text-yatra-on-dark transition-colors">
308 {booking.trip_title}
309 </h4>
310 <span className={getBadge(booking.booking_status)}>
311 {getStatusLabel(booking.booking_status)}
312 </span>
313 </div>
314 <p className="text-sm text-gray-600 dark:text-gray-400 mb-2 flex items-center gap-2">
315 <MapPin className="w-4 h-4" />
316 {booking.destination ||
317 __("Multiple destinations", "yatra")}
318 </p>
319 <div className="flex items-center gap-4 text-xs text-gray-500 dark:text-gray-400">
320 <span className="flex items-center gap-1">
321 <Calendar className="w-3.5 h-3.5" />
322 {formatTravelDateRange(
323 booking.travel_date,
324 booking.end_date,
325 )}
326 </span>
327 <span className="flex items-center gap-1">
328 <User className="w-3.5 h-3.5" />
329 {(() => {
330 // Use `travelers_count` for the count — see
331 // Booking interface comment in types.ts.
332 const n =
333 Number(
334 booking.travelers_count ??
335 booking.travelers ??
336 0,
337 ) || 0;
338 // __() (not _n): make-pot misses _n() in the
339 // minified account bundle, so plurals stay
340 // English on the frontend. See BookingDetails.
341 return n === 1
342 ? sprintf(__("%d Traveler", "yatra"), n)
343 : sprintf(__("%d Travelers", "yatra"), n);
344 })()}
345 </span>
346 </div>
347 </div>
348 <ChevronRight className="w-5 h-5 text-gray-400 group-hover:text-yatra-primary dark:group-hover:text-yatra-on-dark transition-colors flex-shrink-0" />
349 </div>
350 </div>
351 );
352 })}
353 </div>
354 ) : (
355 <div className="text-center py-12">
356 <div className="w-16 h-16 bg-gray-100 dark:bg-gray-700 rounded-full flex items-center justify-center mx-auto mb-4">
357 <Calendar className="w-8 h-8 text-gray-400" />
358 </div>
359 <p className="text-gray-500 dark:text-gray-400 font-medium mb-1">
360 {__("No upcoming trips", "yatra")}
361 </p>
362 <p className="text-sm text-gray-400 dark:text-gray-500">
363 {__("Start planning your next adventure!", "yatra")}
364 </p>
365 </div>
366 )}
367 </div>
368 </div>
369
370 {/* Quick Actions & Notifications - Takes 1 column */}
371 <div className="space-y-6">
372 {/* Quick Actions */}
373 <div className="yatra-dashboard-quick-actions bg-white dark:bg-gray-800 border border-gray-100 dark:border-gray-700 rounded-xl shadow-sm overflow-hidden">
374 <div className="yatra-dashboard-quick-actions-header p-6 border-b border-gray-100 dark:border-gray-700">
375 <div className="flex items-center gap-3">
376 <div className="p-2 bg-purple-50 dark:bg-purple-900/20 rounded-lg">
377 <Sparkles className="w-5 h-5 text-purple-600 dark:text-purple-400" />
378 </div>
379 <h3 className="text-base font-semibold text-gray-900 dark:text-white">
380 {__("Quick Actions", "yatra")}
381 </h3>
382 </div>
383 </div>
384 <div className="p-6 space-y-3">
385 <div
386 role="button"
387 tabIndex={0}
388 onClick={() => onSectionChange("bookings")}
389 className="w-full flex items-center justify-between p-4 border border-gray-200 dark:border-gray-700 rounded-lg hover:border-yatra-border-hover dark:hover:border-yatra-border-hover-dark hover:bg-yatra-hover-soft dark:hover:bg-yatra-hover-soft-dark transition-all group cursor-pointer text-sm"
390 >
391 <div className="flex items-center gap-3">
392 <Package className="w-5 h-5 text-gray-400 group-hover:text-yatra-primary dark:group-hover:text-yatra-on-dark" />
393 <span className="font-medium text-gray-700 dark:text-gray-300 group-hover:text-yatra-primary dark:group-hover:text-yatra-on-dark">
394 {__("View Bookings", "yatra")}
395 </span>
396 </div>
397 <ChevronRight className="w-4 h-4 text-gray-400 group-hover:text-yatra-primary dark:group-hover:text-yatra-on-dark" />
398 </div>
399 <div
400 role="button"
401 tabIndex={0}
402 onClick={() => onSectionChange("payments")}
403 className="w-full flex items-center justify-between p-4 border border-gray-200 dark:border-gray-700 rounded-lg hover:border-yatra-border-hover dark:hover:border-yatra-border-hover-dark hover:bg-yatra-hover-soft dark:hover:bg-yatra-hover-soft-dark transition-all group cursor-pointer text-sm"
404 >
405 <div className="flex items-center gap-3">
406 <CreditCard className="w-5 h-5 text-gray-400 group-hover:text-yatra-primary dark:group-hover:text-yatra-on-dark" />
407 <span className="font-medium text-gray-700 dark:text-gray-300 group-hover:text-yatra-primary dark:group-hover:text-yatra-on-dark">
408 {__("Make Payment", "yatra")}
409 </span>
410 </div>
411 <ChevronRight className="w-4 h-4 text-gray-400 group-hover:text-yatra-primary dark:group-hover:text-yatra-on-dark" />
412 </div>
413 <div
414 role="button"
415 tabIndex={0}
416 onClick={() => onSectionChange("documents")}
417 className="w-full flex items-center justify-between p-4 border border-gray-200 dark:border-gray-700 rounded-lg hover:border-yatra-border-hover dark:hover:border-yatra-border-hover-dark hover:bg-yatra-hover-soft dark:hover:bg-yatra-hover-soft-dark transition-all group cursor-pointer text-sm"
418 >
419 <div className="flex items-center gap-3">
420 <FileText className="w-5 h-5 text-gray-400 group-hover:text-yatra-primary dark:group-hover:text-yatra-on-dark" />
421 <span className="font-medium text-gray-700 dark:text-gray-300 group-hover:text-yatra-primary dark:group-hover:text-yatra-on-dark">
422 {__("My Documents", "yatra")}
423 </span>
424 </div>
425 <ChevronRight className="w-4 h-4 text-gray-400 group-hover:text-yatra-primary dark:group-hover:text-yatra-on-dark" />
426 </div>
427 {conciergeTel ? (
428 <a
429 href={conciergeTel}
430 className="w-full flex items-center justify-between p-4 border border-gray-200 dark:border-gray-700 rounded-lg hover:border-yatra-border-hover dark:hover:border-yatra-border-hover-dark hover:bg-yatra-hover-soft dark:hover:bg-yatra-hover-soft-dark transition-all group cursor-pointer text-sm no-underline text-inherit"
431 >
432 <div className="flex items-center gap-3">
433 <LifeBuoy className="w-5 h-5 text-gray-400 group-hover:text-yatra-primary dark:group-hover:text-yatra-on-dark" />
434 <span className="font-medium text-gray-700 dark:text-gray-300 group-hover:text-yatra-primary dark:group-hover:text-yatra-on-dark">
435 {__("Call us", "yatra")}
436 </span>
437 </div>
438 <ChevronRight className="w-4 h-4 text-gray-400 group-hover:text-yatra-primary dark:group-hover:text-yatra-on-dark" />
439 </a>
440 ) : conciergeMail ? (
441 <a
442 href={`mailto:${encodeURIComponent(conciergeMail)}`}
443 className="w-full flex items-center justify-between p-4 border border-gray-200 dark:border-gray-700 rounded-lg hover:border-yatra-border-hover dark:hover:border-yatra-border-hover-dark hover:bg-yatra-hover-soft dark:hover:bg-yatra-hover-soft-dark transition-all group cursor-pointer text-sm no-underline text-inherit"
444 >
445 <div className="flex items-center gap-3">
446 <LifeBuoy className="w-5 h-5 text-gray-400 group-hover:text-yatra-primary dark:group-hover:text-yatra-on-dark" />
447 <span className="font-medium text-gray-700 dark:text-gray-300 group-hover:text-yatra-primary dark:group-hover:text-yatra-on-dark">
448 {__("Email us", "yatra")}
449 </span>
450 </div>
451 <ChevronRight className="w-4 h-4 text-gray-400 group-hover:text-yatra-primary dark:group-hover:text-yatra-on-dark" />
452 </a>
453 ) : null}
454 </div>
455 </div>
456
457 {/* Notifications */}
458 <div className="yatra-dashboard-notifications bg-white dark:bg-gray-800 border border-gray-100 dark:border-gray-700 rounded-xl shadow-sm overflow-hidden">
459 <div className="yatra-dashboard-notifications-header p-6 border-b border-gray-100 dark:border-gray-700">
460 <div className="flex items-center gap-3">
461 <div className="p-2 bg-amber-50 dark:bg-amber-900/20 rounded-lg">
462 <Bell className="w-5 h-5 text-amber-600 dark:text-amber-400" />
463 </div>
464 <div>
465 <h3 className="text-base font-semibold text-gray-900 dark:text-white">
466 {__("Notifications", "yatra")}
467 </h3>
468 <p className="text-xs text-gray-500 dark:text-gray-400">
469 {__("Updates & reminders", "yatra")}
470 </p>
471 </div>
472 </div>
473 </div>
474 <div className="p-6 space-y-3">
475 {displayNotifications.length > 0 ? (
476 displayNotifications.map((notif) => (
477 <div
478 key={notif.id}
479 className={`p-4 rounded-lg border ${
480 notif.type === "warning"
481 ? "bg-amber-50 dark:bg-amber-900/10 border-amber-200 dark:border-amber-800"
482 : "bg-yatra-soft dark:bg-yatra-hover-soft-dark border-yatra-border-subtle dark:border-yatra-border-dark"
483 }`}
484 >
485 <div className="flex items-start gap-3">
486 {notif.type === "warning" ? (
487 <AlertCircle className="w-5 h-5 text-amber-600 dark:text-amber-400 flex-shrink-0 mt-0.5" />
488 ) : (
489 <CheckCircle2 className="w-5 h-5 text-yatra-primary dark:text-yatra-on-dark flex-shrink-0 mt-0.5" />
490 )}
491 <div className="flex-1 min-w-0">
492 <p className="font-semibold text-sm text-gray-900 dark:text-white mb-1">
493 {notif.title}
494 </p>
495 <p className="text-xs text-gray-600 dark:text-gray-400 leading-relaxed">
496 {notif.message}
497 </p>
498 </div>
499 </div>
500 </div>
501 ))
502 ) : (
503 <div className="text-center py-6">
504 <Bell className="w-8 h-8 text-gray-300 dark:text-gray-600 mx-auto mb-2" />
505 <p className="text-sm text-gray-400 dark:text-gray-500">
506 {__("No new notifications", "yatra")}
507 </p>
508 </div>
509 )}
510 </div>
511 </div>
512 </div>
513 </div>
514
515 {/* Recent Activity Section */}
516 {(recentBookings.length > 0 || pendingPayments.length > 0) && (
517 <div className="yatra-dashboard-recent-activity bg-white dark:bg-gray-800 border border-gray-100 dark:border-gray-700 rounded-xl shadow-sm overflow-hidden">
518 <div className="yatra-dashboard-recent-activity-header p-6 border-b border-gray-100 dark:border-gray-700">
519 <div className="flex items-center gap-3">
520 <div className="p-2 bg-yatra-soft dark:bg-yatra-surface-dark-muted rounded-lg">
521 <Clock className="w-5 h-5 text-yatra-primary dark:text-yatra-on-dark" />
522 </div>
523 <div>
524 <h3 className="text-base font-semibold text-gray-900 dark:text-white">
525 {__("Recent Activity", "yatra")}
526 </h3>
527 <p className="text-sm text-gray-500 dark:text-gray-400">
528 {__("Your latest updates", "yatra")}
529 </p>
530 </div>
531 </div>
532 </div>
533 <div className="p-6">
534 <div className="space-y-4">
535 {recentBookings.map((booking) => (
536 <div
537 key={booking.id}
538 className="flex items-center gap-4 pb-4 border-b border-gray-100 dark:border-gray-700 last:border-0 last:pb-0"
539 >
540 <div className="w-10 h-10 bg-yatra-chip-bg dark:bg-yatra-surface-dark rounded-full flex items-center justify-center flex-shrink-0">
541 <CheckCircle2 className="w-5 h-5 text-yatra-primary dark:text-yatra-on-dark" />
542 </div>
543 <div className="flex-1 min-w-0">
544 <p className="text-sm font-medium text-gray-900 dark:text-white">
545 {__("Booking confirmed:", "yatra")} {booking.trip_title}
546 </p>
547 <p className="text-xs text-gray-500 dark:text-gray-400">
548 {formatDate(booking.booking_date || booking.created_at)}
549 </p>
550 </div>
551 <span className={getBadge(booking.booking_status)}>
552 {getStatusLabel(booking.booking_status)}
553 </span>
554 </div>
555 ))}
556 {pendingPayments.map((payment) => (
557 <div
558 key={payment.id}
559 className="flex items-center gap-4 pb-4 border-b border-gray-100 dark:border-gray-700 last:border-0 last:pb-0"
560 >
561 <div className="w-10 h-10 bg-amber-100 dark:bg-amber-900/30 rounded-full flex items-center justify-center flex-shrink-0">
562 <Clock className="w-5 h-5 text-amber-600 dark:text-amber-400" />
563 </div>
564 <div className="flex-1 min-w-0">
565 <p className="text-sm font-medium text-gray-900 dark:text-white">
566 {__("Payment pending:", "yatra")}{" "}
567 {currency(payment.amount)}
568 </p>
569 <p className="text-xs text-gray-500 dark:text-gray-400">
570 {formatDate(payment.date)}
571 </p>
572 </div>
573 <span className={getBadge(payment.status)}>
574 {getStatusLabel(payment.status)}
575 </span>
576 </div>
577 ))}
578 </div>
579 </div>
580 </div>
581 )}
582 </div>
583 );
584 };
585
586 export default Dashboard;
587