fix(ui): fix profile screen

This commit is contained in:
shafin-r
2025-07-16 16:25:26 +06:00
parent aa7bc67dc9
commit 32c9065f6f
7 changed files with 385 additions and 4 deletions

View File

@ -0,0 +1,94 @@
"use client";
import ProfileManager from "@/components/ProfileManager";
import { Avatar, AvatarFallback } from "@/components/ui/avatar";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { getToken, API_URL } from "@/lib/auth";
import { ChevronLeft, Edit2, Lock, Save } from "lucide-react";
import { useRouter } from "next/navigation";
import React, { useEffect, useState } from "react";
interface UserData {
name: string;
institution: string;
sscRoll: string;
hscRoll: string;
email: string;
phone: string;
}
const ProfilePage = () => {
const router = useRouter();
const [userData, setUserData] = useState<UserData | undefined>();
const [editStatus, setEditStatus] = useState(false);
useEffect(() => {
async function fetchUser() {
try {
const token = await getToken();
if (!token) return;
const response = await fetch(`${API_URL}/me`, {
method: "GET",
headers: {
Authorization: `Bearer ${token}`,
},
});
if (response.ok) {
const fetchedUserData = await response.json();
setUserData(fetchedUserData);
}
} catch (error) {
console.error("Error fetching user data: ", error);
}
}
fetchUser();
}, []);
return (
<section className="min-h-screen mb-32 ">
<div className="h-48 bg-gradient-to-b from-[#113768] to-white w-full">
<button
onClick={() => router.push("/settings")}
className="absolute top-10 left-6 p-2 bg-black/30 rounded-full"
>
<ChevronLeft size={30} color="white" />
</button>
</div>
<div className="relative mx-10">
<Avatar className="bg-[#113768] w-32 h-32 absolute -top-20 left-1/2 transform -translate-x-1/2">
<AvatarFallback className="text-3xl text-white">
{userData?.name ? userData.name.charAt(0).toUpperCase() : ""}
</AvatarFallback>
</Avatar>
<div className="pt-14 space-y-8">
<ProfileManager userData={userData} edit={editStatus} />
<button
onClick={() => setEditStatus(!editStatus)}
className="p-3 bg-[#113768] w-full flex gap-3 justify-center items-center rounded-full"
>
{editStatus ? (
<Save size={20} color="white" />
) : (
<Edit2 size={20} color="white" />
)}
<p className="text-white">
{editStatus ? "Save Changes" : "Edit Profile"}
</p>
</button>
<button className="p-3 bg-[#113768] w-full flex gap-3 justify-center items-center rounded-full">
<Lock size={20} color="white" />
<p className="text-white">Change Password</p>
</button>
</div>
</div>
</section>
);
};
export default ProfilePage;

View File

@ -3,8 +3,20 @@
import BackgroundWrapper from "@/components/BackgroundWrapper";
import { Avatar, AvatarFallback } from "@/components/ui/avatar";
import { API_URL, getToken } from "@/lib/auth";
import { MoveLeft, UserCircle2 } from "lucide-react";
import Image from "next/image";
import {
Bookmark,
ChartColumn,
ChevronRight,
Clock4,
CreditCard,
Crown,
Globe,
LogOut,
MapPin,
MoveLeft,
Trash2,
UserCircle2,
} from "lucide-react";
import { useRouter } from "next/navigation";
import React, { useEffect, useState } from "react";
@ -28,7 +40,6 @@ const SettingsPage = () => {
if (response.ok) {
const fetchedUserData = await response.json();
setUserData(fetchedUserData);
console.log(fetchedUserData);
}
} catch (error) {
console.error("Error fetching user data: ", error);
@ -63,12 +74,113 @@ const SettingsPage = () => {
: ""}
</AvatarFallback>
</Avatar>
<div className="flex flex-col ">
<div className="flex flex-col items-start">
<h1 className="font-semibold text-2xl">{userData?.name}</h1>
<h3 className=" text-md">{userData?.email}</h3>
</div>
</div>
</section>
<section className="flex flex-col gap-8">
<button
onClick={() => router.push("/profile")}
className="flex justify-between"
>
<div className="flex items-center gap-4">
<UserCircle2 size={30} color="#113768" />
<h3 className="text-md font-medium text-[#113768]">
Your profile
</h3>
</div>
<ChevronRight size={30} color="#113768" />
</button>
<div className="flex justify-between">
<div className="flex items-center gap-4">
<Bookmark size={30} color="#113768" />
<h3 className="text-md font-medium text-[#113768]">
Bookmarks
</h3>
</div>
<ChevronRight size={30} color="#113768" />
</div>
<div className="flex justify-between">
<div className="flex items-center gap-4">
<CreditCard size={30} color="#113768" />
<h3 className="text-md font-medium text-[#113768]">
Payments
</h3>
</div>
<ChevronRight size={30} color="#113768" />
</div>
<div className="h-[0.5px] border-[0.1px] w-full border-[#113768]/20"></div>
<div className="flex justify-between">
<div className="flex items-center gap-4">
<Globe size={30} color="#113768" />
<h3 className="text-md font-medium text-[#113768]">
Languages
</h3>
</div>
<ChevronRight size={30} color="#113768" />
</div>
<div className="flex justify-between">
<div className="flex items-center gap-4">
<MapPin size={30} color="#113768" />
<h3 className="text-md font-medium text-[#113768]">
Location
</h3>
</div>
<ChevronRight size={30} color="#113768" />
</div>
<div className="flex justify-between">
<div className="flex items-center gap-4">
<Crown size={30} color="#113768" />
<h3 className="text-md font-medium text-[#113768]">
Subscription
</h3>
</div>
<ChevronRight size={30} color="#113768" />
</div>
<div className="flex justify-between">
<div className="flex items-center gap-4">
<ChartColumn size={30} color="#113768" />
<h3 className="text-md font-medium text-[#113768]">
Performance
</h3>
</div>
<ChevronRight size={30} color="#113768" />
</div>
<div className="h-[0.5px] border-[0.1px] w-full border-[#113768]/20"></div>
<div className="flex justify-between">
<div className="flex items-center gap-4">
<Trash2 size={30} color="#113768" />
<h3 className="text-md font-medium text-[#113768]">
Clear Cache
</h3>
</div>
<ChevronRight size={30} color="#113768" />
</div>
<div className="flex justify-between">
<div className="flex items-center gap-4">
<Clock4 size={30} color="#113768" />
<h3 className="text-md font-medium text-[#113768]">
Clear History
</h3>
</div>
<ChevronRight size={30} color="#113768" />
</div>
<div className="flex justify-between">
<div className="flex items-center gap-4">
<LogOut size={30} color="#113768" />
<h3 className="text-md font-medium text-[#113768]">
Log out
</h3>
</div>
<ChevronRight size={30} color="#113768" />
</div>
<div className="h-[0.5px] border-[0.1px] w-full border-[#113768]/20"></div>
<p className="text-center text-[#113768]/50 font-medium">
ExamJam | Version 1.0
</p>
</section>
</div>
</div>
</section>

BIN
bun.lockb

Binary file not shown.

View File

@ -0,0 +1,129 @@
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
interface UserData {
name: string;
institution: string;
sscRoll: string;
hscRoll: string;
email: string;
phone: string;
}
interface ProfileManagerProps {
userData: UserData | undefined;
edit: boolean;
}
export default function ProfileManager({
userData,
edit,
}: ProfileManagerProps) {
return (
<div className="mx-auto">
<div className="space-y-4">
<div className="space-y-2">
<Label
htmlFor="name"
className="text-sm font-semibold tracking-tighter text-gray-700"
>
Name
</Label>
<Input
id="name"
type="text"
value={userData?.name}
readOnly
className="bg-gray-50 cursor-default py-6"
disabled={!edit}
/>
</div>
<div className="space-y-2">
<Label
htmlFor="institution"
className="text-sm font-semibold tracking-tighter text-gray-700"
>
Institution
</Label>
<Input
id="institution"
type="text"
value={userData?.institution}
readOnly
className="bg-gray-50 cursor-default py-6"
disabled={!edit}
/>
</div>
<div className="space-y-2">
<Label
htmlFor="sscRoll"
className="text-sm font-semibold tracking-tighter text-gray-700"
>
SSC Roll
</Label>
<Input
id="sscRoll"
type="text"
value={userData?.sscRoll}
readOnly
className="bg-gray-50 cursor-default py-6"
disabled={!edit}
/>
</div>
<div className="space-y-2">
<Label
htmlFor="hscRoll"
className="text-sm font-semibold tracking-tighter text-gray-700"
>
HSC Roll
</Label>
<Input
id="hscRoll"
type="text"
value={userData?.hscRoll}
readOnly
className="bg-gray-50 cursor-default py-6"
disabled={!edit}
/>
</div>
<div className="space-y-2">
<Label
htmlFor="email"
className="text-sm font-semibold tracking-tighter text-gray-700"
>
Email
</Label>
<Input
id="email"
type="email"
value={userData?.email}
readOnly
className="bg-gray-50 cursor-default py-6"
disabled={!edit}
/>
</div>
<div className="space-y-2">
<Label
htmlFor="phone"
className="text-sm font-semibold tracking-tighter text-gray-700"
>
Phone
</Label>
<Input
id="phone"
type="tel"
value={userData?.phone}
readOnly
className="bg-gray-50 cursor-default py-6"
disabled={!edit}
/>
</div>
</div>
</div>
);
}

21
components/ui/input.tsx Normal file
View File

@ -0,0 +1,21 @@
import * as React from "react"
import { cn } from "@/lib/utils"
function Input({ className, type, ...props }: React.ComponentProps<"input">) {
return (
<input
type={type}
data-slot="input"
className={cn(
"file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 border-input flex h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
"focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
"aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
className
)}
{...props}
/>
)
}
export { Input }

24
components/ui/label.tsx Normal file
View File

@ -0,0 +1,24 @@
"use client"
import * as React from "react"
import * as LabelPrimitive from "@radix-ui/react-label"
import { cn } from "@/lib/utils"
function Label({
className,
...props
}: React.ComponentProps<typeof LabelPrimitive.Root>) {
return (
<LabelPrimitive.Root
data-slot="label"
className={cn(
"flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50",
className
)}
{...props}
/>
)
}
export { Label }

View File

@ -10,6 +10,7 @@
},
"dependencies": {
"@radix-ui/react-avatar": "^1.1.10",
"@radix-ui/react-label": "^2.1.7",
"@radix-ui/react-slot": "^1.2.3",
"capacitor-secure-storage-plugin": "^0.11.0",
"clsx": "^2.1.1",