Show date of birth with calculated age in IAM user detail

Adds date_of_birth to UserDetailResponse schema, AdminUserDetail
TypeScript type, and the User Information card in UserDetailSection.
Displays formatted date with age in parentheses (e.g. "3/02/2000 (26)").

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Kyle 2026-03-02 19:58:21 +08:00
parent e8109cef6b
commit 3a456e56dd
3 changed files with 13 additions and 1 deletions

View File

@ -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

View File

@ -117,6 +117,16 @@ export default function UserDetailSection({ userId, onClose }: UserDetailSection
<DetailRow label="Last Name" value={user.last_name} />
<DetailRow label="Email" value={user.email} />
<DetailRow label="Preferred Name" value={user.preferred_name} />
<DetailRow
label="Date of Birth"
value={user.date_of_birth ? (() => {
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}
/>
<DetailRow
label="Created"
value={getRelativeTime(user.created_at)}

View File

@ -237,6 +237,7 @@ export interface AdminUser {
export interface AdminUserDetail extends AdminUser {
active_sessions: number;
preferred_name?: string | null;
date_of_birth?: string | null;
must_change_password?: boolean;
locked_until?: string | null;
}