Skip to content

Commit 054008a

Browse files
committed
side nav completed almost
1 parent a82db18 commit 054008a

31 files changed

+4696
-236
lines changed

app/(routes)/dashboard/layout.tsx

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
"use client";
2+
3+
import Sidebar from "@/app/_components/Sidebar";
4+
import { api } from "@/convex/_generated/api";
5+
import { useKindeBrowserClient } from "@kinde-oss/kinde-auth-nextjs";
6+
import { useConvex } from "convex/react";
7+
import { useRouter } from "next/navigation";
8+
import { useEffect } from "react";
9+
10+
export default function DashboardLayout({
11+
children,
12+
}: Readonly<{
13+
children: React.ReactNode;
14+
}>) {
15+
const { user } = useKindeBrowserClient();
16+
const convex = useConvex();
17+
const router = useRouter();
18+
19+
useEffect(() => {
20+
if (user) {
21+
checkTeam();
22+
}
23+
}, [user]);
24+
25+
const checkTeam = async () => {
26+
const result = await convex.query(api.teams.getTeams, {
27+
email: user?.email!,
28+
});
29+
if (!result.length) {
30+
router.push("/team/create");
31+
}
32+
};
33+
34+
return (
35+
<div className="h-screen">
36+
<div className="grid grid-cols-5">
37+
<div>
38+
<Sidebar />
39+
</div>
40+
<div className="grid-cols-4 pl-4 border-l border-neutral-800 w-[80vw]">
41+
{children}
42+
</div>
43+
</div>
44+
</div>
45+
);
46+
}

app/(routes)/dashboard/page.tsx

+52-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,57 @@
1-
import React from "react";
1+
"use client";
22

3+
import React, { useEffect } from "react";
4+
import { useKindeBrowserClient } from "@kinde-oss/kinde-auth-nextjs";
5+
import { LogoutLink } from "@kinde-oss/kinde-auth-nextjs/components";
6+
import { Button } from "@/components/ui/button";
7+
import { useConvex, useMutation, useQuery } from "convex/react";
8+
import { api } from "@/convex/_generated/api";
9+
import { useRouter } from "next/navigation";
310
const page = () => {
4-
return <div className="text-white">DashBoard</div>;
11+
const { user } = useKindeBrowserClient();
12+
const convex = useConvex();
13+
const router = useRouter();
14+
const createUser = useMutation(api.user.createUser);
15+
16+
useEffect(() => {
17+
if (user) {
18+
checkUser();
19+
}
20+
}, [user]);
21+
22+
const checkUser = async () => {
23+
const result = await convex.query(api.user.getUser, {
24+
email: user?.email!,
25+
});
26+
if (!result.length) {
27+
createUser({
28+
name: user?.given_name! + " " + user?.family_name!,
29+
email: user?.email!,
30+
image:
31+
user?.picture ??
32+
"https://img.freepik.com/free-vector/graphic-designer-man_78370-159.jpg?size=626&ext=jpg&ga=GA1.1.1395880969.1709251200&semt=ais",
33+
}).then((res) => {
34+
console.log(res);
35+
});
36+
}
37+
};
38+
return (
39+
<div className="text-white h-screen">
40+
DashBoard Page user Id : {user?.id}
41+
<div className="">
42+
<h2>
43+
Welcome to the dashboard {user?.given_name} {user?.family_name}. You
44+
can now access the protected route. showing data for team = {}
45+
</h2>
46+
<h3>You can also logout by clicking the logout button below.</h3>
47+
</div>
48+
<div className="mt-3 ml-3">
49+
<Button className="rounded-full p-4" variant={"destructive"}>
50+
<LogoutLink>Logout</LogoutLink>
51+
</Button>
52+
</div>
53+
</div>
54+
);
555
};
656

757
export default page;

app/(routes)/team/create/page.tsx

+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
"use client";
2+
3+
import { Button } from "@/components/ui/button";
4+
import { Input } from "@/components/ui/input";
5+
import { Label } from "@/components/ui/label";
6+
import { api } from "@/convex/_generated/api";
7+
import { useKindeBrowserClient } from "@kinde-oss/kinde-auth-nextjs";
8+
import { useMutation } from "convex/react";
9+
import { useRouter } from "next/navigation";
10+
11+
import React, { useState } from "react";
12+
import { toast } from "sonner";
13+
14+
const page = () => {
15+
const [teamName, setTeamName] = useState("" as string);
16+
const { user } = useKindeBrowserClient();
17+
const createTeam = useMutation(api.teams.createTeam);
18+
const router = useRouter();
19+
const handleCreateTeam = async () => {
20+
await createTeam({
21+
teamName,
22+
createdBy: user?.email!,
23+
}).then((res) => {
24+
console.log(res);
25+
if (res) {
26+
router.push("/dashboard");
27+
toast.success("Team created successfully");
28+
}
29+
});
30+
};
31+
32+
return (
33+
<div className="relative h-screen flex items-center justify-center">
34+
<div className="absolute top-8 left-8 flex items-center space-x-2">
35+
<img src="/logo.svg" alt="logo" className="w-10 h-10" />
36+
<h1 className="text-white font-bold">eraser</h1>
37+
</div>
38+
<div className="flex flex-col gap-4 justify-center items-center">
39+
<div className="text-center w-full">
40+
<h1 className="font-bold text-4xl mb-4">
41+
What should we call your team?
42+
</h1>
43+
44+
<h3 className="text-neutral-400">
45+
You can always change this later from settings.
46+
</h3>
47+
</div>
48+
<div className="grid w-full max-w-lg items-center gap-1.5 mt-16 mb-16">
49+
<Label htmlFor="team_name">Team Name</Label>
50+
<Input
51+
className="bg-neutral-800 m-1"
52+
type="text"
53+
id="team_name"
54+
placeholder="Team Name"
55+
onChange={(e) => setTeamName(e.target.value)}
56+
onSubmit={(e) => {
57+
e.preventDefault();
58+
handleCreateTeam();
59+
}}
60+
/>
61+
</div>
62+
63+
<Button
64+
onClick={handleCreateTeam}
65+
disabled={!(teamName && teamName.length > 0)}
66+
className="bg-blue-500 text-white w-full max-w-[300px] hover:bg-blue-600"
67+
>
68+
Create team
69+
</Button>
70+
</div>
71+
</div>
72+
);
73+
};
74+
75+
export default page;

app/ConvexClientProvider.tsx

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
"use client";
2+
import { ReactNode } from "react";
3+
import { ConvexProvider, ConvexReactClient } from "convex/react";
4+
5+
const convex = new ConvexReactClient(process.env.NEXT_PUBLIC_CONVEX_URL!);
6+
7+
export default function ConvexClientProvider({
8+
children,
9+
}: {
10+
children: ReactNode;
11+
}) {
12+
return <ConvexProvider client={convex}>{children}</ConvexProvider>;
13+
}

app/_components/Header.tsx

+31-13
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,15 @@
11
import Image from "next/image";
22
import React from "react";
3+
import {
4+
RegisterLink,
5+
LoginLink,
6+
} from "@kinde-oss/kinde-auth-nextjs/components";
7+
import { getKindeServerSession } from "@kinde-oss/kinde-auth-nextjs/server";
8+
import { Button } from "@/components/ui/button";
39

4-
const Header = () => {
10+
const Header = async () => {
11+
const { getUser } = getKindeServerSession();
12+
const user = await getUser();
513
return (
614
<header className="z-10 backdrop-blur-xl w-full fixed">
715
<div className="mx-auto flex h-16 max-w-screen-xl items-center gap-8 px-4 sm:px-6 lg:px-8">
@@ -67,18 +75,28 @@ const Header = () => {
6775

6876
<div className="flex items-center gap-4">
6977
<div className="sm:flex sm:gap-4">
70-
<a
71-
className="block rounded-lg px-5 py-2.5 text-sm font-medium text-white transition hover:bg-blue-500 "
72-
href="#"
73-
>
74-
Login
75-
</a>
76-
<a
77-
className="hidden md:block rounded-lg px-5 py-2.5 text-sm font-medium text-white transition hover:bg-gray-700"
78-
href="#"
79-
>
80-
Register
81-
</a>
78+
{user && (
79+
<Button>
80+
<LoginLink>Go to Dashboard</LoginLink>
81+
</Button>
82+
)}
83+
84+
{!user && (
85+
<>
86+
<LoginLink
87+
postLoginRedirectURL="/dashboard"
88+
className="block rounded-lg px-5 py-2.5 text-sm font-medium text-white transition hover:bg-blue-500 "
89+
>
90+
Login
91+
</LoginLink>
92+
<RegisterLink
93+
postLoginRedirectURL="/dashboard"
94+
className="hidden md:block rounded-lg px-5 py-2.5 text-sm font-medium text-white transition hover:bg-gray-700"
95+
>
96+
Register
97+
</RegisterLink>
98+
</>
99+
)}
82100
</div>
83101

84102
<button className="block rounded bg-gray-100 p-2.5 text-black transition hover:text-gray-500/75 md:hidden">

app/_components/Hero.tsx

+3-5
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { LoginLink } from "@kinde-oss/kinde-auth-nextjs/components";
12
import { ArrowRight } from "lucide-react";
23
import React from "react";
34

@@ -28,15 +29,12 @@ const Hero = () => {
2829
</p>
2930

3031
<div className="mt-8 flex flex-wrap justify-center gap-4">
31-
<a
32-
className="flex items-center w-full rounded-lg border border-white bg-neutral-100 px-4 py-2 text-sm font-medium text-black hover:bg-neutral-300 hover:text-neutral-900 focus:outline-none focus:ring active:text-opacity-75 sm:w-auto"
33-
href="#"
34-
>
32+
<LoginLink className="flex items-center w-full rounded-lg border border-white bg-neutral-100 px-4 py-2 text-sm font-medium text-black hover:bg-neutral-300 hover:text-neutral-900 focus:outline-none focus:ring active:text-opacity-75 sm:w-auto">
3533
Get Started
3634
<p className="ml-2">
3735
<ArrowRight size={24} />
3836
</p>
39-
</a>
37+
</LoginLink>
4038
</div>
4139
</div>
4240
</div>

app/_components/MyAvatar.tsx

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import React from "react";
2+
3+
const MyAvatar = () => {
4+
return <div>MyAvatar</div>;
5+
};
6+
7+
export default MyAvatar;

app/_components/SideNavBottomMenu.tsx

+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import React from "react";
2+
import {
3+
ArchiveIcon,
4+
FlagIcon,
5+
Github,
6+
LayoutDashboard,
7+
LucideLock,
8+
} from "lucide-react";
9+
import { Button } from "@/components/ui/button";
10+
import { Progress } from "@/components/ui/progress";
11+
12+
const SideNavBottomMenu = () => {
13+
const menuList = [
14+
{
15+
id: 1,
16+
name: "Getting Started",
17+
icon: FlagIcon,
18+
link: "/dashboard/getting-started",
19+
},
20+
{
21+
id: 2,
22+
name: "Github Sync",
23+
icon: Github,
24+
link: "/dashboard",
25+
},
26+
{
27+
id: 3,
28+
name: "Private Files",
29+
icon: LucideLock,
30+
link: "/dashboard",
31+
},
32+
{
33+
id: 4,
34+
name: "Archive",
35+
icon: ArchiveIcon,
36+
link: "/dashboard",
37+
},
38+
];
39+
return (
40+
<div>
41+
{menuList.map((item) => (
42+
<div
43+
key={item.id}
44+
className="flex space-x-2 text-neutral-300 cursor-pointer items-center justify-start hover:bg-neutral-800 text-sm px-2 font-semibold py-1 rounded-lg mx-3"
45+
>
46+
<item.icon size={14} className="mr-2" />
47+
{item.name}
48+
</div>
49+
))}
50+
<Button className="bg-blue-500 w-full mt-8 mb-4 justify-start text-neutral-300 font-medium hover:bg-blue-600 hover:text-white">
51+
New File
52+
</Button>
53+
<Progress value={0} className="bg-neutral-700" />
54+
<div className="text-xs mt-2">
55+
<span className="font-bold">0</span> out of{" "}
56+
<span className="font-bold">5</span> files used.
57+
</div>
58+
<div className="text-xs mt-1 mb-2">
59+
<span className="font-semibold cursor-pointer underline">Upgrade</span>{" "}
60+
your plan for unlimited access.
61+
</div>
62+
</div>
63+
);
64+
};
65+
66+
export default SideNavBottomMenu;

app/_components/Sidebar.tsx

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import React from "react";
2+
import SidebarTopButton from "./SidebarTopButton";
3+
import { Button } from "@/components/ui/button";
4+
import { LayoutDashboard } from "lucide-react";
5+
import SideNavBottomMenu from "./SideNavBottomMenu";
6+
7+
const Sidebar = () => {
8+
return (
9+
<div className="text-white h-screen fixed max-w-64 py-4 px-4 flex flex-col">
10+
<div className="flex-1">
11+
<SidebarTopButton />
12+
<Button
13+
variant={"outline"}
14+
className="bg-gradient-to-r from-neutral-600 backdrop:blur-md to-neutral-700 border-neutral-800 w-full mt-10 text-left justify-start hover:bg-neutral-600 hover:border-neutral-700 hover:from-neutral-600 hover:to-neutral-700 hover:text-white"
15+
>
16+
<LayoutDashboard size={16} className="mr-2" />
17+
All files
18+
</Button>
19+
</div>
20+
21+
{/* bottom layout */}
22+
<SideNavBottomMenu />
23+
</div>
24+
);
25+
};
26+
27+
export default Sidebar;

0 commit comments

Comments
 (0)