import atproto_core/xrpc import crate_web/effects.{load_entry, load_shelf} import crate_web/model.{ type EntryDetail, type Model, type Notice, EntryDetail, Failure, LoggedOut, Model, Notice, OwnCrate, ShelfLoaded, Success, Warning, blank_amend, set_crate, } import crate_web/msg.{type Msg, GotEntry} import gleam/int import gleam/list import gleam/option.{type Option, None, Some} import lustre/effect.{type Effect} /// A success notice. pub fn succeeded(message: String) -> Option(Notice) { Some(Notice(Success, message)) } /// A failure notice. pub fn failed(message: String) -> Option(Notice) { Some(Notice(Failure, message)) } /// The shared 401-vs-everything-else handling for a failed write: a session /// expiry signs the visitor out and clears their shelf, anything else just /// surfaces `fallback` as a failure notice. pub fn write_error( model: Model, error: msg.ApiError, fallback: String, ) -> #(Model, Effect(Msg)) { case error { xrpc.BadStatus(status: 401, ..) -> #( Model( ..set_crate(model, OwnCrate, ShelfLoaded(model.Own, [])), auth: LoggedOut, busy: False, notice: Some(Notice( Warning, "Your session expired. Please sign in again.", )), ), effect.none(), ) _ -> #(Model(..model, busy: False, notice: failed(fallback)), effect.none()) } } /// The one hydrated-entry payload the record pages and the feed cache share, /// built from the `getEntry` response. pub fn detail_of(data: msg.EntryDetailData) -> EntryDetail { EntryDetail( did: data.did, handle: data.handle, entry: data.entry, events: data.events, release_info: data.release, ) } /// Seed an amend draft from the entry's snapshot (title + year as released, /// rest blank), or a blank draft when the entry isn't loaded (yet). pub fn seed_amend_draft(model: Model, entry_id: String) -> model.AmendDraft { case list.find(model.entries(model), fn(e) { e.entry_id == entry_id }) { Ok(found) -> model.AmendDraft( title: model.entry_snapshot(found).title, released: model.entry_snapshot(found).year |> option.map(int.to_string) |> option.unwrap(""), country: "", genres: "", styles: "", refresh_cover: False, ) Error(Nil) -> blank_amend() } } /// After an event lands, refresh the shelf and the open record detail (if any). pub fn after_write(model: Model) -> Effect(Msg) { case model.selected { Some(entry_id) -> effect.batch([ load_shelf(None, model.view), load_entry(None, entry_id, GotEntry), ]) None -> load_shelf(None, model.view) } }