diff --git a/knockoutwhistweb/app/assets/stylesheets/dark-mode.less b/knockoutwhistweb/app/assets/stylesheets/dark-mode.less
index 02d2efa..c34aab1 100644
--- a/knockoutwhistweb/app/assets/stylesheets/dark-mode.less
+++ b/knockoutwhistweb/app/assets/stylesheets/dark-mode.less
@@ -3,7 +3,7 @@
--background-image: url('/assets/images/background.png') !important;
--color: #f8f9fa !important; /* Light text on dark bg */
--highlightscolor: rgba(131, 131, 131, 0.75) !important;
-
+ --background-color: #192734;
/* Bootstrap variable overrides for dark mode */
--bs-body-color: var(--color);
--bs-link-color: #66b2ff;
diff --git a/knockoutwhistweb/app/assets/stylesheets/light-mode.less b/knockoutwhistweb/app/assets/stylesheets/light-mode.less
index 5975dcc..3054bc2 100644
--- a/knockoutwhistweb/app/assets/stylesheets/light-mode.less
+++ b/knockoutwhistweb/app/assets/stylesheets/light-mode.less
@@ -2,4 +2,5 @@
--background-image: url('/assets/images/img.png');
--color: black;
--highlightscolor: rgba(0, 0, 0, 0.75);
+ --background-color: rgba(228, 232, 237, 1);
}
diff --git a/knockoutwhistweb/app/assets/stylesheets/main.less b/knockoutwhistweb/app/assets/stylesheets/main.less
index d41bf29..145789b 100644
--- a/knockoutwhistweb/app/assets/stylesheets/main.less
+++ b/knockoutwhistweb/app/assets/stylesheets/main.less
@@ -14,7 +14,7 @@
--bs-border-color: rgba(0, 0, 0, 0.125) !important;
--bs-heading-color: var(--color) !important;
}
-
+@background-color: var(--background-color);
@highlightcolor: var(--highlightscolor);
@background-image: var(--background-image);
@color: var(--color);
@@ -24,10 +24,14 @@
}
.game-field-background {
background-image: @background-image;
- background-size: cover;
- background-position: center center;
- background-repeat: no-repeat;
- background-attachment: fixed;
+ max-width: 1400px;
+ margin: 0 auto;
+ min-height: 100vh;
+}
+.lobby-background {
+ background-color: @background-color;
+ width: 100%;
+ height: 100vh;
}
.navbar-header{
@@ -45,8 +49,11 @@
.bottom-div {
position: fixed;
bottom: 0;
- left: 0;
+ left: 50%;
+ transform: translateX(-50%);
+ max-width: 1400px;
width: 100%;
+ margin: 0;
text-align: center;
padding: 10px;
}
@@ -205,4 +212,20 @@ body {
color: @color;
font-size: 1.5em;
font-family: Arial, serif;
+}
+.score-table {
+ background-color: rgba(255, 255, 255, 0.1);
+ border-radius: 8px;
+ padding: 10px;
+ margin-bottom: 20px;
+ backdrop-filter: blur(8px);
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
+}
+.score-header {
+ font-weight: bold;
+ color: #000000;
+ border-bottom: 1px solid rgba(255, 255, 255, 0.3);
+}
+.score-row {
+ color: #000000;
}
\ No newline at end of file
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
new file mode 100644
index 0000000..2cd5f06
--- /dev/null
+++ b/knockoutwhistweb/app/controllers/JavaScriptRoutingController.scala
@@ -0,0 +1,26 @@
+package controllers
+
+import auth.{AuthAction, AuthenticatedRequest}
+import logic.PodManager
+import play.api.mvc.{Action, AnyContent, BaseController, ControllerComponents}
+import play.api.routing.JavaScriptReverseRouter
+
+import javax.inject.Inject
+
+class JavaScriptRoutingController @Inject()(
+ val controllerComponents: ControllerComponents,
+ val authAction: AuthAction,
+ val podManager: PodManager
+ ) extends BaseController {
+ def javascriptRoutes(): Action[AnyContent] = authAction { implicit request: AuthenticatedRequest[AnyContent] =>
+ Ok(
+ JavaScriptReverseRouter("jsRoutes")(
+ routes.javascript.MainMenuController.createGame,
+ 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 55c4a1b..b4c0e4b 100644
--- a/knockoutwhistweb/app/controllers/MainMenuController.scala
+++ b/knockoutwhistweb/app/controllers/MainMenuController.scala
@@ -3,6 +3,7 @@ package controllers
import auth.{AuthAction, AuthenticatedRequest}
import logic.PodManager
import play.api.*
+import play.api.libs.json.Json
import play.api.mvc.*
import javax.inject.*
@@ -29,18 +30,28 @@ class MainMenuController @Inject()(
}
def createGame(): Action[AnyContent] = authAction { implicit request: AuthenticatedRequest[AnyContent] =>
- val postData = request.body.asFormUrlEncoded
- if (postData.isDefined) {
- val gamename = postData.get.get("lobbyname").flatMap(_.headOption).getOrElse(s"${request.user.name}'s Game")
- val playeramount = postData.get.get("playeramount").flatMap(_.headOption).getOrElse("")
+ val jsonBody = request.body.asJson
+ if (jsonBody.isDefined) {
+ val gamename: String = (jsonBody.get \ "lobbyname").asOpt[String]
+ .getOrElse(s"${request.user.name}'s Game")
+
+ val playeramount: String = (jsonBody.get \ "playeramount").asOpt[String]
+ .getOrElse(throw new IllegalArgumentException("Player amount is required."))
+
val gameLobby = podManager.createGame(
host = request.user,
name = gamename,
maxPlayers = playeramount.toInt
)
- Redirect(routes.IngameController.game(gameLobby.id))
+ Ok(Json.obj(
+ "status" -> "success",
+ "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 db56c27..271fc28 100644
--- a/knockoutwhistweb/app/views/ingame/ingame.scala.html
+++ b/knockoutwhistweb/app/views/ingame/ingame.scala.html
@@ -3,68 +3,86 @@
@(player: de.knockoutwhist.player.AbstractPlayer, gamelobby: logic.game.GameLobby)
@main("Ingame") {
-
+
+
+
-
-
-
Current Player
-
@gamelobby.getLogic.getCurrentPlayer.get.name
- @if(!TrickUtil.isOver(gamelobby.getLogic.getCurrentMatch.get, gamelobby.getLogic.getPlayerQueue.get)) {
+
+
+
Current Player
+
@gamelobby.getLogic.getCurrentPlayer.get.name
+ @if(!TrickUtil.isOver(gamelobby.getLogic.getCurrentMatch.get, gamelobby.getLogic.getPlayerQueue.get)) {
Next Player
@for(nextplayer <- gamelobby.getLogic.getPlayerQueue.get.duplicate()) {
-
@nextplayer
+
@nextplayer
}
- }
-
+ }
+
-
- @for((cardplayed, player) <- gamelobby.getLogic.getCurrentTrick.get.cards) {
-
-
-
- @util.WebUIUtils.cardtoImage(cardplayed) width="100%"/>
-
-
-
@player
+
+
+
+
Tricks Won
+
+
+
+ @for(player <- gamelobby.getLogic.getPlayerQueue.get.toList.sortBy { p =>
+ -(gamelobby.getLogic.getCurrentRound.get.tricklist.filter { trick => trick.winner.contains(p) }.size)
+ }) {
+
+
@player.name
+
+ @(gamelobby.getLogic.getCurrentRound.get.tricklist.filter { trick => trick.winner.contains(player) }.size)
+ }
+
- }
+
+ @for((cardplayed, player) <- gamelobby.getLogic.getCurrentTrick.get.cards) {
+
+
+
+ @util.WebUIUtils.cardtoImage(cardplayed) width="100%"/>
+
+
+ @player
+
+
+
+ }
+
+
+
+
Trumpsuit
+
@gamelobby.getLogic.getCurrentRound.get.trumpSuit
+
+
First Card
+
+ @if(gamelobby.getLogic.getCurrentTrick.get.firstCard.isDefined) {
+ @util.WebUIUtils.cardtoImage(gamelobby.getLogic.getCurrentTrick.get.firstCard.get) width="80px"/>
+ } else {
+ @views.html.render.card.apply("images/cards/1B.png")("Blank Card") width="80px"/>
+ }
+
+
-
-
Trumpsuit
-
@gamelobby.getLogic.getCurrentRound.get.trumpSuit
-
-
First Card
-
- @if(gamelobby.getLogic.getCurrentTrick.get.firstCard.isDefined) {
- @util.WebUIUtils.cardtoImage(gamelobby.getLogic.getCurrentTrick.get.firstCard.get) width="80px"/>
- } else {
- @views.html.render.card.apply("images/cards/1B.png")("Blank Card") width="80px"/>
- }
+
+
+ @for(i <- player.currentHand().get.cards.indices) {
+
+
+ @util.WebUIUtils.cardtoImage(player.currentHand().get.cards(i)) width="120px" style="border-radius: 6px"/>
+
+
+ }
-
-
-
-
-
-
-
-
- @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 46eabb6..75ba8d4 100644
--- a/knockoutwhistweb/app/views/lobby/lobby.scala.html
+++ b/knockoutwhistweb/app/views/lobby/lobby.scala.html
@@ -1,82 +1,69 @@
@(user: Option[model.users.User], gamelobby: logic.game.GameLobby)
@main("Lobby") {
-
-
-
-
-
- Lobby-Name: @gamelobby.name
+
+
+
+
+
+
+ Lobby-Name: @gamelobby.name
+
+
Exit
-
-
-
-
-
Playeramount: @gamelobby.getPlayers.size / @gamelobby.maxPlayers
+
+
+
Playeramount: @gamelobby.getPlayers.size / @gamelobby.maxPlayers
+
-
-
-
- @if((gamelobby.getUserSession(user.get.id).host)) {
- @for(playersession <- gamelobby.getPlayers.values) {
-
-
+
+ @if((gamelobby.getUserSession(user.get.id).host)) {
+ @for(playersession <- gamelobby.getPlayers.values) {
+
+
+

+
+ @if(playersession.id == user.get.id) {
+
@playersession.name (You)
+ @*
Your text could be here!
*@
+
Remove
+ } else {
+
@playersession.name
+ @*
Your text could be here!
*@
+
Remove
+ }
+
+
+
+ }
+
+ } else {
+ @for(playersession <- gamelobby.getPlayers.values) {
+
@if(playersession.id == user.get.id) {
-
@playersession.name (You)
-@*
Your text could be here!
*@
-
Remove
+
@playersession.name (You)
} else {
-
@playersession.name
-@*
Your text could be here!
*@
-
+
@playersession.name
}
-
-
- }
-
- } else {
- @for(playersession <- gamelobby.getPlayers.values) {
-
-
-

-
- @if(playersession.id == user.get.id) {
-
@playersession.name (You)
- } else {
- @playersession.name
- }
-
-
-
- }
-
-
-
Waiting for the host to start the game...
-
-
-
-
-
+ }
+
+
+
Waiting for the host to start the game...
+
+ Loading...
+
-
- }
+ }
+
-
+
}
\ No newline at end of file
diff --git a/knockoutwhistweb/app/views/main.scala.html b/knockoutwhistweb/app/views/main.scala.html
index daccc3a..e1cc5d1 100644
--- a/knockoutwhistweb/app/views/main.scala.html
+++ b/knockoutwhistweb/app/views/main.scala.html
@@ -18,16 +18,11 @@
-
-
+
@* And here's where we render the `Html` object containing
* the page content. *@
@content
-
-
-
-
+
diff --git a/knockoutwhistweb/app/views/mainmenu/creategame.scala.html b/knockoutwhistweb/app/views/mainmenu/creategame.scala.html
index 1e5905c..fd680fd 100644
--- a/knockoutwhistweb/app/views/mainmenu/creategame.scala.html
+++ b/knockoutwhistweb/app/views/mainmenu/creategame.scala.html
@@ -2,7 +2,7 @@
@main("Create Game") {
@navbar(user)
-
-
+
}
\ No newline at end of file
diff --git a/knockoutwhistweb/conf/routes b/knockoutwhistweb/conf/routes
index bba5dda..9a1a4a6 100644
--- a/knockoutwhistweb/conf/routes
+++ b/knockoutwhistweb/conf/routes
@@ -3,7 +3,8 @@
# https://www.playframework.com/documentation/latest/ScalaRouting
# ~~~~
-
+# For the javascript routing
+GET /assets/js/routes controllers.JavaScriptRoutingController.javascriptRoutes()
# Primary routes
GET / controllers.MainMenuController.index()
GET /assets/*file controllers.Assets.versioned(path="/public", file: Asset)
@@ -25,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 36ec495..aa8ec29 100644
--- a/knockoutwhistweb/public/javascripts/main.js
+++ b/knockoutwhistweb/public/javascripts/main.js
@@ -77,4 +77,187 @@
})
})
})
-})()
\ No newline at end of file
+})()
+
+function createGameJS() {
+ let lobbyName = document.getElementById("lobbyname").value;
+ if (lobbyName === "") {
+ lobbyName = "DefaultLobby"
+ }
+ const playerAmount = document.getElementById("playeramount").value;
+ const jsonObj = {
+ lobbyname: lobbyName,
+ playeramount: playerAmount
+ }
+ sendGameCreationRequest(jsonObj);
+}
+
+function sendGameCreationRequest(dataObject) {
+ const route = jsRoutes.controllers.MainMenuController.createGame();
+
+ fetch(route.url, {
+ method: route.type,
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify(dataObject)
+ })
+ .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.');
+ }
+ });
+}
+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.');
+ }
+ });
+}
+