Skip to content

Commit

Permalink
Merge pull request #261 from ufsasewebmaster/kaylee/userinfobox
Browse files Browse the repository at this point in the history
User info box component
  • Loading branch information
T-Joseph-Kim authored Mar 1, 2025
2 parents 9d6cc08 + 7e07b8a commit 992f8f3
Show file tree
Hide file tree
Showing 3 changed files with 149 additions and 47 deletions.
83 changes: 44 additions & 39 deletions src/client/components/profile/ProfileNav.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { cn } from "@/shared/utils";
import { Icon } from "@iconify/react";
import { Link } from "@tanstack/react-router";

const SASE_COLORS = ["saseBlue", "saseGreen"];

interface ProfileNavProps {
profileName?: string;
update: (section: string) => void;
}

const ProfileNav: React.FC<ProfileNavProps> = ({ profileName = "User" }) => {
const ProfileNav: React.FC<ProfileNavProps> = ({ profileName = "User", update }) => {
return (
<div className={cn("flex w-60 flex-col rounded-3xl bg-white p-6 font-redhat shadow-lg")}>
{/* Profile Info */}
Expand All @@ -23,52 +23,57 @@ const ProfileNav: React.FC<ProfileNavProps> = ({ profileName = "User" }) => {

<nav className="flex flex-col space-y-2">
{[
{ icon: "mdi:account-circle-outline", text: "Account", to: "/" },
{ icon: "mdi:information-outline", text: "User Info", to: "/" },
{ icon: "mdi:lock-outline", text: "Security", to: "/" },
{ icon: "mdi:clipboard-check-outline", text: "Attendance", to: "/" },
{ icon: "mdi:file-document-outline", text: "Forms", to: "/" },
{ icon: "mdi:book-open-page-variant-outline", text: "Resources", to: "/" },
{ icon: "mdi:cog-outline", text: "Settings", to: "/" },
{ icon: "mdi:account-circle-outline", text: "Account" },
{ icon: "mdi:information-outline", text: "User Info" },
{ icon: "mdi:lock-outline", text: "Security" },
{ icon: "mdi:clipboard-check-outline", text: "Attendance" },
{ icon: "mdi:file-document-outline", text: "Forms" },
{ icon: "mdi:book-open-page-variant-outline", text: "Resources" },
{ icon: "mdi:cog-outline", text: "Settings" },
].map((item, idx) => (
<NavItem key={idx} icon={item.icon} text={item.text} to={item.to} color={SASE_COLORS[idx % 2]} />
<NavItem key={idx} icon={item.icon} text={item.text} color={SASE_COLORS[idx % 2]} update={update} />
))}
</nav>
</div>
);
};

const NavItem = ({ color, icon, text, to }: { icon: string; text: string; to: string; color: string }) => (
<Link
to={to}
className={cn(
"group relative flex items-center space-x-3 rounded-md p-3 text-left font-redhat transition-transform duration-300 hover:scale-105",
)}
>
<Icon
icon={icon}
className={cn(
"text-3xl text-black transition-colors duration-300",
color === "saseBlue" ? "group-hover:text-saseBlue" : "group-hover:text-saseGreen",
)}
/>
<div className="relative">
<span
const NavItem = ({ color, icon, text, update }: { icon: string; text: string; color: string; update: (section: string) => void }) => {
const setActiveSection = () => {
const section = text.toLowerCase().replace(/\s+/g, "");
update(section);
};

return (
<button
className="group relative flex items-center space-x-3 rounded-md p-3 text-left font-redhat transition-transform duration-300 hover:scale-105"
onClick={setActiveSection}
>
<Icon
icon={icon}
className={cn(
"font-medium text-black transition-all duration-300 group-hover:font-bold",
"text-3xl text-black transition-colors duration-300",
color === "saseBlue" ? "group-hover:text-saseBlue" : "group-hover:text-saseGreen",
)}
>
{text}
</span>
<span
className={cn(
"absolute bottom-0 left-0 h-[2px] w-0 transition-all duration-300 group-hover:w-full",
color === "saseBlue" ? "group-hover:bg-saseBlue" : "group-hover:bg-saseGreen",
)}
></span>
</div>
</Link>
);
/>
<div className="relative">
<span
className={cn(
"font-medium text-black transition-all duration-300 group-hover:font-bold",
color === "saseBlue" ? "group-hover:text-saseBlue" : "group-hover:text-saseGreen",
)}
>
{text}
</span>
<span
className={cn(
"absolute bottom-0 left-0 h-[2px] w-0 transition-all duration-300 group-hover:w-full",
color === "saseBlue" ? "group-hover:bg-saseBlue" : "group-hover:bg-saseGreen",
)}
></span>
</div>
</button>
);
};

export default ProfileNav;
71 changes: 71 additions & 0 deletions src/client/components/profile/UserInfoBox.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { Icon } from "@iconify/react";
import { useState } from "react";

const UserInfoBox = () => {
const [editMode, setEditMode] = useState(false);

return (
<div className="w-3/4 rounded-2xl border border-black bg-white px-10 py-6">
<div className="mb-6 flex flex-row justify-between font-redhat">
<p className="font-redhat text-xl font-bold">User Info</p>
<button className="flex flex-row gap-2 hover:scale-105" onClick={() => setEditMode(true)}>
<Icon icon="material-symbols:edit" width="24" height="24" color="#0668B3" />
<p className="font-semibold text-saseBlue">Edit</p>
</button>
</div>
<div className="flex flex-row justify-between">
<div className="w-1/3">
<div className="mb-4 flex flex-col gap-2">
<p className="pl-2">Name:</p>
<input type="text" placeholder="[First_Last]" className="rounded-md border border-black bg-gray-300 p-2" disabled={!editMode} />
</div>
<div className="mb-4 flex flex-col gap-2">
<p className="pl-2">UFID:</p>
<input type="text" placeholder="[UFID]" className="rounded-md border border-black bg-gray-300 p-2" disabled={!editMode} />
</div>
<div className="mb-4 flex flex-col gap-2">
<p className="pl-2">Bio:</p>
<input type="text" placeholder="[Bio]" className="rounded-md border border-black bg-gray-300 p-2" disabled={!editMode} />
</div>
<div className="mb-4 flex flex-col gap-2">
<p className="pl-2">Discord:</p>
<input type="text" placeholder="[Discord_Username]" className="rounded-md border border-black bg-gray-300 p-2" disabled={!editMode} />
</div>
<div className="mb-4 flex flex-col gap-2">
<p className="pl-2">Roles:</p>
<input
type="text"
placeholder="[Ex. Webdev member, Interns]"
className="rounded-md border border-black bg-gray-300 p-2"
disabled={!editMode}
/>
</div>
</div>
<div className="mr-10 w-1/3">
<div className="mb-4 flex flex-col gap-2">
<p className="pl-2">Email:</p>
<input type="text" placeholder="[Email]" className="rounded-md border border-black bg-gray-300 p-2" disabled={!editMode} />
</div>
<div className="mb-4 flex flex-col">
<p>Password:</p>
<p>[xxxxxxxxxxx]</p>
<p className="text-saseBlue">2FA to reset password</p>
</div>
<div className="relative flex h-1/4 w-1/2 items-center justify-center rounded-full bg-saseBlue">
<Icon icon="mdi:account" className="text-7xl text-saseGreen" />
<div className="absolute bottom-[20%] left-1/2 -translate-x-1/2 transform rounded-full p-2">
<Icon icon="mdi:upload" className="text-5xl text-white" />
</div>
</div>
</div>
</div>
<div className="flex justify-end">
<button className="rounded-md border border-black bg-gray-300 px-4 py-2 font-semibold hover:scale-105" onClick={() => setEditMode(false)}>
Save
</button>
</div>
</div>
);
};

export default UserInfoBox;
42 changes: 34 additions & 8 deletions src/client/routes/profile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,23 @@ import ProfileNav from "@components/profile/ProfileNav";
import { createFileRoute, useNavigate } from "@tanstack/react-router";
import { useEffect, useState } from "react";
import { useAuth } from "../AuthContext";
import UserInfoBox from "../components/profile/UserInfoBox";
import { Button } from "../components/ui/button";

export const Route = createFileRoute("/profile")({
component: () => {
const [profile, setProfile] = useState<{ username: string } | null>(null);
const [isLoading, setIsLoading] = useState<boolean>(true);
const [error, setError] = useState<string | null>(null);
const [activeSection, setActiveSection] = useState({
account: true,
userinfo: false,
security: false,
attendance: false,
forms: false,
resources: false,
settings: false,
});
const { logout } = useAuth();
const navigate = useNavigate();

Expand Down Expand Up @@ -47,29 +57,45 @@ export const Route = createFileRoute("/profile")({
}
};

const updateComponent = (section: string) => {
setActiveSection({
account: false,
userinfo: false,
security: false,
attendance: false,
forms: false,
resources: false,
settings: false,
});

setActiveSection((prev) => ({ ...prev, [section]: true }));
};

if (isLoading) return <div>Loading...</div>;
if (error) return <div>Error: {error}</div>;

return (
<div className="flex min-h-screen bg-gray-100 p-10">
<div className="flex items-start">
<ProfileNav profileName={profile?.username} />
<ProfileNav profileName={profile?.username} update={updateComponent} />
</div>
<div className="flex flex-1 items-center justify-center">
<div className="w-full max-w-md rounded-lg bg-white p-6 shadow-md">
<div className="flex w-full flex-col items-center justify-between py-6">
{activeSection.userinfo ? <UserInfoBox /> : <div className="h-3/4 w-3/4 rounded-xl border border-black"></div>}

{/* <div className="w-full max-w-md rounded-lg bg-white p-6 shadow-md">
<div className="mb-4 flex items-center justify-between">
<h1 className="text-2xl font-bold">Profile</h1>
</div>
<div className="text-center">
<div className="mx-auto mb-4 flex h-24 w-24 items-center justify-center rounded-full bg-blue-500 text-white">
<span className="text-4xl font-bold">{profile?.username?.charAt(0).toUpperCase()}</span>
</div>
<h2 className="text-xl font-semibold">Welcome, {profile?.username}!</h2>
<Button variant="destructive" className="mt-4" onClick={handleLogout}>
Log Out
</Button>
<h2 className="text-xl font-semibold">Welcome, {profile?.username}!</h2>
</div>
</div>
</div> */}
<Button variant="destructive" className="mt-4" onClick={handleLogout}>
Log Out
</Button>
</div>
</div>
);
Expand Down

0 comments on commit 992f8f3

Please sign in to comment.