Answer handling yay
This commit is contained in:
parent
f3020b7cb0
commit
1a410072c2
9 changed files with 79 additions and 42 deletions
|
|
@ -62,18 +62,21 @@ fn view_room_list(items: List(Room)) -> Element(Msg) {
|
||||||
|
|
||||||
fn view_enter_pin() -> Element(Msg) {
|
fn view_enter_pin() -> Element(Msg) {
|
||||||
layout("Enter PIN code for room", None, [
|
layout("Enter PIN code for room", None, [
|
||||||
|
html.div([class("participant-hidden")], []),
|
||||||
|
|
||||||
input_cell("[#ENTER PIN]", True, KeyPin),
|
input_cell("[#ENTER PIN]", True, KeyPin),
|
||||||
|
html.div([class("participant-hidden")], []),
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view_join_live(room: String, pin: String) -> Element(Msg) {
|
fn view_join_live(room: String, pin: String) -> Element(Msg) {
|
||||||
element.fragment([
|
element.fragment([
|
||||||
server_component.element(
|
server_component.element(
|
||||||
[server_component.route("/socket/live/" <> room)],
|
[server_component.route("/socket/live/" <> room <> "/" <> pin)],
|
||||||
[],
|
[],
|
||||||
),
|
),
|
||||||
server_component.element(
|
server_component.element(
|
||||||
[server_component.route("/socket/control/" <> room)],
|
[server_component.route("/socket/control/" <> room <> "/" <> pin)],
|
||||||
[],
|
[],
|
||||||
),
|
),
|
||||||
])
|
])
|
||||||
|
|
@ -81,7 +84,7 @@ fn view_join_live(room: String, pin: String) -> Element(Msg) {
|
||||||
|
|
||||||
fn view_join_single(room: String, pin: String) -> Element(Msg) {
|
fn view_join_single(room: String, pin: String) -> Element(Msg) {
|
||||||
server_component.element(
|
server_component.element(
|
||||||
[server_component.route("/socket/single/" <> room)],
|
[server_component.route("/socket/single/" <> room <> "/" <> pin)],
|
||||||
[],
|
[],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -98,7 +101,7 @@ fn input_cell(
|
||||||
password: Bool,
|
password: Bool,
|
||||||
on_input: fn(String) -> Msg,
|
on_input: fn(String) -> Msg,
|
||||||
) -> Element(Msg) {
|
) -> Element(Msg) {
|
||||||
html.div([class("participant-login")], [
|
html.div([class("participant-box")], [
|
||||||
html.div([class("participant-name")], [
|
html.div([class("participant-name")], [
|
||||||
html.p([], [html.text("► " <> header)]),
|
html.p([], [html.text("► " <> header)]),
|
||||||
html.div([], [
|
html.div([], [
|
||||||
|
|
|
||||||
|
|
@ -136,7 +136,7 @@ body {
|
||||||
}
|
}
|
||||||
|
|
||||||
.participant-hidden {
|
.participant-hidden {
|
||||||
border: 0px dashed #005500;
|
border: none;
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
color: #000000;
|
color: #000000;
|
||||||
transition: all 0.2s;
|
transition: all 0.2s;
|
||||||
|
|
|
||||||
|
|
@ -112,16 +112,10 @@ fn add_player(name: String, players: List(#(String, #(String, List(#(_, _))))))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fetch_players(
|
fn fetch_players(
|
||||||
players: List(#(String, #(String, List(#(_, String))))),
|
players: List(#(String, #(String, List(#(String, String))))),
|
||||||
subject: Subject(List(#(String, String))),
|
subject: Subject(List(#(String, #(String, List(#(String, String)))))),
|
||||||
) {
|
) {
|
||||||
actor.send(
|
actor.send(subject, players)
|
||||||
subject,
|
|
||||||
list.map(players, fn(player) {
|
|
||||||
let #(id, #(name, _)) = player
|
|
||||||
#(id, name)
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reschedule a new ping request, and ask clients to ping us back
|
// Reschedule a new ping request, and ask clients to ping us back
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,11 @@
|
||||||
import backend/playerhandler as player_handler
|
import backend/playerhandler as player_handler
|
||||||
|
import gleam/bit_array
|
||||||
|
import gleam/crypto
|
||||||
import gleam/erlang/process.{type Subject}
|
import gleam/erlang/process.{type Subject}
|
||||||
import gleam/list
|
import gleam/list
|
||||||
import gleam/option.{Some}
|
import gleam/option.{None, Some}
|
||||||
import gleam/otp/actor.{type Started}
|
import gleam/otp/actor.{type Started}
|
||||||
|
import gleam/string
|
||||||
import group_registry
|
import group_registry
|
||||||
import shared/message.{
|
import shared/message.{
|
||||||
type Room, type RoomControl, type StateControl, CreateRoom, FetchRoom,
|
type Room, type RoomControl, type StateControl, CreateRoom, FetchRoom,
|
||||||
|
|
@ -56,12 +59,22 @@ pub fn initialize(state_handler: Started(Subject(StateControl))) {
|
||||||
Ok(_) -> state
|
Ok(_) -> state
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
FetchRoom(id:, subject:) -> {
|
FetchRoom(id:, pin:, subject:) -> {
|
||||||
case
|
case
|
||||||
// Find the room, if it exists
|
// Find the room, if it exists
|
||||||
state.rooms |> list.key_find(id)
|
state.rooms |> list.key_find(id)
|
||||||
{
|
{
|
||||||
Ok(Room(_, _, actors)) -> actor.send(subject, Some(actors))
|
Ok(Room(_, pin_enc, actors)) -> {
|
||||||
|
case
|
||||||
|
string.uppercase(pin_enc)
|
||||||
|
== bit_array.base16_encode(
|
||||||
|
crypto.hash(crypto.Sha256, <<pin:utf8>>),
|
||||||
|
)
|
||||||
|
{
|
||||||
|
True -> actor.send(subject, Some(actors))
|
||||||
|
False -> actor.send(subject, None)
|
||||||
|
}
|
||||||
|
}
|
||||||
_ -> actor.send(subject, option.None)
|
_ -> actor.send(subject, option.None)
|
||||||
}
|
}
|
||||||
state
|
state
|
||||||
|
|
|
||||||
|
|
@ -14,9 +14,10 @@ pub fn serve(
|
||||||
request: Request(Connection),
|
request: Request(Connection),
|
||||||
component: lustre.App(message.ClientsServer, model, msg),
|
component: lustre.App(message.ClientsServer, model, msg),
|
||||||
id: String,
|
id: String,
|
||||||
|
pin: String,
|
||||||
actor: actor.Started(Subject(message.RoomControl)),
|
actor: actor.Started(Subject(message.RoomControl)),
|
||||||
) -> Response(ResponseData) {
|
) -> Response(ResponseData) {
|
||||||
let start_args = actor.call(actor.data, 1000, message.FetchRoom(id, _))
|
let start_args = actor.call(actor.data, 1000, message.FetchRoom(id, pin, _))
|
||||||
case start_args {
|
case start_args {
|
||||||
Some(start_args) ->
|
Some(start_args) ->
|
||||||
mist.websocket(
|
mist.websocket(
|
||||||
|
|
@ -35,13 +36,18 @@ pub fn serve(
|
||||||
|
|
||||||
pub fn serve_slow(
|
pub fn serve_slow(
|
||||||
request: Request(Connection),
|
request: Request(Connection),
|
||||||
component: lustre.App(#(List(#(String, String)), message.ClientsServer), model, msg),
|
component: lustre.App(
|
||||||
|
#(List(#(String, String)), message.ClientsServer),
|
||||||
|
model,
|
||||||
|
msg,
|
||||||
|
),
|
||||||
id: String,
|
id: String,
|
||||||
|
pin: String,
|
||||||
roomhandler: actor.Started(Subject(message.RoomControl)),
|
roomhandler: actor.Started(Subject(message.RoomControl)),
|
||||||
statehandler: actor.Started(Subject(message.StateControl)),
|
statehandler: actor.Started(Subject(message.StateControl)),
|
||||||
) -> Response(ResponseData) {
|
) -> Response(ResponseData) {
|
||||||
let start_args_opt =
|
let start_args_opt =
|
||||||
actor.call(roomhandler.data, 1000, message.FetchRoom(id, _))
|
actor.call(roomhandler.data, 1000, message.FetchRoom(id, pin, _))
|
||||||
let answer_list = actor.call(statehandler.data, 1000, message.FetchQuestions)
|
let answer_list = actor.call(statehandler.data, 1000, message.FetchQuestions)
|
||||||
|
|
||||||
case start_args_opt {
|
case start_args_opt {
|
||||||
|
|
|
||||||
|
|
@ -37,15 +37,22 @@ pub fn main() {
|
||||||
["lustre", "runtime.mjs"] -> serve_runtime()
|
["lustre", "runtime.mjs"] -> serve_runtime()
|
||||||
["client.js"] -> serve_static("client.js")
|
["client.js"] -> serve_static("client.js")
|
||||||
["static", file] -> serve_static(file)
|
["static", file] -> serve_static(file)
|
||||||
["socket", "live", id] ->
|
["socket", "live", id, pin] ->
|
||||||
sockethandler.serve(req, card.component(), id, room_handler)
|
sockethandler.serve(req, card.component(), id, pin, room_handler)
|
||||||
["socket", "control", id] ->
|
["socket", "control", id, pin] ->
|
||||||
sockethandler.serve(req, control.component(), id, room_handler)
|
sockethandler.serve(
|
||||||
["socket", "single", id] ->
|
req,
|
||||||
|
control.component(),
|
||||||
|
id,
|
||||||
|
pin,
|
||||||
|
room_handler,
|
||||||
|
)
|
||||||
|
["socket", "single", id, pin] ->
|
||||||
sockethandler.serve_slow(
|
sockethandler.serve_slow(
|
||||||
req,
|
req,
|
||||||
answerlist.component(),
|
answerlist.component(),
|
||||||
id,
|
id,
|
||||||
|
pin,
|
||||||
room_handler,
|
room_handler,
|
||||||
state_handler,
|
state_handler,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ pub type NotifyServer {
|
||||||
GiveName(name: String)
|
GiveName(name: String)
|
||||||
GiveAnswer(name: String, answer: Option(String))
|
GiveAnswer(name: String, answer: Option(String))
|
||||||
GiveSingleAnswer(id: String, question: String, answer: String)
|
GiveSingleAnswer(id: String, question: String, answer: String)
|
||||||
FetchPlayers(subject: Subject(List(#(String, String))))
|
FetchPlayers(subject: Subject(List(#(String, #(String, List(#(String, String)))))))
|
||||||
AddPlayer(String)
|
AddPlayer(String)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -37,7 +37,7 @@ pub type RoomInfo {
|
||||||
|
|
||||||
pub type RoomControl {
|
pub type RoomControl {
|
||||||
CreateRoom(id: String, room: RoomInfo)
|
CreateRoom(id: String, room: RoomInfo)
|
||||||
FetchRoom(id: String, subject: Subject(Option(ClientsServer)))
|
FetchRoom(id: String, pin: String, subject: Subject(Option(ClientsServer)))
|
||||||
FetchRooms(subject: Subject(List(#(String, RoomInfo))))
|
FetchRooms(subject: Subject(List(#(String, RoomInfo))))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,13 +29,24 @@ pub fn component() -> lustre.App(
|
||||||
pub opaque type Model {
|
pub opaque type Model {
|
||||||
Model(
|
Model(
|
||||||
state: Msg,
|
state: Msg,
|
||||||
players: List(#(String, String)),
|
players: List(#(String, #(String, List(#(String, String))))),
|
||||||
player: Option(#(String, String)),
|
player: Option(#(String, String)),
|
||||||
answers: List(#(String, #(String, String))),
|
answers: List(#(String, #(String, String))),
|
||||||
handler: Started(Subject(NotifyServer)),
|
handler: Started(Subject(NotifyServer)),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub opaque type Msg {
|
||||||
|
Initial
|
||||||
|
PickedPlayer(player: Option(#(String, String)))
|
||||||
|
SharedMessage(message: NotifyClient)
|
||||||
|
ReceiveName(name: Option(String))
|
||||||
|
AcceptPlayer(accept: Option(#(String, String)))
|
||||||
|
PickQuestion
|
||||||
|
PickedQuestion(question: Option(#(String, String)))
|
||||||
|
GiveAnswer(question: #(String, String), answer: Option(String))
|
||||||
|
}
|
||||||
|
|
||||||
fn init(
|
fn init(
|
||||||
start_args: #(List(#(String, String)), message.ClientsServer),
|
start_args: #(List(#(String, String)), message.ClientsServer),
|
||||||
) -> #(Model, Effect(Msg)) {
|
) -> #(Model, Effect(Msg)) {
|
||||||
|
|
@ -63,17 +74,6 @@ fn init(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub opaque type Msg {
|
|
||||||
Initial
|
|
||||||
PickedPlayer(player: Option(#(String, String)))
|
|
||||||
SharedMessage(message: NotifyClient)
|
|
||||||
ReceiveName(name: Option(String))
|
|
||||||
AcceptPlayer(accept: Option(#(String, String)))
|
|
||||||
PickQuestion
|
|
||||||
PickedQuestion(question: Option(#(String, String)))
|
|
||||||
GiveAnswer(question: #(String, String), answer: Option(String))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update(model: Model, msg: Msg) -> #(Model, Effect(Msg)) {
|
fn update(model: Model, msg: Msg) -> #(Model, Effect(Msg)) {
|
||||||
case msg {
|
case msg {
|
||||||
Initial -> #(Model(..model, state: msg), effect.none())
|
Initial -> #(Model(..model, state: msg), effect.none())
|
||||||
|
|
@ -168,7 +168,14 @@ fn view(model: Model) -> Element(Msg) {
|
||||||
Initial ->
|
Initial ->
|
||||||
case model.players {
|
case model.players {
|
||||||
[] -> shared.input_new_player(ReceiveName)
|
[] -> shared.input_new_player(ReceiveName)
|
||||||
_ -> shared.view_players(model.players, PickedPlayer)
|
_ ->
|
||||||
|
shared.view_players(
|
||||||
|
list.map(model.players, fn(player) {
|
||||||
|
let #(id, #(name, _)) = player
|
||||||
|
#(id, name)
|
||||||
|
}),
|
||||||
|
PickedPlayer,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
PickQuestion -> view_questions(model.answers)
|
PickQuestion -> view_questions(model.answers)
|
||||||
ReceiveName(_) -> shared.input_new_player(ReceiveName)
|
ReceiveName(_) -> shared.input_new_player(ReceiveName)
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ type State {
|
||||||
pub opaque type Model {
|
pub opaque type Model {
|
||||||
Model(
|
Model(
|
||||||
state: State,
|
state: State,
|
||||||
players: List(#(String, String)),
|
players: List(#(String, #(String, List(#(String, String))))),
|
||||||
lobby: #(String, List(User)),
|
lobby: #(String, List(User)),
|
||||||
registry: GroupRegistry(NotifyClient),
|
registry: GroupRegistry(NotifyClient),
|
||||||
handler: Started(Subject(NotifyServer)),
|
handler: Started(Subject(NotifyServer)),
|
||||||
|
|
@ -137,7 +137,14 @@ fn view(model: Model) -> Element(Msg) {
|
||||||
AskName ->
|
AskName ->
|
||||||
case model.players {
|
case model.players {
|
||||||
[] -> input_new_player(ReceiveName)
|
[] -> input_new_player(ReceiveName)
|
||||||
_ -> view_players(model.players, AcceptName)
|
_ ->
|
||||||
|
view_players(
|
||||||
|
list.map(model.players, fn(player) {
|
||||||
|
let #(id, #(name, _)) = player
|
||||||
|
#(id, name)
|
||||||
|
}),
|
||||||
|
AcceptName,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
NameOk(name) -> {
|
NameOk(name) -> {
|
||||||
shared.confirm_cells(
|
shared.confirm_cells(
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue