quizterm/client/src/client.gleam
2026-04-10 19:36:28 +02:00

87 lines
2.3 KiB
Gleam

import gleam/dynamic/decode
import gleam/json
import gleam/option.{type Option, None, Some}
import gleam/result
import gleam/string
import lustre
import lustre/effect.{type Effect}
import model.{
type Model, type Msg, type Room, Empty, EnterPin, Initialize, KeyPin, Model,
Room, SelectedGamestyle, SelectedRoom,
}
import plinth/browser/document
import plinth/browser/element as plinth_element
import view.{view}
pub fn main() {
let room_decoder = {
use name <- decode.field("name", decode.string)
use id <- decode.field("id", decode.string)
use pin <- decode.field("key", decode.string)
decode.success(Room(id:, name:, pin:))
}
let initial_items =
document.query_selector("#model")
|> result.map(plinth_element.inner_text)
|> result.try(fn(json) {
json.parse(json, decode.list(room_decoder))
|> result.replace_error(Nil)
})
|> result.unwrap([])
let app = lustre.application(init, update, view)
let assert Ok(_) = lustre.start(app, "#app", #(initial_items, None))
Nil
}
fn init(initial: #(List(Room), Option(String))) -> #(Model, Effect(Msg)) {
let #(rooms, ohno) = initial
let model = Model(rooms:, state: Empty, ohno:)
#(model, effect.none())
}
fn update(model: Model, msg: Msg) -> #(Model, Effect(Msg)) {
case msg {
Initialize -> init(#(model.rooms, None))
SelectedRoom(room) -> #(
Model(..model, state: EnterPin(room:, pin: "")),
effect.none(),
)
KeyPin(pin) -> {
case model.state {
EnterPin(room, _) -> #(
Model(..model, state: case string.length(pin) < 4 {
False -> model.SelectGamestyle(room:, pin:)
True -> EnterPin(room:, pin:)
}),
effect.none(),
)
_ ->
init(#(
model.rooms,
Some("(fail: enterpin) Invalid state, starting over"),
))
}
}
SelectedGamestyle(style) -> {
case model.state {
model.SelectGamestyle(room:, pin:) -> {
#(
Model(..model, state: case style {
"Single Game" -> model.JoinSingle(room:, pin:)
_ -> model.JoinLive(room:, pin:)
}),
effect.none(),
)
}
_ ->
init(#(
model.rooms,
Some("(fail: selectgamestyle) Invalid state, starting over"),
))
}
}
}
}