diff --git a/src/app/u/[handle]/page.tsx b/src/app/u/[handle]/page.tsx index 2700b45..ec0bd89 100644 --- a/src/app/u/[handle]/page.tsx +++ b/src/app/u/[handle]/page.tsx @@ -15,6 +15,7 @@ import { ProfileHeader } from '@/components/profile/profile-header' import { ProfileSkeleton } from '@/components/profile/profile-skeleton' import { getUserProfile, getPublicSettings } from '@/lib/api/client' import { useAuth } from '@/hooks/use-auth' +import { formatDateLong } from '@/lib/format' import type { UserProfile } from '@/lib/api/types' interface UserProfilePageProps { @@ -119,11 +120,7 @@ export default function UserProfilePage({ params }: UserProfilePageProps) { const reputationScore = computeReputation(profile.activity) const postCount = profile.activity.topicCount + profile.activity.replyCount - const joinDate = new Date(profile.firstSeenAt).toLocaleDateString('en-US', { - year: 'numeric', - month: 'long', - day: 'numeric', - }) + const joinDate = formatDateLong(profile.firstSeenAt) return ( diff --git a/src/components/admin/users/user-card.tsx b/src/components/admin/users/user-card.tsx index eeaa30f..c2de8bb 100644 --- a/src/components/admin/users/user-card.tsx +++ b/src/components/admin/users/user-card.tsx @@ -7,6 +7,7 @@ import { Prohibit, WarningCircle } from '@phosphor-icons/react' import { cn } from '@/lib/utils' +import { formatDateShort } from '@/lib/format' import type { AdminUser } from '@/lib/api/types' const ROLE_COLORS: Record = { @@ -15,14 +16,6 @@ const ROLE_COLORS: Record = { member: 'bg-muted text-muted-foreground', } -function formatDate(dateStr: string) { - return new Date(dateStr).toLocaleDateString('en-US', { - month: 'short', - day: 'numeric', - year: 'numeric', - }) -} - interface UserCardProps { user: AdminUser onBan: (did: string) => void @@ -61,7 +54,7 @@ export function UserCard({ user, onBan, onUnban }: UserCardProps) { {user.topicCount} topics {user.replyCount} replies {user.reportCount} reports - Joined {formatDate(user.firstSeenAt)} + Joined {formatDateShort(user.firstSeenAt)} {user.bannedFromOtherCommunities > 0 && (

diff --git a/src/components/profile/profile-header.test.tsx b/src/components/profile/profile-header.test.tsx index 85624d4..c77427f 100644 --- a/src/components/profile/profile-header.test.tsx +++ b/src/components/profile/profile-header.test.tsx @@ -290,18 +290,22 @@ describe('ProfileHeader', () => { }) it('renders AT Protocol account creation date when accountCreatedAt is set', () => { - render( + const { container } = render( ) - expect(screen.getByText(/since June 15, 2024/i)).toBeInTheDocument() + const timeEl = container.querySelector('time[datetime="2024-06-15T10:30:00.000Z"]') + expect(timeEl).toBeInTheDocument() + expect(timeEl).toHaveTextContent('June 15, 2024') }) it('does not render AT Protocol account creation date when accountCreatedAt is null', () => { - render() - expect(screen.queryByText(/since/i)).not.toBeInTheDocument() + const { container } = render( + + ) + expect(container.querySelector('time')).not.toBeInTheDocument() }) it('renders labels section when labels are present', () => { diff --git a/src/components/profile/profile-stats.tsx b/src/components/profile/profile-stats.tsx index 399e2f5..1acab09 100644 --- a/src/components/profile/profile-stats.tsx +++ b/src/components/profile/profile-stats.tsx @@ -6,6 +6,7 @@ import { Users, ArrowSquareOut, CalendarBlank } from '@phosphor-icons/react' import { formatCount } from '@/lib/format-count' +import { formatDateLong } from '@/lib/format' import type { UserProfile } from '@/lib/api/types' interface ProfileStatsProps { @@ -15,11 +16,7 @@ interface ProfileStatsProps { export function ProfileStats({ profile, handle }: ProfileStatsProps) { const accountCreatedDate = profile.accountCreatedAt - ? new Date(profile.accountCreatedAt).toLocaleDateString('en-US', { - year: 'numeric', - month: 'long', - day: 'numeric', - }) + ? formatDateLong(profile.accountCreatedAt) : null return ( @@ -42,7 +39,7 @@ export function ProfileStats({ profile, handle }: ProfileStatsProps) { {accountCreatedDate && ( )} diff --git a/src/lib/format.ts b/src/lib/format.ts index d090907..ead3176 100644 --- a/src/lib/format.ts +++ b/src/lib/format.ts @@ -52,6 +52,17 @@ export function formatDateShort(dateStr: string): string { }) } +/** + * Formats an ISO date string as a long date (e.g., "January 15, 2026"). + */ +export function formatDateLong(dateStr: string): string { + return new Date(dateStr).toLocaleDateString('en-US', { + year: 'numeric', + month: 'long', + day: 'numeric', + }) +} + /** * Formats a number with locale-aware separators (e.g., 1,234). */ diff --git a/src/mocks/data.ts b/src/mocks/data.ts index a85c141..9ef5101 100644 --- a/src/mocks/data.ts +++ b/src/mocks/data.ts @@ -1036,6 +1036,7 @@ export const mockUserProfiles: Record = { role: 'admin', firstSeenAt: TWO_DAYS_AGO, lastActiveAt: NOW, + accountCreatedAt: null, followersCount: 150, followsCount: 75, atprotoPostsCount: 230, @@ -1065,6 +1066,7 @@ export const mockUserProfiles: Record = { role: 'moderator', firstSeenAt: TWO_DAYS_AGO, lastActiveAt: YESTERDAY, + accountCreatedAt: null, followersCount: 30, followsCount: 20, atprotoPostsCount: 45,