PluginProbe
Yatra – Travel Booking & Tour Operator Software / 3.0.8
Yatra – Travel Booking & Tour Operator Software v3.0.8
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.8, at resources/js/components/charts/BookingsOverviewChart.tsx

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