Current section
Files
Jump to
Current section
Files
src/illustrious/internal/state_priv.gleam
import gleam/dynamic
import gleam/json
import gleam/list
import gleam/result
import illustrious.{type Path}
import illustrious/internal/api_helpers
import illustrious/internal/router
import illustrious/state.{
type IllustriousAction, type IllustriousModel, IllustriousModel,
}
import lustre/effect.{type Effect}
import lustre_http.{expect_text, post}
pub fn wrap_decoder(decoder: state.Decoder(action)) {
fn(json: String) {
case json.decode(json, dynamic.list(decoder)) {
Ok(actions) -> state.All(actions)
_ -> json.decode(json, decoder) |> result.unwrap(state.Noop)
}
}
}
pub type WrappedUpdater(model, action) =
fn(IllustriousModel(model), IllustriousAction(action)) ->
#(IllustriousModel(model), Effect(IllustriousAction(action)))
pub fn wrap_updater(
update: state.Updater(model, action),
decoder: state.Decoder(action),
) -> WrappedUpdater(model, action) {
let wrapped_decoder = wrap_decoder(decoder)
let loader = fn(split_path: Path) {
let path =
list.fold(split_path, "", fn(full_path, part) { full_path <> "/" <> part })
post(
api_helpers.get_illustrious_api(),
json.object([#("path", json.string(path))]),
expect_text(fn(result) {
case result {
Ok(json) -> wrapped_decoder(json)
_ -> state.Noop
}
}),
)
}
fn(
illustrious_model: IllustriousModel(model),
action: IllustriousAction(action),
) {
case action {
state.Perform(sub_action) -> {
let orig_update = update(illustrious_model.inner_model, sub_action)
#(
IllustriousModel(..illustrious_model, inner_model: orig_update.0),
orig_update.1,
)
}
state.GoTo(path) -> {
let split_path = router.parse_path(path)
case illustrious_model.route == split_path {
True -> #(illustrious_model, effect.none())
False -> {
router.push_path(path)
#(
IllustriousModel(..illustrious_model, route: split_path),
loader(split_path),
)
}
}
}
state.Redirect(path) -> {
let split_path = router.parse_path(path)
case illustrious_model.route == split_path {
True -> #(illustrious_model, effect.none())
False -> {
router.replace_path(path)
#(
IllustriousModel(..illustrious_model, route: split_path),
loader(split_path),
)
}
}
}
state.Back -> {
router.back()
#(illustrious_model, effect.none())
}
state.Forward -> {
router.forward()
#(illustrious_model, effect.none())
}
state.SetPath(split_path) -> {
case illustrious_model.route == split_path {
True -> #(illustrious_model, effect.none())
False -> #(
IllustriousModel(..illustrious_model, route: split_path),
loader(split_path),
)
}
}
state.Noop -> #(illustrious_model, effect.none())
state.All(actions) -> #(
illustrious_model,
effect.from(fn(dispatch) { list.each(actions, dispatch) }),
)
}
}
}