feat: Add optional display name to user profile with corresponding API and UI updates
This commit is contained in:
@@ -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 (
|
||||
<div style={{ padding: 'var(--space-lg)' }}>
|
||||
<header style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 'var(--space-xl)' }}>
|
||||
@@ -70,7 +82,7 @@ export function Dashboard() {
|
||||
<div className="card" style={{ marginBottom: 'var(--space-lg)' }}>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start' }}>
|
||||
<div>
|
||||
<h3 style={{ marginBottom: 'var(--space-sm)' }}>Welcome, {user.username}</h3>
|
||||
<h3 style={{ marginBottom: 'var(--space-sm)' }}>Welcome, {displayName}</h3>
|
||||
<p className="text-secondary text-sm">
|
||||
Role: <span className="indicator indicator-info">{user.role}</span>
|
||||
</p>
|
||||
|
||||
@@ -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<number | null>(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() {
|
||||
</header>
|
||||
|
||||
<form onSubmit={handleSubmit}>
|
||||
{/* Username (read-only) */}
|
||||
{/* Account Info */}
|
||||
<div className="card" style={{ marginBottom: 'var(--space-lg)' }}>
|
||||
<h3 style={{ marginBottom: 'var(--space-md)' }}>Account</h3>
|
||||
<div className="form-group">
|
||||
<label>Username</label>
|
||||
<input type="text" className="input" value={username} disabled />
|
||||
</div>
|
||||
<div className="form-group">
|
||||
<label htmlFor="name">Display Name</label>
|
||||
<input
|
||||
id="name"
|
||||
type="text"
|
||||
className="input"
|
||||
value={name}
|
||||
onChange={(e) => setName(e.target.value)}
|
||||
placeholder="Your full name"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Physical Info */}
|
||||
|
||||
Reference in New Issue
Block a user