Skip to content

Commit 5c2fe80

Browse files
committed
feat(dashboard): project overview header
1 parent 5398cb4 commit 5c2fe80

File tree

8 files changed

+81
-15
lines changed

8 files changed

+81
-15
lines changed

apps/dashboard/src/@/components/blocks/app-footer.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export function AppFooter(props: AppFooterProps) {
1919
return (
2020
<footer
2121
className={cn(
22-
"w-full border-border border-t bg-muted/50 py-6 md:py-8",
22+
"w-full border-border border-t bg-white py-6 md:py-8 dark:bg-muted/50",
2323
props.className,
2424
)}
2525
>

apps/dashboard/src/@/components/ui/DatePickerWithRange.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ export function DatePickerWithRange(props: {
5050
id="date"
5151
variant="outline"
5252
className={cn(
53-
"justify-start gap-2 text-left font-normal",
53+
"justify-start gap-2 bg-card text-left font-normal",
5454
props.className,
5555
)}
5656
>

apps/dashboard/src/app/team/[team_slug]/(team)/TeamOverviewPage.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ function ProjectCard(props: {
127127
<Link
128128
className="group static before:absolute before:top-0 before:right-0 before:bottom-0 before:left-0 before:z-0"
129129
// remove /connect when we have overview page
130-
href={`/team/${team_slug}/${project.slug}/connect/analytics`}
130+
href={`/team/${team_slug}/${project.slug}`}
131131
>
132132
<h2 className="font-medium text-base">{project.name}</h2>
133133
</Link>
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import type { Project } from "@/api/projects";
2+
import { RangeSelector } from "components/analytics/range-selector";
3+
4+
export function ProjectOverviewHeader(props: {
5+
project: Project;
6+
}) {
7+
const { project } = props;
8+
9+
return (
10+
<div className="flex flex-col items-start gap-6 py-6 md:h-[120px] md:flex-row md:items-center md:py-0">
11+
<div className="flex-1">
12+
<h1 className="font-semibold text-3xl text-foreground">
13+
{project.name}
14+
</h1>
15+
</div>
16+
<RangeSelector interval="day" />
17+
</div>
18+
);
19+
}

apps/dashboard/src/app/team/[team_slug]/[project_slug]/layout.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ export default async function TeamLayout(props: {
3535

3636
return (
3737
<div className="flex grow flex-col">
38-
<div className="bg-muted/50">
38+
<div className="bg-white dark:bg-muted/50">
3939
<TeamHeader
4040
currentProject={project}
4141
currentTeam={team}
@@ -44,6 +44,11 @@ export default async function TeamLayout(props: {
4444
<TabPathLinks
4545
tabContainerClassName="px-4 lg:px-6"
4646
links={[
47+
{
48+
path: `/team/${props.params.team_slug}/${props.params.project_slug}`,
49+
exactMatch: true,
50+
name: "Overview",
51+
},
4752
{
4853
path: `/team/${props.params.team_slug}/${props.params.project_slug}/connect/analytics`,
4954
name: "Connect",
Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,26 @@
1-
import { redirect } from "next/navigation";
1+
import { getProjects } from "@/api/projects";
2+
import { notFound } from "next/navigation";
3+
import { ProjectOverviewHeader } from "./components/ProjectOverviewHeader";
24

3-
export default function ProjectOverviewPage(props: {
5+
export default async function ProjectOverviewPage(props: {
46
params: { team_slug: string; project_slug: string };
7+
searchParams: { from: string; to: string; type: string; interval: string };
58
}) {
6-
// TODO: implement overview page for project
7-
// redirect to connect for now
8-
redirect(
9-
`/team/${props.params.team_slug}/${props.params.project_slug}/connect`,
9+
const projects = await getProjects(props.params.team_slug);
10+
11+
const project = projects.find((p) => p.slug === props.params.project_slug);
12+
13+
if (!project) {
14+
notFound();
15+
}
16+
17+
return (
18+
<div>
19+
<div className="w-full border-border-800 border-b bg-muted/50 px-6">
20+
<div className="container">
21+
<ProjectOverviewHeader project={project} />
22+
</div>
23+
</div>
24+
</div>
1025
);
1126
}

apps/dashboard/src/components/analytics/date-range-selector.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ const durationPresets = [
107107
},
108108
] as const;
109109

110-
type DurationId = (typeof durationPresets)[number]["id"];
110+
export type DurationId = (typeof durationPresets)[number]["id"];
111111

112112
export type Range = {
113113
type: DurationId | "custom";

apps/dashboard/src/components/analytics/range-selector.tsx

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,50 @@
11
"use client";
22
import { useDashboardRouter } from "@/lib/DashboardRouter";
3-
import { DateRangeSelector } from "components/analytics/date-range-selector";
4-
import type { Range } from "components/analytics/date-range-selector";
3+
import { useQuery } from "@tanstack/react-query";
4+
import {
5+
DateRangeSelector,
6+
getLastNDaysRange,
7+
} from "components/analytics/date-range-selector";
8+
import type {
9+
DurationId,
10+
Range,
11+
} from "components/analytics/date-range-selector";
512
import { IntervalSelector } from "components/analytics/interval-selector";
613
import { differenceInDays } from "date-fns";
714
import { usePathname, useSearchParams } from "next/navigation";
815

916
export function RangeSelector({
1017
range,
1118
interval,
12-
}: { range: Range; interval: "day" | "week" }) {
19+
}: { range?: Range; interval: "day" | "week" }) {
1320
const pathname = usePathname();
1421
const searchParams = useSearchParams();
1522
const router = useDashboardRouter();
1623

24+
const { data: computedRange } = useQuery({
25+
queryKey: ["analytics-range", searchParams?.toString(), range],
26+
queryFn: async () => {
27+
if (range) {
28+
return range;
29+
}
30+
if (searchParams) {
31+
const fromStringified = searchParams.get("from");
32+
const from = fromStringified
33+
? new Date(fromStringified)
34+
: getLastNDaysRange("last-120").from;
35+
const toStringified = searchParams.get("to");
36+
const to = toStringified ? new Date(toStringified) : new Date();
37+
const type = (searchParams.get("type") as DurationId) || "last-120";
38+
return { from, to, type } satisfies Range;
39+
}
40+
return getLastNDaysRange("last-120");
41+
},
42+
});
43+
1744
return (
1845
<div className="flex justify-end gap-3">
1946
<DateRangeSelector
20-
range={range}
47+
range={computedRange || getLastNDaysRange("last-120")}
2148
setRange={(newRange) => {
2249
const days = differenceInDays(newRange.to, newRange.from);
2350
const interval = days > 30 ? "week" : "day";

0 commit comments

Comments
 (0)