From d981ff37fb431419038f13d6fd90576465ce554c Mon Sep 17 00:00:00 2001 From: abhishekbhakat Date: Fri, 19 Dec 2025 18:07:01 +0530 Subject: [PATCH] feat: Add optional display name to user profile with corresponding API and UI updates --- backend/src/handlers/users.rs | 9 +++++++++ backend/src/models/user/user.rs | 3 +++ frontend/src/pages/Dashboard.tsx | 20 ++++++++++++++++---- frontend/src/pages/Profile.tsx | 17 ++++++++++++++++- 4 files changed, 44 insertions(+), 5 deletions(-) diff --git a/backend/src/handlers/users.rs b/backend/src/handlers/users.rs index 08b9d75..82a1cef 100644 --- a/backend/src/handlers/users.rs +++ b/backend/src/handlers/users.rs @@ -28,6 +28,7 @@ pub struct CreateUserRequest { /// Request to update a user. #[derive(Deserialize)] pub struct UpdateUserRequest { + pub name: Option, pub height_cm: Option, pub blood_type: Option, pub birthdate: Option, @@ -41,6 +42,7 @@ pub struct UpdateUserRequest { pub struct UserResponse { pub id: i32, pub username: String, + pub name: Option, pub role: String, pub height_cm: Option, pub blood_type: Option, @@ -85,6 +87,7 @@ pub async fn list_users( .map(|u| UserResponse { id: u.id, username: u.username, + name: u.name, role: role_map.get(&u.role_id).cloned().unwrap_or_default(), height_cm: u.height_cm, blood_type: u.blood_type, @@ -130,6 +133,7 @@ pub async fn get_user( Ok(Json(UserResponse { id: u.id, username: u.username, + name: u.name, role: role_name, height_cm: u.height_cm, blood_type: u.blood_type, @@ -211,6 +215,7 @@ pub async fn create_user( Ok(Json(UserResponse { id: inserted.id, username: inserted.username, + name: inserted.name, role: role_name, height_cm: inserted.height_cm, blood_type: inserted.blood_type, @@ -246,6 +251,9 @@ pub async fn update_user( let now = Utc::now().naive_utc(); let mut active: user::ActiveModel = existing.into(); + if req.name.is_some() { + active.name = Set(req.name); + } if req.height_cm.is_some() { active.height_cm = Set(req.height_cm); } @@ -291,6 +299,7 @@ pub async fn update_user( Ok(Json(UserResponse { id: updated.id, username: updated.username, + name: updated.name, role: role_name, height_cm: updated.height_cm, blood_type: updated.blood_type, diff --git a/backend/src/models/user/user.rs b/backend/src/models/user/user.rs index d37c9ca..3d7790f 100644 --- a/backend/src/models/user/user.rs +++ b/backend/src/models/user/user.rs @@ -18,6 +18,9 @@ pub struct Model { /// Foreign key to roles table pub role_id: i32, + /// Display name (optional, separate from username) + pub name: Option, + // Profile fields /// Height in centimeters pub height_cm: Option, diff --git a/frontend/src/pages/Dashboard.tsx b/frontend/src/pages/Dashboard.tsx index 4143b50..817e298 100644 --- a/frontend/src/pages/Dashboard.tsx +++ b/frontend/src/pages/Dashboard.tsx @@ -4,6 +4,7 @@ import { useNavigate, Link } from 'react-router-dom' interface User { id: number username: string + name: string | null role: string } @@ -13,13 +14,21 @@ export function Dashboard() { const [loading, setLoading] = useState(true) useEffect(() => { + // First get auth info, then fetch full user profile for name fetch('/api/auth/me', { credentials: 'include' }) .then(res => res.json()) .then(data => { - if (data.user) { - setUser(data.user) - } else { + if (!data.user) { navigate('/login') + return null + } + // Fetch full user profile to get name + return fetch(`/api/users/${data.user.id}`, { credentials: 'include' }) + .then(res => res.json()) + }) + .then((profile) => { + if (profile) { + setUser(profile) } }) .catch(() => navigate('/login')) @@ -49,6 +58,9 @@ export function Dashboard() { localStorage.setItem('theme', newTheme) } + // Display name or username fallback + const displayName = user.name || user.username + return (
@@ -70,7 +82,7 @@ export function Dashboard() {
-

Welcome, {user.username}

+

Welcome, {displayName}

Role: {user.role}

diff --git a/frontend/src/pages/Profile.tsx b/frontend/src/pages/Profile.tsx index 5fb7833..a2916b7 100644 --- a/frontend/src/pages/Profile.tsx +++ b/frontend/src/pages/Profile.tsx @@ -10,6 +10,7 @@ interface Diet { interface UserProfile { id: number username: string + name: string | null role: string height_cm: number | null blood_type: string | null @@ -29,6 +30,7 @@ export function ProfilePage() { // Form state const [userId, setUserId] = useState(null) const [username, setUsername] = useState('') + const [name, setName] = useState('') const [heightCm, setHeightCm] = useState('') const [bloodType, setBloodType] = useState('') const [birthdate, setBirthdate] = useState('') @@ -55,6 +57,7 @@ export function ProfilePage() { .then((profile: UserProfile) => { setUserId(profile.id) setUsername(profile.username) + setName(profile.name || '') setHeightCm(profile.height_cm?.toString() || '') setBloodType(profile.blood_type || '') setBirthdate(profile.birthdate || '') @@ -82,6 +85,7 @@ export function ProfilePage() { headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({ + name: name || null, height_cm: heightCm ? parseFloat(heightCm) : null, blood_type: bloodType || null, birthdate: birthdate || null, @@ -115,13 +119,24 @@ export function ProfilePage() {
- {/* Username (read-only) */} + {/* Account Info */}

Account

+
+ + setName(e.target.value)} + placeholder="Your full name" + /> +
{/* Physical Info */}