diff --git a/services/app/apps/codebattle/assets/js/widgets/components/TournamentType.jsx b/services/app/apps/codebattle/assets/js/widgets/components/TournamentType.jsx index 73cec0ca7..ad4c53a27 100644 --- a/services/app/apps/codebattle/assets/js/widgets/components/TournamentType.jsx +++ b/services/app/apps/codebattle/assets/js/widgets/components/TournamentType.jsx @@ -2,20 +2,22 @@ import React from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import TournamentTypeCodes from '../config/tournamentTypes'; + function TournamentType({ type }) { - if (type === 'ladder') { + if (type === TournamentTypeCodes.ladder) { return 'Ladder'; } - if (type === 'swiss') { + if (type === TournamentTypeCodes.swiss) { return 'Swiss'; } - if (type === 'individual') { + if (type === TournamentTypeCodes.individual) { return (); } - if (type === 'team') { + if (type === TournamentTypeCodes.team) { return ( <> @@ -25,7 +27,7 @@ function TournamentType({ type }) { ); } - if (type === 'stairway') { + if (type === TournamentTypeCodes.stairway) { return ( <> @@ -34,6 +36,12 @@ function TournamentType({ type }) { ); } + if (type === TournamentTypeCodes.show) { + return ( + + ); + } + return ( payload.state === 'game_over', // TODO: figureOut why soundWin doesn't work - actions: ['soundWin', 'handleGameAward', 'showGameResultModal'], + actions: ['soundWin', 'showGameResultModal'], }, 'user:give_up': { target: 'game_over', @@ -356,7 +356,6 @@ export const config = { handleReconnection: () => { }, // game actions - handleGameAward: () => { }, soundWin: () => { sound.play('win'); }, diff --git a/services/app/apps/codebattle/assets/js/widgets/middlewares/Room.js b/services/app/apps/codebattle/assets/js/widgets/middlewares/Room.js index a956d765c..f96964836 100644 --- a/services/app/apps/codebattle/assets/js/widgets/middlewares/Room.js +++ b/services/app/apps/codebattle/assets/js/widgets/middlewares/Room.js @@ -191,6 +191,14 @@ export const sendEditorCursorSelection = (startOffset, endOffset) => { }); }; +export const sendPassCode = (passCode, onError) => () => { + channel.push('enter_pass_code', { pass_code: passCode }) + .receive('ok', () => {}) + .receive('error', message => { + onError({ message }); + }); +}; + export const sendGiveUp = () => { channel.push('give_up', {}); }; diff --git a/services/app/apps/codebattle/assets/js/widgets/middlewares/Tournament.js b/services/app/apps/codebattle/assets/js/widgets/middlewares/Tournament.js index 9659e710d..b2ce4868c 100644 --- a/services/app/apps/codebattle/assets/js/widgets/middlewares/Tournament.js +++ b/services/app/apps/codebattle/assets/js/widgets/middlewares/Tournament.js @@ -4,6 +4,7 @@ import { camelizeKeys, decamelizeKeys } from 'humps'; import compact from 'lodash/compact'; import socket from '../../socket'; +import TournamentTypes from '../config/tournamentTypes'; import { actions } from '../slices'; const tournamentId = Gon.getAsset('tournament_id'); @@ -26,6 +27,7 @@ const initTournamentChannel = dispatch => { topPlayerIds: response.topPlayerIds || [], matches: {}, players: {}, + showBots: response.tournament.type !== TournamentTypes.show, channel: { online: true }, playersPageNumber: 1, playersPageSize: 20, @@ -33,6 +35,7 @@ const initTournamentChannel = dispatch => { dispatch(actions.updateTournamentPlayers(compact(response.players))); dispatch(actions.updateTournamentMatches(compact(response.matches))); + dispatch(actions.setTournamentTaskList(compact(response.tasksInfo))); }; channel.onMessage = (_event, payload) => camelizeKeys(payload); @@ -58,6 +61,7 @@ export const connectToTournament = () => dispatch => { dispatch(actions.updateTournamentData(response.tournament)); dispatch(actions.updateTournamentPlayers(compact(response.players || []))); dispatch(actions.updateTournamentMatches(compact(response.matches || []))); + dispatch(actions.setTournamentTaskList(compact(response.tasksInfo || []))); }; const handleMatchesUpdate = response => { diff --git a/services/app/apps/codebattle/assets/js/widgets/pages/RoomWidget.jsx b/services/app/apps/codebattle/assets/js/widgets/pages/RoomWidget.jsx index 2857a9304..93679d211 100644 --- a/services/app/apps/codebattle/assets/js/widgets/pages/RoomWidget.jsx +++ b/services/app/apps/codebattle/assets/js/widgets/pages/RoomWidget.jsx @@ -1,28 +1,25 @@ -import React, { useEffect } from 'react'; +import React from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { useDispatch, useSelector } from 'react-redux'; +import cn from 'classnames'; import { CSSTransition, SwitchTransition } from 'react-transition-group'; import FeedbackAlertNotification from '../components/FeedbackAlertNotification'; import FeedbackWidget from '../components/FeedbackWidget'; import GameWidgetGuide from '../components/GameWidgetGuide'; import RoomContext from '../components/RoomContext'; -import PageNames from '../config/pageNames'; -import sound from '../lib/sound'; import * as machineSelectors from '../machines/selectors'; -import * as ChatActions from '../middlewares/Chat'; -import * as GameRoomActions from '../middlewares/Room'; -import * as selectors from '../selectors'; -import { actions } from '../slices'; import useGameRoomMachine from '../utils/useGameRoomMachine'; import useGameRoomModals from '../utils/useGameRoomModals'; +import useGameRoomSocketChannel from '../utils/useGameRoomSocketChannel'; +import useGameRoomSoundSettings from '../utils/useGameRoomSoundSettings'; import useMachineStateSelector from '../utils/useMachineStateSelector'; import useRoomSettings from '../utils/useRoomSettings'; import BuilderEditorsWidget from './builder/BuilderEditorsWidget'; import BuilderSettingsWidget from './builder/BuilderSettingsWidget'; import CodebattlePlayer from './game/CodebattlePlayer'; +import GameRoomLockPanel from './game/GameRoomLockPanel'; import GameWidget from './game/GameWidget'; import InfoWidget from './game/InfoWidget'; import NetworkAlert from './game/NetworkAlert'; @@ -35,10 +32,6 @@ function RoomWidget({ taskMachine, editorMachine, }) { - const dispatch = useDispatch(); - - const useChat = useSelector(selectors.gameUseChatSelector); - const mute = useSelector(state => state.user.settings.mute); const machines = useGameRoomMachine({ mainMachine, taskMachine, @@ -50,6 +43,7 @@ function RoomWidget({ ); const gameRoomKey = machineSelectors.gameRoomKeySelector(roomMachineState); + const mute = useGameRoomSoundSettings(); const { tournamentId, viewMode, @@ -58,54 +52,11 @@ function RoomWidget({ showTaskBuilder, showTimeoutMessage, showReplayer, + roomLocked = false, + disabled = false, } = useRoomSettings(pageName, roomMachineState); useGameRoomModals(machines); - - useEffect(() => { - if (pageName === PageNames.builder) { - const clearTask = GameRoomActions.connectToTask( - machines.mainService, - machines.taskService, - )(dispatch); - - return clearTask; - } - - const options = { cancelRedirect: false }; - - const clearGame = GameRoomActions.connectToGame(machines.mainService, options)( - dispatch, - ); - const clearChat = ChatActions.connectToChat(useChat)(dispatch); - - return () => { - clearGame(); - clearChat(); - }; - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - - useEffect(() => { - const muteSound = e => { - if ((e.ctrlKey || e.metaKey) && e.key === 'm') { - e.preventDefault(); - - if (mute) { - sound.toggle(); - } else { - sound.toggle(0); - } - - actions.toggleMuteSound(); - } - }; - - window.addEventListener('keydown', muteSound); - - return () => { - window.removeEventListener('keydown', muteSound); - }; - }, [mute]); + useGameRoomSocketChannel(pageName, machines); if (showWaitingRoom) { const gameUrl = window.location.href; @@ -130,7 +81,13 @@ function RoomWidget({ -
+
{showTaskBuilder && ( <> @@ -158,6 +115,18 @@ function RoomWidget({
{showReplayer && }
+
+ +
diff --git a/services/app/apps/codebattle/assets/js/widgets/pages/game/GameRoomLockPanel.jsx b/services/app/apps/codebattle/assets/js/widgets/pages/game/GameRoomLockPanel.jsx new file mode 100644 index 000000000..cafea69fb --- /dev/null +++ b/services/app/apps/codebattle/assets/js/widgets/pages/game/GameRoomLockPanel.jsx @@ -0,0 +1,69 @@ +import React, { useState, useRef, useCallback } from 'react'; + +import cn from 'classnames'; +import { useDispatch } from 'react-redux'; + +import { sendPassCode } from '../../middlewares/Room'; + +const passCodeLength = 8; + +function GameRoomLockPanel() { + const dispatch = useDispatch(); + + const inputRef = useRef(null); + + const [error, setError] = useState(null); + + const onChangePassCode = useCallback(() => { + if (error) { + setError(null); + } + }, [error, setError]); + const onSubmitCode = useCallback(() => { + const value = (inputRef.current.value || '').replaceAll(' ', ''); + const onError = err => setError(err); + + if (passCodeLength === value.length) { + onError({ + message: `Only ${passCodeLength} character pass code (now ${value.length})`, + }); + return; + } + + dispatch(sendPassCode(value, onError)); + }, [inputRef, setError, dispatch]); + + const inputClassName = cn('form-control', { + 'is-invalid': !!error, + }); + + return ( +
+ Game is Locked +
+ + +
+
+ Example: 12345678 + {error && {error.message}} +
+
+ ); +} + +export default GameRoomLockPanel; diff --git a/services/app/apps/codebattle/assets/js/widgets/pages/tournament/CustomTournamentInfoPanel.jsx b/services/app/apps/codebattle/assets/js/widgets/pages/tournament/CustomTournamentInfoPanel.jsx index de6fa33b0..314d47b25 100644 --- a/services/app/apps/codebattle/assets/js/widgets/pages/tournament/CustomTournamentInfoPanel.jsx +++ b/services/app/apps/codebattle/assets/js/widgets/pages/tournament/CustomTournamentInfoPanel.jsx @@ -14,6 +14,7 @@ function CustomTournamentInfoPanel({ currentRoundPosition = 0, matches, players, + taskList, topPlayerIds, currentUserId, pageNumber, @@ -57,10 +58,11 @@ function CustomTournamentInfoPanel({ } disabledSearch={!isAdmin && !isOwner} /> - {!hideCustomGameConsole && ( + {!hideCustomGameConsole && (isOwner || isAdmin) && ( )} diff --git a/services/app/apps/codebattle/assets/js/widgets/pages/tournament/PlayersPanel.jsx b/services/app/apps/codebattle/assets/js/widgets/pages/tournament/PlayersPanel.jsx index e0a622434..55095e2a3 100644 --- a/services/app/apps/codebattle/assets/js/widgets/pages/tournament/PlayersPanel.jsx +++ b/services/app/apps/codebattle/assets/js/widgets/pages/tournament/PlayersPanel.jsx @@ -8,6 +8,7 @@ const Players = ({ playersCount, players, canBan, + showBots, handleKick, }) => (
@@ -27,23 +28,25 @@ const Players = ({ {playersCount === 0 ? (

NO_PARTICIPANTS_YET

) : ( - Object.values(players).slice(0, 30).map(player => ( -
-
- + Object.values(players) + .filter(player => (showBots ? true : !player.isBot)) + .slice(0, 30).map(player => ( +
+
+ +
+ {canBan && ( + + )}
- {canBan && ( - - )} -
- )) + )) )}
diff --git a/services/app/apps/codebattle/assets/js/widgets/pages/tournament/Tournament.jsx b/services/app/apps/codebattle/assets/js/widgets/pages/tournament/Tournament.jsx index 879a14f97..2caf09387 100644 --- a/services/app/apps/codebattle/assets/js/widgets/pages/tournament/Tournament.jsx +++ b/services/app/apps/codebattle/assets/js/widgets/pages/tournament/Tournament.jsx @@ -17,6 +17,7 @@ import { kickFromTournament, } from '../../middlewares/Tournament'; import * as selectors from '../../selectors'; +import { actions } from '../../slices'; import CustomTournamentInfoPanel from './CustomTournamentInfoPanel'; import DetailsModal from './DetailsModal'; @@ -68,6 +69,7 @@ function InfoPanel({ return ( @@ -113,8 +119,10 @@ function Tournament() { ] = useState(false); const playersCount = useMemo( - () => Object.keys(tournament.players).length, - [tournament.players], + () => Object.values(tournament.players) + .filter(player => (tournament.showBots ? true : !player.isBot)) + .length, + [tournament.players, tournament.showBots], ); const isOver = useMemo( () => [TournamentStates.finished, TournamentStates.cancelled].includes( @@ -133,6 +141,9 @@ function Tournament() { const onCloseRoundConfirmationModal = useCallback(() => { setStartRoundConfirmationModalShowing(false); }, [setStartRoundConfirmationModalShowing]); + const toggleShowBots = useCallback(() => { + dispatch(actions.toggleShowBots()); + }, [dispatch]); const handleKick = useCallback(event => { const { playerId } = event.currentTarget.dataset; if (playerId) { @@ -243,12 +254,14 @@ function Tournament() { players={tournament.players} playersCount={playersCount} playersLimit={tournament.playersLimit} + showBots={tournament.showBots} hideResults={hideResults} startsAt={tournament.startsAt} state={tournament.state} type={tournament.type} handleStartRound={handleStartRound} handleOpenDetails={handleOpenDetails} + toggleShowBots={toggleShowBots} />
@@ -267,12 +280,13 @@ function Tournament() {
{tournament.useChat && ()} diff --git a/services/app/apps/codebattle/assets/js/widgets/pages/tournament/TournamentGameCreatePanel.jsx b/services/app/apps/codebattle/assets/js/widgets/pages/tournament/TournamentGameCreatePanel.jsx index 5339d7985..935e51c52 100644 --- a/services/app/apps/codebattle/assets/js/widgets/pages/tournament/TournamentGameCreatePanel.jsx +++ b/services/app/apps/codebattle/assets/js/widgets/pages/tournament/TournamentGameCreatePanel.jsx @@ -4,6 +4,7 @@ import React, { import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import MatchStates from '../../config/matchStates'; import { createCustomGame } from '../../middlewares/Tournament'; import { tournamentEmptyPlayerUrl } from '../../utils/urlBuilders'; @@ -12,23 +13,44 @@ const emptyPlayer = {}; function TournamentGameCreatePanel({ players, matches, + taskList = [], currentRoundPosition, }) { const [selectedPlayer, setSelectedPlayer] = useState(emptyPlayer); const [selectedTaskLevel, setSelectedTaskLevel] = useState(); - const alreadyHaveActiveMatch = useMemo(() => { - if (!selectedPlayer) return false; + const activeMatch = useMemo(() => { + if (!selectedPlayer) return null; const activeMatches = Object.values(matches) .filter(match => ( match.roundPosition === currentRoundPosition && match.playerIds.includes(selectedPlayer.id) - && match.state === 'playing' + && match.state === MatchStates.playing )); - return activeMatches.length !== 0; + if (activeMatches.length === 0) { + return null; + } + return activeMatches[0]; }, [selectedPlayer, matches, currentRoundPosition]); + const availableTasks = useMemo(() => ( + taskList.reduce((acc, task) => { + if (selectedPlayer && players[selectedPlayer.id]?.taskIds?.includes(task.id)) { + return acc; + } + + acc[task.level].push(task); + + return acc; + }, { + elementary: [], + easy: [], + medium: [], + hard: [], + }) + ), [selectedPlayer, players, taskList]); + const clearSelectedPlayer = useCallback(() => { setSelectedPlayer(); setSelectedTaskLevel(); @@ -40,7 +62,7 @@ function TournamentGameCreatePanel({ useEffect(() => { if (selectedPlayer === emptyPlayer) { const playersListWithoutBots = Object.values(players) - .filter(player => !player.isBot); + .filter(player => !player.isBot); if (playersListWithoutBots.length === 1) { setSelectedPlayer(playersListWithoutBots[0]); @@ -78,29 +100,54 @@ function TournamentGameCreatePanel({ )} {selectedPlayer && !selectedTaskLevel && ( <> -
- {`Choose task level for player ${selectedPlayer.name}: `} -
+
+ + {'Choose task level for player '} + {selectedPlayer.name} + : + +
+
@@ -123,7 +170,7 @@ function TournamentGameCreatePanel({ {`Player: ${selectedPlayer.name}`}
- {`Level: ${selectedTaskLevel}`} + {`Level: ${selectedTaskLevel} (${availableTasks[selectedTaskLevel].length} available)`}
- {alreadyHaveActiveMatch ? ( + {activeMatch ? (
diff --git a/services/app/apps/codebattle/assets/js/widgets/pages/tournament/TournamentMainControlButtons.jsx b/services/app/apps/codebattle/assets/js/widgets/pages/tournament/TournamentMainControlButtons.jsx index 0dbbe95e3..25dfe0e0f 100644 --- a/services/app/apps/codebattle/assets/js/widgets/pages/tournament/TournamentMainControlButtons.jsx +++ b/services/app/apps/codebattle/assets/js/widgets/pages/tournament/TournamentMainControlButtons.jsx @@ -29,9 +29,12 @@ const TournamentMainControlButtons = ({ canStart, canStartRound, canFinishRound, + canToggleShowBots, canRestart, - disabled = true, + showBots, hideResults, + disabled = true, + toggleShowBots, handleStartRound, handleOpenDetails, }) => { @@ -115,6 +118,14 @@ const TournamentMainControlButtons = ({ Show Results + + + {showBots ? 'Hide bots' : 'Show bots'} + , * tournamentsInfo: {?Object}, @@ -364,6 +367,11 @@ const defaultTournamentPlayerParams = { * alerts: Object, * }} GameState * @typedef {{ + * id: number, + * level: @type {import("../config/levels.js").default}, + * name: string, + * }} TaskInfo + * @typedef {{ * accessToken: string, * accessType: string, * breakDurationSeconds: number, @@ -371,7 +379,7 @@ const defaultTournamentPlayerParams = { * currentRoundPosition: number, * defaultLanguage: string, * description: string, - * level: string, + * level: @type {import("../config/levels.js").default}, * matchTimeoutSeconds: number, * matches: Object, * lastRoundStartedAt: string, @@ -380,6 +388,7 @@ const defaultTournamentPlayerParams = { * name: string, * playedPairIds: number[], * players: Object, + * taskList: TaskInfo[], * playersCount: number, * playersLimit: number, * startsAt: string, @@ -387,6 +396,8 @@ const defaultTournamentPlayerParams = { * taskStrategy: string, * type: string, * useChat: boolean, + * showBots: boolean, + * showResults: boolean, * }} TournamentState * * @typedef {{ @@ -415,6 +426,8 @@ const defaultTournamentPlayerParams = { export default { game: { gameStatus: initialGameStatus, + award: null, + awardStatus: 'idle', task: initialGameTask, players: initialPlayers, tournamentsInfo: null, diff --git a/services/app/apps/codebattle/assets/js/widgets/slices/tournament.js b/services/app/apps/codebattle/assets/js/widgets/slices/tournament.js index 2ee132c90..16eca57b2 100644 --- a/services/app/apps/codebattle/assets/js/widgets/slices/tournament.js +++ b/services/app/apps/codebattle/assets/js/widgets/slices/tournament.js @@ -1,6 +1,8 @@ import { createSlice } from '@reduxjs/toolkit'; import omit from 'lodash/omit'; +import TournamentTypes from '../config/tournamentTypes'; + import initial from './initial'; const initialState = initial.tournament; @@ -14,7 +16,12 @@ const tournament = createSlice({ }), updateTournamentData: (state, { payload }) => ({ ...state, - ...(['swiss', 'ladder', 'stairway'].includes(payload.type) ? omit(payload, ['matches', 'players']) : payload), + ...( + [TournamentTypes.swiss, TournamentTypes.ladder, TournamentTypes.stairway, TournamentTypes.show] + .includes(payload.type) + ? omit(payload, ['matches', 'players']) + : payload + ), }), updateTournamentMatches: (state, { payload }) => { const newMatches = payload.reduce((acc, match) => ({ @@ -30,6 +37,9 @@ const tournament = createSlice({ ...newMatches, }; }, + setTournamentTaskList: (state, { payload }) => { + state.taskList = payload; + }, addTournamentPlayer: (state, { payload }) => { state.players = { ...state.players, [payload.player.id]: payload.player }; }, @@ -74,6 +84,11 @@ const tournament = createSlice({ setTournamentPlayersPageNumber: (state, { payload }) => { state.playersPageNumber = payload; }, + toggleShowBots: state => { + if (state.type === TournamentTypes.show) { + state.showBots = !state.showBots; + } + }, }, }); diff --git a/services/app/apps/codebattle/assets/js/widgets/utils/useGameRoomSocketChannel.js b/services/app/apps/codebattle/assets/js/widgets/utils/useGameRoomSocketChannel.js new file mode 100644 index 000000000..d14898c52 --- /dev/null +++ b/services/app/apps/codebattle/assets/js/widgets/utils/useGameRoomSocketChannel.js @@ -0,0 +1,40 @@ +import { useEffect } from 'react'; + +import { useDispatch, useSelector } from 'react-redux'; + +import PageNames from '../config/pageNames'; +import * as ChatActions from '../middlewares/Chat'; +import * as GameRoomActions from '../middlewares/Room'; +import * as selectors from '../selectors'; + +const useGameRoomSocketChannel = (pageName, machines) => { + const dispatch = useDispatch(); + + const useChat = useSelector(selectors.gameUseChatSelector); + + useEffect(() => { + if (pageName === PageNames.builder) { + const clearTask = GameRoomActions.connectToTask( + machines.mainService, + machines.taskService, + )(dispatch); + + return clearTask; + } + + const options = { cancelRedirect: false }; + + const clearGame = GameRoomActions.connectToGame(machines.mainService, options)( + dispatch, + ); + const clearChat = ChatActions.connectToChat(useChat)(dispatch); + + return () => { + clearGame(); + clearChat(); + }; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); +}; + +export default useGameRoomSocketChannel; diff --git a/services/app/apps/codebattle/assets/js/widgets/utils/useGameRoomSoundSettings.js b/services/app/apps/codebattle/assets/js/widgets/utils/useGameRoomSoundSettings.js new file mode 100644 index 000000000..3c4b593de --- /dev/null +++ b/services/app/apps/codebattle/assets/js/widgets/utils/useGameRoomSoundSettings.js @@ -0,0 +1,38 @@ +import { useEffect } from 'react'; + +import { useDispatch, useSelector } from 'react-redux'; + +import sound from '../lib/sound'; +import { actions } from '../slices'; + +const useGameRoomSoundSettings = () => { + const dispatch = useDispatch(); + + const mute = useSelector(state => state.user.settings.mute); + + useEffect(() => { + const muteSound = e => { + if ((e.ctrlKey || e.metaKey) && e.key === 'm') { + e.preventDefault(); + + if (mute) { + sound.toggle(); + } else { + sound.toggle(0); + } + + dispatch(actions.toggleMuteSound()); + } + }; + + window.addEventListener('keydown', muteSound); + + return () => { + window.removeEventListener('keydown', muteSound); + }; + }, [dispatch, mute]); + + return mute; +}; + +export default useGameRoomSoundSettings; diff --git a/services/app/apps/codebattle/assets/js/widgets/utils/useRoomSettings.js b/services/app/apps/codebattle/assets/js/widgets/utils/useRoomSettings.js index 8d51ceee6..fefd1b3c7 100644 --- a/services/app/apps/codebattle/assets/js/widgets/utils/useRoomSettings.js +++ b/services/app/apps/codebattle/assets/js/widgets/utils/useRoomSettings.js @@ -30,10 +30,9 @@ const useRoomSettings = (pageName, roomMachineState) => { const showBattleRoom = !showTaskBuilder; const showTimeoutMessage = gameStatus.state === GameStateCodes.timeout && !(firstPlayer && secondPlayer); - console.log(gameStatus); - return { tournamentId, + // viewMode: BattleRoomViewModesCodes.single, viewMode: mapGameTypeOnViewMode[gameStatus.type] || BattleRoomViewModesCodes.duel, showWaitingRoom, showBattleRoom, diff --git a/services/app/apps/codebattle/lib/codebattle/game/auth.ex b/services/app/apps/codebattle/lib/codebattle/game/auth.ex index d54c8832f..78d67e593 100644 --- a/services/app/apps/codebattle/lib/codebattle/game/auth.ex +++ b/services/app/apps/codebattle/lib/codebattle/game/auth.ex @@ -17,7 +17,7 @@ defmodule Codebattle.Game.Auth do is_player = Game.Context.get_active_games() |> Enum.any?(fn game -> - Game.Helpers.is_player?(game, player.id) + Game.Helpers.player?(game, player.id) end) case is_player do @@ -27,7 +27,7 @@ defmodule Codebattle.Game.Auth do end def player_can_cancel_game?(game, player) do - case {Game.Helpers.is_player?(game, player.id), game.state} do + case {Game.Helpers.player?(game, player.id), game.state} do {true, "waiting_opponent"} -> :ok {false, _} -> {:error, :not_authorized} {_, _} -> {:error, :only_waiting_opponent} @@ -35,7 +35,7 @@ defmodule Codebattle.Game.Auth do end def player_can_rematch?(game, player_id) do - case Game.Helpers.is_player?(game, player_id) do + case Game.Helpers.player?(game, player_id) do true -> :ok false -> {:error, :not_authorized} end diff --git a/services/app/apps/codebattle/lib/codebattle/game/helpers.ex b/services/app/apps/codebattle/lib/codebattle/game/helpers.ex index d373263a1..1490ae87d 100644 --- a/services/app/apps/codebattle/lib/codebattle/game/helpers.ex +++ b/services/app/apps/codebattle/lib/codebattle/game/helpers.ex @@ -38,7 +38,7 @@ defmodule Codebattle.Game.Helpers do |> Enum.find(fn player -> player.id == id end) end - def is_player?(game, player_id) do + def player?(game, player_id) do game |> get_players |> Enum.any?(&(&1.id == player_id)) @@ -75,10 +75,10 @@ defmodule Codebattle.Game.Helpers do |> Enum.into(%{}) end - def winner?(game, player_id), do: is_player_result?(game, player_id, "won") + def winner?(game, player_id), do: player_result?(game, player_id, "won") - def lost?(game, player_id), do: is_player_result?(game, player_id, "lost") - def gave_up?(game, player_id), do: is_player_result?(game, player_id, "gave_up") + def lost?(game, player_id), do: player_result?(game, player_id, "lost") + def gave_up?(game, player_id), do: player_result?(game, player_id, "gave_up") def update_player(game, player_id, params) do new_players = @@ -126,7 +126,7 @@ defmodule Codebattle.Game.Helpers do } end - defp is_player_result?(game, player_id, result) do + defp player_result?(game, player_id, result) do game |> get_players |> Enum.find_value(fn p -> p.id == player_id && p.result == result end) diff --git a/services/app/apps/codebattle/lib/codebattle/tournament/helpers.ex b/services/app/apps/codebattle/lib/codebattle/tournament/helpers.ex index 5bab67d62..f80f42dff 100644 --- a/services/app/apps/codebattle/lib/codebattle/tournament/helpers.ex +++ b/services/app/apps/codebattle/lib/codebattle/tournament/helpers.ex @@ -15,6 +15,7 @@ defmodule Codebattle.Tournament.Helpers do def get_players(tournament, ids), do: Tournament.Players.get_players(tournament, ids) + def get_tasks(tournament = %{tasks_table: nil}), do: [] def get_tasks(tournament), do: Tournament.Tasks.get_tasks(tournament) def players_count(tournament = %{players_table: nil}) do @@ -135,7 +136,7 @@ defmodule Codebattle.Tournament.Helpers do ) end - def is_match_player?(match, player_id), do: Enum.any?(match.player_ids, &(&1 == player_id)) + def match_player?(match, player_id), do: Enum.any?(match.player_ids, &(&1 == player_id)) def get_player_ids(tournament), do: tournament |> get_players |> Enum.map(& &1.id) @@ -150,37 +151,37 @@ defmodule Codebattle.Tournament.Helpers do def can_be_started?(_t), do: false def can_moderate?(tournament, user) do - is_creator?(tournament, user) || User.admin?(user) + creator?(tournament, user) || User.admin?(user) end def can_access?(tournament = %{access_type: "token"}, user, params) do can_moderate?(tournament, user) || - is_player?(tournament, user.id) || + player?(tournament, user.id) || params["access_token"] == tournament.access_token end # default public or null for old tournaments def can_access?(_tournament, _user, _params), do: true - def is_active?(tournament), do: tournament.state == "active" - def is_waiting_participants?(tournament), do: tournament.state == "waiting_participants" - def is_canceled?(tournament), do: tournament.state == "canceled" - def is_finished?(tournament), do: tournament.state == "finished" - def is_individual?(tournament), do: tournament.type == "individual" - def is_stairway?(tournament), do: tournament.type == "stairway" - def is_team?(tournament), do: tournament.type == "team" - def is_public?(tournament), do: tournament.access_type == "public" - def is_visible_by_token?(tournament), do: tournament.access_type == "token" + def active?(tournament), do: tournament.state == "active" + def waiting_participants?(tournament), do: tournament.state == "waiting_participants" + def canceled?(tournament), do: tournament.state == "canceled" + def finished?(tournament), do: tournament.state == "finished" + def individual?(tournament), do: tournament.type == "individual" + def stairway?(tournament), do: tournament.type == "stairway" + def team?(tournament), do: tournament.type == "team" + def public?(tournament), do: tournament.access_type == "public" + def visible_by_token?(tournament), do: tournament.access_type == "token" def in_break?(tournament), do: tournament.break_state == "on" - def is_player?(tournament, player_id) do + def player?(tournament, player_id) do tournament |> get_player(player_id) |> Kernel.!() |> Kernel.!() end - def is_player?(tournament, player_id, team_id) do + def player?(tournament, player_id, team_id) do tournament |> get_player(player_id) |> case do @@ -189,7 +190,7 @@ defmodule Codebattle.Tournament.Helpers do end end - def is_creator?(tournament, user) do + def creator?(tournament, user) do tournament.creator_id == user.id end diff --git a/services/app/apps/codebattle/lib/codebattle/tournament/server.ex b/services/app/apps/codebattle/lib/codebattle/tournament/server.ex index 21e9f9d9b..9a83865d3 100644 --- a/services/app/apps/codebattle/lib/codebattle/tournament/server.ex +++ b/services/app/apps/codebattle/lib/codebattle/tournament/server.ex @@ -144,7 +144,7 @@ defmodule Codebattle.Tournament.Server do def handle_info({:stop_round_break, round_position}, %{tournament: tournament}) do if tournament.current_round_position == round_position and in_break?(tournament) and - not is_finished?(tournament) do + not finished?(tournament) do new_tournament = tournament.module.stop_round_break(tournament) {:noreply, %{tournament: new_tournament}} @@ -156,7 +156,7 @@ defmodule Codebattle.Tournament.Server do def handle_info({:finish_round_force, round_position}, %{tournament: tournament}) do if tournament.current_round_position == round_position and not in_break?(tournament) and - not is_finished?(tournament) do + not finished?(tournament) do new_tournament = tournament.module.finish_round(tournament) {:noreply, %{tournament: new_tournament}} @@ -168,7 +168,7 @@ defmodule Codebattle.Tournament.Server do def handle_info({:start_rematch, match_ref, round_position}, %{tournament: tournament}) do if tournament.current_round_position == round_position and not in_break?(tournament) and - not is_finished?(tournament) do + not finished?(tournament) do new_tournament = tournament.module.start_rematch(tournament, match_ref) broadcast_tournament_update(new_tournament) @@ -191,7 +191,7 @@ defmodule Codebattle.Tournament.Server do if tournament.current_round_position == match.round_position and not in_break?(tournament) and - not is_finished?(tournament) do + not finished?(tournament) do new_tournament = tournament.module.finish_match(tournament, Map.put(payload, :game_id, match.game_id)) diff --git a/services/app/apps/codebattle/lib/codebattle/tournament/strategy/base.ex b/services/app/apps/codebattle/lib/codebattle/tournament/strategy/base.ex index ef766a415..522905811 100644 --- a/services/app/apps/codebattle/lib/codebattle/tournament/strategy/base.ex +++ b/services/app/apps/codebattle/lib/codebattle/tournament/strategy/base.ex @@ -575,6 +575,7 @@ defmodule Codebattle.Tournament.Base do defp broadcast_round_created(tournament) do Codebattle.PubSub.broadcast("tournament:round_created", %{tournament: tournament}) + tournament end diff --git a/services/app/apps/codebattle/lib/codebattle/tournament/tournament.ex b/services/app/apps/codebattle/lib/codebattle/tournament/tournament.ex index 398ecbfab..314d0d48d 100644 --- a/services/app/apps/codebattle/lib/codebattle/tournament/tournament.ex +++ b/services/app/apps/codebattle/lib/codebattle/tournament/tournament.ex @@ -126,6 +126,7 @@ defmodule Codebattle.Tournament do :task_pack_name, :task_provider, :task_strategy, + :task_pack_name, :type, :use_chat, :use_infinite_break, diff --git a/services/app/apps/codebattle/lib/codebattle_web/channels/lobby_channel.ex b/services/app/apps/codebattle/lib/codebattle_web/channels/lobby_channel.ex index 0a177828a..7d7353388 100644 --- a/services/app/apps/codebattle/lib/codebattle_web/channels/lobby_channel.ex +++ b/services/app/apps/codebattle/lib/codebattle_web/channels/lobby_channel.ex @@ -102,7 +102,7 @@ defmodule CodebattleWeb.LobbyChannel do def handle_info(_, socket), do: {:noreply, socket} defp can_user_see_game?(game, user) do - game.visibility_type == "public" || Game.Helpers.is_player?(game, user) + game.visibility_type == "public" || Game.Helpers.player?(game, user) end defp add_players(acc, %{"opponent_type" => "bot"}, user), diff --git a/services/app/apps/codebattle/lib/codebattle_web/channels/tournament_channel.ex b/services/app/apps/codebattle/lib/codebattle_web/channels/tournament_channel.ex index 633abe1bb..7b78535bd 100644 --- a/services/app/apps/codebattle/lib/codebattle_web/channels/tournament_channel.ex +++ b/services/app/apps/codebattle/lib/codebattle_web/channels/tournament_channel.ex @@ -253,12 +253,19 @@ defmodule CodebattleWeb.TournamentChannel do def handle_info(%{event: "tournament:updated", payload: payload}, socket) do matches = - if payload.tournament.type in ["swiss", "ladder"] do + if payload.tournament.type in ["swiss", "ladder", "show"] do [] else Helpers.get_matches(payload.tournament) end + tasks_info = + if payload.tournament.type == "show" do + Helpers.get_tasks(payload.tournament) + else + [] + end + push(socket, "tournament:update", %{ tournament: Map.drop(payload.tournament, [ @@ -274,7 +281,8 @@ defmodule CodebattleWeb.TournamentChannel do :played_pair_ids ]), players: Helpers.get_top_players(payload.tournament), - matches: matches + matches: matches, + tasks_info: tasks_info }) {:noreply, socket} @@ -287,7 +295,10 @@ defmodule CodebattleWeb.TournamentChannel do end def handle_info(%{event: "tournament:round_created", payload: payload}, socket) do - push(socket, "tournament:round_created", %{tournament: payload.tournament}) + push(socket, "tournament:round_created", %{ + tournament: payload.tournament, + tasks_info: payload.tasks_info + }) {:noreply, socket} end @@ -341,7 +352,7 @@ defmodule CodebattleWeb.TournamentChannel do tournament end - defp get_tournament_join_payload(%{type: type} = tournament, socket) + defp get_tournament_join_payload(tournament = %{type: type}, socket) when type in ["swiss", "ladder", "stairway"] do current_user = socket.assigns.current_user @@ -387,7 +398,7 @@ defmodule CodebattleWeb.TournamentChannel do } end - defp get_tournament_join_payload(%{type: "show"} = tournament, _socket) do + defp get_tournament_join_payload(tournament = %{type: "show"}, _socket) do %{ tournament: Map.drop(tournament, [:players_table, :matches_table, :tasks_table]), matches: Helpers.get_matches(tournament), diff --git a/services/app/apps/codebattle/lib/codebattle_web/controllers/api/v1/user_game_report_controller.ex b/services/app/apps/codebattle/lib/codebattle_web/controllers/api/v1/user_game_report_controller.ex index e5b6a8265..e452a8619 100644 --- a/services/app/apps/codebattle/lib/codebattle_web/controllers/api/v1/user_game_report_controller.ex +++ b/services/app/apps/codebattle/lib/codebattle_web/controllers/api/v1/user_game_report_controller.ex @@ -13,8 +13,8 @@ defmodule CodebattleWeb.Api.V1.UserGameReportController do reporter = conn.assigns.current_user game = Game.Context.get_game!(game_id) - is_reporter_player = Game.Helpers.is_player?(game, reporter.id) - is_reported_user_player = Game.Helpers.is_player?(game, reported_user_id) + is_reporter_player = Game.Helpers.player?(game, reporter.id) + is_reported_user_player = Game.Helpers.player?(game, reported_user_id) is_reported_himself = reporter.id == reported_user_id case {is_reporter_player, is_reported_himself, is_reported_user_player} do diff --git a/services/app/apps/codebattle/lib/codebattle_web/controllers/game_controller.ex b/services/app/apps/codebattle/lib/codebattle_web/controllers/game_controller.ex index 6589507ed..0f2535f9f 100644 --- a/services/app/apps/codebattle/lib/codebattle_web/controllers/game_controller.ex +++ b/services/app/apps/codebattle/lib/codebattle_web/controllers/game_controller.ex @@ -33,7 +33,7 @@ defmodule CodebattleWeb.GameController do players: present_users_for_gon(Helpers.get_players(game)) ) - is_player = Helpers.is_player?(game, user.id) + is_player = Helpers.player?(game, user.id) case {game.state, is_player} do {"waiting_opponent", false} -> diff --git a/services/app/apps/codebattle/lib/codebattle_web/live/components/tournament/edit_form.ex b/services/app/apps/codebattle/lib/codebattle_web/live/components/tournament/edit_form.ex index b1269e0a2..a7f1bd570 100644 --- a/services/app/apps/codebattle/lib/codebattle_web/live/components/tournament/edit_form.ex +++ b/services/app/apps/codebattle/lib/codebattle_web/live/components/tournament/edit_form.ex @@ -108,14 +108,14 @@ defmodule CodebattleWeb.Live.Tournament.EditFormComponent do ) %> <%= error_tag(f, :task_provider) %>
- <%= if (f.params["task_provider"] == "level" || is_nil(f.params["task_provider"])) do %> + <%= if (f.params["task_provider"] == "level" || f.data.task_provider == "level") do %>
<%= label(f, :level) %> <%= select(f, :level, Codebattle.Tournament.levels(), class: "custom-select") %> <%= error_tag(f, :level) %>
<% end %> - <%= if (f.params["task_provider"] == "task_pack") do %> + <%= if (f.params["task_provider"] == "task_pack" || f.data.task_provider == "task_pack") do %>
<%= label(f, :task_pack_name) %> <%= select(f, :task_pack_name, @task_pack_names, @@ -125,7 +125,7 @@ defmodule CodebattleWeb.Live.Tournament.EditFormComponent do <%= error_tag(f, :task_pack_name) %>
<% end %> - <%= if (f.params["task_provider"] == "tags") do %> + <%= if (f.params["task_provider"] == "tags" || f.data.task_provider == "tags") do %>
<%= label(f, :tags) %> <%= text_input(f, :tags, diff --git a/services/app/apps/codebattle/lib/codebattle_web/live/components/tournament/header.ex b/services/app/apps/codebattle/lib/codebattle_web/live/components/tournament/header.ex index 7676a0d6a..831dda9a3 100644 --- a/services/app/apps/codebattle/lib/codebattle_web/live/components/tournament/header.ex +++ b/services/app/apps/codebattle/lib/codebattle_web/live/components/tournament/header.ex @@ -12,10 +12,10 @@ defmodule CodebattleWeb.Live.Tournament.HeaderComponent do {@tournament.level}
- <%= if is_waiting_participants?(@tournament) do %> + <%= if waiting_participants?(@tournament) do %>
- <%= if is_individual?(@tournament) do %> - <%= if is_player?(@tournament, @current_user.id) do %> + <%= if individual?(@tournament) do %> + <%= if player?(@tournament, @current_user.id) do %> @@ -24,8 +24,8 @@ defmodule CodebattleWeb.Live.Tournament.HeaderComponent do <% end %> <% end %> - <%= if is_stairway?(@tournament) do %> - <%= if is_player?(@tournament, @current_user.id) do %> + <%= if stairway?(@tournament) do %> + <%= if player?(@tournament, @current_user.id) do %> <% else %> @@ -44,29 +44,29 @@ defmodule CodebattleWeb.Live.Tournament.HeaderComponent do - <%= if !is_public?(@tournament) do %> + <%= if !public?(@tournament) do %> <% end %> <% end %>
<% end %> - <%= if is_active?(@tournament) do %> + <%= if active?(@tournament) do %>
<%= if can_moderate?(@tournament, @current_user) do %> - <%= if !is_public?(@tournament) do %> + <%= if !public?(@tournament) do %> <% end %> <% end %>
<% end %> - <%= if is_finished?(@tournament) do %> + <%= if finished?(@tournament) do %>
<%= if can_moderate?(@tournament, @current_user) do %> - <%= if !is_public?(@tournament) do %> + <%= if !public?(@tournament) do %> <% end %> <% end %> @@ -81,7 +81,7 @@ defmodule CodebattleWeb.Live.Tournament.HeaderComponent do Access: <%= @tournament.access_type %> <% end %> PlayersLimit: <%= @tournament.players_limit %> - <%= if is_visible_by_token?(@tournament) && can_moderate?(@tournament, @current_user) do %> + <%= if visible_by_token?(@tournament) && can_moderate?(@tournament, @current_user) do %> Private url: <%= Routes.tournament_url(@socket, :show, @tournament.id, access_token: @tournament.access_token diff --git a/services/app/apps/codebattle/lib/codebattle_web/live/components/tournament/individual.ex b/services/app/apps/codebattle/lib/codebattle_web/live/components/tournament/individual.ex index a816df7b4..e92f4b39a 100644 --- a/services/app/apps/codebattle/lib/codebattle_web/live/components/tournament/individual.ex +++ b/services/app/apps/codebattle/lib/codebattle_web/live/components/tournament/individual.ex @@ -34,11 +34,11 @@ defmodule CodebattleWeb.Live.Tournament.IndividualComponent do
- <%= if is_active?(@tournament) || is_finished?(@tournament) do %> + <%= if active?(@tournament) || finished?(@tournament) do %> <% end %> - <%= if is_waiting_participants?(@tournament) do %> - <%= if is_player?(@tournament, @current_user.id) do %> + <%= if waiting_participants?(@tournament) do %> + <%= if player?(@tournament, @current_user.id) do %> diff --git a/services/app/apps/codebattle/lib/codebattle_web/live/components/tournament/ladder.ex b/services/app/apps/codebattle/lib/codebattle_web/live/components/tournament/ladder.ex index 40609d24a..23a698f0b 100644 --- a/services/app/apps/codebattle/lib/codebattle_web/live/components/tournament/ladder.ex +++ b/services/app/apps/codebattle/lib/codebattle_web/live/components/tournament/ladder.ex @@ -26,7 +26,7 @@ defmodule CodebattleWeb.Live.Tournament.LadderComponent do current_user={@current_user} messages={@messages} /> - <%= if is_waiting_participants?(@tournament) do %> + <%= if waiting_participants?(@tournament) do %>
- <%= if !is_waiting_participants?(@tournament) do %> + <%= if !waiting_participants?(@tournament) do %>
<% end %> - <%= if is_waiting_participants?(@tournament) do %> - <%= if is_player?(@tournament, @current_user.id) do %> + <%= if waiting_participants?(@tournament) do %> + <%= if player?(@tournament, @current_user.id) do %> diff --git a/services/app/apps/codebattle/lib/codebattle_web/live/components/tournament/match.ex b/services/app/apps/codebattle/lib/codebattle_web/live/components/tournament/match.ex index 103ae0cb0..af76960e9 100644 --- a/services/app/apps/codebattle/lib/codebattle_web/live/components/tournament/match.ex +++ b/services/app/apps/codebattle/lib/codebattle_web/live/components/tournament/match.ex @@ -38,7 +38,7 @@ defmodule CodebattleWeb.Live.Tournament.MatchComponent do end def get_match_bg_class(match, player_id) do - if is_match_player?(match, player_id) do + if match_player?(match, player_id) do "p-1 border border-success bg-winner" else "p-1 border border-success" @@ -46,7 +46,7 @@ defmodule CodebattleWeb.Live.Tournament.MatchComponent do end def get_game_link_name(match, player_id) do - case {match.state, is_match_player?(match, player_id)} do + case {match.state, match_player?(match, player_id)} do {"pending", true} -> "Pending" {"playing", true} -> "Join" _ -> "Show" diff --git a/services/app/apps/codebattle/lib/codebattle_web/live/components/tournament/players.ex b/services/app/apps/codebattle/lib/codebattle_web/live/components/tournament/players.ex index 6ef632c30..dc934a2a2 100644 --- a/services/app/apps/codebattle/lib/codebattle_web/live/components/tournament/players.ex +++ b/services/app/apps/codebattle/lib/codebattle_web/live/components/tournament/players.ex @@ -19,7 +19,7 @@ defmodule CodebattleWeb.Live.Tournament.PlayersComponent do
- <%= if can_moderate?(@tournament, @current_user) and is_waiting_participants?(@tournament) do %> + <%= if can_moderate?(@tournament, @current_user) and waiting_participants?(@tournament) do %> diff --git a/services/app/apps/codebattle/lib/codebattle_web/live/components/tournament/stairway_round.ex b/services/app/apps/codebattle/lib/codebattle_web/live/components/tournament/stairway_round.ex index d85eda285..81c40f4ec 100644 --- a/services/app/apps/codebattle/lib/codebattle_web/live/components/tournament/stairway_round.ex +++ b/services/app/apps/codebattle/lib/codebattle_web/live/components/tournament/stairway_round.ex @@ -68,7 +68,7 @@ defmodule CodebattleWeb.Live.Tournament.StairwayRoundComponent do end defp get_game_link_name(match, player_id) do - case {match.state, is_match_player?(match, player_id)} do + case {match.state, match_player?(match, player_id)} do {"pending", true} -> "Pending" {"playing", true} -> "Join" _ -> "Show" @@ -76,7 +76,7 @@ defmodule CodebattleWeb.Live.Tournament.StairwayRoundComponent do end defp get_match_bg_class(match, player_id) do - if is_match_player?(match, player_id) do + if match_player?(match, player_id) do "p-1 border bg-winner" else "p-1 border" diff --git a/services/app/apps/codebattle/lib/codebattle_web/live/components/tournament/swiss.ex b/services/app/apps/codebattle/lib/codebattle_web/live/components/tournament/swiss.ex index 226c31094..5412e9efb 100644 --- a/services/app/apps/codebattle/lib/codebattle_web/live/components/tournament/swiss.ex +++ b/services/app/apps/codebattle/lib/codebattle_web/live/components/tournament/swiss.ex @@ -26,7 +26,7 @@ defmodule CodebattleWeb.Live.Tournament.SwissComponent do current_user={@current_user} messages={@messages} /> - <%= if is_waiting_participants?(@tournament) do %> + <%= if waiting_participants?(@tournament) do %>
- <%= if !is_waiting_participants?(@tournament) do %> + <%= if !waiting_participants?(@tournament) do %>
<% end %> - <%= if is_waiting_participants?(@tournament) do %> - <%= if is_player?(@tournament, @current_user.id) do %> + <%= if waiting_participants?(@tournament) do %> + <%= if player?(@tournament, @current_user.id) do %> diff --git a/services/app/apps/codebattle/lib/codebattle_web/live/components/tournament/team_round.ex b/services/app/apps/codebattle/lib/codebattle_web/live/components/tournament/team_round.ex index da0b8ac10..9a26520ba 100644 --- a/services/app/apps/codebattle/lib/codebattle_web/live/components/tournament/team_round.ex +++ b/services/app/apps/codebattle/lib/codebattle_web/live/components/tournament/team_round.ex @@ -39,7 +39,7 @@ defmodule CodebattleWeb.Live.Tournament.TeamRoundComponent do end def get_game_link_name(match, player_id) do - case {match.state, is_match_player?(match, player_id)} do + case {match.state, match_player?(match, player_id)} do {"pending", true} -> "Pending" {"playing", true} -> "Join" _ -> "Show" @@ -47,7 +47,7 @@ defmodule CodebattleWeb.Live.Tournament.TeamRoundComponent do end def get_match_bg_class(match, player_id) do - if is_match_player?(match, player_id) do + if match_player?(match, player_id) do "row align-items-center py-2 bg-light" else "row align-items-center py-2" diff --git a/services/app/apps/codebattle/lib/codebattle_web/live/components/tournament/team_tab.ex b/services/app/apps/codebattle/lib/codebattle_web/live/components/tournament/team_tab.ex index a286c0f88..2a121c11c 100644 --- a/services/app/apps/codebattle/lib/codebattle_web/live/components/tournament/team_tab.ex +++ b/services/app/apps/codebattle/lib/codebattle_web/live/components/tournament/team_tab.ex @@ -22,8 +22,8 @@ defmodule CodebattleWeb.Live.Tournament.TeamTabComponent do <%= for team <- @teams do %>
- <%= if is_waiting_participants?(@tournament) do %> - <%= if is_player?(@tournament, @current_user.id, team.id) do %> + <%= if waiting_participants?(@tournament) do %> + <%= if player?(@tournament, @current_user.id, team.id) do %> <% else %>