diff --git a/src/features/bracket/components/bracket-view.tsx b/src/features/bracket/components/bracket-view.tsx index bf14f71..2f337bb 100644 --- a/src/features/bracket/components/bracket-view.tsx +++ b/src/features/bracket/components/bracket-view.tsx @@ -1,5 +1,5 @@ import { Flex } from '@mantine/core'; -import React from 'react'; +import React, { useCallback } from 'react'; import { BracketMaps } from '../utils/bracket-maps'; import { BracketRound } from './bracket-round'; import { Match } from '../types'; @@ -16,7 +16,7 @@ const BracketView: React.FC = ({ onAnnounce, }) => { - const getParentMatchOrder = (parentLid: number): number | string => { + const getParentMatchOrder = useCallback((parentLid: number): number | string => { const parentMatch = bracketMaps.matchByLid.get(parentLid); if ( parentMatch && @@ -26,7 +26,7 @@ const BracketView: React.FC = ({ return parentMatch.order; } return `Match ${parentLid}`; - }; + }, [bracketMaps]); return ( diff --git a/src/features/bracket/components/match-card.tsx b/src/features/bracket/components/match-card.tsx index b9534d2..1bde010 100644 --- a/src/features/bracket/components/match-card.tsx +++ b/src/features/bracket/components/match-card.tsx @@ -1,6 +1,6 @@ import { ActionIcon, Card, Text } from '@mantine/core'; import { PlayIcon } from '@phosphor-icons/react'; -import React from 'react'; +import React, { useCallback, useMemo } from 'react'; import { MatchSlot } from './match-slot'; import { Match } from '../types'; @@ -15,6 +15,14 @@ export const MatchCard: React.FC = ({ getParentMatchOrder, onAnnounce }) => { + + const showAnnounce = useMemo(() => + onAnnounce && match.home.team && match.away.team, + [onAnnounce, match.home.team, match.away.team]); + + const handleAnnounce = useCallback(() => + onAnnounce?.(match.home.team, match.away.team), [match.home.team, match.away.team]); + return ( = ({ )} - {onAnnounce && match.home?.team && match.away?.team && ( + {showAnnounce && ( { - onAnnounce(match.home.team, match.away.team); - }} + onClick={handleAnnounce} bd="none" style={{ boxShadow: 'none' }} size="xs" diff --git a/src/features/players/components/player-list.tsx b/src/features/players/components/player-list.tsx index e775a42..5c2425d 100644 --- a/src/features/players/components/player-list.tsx +++ b/src/features/players/components/player-list.tsx @@ -2,6 +2,7 @@ import { List, ListItem, Skeleton, Text } from "@mantine/core"; import { useNavigate } from "@tanstack/react-router"; import Avatar from "@/components/avatar"; import { Player } from "@/features/players/types"; +import { useCallback } from "react"; interface PlayerListProps { players: Player[]; @@ -10,6 +11,9 @@ interface PlayerListProps { const PlayerList = ({ players, loading = false }: PlayerListProps) => { const navigate = useNavigate(); + + const handleClick = useCallback((playerId: string) => + navigate({ to: `/profile/${playerId} `}), [navigate]); if (loading) return {Array.from({ length: 10 }).map((_, i) => ( @@ -27,9 +31,7 @@ const PlayerList = ({ players, loading = false }: PlayerListProps) => { py='xs' icon={} style={{ cursor: 'pointer' }} - onClick={() => { - navigate({ to: `/profile/${player.id}` }); - }} + onClick={() => handleClick(player.id)} > {`${player.first_name} ${player.last_name}`} diff --git a/src/features/players/types.ts b/src/features/players/types.ts index 73ee166..497f2d8 100644 --- a/src/features/players/types.ts +++ b/src/features/players/types.ts @@ -2,7 +2,7 @@ import { Team } from "@/features/teams/types"; import { z } from 'zod'; export interface Player { - id?: string; + id: string; auth_id?: string; first_name?: string; last_name?: string; diff --git a/src/features/teams/components/team-list.tsx b/src/features/teams/components/team-list.tsx index be95e7b..10834f6 100644 --- a/src/features/teams/components/team-list.tsx +++ b/src/features/teams/components/team-list.tsx @@ -2,6 +2,22 @@ import { Group, List, ListItem, Skeleton, Stack, Text } from "@mantine/core"; import Avatar from "@/components/avatar"; import { Team } from "@/features/teams/types"; import { useNavigate } from "@tanstack/react-router"; +import { useCallback, useMemo } from "react"; +import React from "react"; + +interface TeamListItemProps { team: Team } +const TeamListItem = React.memo(({ team }: TeamListItemProps) => { + const playerNames = useMemo(() => team.players?.map(p => `${p.first_name} ${p.last_name}`) || [], [team.players]); + + return <> + + {`${team.name}`} + { + playerNames.map(name => {name}) + } + + +}) interface TeamListProps { teams: Team[]; @@ -11,6 +27,9 @@ interface TeamListProps { const TeamList = ({ teams, loading = false }: TeamListProps) => { const navigate = useNavigate(); + const handleClick = useCallback((teamId: string) => + navigate({ to: `/teams/${teamId}` }), [navigate]); + if (loading) return {Array.from({ length: 10 }).map((_, i) => ( } @@ -26,13 +45,9 @@ const TeamList = ({ teams, loading = false }: TeamListProps) => { py='xs' icon={} style={{ cursor: 'pointer' }} - onClick={() => navigate({ to: `/teams/${team.id}` })} + onClick={() => handleClick(team.id)} > - - {`${team.name}`} - {team.players?.map(p => {p.first_name} {p.last_name})} - - + ))} diff --git a/src/features/tournaments/components/tournament-form.tsx b/src/features/tournaments/components/tournament-form.tsx index fba9cb9..3d77cf1 100644 --- a/src/features/tournaments/components/tournament-form.tsx +++ b/src/features/tournaments/components/tournament-form.tsx @@ -11,6 +11,7 @@ import { logger } from ".."; import { useQueryClient } from "@tanstack/react-query"; import { tournamentQueries } from "@/features/tournaments/queries"; import { DateTimePicker } from "@mantine/dates"; +import { useCallback } from "react"; interface TournamentFormProps { close: () => void; @@ -48,7 +49,7 @@ const TournamentForm = ({ close, initialValues, tournamentId }: TournamentFormPr const isPending = createPending || updatePending; - const handleSubmit = async (values: TournamentFormInput) => { + const handleSubmit = useCallback(async (values: TournamentFormInput) => { const { logo, ...tournamentData } = values; const mutation = isEditMode ? updateTournament : createTournament; @@ -100,7 +101,7 @@ const TournamentForm = ({ close, initialValues, tournamentId }: TournamentFormPr logger.error(`Tournament ${isEditMode ? 'update' : 'create'} error`, error); } }); - } + }, [isEditMode, createTournament, updateTournament, queryClient]); return ( { const navigate = useNavigate(); + + const handleClick = useCallback((tournamentId: string) => + navigate({ to: `/tournaments/${tournamentId}` }), [navigate]); if (loading) return {Array.from({ length: 10 }).map((_, i) => ( @@ -27,9 +31,7 @@ const TournamentList = ({ tournaments, loading = false }: TournamentListProps) = py='xs' icon={} style={{ cursor: 'pointer' }} - onClick={() => { - navigate({ to: `/tournaments/${tournament.id}` }); - }} + onClick={() => handleClick(tournament.id)} > {`${tournament.name}`}