diff --git a/app/hooks/useBracketDataWithEvents.ts b/app/hooks/useBracketDataWithEvents.ts index 65009fd08..8a1d16e15 100644 --- a/app/hooks/useBracketDataWithEvents.ts +++ b/app/hooks/useBracketDataWithEvents.ts @@ -1,7 +1,8 @@ -// TODO: use socket.io - +import { useLoaderData } from "remix"; import type { BracketModified } from "~/services/bracket"; import { Unpacked } from "~/utils"; +import * as React from "react"; +import { useSocketEvent } from "./useSocketEvent"; export type BracketData = { number: Unpacked["matches"]>["number"]; @@ -13,45 +14,52 @@ export type BracketData = { | null; }[]; -export function useBracketDataWithEvents() /*: BracketModified*/ { - // const data = useLoaderData(); - // const [dataWithEvents, setDataWithEvents] = React.useState(data); - // useEvents({ type: "bracket", bracketId: data.id }, (data: unknown) => { - // const dataMap = (data as BracketData).reduce( - // (map, bracketData) => map.set(bracketData.number, bracketData), - // new Map>() - // ); - // setDataWithEvents({ - // ...dataWithEvents, - // rounds: dataWithEvents.rounds.map((round) => ({ - // ...round, - // matches: round.matches.map((match) => { - // const bracketData = dataMap.get(match.number); - // if (match.number !== bracketData?.number) return match; - // // with null we overwrite - // // with undefined we use the previous value - // const getParticipants = () => { - // if (bracketData.participants === null) return undefined; - // if (bracketData.participants) return bracketData.participants; - // return match.participants; - // }; - // const getScore = () => { - // if (bracketData.score === null) return undefined; - // if (bracketData.score) return bracketData.score; - // return match.score; - // }; - // return { - // id: match.id, - // loserDestinationMatchId: match.loserDestinationMatchId, - // winnerDestinationMatchId: match.winnerDestinationMatchId, - // number: match.number, - // participantSourceMatches: match.participantSourceMatches, - // participants: getParticipants(), - // score: getScore(), - // }; - // }), - // })), - // }); - // }); - //return dataWithEvents; +export function useBracketDataWithEvents(): BracketModified { + const data = useLoaderData(); + const [dataWithEvents, setDataWithEvents] = React.useState(data); + + const eventHandler = React.useCallback( + (data: unknown) => { + const dataMap = (data as BracketData).reduce( + (map, bracketData) => map.set(bracketData.number, bracketData), + new Map>() + ); + setDataWithEvents({ + ...dataWithEvents, + rounds: dataWithEvents.rounds.map((round) => ({ + ...round, + matches: round.matches.map((match) => { + const bracketData = dataMap.get(match.number); + if (match.number !== bracketData?.number) return match; + // with null we overwrite + // with undefined we use the previous value + const getParticipants = () => { + if (bracketData.participants === null) return undefined; + if (bracketData.participants) return bracketData.participants; + return match.participants; + }; + const getScore = () => { + if (bracketData.score === null) return undefined; + if (bracketData.score) return bracketData.score; + return match.score; + }; + return { + id: match.id, + loserDestinationMatchId: match.loserDestinationMatchId, + winnerDestinationMatchId: match.winnerDestinationMatchId, + number: match.number, + participantSourceMatches: match.participantSourceMatches, + participants: getParticipants(), + score: getScore(), + }; + }), + })), + }); + }, + [data, setDataWithEvents] + ); + + useSocketEvent(`bracket-${data.id}`, eventHandler); + + return dataWithEvents; } diff --git a/app/routes/to/$organization.$tournament/bracket.$bid.tsx b/app/routes/to/$organization.$tournament/bracket.$bid.tsx index 21f092b0c..d2556d978 100644 --- a/app/routes/to/$organization.$tournament/bracket.$bid.tsx +++ b/app/routes/to/$organization.$tournament/bracket.$bid.tsx @@ -9,8 +9,14 @@ import type { BracketModified } from "~/services/bracket"; import { bracketById, reportScore, undoLastScore } from "~/services/bracket"; import type { FindTournamentByNameForUrlI } from "~/services/tournament"; import styles from "~/styles/tournament-bracket.css"; -import { parseRequestFormData, requireUser, safeJSONParse } from "~/utils"; +import { + getSocket, + parseRequestFormData, + requireUser, + safeJSONParse, +} from "~/utils"; import { useUser } from "~/hooks/common"; +import { useBracketDataWithEvents } from "~/hooks/useBracketDataWithEvents"; export const links: LinksFunction = () => { return [{ rel: "stylesheet", href: styles }]; @@ -61,11 +67,11 @@ export const action: ActionFunction = async ({ }); invariant(typeof params.bid === "string", "Expected params.bid to be string"); const user = requireUser(context); - //const events = requireEvents(context); + const socket = getSocket(context); switch (data._action) { case "REPORT_SCORE": { - /*const bracketData = */ await reportScore({ + const bracketData = await reportScore({ matchId: data.matchId, playerIds: data.playerIds, userId: user.id, @@ -73,26 +79,19 @@ export const action: ActionFunction = async ({ position: data.position, bracketId: params.bid, }); - // if (bracketData) { - // for (const { event } of events.bracket[params.bid]) { - // event(bracketData); - // } - // } + + socket.emit(`bracket-${params.bid}`, bracketData); return { ok: "REPORT_SCORE" }; } case "UNDO_REPORT_SCORE": { - /*const bracketData = */ await undoLastScore({ + const bracketData = await undoLastScore({ matchId: data.matchId, position: data.position, userId: user.id, }); - // if (bracketData) { - // for (const { event } of events.bracket[params.bid]) { - // event(bracketData); - // } - // } + socket.emit(`bracket-${params.bid}`, bracketData); return { ok: "UNDO_REPORT_SCORE" }; } @@ -116,8 +115,7 @@ export const loader: LoaderFunction = async ({ params }) => { // TODO: make bracket a bit smaller export default function BracketTabWrapper() { - // const data = useBracketDataWithEvents(); - const data = useLoaderData(); + const data = useBracketDataWithEvents(); const [, parentRoute] = useMatches(); const { teams } = parentRoute.data as FindTournamentByNameForUrlI; const user = useUser();