PluginProbe
Yatra – Travel Booking & Tour Operator Software / 3.0.10
Yatra – Travel Booking & Tour Operator Software v3.0.10
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 2.0.10 All 83 releases
yatra / resources / js / components / trips / TripsTable.tsx

TripsTable.tsx in Yatra – Travel Booking & Tour Operator Software 3.0.10, at resources/js/components/trips/TripsTable.tsx

213 lines 6.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /**
2 * Trips Table Component
3 * Modular table component for displaying trips
4 * Supports extensibility for Pro features
5 */
6
7 import React from "react";
8 import { __ } from "../../lib/i18n";
9 import { formatYatraMoney } from "../../lib/currency-display";
10 import { ConditionalRender } from "../ui/conditional-render";
11 import {
12 Table,
13 TableBody,
14 TableCell,
15 TableHead,
16 TableHeader,
17 TableRow,
18 } from "../ui/table";
19 import { Button } from "../ui/button";
20 import { Badge } from "../ui/badge";
21 import { Edit, Trash2, Eye } from "lucide-react";
22
23 interface Trip {
24 id: number;
25 title: string;
26 slug: string;
27 price: number;
28 status: string;
29 created_at: string;
30 bookings_count?: number;
31 featured?: boolean;
32 }
33
34 interface TripsTableProps {
35 trips: Trip[];
36 loading?: boolean;
37 onEdit?: (trip: Trip) => void;
38 onDelete?: (trip: Trip) => void;
39 onView?: (trip: Trip) => void;
40 showProFeatures?: boolean;
41 }
42
43 /**
44 * Trips Table Component
45 * Displays trips in a table format with actions
46 */
47 export const TripsTable: React.FC<TripsTableProps> = ({
48 trips,
49 loading = false,
50 onEdit,
51 onDelete,
52 onView,
53 showProFeatures = false,
54 }) => {
55 const formatDate = (dateString: string) => {
56 return new Date(dateString).toLocaleDateString();
57 };
58
59 const defaultCurrency =
60 (typeof window !== "undefined" &&
61 ((window as unknown as { yatraAdmin?: { currency?: string } }).yatraAdmin
62 ?.currency ||
63 (window as unknown as { yatraBookingData?: { currency?: string } })
64 .yatraBookingData?.currency)) ||
65 "USD";
66
67 const formatPrice = (price: number) =>
68 formatYatraMoney(Number(price) || 0, defaultCurrency, {
69 zeroAsUnknown: false,
70 });
71
72 const getStatusBadge = (status: string) => {
73 const statusMap: Record<
74 string,
75 {
76 variant: "default" | "success" | "warning" | "error" | "info";
77 label: string;
78 }
79 > = {
80 active: { variant: "success", label: __("Active", "yatra") },
81 draft: { variant: "default", label: __("Draft", "yatra") },
82 inactive: { variant: "error", label: __("Inactive", "yatra") },
83 pending: { variant: "warning", label: __("Pending", "yatra") },
84 };
85
86 const statusInfo = statusMap[status] || {
87 variant: "default" as const,
88 label: status,
89 };
90 return <Badge variant={statusInfo.variant}>{statusInfo.label}</Badge>;
91 };
92
93 if (loading) {
94 return (
95 <div className="p-8 text-center text-gray-500 dark:text-gray-400">
96 {__("Loading trips...", "yatra")}
97 </div>
98 );
99 }
100
101 if (trips.length === 0) {
102 return (
103 <div className="p-8 text-center text-gray-500 dark:text-gray-400">
104 {__("No trips found", "yatra")}
105 </div>
106 );
107 }
108
109 return (
110 <div className="border border-gray-200 dark:border-gray-700 rounded-lg overflow-hidden">
111 <Table>
112 <TableHeader>
113 <TableRow>
114 <TableHead>{__("Title", "yatra")}</TableHead>
115 <TableHead>{__("Slug", "yatra")}</TableHead>
116 <TableHead>{__("Price", "yatra")}</TableHead>
117 <TableHead>{__("Status", "yatra")}</TableHead>
118 {showProFeatures && (
119 <TableHead>{__("Bookings", "yatra")}</TableHead>
120 )}
121 <TableHead>{__("Created", "yatra")}</TableHead>
122 <TableHead className="text-right">
123 {__("Actions", "yatra")}
124 </TableHead>
125 </TableRow>
126 </TableHeader>
127 <TableBody>
128 {trips.map((trip) => (
129 <TableRow key={trip.id}>
130 <TableCell className="font-medium">
131 <div className="flex items-center gap-2">
132 {trip.title}
133 {trip.featured && showProFeatures && (
134 <Badge variant="info" className="text-xs">
135 {__("Featured", "yatra")}
136 </Badge>
137 )}
138 </div>
139 </TableCell>
140 <TableCell className="text-gray-500 dark:text-gray-400">
141 {trip.slug}
142 </TableCell>
143 <TableCell>{formatPrice(trip.price)}</TableCell>
144 <TableCell>{getStatusBadge(trip.status)}</TableCell>
145 {showProFeatures && (
146 <TableCell>{trip.bookings_count || 0}</TableCell>
147 )}
148 <TableCell className="text-gray-500 dark:text-gray-400">
149 {formatDate(trip.created_at)}
150 </TableCell>
151 <TableCell className="text-right">
152 <div className="flex items-center justify-end gap-2">
153 <ConditionalRender capability="yatra_view_trips">
154 {onView && (
155 <Button
156 variant="ghost"
157 size="sm"
158 onClick={() => onView(trip)}
159 aria-label={__("View trip", "yatra")}
160 >
161 <Eye className="w-4 h-4" />
162 </Button>
163 )}
164 </ConditionalRender>
165
166 <ConditionalRender capability="yatra_edit_trips">
167 {onEdit && (
168 <Button
169 variant="ghost"
170 size="sm"
171 onClick={() => onEdit(trip)}
172 aria-label={__("Edit trip", "yatra")}
173 >
174 <Edit className="w-4 h-4" />
175 </Button>
176 )}
177 </ConditionalRender>
178
179 <ConditionalRender capability="yatra_delete_trips">
180 {onDelete && (
181 <Button
182 variant="ghost"
183 size="sm"
184 onClick={() => {
185 if (
186 confirm(
187 __(
188 "Are you sure you want to delete this trip?",
189 "yatra",
190 ),
191 )
192 ) {
193 onDelete(trip);
194 }
195 }}
196 aria-label={__("Delete trip", "yatra")}
197 >
198 <Trash2 className="w-4 h-4 text-red-500" />
199 </Button>
200 )}
201 </ConditionalRender>
202 </div>
203 </TableCell>
204 </TableRow>
205 ))}
206 </TableBody>
207 </Table>
208 </div>
209 );
210 };
211
212 export default TripsTable;
213