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 / charts / BookingsOverviewChart.tsx

BookingsOverviewChart.tsx in Yatra – Travel Booking & Tour Operator Software 3.0.2.6, at resources/js/components/charts/BookingsOverviewChart.tsx

155 lines 3.9 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 BarChart,
4 Bar,
5 XAxis,
6 YAxis,
7 Tooltip,
8 ResponsiveContainer,
9 CartesianGrid,
10 Legend,
11 } from "recharts";
12
13 export interface BookingsOverviewPoint {
14 label: string;
15 count: number;
16 amount: number;
17 }
18
19 interface BookingsOverviewChartProps {
20 data: BookingsOverviewPoint[];
21 currency: string;
22 currencyPosition?: string;
23 currencyDecimals?: number;
24 }
25
26 const BookingsOverviewChart: React.FC<BookingsOverviewChartProps> = ({
27 data,
28 currency,
29 currencyPosition = "left",
30 currencyDecimals = 2,
31 }) => {
32 const currencySymbolMap: Record<string, string> = {
33 USD: "$",
34 EUR: "€",
35 GBP: "£",
36 INR: "₹",
37 GHS: "₵",
38 AUD: "A$",
39 CAD: "C$",
40 };
41
42 const symbol = currencySymbolMap[currency] || currency || "";
43
44 const formatAmount = (value: number, { compact }: { compact: boolean }) => {
45 const v = Number(value) || 0;
46 const decimals = Math.max(0, Math.min(4, currencyDecimals));
47
48 const formatCore = (num: number, useK: boolean) => {
49 if (compact && useK && Math.abs(num) >= 1000) {
50 const base = (num / 1000).toFixed(1);
51 return `${base}k`;
52 }
53 return num.toFixed(decimals);
54 };
55
56 const useK = compact;
57 const core = formatCore(v, useK);
58
59 switch (currencyPosition) {
60 case "right":
61 return `${core}${symbol}`;
62 case "left_space":
63 return `${symbol} ${core}`;
64 case "right_space":
65 return `${core} ${symbol}`;
66 case "left":
67 default:
68 return `${symbol}${core}`;
69 }
70 };
71 const safeData = Array.isArray(data)
72 ? data.map((d) => ({
73 month: d.label,
74 bookings: d.count ?? 0,
75 amount: d.amount ?? 0,
76 }))
77 : [];
78
79 if (!safeData.length) {
80 return (
81 <div className="flex items-center justify-center h-[140px] text-gray-500 dark:text-gray-400">
82 No data available
83 </div>
84 );
85 }
86
87 return (
88 <div className="w-full" style={{ height: 220 }}>
89 <ResponsiveContainer width="100%" height="100%">
90 <BarChart
91 data={safeData}
92 margin={{ top: 16, right: 16, left: 24, bottom: 24 }}
93 >
94 <CartesianGrid strokeDasharray="3 3" vertical={false} />
95 <XAxis
96 dataKey="month"
97 tickLine={false}
98 axisLine={false}
99 tick={{ fontFamily: "inherit", fontSize: 11, fill: "#6b7280" }}
100 />
101 <YAxis
102 yAxisId="left"
103 allowDecimals={false}
104 tickLine={false}
105 axisLine={{ stroke: "#e5e7eb" }}
106 tick={{ fontFamily: "inherit", fontSize: 11, fill: "#6b7280" }}
107 />
108 <YAxis
109 yAxisId="right"
110 orientation="right"
111 tickLine={false}
112 axisLine={false}
113 tickFormatter={(value: number) =>
114 formatAmount(value, { compact: true })
115 }
116 tick={{ fontFamily: "inherit", fontSize: 11, fill: "#6b7280" }}
117 />
118 <Tooltip
119 cursor={{ fill: "rgba(148, 163, 184, 0.12)" }}
120 formatter={(value: any, name: any) => {
121 if (name === "Bookings") {
122 return [value, "Bookings"];
123 }
124 if (name === "Amount") {
125 const formatted = formatAmount(Number(value) || 0, {
126 compact: false,
127 });
128 return [formatted, "Amount"];
129 }
130 return [value, name];
131 }}
132 />
133 <Legend />
134 <Bar
135 yAxisId="left"
136 dataKey="bookings"
137 name="Bookings"
138 radius={[4, 4, 0, 0]}
139 fill="#3b82f6"
140 />
141 <Bar
142 yAxisId="right"
143 dataKey="amount"
144 name="Amount"
145 radius={[4, 4, 0, 0]}
146 fill="#10b981"
147 />
148 </BarChart>
149 </ResponsiveContainer>
150 </div>
151 );
152 };
153
154 export default BookingsOverviewChart;
155