
A dynamic chart tracking revenue trends and performance with interactive cursor details and tooltips.
components/blocks/dashboard/chart/chart-3.tsx
import { useState } from "react";
import {
ArrowDownToLineIcon,
FileJsonIcon,
MoreHorizontalIcon,
RefreshCwIcon,
SettingsIcon,
Share2Icon,
} from "lucide-react";
import { Bar, BarChart, CartesianGrid, XAxis, YAxis } from "recharts";
import { Button } from "@/components/ui/button";
import { Card, CardAction, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { type ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent } from "@/components/ui/chart";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuGroup,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
const generateData = () => {
return Array.from({ length: 20 }, (_, i) => {
const date = new Date();
date.setMonth(date.getMonth() - 1);
date.setDate(date.getDate() + i);
return {
date: date.toISOString().split("T")[0],
item1: Math.floor(Math.random() * 500) + 50,
item2: Math.floor(Math.random() * 500) + 50,
};
});
};
const chartConfig: ChartConfig = {
visitors: {
label: "Visitors",
},
item1: {
label: "Item 1",
color: "var(--chart-2)",
},
item2: {
label: "Item 2",
color: "var(--chart-1)",
},
};
export const Chart3 = () => {
const [chartData, setChartData] = useState(generateData());
const handleRefresh = () => {
setChartData(generateData());
};
return (
<Card className="@container/card max-md:py-4!">
<CardHeader className="max-md:px-4">
<CardTitle>Financial Performance</CardTitle>
<CardDescription>Real-time insights for the last 30 days</CardDescription>
<CardAction className="flex items-center gap-2">
<Button
variant="outline"
size="icon-sm"
className="max-sm:hidden"
aria-label="Refresh"
onClick={handleRefresh}>
<RefreshCwIcon />
</Button>
<Button variant="outline" size="icon-sm" className="max-sm:hidden" aria-label="Download">
<ArrowDownToLineIcon />
</Button>
<DropdownMenu>
<DropdownMenuTrigger
render={
<Button variant="outline" size="icon-sm">
<MoreHorizontalIcon />
<span className="sr-only">Open menu</span>
</Button>
}></DropdownMenuTrigger>
<DropdownMenuContent align="end" className="w-40">
<DropdownMenuGroup>
<DropdownMenuLabel>Options</DropdownMenuLabel>
<DropdownMenuItem>
<SettingsIcon />
<span>Configure</span>
</DropdownMenuItem>
<DropdownMenuItem onClick={handleRefresh}>
<RefreshCwIcon />
<span>Refresh Data</span>
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem>
<ArrowDownToLineIcon />
<span>Export as PNG</span>
</DropdownMenuItem>
<DropdownMenuItem>
<FileJsonIcon />
<span>Export CSV</span>
</DropdownMenuItem>
<DropdownMenuItem>
<Share2Icon />
<span>Share Chart</span>
</DropdownMenuItem>
</DropdownMenuGroup>
</DropdownMenuContent>
</DropdownMenu>
</CardAction>
<div className="mt-4 flex items-center gap-6">
<div className="space-y-1.5">
<p className="text-muted-foreground text-sm font-medium">Revenue</p>
<p className="text-lg leading-none font-semibold sm:text-2xl">$12,345</p>
</div>
<div className="bg-border h-10 w-px"></div>
<div className="space-y-1.5">
<p className="text-muted-foreground text-sm font-medium whitespace-nowrap">Avg. Order</p>
<p className="text-lg leading-none font-semibold sm:text-2xl">$248</p>
</div>
<div className="bg-border h-10 w-px max-sm:hidden"></div>
<div className="space-y-1.5 max-sm:hidden">
<p className="text-muted-foreground text-sm font-medium">Conversion</p>
<p className="text-lg leading-none font-semibold sm:text-2xl">+7.2%</p>
</div>
</div>
</CardHeader>
<CardContent className="px-2 pt-4 sm:px-6 sm:pt-6">
<ChartContainer config={chartConfig} className="aspect-auto h-65 w-full">
<BarChart data={chartData}>
<CartesianGrid vertical={false} />
<XAxis
dataKey="date"
tickLine={false}
axisLine={false}
tickMargin={8}
minTickGap={32}
tickFormatter={(value) => {
const date = new Date(value);
return date.toLocaleDateString("en-US", {
month: "short",
day: "numeric",
});
}}
/>
<YAxis
tickLine={false}
axisLine={false}
tickMargin={4}
width={35}
className="text-sm sm:text-xs"
tickFormatter={(value) => `${value}`}
/>
<ChartTooltip
cursor={false}
content={
<ChartTooltipContent
className="rounded-md shadow-none"
labelFormatter={(value) => {
return new Date(value as any).toLocaleDateString("en-US", {
month: "short",
day: "numeric",
});
}}
indicator="dot"
/>
}
/>
<Bar
dataKey="item1"
stackId="a"
fill="var(--color-item1)"
radius={6}
className="stroke-background"
strokeWidth={3}
/>
<Bar
dataKey="item2"
stackId="a"
fill="var(--color-item2)"
radius={6}
className="stroke-background"
strokeWidth={3}
/>
</BarChart>
</ChartContainer>
</CardContent>
</Card>
);
};