diff --git a/backend/app/schemas/admin.py b/backend/app/schemas/admin.py index ca0c781..fa52d2a 100644 --- a/backend/app/schemas/admin.py +++ b/backend/app/schemas/admin.py @@ -5,7 +5,7 @@ All admin-facing request/response shapes live here to keep the admin router clean and testable in isolation. """ import re -from datetime import datetime +from datetime import date, datetime from typing import Optional, Literal from pydantic import BaseModel, ConfigDict, Field, field_validator @@ -42,6 +42,7 @@ class UserListResponse(BaseModel): class UserDetailResponse(UserListItem): preferred_name: Optional[str] = None + date_of_birth: Optional[date] = None must_change_password: bool = False locked_until: Optional[datetime] = None diff --git a/frontend/src/components/admin/UserDetailSection.tsx b/frontend/src/components/admin/UserDetailSection.tsx index 0f09563..83bdc7a 100644 --- a/frontend/src/components/admin/UserDetailSection.tsx +++ b/frontend/src/components/admin/UserDetailSection.tsx @@ -117,6 +117,16 @@ export default function UserDetailSection({ userId, onClose }: UserDetailSection + { + const dob = new Date(user.date_of_birth + 'T00:00:00'); + const now = new Date(); + let age = now.getFullYear() - dob.getFullYear(); + if (now.getMonth() < dob.getMonth() || (now.getMonth() === dob.getMonth() && now.getDate() < dob.getDate())) age--; + return `${dob.toLocaleDateString()} (${age})`; + })() : null} + />