diff --git a/services/app/apps/codebattle/assets/js/widgets/machines/waitingRoom.js b/services/app/apps/codebattle/assets/js/widgets/machines/waitingRoom.js new file mode 100644 index 000000000..5fe7e0f0f --- /dev/null +++ b/services/app/apps/codebattle/assets/js/widgets/machines/waitingRoom.js @@ -0,0 +1,188 @@ +import { assign } from 'xstate'; + +const states = { + room: { + none: 'none', + active: 'active', + inactive: 'inactive', + }, + player: { + ready: 'ready', + baned: 'baned', + }, + matchmaking: { + progress: 'matchmaking.progress', + success: 'matchmaking.success', + paused: 'matchmaking.paused', + }, +}; + +const machine = { + id: 'waitingRoom', + type: 'parallel', + initial: 'none', + context: { + waitingPlayers: [], + pausedPlayers: [], + finishedPlayers: [], + banedPlayers: [], + errorMessage: null, + }, + states: { + status: { + initial: 'none', + on: { + 'waiting_room:started': 'active', + }, + states: { + none: { + on: { + LOAD_WAITING_ROOM: 'active', + REJECT_LOADING: 'inactive', + FAILED_LOADING: { + target: 'failure', + actions: ['handleError', 'throwError'], + }, + }, + }, + active: { + entry: ['loadWaitingRoom'], + on: { + 'waiting_room:ended': 'inactive', + 'waiting_room:player:matchmaking_started': { + actions: 'addWaitingPlayer', + }, + 'waiting_room:player:matchmaking_paused': { + actions: 'addPausedPlayer', + }, + 'waiting_room:player:match_created': { + actions: 'removeWaitingPlayer', + }, + 'waiting_room:player:banned': { + actions: 'addBannedPlayer', + }, + 'waiting_room:player:unbanned': { + actions: 'removeBannedPlayer', + }, + 'waiting_room:player:finished': { + actions: 'addFinishedPlayer', + }, + }, + exit: ['unloadWaitingRoom'], + }, + inactive: {}, + failure: {}, + }, + }, + player: { + initial: 'ready', + states: { + ready: { + on: { + 'waiting_room:player:baned': 'baned', + 'waiting_room:player:matchmaking_started': 'matchmaking', + 'waiting_room:started': [ + { target: 'matchmaking.paused', cond: 'isMatchmakingPaused' }, + { target: 'matchmaking' }, + ], + }, + }, + matchmaking: { + initial: 'progress', + on: { + 'waiting_room:player:baned': 'baned', + 'waiting_room:player:matchmaking_stoped': 'ready', + }, + states: { + progress: { + on: { + 'waiting_room:player:matchmaking_paused': 'paused', + 'waiting_room:player:match_created': 'success', + }, + }, + success: {}, + paused: { + on: { + 'waiting_room:player:matchmaking_restarted': 'progress', + }, + }, + }, + }, + baned: { + on: { + 'waiting_room:player:unbaned': [ + { target: 'matchmaking', cond: 'isMatchmakingInProgress' }, + { target: 'ready' }, + ], + }, + }, + }, + }, + }, +}; + +export const config = { + guards: { + isMatchmakingInProgress: (_ctx, { payload }) => !!payload.isWait, + isMatchmakingPaused: (_ctx, { payload }) => !!payload.isPaused, + }, + actions: { + loadWaitingRoom: assign({ + errorMessage: null, + waitingPlayers: (_ctx, { payload }) => payload?.waitingPlayers || [], + pausedPlayers: (_ctx, { payload }) => payload?.pausedPlayers || [], + finishedPlayers: (_ctx, { payload }) => payload?.finishedPlayers || [], + banedPlayers: (_ctx, { payload }) => payload?.banedPlayers || [], + }), + unloadWaitingRoom: assign({ + errorMessage: null, + waitingPlayers: [], + pausedPlayers: [], + finishedPlayers: [], + banedPlayers: [], + }), + addWaitingPlayer: assign({ + waitingPlayers: (ctx, { payload }) => ( + payload.playerId + ? ctx.waitingPlayers.push(payload?.playerId) + : ctx.waitingPlayers + ), + pausedPlayers: (ctx, { payload }) => ( + ctx.pausedPlayers.filter(payload.playerId) + ), + finishedPlayers: (ctx, { payload }) => ( + ctx.finishedPlayers.filter(payload.playerId) + ), + }), + addPausedPlayer: assign({ + waitingPlayers: (ctx, { payload }) => ( + ctx.waitingPlayers.filter(payload.playerId) + ), + pausedPlayers: (ctx, { payload }) => ( + payload.playerId + ? ctx.pausedPlayers.push(payload?.playerId) + : ctx.pausedPlayers + ), + }), + removeWaitingPlayer: assign({ + waitingPlayers: (ctx, { payload }) => ( + ctx.waitingPlayers.filter(payload.playerId) + ), + }), + addBannedPlayer: assign({ + waitingPlayers: (ctx, { payload }) => ( + ctx.waitingPlayers.filter(payload.playerId) + ), + pausedPlayers: (ctx, { payload }) => ( + ctx.pausedPlayers.filter(payload.playerId) + ), + }), + handleError: assign({ + errorMessage: (_ctx, { payload }) => payload.message, + }), + }, +}; + +export const waitingRoomMachineStates = states; + +export default machine; 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 8994cd01d..8b2a7e77e 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 @@ -12,6 +12,7 @@ import TournamentGameCreatePanel from './TournamentGameCreatePanel'; function CustomTournamentInfoPanel({ roundsLimit = 1, currentRoundPosition = 0, + matchTimeoutSeconds, matches, players, taskList, @@ -45,6 +46,7 @@ function CustomTournamentInfoPanel({ matches={matches} taskList={taskList} currentRoundPosition={currentRoundPosition} + defaultMatchTimeoutSeconds={matchTimeoutSeconds} /> )} 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 45105f9bd..df3b1e100 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 @@ -80,6 +80,7 @@ function InfoPanel({ return ( { if (!selectedPlayer) return null; @@ -208,6 +211,33 @@ function TournamentGameCreatePanel({ +
+ { + const newTimeout = Number(event.target.value); + + if (newTimeout >= 180 && newTimeout <= 7200) { + setSelectedTimeoutSeconds(Number(event.target.value)); + } else if (newTimeout <= 180) { + setSelectedTimeoutSeconds(180); + } else if (newTimeout >= 7200) { + setSelectedTimeoutSeconds(7200); + } + }} + className="my-1 mr-1" + /> + +
{activeMatch ? (