All files / web/src/arcade-games/rithmomachia/hooks useRosterWarning.ts

0% Statements 0/123
0% Branches 0/1
0% Functions 0/1
0% Lines 0/123

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124                                                                                                                                                                                                                                                       
import { useMemo } from 'react'
import type { RosterWarning } from '@/components/nav/GameContextNav'
import { useGameMode } from '@/contexts/GameModeContext'
import { useDeactivatePlayer, useKickUser } from '@/hooks/useRoomData'
import { useUserId } from '@/hooks/useUserId'
import { useRithmomachia } from '../Provider'

export function useRosterWarning(phase: 'setup' | 'playing'): RosterWarning | undefined {
  const { rosterStatus, whitePlayerId, blackPlayerId } = useRithmomachia()
  const {
    players: playerMap,
    activePlayers: activePlayerIds,
    addPlayer,
    setActive,
    roomData,
  } = useGameMode()
  const { data: viewerId } = useUserId()
  const { mutate: kickUser } = useKickUser()
  const { mutate: deactivatePlayer } = useDeactivatePlayer()

  return useMemo(() => {
    // Don't show notice for 'ok' or 'noLocalControl' (observers are allowed)
    if (rosterStatus.status === 'ok' || rosterStatus.status === 'noLocalControl') {
      return undefined
    }

    const playersArray = Array.from(playerMap.values()).sort((a, b) => {
      const aTime =
        typeof a.createdAt === 'number'
          ? a.createdAt
          : a.createdAt instanceof Date
            ? a.createdAt.getTime()
            : 0
      const bTime =
        typeof b.createdAt === 'number'
          ? b.createdAt
          : b.createdAt instanceof Date
            ? b.createdAt.getTime()
            : 0
      return aTime - bTime
    })

    const isHost =
      roomData && viewerId
        ? roomData.members?.find((m) => m.userId === viewerId)?.isCreator === true
        : false

    const removableLocalPlayers = playersArray.filter(
      (player) =>
        player.isLocal !== false &&
        activePlayerIds.has(player.id) &&
        player.id !== whitePlayerId &&
        player.id !== blackPlayerId
    )

    const kickablePlayers =
      isHost && roomData
        ? playersArray.filter(
            (player) =>
              player.isLocal === false &&
              activePlayerIds.has(player.id) &&
              player.id !== whitePlayerId &&
              player.id !== blackPlayerId
          )
        : []

    const inactiveLocalPlayer = playersArray.find(
      (player) => player.isLocal !== false && !activePlayerIds.has(player.id)
    )

    const handleKick = (player: any) => {
      if (!roomData) return
      for (const [userId, players] of Object.entries(roomData.memberPlayers ?? {})) {
        if (players.some((p) => p.id === player.id)) {
          kickUser({ roomId: roomData.id!, userId })
          break
        }
      }
    }

    if (rosterStatus.status === 'tooFew') {
      // During setup, don't show nav banner - SetupPlayerRequirement panel handles this
      if (phase === 'setup') {
        return undefined
      }

      // During playing phase, show nav warning banner
      const actions = []
      if (inactiveLocalPlayer) {
        actions.push({
          label: `Activate ${inactiveLocalPlayer.name}`,
          onClick: () => setActive(inactiveLocalPlayer.id, true),
        })
      } else {
        actions.push({
          label: 'Create local player',
          onClick: () => addPlayer({ isActive: true }),
        })
      }

      return {
        heading: 'Need two active players',
        description: 'Gameplay is paused until two players are active.',
        actions,
      }
    }

    return undefined
  }, [
    rosterStatus.status,
    phase,
    playerMap,
    activePlayerIds,
    whitePlayerId,
    blackPlayerId,
    roomData,
    viewerId,
    addPlayer,
    setActive,
    kickUser,
    deactivatePlayer,
  ])
}