website refactor
This commit is contained in:
@@ -9,7 +9,7 @@ type RaceWithResults = {
|
||||
track: string;
|
||||
car: string;
|
||||
winnerName: string;
|
||||
scheduledAt: string | Date;
|
||||
formattedDate: string;
|
||||
};
|
||||
|
||||
interface LatestResultsSidebarProps {
|
||||
@@ -28,14 +28,12 @@ export function LatestResultsSidebar({ results }: LatestResultsSidebarProps) {
|
||||
</Heading>
|
||||
<RaceResultList>
|
||||
{results.slice(0, 4).map((result) => {
|
||||
const scheduledAt = typeof result.scheduledAt === 'string' ? new Date(result.scheduledAt) : result.scheduledAt;
|
||||
|
||||
return (
|
||||
<Box as="li" key={result.raceId}>
|
||||
<RaceSummaryItem
|
||||
track={result.track}
|
||||
meta={`${result.winnerName} • ${result.car}`}
|
||||
dateLabel={scheduledAt.toLocaleDateString()}
|
||||
dateLabel={result.formattedDate}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
|
||||
@@ -10,7 +10,8 @@ import { Calendar, Car, Clock, LucideIcon } from 'lucide-react';
|
||||
|
||||
interface RaceHeroProps {
|
||||
track: string;
|
||||
scheduledAt: string;
|
||||
formattedDate: string;
|
||||
formattedTime: string;
|
||||
car: string;
|
||||
status: 'scheduled' | 'running' | 'completed' | 'cancelled';
|
||||
statusConfig: {
|
||||
@@ -20,9 +21,8 @@ interface RaceHeroProps {
|
||||
};
|
||||
}
|
||||
|
||||
export function RaceHero({ track, scheduledAt, car, status, statusConfig }: RaceHeroProps) {
|
||||
export function RaceHero({ track, formattedDate, formattedTime, car, status, statusConfig }: RaceHeroProps) {
|
||||
const StatusIcon = statusConfig.icon;
|
||||
const date = new Date(scheduledAt);
|
||||
|
||||
return (
|
||||
<Hero variant="primary">
|
||||
@@ -59,11 +59,11 @@ export function RaceHero({ track, scheduledAt, car, status, statusConfig }: Race
|
||||
<Stack direction="row" align="center" gap={6} wrap>
|
||||
<Stack direction="row" align="center" gap={2}>
|
||||
<Icon icon={Calendar} size={4} color="rgb(156, 163, 175)" />
|
||||
<Text color="text-gray-400">{date.toLocaleDateString()}</Text>
|
||||
<Text color="text-gray-400">{formattedDate}</Text>
|
||||
</Stack>
|
||||
<Stack direction="row" align="center" gap={2}>
|
||||
<Icon icon={Clock} size={4} color="rgb(156, 163, 175)" />
|
||||
<Text color="text-gray-400">{date.toLocaleTimeString()}</Text>
|
||||
<Text color="text-gray-400">{formattedTime}</Text>
|
||||
</Stack>
|
||||
<Stack direction="row" align="center" gap={2}>
|
||||
<Icon icon={Car} size={4} color="rgb(156, 163, 175)" />
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import { RaceHero as UiRaceHero } from '@/components/races/RaceHero';
|
||||
import { LucideIcon } from 'lucide-react';
|
||||
import { DateDisplay } from '@/lib/display-objects/DateDisplay';
|
||||
|
||||
interface RaceHeroProps {
|
||||
track: string;
|
||||
@@ -17,7 +18,7 @@ interface RaceHeroProps {
|
||||
}
|
||||
|
||||
export function RaceHero(props: RaceHeroProps) {
|
||||
const { statusConfig, ...rest } = props;
|
||||
const { statusConfig, scheduledAt, ...rest } = props;
|
||||
|
||||
// Map variant to match UI component expectations
|
||||
const mappedConfig: {
|
||||
@@ -30,5 +31,12 @@ export function RaceHero(props: RaceHeroProps) {
|
||||
variant: statusConfig.variant === 'default' ? 'default' : statusConfig.variant
|
||||
};
|
||||
|
||||
return <UiRaceHero {...rest} statusConfig={mappedConfig} />;
|
||||
return (
|
||||
<UiRaceHero
|
||||
{...rest}
|
||||
formattedDate={DateDisplay.formatShort(scheduledAt)}
|
||||
formattedTime={DateDisplay.formatTime(scheduledAt)}
|
||||
statusConfig={mappedConfig}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
|
||||
import { routes } from '@/lib/routing/RouteConfig';
|
||||
import { RaceListItem as UiRaceListItem } from '@/components/races/RaceListItem';
|
||||
import { CheckCircle2, Clock, PlayCircle, XCircle } from 'lucide-react';
|
||||
import { DateDisplay } from '@/lib/display-objects/DateDisplay';
|
||||
import { StatusDisplay } from '@/lib/display-objects/StatusDisplay';
|
||||
|
||||
interface Race {
|
||||
id: string;
|
||||
@@ -26,45 +27,32 @@ export function RaceListItem({ race, onClick }: RaceListItemProps) {
|
||||
scheduled: {
|
||||
iconName: 'Clock',
|
||||
variant: 'primary' as const,
|
||||
label: 'Scheduled',
|
||||
},
|
||||
running: {
|
||||
iconName: 'PlayCircle',
|
||||
variant: 'success' as const,
|
||||
label: 'LIVE',
|
||||
},
|
||||
completed: {
|
||||
iconName: 'CheckCircle2',
|
||||
variant: 'default' as const,
|
||||
label: 'Completed',
|
||||
},
|
||||
cancelled: {
|
||||
iconName: 'XCircle',
|
||||
variant: 'warning' as const,
|
||||
label: 'Cancelled',
|
||||
},
|
||||
};
|
||||
|
||||
const config = statusConfig[race.status];
|
||||
|
||||
const formatTime = (date: string) => {
|
||||
return new Date(date).toLocaleTimeString('en-US', {
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
});
|
||||
};
|
||||
|
||||
const date = new Date(race.scheduledAt);
|
||||
|
||||
return (
|
||||
<UiRaceListItem
|
||||
track={race.track}
|
||||
car={race.car}
|
||||
dateLabel={date.toLocaleDateString('en-US', { month: 'short' })}
|
||||
dayLabel={date.getDate().toString()}
|
||||
timeLabel={formatTime(race.scheduledAt)}
|
||||
dateLabel={DateDisplay.formatMonthDay(race.scheduledAt).split(' ')[0]}
|
||||
dayLabel={DateDisplay.formatMonthDay(race.scheduledAt).split(' ')[1]}
|
||||
timeLabel={DateDisplay.formatTime(race.scheduledAt)}
|
||||
status={race.status}
|
||||
statusLabel={config.label}
|
||||
statusLabel={StatusDisplay.raceStatus(race.status)}
|
||||
statusVariant={config.variant}
|
||||
statusIconName={config.iconName}
|
||||
leagueName={race.leagueName}
|
||||
|
||||
@@ -12,10 +12,12 @@ interface RaceResultCardProps {
|
||||
raceId: string;
|
||||
track: string;
|
||||
car: string;
|
||||
scheduledAt: string | Date;
|
||||
formattedDate: string;
|
||||
position: number;
|
||||
startPosition: number;
|
||||
incidents: number;
|
||||
positionLabel: string;
|
||||
startPositionLabel: string;
|
||||
incidentsLabel: string;
|
||||
positionsGainedLabel?: string;
|
||||
leagueName?: string;
|
||||
showLeague?: boolean;
|
||||
onClick?: () => void;
|
||||
@@ -25,10 +27,12 @@ export function RaceResultCard({
|
||||
raceId,
|
||||
track,
|
||||
car,
|
||||
scheduledAt,
|
||||
formattedDate,
|
||||
position,
|
||||
startPosition,
|
||||
incidents,
|
||||
positionLabel,
|
||||
startPositionLabel,
|
||||
incidentsLabel,
|
||||
positionsGainedLabel,
|
||||
leagueName,
|
||||
showLeague = true,
|
||||
onClick,
|
||||
@@ -66,7 +70,7 @@ export function RaceResultCard({
|
||||
border
|
||||
borderColor="border-outline-steel"
|
||||
>
|
||||
P{position}
|
||||
{positionLabel}
|
||||
</Stack>
|
||||
<Stack>
|
||||
<Text color="text-white" weight="medium" block groupHoverTextColor="text-primary-accent" transition>
|
||||
@@ -78,11 +82,7 @@ export function RaceResultCard({
|
||||
<Stack direction="row" align="center" gap={3}>
|
||||
<Stack textAlign="right">
|
||||
<Text size="sm" color="text-gray-400" block>
|
||||
{new Date(scheduledAt).toLocaleDateString('en-US', {
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
year: 'numeric',
|
||||
})}
|
||||
{formattedDate}
|
||||
</Text>
|
||||
{showLeague && leagueName && (
|
||||
<Text size="xs" color="text-gray-500" block>{leagueName}</Text>
|
||||
@@ -92,16 +92,16 @@ export function RaceResultCard({
|
||||
</Stack>
|
||||
</Stack>
|
||||
<Stack direction="row" align="center" gap={4}>
|
||||
<Text size="xs" color="text-gray-500">Started P{startPosition}</Text>
|
||||
<Text size="xs" color="text-gray-500">Started {startPositionLabel}</Text>
|
||||
<Text size="xs" color="text-gray-500">•</Text>
|
||||
<Text size="xs" color={incidents === 0 ? 'text-success-green' : incidents > 2 ? 'text-error-red' : 'text-gray-500'}>
|
||||
{incidents}x incidents
|
||||
<Text size="xs" color="text-gray-500">
|
||||
{incidentsLabel}
|
||||
</Text>
|
||||
{position < startPosition && (
|
||||
{positionsGainedLabel && (
|
||||
<>
|
||||
<Text size="xs" color="text-gray-500">•</Text>
|
||||
<Text size="xs" color="text-success-green">
|
||||
+{startPosition - position} positions
|
||||
{positionsGainedLabel}
|
||||
</Text>
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import { RaceResultViewModel } from '@/lib/view-models/RaceResultViewModel';
|
||||
import { RaceResultCard as UiRaceResultCard } from './RaceResultCard';
|
||||
import { DateDisplay } from '@/lib/display-objects/DateDisplay';
|
||||
|
||||
interface RaceResultCardProps {
|
||||
race: {
|
||||
@@ -28,10 +29,12 @@ export function RaceResultCard({
|
||||
raceId={race.id}
|
||||
track={race.track}
|
||||
car={race.car}
|
||||
scheduledAt={race.scheduledAt}
|
||||
formattedDate={DateDisplay.formatShort(race.scheduledAt)}
|
||||
position={result.position}
|
||||
startPosition={result.startPosition}
|
||||
incidents={result.incidents}
|
||||
positionLabel={result.formattedPosition}
|
||||
startPositionLabel={result.formattedStartPosition}
|
||||
incidentsLabel={result.formattedIncidents}
|
||||
positionsGainedLabel={result.formattedPositionsGained}
|
||||
leagueName={league?.name}
|
||||
showLeague={showLeague}
|
||||
/>
|
||||
|
||||
@@ -8,7 +8,7 @@ type UpcomingRace = {
|
||||
id: string;
|
||||
track: string;
|
||||
car: string;
|
||||
scheduledAt: string | Date;
|
||||
formattedDate: string;
|
||||
};
|
||||
|
||||
interface UpcomingRacesSidebarProps {
|
||||
@@ -35,14 +35,12 @@ export function UpcomingRacesSidebar({ races }: UpcomingRacesSidebarProps) {
|
||||
</Stack>
|
||||
<Stack gap={3}>
|
||||
{races.slice(0, 4).map((race) => {
|
||||
const scheduledAt = typeof race.scheduledAt === 'string' ? new Date(race.scheduledAt) : race.scheduledAt;
|
||||
|
||||
return (
|
||||
<RaceSummaryItem
|
||||
key={race.id}
|
||||
track={race.track}
|
||||
meta={race.car}
|
||||
dateLabel={scheduledAt.toLocaleDateString()}
|
||||
dateLabel={race.formattedDate}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
|
||||
Reference in New Issue
Block a user