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:
parent
e8109cef6b
commit
3a456e56dd
@ -5,7 +5,7 @@ All admin-facing request/response shapes live here to keep the admin router
|
|||||||
clean and testable in isolation.
|
clean and testable in isolation.
|
||||||
"""
|
"""
|
||||||
import re
|
import re
|
||||||
from datetime import datetime
|
from datetime import date, datetime
|
||||||
from typing import Optional, Literal
|
from typing import Optional, Literal
|
||||||
|
|
||||||
from pydantic import BaseModel, ConfigDict, Field, field_validator
|
from pydantic import BaseModel, ConfigDict, Field, field_validator
|
||||||
@ -42,6 +42,7 @@ class UserListResponse(BaseModel):
|
|||||||
|
|
||||||
class UserDetailResponse(UserListItem):
|
class UserDetailResponse(UserListItem):
|
||||||
preferred_name: Optional[str] = None
|
preferred_name: Optional[str] = None
|
||||||
|
date_of_birth: Optional[date] = None
|
||||||
must_change_password: bool = False
|
must_change_password: bool = False
|
||||||
locked_until: Optional[datetime] = None
|
locked_until: Optional[datetime] = None
|
||||||
|
|
||||||
|
|||||||
@ -117,6 +117,16 @@ export default function UserDetailSection({ userId, onClose }: UserDetailSection
|
|||||||
<DetailRow label="Last Name" value={user.last_name} />
|
<DetailRow label="Last Name" value={user.last_name} />
|
||||||
<DetailRow label="Email" value={user.email} />
|
<DetailRow label="Email" value={user.email} />
|
||||||
<DetailRow label="Preferred Name" value={user.preferred_name} />
|
<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
|
<DetailRow
|
||||||
label="Created"
|
label="Created"
|
||||||
value={getRelativeTime(user.created_at)}
|
value={getRelativeTime(user.created_at)}
|
||||||
|
|||||||
@ -237,6 +237,7 @@ export interface AdminUser {
|
|||||||
export interface AdminUserDetail extends AdminUser {
|
export interface AdminUserDetail extends AdminUser {
|
||||||
active_sessions: number;
|
active_sessions: number;
|
||||||
preferred_name?: string | null;
|
preferred_name?: string | null;
|
||||||
|
date_of_birth?: string | null;
|
||||||
must_change_password?: boolean;
|
must_change_password?: boolean;
|
||||||
locked_until?: string | null;
|
locked_until?: string | null;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user