Skip to content

Commit

Permalink
Merge pull request #541 from hngprojects/78-feat-super-admin-dashboar…
Browse files Browse the repository at this point in the history
…d-page

78 feat super admin dashboard page
  • Loading branch information
mrcoded authored Jul 22, 2024
2 parents b74ac3c + 6aeb45b commit 52ed28c
Show file tree
Hide file tree
Showing 15 changed files with 477 additions and 1 deletion.
4 changes: 4 additions & 0 deletions public/icons/arrowUp.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions public/icons/box.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions public/icons/dollarSign.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions public/icons/user.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
52 changes: 52 additions & 0 deletions src/app/(admin)/admin/dashboard/client.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
"use client";

import Link from "next/link";

import CardComponent from "~/components/adminDashboard/CardComponent";
import { cardData } from "~/components/adminDashboard/cardData";
import { Chart } from "~/components/adminDashboard/Chart";
import { chartConfig, chartData } from "~/components/adminDashboard/chartData";
import { data, gradients } from "~/components/adminDashboard/productData";
import TopProductsComponent from "~/components/adminDashboard/TopProductsComponent";
import { Card } from "~/components/ui/card";

const Client = () => {
return (
<section className="px-4 md:p-4 md:pt-0">
<div className="mb-4 md:mb-0">
<div className="flex flex-col items-start justify-start">
<Link href="#" className="pb-[6px]">
<h1 className="text-2xl font-bold text-neutral-600">Overview</h1>
</Link>
<p className="text-base font-normal text-neutral-600">
Showing records from the last .....
</p>
</div>
</div>

<div className="mb-6 mt-4 grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-4">
{cardData.map((card, index) => (
<CardComponent
key={index}
title={card.title}
value={card.value}
description={card.description}
icon={card.icon}
/>
))}
</div>

<div className="mt-6 flex flex-col gap-4 lg:flex-row">
<Card className="rounded-xl border border-slate-300 bg-white p-4 shadow-md lg:flex-1">
<h2 className="mb-2 ml-4 text-base font-semibold text-zinc-950">
Overview
</h2>
<Chart chartData={chartData} chartConfig={chartConfig} />
</Card>
<TopProductsComponent data={data} gradients={gradients} />
</div>
</section>
);
};

export default Client;
13 changes: 13 additions & 0 deletions src/app/(admin)/admin/dashboard/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import Client from "./client";

export const metadata = {
title: "Dashboard",
description:
"Super Admin Dashboard using ShadCN UI components, adhering to design specifications and best practices for accessibility.",
};

const AdminDashboardPage = () => {
return <Client />;
};

export default AdminDashboardPage;
2 changes: 1 addition & 1 deletion src/app/guides/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ const StyleGuide: FC = () => {
</div>
<h2 className="text-2xl font-semibold">Input Components</h2>
<div
className="grid w-full items-start items-center gap-4"
className="grid w-full items-center gap-4"
style={{ gridTemplateColumns: "repeat(auto-fit,minmax(300px,1fr))" }}
>
<CustomInput
Expand Down
41 changes: 41 additions & 0 deletions src/components/adminDashboard/CardComponent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import Image from "next/image";
import { FC } from "react";

import { Card, CardContent, CardHeader, CardTitle } from "../ui/card";

interface CardProperties {
title: string;
value: string;
description: string;
icon: string;
}

const CardComponent: FC<CardProperties> = ({
title,
value,
description,
icon,
}) => {
return (
<Card className="border border-[#CBD5E1] bg-white shadow-md">
<CardHeader>
<CardTitle className="flex justify-between text-[12px] text-neutral-950">
{title}
<Image
src={icon}
alt={title}
width={24}
height={24}
className="mr-2"
/>
</CardTitle>
</CardHeader>
<CardContent>
<p className="text-[24px] font-semibold">{value}</p>
<p className="text-sm text-[#525252]">{description}</p>
</CardContent>
</Card>
);
};

export default CardComponent;
58 changes: 58 additions & 0 deletions src/components/adminDashboard/Chart.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { Bar, BarChart, CartesianGrid, XAxis, YAxis } from "recharts";

import { CardContent } from "~/components/ui/card";
import {
ChartConfig,
ChartContainer,
ChartTooltip,
ChartTooltipContent,
} from "~/components/ui/chart";

type ChartProperties = {
chartData: { month: string; revenue: number }[];
chartConfig: ChartConfig;
};

export function Chart({ chartData = [], chartConfig }: ChartProperties) {
return (
<>
<div className="h-full w-full">
<CardContent className="h-full w-full pl-0">
<ChartContainer className="h-full w-full p-0" config={chartConfig}>
<BarChart
className="w-full"
accessibilityLayer
data={chartData}
margin={{ top: 20, bottom: 2 }}
>
<CartesianGrid vertical={false} />
<XAxis
dataKey="month"
tickLine={false}
tickMargin={10}
axisLine={false}
tickFormatter={(value) => value.slice(0, 3)}
/>
<YAxis
ticks={[0, 1500, 3000, 4500, 6000]}
axisLine={false}
tickLine={false}
tickFormatter={(value) => `$${value}`}
/>
<ChartTooltip
cursor={false}
content={<ChartTooltipContent hideLabel />}
/>
<Bar
dataKey="revenue"
fill="var(--color-desktop)"
radius={8}
data-testid="bar"
/>
</BarChart>
</ChartContainer>
</CardContent>
</div>
</>
);
}
91 changes: 91 additions & 0 deletions src/components/adminDashboard/TopProductsComponent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import React from "react";

import { Card } from "../ui/card";

type ProductData = {
name: string;
amount: string;
};

type TopProductsProperties = {
data: ProductData[];
gradients: string[];
};

const TopProductsComponent: React.FC<TopProductsProperties> = ({
data,
gradients,
}) => {
return (
<Card className="rounded-xl border border-slate-300 bg-white p-4 shadow">
<div className="mb-6 flex items-center justify-between">
<div className="flex flex-col items-start gap-2">
<h2 className="text-2xl font-semibold text-neutral-950">
Top Products
</h2>
<p className="text-xs font-normal text-neutral-600">
Your top selling products appear here.
</p>
</div>
<button className="flex items-center justify-center gap-2 rounded-md bg-orange-500 px-4 py-2 text-sm font-medium text-neutral-50">
View All
<span>
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 16 16"
fill="none"
>
<path
d="M4.66669 11.3334L11.3334 4.66675"
stroke="#FAFAFA"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M4.66669 4.66675H11.3334V11.3334"
stroke="#FAFAFA"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
</span>
</button>
</div>
<ul className="text-[#0A0A0A]">
{data.map((item, index) => (
<li
key={index}
className="mb-2 flex items-center justify-between py-2"
>
<div className="flex items-center space-x-4">
<div
className="h-10 w-10 rounded-md"
style={{ background: gradients[index % gradients.length] }}
/>
<div>
<p
data-testid={`product-name-${index}`}
className="text-base font-medium"
>
{item.name}
</p>
</div>
</div>
<p
data-testid={`product-amount-${index}`}
className="text-[16px] font-semibold"
>
{item.amount}
</p>
</li>
))}
</ul>
</Card>
);
};

export default TopProductsComponent;
33 changes: 33 additions & 0 deletions src/components/adminDashboard/cardData.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
type CardData = {
title: string;
value: string;
description: string;
icon: string;
};

export const cardData: CardData[] = [
{
title: "Total Revenue",
value: "$45,000.00",
description: "+20% from last month",
icon: `/icons/dollarSign.svg`,
},
{
title: "Total Users",
value: "+4,000",
description: "+10% from last month",
icon: `/icons/user.svg`,
},
{
title: "Total Products",
value: "1,000",
description: "+20% from last month",
icon: `/icons/box.svg`,
},
{
title: "Lifetime Sales",
value: "$450,000.00",
description: "+150% from last month",
icon: `/icons/arrowUp.svg`,
},
];
30 changes: 30 additions & 0 deletions src/components/adminDashboard/chartData.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { ChartConfig } from "~/components/ui/chart";

export const generateRandomRevenue = () =>
(Math.floor(Math.random() * 11) + 1) * 500;

export const chartData = [
{ month: "January", revenue: generateRandomRevenue() },
{ month: "February", revenue: generateRandomRevenue() },
{ month: "March", revenue: generateRandomRevenue() },
{ month: "April", revenue: generateRandomRevenue() },
{ month: "May", revenue: generateRandomRevenue() },
{ month: "June", revenue: generateRandomRevenue() },
{ month: "July", revenue: generateRandomRevenue() },
{ month: "August", revenue: generateRandomRevenue() },
{ month: "September", revenue: generateRandomRevenue() },
{ month: "October", revenue: generateRandomRevenue() },
{ month: "November", revenue: generateRandomRevenue() },
{ month: "December", revenue: generateRandomRevenue() },
];

export const chartConfig: ChartConfig = {
desktop: {
label: "Revenue",
color: "#F97316",
},
mobile: {
label: "Mobile",
color: "#F97316",
},
};
37 changes: 37 additions & 0 deletions src/components/adminDashboard/productData.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
const data = [
{
name: "The Lemonade blender",
amount: "500 sales",
},
{
name: "Bean Cake Powder",
amount: "250 sales",
},
{
name: "Flour Mixer",
amount: "230 sales",
},
{
name: "Blender",
amount: "500 sales",
},
{
name: "A Food Product",
amount: "150 sales",
},
{
name: "Cake Powder",
amount: "100 sales",
},
];

const gradients = [
" linear-gradient(180deg, #F6C790 0%, #E77F1E 100%)",
"linear-gradient(180deg, #D6F690 0%, #D7E71E 100%)",
"linear-gradient(180deg, #9290F6 0%, #461EE7 100%)",
" linear-gradient(180deg, #F690A8 0%, #E71E4E 100%)",
"linear-gradient(180deg, #B4F690 0%, #64E71E 100%)",
"linear-gradient(180deg, #E990F6 0%, #CB1EE7 100%)",
];

export { data, gradients };
Loading

0 comments on commit 52ed28c

Please sign in to comment.