Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: adding charts in dashboard #51

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 94 additions & 0 deletions client/app/private/dashboard/_components/market-feed.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
"use client";

import type { IChartApi, UTCTimestamp } from "lightweight-charts";
import { createChart } from "lightweight-charts";
import { useEffect, useRef } from "react";
import useSWRImmutable from "swr/immutable";

interface KiteTick {
tradable: boolean;
mode: "full" | "ltp" | "quote";
instrument_token: number;
last_price: number;
last_traded_quantity: number;
average_traded_price: number;
volume_traded: number;
total_buy_quantity: number;
total_sell_quantity: number;
ohlc: { open: number; high: number; low: number; close: number };
change: number;
last_trade_time: string; // date;
oi: number;
oi_day_high: number;
oi_day_low: number;
exchange_timestamp: string; // date;
depth: {
buy: Array<{ quantity: number; price: number; order: number }>;
sell: Array<{ quantity: number; price: number; order: number }>;
};
}

interface Tick {
id: string;
timestamp: string; // date;
metadata: {
instrument_token: string;
tradingsymbol: string;
};
data: KiteTick;
received_at: string; // date;
}

interface APITickResponse {
ticks: Tick[];
}

export function MarketFeed() {
const { data, isLoading } = useSWRImmutable("/api/ticks/HDFCBANK", async (url) => {
const res = await fetch(url);
return (await res.json()) as APITickResponse;
});
const containerRef = useRef<HTMLDivElement | null>(null);
const chartRef = useRef<IChartApi | null>(null);

useEffect(() => {
if (!containerRef.current || !data) return;
chartRef.current = createChart(containerRef.current, {
width: containerRef.current.clientWidth,
height: 300,
timeScale: {
timeVisible: true,
},
});
chartRef.current.timeScale().fitContent();

const newSeries = chartRef.current.addLineSeries();
const chartData = data.ticks.map<{ time: UTCTimestamp; value: number }>((tick) => ({
time: (new Date(tick.received_at).getTime() / 1000) as UTCTimestamp,
value: tick.data.last_price,
}));
newSeries.setData(chartData);

return () => {
if (chartRef.current) {
chartRef.current.remove();
}
};
}, [data]);

useEffect(() => {
const handleResize = () => {
if (chartRef.current && containerRef.current) {
chartRef.current.applyOptions({ width: containerRef.current.clientWidth });
}
};
window.addEventListener("resize", handleResize);
return () => {
window.removeEventListener("resize", handleResize);
};
});

// const { data, loading } = useQuery(GET_MARKET_FEED);
console.log({ isLoading, data });
return <div ref={containerRef} />;
}
112 changes: 112 additions & 0 deletions client/app/private/dashboard/_components/overview.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";

export function Overview() {
return (
<div className="space-y-4">
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-4">
<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Total Revenue</CardTitle>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
className="h-4 w-4 text-muted-foreground"
>
<path d="M12 2v20M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6" />
</svg>
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">$45,231.89</div>
<p className="text-xs text-muted-foreground">+20.1% from last month</p>
</CardContent>
</Card>
<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Subscriptions</CardTitle>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
className="h-4 w-4 text-muted-foreground"
>
<path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2" />
<circle cx="9" cy="7" r="4" />
<path d="M22 21v-2a4 4 0 0 0-3-3.87M16 3.13a4 4 0 0 1 0 7.75" />
</svg>
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">+2350</div>
<p className="text-xs text-muted-foreground">+180.1% from last month</p>
</CardContent>
</Card>
<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Sales</CardTitle>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
className="h-4 w-4 text-muted-foreground"
>
<rect width="20" height="14" x="2" y="5" rx="2" />
<path d="M2 10h20" />
</svg>
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">+12,234</div>
<p className="text-xs text-muted-foreground">+19% from last month</p>
</CardContent>
</Card>
<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Active Now</CardTitle>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
className="h-4 w-4 text-muted-foreground"
>
<path d="M22 12h-4l-3 9L9 3l-3 9H2" />
</svg>
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">+573</div>
<p className="text-xs text-muted-foreground">+201 since last hour</p>
</CardContent>
</Card>
</div>
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-7">
<Card className="col-span-4">
<CardHeader>
<CardTitle>Overview</CardTitle>
</CardHeader>
<CardContent className="pl-2"></CardContent>
</Card>
<Card className="col-span-3">
<CardHeader>
<CardTitle>Recent Sales</CardTitle>
<CardDescription>You made 265 sales this month.</CardDescription>
</CardHeader>
<CardContent></CardContent>
</Card>
</div>
</div>
);
}
123 changes: 9 additions & 114 deletions client/app/private/dashboard/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import { PageHeader } from "@/components/page-header";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";

import { MarketFeed } from "./_components/market-feed";
import { Overview } from "./_components/overview";

export const metadata: Metadata = {
title: "Dashboard",
description: "Example dashboard app built using the components.",
Expand All @@ -16,121 +19,13 @@ export default function DashboardPage() {
<Tabs defaultValue="overview" className="space-y-4">
<TabsList>
<TabsTrigger value="overview">Overview</TabsTrigger>
<TabsTrigger value="analytics" disabled>
Analytics
</TabsTrigger>
<TabsTrigger value="reports" disabled>
Reports
</TabsTrigger>
<TabsTrigger value="notifications" disabled>
Notifications
</TabsTrigger>
<TabsTrigger value="market-feed">Market Feed</TabsTrigger>
</TabsList>
<TabsContent value="overview" className="space-y-4">
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-4">
<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Total Revenue</CardTitle>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
className="h-4 w-4 text-muted-foreground"
>
<path d="M12 2v20M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6" />
</svg>
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">$45,231.89</div>
<p className="text-xs text-muted-foreground">+20.1% from last month</p>
</CardContent>
</Card>
<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Subscriptions</CardTitle>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
className="h-4 w-4 text-muted-foreground"
>
<path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2" />
<circle cx="9" cy="7" r="4" />
<path d="M22 21v-2a4 4 0 0 0-3-3.87M16 3.13a4 4 0 0 1 0 7.75" />
</svg>
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">+2350</div>
<p className="text-xs text-muted-foreground">+180.1% from last month</p>
</CardContent>
</Card>
<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Sales</CardTitle>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
className="h-4 w-4 text-muted-foreground"
>
<rect width="20" height="14" x="2" y="5" rx="2" />
<path d="M2 10h20" />
</svg>
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">+12,234</div>
<p className="text-xs text-muted-foreground">+19% from last month</p>
</CardContent>
</Card>
<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Active Now</CardTitle>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
className="h-4 w-4 text-muted-foreground"
>
<path d="M22 12h-4l-3 9L9 3l-3 9H2" />
</svg>
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">+573</div>
<p className="text-xs text-muted-foreground">+201 since last hour</p>
</CardContent>
</Card>
</div>
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-7">
<Card className="col-span-4">
<CardHeader>
<CardTitle>Overview</CardTitle>
</CardHeader>
<CardContent className="pl-2"></CardContent>
</Card>
<Card className="col-span-3">
<CardHeader>
<CardTitle>Recent Sales</CardTitle>
<CardDescription>You made 265 sales this month.</CardDescription>
</CardHeader>
<CardContent></CardContent>
</Card>
</div>
<TabsContent value="overview">
<Overview />
</TabsContent>
<TabsContent value="market-feed">
<MarketFeed />
</TabsContent>
</Tabs>
</>
Expand Down
27 changes: 27 additions & 0 deletions client/components/line-plot.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import * as d3 from "d3";

interface LinePlotProps {
data: number[];
}

export default function LinePlot({ data = [] }: LinePlotProps) {
const width = 640;
const height = 400;
const marginTop = 20;
const marginRight = 20;
const marginBottom = 20;
const marginLeft = 20;
const x = d3.scaleLinear([0, data.length - 1], [marginLeft, width - marginRight]);
const y = d3.scaleLinear(d3.extent(data), [height - marginBottom, marginTop]);
const line = d3.line((d, i) => x(i), y);
return (
<svg width={width} height={height}>
<path fill="none" stroke="currentColor" strokeWidth="1.5" d={line(data)} />
<g fill="white" stroke="currentColor" strokeWidth="1.5">
{data.map((d, i) => (
<circle key={i} cx={x(i)} cy={y(d)} r="2.5" />
))}
</g>
</svg>
);
}
3 changes: 3 additions & 0 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.0",
"cmdk": "^0.2.1",
"d3": "^7.9.0",
"lightweight-charts": "^4.1.3",
"lucide-react": "^0.350.0",
"next": "14.1.1",
"next-themes": "^0.3.0",
Expand All @@ -38,6 +40,7 @@
"zod": "^3.22.4"
},
"devDependencies": {
"@types/d3": "^7.4.3",
"@types/node": "^20",
"@types/react": "^18",
"@types/react-dom": "^18",
Expand Down
Loading