sendou.ink/app/features/user-page/components/UserResultsTable.tsx
Kalle eae3d529e2
Bracket component rewrite (#1653)
* Remove old code

* Add prefetching

* Elim bracket initial

* Hide rounds with only byes

* Round hiding logic

* Align stuff

* Add TODO

* Adjustments

* Deadline

* Compactify button

* Simulations

* Round robin bracket initial

* eventId -> tournamentId

* seedByTeamId removed

* Couple more TODOs

* RR placements table

* Locking matches

* Extract TournamentStream component

* Bracket streams

* Remove extras for tournament-manager, misc

* Fix E2E tests

* Fix SKALOP_SYSTEM_MESSAGE_URL in env.example

* TODOs

* TODO moved to GitHub

* Handle team changing in match cache invalidation

* Fix streamer seeing undo last score button

* Show "Sub" badge on team roster page

* Show who didn't play yet on match teams preview

* Ranked/unranked badge

* Bracket hover show roster

* Add lock/unlock match test

* Fix score reporting
2024-02-11 10:49:12 +02:00

152 lines
5.1 KiB
TypeScript

import { Link } from "@remix-run/react";
import { useTranslation } from "react-i18next";
import { Avatar } from "~/components/Avatar";
import { Placement } from "~/components/Placement";
import { type UserPageLoaderData } from "~/features/user-page/routes/u.$identifier";
import { databaseTimestampToDate } from "~/utils/dates";
import {
calendarEventPage,
tournamentBracketsPage,
tournamentTeamPage,
userPage,
} from "~/utils/urls";
import { Table } from "~/components/Table";
export type UserResultsTableProps = {
results: UserPageLoaderData["results"];
id: string;
hasHighlightCheckboxes?: boolean;
};
export const HIGHLIGHT_CHECKBOX_NAME = "highlightTeamIds";
export const HIGHLIGHT_TOURNAMENT_CHECKBOX_NAME = "highlightTournamentTeamIds";
export function UserResultsTable({
results,
id,
hasHighlightCheckboxes,
}: UserResultsTableProps) {
const { t, i18n } = useTranslation("user");
const placementHeaderId = `${id}-th-placement`;
return (
<Table>
<thead>
<tr>
{hasHighlightCheckboxes && <th />}
<th id={placementHeaderId}>{t("results.placing")}</th>
<th>{t("results.team")}</th>
<th>{t("results.tournament")}</th>
<th>{t("results.participants")}</th>
<th>{t("results.date")}</th>
<th>{t("results.mates")}</th>
</tr>
</thead>
<tbody>
{results.map((result, i) => {
// We are trying to construct a reasonable label for the checkbox
// which shouldn't contain the whole information of the table row as
// that can be also accessed when needed.
// e.g. "20xx Placing 2nd", "Big House 10 Placing 20th"
const placementCellId = `${id}-${result.teamId}-placement`;
const nameCellId = `${id}-${result.teamId}-name`;
const checkboxLabelIds = `${nameCellId} ${placementHeaderId} ${placementCellId}`;
return (
<tr key={result.teamId}>
{hasHighlightCheckboxes && (
<td>
<input
value={result.teamId}
aria-labelledby={checkboxLabelIds}
name={
result.tournamentId
? HIGHLIGHT_TOURNAMENT_CHECKBOX_NAME
: HIGHLIGHT_CHECKBOX_NAME
}
type="checkbox"
defaultChecked={Boolean(result.isHighlight)}
/>
</td>
)}
<td className="pl-4" id={placementCellId}>
<Placement placement={result.placement} />
</td>
<td>
{result.tournamentId ? (
<Link
to={tournamentTeamPage({
tournamentId: result.tournamentId,
tournamentTeamId: result.teamId,
})}
>
{result.teamName}
</Link>
) : (
<>{result.teamName}</>
)}
</td>
<td id={nameCellId}>
{result.eventId ? (
<Link to={calendarEventPage(result.eventId)}>
{result.eventName}
</Link>
) : null}
{result.tournamentId ? (
<Link
to={tournamentBracketsPage({
tournamentId: result.tournamentId,
})}
data-testid="tournament-name-cell"
>
{result.eventName}
</Link>
) : null}
</td>
<td>{result.participantCount}</td>
<td>
{/* TODO: can be made better when $narrowNotNull lands */}
{databaseTimestampToDate(result.startTime!).toLocaleDateString(
i18n.language,
{
day: "numeric",
month: "numeric",
year: "numeric",
},
)}
</td>
<td>
<ul
className="u__results-players"
data-testid={`mates-cell-placement-${i}`}
>
{result.mates.map((player) => (
<li
key={player.name ? player.name : player.id}
className="flex items-center"
>
{player.name ? (
player.name
) : (
// as any but we know it's a user since it doesn't have name
<Link
to={userPage(player as any)}
className="stack horizontal xs items-center"
>
<Avatar user={player as any} size="xxs" />
{player.discordName}
</Link>
)}
</li>
))}
</ul>
</td>
</tr>
);
})}
</tbody>
</Table>
);
}