mirror of
https://github.com/correl/planning-poker.git
synced 2024-11-24 19:19:53 +00:00
Join rooms via websockets
This commit is contained in:
parent
62b2bc2484
commit
a534184ff1
12 changed files with 255 additions and 81 deletions
|
@ -9,11 +9,11 @@
|
||||||
"elm/browser": "1.0.2",
|
"elm/browser": "1.0.2",
|
||||||
"elm/core": "1.0.5",
|
"elm/core": "1.0.5",
|
||||||
"elm/html": "1.0.0",
|
"elm/html": "1.0.0",
|
||||||
|
"elm/json": "1.1.3",
|
||||||
"elm/url": "1.0.0",
|
"elm/url": "1.0.0",
|
||||||
"mdgriffith/elm-ui": "1.1.5"
|
"mdgriffith/elm-ui": "1.1.5"
|
||||||
},
|
},
|
||||||
"indirect": {
|
"indirect": {
|
||||||
"elm/json": "1.1.3",
|
|
||||||
"elm/time": "1.0.0",
|
"elm/time": "1.0.0",
|
||||||
"elm/virtual-dom": "1.0.2"
|
"elm/virtual-dom": "1.0.2"
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,8 +14,38 @@ import "../css/app.scss"
|
||||||
//
|
//
|
||||||
import "phoenix_html"
|
import "phoenix_html"
|
||||||
|
|
||||||
import { Elm } from "../src/Main.elm";
|
import { Socket, Presence } from "phoenix"
|
||||||
|
import { Elm } from "../src/Main.elm"
|
||||||
|
import uuid4 from "uuid4"
|
||||||
|
|
||||||
|
var player_id = uuid4()
|
||||||
|
|
||||||
|
var socket = new Socket("/socket", {params: {player_id: player_id}})
|
||||||
|
socket.connect()
|
||||||
|
|
||||||
var app = Elm.Main.init({
|
var app = Elm.Main.init({
|
||||||
node: document.getElementById("elm-main")
|
node: document.getElementById("elm-main"),
|
||||||
});
|
flags: "player:" + player_id
|
||||||
|
})
|
||||||
|
|
||||||
|
app.ports.joinRoom.subscribe(options => {
|
||||||
|
let channel = socket.channel(
|
||||||
|
"room:" + options.room,
|
||||||
|
{playerName: options.playerName}
|
||||||
|
)
|
||||||
|
let presences = {}
|
||||||
|
channel.join()
|
||||||
|
.receive("ok", resp => {
|
||||||
|
console.log("Joined successfully", resp);
|
||||||
|
app.ports.joinedRoom.send(options.room);
|
||||||
|
})
|
||||||
|
.receive("error", resp => { console.log("Unable to join", resp) })
|
||||||
|
channel.on("presence_state", state => {
|
||||||
|
presences = Presence.syncState(presences, state)
|
||||||
|
app.ports.gotPresence.send(presences)
|
||||||
|
})
|
||||||
|
channel.on("presence_diff", diff => {
|
||||||
|
presences = Presence.syncDiff(presences, diff)
|
||||||
|
app.ports.gotPresence.send(presences)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
5
assets/package-lock.json
generated
5
assets/package-lock.json
generated
|
@ -8132,6 +8132,11 @@
|
||||||
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
|
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"uuid4": {
|
||||||
|
"version": "1.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/uuid4/-/uuid4-1.1.4.tgz",
|
||||||
|
"integrity": "sha512-Gr1q2k40LpF8CokcnQFjPDsdslzJbTCTBG5xQIEflUov431gFkY5KduiGIeKYAamkQnNn4IfdHJbLnl9Bib8TQ=="
|
||||||
|
},
|
||||||
"v8-compile-cache": {
|
"v8-compile-cache": {
|
||||||
"version": "2.0.3",
|
"version": "2.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.0.3.tgz",
|
||||||
|
|
|
@ -9,7 +9,8 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"phoenix": "file:../deps/phoenix",
|
"phoenix": "file:../deps/phoenix",
|
||||||
"phoenix_html": "file:../deps/phoenix_html"
|
"phoenix_html": "file:../deps/phoenix_html",
|
||||||
|
"uuid4": "^1.1.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.0.0",
|
"@babel/core": "^7.0.0",
|
||||||
|
|
|
@ -13,6 +13,7 @@ import Url.Parser as Parser exposing ((</>), Parser, s, string)
|
||||||
type alias Model =
|
type alias Model =
|
||||||
{ page : Page
|
{ page : Page
|
||||||
, key : Nav.Key
|
, key : Nav.Key
|
||||||
|
, player : String
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -34,9 +35,9 @@ type Msg
|
||||||
| RoomMsg Room.Msg
|
| RoomMsg Room.Msg
|
||||||
|
|
||||||
|
|
||||||
init : () -> Url -> Nav.Key -> ( Model, Cmd Msg )
|
init : String -> Url -> Nav.Key -> ( Model, Cmd Msg )
|
||||||
init _ url key =
|
init player url key =
|
||||||
updateUrl url { page = NotFound, key = key }
|
updateUrl url { page = NotFound, key = key, player = player }
|
||||||
|
|
||||||
|
|
||||||
update : Msg -> Model -> ( Model, Cmd Msg )
|
update : Msg -> Model -> ( Model, Cmd Msg )
|
||||||
|
@ -83,7 +84,8 @@ updateUrl url model =
|
||||||
EntryPage entryModel ->
|
EntryPage entryModel ->
|
||||||
toRoom model
|
toRoom model
|
||||||
(Room.init
|
(Room.init
|
||||||
{ room = id
|
{ id = id
|
||||||
|
, player = model.player
|
||||||
, roomName =
|
, roomName =
|
||||||
case String.trim entryModel.roomName of
|
case String.trim entryModel.roomName of
|
||||||
"" ->
|
"" ->
|
||||||
|
@ -98,7 +100,8 @@ updateUrl url model =
|
||||||
_ ->
|
_ ->
|
||||||
toRoom model
|
toRoom model
|
||||||
(Room.init
|
(Room.init
|
||||||
{ room = id
|
{ id = id
|
||||||
|
, player = model.player
|
||||||
, roomName = "Planning Poker"
|
, roomName = "Planning Poker"
|
||||||
, playerName = ""
|
, playerName = ""
|
||||||
}
|
}
|
||||||
|
@ -133,7 +136,7 @@ view model =
|
||||||
NotFound.view
|
NotFound.view
|
||||||
|
|
||||||
|
|
||||||
main : Program () Model Msg
|
main : Program String Model Msg
|
||||||
main =
|
main =
|
||||||
Browser.application
|
Browser.application
|
||||||
{ init = init
|
{ init = init
|
||||||
|
@ -141,5 +144,13 @@ main =
|
||||||
, update = update
|
, update = update
|
||||||
, onUrlChange = ChangedUrl
|
, onUrlChange = ChangedUrl
|
||||||
, onUrlRequest = ClickedLink
|
, onUrlRequest = ClickedLink
|
||||||
, subscriptions = \_ -> Sub.none
|
, subscriptions = subscriptions
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
subscriptions : Model -> Sub Msg
|
||||||
|
subscriptions _ =
|
||||||
|
Sub.batch
|
||||||
|
[ Sub.map EntryMsg Entry.subscriptions
|
||||||
|
, Sub.map RoomMsg Room.subscriptions
|
||||||
|
]
|
||||||
|
|
16
assets/src/PlanningPokerAPI.elm
Normal file
16
assets/src/PlanningPokerAPI.elm
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
port module PlanningPokerAPI exposing
|
||||||
|
( gotPresence
|
||||||
|
, joinRoom
|
||||||
|
, joinedRoom
|
||||||
|
)
|
||||||
|
|
||||||
|
import Json.Decode exposing (Value)
|
||||||
|
|
||||||
|
|
||||||
|
port joinRoom : { room : String, playerName : String } -> Cmd msg
|
||||||
|
|
||||||
|
|
||||||
|
port joinedRoom : (String -> msg) -> Sub msg
|
||||||
|
|
||||||
|
|
||||||
|
port gotPresence : (Value -> msg) -> Sub msg
|
|
@ -8,6 +8,7 @@ import Element.Border as Border
|
||||||
import Element.Font as Font
|
import Element.Font as Font
|
||||||
import Element.Input as Input
|
import Element.Input as Input
|
||||||
import Html exposing (Html)
|
import Html exposing (Html)
|
||||||
|
import PlanningPokerAPI as API
|
||||||
import PlanningPokerUI as UI
|
import PlanningPokerUI as UI
|
||||||
|
|
||||||
|
|
||||||
|
@ -23,6 +24,7 @@ type Msg
|
||||||
= PlayerNameChanged String
|
= PlayerNameChanged String
|
||||||
| RoomNameChanged String
|
| RoomNameChanged String
|
||||||
| CreateRoom
|
| CreateRoom
|
||||||
|
| JoinedRoom String
|
||||||
|
|
||||||
|
|
||||||
init : () -> ( Model, Cmd Msg )
|
init : () -> ( Model, Cmd Msg )
|
||||||
|
@ -46,7 +48,16 @@ update key msg model =
|
||||||
( { model | roomName = newName }, Cmd.none )
|
( { model | roomName = newName }, Cmd.none )
|
||||||
|
|
||||||
CreateRoom ->
|
CreateRoom ->
|
||||||
( model, Nav.pushUrl key "/room/a0fd1422-abd9-434e-9d7c-883294b2992c" )
|
let
|
||||||
|
room =
|
||||||
|
"a0fd1422-abd9-434e-9d7c-883294b2992c"
|
||||||
|
in
|
||||||
|
( model
|
||||||
|
, API.joinRoom { room = room, playerName = model.playerName }
|
||||||
|
)
|
||||||
|
|
||||||
|
JoinedRoom room ->
|
||||||
|
( model, Nav.pushUrl key ("/room/" ++ room) )
|
||||||
|
|
||||||
|
|
||||||
view : Model -> Document Msg
|
view : Model -> Document Msg
|
||||||
|
@ -92,3 +103,8 @@ layout model =
|
||||||
<|
|
<|
|
||||||
text (Maybe.withDefault " " model.error)
|
text (Maybe.withDefault " " model.error)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
subscriptions : Sub Msg
|
||||||
|
subscriptions =
|
||||||
|
API.joinedRoom JoinedRoom
|
||||||
|
|
|
@ -1,4 +1,11 @@
|
||||||
module PlanningPokerRoom exposing (Model, Msg, init, update, view)
|
module PlanningPokerRoom exposing
|
||||||
|
( Model
|
||||||
|
, Msg
|
||||||
|
, init
|
||||||
|
, subscriptions
|
||||||
|
, update
|
||||||
|
, view
|
||||||
|
)
|
||||||
|
|
||||||
import Browser exposing (Document)
|
import Browser exposing (Document)
|
||||||
import Browser.Navigation as Nav
|
import Browser.Navigation as Nav
|
||||||
|
@ -9,6 +16,8 @@ import Element.Border as Border
|
||||||
import Element.Font as Font
|
import Element.Font as Font
|
||||||
import Element.Input as Input
|
import Element.Input as Input
|
||||||
import Html exposing (Html)
|
import Html exposing (Html)
|
||||||
|
import Json.Decode as Decode
|
||||||
|
import PlanningPokerAPI as API
|
||||||
import PlanningPokerUI as UI
|
import PlanningPokerUI as UI
|
||||||
|
|
||||||
|
|
||||||
|
@ -16,14 +25,17 @@ type alias Model =
|
||||||
{ room : Maybe Room
|
{ room : Maybe Room
|
||||||
, player : String
|
, player : String
|
||||||
, playerName : String
|
, playerName : String
|
||||||
|
, showVotes : Bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
type Msg
|
type Msg
|
||||||
= Vote String
|
= Vote String
|
||||||
| Reset
|
| Reset
|
||||||
|
| Reveal
|
||||||
| PlayerNameChanged String
|
| PlayerNameChanged String
|
||||||
| JoinRoom
|
| JoinRoom
|
||||||
|
| GotPresence Decode.Value
|
||||||
|
|
||||||
|
|
||||||
type alias Room =
|
type alias Room =
|
||||||
|
@ -33,11 +45,6 @@ type alias Room =
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
type UserLevel
|
|
||||||
= Moderator
|
|
||||||
| Participant
|
|
||||||
|
|
||||||
|
|
||||||
type alias Player =
|
type alias Player =
|
||||||
{ level : UserLevel
|
{ level : UserLevel
|
||||||
, name : String
|
, name : String
|
||||||
|
@ -45,52 +52,35 @@ type alias Player =
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
init : { room : String, roomName : String, playerName : String } -> ( Model, Cmd Msg )
|
type UserLevel
|
||||||
init { room, roomName, playerName } =
|
= Moderator
|
||||||
|
| Participant
|
||||||
|
|
||||||
|
|
||||||
|
type Vote
|
||||||
|
= Hidden (Maybe String)
|
||||||
|
| Revealed (Maybe String)
|
||||||
|
|
||||||
|
|
||||||
|
init :
|
||||||
|
{ id : String
|
||||||
|
, player : String
|
||||||
|
, roomName : String
|
||||||
|
, playerName : String
|
||||||
|
}
|
||||||
|
-> ( Model, Cmd Msg )
|
||||||
|
init { id, player, roomName, playerName } =
|
||||||
let
|
let
|
||||||
preparedRooms =
|
room =
|
||||||
Dict.fromList
|
{ id = id
|
||||||
[ -- Room created from mocked entry page
|
, name = roomName
|
||||||
( "a0fd1422-abd9-434e-9d7c-883294b2992c"
|
, players = Dict.empty
|
||||||
, { 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 }
|
|
||||||
)
|
|
||||||
]
|
|
||||||
}
|
|
||||||
)
|
|
||||||
, -- Room created from direct url access (unjoined)
|
|
||||||
( "joinable"
|
|
||||||
, { id = "a0fd1422-abd9-434e-9d7c-883294b2992c"
|
|
||||||
, name = "Today's Grooming Session"
|
|
||||||
, 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
|
in
|
||||||
( { room = Dict.get room preparedRooms
|
( { room = Just room
|
||||||
, player = "00000000-0000-0000-0000-000000000000"
|
, player = player
|
||||||
, playerName = playerName
|
, playerName = playerName
|
||||||
|
, showVotes = False
|
||||||
}
|
}
|
||||||
, Cmd.none
|
, Cmd.none
|
||||||
)
|
)
|
||||||
|
@ -116,6 +106,11 @@ update key msg model =
|
||||||
, Cmd.none
|
, Cmd.none
|
||||||
)
|
)
|
||||||
|
|
||||||
|
Reveal ->
|
||||||
|
( { model | showVotes = True }
|
||||||
|
, Cmd.none
|
||||||
|
)
|
||||||
|
|
||||||
Reset ->
|
Reset ->
|
||||||
( { model
|
( { model
|
||||||
| room =
|
| room =
|
||||||
|
@ -126,6 +121,7 @@ update key msg model =
|
||||||
(\k v -> { v | vote = Nothing })
|
(\k v -> { v | vote = Nothing })
|
||||||
room.players
|
room.players
|
||||||
}
|
}
|
||||||
|
, showVotes = False
|
||||||
}
|
}
|
||||||
, Cmd.none
|
, Cmd.none
|
||||||
)
|
)
|
||||||
|
@ -146,7 +142,21 @@ update key msg model =
|
||||||
room.players
|
room.players
|
||||||
}
|
}
|
||||||
in
|
in
|
||||||
( { model | room = Just newRoom }, Cmd.none )
|
( model
|
||||||
|
, API.joinRoom { room = room.id, playerName = model.playerName }
|
||||||
|
)
|
||||||
|
|
||||||
|
GotPresence value ->
|
||||||
|
case Decode.decodeValue playersDecoder value of
|
||||||
|
Ok players ->
|
||||||
|
let
|
||||||
|
newRoom =
|
||||||
|
{ room | players = players }
|
||||||
|
in
|
||||||
|
( { model | room = Just newRoom }, Cmd.none )
|
||||||
|
|
||||||
|
Err _ ->
|
||||||
|
( model, Cmd.none )
|
||||||
|
|
||||||
Nothing ->
|
Nothing ->
|
||||||
case msg of
|
case msg of
|
||||||
|
@ -168,7 +178,7 @@ view model =
|
||||||
{ title = room.name
|
{ title = room.name
|
||||||
, body =
|
, body =
|
||||||
[ navBar { title = room.name, playerName = player.name }
|
[ navBar { title = room.name, playerName = player.name }
|
||||||
, viewRoom model.player room
|
, viewRoom model.player room model.showVotes
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,8 +200,8 @@ view model =
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
viewRoom : String -> Room -> Element Msg
|
viewRoom : String -> Room -> Bool -> Element Msg
|
||||||
viewRoom player room =
|
viewRoom player room showVotes =
|
||||||
let
|
let
|
||||||
myVote =
|
myVote =
|
||||||
Dict.get player room.players
|
Dict.get player room.players
|
||||||
|
@ -203,7 +213,7 @@ viewRoom player room =
|
||||||
[ el [ width (fillPortion 3), alignTop ] <|
|
[ el [ width (fillPortion 3), alignTop ] <|
|
||||||
viewCards myVote
|
viewCards myVote
|
||||||
, el [ width (fillPortion 1), alignTop ] <|
|
, el [ width (fillPortion 1), alignTop ] <|
|
||||||
viewPlayers (Dict.values room.players)
|
viewPlayers (Dict.values room.players) showVotes
|
||||||
]
|
]
|
||||||
, moderatorTools
|
, moderatorTools
|
||||||
]
|
]
|
||||||
|
@ -259,8 +269,8 @@ viewCards selected =
|
||||||
List.map card [ "1", "3", "5", "8", "13" ]
|
List.map card [ "1", "3", "5", "8", "13" ]
|
||||||
|
|
||||||
|
|
||||||
viewPlayers : List Player -> Element Msg
|
viewPlayers : List Player -> Bool -> Element Msg
|
||||||
viewPlayers playerList =
|
viewPlayers playerList showVotes =
|
||||||
table [ width fill ]
|
table [ width fill ]
|
||||||
{ data = playerList
|
{ data = playerList
|
||||||
, columns =
|
, columns =
|
||||||
|
@ -275,11 +285,19 @@ viewPlayers playerList =
|
||||||
, width = px 50
|
, width = px 50
|
||||||
, view =
|
, view =
|
||||||
\player ->
|
\player ->
|
||||||
|
let
|
||||||
|
vote =
|
||||||
|
if showVotes then
|
||||||
|
player.vote
|
||||||
|
|
||||||
|
else
|
||||||
|
Maybe.map (\_ -> "✓") player.vote
|
||||||
|
in
|
||||||
el
|
el
|
||||||
[ padding 10
|
[ padding 10
|
||||||
, Font.alignRight
|
, Font.alignRight
|
||||||
]
|
]
|
||||||
(text <| Maybe.withDefault " " player.vote)
|
(text <| Maybe.withDefault " " vote)
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -287,12 +305,20 @@ viewPlayers playerList =
|
||||||
|
|
||||||
moderatorTools : Element Msg
|
moderatorTools : Element Msg
|
||||||
moderatorTools =
|
moderatorTools =
|
||||||
UI.actionButton
|
row [ centerX, spacing 20 ]
|
||||||
[ centerX ]
|
[ UI.actionButton
|
||||||
{ isActive = True
|
[ centerX ]
|
||||||
, onPress = Reset
|
{ isActive = True
|
||||||
, label = text "Reset"
|
, onPress = Reveal
|
||||||
}
|
, label = text "Reveal"
|
||||||
|
}
|
||||||
|
, UI.actionButton
|
||||||
|
[ centerX ]
|
||||||
|
{ isActive = True
|
||||||
|
, onPress = Reset
|
||||||
|
, label = text "Reset"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
joinForm : Room -> String -> Element Msg
|
joinForm : Room -> String -> Element Msg
|
||||||
|
@ -337,3 +363,38 @@ joinForm room playerName =
|
||||||
++ " People are already here"
|
++ " People are already here"
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
subscriptions : Sub Msg
|
||||||
|
subscriptions =
|
||||||
|
API.gotPresence GotPresence
|
||||||
|
|
||||||
|
|
||||||
|
type alias Presence =
|
||||||
|
{ metas : List PresenceMeta }
|
||||||
|
|
||||||
|
|
||||||
|
type alias PresenceMeta =
|
||||||
|
{ name : String
|
||||||
|
, online_at : String
|
||||||
|
, phx_ref : String
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
playersDecoder : Decode.Decoder (Dict String Player)
|
||||||
|
playersDecoder =
|
||||||
|
let
|
||||||
|
meta =
|
||||||
|
Decode.field "name" Decode.string
|
||||||
|
|
||||||
|
presence =
|
||||||
|
Decode.field "metas" (Decode.index 0 meta)
|
||||||
|
|
||||||
|
toPlayer id name =
|
||||||
|
{ level = Participant
|
||||||
|
, name = name
|
||||||
|
, vote = Nothing
|
||||||
|
}
|
||||||
|
in
|
||||||
|
Decode.dict presence
|
||||||
|
|> Decode.map (Dict.map toPlayer)
|
||||||
|
|
|
@ -12,9 +12,10 @@ defmodule Planningpoker.Application do
|
||||||
# Start the PubSub system
|
# Start the PubSub system
|
||||||
{Phoenix.PubSub, name: Planningpoker.PubSub},
|
{Phoenix.PubSub, name: Planningpoker.PubSub},
|
||||||
# Start the Endpoint (http/https)
|
# Start the Endpoint (http/https)
|
||||||
PlanningpokerWeb.Endpoint
|
PlanningpokerWeb.Endpoint,
|
||||||
# Start a worker by calling: Planningpoker.Worker.start_link(arg)
|
# Start a worker by calling: Planningpoker.Worker.start_link(arg)
|
||||||
# {Planningpoker.Worker, arg}
|
# {Planningpoker.Worker, arg}
|
||||||
|
PlanningpokerWeb.Presence
|
||||||
]
|
]
|
||||||
|
|
||||||
# See https://hexdocs.pm/elixir/Supervisor.html
|
# See https://hexdocs.pm/elixir/Supervisor.html
|
||||||
|
|
10
lib/planningpoker_web/channels/presence.ex
Normal file
10
lib/planningpoker_web/channels/presence.ex
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
defmodule PlanningpokerWeb.Presence do
|
||||||
|
@moduledoc """
|
||||||
|
Provides presence tracking to channels and processes.
|
||||||
|
|
||||||
|
See the [`Phoenix.Presence`](http://hexdocs.pm/phoenix/Phoenix.Presence.html)
|
||||||
|
docs for more details.
|
||||||
|
"""
|
||||||
|
use Phoenix.Presence, otp_app: :planningpoker,
|
||||||
|
pubsub_server: Planningpoker.PubSub
|
||||||
|
end
|
23
lib/planningpoker_web/channels/room_channel.ex
Normal file
23
lib/planningpoker_web/channels/room_channel.ex
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
defmodule PlanningpokerWeb.RoomChannel do
|
||||||
|
use Phoenix.Channel
|
||||||
|
alias PlanningpokerWeb.Presence
|
||||||
|
|
||||||
|
def join("room:" <> room_id, params, socket) do
|
||||||
|
send(self(), :after_join)
|
||||||
|
{:ok, %{channel: room_id, topic: "Planning Poker"},
|
||||||
|
socket
|
||||||
|
|> assign(:room_id, room_id)
|
||||||
|
|> assign(:player_name, params["playerName"])}
|
||||||
|
end
|
||||||
|
def handle_info(:after_join, socket) do
|
||||||
|
{:ok, _} = Presence.track(
|
||||||
|
socket,
|
||||||
|
"player:#{socket.assigns.player_id}",
|
||||||
|
%{
|
||||||
|
name: socket.assigns.player_name,
|
||||||
|
online_at: inspect(System.system_time(:second))
|
||||||
|
})
|
||||||
|
push(socket, "presence_state", Presence.list(socket))
|
||||||
|
{:noreply, socket}
|
||||||
|
end
|
||||||
|
end
|
|
@ -2,7 +2,7 @@ defmodule PlanningpokerWeb.UserSocket do
|
||||||
use Phoenix.Socket
|
use Phoenix.Socket
|
||||||
|
|
||||||
## Channels
|
## Channels
|
||||||
# channel "room:*", PlanningpokerWeb.RoomChannel
|
channel "room:*", PlanningpokerWeb.RoomChannel
|
||||||
|
|
||||||
# Socket params are passed from the client and can
|
# Socket params are passed from the client and can
|
||||||
# be used to verify and authenticate a user. After
|
# be used to verify and authenticate a user. After
|
||||||
|
@ -16,8 +16,8 @@ defmodule PlanningpokerWeb.UserSocket do
|
||||||
# See `Phoenix.Token` documentation for examples in
|
# See `Phoenix.Token` documentation for examples in
|
||||||
# performing token verification on connect.
|
# performing token verification on connect.
|
||||||
@impl true
|
@impl true
|
||||||
def connect(_params, socket, _connect_info) do
|
def connect(params, socket, _connect_info) do
|
||||||
{:ok, socket}
|
{:ok, assign(socket, :player_id, params["player_id"])}
|
||||||
end
|
end
|
||||||
|
|
||||||
# Socket id's are topics that allow you to identify all sockets for a given user:
|
# Socket id's are topics that allow you to identify all sockets for a given user:
|
||||||
|
@ -31,5 +31,5 @@ defmodule PlanningpokerWeb.UserSocket do
|
||||||
#
|
#
|
||||||
# Returning `nil` makes this socket anonymous.
|
# Returning `nil` makes this socket anonymous.
|
||||||
@impl true
|
@impl true
|
||||||
def id(_socket), do: nil
|
def id(_socket), do: "player:${socket.assigns.player_id}"
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue