do to formatters

This commit is contained in:
2026-01-24 01:07:43 +01:00
parent ae59df61eb
commit 891b3cf0ee
140 changed files with 656 additions and 1159 deletions

View File

@@ -1,8 +1,8 @@
import { DateFormatter } from '@/lib/formatters/DateFormatter';
import { Card } from '@/ui/Card';
import { Text } from '@/ui/Text';
import { Group } from '@/ui/Group';
import { Stack } from '@/ui/Stack';
import { DateDisplay } from '@/lib/display-objects/DateDisplay';
import { Text } from '@/ui/Text';
interface AchievementCardProps {
title: string;
@@ -36,7 +36,7 @@ export function AchievementCard({
<Text weight="medium" variant="high">{title}</Text>
<Text size="xs" variant="med">{description}</Text>
<Text size="xs" variant="low">
{DateDisplay.formatShort(unlockedAt)}
{DateFormatter.formatShort(unlockedAt)}
</Text>
</Stack>
</Group>

View File

@@ -1,15 +1,13 @@
import { AchievementDisplay } from '@/lib/display-objects/AchievementDisplay';
import { AchievementFormatter } from '@/lib/formatters/AchievementFormatter';
import { Card } from '@/ui/Card';
import { Grid } from '@/ui/Grid';
import { Group } from '@/ui/Group';
import { Heading } from '@/ui/Heading';
import { Icon } from '@/ui/Icon';
import { Group } from '@/ui/Group';
import { Stack } from '@/ui/Stack';
import { Box } from '@/ui/Box';
import { Surface } from '@/ui/Surface';
import { Text } from '@/ui/Text';
import { Award, Crown, Medal, Star, Target, Trophy, Zap } from 'lucide-react';
import React from 'react';
interface Achievement {
id: string;
@@ -53,7 +51,7 @@ export function AchievementGrid({ achievements }: AchievementGridProps) {
<Grid cols={1} gap={4}>
{achievements.map((achievement) => {
const AchievementIcon = getAchievementIcon(achievement.icon);
const rarity = AchievementDisplay.getRarityVariant(achievement.rarity);
const rarity = AchievementFormatter.getRarityVariant(achievement.rarity);
return (
<Card
key={achievement.id}

View File

@@ -1,26 +1,24 @@
'use client';
import { DateDisplay } from '@/lib/display-objects/DateDisplay';
import { DateFormatter } from '@/lib/formatters/DateFormatter';
import { AdminUsersViewData } from '@/lib/view-data/AdminUsersViewData';
import { Badge } from '@/ui/Badge';
import { Button } from '@/ui/Button';
import { DriverIdentity } from '@/ui/DriverIdentity';
import { Group } from '@/ui/Group';
import { IconButton } from '@/ui/IconButton';
import { SimpleCheckbox } from '@/ui/SimpleCheckbox';
import { Badge } from '@/ui/Badge';
import { Box } from '@/ui/Box';
import { Group } from '@/ui/Group';
import { DriverIdentity } from '@/ui/DriverIdentity';
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow
} from '@/ui/Table';
import { Text } from '@/ui/Text';
import { MoreVertical, Trash2 } from 'lucide-react';
import { UserStatusTag } from './UserStatusTag';
import React from 'react';
interface AdminUsersTableProps {
users: AdminUsersViewData['users'];
@@ -102,7 +100,7 @@ export function AdminUsersTable({
</TableCell>
<TableCell>
<Text size="sm" variant="low">
{user.lastLoginAt ? DateDisplay.formatShort(user.lastLoginAt) : 'Never'}
{user.lastLoginAt ? DateFormatter.formatShort(user.lastLoginAt) : 'Never'}
</Text>
</TableCell>
<TableCell>

View File

@@ -1,6 +1,6 @@
import { CountryFlagDisplay } from '@/lib/display-objects/CountryFlagDisplay';
import { CountryFlagFormatter } from '@/lib/formatters/CountryFlagFormatter';
import { Badge } from '@/ui/Badge';
import { Icon } from '@/ui/Icon';
import { Image } from '@/ui/Image';
@@ -88,7 +88,7 @@ export function DriverEntryRow({
justifyContent="center"
fontSize="0.625rem"
>
{CountryFlagDisplay.fromCountryCode(country).toString()}
{CountryFlagFormatter.fromCountryCode(country).toString()}
</Stack>
</Stack>

View File

@@ -1,16 +1,16 @@
import { mediaConfig } from '@/lib/config/mediaConfig';
import { CountryFlagDisplay } from '@/lib/display-objects/CountryFlagDisplay';
import { CountryFlagFormatter } from '@/lib/formatters/CountryFlagFormatter';
import { Box } from '@/ui/Box';
import { Button } from '@/ui/Button';
import { Heading } from '@/ui/Heading';
import { Icon } from '@/ui/Icon';
import { Image } from '@/ui/Image';
import { Link } from '@/ui/Link';
import { Stack } from '@/ui/Stack';
import { Surface } from '@/ui/Surface';
import { Text } from '@/ui/Text';
import { Box } from '@/ui/Box';
import { Icon } from '@/ui/Icon';
import { Calendar, Clock, ExternalLink, Globe, Star, Trophy, UserPlus } from 'lucide-react';
interface ProfileHeroProps {
@@ -93,7 +93,7 @@ export function ProfileHero({
<Stack direction="row" align="center" gap={3} wrap mb={2}>
<Heading level={1}>{driver.name}</Heading>
<Text size="4xl" aria-label={`Country: ${driver.country}`}>
{CountryFlagDisplay.fromCountryCode(driver.country).toString()}
{CountryFlagFormatter.fromCountryCode(driver.country).toString()}
</Text>
</Stack>

View File

@@ -11,52 +11,41 @@ import { Input } from '@/ui/Input';
import { Stack } from '@/ui/Stack';
import { Text } from '@/ui/Text';
import {
Activity,
AlertTriangle,
Bug,
ChevronDown,
Clock,
Copy,
Cpu,
Download,
FileText,
Globe,
RefreshCw,
Search,
Terminal,
Trash2,
Zap
Activity,
AlertTriangle,
Bug,
ChevronDown,
Clock,
Copy,
Cpu,
Download,
FileText,
Globe,
RefreshCw,
Search,
Terminal,
Trash2,
Zap
} from 'lucide-react';
import { useEffect, useState } from 'react';
import { DateDisplay } from '@/lib/display-objects/DateDisplay';
import { DurationDisplay } from '@/lib/display-objects/DurationDisplay';
import { MemoryDisplay } from '@/lib/display-objects/MemoryDisplay';
import { PercentDisplay } from '@/lib/display-objects/PercentDisplay';
import { TimeDisplay } from '@/lib/display-objects/TimeDisplay';
import { DateFormatter } from '@/lib/formatters/DateFormatter';
import { DurationFormatter } from '@/lib/formatters/DurationFormatter';
import { MemoryFormatter } from '@/lib/formatters/MemoryFormatter';
import { PercentFormatter } from '@/lib/formatters/PercentFormatter';
interface ErrorAnalyticsDashboardProps {
/**
* Auto-refresh interval in milliseconds
*/
refreshInterval?: number;
/**
* Whether to show in production (default: false)
*/
showInProduction?: boolean;
}
function formatDuration(duration: number): string {
return DurationDisplay.formatMs(duration);
return DurationFormatter.formatMs(duration);
}
function formatPercentage(value: number, total: number): string {
if (total === 0) return '0%';
return PercentDisplay.format(value / total);
return PercentFormatter.format(value / total);
}
function formatMemory(bytes: number): string {
return MemoryDisplay.formatMB(bytes);
return MemoryFormatter.formatMB(bytes);
}
interface PerformanceWithMemory extends Performance {
@@ -327,7 +316,7 @@ export function ErrorAnalyticsDashboard({
<Stack display="flex" justifyContent="between" alignItems="start" gap={2} mb={1}>
<Text size="xs" font="mono" weight="bold" color="text-red-400" truncate>{error.type}</Text>
<Text size="xs" color="text-gray-500" fontSize="10px">
{DateDisplay.formatTime(error.timestamp)}
{DateFormatter.formatTime(error.timestamp)}
</Text>
</Stack>
<Text size="xs" color="text-gray-300" block mb={1}>{error.message}</Text>

View File

@@ -1,11 +1,11 @@
'use client';
import React, { useEffect, useState } from 'react';
import { TimeFormatter } from '@/lib/formatters/TimeFormatter';
import { Button } from '@/ui/Button';
import { FeedItem } from '@/ui/FeedItem';
import { Text } from '@/ui/Text';
import { Stack } from '@/ui/Stack';
import { TimeDisplay } from '@/lib/display-objects/TimeDisplay';
import { Text } from '@/ui/Text';
import { useEffect, useState } from 'react';
interface FeedItemData {
id: string;
@@ -50,7 +50,7 @@ export function FeedItemCard({ item }: FeedItemCardProps) {
name: actor?.name || 'Unknown',
avatar: actor?.avatarUrl
}}
timestamp={TimeDisplay.timeAgo(item.timestamp)}
timestamp={TimeFormatter.timeAgo(item.timestamp)}
content={
<Stack gap={2}>
<Text weight="bold" variant="high">{item.headline}</Text>

View File

@@ -1,14 +1,14 @@
import { FeedList } from '@/components/feed/FeedList';
import { LatestResultsSidebar } from '@/components/races/LatestResultsSidebar';
import { UpcomingRacesSidebar } from '@/components/races/UpcomingRacesSidebar';
import { DateFormatter } from '@/lib/formatters/DateFormatter';
import { Card } from '@/ui/Card';
import { Container } from '@/ui/Container';
import { Heading } from '@/ui/Heading';
import { Grid } from '@/ui/Grid';
import { Stack } from '@/ui/Stack';
import { Heading } from '@/ui/Heading';
import { Section } from '@/ui/Section';
import { Stack } from '@/ui/Stack';
import { Text } from '@/ui/Text';
import { DateDisplay } from '@/lib/display-objects/DateDisplay';
interface FeedItemData {
id: string;
@@ -49,12 +49,12 @@ export function FeedLayout({
}: FeedLayoutProps) {
const formattedUpcomingRaces = upcomingRaces.map(r => ({
...r,
formattedDate: DateDisplay.formatShort(r.scheduledAt),
formattedDate: DateFormatter.formatShort(r.scheduledAt),
}));
const formattedLatestResults = latestResults.map(r => ({
...r,
formattedDate: DateDisplay.formatShort(r.scheduledAt),
formattedDate: DateFormatter.formatShort(r.scheduledAt),
}));
return (

View File

@@ -1,11 +1,11 @@
import { RankBadge } from '@/components/leaderboards/RankBadge';
import { RatingDisplay } from '@/lib/display-objects/RatingDisplay';
import { SkillLevelDisplay } from '@/lib/display-objects/SkillLevelDisplay';
import { RatingFormatter } from '@/lib/formatters/RatingFormatter';
import { SkillLevelFormatter } from '@/lib/formatters/SkillLevelFormatter';
import { Avatar } from '@/ui/Avatar';
import { Group } from '@/ui/Group';
import { LeaderboardList } from '@/ui/LeaderboardList';
import { LeaderboardPreviewShell } from '@/ui/LeaderboardPreviewShell';
import { LeaderboardRow } from '@/ui/LeaderboardRow';
import { Group } from '@/ui/Group';
import { Text } from '@/ui/Text';
import { Trophy } from 'lucide-react';
@@ -69,8 +69,8 @@ export function DriverLeaderboardPreview({
</Text>
<Group gap={2}>
<Text size="xs" variant="low" uppercase weight="bold" letterSpacing="wider">{driver.nationality}</Text>
<Text size="xs" weight="bold" color={SkillLevelDisplay.getColor(driver.skillLevel)} uppercase letterSpacing="wider">
{SkillLevelDisplay.getLabel(driver.skillLevel)}
<Text size="xs" weight="bold" color={SkillLevelFormatter.getColor(driver.skillLevel)} uppercase letterSpacing="wider">
{SkillLevelFormatter.getLabel(driver.skillLevel)}
</Text>
</Group>
</Group>
@@ -80,7 +80,7 @@ export function DriverLeaderboardPreview({
<Group gap={8}>
<Group direction="column" align="end" gap={0}>
<Text variant="primary" font="mono" weight="bold" block size="md" align="right">
{RatingDisplay.format(driver.rating)}
{RatingFormatter.format(driver.rating)}
</Text>
<Text size="xs" variant="low" block uppercase letterSpacing="widest" weight="bold" fontSize="9px" align="right">
Rating

View File

@@ -1,5 +1,5 @@
import { MedalDisplay } from '@/lib/display-objects/MedalDisplay';
import { RatingDisplay } from '@/lib/display-objects/RatingDisplay';
import { MedalFormatter } from '@/lib/formatters/MedalFormatter';
import { RatingFormatter } from '@/lib/formatters/RatingFormatter';
import { Image } from '@/ui/Image';
import { Stack } from '@/ui/Stack';
import { Text } from '@/ui/Text';
@@ -91,8 +91,8 @@ export function LeaderboardPodium({ podium, onDriverClick }: LeaderboardPodiumPr
border
transform="translateX(-50%)"
borderWidth="2px"
bg={MedalDisplay.getBg(position)}
color={MedalDisplay.getColor(position)}
bg={MedalFormatter.getBg(position)}
color={MedalFormatter.getColor(position)}
shadow="lg"
>
<Text size="sm" weight="bold">{position}</Text>
@@ -122,7 +122,7 @@ export function LeaderboardPodium({ podium, onDriverClick }: LeaderboardPodiumPr
block
color={isFirst ? 'text-warning-amber' : 'text-primary-blue'}
>
{RatingDisplay.format(driver.rating)}
{RatingFormatter.format(driver.rating)}
</Text>
<Stack direction="row" align="center" gap={3} mt={1}>
@@ -155,7 +155,7 @@ export function LeaderboardPodium({ podium, onDriverClick }: LeaderboardPodiumPr
<Text
weight="bold"
size="4xl"
color={MedalDisplay.getColor(position)}
color={MedalFormatter.getColor(position)}
opacity={0.1}
fontSize={isFirst ? '5rem' : '3.5rem'}
>

View File

@@ -1,11 +1,10 @@
import { MedalDisplay } from '@/lib/display-objects/MedalDisplay';
import { RankMedal as UiRankMedal, RankMedalProps } from '@/ui/RankMedal';
import React from 'react';
import { MedalFormatter } from '@/lib/formatters/MedalFormatter';
import { RankMedalProps, RankMedal as UiRankMedal } from '@/ui/RankMedal';
export function RankMedal(props: RankMedalProps) {
const variant = MedalDisplay.getVariant(props.rank);
const bg = MedalDisplay.getBg(props.rank);
const color = MedalDisplay.getColor(props.rank);
const variant = MedalFormatter.getVariant(props.rank);
const bg = MedalFormatter.getBg(props.rank);
const color = MedalFormatter.getColor(props.rank);
return (
<UiRankMedal

View File

@@ -1,12 +1,11 @@
import { RatingDisplay } from '@/lib/display-objects/RatingDisplay';
import { RatingFormatter } from '@/lib/formatters/RatingFormatter';
import { SkillLevelFormatter } from '@/lib/formatters/SkillLevelFormatter';
import { Avatar } from '@/ui/Avatar';
import { Group } from '@/ui/Group';
import { LeaderboardRow } from '@/ui/LeaderboardRow';
import { Text } from '@/ui/Text';
import { DeltaChip } from './DeltaChip';
import { RankBadge } from './RankBadge';
import { LeaderboardRow } from '@/ui/LeaderboardRow';
import { SkillLevelDisplay } from '@/lib/display-objects/SkillLevelDisplay';
import React from 'react';
interface RankingRowProps {
id: string;
@@ -65,8 +64,8 @@ export function RankingRow({
</Text>
<Group gap={2}>
<Text size="xs" variant="low" uppercase weight="bold" letterSpacing="wider">{nationality}</Text>
<Text size="xs" weight="bold" style={{ color: SkillLevelDisplay.getColor(skillLevel) }} uppercase letterSpacing="wider">
{SkillLevelDisplay.getLabel(skillLevel)}
<Text size="xs" weight="bold" style={{ color: SkillLevelFormatter.getColor(skillLevel) }} uppercase letterSpacing="wider">
{SkillLevelFormatter.getLabel(skillLevel)}
</Text>
</Group>
</Group>
@@ -84,7 +83,7 @@ export function RankingRow({
</Group>
<Group direction="column" align="end" gap={0}>
<Text variant="primary" font="mono" weight="bold" block size="md">
{RatingDisplay.format(rating)}
{RatingFormatter.format(rating)}
</Text>
<Text size="xs" variant="low" block uppercase letterSpacing="widest" weight="bold">
Rating

View File

@@ -1,10 +1,7 @@
import { RatingFormatter } from '@/lib/formatters/RatingFormatter';
import { Avatar } from '@/ui/Avatar';
import { Group } from '@/ui/Group';
import { Text } from '@/ui/Text';
import { RatingDisplay } from '@/lib/display-objects/RatingDisplay';
import { MedalDisplay } from '@/lib/display-objects/MedalDisplay';
import { Surface } from '@/ui/Surface';
import React from 'react';
interface PodiumDriver {
id: string;
@@ -20,7 +17,7 @@ interface RankingsPodiumProps {
onDriverClick?: (id: string) => void;
}
export function RankingsPodium({ podium, onDriverClick }: RankingsPodiumProps) {
export function RankingsPodium({ podium }: RankingsPodiumProps) {
return (
<Group justify="center" align="end" gap={4}>
{[1, 0, 2].map((index) => {
@@ -57,7 +54,7 @@ export function RankingsPodium({ podium, onDriverClick }: RankingsPodiumProps) {
<Text weight="bold" variant="high" size={isFirst ? 'md' : 'sm'}>{driver.name}</Text>
<Text font="mono" weight="bold" variant={isFirst ? 'warning' : 'primary'}>
{RatingDisplay.format(driver.rating)}
{RatingFormatter.format(driver.rating)}
</Text>
</Group>

View File

@@ -1,18 +1,16 @@
'use client';
import React, { useState } from 'react';
import { useRouter } from 'next/navigation';
import { routes } from '@/lib/routing/RouteConfig';
import { Box } from '@/ui/Box';
import { Text } from '@/ui/Text';
import { Stack } from '@/ui/Stack';
import { Button } from '@/ui/Button';
import { Icon } from '@/ui/Icon';
import { DateFormatter } from '@/lib/formatters/DateFormatter';
import { Badge } from '@/ui/Badge';
import { Box } from '@/ui/Box';
import { Button } from '@/ui/Button';
import { Group } from '@/ui/Group';
import { Icon } from '@/ui/Icon';
import { Stack } from '@/ui/Stack';
import { Surface } from '@/ui/Surface';
import { ChevronDown, ChevronUp, Calendar, CheckCircle, Trophy, Edit, Clock } from 'lucide-react';
import { DateDisplay } from '@/lib/display-objects/DateDisplay';
import { Text } from '@/ui/Text';
import { Calendar, CheckCircle, ChevronDown, ChevronUp, Clock, Edit, Trophy } from 'lucide-react';
import { useState } from 'react';
interface RaceEvent {
id: string;
@@ -50,9 +48,6 @@ interface MonthGroup {
export function EnhancedLeagueSchedulePanel({
events,
leagueId,
currentDriverId,
isAdmin,
onRegister,
onWithdraw,
onEdit,
@@ -60,7 +55,6 @@ export function EnhancedLeagueSchedulePanel({
onRaceDetail,
onResultsClick,
}: EnhancedLeagueSchedulePanelProps) {
const router = useRouter();
const [expandedMonths, setExpandedMonths] = useState<Set<string>>(new Set());
// Group races by month
@@ -109,7 +103,7 @@ export function EnhancedLeagueSchedulePanel({
};
const formatTime = (scheduledAt: string) => {
return DateDisplay.formatDateTime(scheduledAt);
return DateFormatter.formatDateTime(scheduledAt);
};
const groups = groupRacesByMonth();
@@ -158,7 +152,7 @@ export function EnhancedLeagueSchedulePanel({
{isExpanded && (
<Box p={4}>
<Stack gap={3}>
{group.races.map((race, raceIndex) => (
{group.races.map((race) => (
<Surface
key={race.id}
variant="precision"

View File

@@ -1,10 +1,10 @@
import { ActivityFeedItem } from '@/components/feed/ActivityFeedItem';
import { useLeagueRaces } from "@/hooks/league/useLeagueRaces";
import { RelativeTimeFormatter } from '@/lib/formatters/RelativeTimeFormatter';
import { LeagueActivityService } from '@/lib/services/league/LeagueActivityService';
import { RelativeTimeDisplay } from '@/lib/display-objects/RelativeTimeDisplay';
import { Icon } from '@/ui/Icon';
import { Text } from '@/ui/Text';
import { Stack } from '@/ui/Stack';
import { Text } from '@/ui/Text';
import { AlertTriangle, Calendar, Flag, Shield, UserMinus, UserPlus } from 'lucide-react';
import { useMemo } from 'react';
@@ -128,7 +128,7 @@ function ActivityItem({ activity }: { activity: LeagueActivity }) {
<ActivityFeedItem
icon={getIcon()}
content={getContent()}
timestamp={RelativeTimeDisplay.format(activity.timestamp, new Date())}
timestamp={RelativeTimeFormatter.format(activity.timestamp, new Date())}
/>
);
}

View File

@@ -1,11 +1,11 @@
import { DriverIdentity } from '@/ui/DriverIdentity';
import { DateFormatter } from '@/lib/formatters/DateFormatter';
import { DriverViewModel } from '@/lib/view-models/DriverViewModel';
import { Badge } from '@/ui/Badge';
import { Box } from '@/ui/Box';
import { DriverIdentity } from '@/ui/DriverIdentity';
import { TableCell, TableRow } from '@/ui/Table';
import { Text } from '@/ui/Text';
import { DateDisplay } from '@/lib/display-objects/DateDisplay';
import React, { ReactNode } from 'react';
import { ReactNode } from 'react';
interface LeagueMemberRowProps {
driver?: DriverViewModel;
@@ -84,7 +84,7 @@ export function LeagueMemberRow({
</TableCell>
<TableCell>
<Text variant="high" size="sm">
{DateDisplay.formatShort(joinedAt)}
{DateFormatter.formatShort(joinedAt)}
</Text>
</TableCell>
{actions && (

View File

@@ -1,39 +1,33 @@
'use client';
import {
Users,
Calendar,
Trophy,
Award,
Rocket,
Gamepad2,
User,
UsersRound,
Clock,
Flag,
Zap,
Timer,
Check,
Globe,
Medal,
type LucideIcon,
} from 'lucide-react';
import type { LeagueConfigFormModel } from '@/lib/types/LeagueConfigFormModel';
import type { LeagueScoringPresetViewModel } from '@/lib/view-models/LeagueScoringPresetViewModel';
import { Stack } from '@/ui/Stack';
import { Text } from '@/ui/Text';
import { Heading } from '@/ui/Heading';
import { Icon } from '@/ui/Icon';
import { Card } from '@/ui/Card';
import { Grid } from '@/ui/Grid';
import { Heading } from '@/ui/Heading';
import { Icon } from '@/ui/Icon';
import { Stack } from '@/ui/Stack';
import { Text } from '@/ui/Text';
import {
Award,
Calendar,
Check,
Clock,
Flag,
Gamepad2,
Globe,
Medal,
Rocket,
Timer,
Trophy,
User,
Users,
UsersRound,
Zap,
type LucideIcon,
} from 'lucide-react';
import { DateDisplay } from '@/lib/display-objects/DateDisplay';
import { DurationDisplay } from '@/lib/display-objects/DurationDisplay';
import { DateFormatter } from '@/lib/formatters/DateFormatter';
interface LeagueReviewSummaryProps {
form: LeagueConfigFormModel;
presets: LeagueScoringPresetViewModel[];
}
// Individual review card component
function ReviewCard({
@@ -142,7 +136,7 @@ export function LeagueReviewSummary({ form, presets }: LeagueReviewSummaryProps)
const seasonStartLabel =
timings.seasonStartDate
? DateDisplay.formatShort(timings.seasonStartDate)
? DateFormatter.formatShort(timings.seasonStartDate)
: null;
const stewardingLabel = (() => {

View File

@@ -1,28 +1,27 @@
'use client';
import React from 'react';
import { Box } from '@/ui/Box';
import { Text } from '@/ui/Text';
import { Stack } from '@/ui/Stack';
import { Group } from '@/ui/Group';
import { Surface } from '@/ui/Surface';
import { Icon } from '@/ui/Icon';
import { Button } from '@/ui/Button';
import { DateFormatter } from '@/lib/formatters/DateFormatter';
import { Badge } from '@/ui/Badge';
import {
Calendar,
Clock,
Car,
MapPin,
Thermometer,
Droplets,
Wind,
import { Box } from '@/ui/Box';
import { Button } from '@/ui/Button';
import { Group } from '@/ui/Group';
import { Icon } from '@/ui/Icon';
import { Stack } from '@/ui/Stack';
import { Surface } from '@/ui/Surface';
import { Text } from '@/ui/Text';
import {
Calendar,
Car,
CheckCircle,
Clock,
Cloud,
X,
Droplets,
MapPin,
Thermometer,
Trophy,
CheckCircle
Wind,
X
} from 'lucide-react';
import { DateDisplay } from '@/lib/display-objects/DateDisplay';
interface RaceDetailModalProps {
race: {
@@ -55,7 +54,7 @@ export function RaceDetailModal({
if (!isOpen) return null;
const formatTime = (scheduledAt: string) => {
return DateDisplay.formatDateTime(scheduledAt);
return DateFormatter.formatDateTime(scheduledAt);
};
const getStatusBadge = (status: 'scheduled' | 'completed') => {

View File

@@ -1,15 +1,11 @@
'use client';
import { CountryFlagDisplay } from '@/lib/display-objects/CountryFlagDisplay';
import { Panel } from '@/ui/Panel';
import { Input } from '@/ui/Input';
import { Text } from '@/ui/Text';
import { TextArea } from '@/ui/TextArea';
import { Box } from '@/ui/Box';
import { CountryFlagFormatter } from '@/lib/formatters/CountryFlagFormatter';
import { Group } from '@/ui/Group';
import { Input } from '@/ui/Input';
import { Panel } from '@/ui/Panel';
import { Stack } from '@/ui/Stack';
import { ProfileStat } from '@/ui/ProfileHero';
import React from 'react';
import { TextArea } from '@/ui/TextArea';
interface ProfileDetailsPanelProps {
driver: {
@@ -50,7 +46,7 @@ export function ProfileDetailsPanel({ driver, isEditing, onUpdate }: ProfileDeta
<Text size="xs" variant="low" weight="bold" uppercase block>Nationality</Text>
<Group gap={2}>
<Text size="xl">
{CountryFlagDisplay.fromCountryCode(driver.country).toString()}
{CountryFlagFormatter.fromCountryCode(driver.country).toString()}
</Text>
<Text variant="med">{driver.country}</Text>
</Group>

View File

@@ -1,16 +1,16 @@
'use client';
import { mediaConfig } from '@/lib/config/mediaConfig';
import { CountryFlagDisplay } from '@/lib/display-objects/CountryFlagDisplay';
import { CountryFlagFormatter } from '@/lib/formatters/CountryFlagFormatter';
import { Box } from '@/ui/Box';
import { Button } from '@/ui/Button';
import { Group } from '@/ui/Group';
import { Heading } from '@/ui/Heading';
import { Image } from '@/ui/Image';
import { ProfileHero, ProfileAvatar, ProfileStatsGroup, ProfileStat } from '@/ui/ProfileHero';
import { Text } from '@/ui/Text';
import { Box } from '@/ui/Box';
import { Group } from '@/ui/Group';
import { ProfileAvatar, ProfileHero, ProfileStat, ProfileStatsGroup } from '@/ui/ProfileHero';
import { Stack } from '@/ui/Stack';
import { Calendar, Globe, Star, Trophy, UserPlus } from 'lucide-react';
import { Text } from '@/ui/Text';
import { Calendar, Globe, UserPlus } from 'lucide-react';
import React from 'react';
interface ProfileHeaderProps {
@@ -56,7 +56,7 @@ export function ProfileHeader({
<Group gap={3}>
<Heading level={1}>{driver.name}</Heading>
<Text size="2xl" aria-label={`Country: ${driver.country}`}>
{CountryFlagDisplay.fromCountryCode(driver.country).toString()}
{CountryFlagFormatter.fromCountryCode(driver.country).toString()}
</Text>
</Group>
</Box>

View File

@@ -1,6 +1,6 @@
'use client';
import { DateDisplay } from '@/lib/display-objects/DateDisplay';
import { DateFormatter } from '@/lib/formatters/DateFormatter';
import { Button } from '@/ui/Button';
import { Card, Card as Surface } from '@/ui/Card';
import { Stack } from '@/ui/Stack';
@@ -64,7 +64,7 @@ export function SponsorshipRequestsPanel({
<Text size="xs" color="text-gray-400" block mt={1}>{request.message}</Text>
)}
<Text size="xs" color="text-gray-500" block mt={2}>
{DateDisplay.formatShort(request.createdAtIso)}
{DateFormatter.formatShort(request.createdAtIso)}
</Text>
</Stack>
<Stack direction="row" gap={2}>

View File

@@ -1,6 +1,5 @@
import React from 'react';
import { RaceStatusDisplay } from '@/lib/display-objects/RaceStatusDisplay';
import { DateDisplay } from '@/lib/display-objects/DateDisplay';
import { DateFormatter } from '@/lib/formatters/DateFormatter';
import { RaceStatusFormatter } from '@/lib/formatters/RaceStatusFormatter';
import { RaceCard as UiRaceCard } from './RaceCard';
interface RaceCardProps {
@@ -23,11 +22,11 @@ export function RaceCard({ race, onClick }: RaceCardProps) {
track={race.track}
car={race.car}
scheduledAt={race.scheduledAt}
scheduledAtLabel={DateDisplay.formatShort(race.scheduledAt)}
timeLabel={DateDisplay.formatTime(race.scheduledAt)}
scheduledAtLabel={DateFormatter.formatShort(race.scheduledAt)}
timeLabel={DateFormatter.formatTime(race.scheduledAt)}
status={race.status}
statusLabel={RaceStatusDisplay.getLabel(race.status)}
statusVariant={RaceStatusDisplay.getVariant(race.status) as any}
statusLabel={RaceStatusFormatter.getLabel(race.status)}
statusVariant={RaceStatusFormatter.getVariant(race.status) as any}
leagueName={race.leagueName}
leagueId={race.leagueId}
strengthOfField={race.strengthOfField}

View File

@@ -1,8 +1,8 @@
import { RaceHero as UiRaceHero } from '@/components/races/RaceHero';
import { DateFormatter } from '@/lib/formatters/DateFormatter';
import { LucideIcon } from 'lucide-react';
import { DateDisplay } from '@/lib/display-objects/DateDisplay';
interface RaceHeroProps {
track: string;
@@ -34,8 +34,8 @@ export function RaceHero(props: RaceHeroProps) {
return (
<UiRaceHero
{...rest}
formattedDate={DateDisplay.formatShort(scheduledAt)}
formattedTime={DateDisplay.formatTime(scheduledAt)}
formattedDate={DateFormatter.formatShort(scheduledAt)}
formattedTime={DateFormatter.formatTime(scheduledAt)}
statusConfig={mappedConfig}
/>
);

View File

@@ -1,9 +1,9 @@
import { routes } from '@/lib/routing/RouteConfig';
import { RaceListItem as UiRaceListItem } from '@/components/races/RaceListItem';
import { DateDisplay } from '@/lib/display-objects/DateDisplay';
import { StatusDisplay } from '@/lib/display-objects/StatusDisplay';
import { DateFormatter } from '@/lib/formatters/DateFormatter';
import { StatusFormatter } from '@/lib/formatters/StatusFormatter';
import { routes } from '@/lib/routing/RouteConfig';
interface Race {
id: string;
@@ -48,11 +48,11 @@ export function RaceListItem({ race, onClick }: RaceListItemProps) {
<UiRaceListItem
track={race.track}
car={race.car}
dateLabel={DateDisplay.formatMonthDay(race.scheduledAt).split(' ')[0]}
dayLabel={DateDisplay.formatMonthDay(race.scheduledAt).split(' ')[1]}
timeLabel={DateDisplay.formatTime(race.scheduledAt)}
dateLabel={DateFormatter.formatMonthDay(race.scheduledAt).split(' ')[0]}
dayLabel={DateFormatter.formatMonthDay(race.scheduledAt).split(' ')[1]}
timeLabel={DateFormatter.formatTime(race.scheduledAt)}
status={race.status}
statusLabel={StatusDisplay.raceStatus(race.status)}
statusLabel={StatusFormatter.raceStatus(race.status)}
statusVariant={config.variant}
statusIconName={config.iconName}
leagueName={race.leagueName}

View File

@@ -1,8 +1,8 @@
import { DateFormatter } from '@/lib/formatters/DateFormatter';
import { RaceResultViewModel } from '@/lib/view-models/RaceResultViewModel';
import { RaceResultCard as UiRaceResultCard } from './RaceResultCard';
import { DateDisplay } from '@/lib/display-objects/DateDisplay';
interface RaceResultCardProps {
race: {
@@ -29,7 +29,7 @@ export function RaceResultCard({
raceId={race.id}
track={race.track}
car={race.car}
formattedDate={DateDisplay.formatShort(race.scheduledAt)}
formattedDate={DateFormatter.formatShort(race.scheduledAt)}
position={result.position}
positionLabel={result.formattedPosition}
startPositionLabel={result.formattedStartPosition}

View File

@@ -1,15 +1,14 @@
'use client';
import { CountryFlagDisplay } from '@/lib/display-objects/CountryFlagDisplay';
import { Image } from '@/ui/Image';
import { ResultRow, PositionBadge, ResultPoints } from '@/ui/ResultRow';
import { Text } from '@/ui/Text';
import { CountryFlagFormatter } from '@/lib/formatters/CountryFlagFormatter';
import { Badge } from '@/ui/Badge';
import { Box } from '@/ui/Box';
import { Group } from '@/ui/Group';
import { Image } from '@/ui/Image';
import { PositionBadge, ResultPoints, ResultRow } from '@/ui/ResultRow';
import { Stack } from '@/ui/Stack';
import { Surface } from '@/ui/Surface';
import React from 'react';
import { Text } from '@/ui/Text';
interface ResultEntry {
position: number;
@@ -62,7 +61,7 @@ export function RaceResultRow({ result, points }: RaceResultRowProps) {
justifyContent="center"
>
<Text size="xs" style={{ fontSize: '0.625rem' }}>
{CountryFlagDisplay.fromCountryCode(country).toString()}
{CountryFlagFormatter.fromCountryCode(country).toString()}
</Text>
</Surface>
</Box>

View File

@@ -1,7 +1,7 @@
'use client';
import { mediaConfig } from '@/lib/config/mediaConfig';
import { CountryFlagDisplay } from '@/lib/display-objects/CountryFlagDisplay';
import { CountryFlagFormatter } from '@/lib/formatters/CountryFlagFormatter';
import { routes } from '@/lib/routing/RouteConfig';
import { Card, Card as Surface } from '@/ui/Card';
import { Heading } from '@/ui/Heading';
@@ -68,7 +68,7 @@ export function FriendsPreview({ friends }: FriendsPreviewProps) {
/>
</Stack>
<Text size="sm" color="text-white">{friend.name}</Text>
<Text size="lg">{CountryFlagDisplay.fromCountryCode(friend.country).toString()}</Text>
<Text size="lg">{CountryFlagFormatter.fromCountryCode(friend.country).toString()}</Text>
</Surface>
</Link>
</Stack>

View File

@@ -1,6 +1,5 @@
'use client';
import { MinimalEmptyState } from '@/ui/EmptyState';
import { TeamRosterItem } from '@/components/teams/TeamRosterItem';
import { TeamRosterList } from '@/components/teams/TeamRosterList';
import { useTeamRoster } from "@/hooks/team/useTeamRoster";
@@ -9,15 +8,16 @@ import { sortMembers } from '@/lib/utilities/roster-utils';
import type { DriverViewModel } from '@/lib/view-models/DriverViewModel';
import { Button } from '@/ui/Button';
import { Card } from '@/ui/Card';
import { MinimalEmptyState } from '@/ui/EmptyState';
import { Heading } from '@/ui/Heading';
import { Stack } from '@/ui/Stack';
import { Select } from '@/ui/Select';
import { Stack } from '@/ui/Stack';
import { Text } from '@/ui/Text';
import { useMemo, useState } from 'react';
import { MemberDisplay } from '@/lib/display-objects/MemberDisplay';
import { RatingDisplay } from '@/lib/display-objects/RatingDisplay';
import { DateDisplay } from '@/lib/display-objects/DateDisplay';
import { DateFormatter } from '@/lib/formatters/DateFormatter';
import { MemberFormatter } from '@/lib/formatters/MemberFormatter';
import { RatingFormatter } from '@/lib/formatters/RatingFormatter';
export type TeamRole = 'owner' | 'admin' | 'member';
export type TeamMemberRole = 'owner' | 'manager' | 'member';
@@ -74,7 +74,7 @@ export function TeamRoster({
const teamAverageRatingLabel = useMemo(() => {
if (teamMembers.length === 0) return '—';
const avg = teamMembers.reduce((sum: number, m: { rating?: number | null }) => sum + (m.rating || 0), 0) / teamMembers.length;
return RatingDisplay.format(avg);
return RatingFormatter.format(avg);
}, [teamMembers]);
if (loading) {
@@ -93,7 +93,7 @@ export function TeamRoster({
<Stack>
<Heading level={3}>Team Roster</Heading>
<Text size="sm" color="text-gray-400" block mt={1}>
{MemberDisplay.formatCount(memberships.length)} Avg Rating:{' '}
{MemberFormatter.formatCount(memberships.length)} Avg Rating:{' '}
<Text color="text-primary-blue" weight="medium">{teamAverageRatingLabel}</Text>
</Text>
</Stack>
@@ -129,8 +129,8 @@ export function TeamRoster({
driver={driver as DriverViewModel}
href={`${routes.driver.detail(driver.id)}?from=team&teamId=${teamId}`}
roleLabel={getRoleLabel(role)}
joinedAtLabel={DateDisplay.formatShort(joinedAt)}
ratingLabel={RatingDisplay.format(rating)}
joinedAtLabel={DateFormatter.formatShort(joinedAt)}
ratingLabel={RatingFormatter.format(rating)}
overallRankLabel={overallRank !== null ? `#${overallRank}` : null}
actions={canManageMembership ? (
<>