diff --git a/frontend/src/app/profile/page.tsx b/frontend/src/app/profile/page.tsx index ea5fc8ec2..52e2de893 100644 --- a/frontend/src/app/profile/page.tsx +++ b/frontend/src/app/profile/page.tsx @@ -3,14 +3,16 @@ import DashboardTemplate from "@/components/templates/DashboardTemplate"; import React, { useEffect, useState } from "react"; import Switch from '@mui/material/Switch'; import Person from "@mui/icons-material/Person"; -import ModeEditIcon from '@mui/icons-material/ModeEdit'; + import auth from "@/utils/firebase-client"; import { onAuthStateChanged } from "firebase/auth"; +import { useRouter } from "next/navigation"; const apiBase = process.env.NEXT_PUBLIC_API_BASE || "http://localhost:8000"; type CurrentUser = { + id: string; firstName: string; lastName: string; email: string; @@ -26,7 +28,7 @@ interface ProfileFieldProps { const ProfileField: React.FC = ({ label, value }) => (

{label}

-

{value}

+

{value || "Not set"}

); @@ -38,11 +40,9 @@ const SectionHeader: React.FC = ({ title }) => (

{title}

); - -// Listen for Firebase auth changes, and whenever a user is logged in, -// call /auth/login with their ID token to load and store the full user record from the backend. const ProfilePage = () => { const [user, setUser] = useState(null); + const router = useRouter(); useEffect(() => { const unsubscribe = onAuthStateChanged(auth, async (firebaseUser) => { @@ -56,10 +56,7 @@ const ProfilePage = () => { method: "GET", headers: { Authorization: `Bearer ${token}` }, }); - if (!res.ok) { - console.error("Failed to load profile user", res.status); - return; - } + if (!res.ok) return; const data = await res.json(); setUser(data.user); } catch (err) { @@ -80,42 +77,35 @@ const ProfilePage = () => {
- {/* Container for profile content */}
{/* Section: Your Profile */}

Your Profile

-
+
- {/* Profile image placeholder with checkerboard background */} + {/* Profile image placeholder */}
-
{/* Personal Info section */}

Personal Information

-
- - + +
@@ -128,14 +118,8 @@ const ProfilePage = () => {
- - + +
@@ -146,7 +130,6 @@ const ProfilePage = () => {
Add more security to your account by enabling Two Factor Authentication. When logging in, you will need to enter a code generated by your preferred authenticator app.
- {/* Toggle Switch aligned top-right */}
Enabled @@ -158,4 +141,4 @@ const ProfilePage = () => { ); }; -export default ProfilePage; \ No newline at end of file +export default ProfilePage; diff --git a/frontend/src/app/settings/page.tsx b/frontend/src/app/settings/page.tsx index 1ca50eb3f..6e610f1ea 100644 --- a/frontend/src/app/settings/page.tsx +++ b/frontend/src/app/settings/page.tsx @@ -2,7 +2,6 @@ import { useEffect, useState } from 'react'; import DashboardTemplate from '@/components/templates/DashboardTemplate'; -import Input from '@/components/atoms/Input'; import auth from '@/utils/firebase-client'; import { onAuthStateChanged, signOut } from 'firebase/auth'; import { useRouter } from 'next/navigation'; @@ -10,6 +9,7 @@ import api from '@/utils/api'; const apiBase = process.env.NEXT_PUBLIC_API_BASE || 'http://localhost:8000'; type CurrentUser = { + id: string; firstName: string; lastName: string; email: string; @@ -20,6 +20,11 @@ type CurrentUser = { export default function SettingsPage() { const [activeTab, setActiveTab] = useState<'funds' | 'account'>('account'); const [user, setUser] = useState(null); + const [editing, setEditing] = useState(false); + const [formData, setFormData] = useState({ firstName: '', lastName: '', email: '', phoneNumber: '' }); + const [saving, setSaving] = useState(false); + const [saveError, setSaveError] = useState(null); + const [saveSuccess, setSaveSuccess] = useState(false); const router = useRouter(); const handleLogout = async () => { @@ -30,25 +35,19 @@ export default function SettingsPage() { router.push('/auth/login'); }; - // Load current user from backend using Firebase auth state useEffect(() => { const unsubscribe = onAuthStateChanged(auth, async (firebaseUser) => { try { - if (!firebaseUser) { - setUser(null); - return; - } + if (!firebaseUser) { setUser(null); return; } const token = await firebaseUser.getIdToken(); const res = await fetch(`${apiBase}/auth/login`, { method: 'GET', headers: { Authorization: `Bearer ${token}` }, }); - if (!res.ok) { - console.error('Failed to fetch user in settings', res.status); - return; - } + if (!res.ok) { console.error('Failed to fetch user in settings', res.status); return; } const data = await res.json(); setUser(data.user); + setFormData({ firstName: data.user.firstName ?? '', lastName: data.user.lastName ?? '', email: data.user.email ?? '', phoneNumber: '' }); } catch (err) { console.error('Error loading user in settings', err); } @@ -56,154 +55,174 @@ export default function SettingsPage() { return () => unsubscribe(); }, []); + const handleChange = (e: React.ChangeEvent) => { + setFormData({ ...formData, [e.target.name]: e.target.value }); + setSaveError(null); + setSaveSuccess(false); + }; + + const handleSave = async () => { + if (!user) return; + setSaving(true); + setSaveError(null); + setSaveSuccess(false); + try { + const res = await api.patch(`/users/${user.id}`, { + firstName: formData.firstName, + lastName: formData.lastName, + email: formData.email, + }); + setUser({ ...user, ...res.data }); + setEditing(false); + setSaveSuccess(true); + } catch (err: any) { + setSaveError(err?.response?.data?.error ?? 'Failed to save changes.'); + } finally { + setSaving(false); + } + }; + + const handleCancel = () => { + if (user) setFormData({ firstName: user.firstName, lastName: user.lastName, email: user.email, phoneNumber: '' }); + setSaveError(null); + setSaveSuccess(false); + setEditing(false); + }; + return (
-

Settings

- - {/* Tabs */} -
- - -
- - {/* Content */} -
- {activeTab === 'funds' ? ( -

Fund Settings will go here.

- ) : ( -
- {/* Your Profile */} -
-

Your profile

-
- {/* Upload box */} -
- - - - -
+

Settings

- {/* Text */} -
-

Add a profile photo

-

Recommended dimensions are 1600 × 1600

-
-
- - {/* Fields */} -
-
- - -
-
- - + {/* Tabs */} +
+ + +
+ + {/* Content */} +
+ {activeTab === 'funds' ? ( +

Fund Settings will go here.

+ ) : ( +
+ + {/* Your Profile */} +
+
+

Your profile

+ {!editing ? ( + + ) : ( +
+ + +
+ )}
-
- - -

- This was assigned by your administrator -

+ + {saveError &&

{saveError}

} + {saveSuccess &&

Profile updated successfully.

} + +
+
+ + {editing ? ( + + ) : ( +

{user?.firstName ?? '—'}

+ )} +
+
+ + {editing ? ( + + ) : ( +

{user?.lastName ?? '—'}

+ )} +
+
+ +

{user?.role ?? '—'}

+

This was assigned by your administrator

+
+
+ + {editing ? ( + + ) : ( +

{user?.email ?? '—'}

+ )} +
+
+ + {editing ? ( + + ) : ( +

{formData.phoneNumber || '—'}

+ )} +
-
- - +
+ + {/* Password */} +
+

Password

+
+ +
-
-
- - {/* Contact Info */} -
-

Additional contact information

- - -
- - {/* Password */} -
-

Password

-
- - -
-
- - {/* 2FA Security */} -
-

Account Security

-

- Make your account more secure through double verification -

- -
- - {/* Logout */} -
-

Account

- -
-
- )} -
-
+
+ + {/* 2FA Security */} +
+

Account Security

+

+ Make your account more secure through double verification +

+ +
+ + {/* Logout */} +
+

Account

+ +
+ +
+ )} +
+ ); } diff --git a/frontend/src/components/organisms/ProfilePage.tsx b/frontend/src/components/organisms/ProfilePage.tsx deleted file mode 100644 index 10642fd37..000000000 --- a/frontend/src/components/organisms/ProfilePage.tsx +++ /dev/null @@ -1,244 +0,0 @@ -"use client"; - -import React, { useState } from "react"; -import Button from "../atoms/Button"; -import { useMediaQuery } from "@mui/material"; -import { Info as InfoIcon } from "@mui/icons-material"; -import { signOut } from "firebase/auth"; -import auth from "@/utils/firebase-client"; -import api from "@/utils/api"; -import { useRouter } from "next/navigation"; - -type FormData = { - firstName: string; - lastName: string; - role: string; - email: string; - phoneNumber: string; -}; - -const ProfilePage = () => { - const isMobile = useMediaQuery("(max-width: 768px)"); - const router = useRouter(); - - const handleLogout = async () => { - try { - await api.post("/auth/logout", {}); - } catch {} - await signOut(auth); - router.push("/auth/login"); - }; - - const [formData, setFormData] = useState({ - firstName: "Janice", - lastName: "Smith", - role: "Analyst", - email: "jsmith@gmail.com", - phoneNumber: "", - }); - - const handleChange = (e: React.ChangeEvent) => { - const { name, value } = e.target; - setFormData({ ...formData, [name]: value }); - }; - - return ( -
-
-
-

- Your Profile -

- {/* First and Last Name */} -
-
- - -
-
- - -
-
-
- - {/* Role and Email */} -
-
- - - - - This was assigned by your administrator - -
-
- - -
-
- - {/* Password Section */} -
-

- Password -

-
- - -
-
- - {/* Logout */} -
-

- Account -

- -
-
-
- ); -}; - -export default ProfilePage;