Install Package
Add Area Variant Component
Add components/area-variant.tsx
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
| import { format } from "date-fns"; import { Tooltip, XAxis, AreaChart, Area, ResponsiveContainer, CartesianGrid } from "recharts"; import { CustomTooltip } from "./custom-tooltips";
type Props = { data: { date: string; income: number; expenses: number; }[]; };
export const AreaVariant = ( {data}: Props ) => { return ( <ResponsiveContainer width="100%" height={350}> <AreaChart data={ data }> <CartesianGrid strokeDasharray="3 3" /> <defs> <linearGradient id="income" x1="0" y1="0" x2="0" y2="1"> <stop offset="2%" stopColor="#3d82f6" stopOpacity={0.8} /> <stop offset="98%" stopColor="#3d82f6" stopOpacity={0} /> </linearGradient> <linearGradient id="expenses" x1="0" y1="0" x2="0" y2="1"> <stop offset="2%" stopColor="#f43f5e" stopOpacity={0.8} /> <stop offset="98%" stopColor="#f43f5e" stopOpacity={0} /> </linearGradient> </defs> <XAxis axisLine={false} tickLine={false} dataKey="date" tickFormatter={(value) => format(value,"dd MMM")} style={{fontSize: "12px" }} tickMargin={16} /> <Tooltip content={<CustomTooltip />}/> <Area type="monotone" dataKey="income" stackId="income" strokeWidth={2} stroke="#3d82f6" fill="url(#income)" className="drop-shadow-sm" /> <Area type="monotone" dataKey="expenses" stackId="expenses" strokeWidth={2} stroke="#f43f5e" fill="url(#expenses)" className="drop-shadow-sm" /> </AreaChart> </ResponsiveContainer> ) }
|
Add Line Variant Component
Add components/line-variant.tsx
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| import { format } from "date-fns"; import { Tooltip, XAxis, ResponsiveContainer, LineChart, Line, CartesianGrid } from "recharts"; import { CustomTooltip } from "./custom-tooltips";
type Props = { data: { date: string; income: number; expenses: number; }[]; };
export const LineVariant = ( {data}: Props ) => { return ( <ResponsiveContainer width="100%" height={350}> <LineChart data={ data }> <CartesianGrid strokeDasharray="3 3" /> <XAxis axisLine={false} tickLine={false} dataKey="date" tickFormatter={(value) => format(value,"dd MMM")} style={{fontSize: "12px" }} tickMargin={16} /> <Tooltip content={<CustomTooltip />}/> <Line dot={false} dataKey="income" stroke="#3d82f6" strokeWidth={2} className="drop-shadow-sm" /> <Line dot={false} dataKey="expenses" stroke="#f43f5e" strokeWidth={2} className="drop-shadow-sm" /> </LineChart> </ResponsiveContainer> ) }
|
Add Bar Variant Component
Add components/bar-variant.tsx
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| import { format } from "date-fns"; import { Tooltip, XAxis, ResponsiveContainer, BarChart, Bar, CartesianGrid } from "recharts"; import { CustomTooltip } from "./custom-tooltips";
type Props = { data: { date: string; income: number; expenses: number; }[]; };
export const BarVariant = ( {data}: Props ) => { return ( <ResponsiveContainer width="100%" height={350}> <BarChart data={ data }> <CartesianGrid strokeDasharray="3 3" /> <XAxis axisLine={false} tickLine={false} dataKey="date" tickFormatter={(value) => format(value,"dd MMM")} style={{fontSize: "12px" }} tickMargin={16} /> <Tooltip content={<CustomTooltip />}/> <Bar dataKey="income" fill="#3d82f6" className="drop-shadow-sm" /> <Bar dataKey="expenses" fill="#f43f5e" className="drop-shadow-sm" /> </BarChart> </ResponsiveContainer> ) }
|
Add Chart Component
Add components/chart.tsx
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
| import { useState } from "react"; import { AreaChart, BarChart3, FileSearch, LineChart } from "lucide-react";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"
import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from "@/components/ui/card"; import { AreaVariant } from "./area-variant"; import { BarVariant } from "./bar-variant"; import { LineVariant } from "./line-variant";
type Props = { data?: { date: string; income: number; expenses: number; }[]; };
export const Chart = ( { data = []} : Props) => { const [chartType, setChartType] = useState("area");
const onTypeChange = ( type: string) => { setChartType(type); } return( <Card className="border-none drop-shadow-sm"> <CardHeader className="flex space-y-2 lg:space-y-0 lg:flex-row lg:items-center justify-between"> <CardTitle className="text-xl line-clamp-1"> Transactions </CardTitle> <Select defaultValue={chartType} onValueChange={onTypeChange} > <SelectTrigger className="lg:w-auto h-9 rounded-md px-3"> <SelectValue placeholder="Chart type" /> </SelectTrigger> <SelectContent> <SelectItem value="area"> <div className="flex items-center"> <AreaChart className="size-4 mr-2 shrink-0" /> <p className="line-clamp-1"> Area chart </p> </div> </SelectItem> <SelectItem value="line"> <div className="flex items-center"> <LineChart className="size-4 mr-2 shrink-0" /> <p className="line-clamp-1"> Line chart </p> </div> </SelectItem> <SelectItem value="bar"> <div className="flex items-center"> <BarChart3 className="size-4 mr-2 shrink-0" /> <p className="line-clamp-1"> Bar chart </p> </div> </SelectItem> </SelectContent> </Select> </CardHeader> <CardContent> {data.length === 0 ? ( <div className="felx flex-col gap-y-4 items-center justify-center h-[350px] w-full"> <FileSearch className="size-6 text-muted-foreground" /> <p className="text-muted-foreground text-sm"> No data for this period </p> </div> ) : ( <> { chartType === "line" && <LineVariant data={data} /> } { chartType === "area" && <AreaVariant data={data} /> } { chartType === "bar" && <BarVariant data={data} /> } </> )} </CardContent> </Card> ) }
|
Add Data Chart Component
ADd components/data-charts.tsx
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| "use client";
import { useGetSummary } from "@/features/summary/api/use-get-summary"; import { Chart } from "./chart";
export const DataCharts = () => { const { data, isLoading} = useGetSummary();
if( isLoading) { return( <div> Loading... </div> ) }
return( <div className="grid grid-cols-1 lg:grid-cols-6 gap-8"> <div className="col-span-1 lg:col-span-5 xl:col-span-6"> <Chart data={data?.days} /> </div> </div> ); }
|
Modify Summary Page
Modify app/(dashboard)/page.tsx
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| "use client";
import { DataCharts } from "@/components/data-charts"; import { DataGrid } from "@/components/data-grid";
export default function DashboardPage() {
return ( <div className="max-w-screen-2xl mx-auto w-full pb-10 -mt-24"> <DataGrid /> <DataCharts /> </div> ); }
|
Add components/custom-tooltips.tsx
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| import { format } from "date-fns"; import { Separator } from "./ui/separator"; import { formatCurrency } from "@/lib/utils";
export const CustomTooltip = ( { active, payload } : any ) => { if (!active) return null;
const date = payload[0].payload.date; const income = payload[0].value; const expenses = payload[1].value;
return( <div className="rounded-sm bg-white shadow-sm border overflow-hidden"> <div className="text-sm p-2 px-3 bg-muted text-muted-foreground"> {format(date, "MMMM dd,yyyy")} </div> <Separator /> <div className="p-2 px-3 space-y-1"> <div className="flex items-center justify-between gap-x-4"> <div className="flex items-center gap-x-2"> <div className="size-1.5 bg-blue-500 rounded-full" /> <p className="text-sm text-muted-foreground"> Income </p> </div> <p className="text-sm text-right font-medium"> {formatCurrency(income)} </p> </div> <div className="flex items-center justify-between gap-x-4"> <div className="flex items-center gap-x-2"> <div className="size-1.5 bg-rose-500 rounded-full" /> <p className="text-sm text-muted-foreground"> Expenses </p> </div> <p className="text-sm text-right font-medium"> {formatCurrency(expenses * -1)} </p> </div> </div> </div> ) }
|