use crate::pages::router;
use reinhardt_pages::component::PageExt;
use reinhardt_pages::{Effect, Element, cleanup_reactive_nodes};
use wasm_bindgen::JsCast;
use wasm_bindgen::prelude::*;
use web_sys::{Event, HtmlElement, window};
#[allow(clippy::main_recursion)]
#[wasm_bindgen(start)]
pub fn main() -> Result<(), JsValue> {
#[cfg(feature = "console_error_panic_hook")]
console_error_panic_hook::set_once();
let window = window().ok_or_else(|| JsValue::from_str("No window object"))?;
let document = window
.document()
.ok_or_else(|| JsValue::from_str("No document object"))?;
let app_element = document
.get_element_by_id("app")
.ok_or_else(|| JsValue::from_str("No #app element found"))?;
reinhardt_pages::reactive::runtime::set_scheduler(|task| {
wasm_bindgen_futures::spawn_local(async move { task() });
});
router::init_global_router();
if reinhardt_pages::auth::get_jwt_token().is_none() {
let login_url = crate::pages::router::get_login_url();
router::with_router(|r| {
let _ = r.push(&login_url);
});
}
let view = router::with_router(|r| r.render_current());
let app_wrapper = Element::new(app_element.clone());
app_element.set_inner_html(""); view.mount(&app_wrapper)
.map_err(|e| JsValue::from_str(&format!("Mount failed: {:?}", e)))?;
let app_clone = app_element.clone();
let _effect = Effect::new(move || {
let view = router::with_router(|r| {
let _ = r.current_path().get();
let _ = r.current_params().get();
r.render_current()
});
cleanup_reactive_nodes();
app_clone.set_inner_html("");
let wrapper = Element::new(app_clone.clone());
if let Err(e) = view.mount(&wrapper) {
web_sys::console::error_1(&format!("Re-mount failed: {:?}", e).into());
}
});
std::mem::forget(_effect);
let link_handler = Closure::wrap(Box::new(move |event: Event| {
if let Some(target) = event.target()
&& let Ok(element) = target.dyn_into::<HtmlElement>()
{
let mut current = Some(element);
while let Some(el) = current {
if el.tag_name().to_lowercase() == "a" {
if let Some(href) = el.get_attribute("href") {
if href.starts_with('/') {
event.prevent_default();
router::with_router(|r| {
let _ = r.push(&href);
});
return;
}
}
break;
}
current = el
.parent_element()
.and_then(|p| p.dyn_into::<HtmlElement>().ok());
}
}
}) as Box<dyn FnMut(_)>);
document.add_event_listener_with_callback("click", link_handler.as_ref().unchecked_ref())?;
link_handler.forget();
let popstate_handler = Closure::wrap(Box::new(move |_event: Event| {
router::with_router(|r| {
let current_path = web_sys::window()
.and_then(|w| {
let location = w.location();
let pathname = location.pathname().ok()?;
let search = location.search().ok().unwrap_or_default();
Some(format!("{}{}", pathname, search))
})
.unwrap_or_else(|| "/".to_string());
let _ = r.replace(¤t_path);
});
}) as Box<dyn FnMut(_)>);
window
.add_event_listener_with_callback("popstate", popstate_handler.as_ref().unchecked_ref())?;
popstate_handler.forget();
Ok(())
}