Files
brackets/frontend/src/components/Schedule/ScheduleRow.tsx
T

114 lines
8.2 KiB
TypeScript

// frontend/src/components/Schedule/ScheduleRow.tsx
import { CheckCircle, Pencil, Plus, Trophy } from 'lucide-react';
import React from 'react';
import { type MatchData } from '../../types';
import { printName, stringToColor } from '../../utils/helpers';
import WhistleIcon from "../../assets/whistle.svg?react"
interface ScheduleRowProps {
match: MatchData;
onMatchClick: (match: MatchData) => void;
badgeWidth: number;
}
export default function ScheduleRow({ match: m, onMatchClick, badgeWidth }: ScheduleRowProps) {
const courtColor = stringToColor(m.court);
const isFinished = m.isFinished;
const refName = m.ref_team?.name || m.ref_label;
return (
<div className="relative mb-5 transition-colors bg-white dark:bg-zinc-900 print:bg-white! p-4 print:p-3 rounded-2xl print:rounded-none border border-zinc-300 dark:border-zinc-800 print:border-b! print:border-x-0! print:border-t-0! print:border-zinc-300! shadow-sm print:shadow-none! flex items-center justify-between hover:border-orange-500/30">
<div className="flex gap-4 md:gap-6 print:gap-6 flex-1 min-w-0">
<div className="flex flex-col gap-1 items-center shrink-0" style={{ minWidth: badgeWidth }}>
<div className="text-lg md:text-xl print:text-xl font-black font-mono text-zinc-900 dark:text-white print:text-black!">{m.time}</div>
<div className="text-tiny font-black text-white print:text-zinc-800! px-2 py-1 rounded uppercase w-full truncate text-center print:border! print:border-zinc-400! print:bg-transparent!" style={{ background: courtColor }}>
{m.court}
</div>
<div className="transition-colors block md:hidden print:hidden text-tiny font-black bg-zinc-100 dark:bg-zinc-800 w-full truncate text-center print:bg-transparent! text-zinc-400 print:text-zinc-500! px-2 py-1 rounded">Match #{m.number}</div>
</div>
<div className="flex-1 flex flex-col gap-0.5 min-w-0 justify-center md:justify-between">
<div className="flex flex-col md:flex-row md:items-end print:flex-row print:items-center gap-1 md:gap-2 print:gap-2">
{[{ n: m.p1, win: m.winnerName === m.p1, real: m.p1_is_real },
{ n: m.p2, win: m.winnerName === m.p2, real: m.p2_is_real }].map((p, i) => (
<React.Fragment key={i}>
<div className="flex items-center gap-2 min-w-0">
{p.win && <Trophy size={14} className="text-orange-500 shrink-0 print:hidden" />}
<span className={`block print:hidden truncate text-sm md:text-base font-bold ${p.win ? 'text-orange-600' : p.real ? 'text-zinc-900 dark:text-zinc-100' : 'text-zinc-400 italic font-normal'}`}>{p.n}</span>
<span className={`hidden print:inline-block print:whitespace-normal print:overflow-visible print:text-base font-bold ${p.real ? 'print:text-black!' : 'print:text-zinc-600! italic font-normal'}`}>
{printName(p.n)}
</span>
</div>
{i === 0 && <span className="block print:block text-zinc-300 dark:text-zinc-700 print:text-zinc-400! text-xs font-black md:pb-0.5">VS</span>}
</React.Fragment>
))}
</div>
<div className="flex flex-col md:flex-row md:items-center gap-0.5 md:gap-2 mt-0.5 md:mt-1">
<div className="transition-colors hidden md:block print:block text-tiny font-black bg-zinc-100 dark:bg-zinc-800 print:bg-transparent! text-zinc-400 print:text-zinc-500! px-2 py-1 rounded w-fit">Match #{m.number}</div>
</div>
</div>
</div>
{/* ACTION BUTTON AREA */}
<div className="ml-3 flex items-stretch shrink-0 print:hidden py-0.5">
{isFinished ? (
<button
onClick={() => onMatchClick(m)}
className="flex flex-col justify-between items-center md:justify-center md:items-end hover:bg-zinc-50 dark:hover:bg-zinc-800 p-1.5 md:p-2 rounded-xl transition group/btn min-w-8 md:min-w-20 border border-transparent hover:border-zinc-200 dark:hover:border-zinc-700"
title="Edit Score"
>
<div className={`${m.winnerName === m.p1 ? 'bg-orange-100 dark:bg-orange-900/30 text-orange-700' : 'bg-zinc-100 dark:bg-zinc-800 text-zinc-900 dark:text-zinc-50'} px-2 py-0.5 rounded text-[10px] font-black font-mono border border-zinc-200 dark:border-zinc-700 md:hidden`}>
{m.p1_sets}
</div>
<div className="w-0.5 h-3 bg-zinc-200 dark:bg-zinc-700 rounded-full md:hidden my-1" />
<div className={`${m.winnerName === m.p2 ? 'bg-orange-100 dark:bg-orange-900/30 text-orange-700' : 'bg-zinc-100 dark:bg-zinc-800 text-zinc-900 dark:text-zinc-50'} px-2 py-0.5 rounded text-[10px] font-black font-mono border border-zinc-200 dark:border-zinc-700 md:hidden`}>
{m.p2_sets}
</div>
<div className="hidden md:flex group-hover/btn:hidden flex-col items-end">
<div className="text-orange-500 font-black text-[10px] uppercase flex items-center gap-1">
<CheckCircle size={12} strokeWidth={3} /> Finished
</div>
<div className="text-sm font-black font-mono text-zinc-900 dark:text-zinc-300">
{m.p1_sets} - {m.p2_sets}
</div>
</div>
<div className="hidden md:group-hover/btn:flex flex-col items-end text-zinc-500 dark:text-zinc-400 animate-in fade-in zoom-in duration-200">
<div className="text-[10px] font-black uppercase flex items-center gap-1">
<Pencil size={12} strokeWidth={3} /> Edit
</div>
<div className="text-sm font-black font-mono">
{m.p1_sets} - {m.p2_sets}
</div>
</div>
</button>
) : m.isReady && (
<button onClick={() => onMatchClick(m)} className="bg-orange-600 hover:bg-orange-500 text-white p-2 md:px-4 md:py-2 rounded-xl shadow-lg active:scale-95 transition-all flex items-center gap-2 group/btn self-center">
<Plus size={18} strokeWidth={3} className="group-hover/btn:rotate-90 transition-transform duration-200" />
<span className="text-xs font-bold uppercase hidden md:inline">Report score</span>
</button>
)}
</div>
<div className="hidden print:flex items-center gap-4 shrink-0 ml-6">
<div className="w-8 h-8 border-[1.5px] border-zinc-400 rounded-md flex items-center justify-center font-bold text-sm text-black">
{isFinished ? m.p1_sets : ''}
</div>
<span className="text-zinc-400 font-bold">-</span>
<div className="w-8 h-8 border-[1.5px] border-zinc-400 rounded-md flex items-center justify-center font-bold text-sm text-black">
{isFinished ? m.p2_sets : ''}
</div>
</div>
{refName && !isFinished && (
<div className="absolute -bottom-3 left-1/2 -translate-x-1/2 bg-zinc-100 dark:bg-zinc-800 border border-zinc-200 dark:border-zinc-700 text-zinc-500 dark:text-zinc-300 text-[9px] md:text-[10px] font-black uppercase tracking-widest px-3 md:px-4 py-1 rounded-full shadow-md whitespace-nowrap z-20 flex items-center gap-1.5 print:hidden max-w-[90%]">
<WhistleIcon className="text-orange-500 shrink-0" width={12} height={12} />
<span className="truncate">{refName}</span>
</div>
)}
</div>
);
}