- Remove OtpGateGuard from transactions controller (OTP verified at login) - Fix categories controller to use authenticated user instead of TEMP_USER_ID - Add comprehensive implementation plan document - Update .env.example with WEB_APP_URL - Prepare for admin dashboard development
7.6 KiB
7.6 KiB
✅ Profile UI Improvements - COMPLETE
🎉 ALL FEATURES IMPLEMENTED:
1. Avatar Upload ✅
- For non-Google users: Upload button on avatar
- For Google users: Avatar synced from Google (no upload)
- Features:
- File type validation (images only)
- File size validation (max 5MB)
- Upload icon with loading state
- Error messages
- Automatic page reload after upload
2. Editable Name ✅
- For non-Google users: Edit button with Save/Cancel
- For Google users: Readonly, synced from Google
- Features:
- Inline editing
- Validation (name cannot be empty)
- Loading states
- Success/error messages
- Automatic page reload after save
3. Email Field ✅
- Always readonly (best practice)
- Reason: Email is primary identifier, changing it causes security risks
- Helper text: "Email cannot be changed"
4. Danger Zone ✅
- Location: Security tab (not Edit Profile)
- Features:
- Red border card
- Warning message
- Password confirmation required
- Two-step confirmation (button → password input)
- Delete button with trash icon
- Loading states
- Error messages
- Automatic logout and redirect after deletion
📊 Email Editability - Best Practices Explained:
❌ Why Email Should NOT Be Editable:
-
Security Risk:
- Email is the primary identifier
- Changing it can enable account takeover
- Requires complex verification flow
-
OAuth Complications:
- Breaks Google OAuth connection
- User loses access to "Continue with Google"
- Requires re-linking accounts
-
Verification Complexity:
- Need to verify NEW email
- Keep OLD email active until verified
- Send notifications to both emails
- Add cooldown period
-
User Confusion:
- Login with old email won't work
- Password reset goes to wrong email
- Support tickets increase
✅ Recommended Approach:
- Keep email readonly
- If user wants different email: Create new account
- Alternative: Add secondary email for notifications (not for login)
🎨 UI Features:
Avatar Section:
- ✅ Larger avatar (20x20)
- ✅ Upload button (bottom-right corner)
- ✅ Conditional display (Google vs non-Google)
- ✅ Loading spinner during upload
- ✅ Helper text explaining sync status
- ✅ Error messages below avatar
Name Field:
- ✅ Conditional editing (Google vs non-Google)
- ✅ Edit/Save/Cancel buttons
- ✅ Inline editing (no modal)
- ✅ Validation messages
- ✅ Loading states
- ✅ Disabled state when not editing
Danger Zone:
- ✅ Red border card
- ✅ Warning icon
- ✅ Clear warning message
- ✅ Two-step confirmation
- ✅ Password input
- ✅ Delete/Cancel buttons
- ✅ Loading states
- ✅ Error handling
🔧 Backend Requirements:
New Endpoints Needed:
-
GET /api/auth/accounts- Check if user has Google OAuth// Returns array of auth accounts [{ provider: 'google', ... }] -
POST /api/users/avatar- Upload avatar// Accepts multipart/form-data // Field name: 'avatar' // Returns updated user with new avatarUrl -
PUT /api/users/profile- Update name (already exists for phone)// Add support for 'name' field { name: string } -
DELETE /api/users/account- Delete account// Requires password confirmation { password: string } // Deletes all user data
📝 Implementation Details:
Google Auth Detection:
const checkGoogleAuth = async () => {
const response = await axios.get(`${API}/auth/accounts`)
const hasGoogle = response.data.some(acc => acc.provider === 'google')
setHasGoogleAuth(hasGoogle)
}
Avatar Upload:
const handleAvatarUpload = async (event) => {
const file = event.target.files?.[0]
// Validate type
if (!file.type.startsWith('image/')) {
setAvatarError("Please select an image file")
return
}
// Validate size (5MB)
if (file.size > 5 * 1024 * 1024) {
setAvatarError("Image size must be less than 5MB")
return
}
const formData = new FormData()
formData.append('avatar', file)
await axios.post(`${API}/users/avatar`, formData, {
headers: { 'Content-Type': 'multipart/form-data' }
})
window.location.reload()
}
Name Update:
const handleUpdateName = async () => {
if (!editedName || editedName.trim().length === 0) {
setNameError("Name cannot be empty")
return
}
await axios.put(`${API}/users/profile`, { name: editedName })
setNameSuccess("Name updated successfully!")
setIsEditingName(false)
window.location.reload()
}
Account Deletion:
const handleDeleteAccount = async () => {
if (!deletePassword) {
setDeleteError("Please enter your password")
return
}
await axios.delete(`${API}/users/account`, {
data: { password: deletePassword }
})
localStorage.removeItem('token')
window.location.href = '/auth/login'
}
🧪 Testing Checklist:
For Google Users:
- Avatar shows Google profile picture
- No upload button on avatar
- Name field is disabled (gray)
- Helper text says "synced from Google"
- Email is readonly
- Phone is editable
- Danger Zone works
For Email/Password Users:
- Avatar shows default icon or uploaded image
- Upload button appears on avatar
- Click upload → file picker opens
- Upload image → avatar updates
- Name field has Edit button
- Click Edit → input becomes editable
- Change name → click Save → name updates
- Click Cancel → changes discarded
- Email is readonly
- Phone is editable
- Danger Zone works
Danger Zone:
- Located in Security tab
- Red border card
- Click "Delete Account" → password input appears
- Enter wrong password → error message
- Enter correct password → account deleted
- Redirects to login page
- Cannot login with deleted account
✅ ESLint:
npm run lint
# ✓ 0 errors, 0 warnings
📊 Files Modified:
apps/web/src/components/pages/Profile.tsx- Added Google auth detection
- Added avatar upload
- Added name editing
- Added danger zone
- Added all handlers and states
🎯 User Experience:
Before:
- All users see same UI
- No way to upload avatar
- No way to edit name
- No way to delete account
- Confusing for non-Google users
After:
- ✅ Conditional UI based on auth method
- ✅ Avatar upload for non-Google users
- ✅ Name editing for non-Google users
- ✅ Clear helper text explaining restrictions
- ✅ Danger zone for account deletion
- ✅ Professional, intuitive interface
🚀 Next Steps:
Backend Implementation Required:
- Create
GET /api/auth/accountsendpoint - Create
POST /api/users/avatarendpoint with multer - Update
PUT /api/users/profileto support name - Create
DELETE /api/users/accountendpoint
Optional Enhancements:
- Avatar cropping before upload
- Image compression
- Multiple avatar options
- Account export before deletion
- Deletion cooldown period (30 days)
🎉 COMPLETE!
All UI improvements implemented:
- ✅ Avatar upload (non-Google users)
- ✅ Editable name (non-Google users)
- ✅ Email readonly (best practice)
- ✅ Danger zone (Security tab)
- ✅ Conditional UI (Google vs non-Google)
- ✅ All validations
- ✅ All error handling
- ✅ ESLint clean
Ready for backend implementation! 🚀