Skip to content

Commit

Permalink
Merge pull request #51 from Informatik-Projekt-Kurs/IPK-197-Settings-…
Browse files Browse the repository at this point in the history
…Page-no-functionality

Ipk 197 settings page no functionality
  • Loading branch information
bencodes07 authored Apr 5, 2024
2 parents 73acf84 + 398ac3f commit c9d43a8
Show file tree
Hide file tree
Showing 3 changed files with 158 additions and 5 deletions.
37 changes: 34 additions & 3 deletions src/app/dashboard/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@ import React, { useEffect, useState } from "react";
import type { User } from "@/types";
import { getAccessToken, getUser } from "@/lib/actions";
import Link from "next/link";
import { usePathname } from "next/navigation";
import { cn } from "@/lib/utils";

export default function DashboardLayout({ children }: { children: React.ReactNode }) {
const [user, setUser] = useState<User | null>();
const [isAdmin, setIsAdmin] = useState(user?.role === "ADMIN");
const [active, setActive] = useState<"dashboard" | "bookings" | "settings">("dashboard");

useEffect(() => {
const fetchUser = async () => {
Expand All @@ -27,6 +30,19 @@ export default function DashboardLayout({ children }: { children: React.ReactNod
useEffect(() => {
setIsAdmin(user?.role === "ADMIN");
}, [user]);

const pathname = usePathname();

useEffect(() => {
// Derive the active state based on the current pathname
if (pathname.includes("/dashboard/bookings")) {
setActive("bookings");
} else if (pathname.includes("/dashboard/settings")) {
setActive("settings");
} else {
setActive("dashboard");
}
}, [pathname]);
return (
<div className="flex w-full flex-col gap-5 pl-8 md:flex-row">
<aside className="hidden lg:block">
Expand All @@ -50,19 +66,34 @@ export default function DashboardLayout({ children }: { children: React.ReactNod
<div className="mt-[35%] flex flex-col items-center justify-start gap-y-4">
<header className="relative left-[-40%] mb-[-6px] text-xs text-muted-foreground">Tools</header>
<Link href={"/dashboard"}>
<Button className="w-[168px] justify-start text-foreground" variant="default">
<Button
className={cn(
"w-[168px] justify-start",
active === "dashboard" ? "text-foreground" : "text-muted-foreground"
)}
variant={active === "dashboard" ? "default" : "ghost"}>
<LuLayoutDashboard className="mx-2" size={18} />
Dashboard
</Button>
</Link>
<Link href={"/dashboard/bookings"}>
<Button className="w-[168px] justify-start text-muted-foreground" variant="ghost">
<Button
className={cn(
"w-[168px] justify-start",
active === "bookings" ? "text-foreground" : "text-muted-foreground"
)}
variant={active === "bookings" ? "default" : "ghost"}>
<LuBookCopy className="mx-2" size={18} />
Bookings
</Button>
</Link>
<Link href={"/dashboard/settings"}>
<Button className="w-[168px] justify-start text-muted-foreground" variant="ghost">
<Button
className={cn(
"w-[168px] justify-start",
active === "settings" ? "text-foreground" : "text-muted-foreground"
)}
variant={active === "settings" ? "default" : "ghost"}>
<LuSettings className="mx-2" size={18} />
Settings
</Button>
Expand Down
10 changes: 9 additions & 1 deletion src/app/dashboard/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,14 @@ import {
import { type User } from "@/types";
import { extractNameInitials } from "@/lib/utils";
import Image from "next/image";
import { useRouter } from "next/navigation";

function Dashboard() {
const [user, setUser] = useState<User | null>();
const [loading, setLoading] = useState(true);

const router = useRouter();

useEffect(() => {
const fetchUser = async () => {
setLoading(true);
Expand Down Expand Up @@ -74,7 +77,12 @@ function Dashboard() {
</div>
</DropdownMenuLabel>
<DropdownMenuSeparator />
<DropdownMenuItem>Settings</DropdownMenuItem>
<DropdownMenuItem
onClick={() => {
router.push("/dashboard/settings");
}}>
Settings
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem onClick={logout} className={"text-red-500"}>
Log out
Expand Down
116 changes: 115 additions & 1 deletion src/app/dashboard/settings/page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,119 @@
"use client";
import Image from "next/image";
import React, { useEffect, useState } from "react";
import type { User } from "@/types";
import { getAccessToken, getUser } from "@/lib/actions";
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
import { toast } from "@/components/ui/use-toast";
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod";
import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form";

const FormSchema = z.object({
name: z.string().min(3, {
message: "Name must be at least 3 characters."
}),
email: z.string().email({ message: "Please enter a valid email address." })
});

function Settings() {
return <div className="flex flex-col items-center justify-start p-8 px-6">Settings</div>;
function onSubmit(data: z.infer<typeof FormSchema>) {
toast({
title: "You submitted the following values:",
description: (
<pre className="mt-2 w-[340px] rounded-md bg-slate-950 p-4">
<code className="text-white">{JSON.stringify(data, null, 2)}</code>
</pre>
)
});
}
const [user, setUser] = useState<User | null>();
const [loading, setLoading] = useState(true);

const form = useForm<z.infer<typeof FormSchema>>({
resolver: zodResolver(FormSchema),
defaultValues: {
name: "",
email: ""
}
});

useEffect(() => {
const fetchUser = async () => {
setLoading(true);
try {
const accessToken = await getAccessToken();
const fetchedUser = await getUser(accessToken);
setUser(fetchedUser);
setLoading(false);

if (fetchedUser !== null)
form.reset({
name: fetchedUser.name ?? "",
email: fetchedUser.email ?? ""
});
} catch (error) {
console.error("Failed to fetch user", error);
setLoading(false);
}
};
fetchUser().catch(console.error);
}, []);
if (loading)
return (
<div className="flex h-[calc(100%-32px)] flex-col items-center justify-center p-8 px-6">
<div className="flex size-20 animate-spin items-center justify-center rounded-[50%] border-4 border-x-background border-b-background border-t-primary bg-transparent"></div>
<Image className={"absolute"} src={"/landingLogo.png"} alt={""} width={40} height={40} />
</div>
);
else
return (
<div className="flex h-[calc(100%-32px)] flex-col items-start justify-start p-8 px-6">
<header className="flex w-full flex-row items-center justify-between">
<h1 className="m-4 font-medium text-foreground md:text-2xl">Settings</h1>
</header>
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="ml-6 flex flex-col gap-4 text-foreground">
<FormField
control={form.control}
name="name"
render={({ field }) => (
<FormItem>
<FormLabel>Name</FormLabel>
<FormControl>
<Input className="w-[320px]" placeholder="Name" {...field}></Input>
</FormControl>
<FormDescription>This is your display name.</FormDescription>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="email"
render={({ field }) => (
<FormItem>
<FormLabel>Email</FormLabel>
<FormControl>
<Input className="w-[320px]" placeholder="Email" {...field}></Input>
</FormControl>
<FormDescription>This is your email address.</FormDescription>
<FormMessage />
</FormItem>
)}
/>
<pre>
Your user ID is: <strong>{user?.id}</strong>
</pre>
<Button type="submit" className={"w-1/4 self-end"}>
Submit
</Button>
</form>
</Form>
</div>
);
}

export default Settings;

0 comments on commit c9d43a8

Please sign in to comment.