From d426cbc5a39cf43eb812227f91cc8f2d93e1e7d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ben=20B=C3=B6ckmann?= Date: Thu, 4 Apr 2024 16:02:50 +0200 Subject: [PATCH] fix: added user to dashboard; added bookings and settings page; added layout to dashboard --- src/app/dashboard/bookings/page.tsx | 7 ++ src/app/dashboard/layout.tsx | 100 +++++++++++++++++ src/app/dashboard/page.tsx | 166 +++++++++------------------- src/app/dashboard/settings/page.tsx | 5 + src/app/login/page.tsx | 3 + src/lib/actions.ts | 6 +- src/lib/utils.ts | 20 +++- src/middleware.ts | 1 - 8 files changed, 191 insertions(+), 117 deletions(-) create mode 100644 src/app/dashboard/bookings/page.tsx create mode 100644 src/app/dashboard/layout.tsx create mode 100644 src/app/dashboard/settings/page.tsx diff --git a/src/app/dashboard/bookings/page.tsx b/src/app/dashboard/bookings/page.tsx new file mode 100644 index 0000000..c081e4a --- /dev/null +++ b/src/app/dashboard/bookings/page.tsx @@ -0,0 +1,7 @@ +import React from "react"; + +function Bookings() { + return
Settings
; +} + +export default Bookings; diff --git a/src/app/dashboard/layout.tsx b/src/app/dashboard/layout.tsx new file mode 100644 index 0000000..3098a60 --- /dev/null +++ b/src/app/dashboard/layout.tsx @@ -0,0 +1,100 @@ +"use client"; +import Image from "next/image"; +import { Button } from "@/components/ui/button"; +import { LuBookCopy, LuBuilding, LuGauge, LuLayoutDashboard, LuSettings, LuUser2 } from "react-icons/lu"; +import React, { useEffect, useState } from "react"; +import type { User } from "@/types"; +import { getAccessToken, getUser } from "@/lib/actions"; +import Link from "next/link"; + +export default function DashboardLayout({ children }: { children: React.ReactNode }) { + const [user, setUser] = useState(); + const [isAdmin, setIsAdmin] = useState(user?.role === "ADMIN"); + + useEffect(() => { + const fetchUser = async () => { + try { + const accessToken = await getAccessToken(); + setUser(await getUser(accessToken)); + } catch (error) { + setIsAdmin(false); + console.error("Failed to fetch user", error); + } + }; + fetchUser().catch(console.error); + }, []); + + useEffect(() => { + setIsAdmin(user?.role === "ADMIN"); + }, [user]); + return ( +
+ +
+ {children} +
+

MeetMate

+
+
+
+ ); +} diff --git a/src/app/dashboard/page.tsx b/src/app/dashboard/page.tsx index 7117089..716ef76 100644 --- a/src/app/dashboard/page.tsx +++ b/src/app/dashboard/page.tsx @@ -1,11 +1,9 @@ "use client"; import { Button } from "@/components/ui/button"; -import Image from "next/image"; import { Input } from "@/components/ui/input"; import { Avatar, AvatarFallback } from "@/components/ui/avatar"; import React, { useEffect, useState } from "react"; -import { LuLayoutDashboard, LuBookCopy, LuSettings, LuGauge, LuUser2, LuBuilding } from "react-icons/lu"; -import { deleteToken, getUser } from "@/lib/actions"; +import { deleteToken, getAccessToken, getUser } from "@/lib/actions"; import { DropdownMenu, DropdownMenuContent, @@ -14,132 +12,76 @@ import { DropdownMenuSeparator, DropdownMenuTrigger } from "@/components/ui/dropdown-menu"; +import { type User } from "@/types"; +import { extractNameInitials } from "@/lib/utils"; function Dashboard() { - const [isAdmin, setIsAdmin] = useState(false); + const [user, setUser] = useState(); + + useEffect(() => { + const fetchUser = async () => { + try { + const accessToken = await getAccessToken(); + setUser(await getUser(accessToken)); + } catch (error) { + console.error("Failed to fetch user", error); + } + }; + fetchUser().catch(console.error); + }, []); const logout = async () => { try { await deleteToken(); + window.location.reload(); } catch (error) { console.error("Logout failed", error); throw error; } }; - - useEffect(() => { - const checkAdmin = async () => { - const user = await getUser(); - setIsAdmin(user?.role === "ADMIN"); - }; - checkAdmin().catch(() => { - setIsAdmin(false); - }); - }, []); return ( -
- -
-
-
-

Welcome back, Tim

-
- - - - - - - -
-

shadcn

-

m@example.com

-
-
- - Settings - - - Log out - -
-
-
-
+ -
-

MeetMate Dashboard

-

Create your appointments in minutes

- -
+
+

MeetMate Dashboard

+

Create your appointments in minutes

+ +
-
+
-
-
-
-

MeetMate

-
-
+
); } diff --git a/src/app/dashboard/settings/page.tsx b/src/app/dashboard/settings/page.tsx new file mode 100644 index 0000000..e6f0954 --- /dev/null +++ b/src/app/dashboard/settings/page.tsx @@ -0,0 +1,5 @@ +function Settings() { + return
Settings
; +} + +export default Settings; diff --git a/src/app/login/page.tsx b/src/app/login/page.tsx index 02508f5..1b8db0c 100644 --- a/src/app/login/page.tsx +++ b/src/app/login/page.tsx @@ -47,6 +47,9 @@ const LoginForm = () => { variant: "default", className: "border-emerald-300" }); + setTimeout(() => { + router.push("/dashboard"); + }, 1500); } }, [formState, toast, dispatch]); diff --git a/src/lib/actions.ts b/src/lib/actions.ts index 9afcb58..1349d29 100644 --- a/src/lib/actions.ts +++ b/src/lib/actions.ts @@ -97,7 +97,7 @@ export async function getUser(accessToken?: string): Promise { if (response.ok) { return (await response.json()) as User; } else { - console.log(response.status); + console.log("Error getting User", response.status); return null; } } catch (error) { @@ -106,6 +106,10 @@ export async function getUser(accessToken?: string): Promise { } } +export async function getAccessToken() { + return cookies().get("accessToken")?.value; +} + type LoginFormState = { message: string; errors: Record | undefined; diff --git a/src/lib/utils.ts b/src/lib/utils.ts index d084cca..9a60cba 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -1,6 +1,20 @@ -import { type ClassValue, clsx } from "clsx" -import { twMerge } from "tailwind-merge" +import { type ClassValue, clsx } from "clsx"; +import { twMerge } from "tailwind-merge"; export function cn(...inputs: ClassValue[]) { - return twMerge(clsx(inputs)) + return twMerge(clsx(inputs)); +} + +export function extractNameInitials(name: string | undefined) { + if (name === undefined) { + return ""; + } + const parts = name.trim().split(/\s+/); + let initials = parts[0][0]; + + if (parts.length > 1) { + initials += parts[parts.length - 1][0]; + } + + return initials.toUpperCase(); } diff --git a/src/middleware.ts b/src/middleware.ts index c2b6979..3e6b308 100644 --- a/src/middleware.ts +++ b/src/middleware.ts @@ -12,7 +12,6 @@ export async function middleware(req: NextRequest) { if (refreshToken !== undefined || refreshToken !== "") { const newAccessToken = await refreshAccessToken(refreshToken); if (newAccessToken !== undefined) { - console.log(newAccessToken); response.cookies.set("accessToken", newAccessToken[0], { httpOnly: true, secure: true, sameSite: "strict" }); response.cookies.set("expires_at", newAccessToken[1], { httpOnly: true, secure: true, sameSite: "strict" }); user = await getUser(newAccessToken[0]);