pub mod api; mod i18n; mod model; mod pages; pub mod shared; use seed::empty; use seed::prelude::*; use crate::i18n::I18n; use crate::model::Model; use crate::pages::{Msg, Page, PublicPage}; #[macro_export] macro_rules! fetch_page { (public $model: expr, $page: ident, $ret: expr) => {{ let p = match &mut $model.page { crate::pages::Page::Public(p) => p, _ => return $ret, }; match p { crate::pages::PublicPage::$page(p) => p, _ => return $ret, } }}; (public $model: expr, $page: ident) => {{ let p = match &mut $model.page { crate::pages::Page::Public(p) => p, _ => return, }; match p { crate::pages::PublicPage::$page(p) => p, _ => return, } }}; (public page $page: expr, $page_name: ident) => {{ let p = match $page { crate::pages::Page::Public(p) => p, _ => return, }; match p { crate::pages::PublicPage::$page_name(p) => p, _ => return, } }}; (public page $page: expr, $page_name: ident, $ret: expr) => {{ let p = match $page { crate::pages::Page::Public(p) => p, _ => { *$page = $ret; return; } }; match p { crate::pages::PublicPage::$page_name(p) => p, _ => { *$page = $ret; return; } } }}; } fn init(url: Url, orders: &mut impl Orders) -> Model { orders .stream(streams::interval(500, || Msg::CheckAccessToken)) .subscribe(Msg::UrlChanged); Model { url: url.clone().set_path(&[] as &[&str]), token: LocalStorage::get("auth-token").ok(), page: Page::init(url, orders), logo: seed::document() .query_selector("link[rel=icon]") .ok() .flatten() .and_then(|el: web_sys::Element| el.get_attribute("href")), shared: shared::Model::default(), i18n: I18n::load(), } } fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders) { match msg { Msg::Shared(msg) => { shared::update(msg, &mut model.shared, orders); } Msg::CheckAccessToken => { orders.skip(); if model.shared.refresh_token.is_none() { return; } if let Some(exp) = model.shared.exp { if exp > chrono::Utc::now().naive_utc() - chrono::Duration::seconds(1) { return; } if let Some(token) = model.shared.refresh_token.take() { orders.send_msg(Msg::Shared(shared::Msg::RefreshToken(token))); } } } Msg::UrlChanged(subs::UrlChanged(url)) => model.page.page_changed(url, orders), Msg::Public(pages::public::Msg::Listing(msg)) => { let page = fetch_page!(public model, Listing); pages::public::listing::update(msg, page, &mut orders.proxy(proxy_public_listing)); } Msg::Public(pages::public::Msg::Product(msg)) => { let page = fetch_page!(public model, Product); pages::public::product::update(msg, page, &mut orders.proxy(proxy_public_product)) } } } fn view(model: &Model) -> Node { match &model.page { Page::Public(PublicPage::Listing(page)) => pages::public::listing::view(model, page), Page::Public(PublicPage::Product(page)) => pages::public::product::view(model, page), _ => empty![], } } #[wasm_bindgen(start)] pub fn start() { App::start("main", init, update, view); } fn proxy_public_listing(msg: pages::public::listing::Msg) -> Msg { Msg::Public(pages::public::Msg::Listing(msg)) } fn proxy_public_product(msg: pages::public::product::Msg) -> Msg { Msg::Public(pages::public::Msg::Product(msg)) }