120 lines
3.0 KiB
TypeScript
120 lines
3.0 KiB
TypeScript
import {
|
|
Divider,
|
|
Group,
|
|
List,
|
|
ListItem,
|
|
Skeleton,
|
|
Stack,
|
|
Text,
|
|
} from "@mantine/core";
|
|
import Avatar from "@/components/avatar";
|
|
import { TeamInfo } from "@/features/teams/types";
|
|
import { useNavigate } from "@tanstack/react-router";
|
|
import { useCallback, useMemo } from "react";
|
|
import React from "react";
|
|
|
|
interface TeamListItemProps {
|
|
team: TeamInfo;
|
|
}
|
|
const TeamListItem = React.memo(({ team }: TeamListItemProps) => {
|
|
const playerNames = useMemo(
|
|
() => team.players?.map((p) => `${p.first_name} ${p.last_name}`) || [],
|
|
[team.players]
|
|
);
|
|
|
|
const teamNameSize = useMemo(() => {
|
|
const nameLength = team.name.length;
|
|
if (nameLength > 20) return 'xs';
|
|
if (nameLength > 15) return 'sm';
|
|
return 'md';
|
|
}, [team.name]);
|
|
|
|
return (
|
|
<Group justify="space-between" w="100%" wrap="nowrap">
|
|
<Text fw={500} size={teamNameSize} style={{ flexShrink: 1, minWidth: 0, maxWidth: 170, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
|
|
{`${team.name}`}
|
|
</Text>
|
|
<Stack ml="auto" gap={0} style={{ flexShrink: 0 }}>
|
|
{playerNames.map((name, idx) => (
|
|
<Text key={idx} size="xs" c="dimmed" ta="right">
|
|
{name}
|
|
</Text>
|
|
))}
|
|
</Stack>
|
|
</Group>
|
|
);
|
|
});
|
|
|
|
interface TeamListProps {
|
|
teams: TeamInfo[];
|
|
loading?: boolean;
|
|
onTeamClick?: (teamId: string) => void;
|
|
}
|
|
|
|
const TeamList = ({ teams, loading = false, onTeamClick }: TeamListProps) => {
|
|
const navigate = useNavigate();
|
|
|
|
const handleClick = useCallback(
|
|
(teamId: string, priv: boolean) => {
|
|
if (onTeamClick) {
|
|
onTeamClick(teamId);
|
|
} else if (!priv) {
|
|
navigate({ to: `/teams/${teamId}` });
|
|
}
|
|
},
|
|
[navigate, onTeamClick]
|
|
);
|
|
|
|
if (loading)
|
|
return (
|
|
<List p="0">
|
|
{Array.from({ length: 10 }).map((_, i) => (
|
|
<ListItem
|
|
key={`skeleton-${i}`}
|
|
py="xs"
|
|
icon={<Skeleton height={40} width={40} />}
|
|
>
|
|
<Skeleton height={35} width={200} />
|
|
</ListItem>
|
|
))}
|
|
</List>
|
|
);
|
|
|
|
return (
|
|
<List p="0">
|
|
{teams?.map((team) => (
|
|
<div key={team.id}>
|
|
<ListItem
|
|
key={`team-list-${team.id}`}
|
|
p="xs"
|
|
icon={
|
|
<Avatar
|
|
radius="sm"
|
|
size={40}
|
|
name={`${team.name}`}
|
|
src={
|
|
team.logo
|
|
? `/api/files/teams/${team.id}/${team.logo}`
|
|
: undefined
|
|
}
|
|
/>
|
|
}
|
|
style={{ cursor: "pointer" }}
|
|
onClick={() => handleClick(team.id, team.private)}
|
|
styles={{
|
|
itemWrapper: { width: "100%" },
|
|
itemLabel: { width: "100%" },
|
|
}}
|
|
w="100%"
|
|
>
|
|
<TeamListItem team={team} />
|
|
</ListItem>
|
|
<Divider />
|
|
</div>
|
|
))}
|
|
</List>
|
|
);
|
|
};
|
|
|
|
export default TeamList;
|