Skip to content

Commit

Permalink
Merge pull request #280 from UoaWDCC/UABC-274-user-profile-page
Browse files Browse the repository at this point in the history
create user profile page
  • Loading branch information
dyzhuu authored Oct 14, 2024
2 parents f95e123 + 6e8616c commit 226b914
Show file tree
Hide file tree
Showing 3 changed files with 187 additions and 2 deletions.
149 changes: 149 additions & 0 deletions src/app/(dev)/account/client-page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
"use client";

import { useState } from "react";
import { zodResolver } from "@hookform/resolvers/zod";
import { useForm } from "react-hook-form";
import { z } from "zod";

import { BackNavigationBar } from "@/components/BackNavigationBar";
import { TextInput } from "@/components/TextInput";
import { Button } from "@/components/ui/button";
// import { useRouter } from "next/router";
import { cn } from "@/lib/utils";
import type { PlayLevel } from "@/types/types";

interface ClientAccountPageProps {
firstName: string;
lastName: string;
email: string;
playLevel: PlayLevel;
selectedLevel?: PlayLevel;
member: boolean;
}

const PLAY_LEVELS: PlayLevel[] = ["beginner", "intermediate", "advanced"];

const formSchema = z.object({
firstName: z.string().min(1, "Field is required"),
lastName: z.string().min(1, "Field is required"),
playLevel: z.union([
z.literal("beginner"),
z.literal("intermediate"),
z.literal("advanced"),
]),
});

export default function ClientAccountPage({
firstName: initialFirstName,
lastName: initialLastName,
email: initialEmail,
playLevel: initialPlayLevel,
member,
}: ClientAccountPageProps) {
const {
register,
handleSubmit,
formState: { errors, isDirty },
watch,
} = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
defaultValues: {
firstName: initialFirstName,
lastName: initialLastName,
playLevel: initialPlayLevel,
},
});

const [email, setEmail] = useState(initialEmail);

const onSubmit = (data: z.infer<typeof formSchema>) => {
// Handle save functionality
console.log("Saving user data:", data);
};

return (
<div className="mx-4 flex h-dvh flex-col gap-y-4">
<BackNavigationBar title="Account" pathName="/sessions" />

<div className="absolute right-4 top-4 flex h-6 items-center justify-center rounded-full bg-tertiary px-4">
<span className="text-center text-sm font-medium text-tertiary-foreground">
{member ? "Member" : "Non-member"}
</span>
</div>

<div className="flex flex-grow flex-col items-center justify-center">
{/* Profile Settings Tab */}

<div className="mb-4 w-full max-w-[460px] rounded-lg border p-6">
<h2 className="mb-2 text-lg font-bold">Full Name</h2>
<form onSubmit={handleSubmit(onSubmit)} className="space-y-4">
<TextInput
label="First Name"
type="text"
{...register("firstName")}
isError={!!errors.firstName?.message}
errorMessage={errors.firstName?.message}
/>
<TextInput
label="Last Name"
type="text"
{...register("lastName")}
isError={!!errors.lastName?.message}
errorMessage={errors.lastName?.message}
/>

{/* Play Level Selector */}
<h2 className="mb-2 text-lg font-bold">Play Level</h2>
<div className="grid grid-cols-3 gap-2 rounded-md border border-tertiary p-2">
{PLAY_LEVELS.map((level) => (
<label key={level} className="flex items-center">
<input
type="radio"
value={level}
className="hidden"
{...register("playLevel")}
/>
<span
className={cn(
"flex h-12 w-full cursor-pointer items-center justify-center rounded-md text-sm font-semibold capitalize",
watch("playLevel") === level
? "bg-primary text-primary-foreground"
: "border-none bg-background text-foreground"
)}
>
{level}
</span>
</label>
))}
</div>

<Button
type="submit"
className="mt-4 rounded px-4 py-2"
disabled={!isDirty}
>
Save Changes
</Button>
</form>
</div>

{/* Email Address Tab */}
<div className="mb-4 flex w-full max-w-[460px] flex-col items-start justify-between rounded-lg border p-6">
<h2 className="mb-2 text-lg font-bold">Email Address</h2>
<div className="flex w-full flex-col gap-2 break-words md:flex-row md:items-center md:justify-between">
<p>{email}</p>
<div>
<Button variant={"outline"}>Change Email</Button>
</div>
</div>
</div>

{/* Password Tab */}
<div className="mb-4 w-full max-w-[460px] rounded-lg border p-6">
<h2 className="mb-2 text-lg font-bold">Password</h2>
<Button variant={"destructive"}>Change Password</Button>
</div>
</div>
</div>
);
}
39 changes: 37 additions & 2 deletions src/app/(dev)/account/page.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,38 @@
export default function AccountPage() {
return <div>Account Page</div>;
import React from "react";
import { redirect } from "next/navigation";

import type { CurrentUserProps } from "@/lib/hoc/withCurrentUser";
import withCurrentUser from "@/lib/hoc/withCurrentUser";
import { getUserFromId } from "@/services/user";
import type { PlayLevel } from "@/types/types";
import ClientAccountPage from "./client-page";

export const metadata = {
title: "Account Settings - UABC Booking Portal",
};

async function AccountPage({ currentUser }: CurrentUserProps) {
const user = await getUserFromId(currentUser.id);

// Check if the user or any required fields are missing
if (!user || !user.firstName || !user.lastName || !user.email) {
// Redirect to login if any required fields are missing
redirect("/auth/login");
}

const playLevel: PlayLevel = user?.playLevel ?? "beginner";

return (
<div className="flex h-dvh flex-col">
<ClientAccountPage
firstName={user?.firstName || ""}
lastName={user?.lastName || ""}
email={user?.email || ""}
playLevel={playLevel}
member={user?.member || false}
/>
</div>
);
}

export default withCurrentUser(AccountPage);
1 change: 1 addition & 0 deletions src/services/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export async function getUserFromId(userId: string) {
member: true,
verified: true,
prepaidSessions: true,
playLevel: true,
},
});
}
Expand Down

0 comments on commit 226b914

Please sign in to comment.