mirror of
https://github.com/correl/planning-poker.git
synced 2024-11-21 19:18:37 +00:00
Mock out joining a room
This commit is contained in:
parent
76d19e0937
commit
22436d22f7
4 changed files with 313 additions and 96 deletions
|
@ -79,7 +79,30 @@ updateUrl url model =
|
||||||
toEntry model (Entry.init ())
|
toEntry model (Entry.init ())
|
||||||
|
|
||||||
Just (Room id) ->
|
Just (Room id) ->
|
||||||
toRoom model (Room.init ())
|
case model.page of
|
||||||
|
EntryPage entryModel ->
|
||||||
|
toRoom model
|
||||||
|
(Room.init
|
||||||
|
{ room = id
|
||||||
|
, roomName =
|
||||||
|
case String.trim entryModel.roomName of
|
||||||
|
"" ->
|
||||||
|
"Planning Poker"
|
||||||
|
|
||||||
|
trimmed ->
|
||||||
|
trimmed
|
||||||
|
, playerName = entryModel.playerName
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
toRoom model
|
||||||
|
(Room.init
|
||||||
|
{ room = id
|
||||||
|
, roomName = "Planning Poker"
|
||||||
|
, playerName = ""
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
Nothing ->
|
Nothing ->
|
||||||
( model, Cmd.none )
|
( model, Cmd.none )
|
||||||
|
|
|
@ -11,26 +11,25 @@ import Html exposing (Html)
|
||||||
import PlanningPokerUI as UI
|
import PlanningPokerUI as UI
|
||||||
|
|
||||||
|
|
||||||
type User
|
|
||||||
= Moderator { name : String }
|
|
||||||
|
|
||||||
|
|
||||||
type alias Model =
|
type alias Model =
|
||||||
{ name : String
|
{ playerName : String
|
||||||
, user : Maybe User
|
, roomName : String
|
||||||
|
, player : Maybe String
|
||||||
, error : Maybe String
|
, error : Maybe String
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
type Msg
|
type Msg
|
||||||
= NameChanged String
|
= PlayerNameChanged String
|
||||||
|
| RoomNameChanged String
|
||||||
| CreateRoom
|
| CreateRoom
|
||||||
|
|
||||||
|
|
||||||
init : () -> ( Model, Cmd Msg )
|
init : () -> ( Model, Cmd Msg )
|
||||||
init _ =
|
init _ =
|
||||||
( { name = ""
|
( { playerName = ""
|
||||||
, user = Nothing
|
, roomName = ""
|
||||||
|
, player = Nothing
|
||||||
, error = Nothing
|
, error = Nothing
|
||||||
}
|
}
|
||||||
, Cmd.none
|
, Cmd.none
|
||||||
|
@ -40,8 +39,11 @@ init _ =
|
||||||
update : Nav.Key -> Msg -> Model -> ( Model, Cmd Msg )
|
update : Nav.Key -> Msg -> Model -> ( Model, Cmd Msg )
|
||||||
update key msg model =
|
update key msg model =
|
||||||
case msg of
|
case msg of
|
||||||
NameChanged newName ->
|
PlayerNameChanged newName ->
|
||||||
( { model | name = newName }, Cmd.none )
|
( { model | playerName = newName }, Cmd.none )
|
||||||
|
|
||||||
|
RoomNameChanged newName ->
|
||||||
|
( { model | roomName = newName }, Cmd.none )
|
||||||
|
|
||||||
CreateRoom ->
|
CreateRoom ->
|
||||||
( model, Nav.pushUrl key "/room/a0fd1422-abd9-434e-9d7c-883294b2992c" )
|
( model, Nav.pushUrl key "/room/a0fd1422-abd9-434e-9d7c-883294b2992c" )
|
||||||
|
@ -62,14 +64,21 @@ layout model =
|
||||||
[ el [ centerX ] (text "Oh, hey!")
|
[ el [ centerX ] (text "Oh, hey!")
|
||||||
, el [ centerX ] (text "Tell us who you are")
|
, el [ centerX ] (text "Tell us who you are")
|
||||||
, Input.text [ centerX, width (px 300) ]
|
, Input.text [ centerX, width (px 300) ]
|
||||||
{ onChange = NameChanged
|
{ onChange = PlayerNameChanged
|
||||||
, text = model.name
|
, text = model.playerName
|
||||||
, label = Input.labelHidden "Your name"
|
, label = Input.labelHidden "Your name"
|
||||||
, placeholder = Just (Input.placeholder [] (text "Your name"))
|
, placeholder = Just (Input.placeholder [] (text "Your name"))
|
||||||
}
|
}
|
||||||
|
, el [ centerX ] (text "and what you're up to")
|
||||||
|
, Input.text [ centerX, width (px 300) ]
|
||||||
|
{ onChange = RoomNameChanged
|
||||||
|
, text = model.roomName
|
||||||
|
, label = Input.labelHidden "Room name"
|
||||||
|
, placeholder = Just (Input.placeholder [] (text "Planning Poker"))
|
||||||
|
}
|
||||||
, el [ centerX ] (text "then")
|
, el [ centerX ] (text "then")
|
||||||
, UI.actionButton [ centerX ]
|
, UI.actionButton [ centerX ]
|
||||||
{ isActive = not (String.isEmpty model.name)
|
{ isActive = not (String.isEmpty model.playerName)
|
||||||
, onPress = CreateRoom
|
, onPress = CreateRoom
|
||||||
, label = text "Make a room!"
|
, label = text "Make a room!"
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,8 +13,22 @@ import PlanningPokerUI as UI
|
||||||
|
|
||||||
|
|
||||||
type alias Model =
|
type alias Model =
|
||||||
{ name : String
|
{ room : Maybe Room
|
||||||
, player : String
|
, player : String
|
||||||
|
, playerName : String
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type Msg
|
||||||
|
= Vote String
|
||||||
|
| Reset
|
||||||
|
| PlayerNameChanged String
|
||||||
|
| JoinRoom
|
||||||
|
|
||||||
|
|
||||||
|
type alias Room =
|
||||||
|
{ id : String
|
||||||
|
, name : String
|
||||||
, players : Dict String Player
|
, players : Dict String Player
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,27 +45,52 @@ type alias Player =
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
type Msg
|
init : { room : String, roomName : String, playerName : String } -> ( Model, Cmd Msg )
|
||||||
= Vote String
|
init { room, roomName, playerName } =
|
||||||
| Reset
|
let
|
||||||
|
preparedRooms =
|
||||||
|
|
||||||
init : () -> ( Model, Cmd Msg )
|
|
||||||
init _ =
|
|
||||||
( { name = "Planning Poker"
|
|
||||||
, player = "099b73da-e714-4085-aa33-6419076d0765"
|
|
||||||
, players =
|
|
||||||
Dict.fromList
|
Dict.fromList
|
||||||
[ ( "099b73da-e714-4085-aa33-6419076d0765"
|
[ -- Room created from mocked entry page
|
||||||
, { level = Moderator, name = "Me", vote = Nothing }
|
( "a0fd1422-abd9-434e-9d7c-883294b2992c"
|
||||||
|
, { id = "a0fd1422-abd9-434e-9d7c-883294b2992c"
|
||||||
|
, name = roomName
|
||||||
|
, players =
|
||||||
|
Dict.fromList
|
||||||
|
[ ( "00000000-0000-0000-0000-000000000000"
|
||||||
|
, { level = Moderator, name = playerName, vote = Nothing }
|
||||||
|
)
|
||||||
|
, ( "44db0a59-28bb-4b9f-8e5d-a46f2c2a3266"
|
||||||
|
, { level = Participant, name = "John", vote = Nothing }
|
||||||
|
)
|
||||||
|
, ( "69b8b450-bc2a-4eeb-b056-91c7aa4ba528"
|
||||||
|
, { level = Participant, name = "Jane", vote = Nothing }
|
||||||
|
)
|
||||||
|
]
|
||||||
|
}
|
||||||
)
|
)
|
||||||
, ( "44db0a59-28bb-4b9f-8e5d-a46f2c2a3266"
|
, -- Room created from direct url access (unjoined)
|
||||||
, { level = Participant, name = "John", vote = Nothing }
|
( "joinable"
|
||||||
)
|
, { id = "a0fd1422-abd9-434e-9d7c-883294b2992c"
|
||||||
, ( "69b8b450-bc2a-4eeb-b056-91c7aa4ba528"
|
, name = "Today's Grooming Session"
|
||||||
, { level = Participant, name = "Jane", vote = Nothing }
|
, players =
|
||||||
|
Dict.fromList
|
||||||
|
[ ( "ffffffff-ffff-ffff-ffff-ffffffffffff"
|
||||||
|
, { level = Moderator, name = "Pat", vote = Nothing }
|
||||||
|
)
|
||||||
|
, ( "44db0a59-28bb-4b9f-8e5d-a46f2c2a3266"
|
||||||
|
, { level = Participant, name = "John", vote = Nothing }
|
||||||
|
)
|
||||||
|
, ( "69b8b450-bc2a-4eeb-b056-91c7aa4ba528"
|
||||||
|
, { level = Participant, name = "Jane", vote = Nothing }
|
||||||
|
)
|
||||||
|
]
|
||||||
|
}
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
in
|
||||||
|
( { room = Dict.get room preparedRooms
|
||||||
|
, player = "00000000-0000-0000-0000-000000000000"
|
||||||
|
, playerName = playerName
|
||||||
}
|
}
|
||||||
, Cmd.none
|
, Cmd.none
|
||||||
)
|
)
|
||||||
|
@ -59,65 +98,119 @@ init _ =
|
||||||
|
|
||||||
update : Nav.Key -> Msg -> Model -> ( Model, Cmd Msg )
|
update : Nav.Key -> Msg -> Model -> ( Model, Cmd Msg )
|
||||||
update key msg model =
|
update key msg model =
|
||||||
case msg of
|
case model.room of
|
||||||
Vote value ->
|
Just room ->
|
||||||
( { model
|
case msg of
|
||||||
| players =
|
Vote value ->
|
||||||
Dict.update
|
( { model
|
||||||
model.player
|
| room =
|
||||||
(Maybe.map (\p -> { p | vote = Just value }))
|
Just
|
||||||
model.players
|
{ room
|
||||||
}
|
| players =
|
||||||
, Cmd.none
|
Dict.update
|
||||||
)
|
model.player
|
||||||
|
(Maybe.map (\p -> { p | vote = Just value }))
|
||||||
|
room.players
|
||||||
|
}
|
||||||
|
}
|
||||||
|
, Cmd.none
|
||||||
|
)
|
||||||
|
|
||||||
Reset ->
|
Reset ->
|
||||||
( { model
|
( { model
|
||||||
| players =
|
| room =
|
||||||
Dict.map
|
Just
|
||||||
(\k v -> { v | vote = Nothing })
|
{ room
|
||||||
model.players
|
| players =
|
||||||
}
|
Dict.map
|
||||||
, Cmd.none
|
(\k v -> { v | vote = Nothing })
|
||||||
)
|
room.players
|
||||||
|
}
|
||||||
|
}
|
||||||
|
, Cmd.none
|
||||||
|
)
|
||||||
|
|
||||||
|
PlayerNameChanged newName ->
|
||||||
|
( { model | playerName = newName }, Cmd.none )
|
||||||
|
|
||||||
|
JoinRoom ->
|
||||||
|
let
|
||||||
|
newRoom =
|
||||||
|
{ room
|
||||||
|
| players =
|
||||||
|
Dict.insert model.player
|
||||||
|
{ level = Participant
|
||||||
|
, name = model.playerName
|
||||||
|
, vote = Nothing
|
||||||
|
}
|
||||||
|
room.players
|
||||||
|
}
|
||||||
|
in
|
||||||
|
( { model | room = Just newRoom }, Cmd.none )
|
||||||
|
|
||||||
|
Nothing ->
|
||||||
|
case msg of
|
||||||
|
_ ->
|
||||||
|
( model, Cmd.none )
|
||||||
|
|
||||||
|
|
||||||
view : Model -> Document Msg
|
view : Model -> Document Msg
|
||||||
view model =
|
view model =
|
||||||
{ title = model.name
|
case model.room of
|
||||||
, body = [ layout model ]
|
Just room ->
|
||||||
}
|
let
|
||||||
|
maybePlayer =
|
||||||
|
Dict.get model.player room.players
|
||||||
|
in
|
||||||
|
case maybePlayer of
|
||||||
|
Just player ->
|
||||||
|
UI.toDocument
|
||||||
|
{ title = room.name
|
||||||
|
, body =
|
||||||
|
[ navBar { title = room.name, playerName = player.name }
|
||||||
|
, viewRoom model.player room
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
Nothing ->
|
||||||
|
UI.toDocument
|
||||||
|
{ title = room.name
|
||||||
|
, body =
|
||||||
|
[ navBar { title = room.name, playerName = "" }
|
||||||
|
, joinForm room model.playerName
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
UI.toDocument
|
||||||
|
{ title = "Loading Room..."
|
||||||
|
, body =
|
||||||
|
[ UI.heroText [ centerX, centerY ] "Loading..."
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
layout : Model -> Html Msg
|
viewRoom : String -> Room -> Element Msg
|
||||||
layout model =
|
viewRoom player room =
|
||||||
let
|
let
|
||||||
myVote =
|
myVote =
|
||||||
Dict.get model.player model.players
|
Dict.get player room.players
|
||||||
|> Maybe.andThen .vote
|
|> Maybe.andThen .vote
|
||||||
in
|
in
|
||||||
Element.layout [] <|
|
column [ width fill, spacing 20 ]
|
||||||
column [ width fill, spacing 20 ]
|
[ row
|
||||||
[ navBar model
|
[ width fill ]
|
||||||
, row
|
[ el [ width (fillPortion 3), alignTop ] <|
|
||||||
[ width fill ]
|
viewCards myVote
|
||||||
[ el [ width (fillPortion 3), alignTop ] <|
|
, el [ width (fillPortion 1), alignTop ] <|
|
||||||
cards myVote
|
viewPlayers (Dict.values room.players)
|
||||||
, el [ width (fillPortion 1), alignTop ] <|
|
|
||||||
players (Dict.values model.players)
|
|
||||||
]
|
|
||||||
, moderatorTools
|
|
||||||
]
|
]
|
||||||
|
, moderatorTools
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
navBar : Model -> Element Msg
|
navBar : { title : String, playerName : String } -> Element Msg
|
||||||
navBar model =
|
navBar { title, playerName } =
|
||||||
let
|
|
||||||
myName =
|
|
||||||
Dict.get model.player model.players
|
|
||||||
|> Maybe.map .name
|
|
||||||
|> Maybe.withDefault ""
|
|
||||||
in
|
|
||||||
row
|
row
|
||||||
[ Background.color UI.blue
|
[ Background.color UI.blue
|
||||||
, height (px 50)
|
, height (px 50)
|
||||||
|
@ -129,17 +222,17 @@ navBar model =
|
||||||
, Font.color UI.white
|
, Font.color UI.white
|
||||||
, width fill
|
, width fill
|
||||||
]
|
]
|
||||||
(text model.name)
|
(text title)
|
||||||
, el
|
, el
|
||||||
[ Font.alignRight
|
[ Font.alignRight
|
||||||
, Font.color UI.white
|
, Font.color UI.white
|
||||||
]
|
]
|
||||||
(text myName)
|
(text playerName)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
cards : Maybe String -> Element Msg
|
viewCards : Maybe String -> Element Msg
|
||||||
cards selected =
|
viewCards selected =
|
||||||
let
|
let
|
||||||
card value =
|
card value =
|
||||||
Input.button
|
Input.button
|
||||||
|
@ -166,8 +259,8 @@ cards selected =
|
||||||
List.map card [ "1", "3", "5", "8", "13" ]
|
List.map card [ "1", "3", "5", "8", "13" ]
|
||||||
|
|
||||||
|
|
||||||
players : List Player -> Element Msg
|
viewPlayers : List Player -> Element Msg
|
||||||
players playerList =
|
viewPlayers playerList =
|
||||||
table [ width fill ]
|
table [ width fill ]
|
||||||
{ data = playerList
|
{ data = playerList
|
||||||
, columns =
|
, columns =
|
||||||
|
@ -201,3 +294,47 @@ moderatorTools =
|
||||||
, onPress = Reset
|
, onPress = Reset
|
||||||
, label = text "Reset"
|
, label = text "Reset"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
joinForm : Room -> String -> Element Msg
|
||||||
|
joinForm room playerName =
|
||||||
|
let
|
||||||
|
players =
|
||||||
|
Dict.values room.players
|
||||||
|
|> List.map .name
|
||||||
|
in
|
||||||
|
column [ width fill, spacing 20, centerX, centerY ]
|
||||||
|
[ UI.heroText [ centerX ] "Welcome!"
|
||||||
|
, el [ centerX ] (text "Tell us who you are")
|
||||||
|
, Input.text [ centerX, width (px 300), Font.center ]
|
||||||
|
{ onChange = PlayerNameChanged
|
||||||
|
, text = playerName
|
||||||
|
, label = Input.labelHidden "Your name"
|
||||||
|
, placeholder = Just (Input.placeholder [] (text "Your name"))
|
||||||
|
}
|
||||||
|
, UI.actionButton [ centerX ]
|
||||||
|
{ isActive = not (String.isEmpty playerName)
|
||||||
|
, onPress = JoinRoom
|
||||||
|
, label = text "Join!"
|
||||||
|
}
|
||||||
|
, el [ centerX ]
|
||||||
|
(text <|
|
||||||
|
case players of
|
||||||
|
[] ->
|
||||||
|
"Nobody else has joined yet."
|
||||||
|
|
||||||
|
[ player ] ->
|
||||||
|
player ++ " is already here!"
|
||||||
|
|
||||||
|
player :: rest ->
|
||||||
|
if List.length players <= 3 then
|
||||||
|
String.join ", " rest
|
||||||
|
++ ", and "
|
||||||
|
++ player
|
||||||
|
++ " are already here!"
|
||||||
|
|
||||||
|
else
|
||||||
|
String.fromInt (List.length players)
|
||||||
|
++ " People are already here"
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
|
@ -1,33 +1,63 @@
|
||||||
module PlanningPokerUI exposing (actionButton, blue, lightGrey, red, white)
|
module PlanningPokerUI exposing
|
||||||
|
( actionButton
|
||||||
|
, blue
|
||||||
|
, colors
|
||||||
|
, fontSizes
|
||||||
|
, heroText
|
||||||
|
, lightGrey
|
||||||
|
, red
|
||||||
|
, toDocument
|
||||||
|
, white
|
||||||
|
)
|
||||||
|
|
||||||
import Element exposing (Element)
|
import Browser exposing (Document)
|
||||||
|
import Element exposing (..)
|
||||||
import Element.Background as Background
|
import Element.Background as Background
|
||||||
import Element.Font as Font
|
import Element.Font as Font
|
||||||
import Element.Input as Input
|
import Element.Input as Input
|
||||||
|
|
||||||
|
|
||||||
blue : Element.Color
|
colors =
|
||||||
|
let
|
||||||
|
primary =
|
||||||
|
blue
|
||||||
|
in
|
||||||
|
{ primary = primary
|
||||||
|
, background = white
|
||||||
|
, selected = primary
|
||||||
|
, disabled = lightGrey
|
||||||
|
, error = red
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fontSizes =
|
||||||
|
{ huge = 80
|
||||||
|
, normal = 18
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
blue : Color
|
||||||
blue =
|
blue =
|
||||||
Element.rgb255 100 100 255
|
rgb255 100 100 255
|
||||||
|
|
||||||
|
|
||||||
lightGrey : Element.Color
|
lightGrey : Color
|
||||||
lightGrey =
|
lightGrey =
|
||||||
Element.rgb255 200 200 200
|
rgb255 200 200 200
|
||||||
|
|
||||||
|
|
||||||
red : Element.Color
|
red : Color
|
||||||
red =
|
red =
|
||||||
Element.rgb255 255 100 100
|
rgb255 255 100 100
|
||||||
|
|
||||||
|
|
||||||
white : Element.Color
|
white : Color
|
||||||
white =
|
white =
|
||||||
Element.rgb255 255 255 255
|
rgb255 255 255 255
|
||||||
|
|
||||||
|
|
||||||
actionButton :
|
actionButton :
|
||||||
List (Element.Attribute msg)
|
List (Attribute msg)
|
||||||
-> { isActive : Bool, onPress : msg, label : Element msg }
|
-> { isActive : Bool, onPress : msg, label : Element msg }
|
||||||
-> Element msg
|
-> Element msg
|
||||||
actionButton attrs { isActive, onPress, label } =
|
actionButton attrs { isActive, onPress, label } =
|
||||||
|
@ -40,7 +70,7 @@ actionButton attrs { isActive, onPress, label } =
|
||||||
( lightGrey, Nothing )
|
( lightGrey, Nothing )
|
||||||
in
|
in
|
||||||
Input.button
|
Input.button
|
||||||
([ Element.padding 20
|
([ padding 20
|
||||||
, Background.color color
|
, Background.color color
|
||||||
, Font.color white
|
, Font.color white
|
||||||
]
|
]
|
||||||
|
@ -49,3 +79,21 @@ actionButton attrs { isActive, onPress, label } =
|
||||||
{ onPress = maybeEvent
|
{ onPress = maybeEvent
|
||||||
, label = label
|
, label = label
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
heroText :
|
||||||
|
List (Attribute msg)
|
||||||
|
-> String
|
||||||
|
-> Element msg
|
||||||
|
heroText attrs s =
|
||||||
|
el ([ Font.size fontSizes.huge ] ++ attrs) (text s)
|
||||||
|
|
||||||
|
|
||||||
|
toDocument : { title : String, body : List (Element msg) } -> Document msg
|
||||||
|
toDocument { title, body } =
|
||||||
|
{ title = title
|
||||||
|
, body =
|
||||||
|
[ layout [ explain Debug.todo ] <|
|
||||||
|
column [ width fill, height fill, spacing 20 ] body
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue