-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
4e5e6ef
commit a933117
Showing
10 changed files
with
519 additions
and
243 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,264 +1,76 @@ | ||
"use client"; | ||
|
||
import { Bike, Car, CircleDollarSign, Truck } from "lucide-react"; | ||
import { | ||
Bar, | ||
BarChart, | ||
CartesianGrid, | ||
Legend, | ||
Line, | ||
LineChart, | ||
ResponsiveContainer, | ||
Tooltip, | ||
XAxis, | ||
YAxis, | ||
} from "recharts"; | ||
import { CategoryInfo } from "@/components/CategoryInfo"; | ||
// import { | ||
// Bar, | ||
// BarChart, | ||
// CartesianGrid, | ||
// Legend, | ||
// Line, | ||
// LineChart, | ||
// ResponsiveContainer, | ||
// Tooltip, | ||
// XAxis, | ||
// YAxis, | ||
// } from "recharts"; | ||
import { | ||
Card, | ||
CardContent, | ||
CardDescription, | ||
CardHeader, | ||
CardTitle, | ||
} from "@/components/ui/card"; | ||
import { useAtomValue } from "jotai"; | ||
import { showCategoriesAtom } from "@/atoms/coeAtom"; | ||
import { fetchApi } from "@/utils/fetchApi"; | ||
import { COEBiddingResult, COEResult } from "@/types"; | ||
import { API_URL } from "@/config"; | ||
import { | ||
Tooltip, | ||
TooltipContent, | ||
TooltipProvider, | ||
TooltipTrigger, | ||
} from "@/components/ui/tooltip"; | ||
import { COECategories } from "@/components/COECategories"; | ||
import { COEPremiumChart } from "@/components/COEPremiumChart"; | ||
import Typography from "@/components/Typography"; | ||
|
||
const COEPricesPage = async () => { | ||
const historicalResult: COEResult[] = await fetchApi<COEResult[]>( | ||
`${API_URL}/coe`, | ||
); | ||
|
||
const groupedData: COEBiddingResult[] = historicalResult.reduce( | ||
(acc: any, item) => { | ||
const key = `${item.month}-${item.bidding_no}`; | ||
console.log(key); | ||
|
||
const COEPricesPage = () => { | ||
const categories = useAtomValue(showCategoriesAtom); | ||
const filteredData = data.map((item) => | ||
Object.entries(item).reduce((acc: any, [key, value]) => { | ||
if ( | ||
key === "month" || | ||
(key.startsWith("Category") && | ||
categories[`Category ${key.slice(-1)}`]) || | ||
(key.startsWith("Bids") && categories[`Category ${key.slice(-1)}`]) | ||
) { | ||
acc[key] = value; | ||
if (!acc[key]) { | ||
acc[key] = { | ||
month: item.month, | ||
biddingNo: item.bidding_no, | ||
}; | ||
} | ||
acc[key][item.vehicle_class] = item.premium; | ||
|
||
return acc; | ||
}, {}), | ||
}, | ||
[], | ||
); | ||
|
||
const data: COEBiddingResult[] = Object.values(groupedData).sort( | ||
(a, b) => a.biddingNo - b.biddingNo, | ||
); | ||
|
||
return ( | ||
<div className="flex flex-col gap-y-8"> | ||
<h2 className="mb-4 text-2xl font-bold text-gray-800"> | ||
COE Bidding Results Dashboard (2024) | ||
</h2> | ||
{/*TODO: Allow filtering by year*/} | ||
<Typography.H1>COE Results Dashboard</Typography.H1> | ||
<div className="grid gap-4 lg:grid-cols-4"> | ||
<div className="grid gap-4 lg:col-span-2 xl:col-span-3"> | ||
<Card> | ||
<CardHeader> | ||
<CardTitle>Quota Premium Trends</CardTitle> | ||
</CardHeader> | ||
<CardContent> | ||
<ResponsiveContainer width="100%" height={400}> | ||
<LineChart data={filteredData}> | ||
<CartesianGrid strokeDasharray="3 3" /> | ||
<XAxis dataKey="month" /> | ||
<YAxis /> | ||
<Tooltip /> | ||
<Legend /> | ||
<Line | ||
type="monotone" | ||
dataKey="CategoryA" | ||
stroke="#8884d8" | ||
name="Category A" | ||
/> | ||
<Line | ||
type="monotone" | ||
dataKey="CategoryB" | ||
stroke="#82ca9d" | ||
name="Category B" | ||
/> | ||
{categories["Category C"] && ( | ||
<Line | ||
type="monotone" | ||
dataKey="CategoryC" | ||
stroke="#ffc658" | ||
name="Category C" | ||
/> | ||
)} | ||
{categories["Category D"] && ( | ||
<Line | ||
type="monotone" | ||
dataKey="CategoryD" | ||
stroke="#ff8042" | ||
name="Category D" | ||
/> | ||
)} | ||
<Line | ||
type="monotone" | ||
dataKey="CategoryE" | ||
stroke="#0088FE" | ||
name="Category E" | ||
/> | ||
</LineChart> | ||
</ResponsiveContainer> | ||
</CardContent> | ||
</Card> | ||
<Card> | ||
<CardHeader> | ||
<CardTitle>Bidding Results</CardTitle> | ||
</CardHeader> | ||
<CardContent> | ||
<ResponsiveContainer width="100%" height={400}> | ||
<BarChart data={filteredData}> | ||
<CartesianGrid strokeDasharray="3 3" /> | ||
<XAxis dataKey="month" /> | ||
<YAxis /> | ||
<Tooltip /> | ||
<Legend /> | ||
<Bar dataKey="BidsA" fill="#8884d8" name="Category A" /> | ||
<Bar dataKey="BidsB" fill="#82ca9d" name="Category B" /> | ||
{categories["Category C"] && ( | ||
<Bar dataKey="BidsC" fill="#ffc658" name="Category C" /> | ||
)} | ||
{categories["Category D"] && ( | ||
<Bar dataKey="BidsD" fill="#ff8042" name="Category D" /> | ||
)} | ||
<Bar dataKey="BidsE" fill="#0088FE" name="Category E" /> | ||
</BarChart> | ||
</ResponsiveContainer> | ||
</CardContent> | ||
</Card> | ||
<COEPremiumChart data={data} /> | ||
</div> | ||
<div className="grid gap-4 lg:col-span-2 xl:col-span-1"> | ||
<Card> | ||
<CardHeader> | ||
<CardTitle>Categories</CardTitle> | ||
<CardDescription>Filter based on Category</CardDescription> | ||
</CardHeader> | ||
<CardContent> | ||
<CategoryInfo | ||
icon={Car} | ||
category="Category A" | ||
description="Cars up to 1600cc & 97kW" | ||
canFilter={false} | ||
/> | ||
<CategoryInfo | ||
icon={Car} | ||
category="Category B" | ||
description="Cars above 1600cc or 97kW" | ||
canFilter={false} | ||
/> | ||
<CategoryInfo | ||
icon={Truck} | ||
category="Category C" | ||
description="Goods vehicles & buses" | ||
/> | ||
<CategoryInfo | ||
icon={Bike} | ||
category="Category D" | ||
description="Motorcycles" | ||
/> | ||
<CategoryInfo | ||
icon={CircleDollarSign} | ||
category="Category E" | ||
description="Open Category" | ||
canFilter={false} | ||
/> | ||
</CardContent> | ||
</Card> | ||
<COECategories /> | ||
</div> | ||
</div> | ||
</div> | ||
); | ||
}; | ||
|
||
// TODO: Dummy data for visualisation ONLY | ||
const data = [ | ||
{ | ||
month: "Jan 2024", | ||
CategoryA: 81589, | ||
CategoryB: 112000, | ||
CategoryC: 68001, | ||
CategoryD: 9309, | ||
CategoryE: 109004, | ||
BidsA: 921, | ||
BidsB: 657, | ||
BidsC: 187, | ||
BidsD: 491, | ||
BidsE: 136, | ||
}, | ||
{ | ||
month: "Feb 2024", | ||
CategoryA: 76801, | ||
CategoryB: 97000, | ||
CategoryC: 73001, | ||
CategoryD: 8911, | ||
CategoryE: 94006, | ||
BidsA: 936, | ||
BidsB: 642, | ||
BidsC: 192, | ||
BidsD: 548, | ||
BidsE: 156, | ||
}, | ||
{ | ||
month: "Mar 2024", | ||
CategoryA: 85489, | ||
CategoryB: 96011, | ||
CategoryC: 70112, | ||
CategoryD: 9689, | ||
CategoryE: 95856, | ||
BidsA: 935, | ||
BidsB: 615, | ||
BidsC: 202, | ||
BidsD: 516, | ||
BidsE: 157, | ||
}, | ||
{ | ||
month: "Apr 2024", | ||
CategoryA: 94010, | ||
CategoryB: 102001, | ||
CategoryC: 68502, | ||
CategoryD: 9990, | ||
CategoryE: 103249, | ||
BidsA: 916, | ||
BidsB: 690, | ||
BidsC: 193, | ||
BidsD: 514, | ||
BidsE: 151, | ||
}, | ||
{ | ||
month: "May 2024", | ||
CategoryA: 92700, | ||
CategoryB: 105689, | ||
CategoryC: 72001, | ||
CategoryD: 9311, | ||
CategoryE: 105002, | ||
BidsA: 980, | ||
BidsB: 641, | ||
BidsC: 198, | ||
BidsD: 523, | ||
BidsE: 176, | ||
}, | ||
{ | ||
month: "Jun 2024", | ||
CategoryA: 90889, | ||
CategoryB: 102334, | ||
CategoryC: 69900, | ||
CategoryD: 9002, | ||
CategoryE: 100000, | ||
BidsA: 955, | ||
BidsB: 670, | ||
BidsC: 206, | ||
BidsD: 519, | ||
BidsE: 175, | ||
}, | ||
{ | ||
month: "Jul 2024", | ||
CategoryA: 91001, | ||
CategoryB: 100901, | ||
CategoryC: 70001, | ||
CategoryD: 8900, | ||
CategoryE: 100889, | ||
BidsA: 932, | ||
BidsB: 671, | ||
BidsC: 213, | ||
BidsD: 517, | ||
BidsE: 170, | ||
}, | ||
]; | ||
|
||
export default COEPricesPage; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
"use client"; | ||
|
||
import { | ||
Bike, | ||
Car, | ||
CircleDollarSign, | ||
HelpCircleIcon, | ||
Truck, | ||
} from "lucide-react"; | ||
import { CategoryInfo } from "@/components/CategoryInfo"; | ||
import { | ||
Card, | ||
CardContent, | ||
CardDescription, | ||
CardHeader, | ||
CardTitle, | ||
} from "@/components/ui/card"; | ||
import { | ||
Tooltip, | ||
TooltipContent, | ||
TooltipProvider, | ||
TooltipTrigger, | ||
} from "@/components/ui/tooltip"; | ||
|
||
export const COECategories = () => { | ||
return ( | ||
<Card> | ||
<CardHeader> | ||
<CardTitle>Categories</CardTitle> | ||
<CardDescription> | ||
<TooltipProvider> | ||
<Tooltip> | ||
<span>Filter based on Category </span> | ||
<TooltipTrigger> | ||
<HelpCircleIcon className="h-4 w-4" /> | ||
</TooltipTrigger> | ||
<TooltipContent> | ||
<p>You can only filter Categories C & D</p> | ||
</TooltipContent> | ||
</Tooltip> | ||
</TooltipProvider> | ||
</CardDescription> | ||
</CardHeader> | ||
<CardContent> | ||
<CategoryInfo | ||
icon={Car} | ||
category="Category A" | ||
description="Cars up to 1600cc & 97kW" | ||
canFilter={false} | ||
/> | ||
<CategoryInfo | ||
icon={Car} | ||
category="Category B" | ||
description="Cars above 1600cc or 97kW" | ||
canFilter={false} | ||
/> | ||
<CategoryInfo | ||
icon={Truck} | ||
category="Category C" | ||
description="Goods vehicles & buses" | ||
/> | ||
<CategoryInfo | ||
icon={Bike} | ||
category="Category D" | ||
description="Motorcycles" | ||
/> | ||
<CategoryInfo | ||
icon={CircleDollarSign} | ||
category="Category E" | ||
description="Open Category" | ||
canFilter={false} | ||
/> | ||
</CardContent> | ||
</Card> | ||
); | ||
}; |
Oops, something went wrong.