Skip to content

Commit

Permalink
(feat-HNG-202): user dashboard overview page layout
Browse files Browse the repository at this point in the history
  • Loading branch information
elitenoire committed Jul 29, 2024
1 parent 4b44f90 commit 6d8156b
Show file tree
Hide file tree
Showing 13 changed files with 310 additions and 48 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.1",
"cookies-next": "^4.2.1",
"date-fns": "^3.6.0",
"framer-motion": "^11.3.8",
"input-otp": "^1.2.4",
"jest-axe": "^9.0.0",
Expand Down
3 changes: 3 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function DashboardAnalytics() {
return <div>REPORTS</div>;
}
40 changes: 40 additions & 0 deletions src/app/dashboard/(user-dashboard)/(user-metrics)/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import type { PropsWithChildren } from "react";

import { DateSelector } from "~/app/dashboard/(user-dashboard)/_components/layout/dateselector";
import { Tablinks } from "~/app/dashboard/(user-dashboard)/_components/layout/tablinks";
import { Button } from "~/components/common/common-button";

const links = [
{
title: "Overview",
href: "/dashboard",
},
{
title: "Analytics",
href: "/dashboard/analytics",
},
{
title: "Reports",
href: "/dashboard/reports",
},
];

export default function UserMetricsLayout({ children }: PropsWithChildren) {
return (
<div className="flex h-full flex-col gap-[37px] bg-background">
<div className="flex flex-wrap items-center justify-between gap-x-6 gap-y-2 pt-6">
<div className="space-y-6">
<h1 className="text-2xl font-semibold lg:text-[30px]">Dashboard</h1>
<Tablinks links={links} />
</div>
<div className="flex flex-wrap items-center gap-2 max-sm:flex-grow max-sm:justify-between">
<DateSelector />
<Button variant="primary" className="h-10">
Download
</Button>
</div>
</div>
<div className="flex-1">{children}</div>
</div>
);
}
13 changes: 13 additions & 0 deletions src/app/dashboard/(user-dashboard)/(user-metrics)/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { OverviewChart } from "~/app/dashboard/(user-dashboard)/_components/overview-chart";

export default function DashboardOverview() {
return (
<div className="flex flex-col gap-4">
<div>Revenue Cards</div>
<div className="flex flex-wrap gap-4">
<OverviewChart className="flex-grow basis-full md:basis-1/2 lg:max-w-[787px]" />
<div className="flex-1 flex-grow md:min-w-[400px]">Recent Sales</div>
</div>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function DashboardReports() {
return <div>REPORTS</div>;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
"use client";

import { format, subMonths } from "date-fns";
import { CalendarDaysIcon } from "lucide-react";
import { useState } from "react";
import { DateRange } from "react-day-picker";

import { Button } from "~/components/common/common-button";
import { Calendar } from "~/components/ui/calendar";
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "~/components/ui/popover";
import { cn } from "~/lib/utils";

type DateSelectorProperties = {
from?: Date;
to?: Date;
className?: string;
};
export function DateSelector({
from = subMonths(new Date(), 1),
to = new Date(),
className,
}: DateSelectorProperties) {
const [date, setDate] = useState<DateRange | undefined>({
from,
to,
});

return (
<div className={cn("grid gap-2", className)}>
<Popover>
<PopoverTrigger asChild>
<Button
id="date"
variant={"outline"}
className={cn(
"h-10 max-w-[256px] justify-start gap-1 p-2 text-left font-normal",
!date && "text-muted-foreground",
)}
>
<CalendarDaysIcon className="h-6 w-6" />
<span className="truncate">
{date?.from ? (
date.to ? (
<>
{format(date.from, "LLL dd, y")} -{" "}
{format(date.to, "LLL dd, y")}
</>
) : (
format(date.from, "LLL dd, y")
)
) : (
"Pick a date"
)}
</span>
</Button>
</PopoverTrigger>
<PopoverContent className="w-auto p-0" align="start">
<Calendar
initialFocus
mode="range"
defaultMonth={date?.from}
selected={date}
onSelect={setDate}
numberOfMonths={2}
/>
</PopoverContent>
</Popover>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
"use client";

import type { Route } from "next";
import Link from "next/link";
import { usePathname } from "next/navigation";

import { cn } from "~/lib/utils";

type TablinksProperties = {
links: {
title: string;
href: Route;
}[];
};

export function Tablinks({ links }: TablinksProperties) {
const pathname = usePathname();
return (
<nav className="flex flex-wrap rounded-[6px] border border-stroke-colors-stroke px-[5px] py-1">
{links.map(({ title, href }) => (
<Link
key={title}
href={href}
className={cn(
"flex rounded bg-white px-3 py-1.5 text-sm font-medium text-neutral-dark-2",
pathname === href && "bg-subtle",
)}
>
{title}
</Link>
))}
</nav>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
"use client";

import { Chart } from "~/components/userDashboard/Chart";
import { chartConfig, chartData } from "~/components/userDashboard/chartData";

type OverviewChartProperties = {
className?: string;
};
export function OverviewChart({ className }: OverviewChartProperties) {
return (
<Chart
className={className}
chartData={chartData}
chartTitle="Overview"
chartConfig={chartConfig}
/>
);
}
2 changes: 1 addition & 1 deletion src/app/dashboard/(user-dashboard)/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export default function AdminLayout({
children: React.ReactNode;
}) {
return (
<div className="grid grid-rows-[auto_1fr]">
<div className="grid min-h-screen grid-rows-[auto_1fr]">
<UserNavbar />
<div className="relative w-full bg-white px-2 max-lg:overflow-hidden xl:px-4">
<Suspense>{children}</Suspense>
Expand Down
2 changes: 1 addition & 1 deletion src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export default function RootLayout({
return (
<html lang="en">
<body className={inter.className}>
<div className="mx-auto w-full max-w-[1440px]">
<div className="mx-auto h-full w-full max-w-[1440px]">
<Providers />
{children}
<Toaster />
Expand Down
67 changes: 67 additions & 0 deletions src/components/ui/calendar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
"use client";

import { ChevronLeft, ChevronRight } from "lucide-react";
import * as React from "react";
import { DayPicker } from "react-day-picker";

// import { buttonVariants } from "~/components/ui/button";
import { buttonVariants } from "~/components/common/common-button";
import { cn } from "~/lib/utils";

export type CalendarProperties = React.ComponentProps<typeof DayPicker>;

function Calendar({
className,
classNames,
showOutsideDays = true,
...properties
}: CalendarProperties) {
return (
<DayPicker
showOutsideDays={showOutsideDays}
className={cn("p-3", className)}
classNames={{
months: "flex flex-col sm:flex-row space-y-4 sm:space-x-4 sm:space-y-0",
month: "space-y-4",
caption: "flex justify-center pt-1 relative items-center",
caption_label: "text-sm font-medium",
nav: "space-x-1 flex items-center",
nav_button: cn(
buttonVariants({ variant: "outline" }),
"h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100",
),
nav_button_previous: "absolute left-1",
nav_button_next: "absolute right-1",
table: "w-full border-collapse space-y-1",
head_row: "flex",
head_cell:
"text-muted-foreground rounded-md w-9 font-normal text-[0.8rem]",
row: "flex w-full mt-2",
cell: "h-9 w-9 text-center text-sm p-0 relative [&:has([aria-selected].day-range-end)]:rounded-r-md [&:has([aria-selected].day-outside)]:bg-accent/50 [&:has([aria-selected])]:bg-accent first:[&:has([aria-selected])]:rounded-l-md last:[&:has([aria-selected])]:rounded-r-md focus-within:relative focus-within:z-20",
day: cn(
buttonVariants({ variant: "ghost" }),
"h-9 w-9 p-0 font-normal aria-selected:opacity-100",
),
day_range_end: "day-range-end",
day_selected:
"bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground focus:bg-primary focus:text-primary-foreground",
day_today: "bg-accent text-accent-foreground",
day_outside:
"day-outside text-muted-foreground opacity-50 aria-selected:bg-accent/50 aria-selected:text-muted-foreground aria-selected:opacity-30",
day_disabled: "text-muted-foreground opacity-50",
day_range_middle:
"aria-selected:bg-accent aria-selected:text-accent-foreground",
day_hidden: "invisible",
...classNames,
}}
components={{
IconLeft: () => <ChevronLeft className="h-4 w-4" />,
IconRight: () => <ChevronRight className="h-4 w-4" />,
}}
{...properties}
/>
);
}
Calendar.displayName = "Calendar";

export { Calendar };
Loading

0 comments on commit 6d8156b

Please sign in to comment.