this repo has no description
lustre frontent oat-ui gleam
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

:sparkles: add backend uri to Model

+45 -16
+2
client/gleam.toml
··· 10 10 rsvp = ">= 1.2.0 and < 2.0.0" 11 11 gleam_http = ">= 4.3.0 and < 5.0.0" 12 12 youid = ">= 1.6.0 and < 2.0.0" 13 + gleam_json = ">= 3.1.0 and < 4.0.0" 14 + envoy = ">= 1.2.0 and < 2.0.0" 13 15 14 16 [dev_dependencies] 15 17 gleeunit = ">= 1.0.0 and < 2.0.0"
+2
client/manifest.toml
··· 47 47 ] 48 48 49 49 [requirements] 50 + envoy = { version = ">= 1.2.0 and < 2.0.0" } 50 51 gleam_http = { version = ">= 4.3.0 and < 5.0.0" } 52 + gleam_json = { version = ">= 3.1.0 and < 4.0.0" } 51 53 gleam_stdlib = { version = ">= 0.44.0 and < 2.0.0" } 52 54 gleeunit = { version = ">= 1.0.0 and < 2.0.0" } 53 55 lustre = { version = ">= 5.6.0 and < 6.0.0" }
+24 -10
client/src/client.gleam
··· 2 2 import client/page/home 3 3 import client/page/login 4 4 import client/page/not_found 5 + import envoy 5 6 import gleam/bool 6 7 import gleam/http/response 7 8 import gleam/option 9 + import gleam/result 10 + import gleam/uri 8 11 import lustre 9 12 import lustre/effect.{type Effect} 10 13 import lustre/element ··· 21 24 route: route.Route, 22 25 /// Current Page model 23 26 page: page.Page, 27 + /// Server uri 28 + api: uri.Uri, 24 29 ) 30 + } 31 + 32 + pub opaque type InitOpts { 33 + InitOpts(api: uri.Uri) 25 34 } 26 35 27 36 pub fn main() -> Nil { 37 + let assert Ok(api) = { 38 + use value <- result.try(envoy.get("API_URL")) 39 + uri.parse(value) 40 + } 41 + 42 + let opts = InitOpts(api:) 28 43 let app = lustre.application(init:, update:, view:) 29 - let assert Ok(_runtime) = lustre.start(app, "#app", Nil) 44 + let assert Ok(_runtime) = lustre.start(app, "#app", opts) 30 45 31 46 Nil 32 47 } ··· 43 58 44 59 // INIT 45 60 46 - pub fn init(_props: Nil) -> #(Model, Effect(Msg)) { 61 + pub fn init(opts: InitOpts) -> #(Model, Effect(Msg)) { 47 62 let assert Ok(uri) = modem.initial_uri() 48 63 let route = route.parse(uri) 49 64 let page = page.init(route) ··· 59 74 |> rsvp.get("/api/whoami", _) 60 75 61 76 let effect = effect.batch([session_effect, router_effect]) 62 - #(Model(session:, route:, page:), effect) 77 + #(Model(session:, route:, page:, api: opts.api), effect) 63 78 } 64 79 65 80 fn init_session(route: route.Route, is_protected: Bool) -> session.Session { ··· 75 90 } 76 91 77 92 fn layout( 78 - _model: Model, 79 93 element_view: element.Element(a), 80 94 f: fn(a) -> Msg, 81 95 ) -> element.Element(Msg) { ··· 85 99 pub fn view(model: Model) -> element.Element(Msg) { 86 100 case model { 87 101 // HOME PAGE --------------------------------------------------------------- 88 - Model(session:, route: route.Home, page: page.Home) -> 89 - layout(model, home.view(session), HomeMsg) 102 + Model(session:, route: route.Home, page: page.Home, ..) -> 103 + layout(home.view(session), HomeMsg) 90 104 91 105 // LOGIN PAGE -------------------------------------------------------------- 92 - Model(session:, route: route.Login, page: page.Login(page_model)) -> 93 - layout(model, login.view(session, page_model), LoginMsg) 106 + Model(session:, route: route.Login, page: page.Login(page_model), ..) -> 107 + layout(login.view(session, page_model), LoginMsg) 94 108 95 109 _ -> not_found.view() 96 110 } ··· 108 122 Model(session: session.Pending(on_success:, on_error: _), ..), 109 123 UserRestoredSession(Ok(session)) 110 124 -> #( 111 - Model(session:, route: on_success, page: page.init(on_success)), 125 + Model(..model, session:, route: on_success, page: page.init(on_success)), 112 126 modem.push(route.to_path(on_success), option.None, option.None), 113 127 ) 114 128 ··· 162 176 page_model: login.Model, 163 177 msg: login.Msg, 164 178 ) -> #(Model, Effect(Msg)) { 165 - case login.update(page_model, msg) { 179 + case login.update(page_model, msg, model.api) { 166 180 login.Continue(page_model, effect) -> #( 167 181 Model(..model, page: page.Login(page_model)), 168 182 effect.map(effect, LoginMsg),
+13 -3
client/src/client/page/login.gleam
··· 1 + import gleam/json 2 + import gleam/uri 1 3 import lustre/effect 2 4 import lustre/element 3 5 import rsvp ··· 28 30 ServerFailedToAuthenticate(reason: rsvp.Error) 29 31 } 30 32 31 - pub fn update(model: Model, msg: Msg) -> LoginStep { 33 + pub fn update(model: Model, msg: Msg, api: uri.Uri) -> LoginStep { 32 34 case msg { 33 35 UserTypedEmail(email:) -> { 34 36 let model = Model(..model, email:) ··· 41 43 } 42 44 43 45 UserClickedSubmit -> { 44 - todo as "send request" 46 + let body = 47 + json.object([ 48 + #("email", json.string(model.email)), 49 + #("password", json.string(model.password)), 50 + ]) 51 + 52 + let path = uri.Uri(..api, path: "/login") |> uri.to_string 53 + let handler = rsvp.expect_json(session.decoder(), ApiReturnedSession) 54 + let effect = rsvp.post(path, body, handler) 45 55 46 56 let model = Model(..model, loading: True) 47 - Continue(model, effect.none()) 57 + Continue(model, effect) 48 58 } 49 59 50 60 ApiReturnedSession(Ok(session)) -> ServerAuthenticatedUser(session)
+4 -3
client/test/page/login_test.gleam
··· 1 1 import client/page/login 2 2 import dummy 3 3 import gleam/list 4 + import gleam/uri 4 5 import lustre/effect 5 6 import rsvp 6 7 import shared/session ··· 17 18 18 19 let #(model, _) = { 19 20 use acc, msg <- list.fold(sequence, #(login.empty, effect.none())) 20 - let assert login.Continue(model, _) = login.update(acc.0, msg) 21 + let assert login.Continue(model, _) = login.update(acc.0, msg, uri.empty) 21 22 22 23 #(model, effect.none()) 23 24 } ··· 33 34 let model = 34 35 Ok(session.Authenticated(want)) 35 36 |> login.ApiReturnedSession 36 - |> login.update(login.empty, _) 37 + |> login.update(login.empty, _, uri.empty) 37 38 38 39 let assert login.ServerAuthenticatedUser(resp) = model 39 40 let assert session.Authenticated(got) = resp ··· 45 46 let model = 46 47 Error(rsvp.NetworkError) 47 48 |> login.ApiReturnedSession 48 - |> login.update(login.empty, _) 49 + |> login.update(login.empty, _, uri.empty) 49 50 50 51 let assert login.ServerFailedToAuthenticate(_) = model 51 52 }