diff --git a/knockoutwhistweb/app/controllers/IngameController.scala b/knockoutwhistweb/app/controllers/IngameController.scala index 373701d..d808f05 100644 --- a/knockoutwhistweb/app/controllers/IngameController.scala +++ b/knockoutwhistweb/app/controllers/IngameController.scala @@ -6,6 +6,7 @@ import exceptions.{CantPlayCardException, GameFullException, NotEnoughPlayersExc import logic.PodManager import model.sessions.{PlayerSession, UserSession} import play.api.* +import play.api.libs.json.Json import play.api.mvc.* import java.util.UUID @@ -64,30 +65,70 @@ class IngameController @Inject()( } } if (result.isSuccess) { - Redirect(routes.IngameController.game(gameId)) + Ok(Json.obj( + "status" -> "success", + "redirectUrl" -> routes.IngameController.game(gameId).url + )) } else { val throwable = result.failed.get throwable match { case _: NotInThisGameException => - BadRequest(throwable.getMessage) + BadRequest(Json.obj( + "status" -> "failure", + "errorMessage" -> throwable.getMessage + )) case _: NotHostException => - Forbidden(throwable.getMessage) + Forbidden(Json.obj( + "status" -> "failure", + "errorMessage" -> throwable.getMessage + )) case _: NotEnoughPlayersException => - BadRequest(throwable.getMessage) + BadRequest(Json.obj( + "status" -> "failure", + "errorMessage" -> throwable.getMessage + )) case _ => - InternalServerError(throwable.getMessage) + InternalServerError(Json.obj( + "status" -> "failure", + "errorMessage" -> throwable.getMessage + )) } } } - def kickPlayer(gameId: String, playerToKick: UUID): Action[AnyContent] = authAction { implicit request: AuthenticatedRequest[AnyContent] => + def kickPlayer(gameId: String, playerToKick: String): Action[AnyContent] = authAction { implicit request: AuthenticatedRequest[AnyContent] => val game = podManager.getGame(gameId) - game.get.leaveGame(playerToKick) - Redirect(routes.IngameController.game(gameId)) + val playerToKickUUID = UUID.fromString(playerToKick) + val result = Try { + game.get.leaveGame(playerToKickUUID) + } + if(result.isSuccess) { + Ok(Json.obj( + "status" -> "success", + "redirectUrl" -> routes.IngameController.game(gameId).url + )) + } else { + InternalServerError(Json.obj( + "status" -> "failure", + "errorMessage" -> "Something went wrong." + )) + } } def leaveGame(gameId: String): Action[AnyContent] = authAction { implicit request: AuthenticatedRequest[AnyContent] => val game = podManager.getGame(gameId) - game.get.leaveGame(request.user.id) - Redirect(routes.MainMenuController.mainMenu()) + val result = Try { + game.get.leaveGame(request.user.id) + } + if (result.isSuccess) { + Ok(Json.obj( + "status" -> "success", + "redirectUrl" -> routes.MainMenuController.mainMenu().url + )) + } else { + InternalServerError(Json.obj( + "status" -> "failure", + "errorMessage" -> "Something went wrong." + )) + } } def joinGame(gameId: String): Action[AnyContent] = authAction { implicit request: AuthenticatedRequest[AnyContent] => val game = podManager.getGame(gameId) @@ -119,7 +160,10 @@ class IngameController @Inject()( val game = podManager.getGame(gameId) game match { case Some(g) => - val cardIdOpt = request.body.asFormUrlEncoded.flatMap(_.get("cardId").flatMap(_.headOption)) + val jsonBody = request.body.asJson + val cardIdOpt: Option[String] = jsonBody.flatMap { jsValue => + (jsValue \ "cardID").asOpt[String] + } cardIdOpt match { case Some(cardId) => var optSession: Option[UserSession] = None @@ -131,27 +175,51 @@ class IngameController @Inject()( } optSession.foreach(_.lock.unlock()) if (result.isSuccess) { - NoContent + Ok(Json.obj( + "status" -> "success", + "redirectUrl" -> routes.IngameController.game(gameId).url + )) } else { val throwable = result.failed.get throwable match { case _: CantPlayCardException => - BadRequest(throwable.getMessage) + BadRequest(Json.obj( + "status" -> "failure", + "errorMessage" -> throwable.getMessage + )) case _: NotInThisGameException => - BadRequest(throwable.getMessage) + BadRequest(Json.obj( + "status" -> "failure", + "errorMessage" -> throwable.getMessage + )) case _: IllegalArgumentException => - BadRequest(throwable.getMessage) + BadRequest(Json.obj( + "status" -> "failure", + "errorMessage" -> throwable.getMessage + )) case _: IllegalStateException => - BadRequest(throwable.getMessage) + BadRequest(Json.obj( + "status" -> "failure", + "errorMessage" -> throwable.getMessage + )) case _ => - InternalServerError(throwable.getMessage) + InternalServerError(Json.obj( + "status" -> "failure", + "errorMessage" -> throwable.getMessage + )) } } case None => - BadRequest("cardId parameter is missing") + BadRequest(Json.obj( + "status" -> "failure", + "errorMessage" -> "cardId Parameter is missing" + )) } case None => - NotFound("Game not found") + NotFound(Json.obj( + "status" -> "failure", + "errorMessage" -> "Game not found" + )) } } } diff --git a/knockoutwhistweb/app/controllers/JavaScriptRoutingController.scala b/knockoutwhistweb/app/controllers/JavaScriptRoutingController.scala index b25f417..2cd5f06 100644 --- a/knockoutwhistweb/app/controllers/JavaScriptRoutingController.scala +++ b/knockoutwhistweb/app/controllers/JavaScriptRoutingController.scala @@ -16,7 +16,10 @@ class JavaScriptRoutingController @Inject()( Ok( JavaScriptReverseRouter("jsRoutes")( routes.javascript.MainMenuController.createGame, - routes.javascript.IngameController.startGame + routes.javascript.IngameController.startGame, + routes.javascript.IngameController.kickPlayer, + routes.javascript.IngameController.leaveGame, + routes.javascript.IngameController.playCard ) ).as("text/javascript") } diff --git a/knockoutwhistweb/app/controllers/MainMenuController.scala b/knockoutwhistweb/app/controllers/MainMenuController.scala index 413df1d..b4c0e4b 100644 --- a/knockoutwhistweb/app/controllers/MainMenuController.scala +++ b/knockoutwhistweb/app/controllers/MainMenuController.scala @@ -36,7 +36,7 @@ class MainMenuController @Inject()( .getOrElse(s"${request.user.name}'s Game") val playeramount: String = (jsonBody.get \ "playeramount").asOpt[String] - .getOrElse(throw new IllegalArgumentException("Player amount is required and must be an integer.")) + .getOrElse(throw new IllegalArgumentException("Player amount is required.")) val gameLobby = podManager.createGame( host = request.user, @@ -48,7 +48,10 @@ class MainMenuController @Inject()( "redirectUrl" -> routes.IngameController.game(gameLobby.id).url )) } else { - BadRequest("Invalid form submission") + BadRequest(Json.obj( + "status" -> "failure", + "errorMessage" -> "Invalid form submission" + )) } } diff --git a/knockoutwhistweb/app/views/ingame/ingame.scala.html b/knockoutwhistweb/app/views/ingame/ingame.scala.html index e18bb49..271fc28 100644 --- a/knockoutwhistweb/app/views/ingame/ingame.scala.html +++ b/knockoutwhistweb/app/views/ingame/ingame.scala.html @@ -75,12 +75,9 @@
@for(i <- player.currentHand().get.cards.indices) {
-
- - -
+
} diff --git a/knockoutwhistweb/app/views/lobby/lobby.scala.html b/knockoutwhistweb/app/views/lobby/lobby.scala.html index a8832e9..75ba8d4 100644 --- a/knockoutwhistweb/app/views/lobby/lobby.scala.html +++ b/knockoutwhistweb/app/views/lobby/lobby.scala.html @@ -9,9 +9,7 @@
Lobby-Name: @gamelobby.name
-
- -
+
Exit
@@ -34,16 +32,14 @@ } else {
@playersession.name
@*

Your text could be here!

*@ -
- -
+
Remove
} }
- Start Game +
Start Game
} else { @for(playersession <- gamelobby.getPlayers.values) { diff --git a/knockoutwhistweb/conf/routes b/knockoutwhistweb/conf/routes index c8f312e..9a1a4a6 100644 --- a/knockoutwhistweb/conf/routes +++ b/knockoutwhistweb/conf/routes @@ -26,6 +26,6 @@ GET /logout controllers.UserController.logout() GET /game/:id controllers.IngameController.game(id: String) GET /game/:id/join controllers.IngameController.joinGame(id: String) GET /game/:id/start controllers.IngameController.startGame(id: String) -POST /game/:id/kickPlayer controllers.IngameController.kickPlayer(id: String, playerId: java.util.UUID) +POST /game/:id/kickPlayer controllers.IngameController.kickPlayer(id: String, playerId: String) GET /game/:id/leaveGame controllers.IngameController.leaveGame(id: String) POST /game/:id/playCard controllers.IngameController.playCard(id: String) \ No newline at end of file diff --git a/knockoutwhistweb/public/javascripts/main.js b/knockoutwhistweb/public/javascripts/main.js index 08ec3bc..aa8ec29 100644 --- a/knockoutwhistweb/public/javascripts/main.js +++ b/knockoutwhistweb/public/javascripts/main.js @@ -103,21 +103,161 @@ function sendGameCreationRequest(dataObject) { body: JSON.stringify(dataObject) }) .then(response => { - if (!response.ok) { - throw new Error(`HTTP error! status: ${response.status}`); - } - return response.json(); + return response.json().then(data => { + if (!response.ok) { + return Promise.reject(data); + } + return data; + }); }) .then(data => { if (data.status === 'success') { - // Redirect the user window.location.href = data.redirectUrl; - } else { - console.error("Game creation failed:", data.message); } }) .catch(error => { - console.error('Fetch error:', error); - alert('Could not create game. Please try again.'); + if (error && error.errorMessage) { + alert(`${error.errorMessage}`); + } else { + alert('An unexpected error occurred. Please try again.'); + } }); -} \ No newline at end of file +} +function startGame(gameId) { + sendGameStartRequest(gameId) +} +function sendGameStartRequest(gameId) { + const route = jsRoutes.controllers.IngameController.startGame(gameId); + + fetch(route.url, { + method: route.type, + }) + .then(response => { + return response.json().then(data => { + if (!response.ok) { + return Promise.reject(data); + } + return data; + }); + }) + .then(data => { + // SUCCESS BLOCK: data is the { status: 'success', ... } object + if (data.status === 'success') { + window.location.href = data.redirectUrl; + } + }) + .catch(error => { + if (error && error.errorMessage) { + alert(`${error.errorMessage}`); + } else { + alert('An unexpected error occurred. Please try again.'); + } + }); +} +function removePlayer(gameid, playersessionId) { + sendRemovePlayerRequest(gameid, playersessionId) +} + +function sendRemovePlayerRequest(gameId, playersessionId) { + const route = jsRoutes.controllers.IngameController.kickPlayer(gameId, playersessionId); + + fetch(route.url, { + method: route.type, + headers: { + 'Content-Type': 'application/json', + } + }) + .then(response => { + return response.json().then(data => { + if (!response.ok) { + return Promise.reject(data); + } + return data; + }); + }) + .then(data => { + // SUCCESS BLOCK: data is the { status: 'success', ... } object + if (data.status === 'success') { + window.location.href = data.redirectUrl; + } + }) + .catch(error => { + if (error && error.errorMessage) { + alert(`${error.errorMessage}`); + } else { + alert('An unexpected error occurred. Please try again.'); + } + }); +} +function leaveGame(gameId) { + sendLeavePlayerRequest(gameId) +} +function sendLeavePlayerRequest(gameId) { + + const route = jsRoutes.controllers.IngameController.leaveGame(gameId); + fetch(route.url, { + method: route.type, + }) + .then(response => { + return response.json().then(data => { + if (!response.ok) { + return Promise.reject(data); + } + return data; + }); + }) + .then(data => { + // SUCCESS BLOCK: data is the { status: 'success', ... } object + if (data.status === 'success') { + window.location.href = data.redirectUrl; + } + }) + .catch(error => { + if (error && error.errorMessage) { + alert(`${error.errorMessage}`); + } else { + alert('An unexpected error occurred. Please try again.'); + } + }); +} + +function handlePlayCard(cardobject, gameId) { + const cardId = cardobject.dataset.cardId; + const jsonObj = { + cardID: cardId + } + sendPlayCardRequest(jsonObj, gameId) +} + +function sendPlayCardRequest(jsonObj, gameId) { + const route = jsRoutes.controllers.IngameController.playCard(gameId); + + fetch(route.url, { + method: route.type, + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(jsonObj) + }) + .then(response => { + return response.json().then(data => { + if (!response.ok) { + return Promise.reject(data); + } + return data; + }); + }) + .then(data => { + if (data.status === 'success') { + window.location.href = data.redirectUrl; + } + }) + .catch(error => { + if (error && error.errorMessage) { + alert(`${error.errorMessage}`); + } else { + alert('An unexpected error occurred. Please try again.'); + } + }); +} +