diff --git a/backend/app/api/users.py b/backend/app/api/users.py
index 65f562e..7542d36 100644
--- a/backend/app/api/users.py
+++ b/backend/app/api/users.py
@@ -49,6 +49,7 @@ def login(form_data: OAuth2PasswordRequestForm = Depends(), db: Session = Depend
"id": user.id,
"username": user.username,
"email": user.email,
+ "avatar": user.avatar,
"is_admin": user.is_admin
}
}
@@ -73,6 +74,7 @@ def register_user(user: UserCreate, background_tasks: BackgroundTasks, db: Sessi
db_user = User(
username=user.username,
email=user.email,
+ avatar=user.avatar,
hashed_password=hashed_password,
is_active=is_active,
is_admin=is_admin
@@ -178,6 +180,7 @@ def create_user(user: UserCreate, db: Session = Depends(get_db)):
db_user = User(
username=user.username,
email=user.email,
+ avatar=user.avatar,
hashed_password=get_password_hash(user.password),
is_active=user.is_active,
is_admin=user.is_admin
diff --git a/backend/app/models/user.py b/backend/app/models/user.py
index be26bae..5192ba5 100644
--- a/backend/app/models/user.py
+++ b/backend/app/models/user.py
@@ -10,6 +10,7 @@ class User(Base):
username = Column(String, unique=True, index=True, nullable=False)
email = Column(String, unique=True, index=True, nullable=False)
hashed_password = Column(String, nullable=False)
+ avatar = Column(String, nullable=True) # Store avatar identifier or URL
is_active = Column(Boolean, default=True)
is_admin = Column(Boolean, default=False)
created_at = Column(DateTime(timezone=True), server_default=func.now())
diff --git a/backend/app/schemas/user.py b/backend/app/schemas/user.py
index 2af1c30..3354fe7 100644
--- a/backend/app/schemas/user.py
+++ b/backend/app/schemas/user.py
@@ -5,6 +5,7 @@ from datetime import datetime
class UserBase(BaseModel):
username: str
email: str
+ avatar: Optional[str] = None
is_active: Optional[bool] = True
is_admin: Optional[bool] = False
@@ -14,6 +15,7 @@ class UserCreate(UserBase):
class UserUpdate(BaseModel):
username: Optional[str] = None
email: Optional[str] = None
+ avatar: Optional[str] = None
is_active: Optional[bool] = None
is_admin: Optional[bool] = None
password: Optional[str] = None
diff --git a/frontend/src/components/Sidebar.tsx b/frontend/src/components/Sidebar.tsx
index e98051b..4f493c5 100644
--- a/frontend/src/components/Sidebar.tsx
+++ b/frontend/src/components/Sidebar.tsx
@@ -885,8 +885,12 @@ function SidebarBody() {
}
}}
>
-
-
+
+ {user?.avatar ? (
+

+ ) : (
+
+ )}
{user?.username || t('defaultUser')}
diff --git a/frontend/src/pages/Settings.tsx b/frontend/src/pages/Settings.tsx
index 09f3ce0..604dc32 100644
--- a/frontend/src/pages/Settings.tsx
+++ b/frontend/src/pages/Settings.tsx
@@ -4,14 +4,30 @@ import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Card, CardContent, CardHeader, CardTitle, CardDescription, CardFooter } from "@/components/ui/card";
-import { Save, Loader2 } from "lucide-react";
+import { Save, Loader2, Check } from "lucide-react";
import { api } from "@/lib/api";
import { useAuthStore } from "@/store/authStore";
+const BUILTIN_AVATARS = [
+ "https://api.dicebear.com/7.x/bottts/svg?seed=Felix",
+ "https://api.dicebear.com/7.x/bottts/svg?seed=Aneka",
+ "https://api.dicebear.com/7.x/bottts/svg?seed=Tinkerbell",
+ "https://api.dicebear.com/7.x/bottts/svg?seed=Bella",
+ "https://api.dicebear.com/7.x/bottts/svg?seed=Buster",
+ "https://api.dicebear.com/7.x/bottts/svg?seed=Max",
+ "https://api.dicebear.com/7.x/adventurer/svg?seed=Leo",
+ "https://api.dicebear.com/7.x/adventurer/svg?seed=Oliver",
+ "https://api.dicebear.com/7.x/adventurer/svg?seed=Mia",
+ "https://api.dicebear.com/7.x/adventurer/svg?seed=Lily",
+ "https://api.dicebear.com/7.x/adventurer/svg?seed=Chloe",
+ "https://api.dicebear.com/7.x/adventurer/svg?seed=Simba"
+];
+
export function Settings() {
const { t } = useTranslation();
const { user, updateUser } = useAuthStore();
const [email, setEmail] = useState('');
+ const [avatar, setAvatar] = useState('');
const [password, setPassword] = useState('');
const [confirmPassword, setConfirmPassword] = useState('');
const [isSaving, setIsSaving] = useState(false);
@@ -21,6 +37,7 @@ export function Settings() {
useEffect(() => {
if (user) {
setEmail(user.email || '');
+ setAvatar(user.avatar || '');
}
}, [user]);
@@ -38,7 +55,8 @@ export function Settings() {
setIsSaving(true);
try {
const updateData: any = {
- email: email
+ email: email,
+ avatar: avatar || null
};
if (password) {
@@ -55,8 +73,8 @@ export function Settings() {
setPassword('');
setConfirmPassword('');
- // Update global state with new email
- updateUser({ email: response.email });
+ // Update global state with new email and avatar
+ updateUser({ email: response.email, avatar: response.avatar });
}
} catch (error: any) {
console.error("Failed to save settings", error);
@@ -87,6 +105,28 @@ export function Settings() {
+
+
+ {BUILTIN_AVATARS.map((url) => (
+
setAvatar(url)}
+ >
+

+ {avatar === url && (
+
+
+
+ )}
+
+ ))}
+
+
+
+