Finish game password protection.
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
"name": "Massive Decks",
|
||||
"repository": "https://github.com/Lattyware/massivedecks",
|
||||
"env": {
|
||||
"ELM_VERSION": "0.17",
|
||||
"ELM_VERSION": "0.18",
|
||||
"ELM_COMPILE": "elm make client/src/MassiveDecks.elm --output public/javascripts/MassiveDecks.js"
|
||||
},
|
||||
"buildpacks": [
|
||||
|
||||
@@ -32,7 +32,7 @@ h2 {
|
||||
}
|
||||
}
|
||||
|
||||
.deck-id-input {
|
||||
.input-with-button {
|
||||
display: flex;
|
||||
|
||||
& > .mui-textfield {
|
||||
|
||||
@@ -360,6 +360,10 @@ ol.played {
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
&.you {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
&.skipping {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
@@ -72,6 +72,7 @@ class API @Inject()(store: LobbyStore) (implicit context: ExecutionContext) exte
|
||||
case "enableRule" => lobby.enableRule(secret, extractCommandArgument((request.body \ "rule").validate[String]))
|
||||
case "disableRule" => lobby.disableRule(secret, extractCommandArgument((request.body \ "rule").validate[String]))
|
||||
case "redraw" => lobby.redraw(secret)
|
||||
case "setPassword" => lobby.setPassword(secret, (request.body \ "password").asOpt[String])
|
||||
case unknown => throw BadRequestException(Errors.InvalidCommand(unknown))
|
||||
}
|
||||
}
|
||||
@@ -82,7 +83,7 @@ class API @Inject()(store: LobbyStore) (implicit context: ExecutionContext) exte
|
||||
wrap {
|
||||
val name = (request.body \ "name").validate[String].getOrElse(throw BadRequestException(Errors.InvalidName()))
|
||||
store.performInLobby(gameCode) { lobby =>
|
||||
Json.toJson(lobby.newPlayer(name))
|
||||
Json.toJson(lobby.newPlayer(name, (request.body \ "password").asOpt[String]))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,11 +28,7 @@ class Config(notifiers: Notifiers) {
|
||||
}
|
||||
|
||||
def setPassword(newPass: Option[String]) = {
|
||||
if (newPass.forall(pw => pw.isEmpty)) {
|
||||
password = None
|
||||
} else {
|
||||
password = newPass
|
||||
}
|
||||
password = newPass.flatMap(pass => if (pass.isEmpty) None else newPass)
|
||||
notifiers.configChange(config)
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ import massivedecks.models.{Errors, Player, Game => GameModel, Lobby => LobbyMod
|
||||
import massivedecks.models.Game.Formatters._
|
||||
import massivedecks.models.Lobby.Formatters._
|
||||
import play.api.libs.iteratee.{Enumerator, Iteratee}
|
||||
import play.api.libs.json.{JsValue, Json}
|
||||
import play.api.libs.json.{JsValue, JsObject, Json}
|
||||
import massivedecks.Util
|
||||
import massivedecks.cardcast.CardcastAPI
|
||||
|
||||
@@ -67,7 +67,7 @@ class Lobby(cardcast: CardcastAPI, val gameCode: String, ownerName: String)(impl
|
||||
case Some(g) => GameModel.State.Playing(g.round)
|
||||
}
|
||||
|
||||
val owner = newPlayer(ownerName)
|
||||
val owner = newPlayer(ownerName, None)
|
||||
|
||||
/**
|
||||
* @return The model for the lobby.
|
||||
@@ -80,8 +80,10 @@ class Lobby(cardcast: CardcastAPI, val gameCode: String, ownerName: String)(impl
|
||||
* @param name The name for the player.
|
||||
* @return The secret for the player.
|
||||
* @throws BadRequestException with key "name-in-use" if there is a player in the lobby with the same name.
|
||||
* @throws ForbiddenException with key "password-wrong" if the password is required and wrong.
|
||||
*/
|
||||
def newPlayer(name: String): Player.Secret = {
|
||||
def newPlayer(name: String, password: Option[String]): Player.Secret = {
|
||||
ForbiddenException.verify(config.password.isEmpty || config.password == password, Errors.PasswordWrong())
|
||||
val secret = players.addPlayer(name)
|
||||
if (game.isDefined) {
|
||||
game.get.addPlayer(secret.id)
|
||||
@@ -97,7 +99,7 @@ class Lobby(cardcast: CardcastAPI, val gameCode: String, ownerName: String)(impl
|
||||
* @param playCode The cardcast play code for the deck.
|
||||
* @return An empty response.
|
||||
* @throws ForbiddenException with key "secret-wrong-or-not-a-player" if the secret is invalid.
|
||||
* @throws ForbiddenException with key "secret-wrong-or-not-a-player" if the secret is invalid.
|
||||
* @throws ForbiddenException with key "not-owner" if the requester is not the owner.
|
||||
* @throws RequestFailedException with the key "cardcast-timeout" if the request to cardcast doesn't complete.
|
||||
*/
|
||||
def addDeck(secret: Player.Secret, playCode: String): JsValue = {
|
||||
@@ -113,7 +115,7 @@ class Lobby(cardcast: CardcastAPI, val gameCode: String, ownerName: String)(impl
|
||||
case Failure(exception) =>
|
||||
throw RequestFailedException(Errors.CardcastTimeout())
|
||||
}
|
||||
Json.toJson("")
|
||||
EmptyResponse
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -188,7 +190,7 @@ class Lobby(cardcast: CardcastAPI, val gameCode: String, ownerName: String)(impl
|
||||
val game = validateInGame()
|
||||
game.choose(secret.id, winner)
|
||||
beginRound()
|
||||
Json.toJson("")
|
||||
EmptyResponse
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -284,7 +286,7 @@ class Lobby(cardcast: CardcastAPI, val gameCode: String, ownerName: String)(impl
|
||||
}
|
||||
}
|
||||
game.skip(secret.id, playerIds)
|
||||
Json.toJson("")
|
||||
EmptyResponse
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -298,7 +300,7 @@ class Lobby(cardcast: CardcastAPI, val gameCode: String, ownerName: String)(impl
|
||||
def back(secret: Player.Secret): JsValue = {
|
||||
players.validateSecret(secret)
|
||||
players.back(secret.id)
|
||||
Json.toJson("")
|
||||
EmptyResponse
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -331,7 +333,23 @@ class Lobby(cardcast: CardcastAPI, val gameCode: String, ownerName: String)(impl
|
||||
players.validateSecret(secret)
|
||||
validateIsOwner(secret)
|
||||
config.addHouseRule(rule)
|
||||
Json.toJson("")
|
||||
EmptyResponse
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the password
|
||||
*
|
||||
* @param secret The secret of the player making the request.
|
||||
* @param password The password to set, empty means no password.
|
||||
* @return An empty response.
|
||||
* @throws ForbiddenException with key "secret-wrong-or-not-a-player" if the secret is invalid.
|
||||
* @throws ForbiddenException with key "not-owner" if the requester is not the owner.
|
||||
*/
|
||||
def setPassword(secret: Player.Secret, password: Option[String]): JsValue = {
|
||||
players.validateSecret(secret)
|
||||
validateIsOwner(secret)
|
||||
config.setPassword(password)
|
||||
EmptyResponse
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -347,9 +365,11 @@ class Lobby(cardcast: CardcastAPI, val gameCode: String, ownerName: String)(impl
|
||||
players.validateSecret(secret)
|
||||
validateIsOwner(secret)
|
||||
config.removeHouseRule(rule)
|
||||
Json.toJson("")
|
||||
EmptyResponse
|
||||
}
|
||||
|
||||
def EmptyResponse: JsValue = JsObject(Seq())
|
||||
|
||||
/**
|
||||
* Register a websocket connection.
|
||||
*
|
||||
|
||||
@@ -26,6 +26,7 @@ object Errors {
|
||||
case class NameInUse(error: String = "name-in-use") extends SimpleErrorDetails
|
||||
case class BadlyFormedSecret(error: String = "badly-formed-secret") extends SimpleErrorDetails
|
||||
case class SecretWrongOrNotAPlayer(error: String = "secret-wrong-or-not-a-player") extends SimpleErrorDetails
|
||||
case class PasswordWrong(error: String = "password-wrong") extends SimpleErrorDetails
|
||||
case class NotAPlayer(error: String = "not-a-player") extends SimpleErrorDetails
|
||||
case class NotBeingSkipped(error: String = "not-being-skipped") extends SimpleErrorDetails
|
||||
case class AlreadyLeftGame(error: String = "already-left-game") extends SimpleErrorDetails
|
||||
|
||||
@@ -3,9 +3,8 @@
|
||||
<head>
|
||||
@head("Massive Decks", url)
|
||||
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.6.3/css/font-awesome.min.css"
|
||||
integrity="sha384-T8Gy5hrqNKT+hzMclPo118YTQO6cYprQmhrYwIiQ/3axmI1hQomh7Ud2hPOy8SP1"
|
||||
crossorigin="anonymous">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
|
||||
integrity="sha256-eZrrJcwDc/3uDhsdt61sL2oOBY362qM3lon1gyExkL0=" crossorigin="anonymous" />
|
||||
|
||||
<script src="@routes.Assets.versioned("javascripts/qrcode.min.js")"></script>
|
||||
|
||||
|
||||
@@ -25,18 +25,20 @@ createLobby name =
|
||||
-}
|
||||
type NewPlayerError
|
||||
= NameInUse
|
||||
| PasswordWrong
|
||||
| NewPlayerLobbyNotFound
|
||||
|
||||
|
||||
{-| Makes a request to add a new player to the given lobby. On success, returns a `Secret` for that player.
|
||||
-}
|
||||
newPlayer : String -> String -> Request NewPlayerError Player.Secret
|
||||
newPlayer gameCode name =
|
||||
newPlayer : String -> String -> String -> Request NewPlayerError Player.Secret
|
||||
newPlayer gameCode name password =
|
||||
request
|
||||
"POST"
|
||||
("/api/lobbies/" ++ gameCode ++ "/players")
|
||||
(Just (encodeName name))
|
||||
(Just (encodeNameAndPassword name password))
|
||||
[ ( ( 400, "name-in-use" ), Decode.succeed NameInUse )
|
||||
, ( ( 403, "password-wrong" ), Decode.succeed PasswordWrong )
|
||||
, ( ( 404, "lobby-not-found" ), Decode.succeed NewPlayerLobbyNotFound )
|
||||
]
|
||||
playerSecretDecoder
|
||||
@@ -279,6 +281,13 @@ disableRule rule gameCode secret =
|
||||
commandRequest "disableRule" [ ( "rule", rule |> HouseRule.toString |> Encode.string ) ] [] (Decode.succeed ()) gameCode secret
|
||||
|
||||
|
||||
{-| Make a request to set the lobby password
|
||||
-}
|
||||
setPassword : String -> Player.Secret -> String -> Request Never ()
|
||||
setPassword gameCode secret password =
|
||||
commandRequest "setPassword" [ ( "password", password |> Encode.string ) ] [] (Decode.succeed ()) gameCode secret
|
||||
|
||||
|
||||
|
||||
{- Private -}
|
||||
|
||||
|
||||
@@ -128,13 +128,18 @@ update message model =
|
||||
if (identity == model.identity) then
|
||||
case change of
|
||||
Changed value ->
|
||||
( { model | value = value }, Cmd.none )
|
||||
( { model
|
||||
| value = value
|
||||
, error = Nothing
|
||||
}
|
||||
, Cmd.none
|
||||
)
|
||||
|
||||
Error error ->
|
||||
( { model | error = error }, Cmd.none )
|
||||
|
||||
Submit ->
|
||||
( model, model.submit )
|
||||
( { model | error = Nothing }, model.submit )
|
||||
|
||||
SetEnabled enabled ->
|
||||
( { model | enabled = enabled }, Cmd.none )
|
||||
@@ -145,4 +150,4 @@ update message model =
|
||||
NoOp ->
|
||||
( model, Cmd.none )
|
||||
else
|
||||
( model, Cmd.none )
|
||||
( { model | error = Nothing }, Cmd.none )
|
||||
|
||||
@@ -25,7 +25,7 @@ type alias GameCode =
|
||||
type alias Config =
|
||||
{ decks : List DeckInfo
|
||||
, houseRules : List HouseRule.Id
|
||||
, pasword : Maybe String
|
||||
, password : Maybe String
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -36,3 +36,11 @@ encodePlayerId playerId =
|
||||
encodeName : String -> Json.Value
|
||||
encodeName name =
|
||||
Json.object [ ( "name", Json.string name ) ]
|
||||
|
||||
|
||||
encodeNameAndPassword : String -> String -> Json.Value
|
||||
encodeNameAndPassword name password =
|
||||
Json.object
|
||||
[ ( "name", Json.string name )
|
||||
, ( "password", Json.string password )
|
||||
]
|
||||
|
||||
@@ -10,18 +10,34 @@ import MassiveDecks.Scenes.Lobby.Models as Lobby
|
||||
import MassiveDecks.Scenes.Config.Messages exposing (ConsumerMessage(..), Message(..), InputId(..), Deck(..))
|
||||
import MassiveDecks.Scenes.Config.Models exposing (Model)
|
||||
import MassiveDecks.Scenes.Config.UI as UI
|
||||
import MassiveDecks.Models.Game as Game
|
||||
import MassiveDecks.Models.Player as Player
|
||||
import MassiveDecks.Util as Util exposing ((:>))
|
||||
|
||||
|
||||
{-| Create the initial model for the config screen.
|
||||
-}
|
||||
init : Model
|
||||
init =
|
||||
{ decks = []
|
||||
, deckIdInput = Input.initWithExtra DeckId "deck-id-input" UI.deckIdInputLabel "" "Play Code" UI.addDeckButton (Util.cmd AddDeck) InputMessage
|
||||
, passwordInput = Input.init Password "password-input" UI.passwordInputLabel "" "Password" (Cmd.none) InputMessage
|
||||
, loadingDecks = []
|
||||
}
|
||||
init : Game.Lobby -> Player.Secret -> ( Model, Cmd ConsumerMessage )
|
||||
init lobby secret =
|
||||
let
|
||||
canChangeConfig =
|
||||
lobby.owner == secret.id
|
||||
|
||||
config =
|
||||
lobby.config
|
||||
|
||||
setPasswordButton =
|
||||
if canChangeConfig then
|
||||
UI.setPasswordButton
|
||||
else
|
||||
(\_ -> [])
|
||||
in
|
||||
{ decks = []
|
||||
, deckIdInput = Input.initWithExtra DeckId "input-with-button" UI.deckIdInputLabel "" "Play Code" UI.addDeckButton (Util.cmd AddDeck) InputMessage
|
||||
, passwordInput = Input.initWithExtra Password "input-with-button" UI.passwordInputLabel (config.password |> Maybe.withDefault "") "Password" setPasswordButton (Util.cmd SetPassword) InputMessage
|
||||
, loadingDecks = []
|
||||
}
|
||||
! [ ( Password, Input.SetEnabled canChangeConfig ) |> InputMessage |> LocalMessage |> Util.cmd ]
|
||||
|
||||
|
||||
{-| Subscriptions for the config screen.
|
||||
@@ -77,10 +93,17 @@ update message lobbyModel =
|
||||
|
||||
InputMessage message ->
|
||||
let
|
||||
( deckIdInput, msg ) =
|
||||
( deckIdInput, deckIdMsg ) =
|
||||
Input.update message lobbyModel.config.deckIdInput
|
||||
|
||||
( passwordInput, passwordMsg ) =
|
||||
Input.update message lobbyModel.config.passwordInput
|
||||
in
|
||||
( { model | deckIdInput = deckIdInput }, Cmd.map LocalMessage msg )
|
||||
{ model
|
||||
| deckIdInput = deckIdInput
|
||||
, passwordInput = passwordInput
|
||||
}
|
||||
! [ Cmd.map LocalMessage deckIdMsg, Cmd.map LocalMessage passwordMsg ]
|
||||
|
||||
AddAi ->
|
||||
( model, Request.send_ (API.newAi gameCode secret) ErrorMessage (\_ -> LocalMessage NoOp) )
|
||||
@@ -94,6 +117,9 @@ update message lobbyModel =
|
||||
DisableRule rule ->
|
||||
( model, Request.send_ (API.disableRule rule gameCode secret) ErrorMessage ignore )
|
||||
|
||||
SetPassword ->
|
||||
( model, Request.send_ (API.setPassword gameCode secret model.passwordInput.value) ErrorMessage ignore )
|
||||
|
||||
NoOp ->
|
||||
( model, Cmd.none )
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ type Message
|
||||
| StartGame
|
||||
| EnableRule HouseRule.Id
|
||||
| DisableRule HouseRule.Id
|
||||
| SetPassword
|
||||
| NoOp
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
module MassiveDecks.Scenes.Config.UI exposing (view, deckIdInputLabel, passwordInputLabel, addDeckButton)
|
||||
module MassiveDecks.Scenes.Config.UI exposing (view, deckIdInputLabel, passwordInputLabel, addDeckButton, setPasswordButton)
|
||||
|
||||
import String
|
||||
import Html exposing (..)
|
||||
@@ -94,18 +94,29 @@ infoBar =
|
||||
|
||||
passwordInputLabel : List (Html msg)
|
||||
passwordInputLabel =
|
||||
[ text "If blank, no password will be needed - anyone with the game code can play." ]
|
||||
[ text "If blank, anyone with the game code can join." ]
|
||||
|
||||
|
||||
password : Input.Model InputId Message -> Html Message
|
||||
password passwordInputModel =
|
||||
div []
|
||||
[ h3 [] [ Icon.icon "key", text " Privacy" ]
|
||||
, p [] [ text "A password that players will need to enter to get in the game." ]
|
||||
, p [] [ text "A password that players will need to enter to get in the game. People already in the game will not need to enter it, and anyone in the game will be able to see it." ]
|
||||
, Input.view passwordInputModel
|
||||
]
|
||||
|
||||
|
||||
setPasswordButton : String -> List (Html Message)
|
||||
setPasswordButton password =
|
||||
[ button
|
||||
[ class "mui-btn mui-btn--small mui-btn--primary"
|
||||
, onClick SetPassword
|
||||
, title "Set the password."
|
||||
]
|
||||
[ Icon.icon "lock" ]
|
||||
]
|
||||
|
||||
|
||||
invite : String -> String -> Html msg
|
||||
invite appUrl lobbyId =
|
||||
let
|
||||
|
||||
@@ -34,19 +34,23 @@ import MassiveDecks.Util as Util exposing ((:>))
|
||||
-}
|
||||
init : Init -> Game.LobbyAndHand -> Player.Secret -> ( Model, Cmd ConsumerMessage )
|
||||
init init lobbyAndHand secret =
|
||||
{ lobby = lobbyAndHand.lobby
|
||||
, hand = lobbyAndHand.hand
|
||||
, config = Config.init
|
||||
, playing = Playing.init init
|
||||
, browserNotifications = BrowserNotifications.init init.browserNotificationsSupported False
|
||||
, secret = secret
|
||||
, init = init
|
||||
, notification = Nothing
|
||||
, qrNeedsRendering = False
|
||||
, sidebar = Sidebar.init 768 {- Should match the enhance-width in less. -}
|
||||
, tts = TTS.init
|
||||
}
|
||||
! []
|
||||
let
|
||||
( config, configCmd ) =
|
||||
Config.init lobbyAndHand.lobby secret
|
||||
in
|
||||
{ lobby = lobbyAndHand.lobby
|
||||
, hand = lobbyAndHand.hand
|
||||
, config = config
|
||||
, playing = Playing.init init
|
||||
, browserNotifications = BrowserNotifications.init init.browserNotificationsSupported False
|
||||
, secret = secret
|
||||
, init = init
|
||||
, notification = Nothing
|
||||
, qrNeedsRendering = False
|
||||
, sidebar = Sidebar.init 768 {- Should match the enhance-width in less. -}
|
||||
, tts = TTS.init
|
||||
}
|
||||
! [ configCmd |> Cmd.map (ConfigMessage >> LocalMessage) ]
|
||||
|
||||
|
||||
{-| Subscriptions for the lobby.
|
||||
|
||||
@@ -130,20 +130,24 @@ score client owner player =
|
||||
[ ( Player.statusName player.status, True )
|
||||
, ( "disconnected", player.disconnected )
|
||||
, ( "left", player.left )
|
||||
, ( "you", player.id == client )
|
||||
]
|
||||
|
||||
prename =
|
||||
((if player.id == owner then
|
||||
[ Icon.icon "star", text " " ]
|
||||
else
|
||||
[]
|
||||
)
|
||||
++ (if player.disconnected then
|
||||
[ Icon.icon "minus-circle", text " " ]
|
||||
else
|
||||
[]
|
||||
)
|
||||
)
|
||||
List.concat
|
||||
[ if player.id == owner then
|
||||
[ Icon.icon "star", text " " ]
|
||||
else
|
||||
[]
|
||||
, if player.id == client then
|
||||
[ Icon.icon "user-circle", text " " ]
|
||||
else
|
||||
[]
|
||||
, if player.disconnected then
|
||||
[ Icon.icon "minus-circle", text " " ]
|
||||
else
|
||||
[]
|
||||
]
|
||||
|
||||
afterNameTitle =
|
||||
(if player.id == owner then
|
||||
|
||||
@@ -40,6 +40,8 @@ init init location =
|
||||
, path = path
|
||||
, nameInput = Input.init Name "name-input" [ text "Your name in the game." ] "" "Nickname" (Util.cmd SubmitCurrentTab) InputMessage
|
||||
, gameCodeInput = Input.init GameCode "game-code-input" [ text "The code for the game to join." ] (path.gameCode |> Maybe.withDefault "") "" (Util.cmd JoinLobbyAsNewPlayer) InputMessage
|
||||
, passwordInput = Input.init Password "password-input" [ text "The password for the game to join." ] "" "Password" (Util.cmd JoinLobbyAsNewPlayer) InputMessage
|
||||
, passwordRequired = Nothing
|
||||
, errors = Errors.init
|
||||
, overlay = Overlay.init OverlayMessage
|
||||
, buttonsEnabled = True
|
||||
@@ -182,6 +184,9 @@ update message model =
|
||||
SetButtonsEnabled enabled ->
|
||||
( { model | buttonsEnabled = enabled }, Cmd.none )
|
||||
|
||||
SetPasswordRequired ->
|
||||
( { model | passwordRequired = Just model.gameCodeInput.value }, Cmd.none )
|
||||
|
||||
JoinLobbyAsNewPlayer ->
|
||||
( { model | buttonsEnabled = False }, Util.cmd (JoinGivenLobbyAsNewPlayer model.gameCodeInput.value) )
|
||||
|
||||
@@ -189,7 +194,7 @@ update message model =
|
||||
case List.filter (.gameCode >> ((==) gameCode)) model.storage |> List.head of
|
||||
Nothing ->
|
||||
model
|
||||
! [ Request.send (API.newPlayer gameCode model.nameInput.value)
|
||||
! [ Request.send (API.newPlayer gameCode model.nameInput.value model.passwordInput.value)
|
||||
newPlayerErrorHandler
|
||||
ErrorMessage
|
||||
(StoreCredentialsAndMoveToLobby gameCode)
|
||||
@@ -237,12 +242,16 @@ update message model =
|
||||
|
||||
( gameCodeInput, gameCodeCmd ) =
|
||||
Input.update message model.gameCodeInput
|
||||
|
||||
( passwordInput, passwordCmd ) =
|
||||
Input.update message model.passwordInput
|
||||
in
|
||||
( { model
|
||||
| nameInput = nameInput
|
||||
, gameCodeInput = gameCodeInput
|
||||
, passwordInput = passwordInput
|
||||
}
|
||||
, Cmd.batch [ nameCmd, gameCodeCmd ]
|
||||
, Cmd.batch [ nameCmd, gameCodeCmd, passwordCmd ]
|
||||
)
|
||||
|
||||
OverlayMessage overlayMessage ->
|
||||
@@ -319,6 +328,12 @@ newPlayerErrorHandler error =
|
||||
API.NameInUse ->
|
||||
( Name, Just "This name is already in use in this game, try something else." |> Input.Error ) |> InputMessage
|
||||
|
||||
API.PasswordWrong ->
|
||||
Batch
|
||||
[ SetPasswordRequired
|
||||
, ( Password, Just "This game requires a password, please check you have the right one." |> Input.Error ) |> InputMessage
|
||||
]
|
||||
|
||||
API.NewPlayerLobbyNotFound ->
|
||||
( GameCode, Just "This game doesn't exist - check you have the right code." |> Input.Error ) |> InputMessage
|
||||
in
|
||||
|
||||
@@ -32,6 +32,7 @@ type Message
|
||||
| OverlayMessage (Overlay.Message Message)
|
||||
| TabsMessage (Tabs.Message Tab)
|
||||
| StorageMessage Storage.Message
|
||||
| SetPasswordRequired
|
||||
| Batch (List Message)
|
||||
| NoOp
|
||||
|
||||
@@ -41,6 +42,7 @@ type Message
|
||||
type InputId
|
||||
= Name
|
||||
| GameCode
|
||||
| Password
|
||||
|
||||
|
||||
{-| Tabs for the start page.
|
||||
|
||||
@@ -18,6 +18,8 @@ type alias Model =
|
||||
, path : Path
|
||||
, nameInput : Input.Model InputId Message
|
||||
, gameCodeInput : Input.Model InputId Message
|
||||
, passwordInput : Input.Model InputId Message
|
||||
, passwordRequired : Maybe String
|
||||
, errors : Errors.Model
|
||||
, overlay : Overlay.Model Message
|
||||
, buttonsEnabled : Bool
|
||||
|
||||
@@ -97,9 +97,17 @@ renderTab nameEntered gameCodeEntered model tab =
|
||||
[ createLobbyButton (nameEntered && model.buttonsEnabled) ]
|
||||
|
||||
Join ->
|
||||
[ Input.view model.gameCodeInput
|
||||
, joinLobbyButton (nameEntered && gameCodeEntered && model.buttonsEnabled)
|
||||
]
|
||||
List.concat
|
||||
[ [ Input.view model.gameCodeInput
|
||||
]
|
||||
, (if model.passwordRequired == (Just model.gameCodeInput.value) then
|
||||
[ Input.view model.passwordInput ]
|
||||
else
|
||||
[]
|
||||
)
|
||||
, [ joinLobbyButton (nameEntered && gameCodeEntered && model.buttonsEnabled)
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
existingGames : List Game.GameCodeAndSecret -> List (Html msg)
|
||||
|
||||
Reference in New Issue
Block a user