feat: Add profile editing (bio) to settings page

This commit is contained in:
fullsizemalt 2025-12-20 02:36:05 -08:00
parent 3575ac4700
commit f9cdd626f4
2 changed files with 86 additions and 0 deletions

View file

@ -1,6 +1,7 @@
from typing import List, Optional
from fastapi import APIRouter, Depends, HTTPException, Query
from sqlmodel import Session, select, func
from pydantic import BaseModel
from database import get_session
from models import User, Review, Attendance, Group, GroupMember, Show
from schemas import UserRead, ReviewRead, ShowRead, GroupRead
@ -8,6 +9,27 @@ from auth import get_current_user
router = APIRouter(prefix="/users", tags=["users"])
class UserProfileUpdate(BaseModel):
bio: Optional[str] = None
avatar: Optional[str] = None
@router.patch("/me", response_model=UserRead)
def update_my_profile(
update: UserProfileUpdate,
current_user: User = Depends(get_current_user),
session: Session = Depends(get_session)
):
"""Update current user's bio and avatar"""
if update.bio is not None:
current_user.bio = update.bio
if update.avatar is not None:
current_user.avatar = update.avatar
session.add(current_user)
session.commit()
session.refresh(current_user)
return current_user
# --- User Stats ---
@router.get("/{user_id}/stats")

View file

@ -1,12 +1,50 @@
"use client"
import { useState, useEffect } from "react"
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
import { Label } from "@/components/ui/label"
import { Switch } from "@/components/ui/switch"
import { Input } from "@/components/ui/input"
import { Textarea } from "@/components/ui/textarea"
import { Button } from "@/components/ui/button"
import { usePreferences } from "@/contexts/preferences-context"
import { useAuth } from "@/contexts/auth-context"
import { getApiUrl } from "@/lib/api-config"
export default function SettingsPage() {
const { preferences, updatePreferences, loading } = usePreferences()
const { user } = useAuth()
const [bio, setBio] = useState("")
const [saving, setSaving] = useState(false)
const [saved, setSaved] = useState(false)
useEffect(() => {
if (user?.bio) {
setBio(user.bio)
}
}, [user])
const handleSaveProfile = async () => {
setSaving(true)
setSaved(false)
const token = localStorage.getItem("token")
try {
await fetch(`${getApiUrl()}/users/me`, {
method: "PATCH",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${token}`
},
body: JSON.stringify({ bio })
})
setSaved(true)
setTimeout(() => setSaved(false), 2000)
} catch (e) {
console.error(e)
} finally {
setSaving(false)
}
}
if (loading) {
return <div>Loading settings...</div>
@ -16,6 +54,32 @@ export default function SettingsPage() {
<div className="max-w-2xl mx-auto space-y-6">
<h1 className="text-3xl font-bold tracking-tight">Settings</h1>
{/* Profile Section */}
<Card>
<CardHeader>
<CardTitle>Profile</CardTitle>
<CardDescription>
Tell other fans about yourself.
</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<div className="space-y-2">
<Label htmlFor="bio">Bio</Label>
<Textarea
id="bio"
placeholder="Been following the band since 2019..."
value={bio}
onChange={(e) => setBio(e.target.value)}
rows={3}
/>
</div>
<Button onClick={handleSaveProfile} disabled={saving}>
{saving ? "Saving..." : saved ? "Saved ✓" : "Save Profile"}
</Button>
</CardContent>
</Card>
{/* Preferences Section */}
<Card>
<CardHeader>
<CardTitle>Preferences</CardTitle>