87 lines
2.8 KiB
TypeScript
87 lines
2.8 KiB
TypeScript
'use client';
|
|
|
|
import { Race } from '../../domain/entities/Race';
|
|
|
|
interface RaceCardProps {
|
|
race: Race;
|
|
leagueName?: string;
|
|
onClick?: () => void;
|
|
}
|
|
|
|
export default function RaceCard({ race, leagueName, onClick }: RaceCardProps) {
|
|
const statusColors = {
|
|
scheduled: 'bg-primary-blue/20 text-primary-blue border-primary-blue/30',
|
|
completed: 'bg-green-500/20 text-green-400 border-green-500/30',
|
|
cancelled: 'bg-gray-500/20 text-gray-400 border-gray-500/30',
|
|
};
|
|
|
|
const formatDate = (date: Date) => {
|
|
return new Date(date).toLocaleDateString('en-US', {
|
|
month: 'short',
|
|
day: 'numeric',
|
|
year: 'numeric',
|
|
});
|
|
};
|
|
|
|
const formatTime = (date: Date) => {
|
|
return new Date(date).toLocaleTimeString('en-US', {
|
|
hour: '2-digit',
|
|
minute: '2-digit',
|
|
timeZoneName: 'short',
|
|
});
|
|
};
|
|
|
|
const getRelativeTime = (date: Date) => {
|
|
const now = new Date();
|
|
const targetDate = new Date(date);
|
|
const diffMs = targetDate.getTime() - now.getTime();
|
|
const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));
|
|
|
|
if (diffDays < 0) return null;
|
|
if (diffDays === 0) return 'Today';
|
|
if (diffDays === 1) return 'Tomorrow';
|
|
if (diffDays < 7) return `in ${diffDays} days`;
|
|
return null;
|
|
};
|
|
|
|
const relativeTime = race.status === 'scheduled' ? getRelativeTime(race.scheduledAt) : null;
|
|
|
|
return (
|
|
<div
|
|
onClick={onClick}
|
|
className={`
|
|
p-6 rounded-lg bg-iron-gray border border-charcoal-outline
|
|
transition-all duration-200
|
|
${onClick ? 'cursor-pointer hover:scale-[1.03] hover:border-primary-blue' : ''}
|
|
`}
|
|
>
|
|
<div className="flex items-start justify-between mb-4">
|
|
<div className="flex-1">
|
|
<div className="flex items-center gap-3 mb-2">
|
|
<h3 className="text-lg font-semibold text-white">{race.track}</h3>
|
|
<span className={`px-2 py-1 text-xs font-medium rounded border ${statusColors[race.status]}`}>
|
|
{race.status.charAt(0).toUpperCase() + race.status.slice(1)}
|
|
</span>
|
|
</div>
|
|
<p className="text-gray-400 text-sm">{race.car}</p>
|
|
{leagueName && (
|
|
<p className="text-gray-500 text-xs mt-1">{leagueName}</p>
|
|
)}
|
|
</div>
|
|
<div className="text-right">
|
|
<p className="text-white font-medium text-sm">{formatDate(race.scheduledAt)}</p>
|
|
<p className="text-gray-400 text-xs">{formatTime(race.scheduledAt)}</p>
|
|
{relativeTime && (
|
|
<p className="text-primary-blue text-xs mt-1">{relativeTime}</p>
|
|
)}
|
|
</div>
|
|
</div>
|
|
|
|
<div className="flex items-center justify-between">
|
|
<span className="text-xs text-gray-500 uppercase tracking-wide">
|
|
{race.sessionType}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
);
|
|
} |