Skip to content

Instantly share code, notes, and snippets.

@shricodev
Created March 30, 2026 16:12
Show Gist options
  • Select an option

  • Save shricodev/ec49249394524a94139a5af16250f2df to your computer and use it in GitHub Desktop.

Select an option

Save shricodev/ec49249394524a94139a5af16250f2df to your computer and use it in GitHub Desktop.
Admin Dashboard - Opus 4.6 (First)
From 9856811178f74c8bcec2132f0014b6e67f20da52 Mon Sep 17 00:00:00 2001
From: Shrijal Acharya <shrijal.acharya@gmail.com>
Date: Sat, 28 Mar 2026 18:46:10 +0545
Subject: [PATCH 1/2] opus 1`
---
src/app/dashboard/overview/layout.tsx | 211 +++++++++---------
.../overview/components/area-graph.tsx | 130 +++++------
.../overview/components/bar-graph.tsx | 150 ++++---------
.../overview/components/pie-graph.tsx | 146 ++++++------
.../overview/components/recent-sales.tsx | 114 +++++-----
.../overview/components/review-cards.tsx | 91 ++++++++
6 files changed, 420 insertions(+), 422 deletions(-)
create mode 100644 src/features/overview/components/review-cards.tsx
diff --git a/src/app/dashboard/overview/layout.tsx b/src/app/dashboard/overview/layout.tsx
index 0d6393d..91fab5b 100644
--- a/src/app/dashboard/overview/layout.tsx
+++ b/src/app/dashboard/overview/layout.tsx
@@ -1,15 +1,53 @@
import PageContainer from '@/components/layout/page-container';
-import { Badge } from '@/components/ui/badge';
-import {
- Card,
- CardHeader,
- CardTitle,
- CardDescription,
- CardAction,
- CardFooter
-} from '@/components/ui/card';
+import { Button } from '@/components/ui/button';
+import { Card, CardContent } from '@/components/ui/card';
import { Icons } from '@/components/icons';
+import { ReviewCards } from '@/features/overview/components/review-cards';
import React from 'react';
+import { cn } from '@/lib/utils';
+
+const statCards = [
+ {
+ label: 'Total Orders',
+ value: '1,840',
+ trend: '+4%',
+ trendUp: true,
+ period: '30 days',
+ icon: 'forms' as const,
+ iconBg: 'bg-blue-100 dark:bg-blue-900/30',
+ iconColor: 'text-blue-600 dark:text-blue-400'
+ },
+ {
+ label: 'Total Delivered',
+ value: '1,622',
+ trend: '+6%',
+ trendUp: true,
+ period: '30 days',
+ icon: 'circleCheck' as const,
+ iconBg: 'bg-green-100 dark:bg-green-900/30',
+ iconColor: 'text-green-600 dark:text-green-400'
+ },
+ {
+ label: 'Total Canceled',
+ value: '218',
+ trend: '+25%',
+ trendUp: false,
+ period: '30 days',
+ icon: 'circleX' as const,
+ iconBg: 'bg-red-100 dark:bg-red-900/30',
+ iconColor: 'text-red-600 dark:text-red-400'
+ },
+ {
+ label: 'Total Revenue',
+ value: '$84,250',
+ trend: '+12%',
+ trendUp: true,
+ period: '30 days',
+ icon: 'creditCard' as const,
+ iconBg: 'bg-purple-100 dark:bg-purple-900/30',
+ iconColor: 'text-purple-600 dark:text-purple-400'
+ }
+];
export default function OverViewLayout({
sales,
@@ -23,103 +61,72 @@ export default function OverViewLayout({
area_stats: React.ReactNode;
}) {
return (
- <PageContainer>
- <div className='flex flex-1 flex-col space-y-2'>
- <div className='flex items-center justify-between'>
- <h2 className='text-2xl font-bold tracking-tight'>Hi, Welcome back 👋</h2>
+ <PageContainer
+ pageTitle='Dashboard'
+ pageDescription='Hi, Welcome back to Admin!'
+ pageHeaderAction={
+ <Button variant='outline' className='gap-2'>
+ <Icons.calendar className='h-4 w-4' />
+ <span className='hidden sm:inline'>Filter Period</span>
+ <Icons.chevronDown className='h-4 w-4' />
+ </Button>
+ }
+ >
+ <div className='flex flex-1 flex-col gap-4'>
+ {/* Stat Cards */}
+ <div className='grid grid-cols-1 gap-4 sm:grid-cols-2 xl:grid-cols-4'>
+ {statCards.map((stat) => {
+ const Icon = Icons[stat.icon];
+ return (
+ <Card key={stat.label} className='shadow-xs'>
+ <CardContent className='flex items-center gap-4 p-6'>
+ <div
+ className={cn(
+ 'flex h-16 w-16 shrink-0 items-center justify-center rounded-full',
+ stat.iconBg
+ )}
+ >
+ <Icon className={cn('h-7 w-7', stat.iconColor)} />
+ </div>
+ <div>
+ <div className='text-3xl font-bold tabular-nums'>{stat.value}</div>
+ <div className='text-muted-foreground text-sm'>{stat.label}</div>
+ <div
+ className={cn(
+ 'mt-1 flex items-center gap-1 text-xs font-medium',
+ stat.trendUp
+ ? 'text-green-600 dark:text-green-400'
+ : 'text-red-600 dark:text-red-400'
+ )}
+ >
+ {stat.trendUp ? (
+ <Icons.trendingUp className='h-3 w-3' />
+ ) : (
+ <Icons.trendingDown className='h-3 w-3' />
+ )}
+ {stat.trend} ({stat.period})
+ </div>
+ </div>
+ </CardContent>
+ </Card>
+ );
+ })}
</div>
- <div className='*:data-[slot=card]:from-primary/5 *:data-[slot=card]:to-card dark:*:data-[slot=card]:bg-card grid grid-cols-1 gap-4 *:data-[slot=card]:bg-gradient-to-t *:data-[slot=card]:shadow-xs md:grid-cols-2 lg:grid-cols-4'>
- <Card className='@container/card'>
- <CardHeader>
- <CardDescription>Total Revenue</CardDescription>
- <CardTitle className='text-2xl font-semibold tabular-nums @[250px]/card:text-3xl'>
- $1,250.00
- </CardTitle>
- <CardAction>
- <Badge variant='outline'>
- <Icons.trendingUp />
- +12.5%
- </Badge>
- </CardAction>
- </CardHeader>
- <CardFooter className='flex-col items-start gap-1.5 text-sm'>
- <div className='line-clamp-1 flex gap-2 font-medium'>
- Trending up this month <Icons.trendingUp className='size-4' />
- </div>
- <div className='text-muted-foreground'>Visitors for the last 6 months</div>
- </CardFooter>
- </Card>
- <Card className='@container/card'>
- <CardHeader>
- <CardDescription>New Customers</CardDescription>
- <CardTitle className='text-2xl font-semibold tabular-nums @[250px]/card:text-3xl'>
- 1,234
- </CardTitle>
- <CardAction>
- <Badge variant='outline'>
- <Icons.trendingDown />
- -20%
- </Badge>
- </CardAction>
- </CardHeader>
- <CardFooter className='flex-col items-start gap-1.5 text-sm'>
- <div className='line-clamp-1 flex gap-2 font-medium'>
- Down 20% this period <Icons.trendingDown className='size-4' />
- </div>
- <div className='text-muted-foreground'>Acquisition needs attention</div>
- </CardFooter>
- </Card>
- <Card className='@container/card'>
- <CardHeader>
- <CardDescription>Active Accounts</CardDescription>
- <CardTitle className='text-2xl font-semibold tabular-nums @[250px]/card:text-3xl'>
- 45,678
- </CardTitle>
- <CardAction>
- <Badge variant='outline'>
- <Icons.trendingUp />
- +12.5%
- </Badge>
- </CardAction>
- </CardHeader>
- <CardFooter className='flex-col items-start gap-1.5 text-sm'>
- <div className='line-clamp-1 flex gap-2 font-medium'>
- Strong user retention <Icons.trendingUp className='size-4' />
- </div>
- <div className='text-muted-foreground'>Engagement exceed targets</div>
- </CardFooter>
- </Card>
- <Card className='@container/card'>
- <CardHeader>
- <CardDescription>Growth Rate</CardDescription>
- <CardTitle className='text-2xl font-semibold tabular-nums @[250px]/card:text-3xl'>
- 4.5%
- </CardTitle>
- <CardAction>
- <Badge variant='outline'>
- <Icons.trendingUp />
- +4.5%
- </Badge>
- </CardAction>
- </CardHeader>
- <CardFooter className='flex-col items-start gap-1.5 text-sm'>
- <div className='line-clamp-1 flex gap-2 font-medium'>
- Steady performance increase <Icons.trendingUp className='size-4' />
- </div>
- <div className='text-muted-foreground'>Meets growth projections</div>
- </CardFooter>
- </Card>
+ {/* Row 2: Metrics gauges (left) + Chart Order (right) */}
+ <div className='grid grid-cols-1 gap-4 lg:grid-cols-7'>
+ <div className='lg:col-span-4'>{pie_stats}</div>
+ <div className='lg:col-span-3'>{bar_stats}</div>
</div>
- <div className='grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-7'>
- <div className='col-span-4'>{bar_stats}</div>
- <div className='col-span-4 md:col-span-3'>
- {/* sales arallel routes */}
- {sales}
- </div>
- <div className='col-span-4'>{area_stats}</div>
- <div className='col-span-4 min-h-0 md:col-span-3'>{pie_stats}</div>
+
+ {/* Row 3: Total Revenue chart (left) + Customer Map (right) */}
+ <div className='grid grid-cols-1 gap-4 lg:grid-cols-7'>
+ <div className='lg:col-span-4'>{area_stats}</div>
+ <div className='lg:col-span-3'>{sales}</div>
</div>
+
+ {/* Row 4: Recent Reviews */}
+ <ReviewCards />
</div>
</PageContainer>
);
diff --git a/src/features/overview/components/area-graph.tsx b/src/features/overview/components/area-graph.tsx
index ea75fd8..81ae8d6 100644
--- a/src/features/overview/components/area-graph.tsx
+++ b/src/features/overview/components/area-graph.tsx
@@ -1,40 +1,37 @@
'use client';
-import { Area, AreaChart, CartesianGrid, XAxis } from 'recharts';
+import { Area, AreaChart, CartesianGrid, XAxis, YAxis } from 'recharts';
-import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
+import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import {
ChartConfig,
ChartContainer,
ChartTooltip,
ChartTooltipContent
} from '@/components/ui/chart';
-import { Badge } from '@/components/ui/badge';
-import { Icons } from '@/components/icons';
-import React from 'react';
const chartData = [
- { month: 'January', desktop: 342, mobile: 245 },
- { month: 'February', desktop: 876, mobile: 654 },
- { month: 'March', desktop: 512, mobile: 387 },
- { month: 'April', desktop: 629, mobile: 521 },
- { month: 'May', desktop: 458, mobile: 412 },
- { month: 'June', desktop: 781, mobile: 598 },
- { month: 'July', desktop: 394, mobile: 312 },
- { month: 'August', desktop: 925, mobile: 743 },
- { month: 'September', desktop: 647, mobile: 489 },
- { month: 'October', desktop: 532, mobile: 476 },
- { month: 'November', desktop: 803, mobile: 687 },
- { month: 'December', desktop: 271, mobile: 198 }
+ { month: 'Jan', current: 15000, previous: 10000 },
+ { month: 'Feb', current: 22000, previous: 18000 },
+ { month: 'Mar', current: 18000, previous: 20000 },
+ { month: 'Apr', current: 25000, previous: 15000 },
+ { month: 'May', current: 38753, previous: 22000 },
+ { month: 'Jun', current: 30000, previous: 28000 },
+ { month: 'Jul', current: 28000, previous: 25000 },
+ { month: 'Aug', current: 35000, previous: 20000 },
+ { month: 'Sep', current: 32000, previous: 18000 },
+ { month: 'Oct', current: 12657, previous: 30000 },
+ { month: 'Nov', current: 27000, previous: 35000 },
+ { month: 'Dec', current: 22000, previous: 32000 }
];
const chartConfig = {
- desktop: {
- label: 'Desktop',
+ current: {
+ label: '2025',
color: 'var(--chart-1)'
},
- mobile: {
- label: 'Mobile',
+ previous: {
+ label: '2024',
color: 'var(--chart-2)'
}
} satisfies ChartConfig;
@@ -42,48 +39,52 @@ const chartConfig = {
export function AreaGraph() {
return (
<Card>
- <CardHeader>
- <CardTitle>
- Dotted Area Chart
- <Badge variant='outline'>
- <Icons.trendingUp />
- -5.2%
- </Badge>
- </CardTitle>
- <CardDescription>Showing total visitors for the last 6 months</CardDescription>
+ <CardHeader className='flex-row items-center justify-between pb-4'>
+ <CardTitle>Total Revenue</CardTitle>
+ <div className='flex items-center gap-4 text-sm'>
+ <div className='flex items-center gap-1.5'>
+ <span
+ className='inline-block h-3 w-3 rounded-full'
+ style={{ background: 'var(--chart-1)' }}
+ />
+ <span className='text-muted-foreground'>2025</span>
+ </div>
+ <div className='flex items-center gap-1.5'>
+ <span
+ className='inline-block h-3 w-3 rounded-full'
+ style={{ background: 'var(--chart-2)' }}
+ />
+ <span className='text-muted-foreground'>2024</span>
+ </div>
+ </div>
</CardHeader>
<CardContent>
- <ChartContainer config={chartConfig}>
- <AreaChart accessibilityLayer data={chartData}>
- <CartesianGrid vertical={false} strokeDasharray='3 3' />
- <XAxis
- dataKey='month'
+ <ChartContainer config={chartConfig} className='h-[240px] w-full'>
+ <AreaChart data={chartData} margin={{ top: 10, right: 10, left: 0, bottom: 0 }}>
+ <CartesianGrid vertical={false} strokeDasharray='3 3' opacity={0.3} />
+ <XAxis dataKey='month' tickLine={false} axisLine={false} tickMargin={8} />
+ <YAxis
tickLine={false}
axisLine={false}
- tickMargin={8}
- tickFormatter={(value) => value.slice(0, 3)}
+ tickFormatter={(v) => `$${(v / 1000).toFixed(0)}k`}
+ width={44}
/>
- <ChartTooltip cursor={false} content={<ChartTooltipContent />} />
- <defs>
- <DottedBackgroundPattern config={chartConfig} />
- </defs>
+ <ChartTooltip content={<ChartTooltipContent />} />
<Area
- dataKey='mobile'
+ dataKey='current'
type='natural'
- fill='url(#dotted-background-pattern-mobile)'
- fillOpacity={0.4}
- stroke='var(--color-mobile)'
- stackId='a'
- strokeWidth={0.8}
+ fill='var(--color-current)'
+ fillOpacity={0.15}
+ stroke='var(--color-current)'
+ strokeWidth={2}
/>
<Area
- dataKey='desktop'
+ dataKey='previous'
type='natural'
- fill='url(#dotted-background-pattern-desktop)'
- fillOpacity={0.4}
- stroke='var(--color-desktop)'
- stackId='a'
- strokeWidth={0.8}
+ fill='var(--color-previous)'
+ fillOpacity={0.15}
+ stroke='var(--color-previous)'
+ strokeWidth={2}
/>
</AreaChart>
</ChartContainer>
@@ -91,26 +92,3 @@ export function AreaGraph() {
</Card>
);
}
-
-const DottedBackgroundPattern = ({ config }: { config: ChartConfig }) => {
- const items = Object.fromEntries(
- Object.entries(config).map(([key, value]) => [key, value.color])
- );
- return (
- <>
- {Object.entries(items).map(([key, value]) => (
- <pattern
- key={key}
- id={`dotted-background-pattern-${key}`}
- x='0'
- y='0'
- width='7'
- height='7'
- patternUnits='userSpaceOnUse'
- >
- <circle cx='5' cy='5' r='1.5' fill={value} opacity={0.5}></circle>
- </pattern>
- ))}
- </>
- );
-};
diff --git a/src/features/overview/components/bar-graph.tsx b/src/features/overview/components/bar-graph.tsx
index b961c73..c3c2be6 100644
--- a/src/features/overview/components/bar-graph.tsx
+++ b/src/features/overview/components/bar-graph.tsx
@@ -1,7 +1,8 @@
'use client';
-import { Bar, BarChart, XAxis } from 'recharts';
+import { Area, AreaChart, XAxis } from 'recharts';
+import { Button } from '@/components/ui/button';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
import {
ChartConfig,
@@ -9,136 +10,61 @@ import {
ChartTooltip,
ChartTooltipContent
} from '@/components/ui/chart';
-import { Badge } from '@/components/ui/badge';
import { Icons } from '@/components/icons';
const chartData = [
- { month: 'January', desktop: 186, mobile: 80 },
- { month: 'February', desktop: 305, mobile: 200 },
- { month: 'March', desktop: 237, mobile: 120 },
- { month: 'April', desktop: 73, mobile: 190 },
- { month: 'May', desktop: 209, mobile: 130 },
- { month: 'June', desktop: 214, mobile: 140 }
+ { day: 'Sun', orders: 280 },
+ { day: 'Mon', orders: 350 },
+ { day: 'Tue', orders: 420 },
+ { day: 'Wed', orders: 380 },
+ { day: 'Thu', orders: 456 },
+ { day: 'Fri', orders: 390 },
+ { day: 'Sat', orders: 320 }
];
const chartConfig = {
- desktop: {
- label: 'Desktop',
+ orders: {
+ label: 'Orders',
color: 'var(--chart-1)'
- },
- mobile: {
- label: 'Mobile',
- color: 'var(--chart-2)'
}
} satisfies ChartConfig;
export function BarGraph() {
return (
- <Card>
- <CardHeader>
- <CardTitle>
- Bar Chart - Multiple
- <Badge variant='outline'>
- <Icons.trendingDown />
- -5.2%
- </Badge>
- </CardTitle>
- <CardDescription>January - June 2025</CardDescription>
+ <Card className='h-full'>
+ <CardHeader className='flex-row items-start justify-between pb-2'>
+ <div>
+ <CardTitle>Chart Order</CardTitle>
+ <CardDescription>Weekly order activity</CardDescription>
+ </div>
+ <Button variant='outline' size='sm' className='gap-1.5 shrink-0'>
+ <Icons.upload className='h-4 w-4' />
+ Save Report
+ </Button>
</CardHeader>
<CardContent>
- <ChartContainer config={chartConfig}>
- <BarChart accessibilityLayer data={chartData}>
- <rect
- x='0'
- y='0'
- width='100%'
- height='85%'
- fill='url(#default-multiple-pattern-dots)'
- />
+ <ChartContainer config={chartConfig} className='h-[220px] w-full'>
+ <AreaChart data={chartData} margin={{ top: 10, right: 10, left: -20, bottom: 0 }}>
<defs>
- <DottedBackgroundPattern />
+ <linearGradient id='orderGradient' x1='0' y1='0' x2='0' y2='1'>
+ <stop offset='5%' stopColor='var(--chart-1)' stopOpacity={0.3} />
+ <stop offset='95%' stopColor='var(--chart-1)' stopOpacity={0} />
+ </linearGradient>
</defs>
- <XAxis
- dataKey='month'
- tickLine={false}
- tickMargin={10}
- axisLine={false}
- tickFormatter={(value) => value.slice(0, 3)}
- />
- <ChartTooltip
- cursor={false}
- content={<ChartTooltipContent indicator='dashed' hideLabel />}
- />
- <Bar
- dataKey='desktop'
- color='var(--chart-1)'
- fill='var(--color-desktop)'
- shape={<CustomHatchedBar isHatched={false} />}
- radius={4}
+ <XAxis dataKey='day' tickLine={false} axisLine={false} tickMargin={8} />
+ <ChartTooltip cursor={false} content={<ChartTooltipContent />} />
+ <Area
+ dataKey='orders'
+ type='natural'
+ fill='url(#orderGradient)'
+ stroke='var(--color-orders)'
+ strokeWidth={2}
+ dot={{ r: 4, fill: 'var(--color-orders)', strokeWidth: 0 }}
+ activeDot={{ r: 6 }}
/>
- <Bar
- dataKey='mobile'
- fill='var(--color-mobile)'
- shape={<CustomHatchedBar />}
- radius={4}
- />
- </BarChart>
+ </AreaChart>
</ChartContainer>
</CardContent>
</Card>
);
}
-
-const CustomHatchedBar = (
- props: React.SVGProps<SVGRectElement> & {
- dataKey?: string;
- isHatched?: boolean;
- }
-) => {
- const { fill, x, y, width, height, dataKey } = props;
-
- const isHatched = props.isHatched ?? true;
-
- return (
- <>
- <rect
- rx={4}
- x={x}
- y={y}
- width={width}
- height={height}
- stroke='none'
- fill={isHatched ? `url(#hatched-bar-pattern-${dataKey})` : fill}
- />
- <defs>
- <pattern
- key={dataKey}
- id={`hatched-bar-pattern-${dataKey}`}
- x='0'
- y='0'
- width='5'
- height='5'
- patternUnits='userSpaceOnUse'
- patternTransform='rotate(-45)'
- >
- <rect width='10' height='10' opacity={0.5} fill={fill}></rect>
- <rect width='1' height='10' fill={fill}></rect>
- </pattern>
- </defs>
- </>
- );
-};
-const DottedBackgroundPattern = () => {
- return (
- <pattern
- id='default-multiple-pattern-dots'
- x='0'
- y='0'
- width='10'
- height='10'
- patternUnits='userSpaceOnUse'
- >
- <circle className='dark:text-muted/40 text-muted' cx='2' cy='2' r='1' fill='currentColor' />
- </pattern>
- );
-};
diff --git a/src/features/overview/components/pie-graph.tsx b/src/features/overview/components/pie-graph.tsx
index b28e5ea..41a4b1f 100644
--- a/src/features/overview/components/pie-graph.tsx
+++ b/src/features/overview/components/pie-graph.tsx
@@ -1,90 +1,82 @@
'use client';
-import { LabelList, Pie, PieChart } from 'recharts';
+import { Label, Pie, PieChart } from 'recharts';
-import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
-import {
- ChartConfig,
- ChartContainer,
- ChartTooltip,
- ChartTooltipContent
-} from '@/components/ui/chart';
-import { Badge } from '@/components/ui/badge';
-import { Icons } from '@/components/icons';
+import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
+import { ChartConfig, ChartContainer } from '@/components/ui/chart';
-const chartData = [
- { browser: 'chrome', visitors: 275, fill: 'var(--color-chrome)' },
- { browser: 'safari', visitors: 200, fill: 'var(--color-safari)' },
- { browser: 'firefox', visitors: 187, fill: 'var(--color-firefox)' },
- { browser: 'edge', visitors: 173, fill: 'var(--color-edge)' },
- { browser: 'other', visitors: 90, fill: 'var(--color-other)' }
-];
+const emptyConfig = {} satisfies ChartConfig;
-const chartConfig = {
- visitors: {
- label: 'Visitors'
- },
- chrome: {
- label: 'Chrome',
- color: 'var(--chart-1)'
- },
- safari: {
- label: 'Safari',
- color: 'var(--chart-2)'
- },
- firefox: {
- label: 'Firefox',
- color: 'var(--chart-3)'
- },
- edge: {
- label: 'Edge',
- color: 'var(--chart-4)'
- },
- other: {
- label: 'Other',
- color: 'var(--chart-5)'
- }
-} satisfies ChartConfig;
+interface DonutGaugeProps {
+ value: number;
+ label: string;
+ color: string;
+}
+
+function DonutGauge({ value, label, color }: DonutGaugeProps) {
+ const data = [
+ { name: 'filled', value, fill: color },
+ { name: 'empty', value: 100 - value, fill: 'var(--muted)' }
+ ];
+
+ return (
+ <div className='flex flex-col items-center gap-2'>
+ <ChartContainer config={emptyConfig} className='h-[148px] w-[148px]'>
+ <PieChart>
+ <Pie
+ data={data}
+ cx='50%'
+ cy='50%'
+ innerRadius={48}
+ outerRadius={66}
+ startAngle={90}
+ endAngle={-270}
+ dataKey='value'
+ strokeWidth={0}
+ cornerRadius={4}
+ >
+ <Label
+ content={({ viewBox }) => {
+ if (viewBox && 'cx' in viewBox && 'cy' in viewBox) {
+ return (
+ <text
+ x={viewBox.cx}
+ y={viewBox.cy}
+ textAnchor='middle'
+ dominantBaseline='middle'
+ >
+ <tspan
+ x={viewBox.cx}
+ y={viewBox.cy}
+ className='fill-foreground'
+ fontSize={20}
+ fontWeight={700}
+ >
+ {value}%
+ </tspan>
+ </text>
+ );
+ }
+ }}
+ />
+ </Pie>
+ </PieChart>
+ </ChartContainer>
+ <span className='text-muted-foreground text-sm font-medium'>{label}</span>
+ </div>
+ );
+}
export function PieGraph() {
return (
<Card className='flex h-full flex-col'>
- <CardHeader className='items-center pb-0'>
- <CardTitle>
- Pie Chart
- <Badge variant='outline'>
- <Icons.trendingUp />
- +5.2%
- </Badge>
- </CardTitle>
- <CardDescription>January - June 2024</CardDescription>
+ <CardHeader className='pb-2'>
+ <CardTitle>Metrics Overview</CardTitle>
</CardHeader>
- <CardContent className='flex flex-1 items-center justify-center pb-0'>
- <ChartContainer
- config={chartConfig}
- className='[&_.recharts-text]:fill-background mx-auto aspect-square max-h-[300px] min-h-[250px]'
- >
- <PieChart>
- <ChartTooltip content={<ChartTooltipContent nameKey='visitors' hideLabel />} />
- <Pie
- data={chartData}
- innerRadius={30}
- dataKey='visitors'
- radius={10}
- cornerRadius={8}
- paddingAngle={4}
- >
- <LabelList
- dataKey='visitors'
- stroke='none'
- fontSize={12}
- fontWeight={500}
- fill='currentColor'
- formatter={(value: number) => value.toString()}
- />
- </Pie>
- </PieChart>
- </ChartContainer>
+ <CardContent className='flex flex-1 items-center justify-around gap-4 py-4'>
+ <DonutGauge value={81} label='Total Orders' color='var(--chart-1)' />
+ <DonutGauge value={22} label='Customer Growth' color='var(--chart-3)' />
+ <DonutGauge value={62} label='Total Revenue' color='var(--chart-2)' />
</CardContent>
</Card>
);
diff --git a/src/features/overview/components/recent-sales.tsx b/src/features/overview/components/recent-sales.tsx
index 7ceff1f..45f5e9e 100644
--- a/src/features/overview/components/recent-sales.tsx
+++ b/src/features/overview/components/recent-sales.tsx
@@ -1,67 +1,71 @@
-import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
-import { Card, CardHeader, CardContent, CardTitle, CardDescription } from '@/components/ui/card';
+'use client';
-const salesData = [
- {
- name: 'Olivia Martin',
- email: 'olivia.martin@email.com',
- avatar: 'https://api.slingacademy.com/public/sample-users/1.png',
- fallback: 'OM',
- amount: '+$1,999.00'
- },
- {
- name: 'Jackson Lee',
- email: 'jackson.lee@email.com',
- avatar: 'https://api.slingacademy.com/public/sample-users/2.png',
- fallback: 'JL',
- amount: '+$39.00'
- },
- {
- name: 'Isabella Nguyen',
- email: 'isabella.nguyen@email.com',
- avatar: 'https://api.slingacademy.com/public/sample-users/3.png',
- fallback: 'IN',
- amount: '+$299.00'
- },
- {
- name: 'William Kim',
- email: 'will@email.com',
- avatar: 'https://api.slingacademy.com/public/sample-users/4.png',
- fallback: 'WK',
- amount: '+$99.00'
+import { Bar, BarChart, XAxis, YAxis } from 'recharts';
+
+import { Button } from '@/components/ui/button';
+import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
+import {
+ ChartConfig,
+ ChartContainer,
+ ChartTooltip,
+ ChartTooltipContent
+} from '@/components/ui/chart';
+
+const chartData = [
+ { day: 'Sun', returning: 45, newVisitors: 30 },
+ { day: 'Mon', returning: 80, newVisitors: 60 },
+ { day: 'Tue', returning: 60, newVisitors: 50 },
+ { day: 'Wed', returning: 75, newVisitors: 65 },
+ { day: 'Thu', returning: 55, newVisitors: 40 },
+ { day: 'Fri', returning: 30, newVisitors: 20 },
+ { day: 'Sat', returning: 50, newVisitors: 45 }
+];
+
+const chartConfig = {
+ returning: {
+ label: 'Returning',
+ color: 'var(--chart-3)'
},
- {
- name: 'Sofia Davis',
- email: 'sofia.davis@email.com',
- avatar: 'https://api.slingacademy.com/public/sample-users/5.png',
- fallback: 'SD',
- amount: '+$39.00'
+ newVisitors: {
+ label: 'New',
+ color: 'var(--chart-5)'
}
-];
+} satisfies ChartConfig;
export function RecentSales() {
return (
<Card className='h-full'>
- <CardHeader>
- <CardTitle>Recent Sales</CardTitle>
- <CardDescription>You made 265 sales this month.</CardDescription>
+ <CardHeader className='flex-row items-center justify-between pb-2'>
+ <CardTitle>Customer Map</CardTitle>
+ <Button variant='outline' size='sm' className='gap-1'>
+ Weekly
+ </Button>
</CardHeader>
<CardContent>
- <div className='space-y-8'>
- {salesData.map((sale, index) => (
- <div key={index} className='flex items-center'>
- <Avatar className='h-9 w-9'>
- <AvatarImage src={sale.avatar} alt='Avatar' />
- <AvatarFallback>{sale.fallback}</AvatarFallback>
- </Avatar>
- <div className='ml-4 space-y-1'>
- <p className='text-sm leading-none font-medium'>{sale.name}</p>
- <p className='text-muted-foreground text-sm'>{sale.email}</p>
- </div>
- <div className='ml-auto font-medium'>{sale.amount}</div>
- </div>
- ))}
- </div>
+ <ChartContainer config={chartConfig} className='h-[220px] w-full'>
+ <BarChart
+ data={chartData}
+ barGap={2}
+ barCategoryGap='30%'
+ margin={{ top: 10, right: 10, left: -20, bottom: 0 }}
+ >
+ <XAxis dataKey='day' tickLine={false} axisLine={false} tickMargin={8} />
+ <YAxis tickLine={false} axisLine={false} width={35} />
+ <ChartTooltip content={<ChartTooltipContent />} />
+ <Bar
+ dataKey='returning'
+ fill='var(--color-returning)'
+ radius={[4, 4, 0, 0]}
+ maxBarSize={14}
+ />
+ <Bar
+ dataKey='newVisitors'
+ fill='var(--color-newVisitors)'
+ radius={[4, 4, 0, 0]}
+ maxBarSize={14}
+ />
+ </BarChart>
+ </ChartContainer>
</CardContent>
</Card>
);
diff --git a/src/features/overview/components/review-cards.tsx b/src/features/overview/components/review-cards.tsx
new file mode 100644
index 0000000..246c475
--- /dev/null
+++ b/src/features/overview/components/review-cards.tsx
@@ -0,0 +1,91 @@
+import { Avatar, AvatarFallback } from '@/components/ui/avatar';
+import { Button } from '@/components/ui/button';
+import { Card, CardContent } from '@/components/ui/card';
+import { Icons } from '@/components/icons';
+
+const reviews = [
+ {
+ name: 'Alex Johnson',
+ initials: 'AJ',
+ timeAgo: '2 days ago',
+ rating: 4.5,
+ text: 'The platform has significantly improved our workflow. Easy to navigate and the reporting tools are excellent for tracking performance metrics across all departments.'
+ },
+ {
+ name: 'Maria Rodriguez',
+ initials: 'MR',
+ timeAgo: '3 days ago',
+ rating: 4.0,
+ text: 'Great experience overall. The dashboard gives real-time insights that help us make better data-driven decisions. The UI is clean and intuitive to use.'
+ },
+ {
+ name: 'Sam Patel',
+ initials: 'SP',
+ timeAgo: '4 days ago',
+ rating: 4.5,
+ text: 'Reliable, intuitive, and packed with features. The analytics section is particularly impressive and saves our team hours every week without any setup overhead.'
+ }
+];
+
+function StarRating({ rating }: { rating: number }) {
+ return (
+ <div className='flex items-center gap-1'>
+ {[1, 2, 3, 4, 5].map((star) => (
+ <Icons.exclusive
+ key={star}
+ className={`h-4 w-4 ${
+ star <= Math.floor(rating)
+ ? 'text-yellow-400'
+ : star - 0.5 <= rating
+ ? 'text-yellow-300'
+ : 'text-muted-foreground/30'
+ }`}
+ />
+ ))}
+ <span className='text-muted-foreground ml-1 text-sm font-medium'>{rating}</span>
+ </div>
+ );
+}
+
+export function ReviewCards() {
+ return (
+ <div className='space-y-4'>
+ <div className='flex items-start justify-between'>
+ <div>
+ <h3 className='text-xl font-semibold'>Recent Reviews</h3>
+ <p className='text-muted-foreground text-sm'>What users are saying about the platform</p>
+ </div>
+ <div className='flex gap-2'>
+ <Button variant='outline' size='icon' aria-label='Previous reviews'>
+ <Icons.chevronLeft className='h-4 w-4' />
+ </Button>
+ <Button variant='outline' size='icon' aria-label='Next reviews'>
+ <Icons.chevronRight className='h-4 w-4' />
+ </Button>
+ </div>
+ </div>
+
+ <div className='grid grid-cols-1 gap-4 md:grid-cols-3'>
+ {reviews.map((review) => (
+ <Card key={review.name} className='overflow-hidden'>
+ <CardContent className='p-6'>
+ <div className='mb-4 flex items-center gap-3'>
+ <Avatar className='h-12 w-12'>
+ <AvatarFallback className='text-sm font-semibold'>
+ {review.initials}
+ </AvatarFallback>
+ </Avatar>
+ <div>
+ <p className='font-semibold leading-tight'>{review.name}</p>
+ <p className='text-muted-foreground text-xs'>{review.timeAgo}</p>
+ </div>
+ </div>
+ <p className='text-muted-foreground mb-4 text-sm leading-relaxed'>{review.text}</p>
+ <StarRating rating={review.rating} />
+ </CardContent>
+ </Card>
+ ))}
+ </div>
+ </div>
+ );
+}
--
2.53.0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment