step for pin code login #1
4 changed files with 97 additions and 47 deletions
7
.gitignore
vendored
7
.gitignore
vendored
|
|
@ -1 +1,6 @@
|
|||
localbuild.sh
|
||||
**/.*
|
||||
/localbuild.sh
|
||||
/client/build
|
||||
/server/build
|
||||
/server/priv/static/client.js
|
||||
/server/priv/static/index.html
|
||||
|
|
|
|||
|
|
@ -6,9 +6,15 @@ FROM ghcr.io/gleam-lang/gleam:${GLEAM_VERSION}-erlang-alpine AS builder
|
|||
COPY ./server/priv /quizterm/server/priv
|
||||
COPY ./server/src /quizterm/server/src
|
||||
COPY ./server/gleam.toml /quizterm/server/
|
||||
COPY ./client/src /quizterm/client/src
|
||||
COPY ./client/gleam.toml /quizterm/client/
|
||||
|
||||
RUN cd /quizterm/server && gleam deps download
|
||||
|
||||
# Compile client code and move generated javascript to server project
|
||||
RUN cd /quizterm/client \
|
||||
&& gleam run -m lustre/dev build --outdir=/quizterm/server/priv/static
|
||||
|
||||
# Compile the server code
|
||||
RUN cd /quizterm/server \
|
||||
&& gleam export erlang-shipment
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
import gleam/int
|
||||
import gleam/json
|
||||
import gleam/list
|
||||
import gleam/option.{type Option, None, Some}
|
||||
import gleam/result
|
||||
import gleam/string
|
||||
import lustre
|
||||
import lustre/attribute.{class}
|
||||
import lustre/effect.{type Effect}
|
||||
|
|
@ -10,7 +12,7 @@ import lustre/element/html
|
|||
import lustre/event
|
||||
import plinth/browser/document
|
||||
import plinth/browser/element as plinth_element
|
||||
import shared
|
||||
import shared.{type Room}
|
||||
|
||||
pub fn main() {
|
||||
let initial_items =
|
||||
|
|
@ -29,37 +31,47 @@ pub fn main() {
|
|||
}
|
||||
|
||||
type Model {
|
||||
Model(rooms: List(shared.Room), name: String)
|
||||
Model(
|
||||
rooms: List(Room),
|
||||
name: Option(String),
|
||||
pin: Option(String),
|
||||
typed: String,
|
||||
)
|
||||
}
|
||||
|
||||
fn init(items: List(shared.Room)) -> #(Model, Effect(Msg)) {
|
||||
let model = Model(rooms: items, name: "")
|
||||
fn init(items: List(Room)) -> #(Model, Effect(State)) {
|
||||
let model = Model(rooms: items, name: None, pin: None, typed: "")
|
||||
|
||||
#(model, effect.none())
|
||||
}
|
||||
|
||||
type Msg {
|
||||
UserTypedNewItem(String)
|
||||
UserAddedItem
|
||||
type State {
|
||||
SelectRoom(String)
|
||||
Initial
|
||||
KeyIn(String)
|
||||
}
|
||||
|
||||
fn update(model: Model, msg: Msg) -> #(Model, Effect(Msg)) {
|
||||
fn update(model: Model, msg: State) -> #(Model, Effect(msg)) {
|
||||
case msg {
|
||||
UserAddedItem ->
|
||||
Initial ->
|
||||
case model.name {
|
||||
_ -> #(model, effect.none())
|
||||
}
|
||||
UserTypedNewItem(text) -> {
|
||||
echo "CLICK " <> text <> "aa"
|
||||
#(Model(..model, name: text), effect.none())
|
||||
SelectRoom(text) -> {
|
||||
#(Model(..model, name: Some(text)), effect.none())
|
||||
}
|
||||
KeyIn(newpin) -> {
|
||||
case string.length(newpin) < 4 {
|
||||
False -> #(Model(..model, pin: Some(newpin)), effect.none())
|
||||
True -> #(Model(..model, typed: newpin), effect.none())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn view(model: Model) -> Element(Msg) {
|
||||
echo "NAME " <> model.name
|
||||
case model.name {
|
||||
"" ->
|
||||
fn view(model: Model) -> Element(State) {
|
||||
case model.name, model.pin {
|
||||
None, _ ->
|
||||
html.div([], [
|
||||
html.div([class("terminal-header")], [
|
||||
html.div([class("terminal-status")], [
|
||||
|
|
@ -72,7 +84,7 @@ fn view(model: Model) -> Element(Msg) {
|
|||
]),
|
||||
view_room_list(model.rooms),
|
||||
])
|
||||
_ -> {
|
||||
Some(_), None -> {
|
||||
html.div([], [
|
||||
html.div([class("terminal-header")], [
|
||||
html.div([class("terminal-status")], [
|
||||
|
|
@ -86,21 +98,40 @@ fn view(model: Model) -> Element(Msg) {
|
|||
pin(),
|
||||
])
|
||||
}
|
||||
Some(_), Some(_) -> {
|
||||
html.div([], [
|
||||
html.div([class("terminal-header")], [
|
||||
html.div([class("terminal-status")], [
|
||||
html.span([class("status-blink")], [html.text("●")]),
|
||||
html.text(" SYSTEM READY"),
|
||||
html.span([class("ml-8")], [
|
||||
html.text("<< Please Log On to use QuizTerm. >>"),
|
||||
]),
|
||||
]),
|
||||
]),
|
||||
html.text("FETCHING USERS FOR ROOM"),
|
||||
])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn pin() -> Element(Msg) {
|
||||
fn pin() -> Element(State) {
|
||||
html.div([attribute.class("terminal-section")], [
|
||||
html.div([attribute.class("terminal-label mb-4")], [
|
||||
html.text("Select room to play in"),
|
||||
]),
|
||||
html.div([attribute.class("participants-grid")], [
|
||||
html.text("Enter PIN code for room"),
|
||||
html.input([
|
||||
attribute.type_("password"),
|
||||
event.on_input(KeyIn),
|
||||
attribute.autofocus(True),
|
||||
]),
|
||||
]),
|
||||
])
|
||||
}
|
||||
|
||||
fn view_room_list(items: List(shared.Room)) -> Element(Msg) {
|
||||
fn view_room_list(items: List(Room)) -> Element(State) {
|
||||
html.div([attribute.class("terminal-section")], [
|
||||
html.div([attribute.class("terminal-label mb-4")], [
|
||||
html.text("Select room to play in"),
|
||||
|
|
@ -109,7 +140,7 @@ fn view_room_list(items: List(shared.Room)) -> Element(Msg) {
|
|||
[] -> [html.text("No items in your list yet.")]
|
||||
_ -> {
|
||||
list.index_map(items, fn(item, index) {
|
||||
content_cell(index, item, UserTypedNewItem)
|
||||
content_cell(index, item, SelectRoom)
|
||||
})
|
||||
}
|
||||
}),
|
||||
|
|
@ -118,9 +149,9 @@ fn view_room_list(items: List(shared.Room)) -> Element(Msg) {
|
|||
|
||||
fn content_cell(
|
||||
number: Int,
|
||||
room: shared.Room,
|
||||
on_click: fn(String) -> Msg,
|
||||
) -> Element(Msg) {
|
||||
room: Room,
|
||||
on_click: fn(String) -> msg,
|
||||
) -> Element(msg) {
|
||||
html.div([class("participant-login"), event.on_click(on_click(room.name))], [
|
||||
html.div([class("participant-name")], [
|
||||
html.text("► " <> "[#" <> int.to_string(number) <> "] Team " <> room.name),
|
||||
|
|
|
|||
|
|
@ -4,13 +4,14 @@ import backend/statehandler
|
|||
import gleam/bytes_tree
|
||||
import gleam/erlang/application
|
||||
import gleam/erlang/process
|
||||
import gleam/http
|
||||
import gleam/http/request
|
||||
import gleam/http/response.{type Response}
|
||||
import gleam/list
|
||||
import gleam/option.{None}
|
||||
import gleam/result
|
||||
import gleam/string
|
||||
import mist.{type ResponseData, File}
|
||||
import mist.{type ResponseData}
|
||||
import web/components/answerlist
|
||||
import web/components/card
|
||||
import web/components/control
|
||||
|
|
@ -25,7 +26,13 @@ pub fn main() {
|
|||
let assert Ok(room_handler) = roomhandler.initialize(state_handler)
|
||||
|
||||
let assert Ok(_) =
|
||||
fn(req) {
|
||||
fn(req: request.Request(mist.Connection)) {
|
||||
case req.method {
|
||||
// Filter out Head requests,
|
||||
http.Head ->
|
||||
response.new(200)
|
||||
|> response.set_body(mist.Bytes(bytes_tree.new()))
|
||||
_ ->
|
||||
case request.path_segments(req) {
|
||||
["lustre", "runtime.mjs"] -> serve_runtime()
|
||||
[] | ["index.html"] -> serve_static("root.html")
|
||||
|
|
@ -50,6 +57,7 @@ pub fn main() {
|
|||
)(req)
|
||||
}
|
||||
}
|
||||
}
|
||||
|> mist.new
|
||||
|> mist.bind("0.0.0.0")
|
||||
|> mist.port(1234)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue