diff --git a/app/src/bootstrap.rs b/app/src/bootstrap.rs new file mode 100644 index 0000000..ada8be4 --- /dev/null +++ b/app/src/bootstrap.rs @@ -0,0 +1,205 @@ +use yew::prelude::*; + +pub mod bs { + use wasm_bindgen::prelude::*; + + #[wasm_bindgen(js_namespace = bootstrap)] + extern "C" { + pub type Modal; + + #[wasm_bindgen(static_method_of = Modal, js_name = "getInstance")] + pub fn get_instance(selector: &str) -> Modal; + + #[wasm_bindgen(method)] + pub fn hide(this: &Modal); + } +} + +#[derive(Properties, PartialEq)] +pub struct ModalProps { + pub id: AttrValue, + #[prop_or(true)] + pub fade: bool, + #[prop_or_default] + pub centered: bool, + #[prop_or_default] + pub labeled_by: Option, + pub children: Children, +} + +#[function_component] +pub fn Modal(props: &ModalProps) -> Html { + let mut class = classes!("modal"); + + if props.fade { + class.push("fade"); + } + + let mut dialog_class = classes!("modal-dialog"); + + if props.centered { + dialog_class.push("modal-dialog-centered"); + } + + html! { + + } +} + +#[derive(Properties, PartialEq)] +pub struct TitledModalProps { + pub id: AttrValue, + #[prop_or(true)] + pub fade: bool, + #[prop_or_default] + pub centered: bool, + pub title: AttrValue, + pub children: Children, +} + +#[function_component] +pub fn TitledModal( + TitledModalProps { + id, + fade, + centered, + children, + title, + }: &TitledModalProps, +) -> Html { + let label = format!("{id}Label"); + html! { + + +

{title}

+ +
+ { for children.iter() } +
+ } +} + +#[derive(PartialEq, Properties)] +pub struct FormModalProps { + pub id: AttrValue, + #[prop_or(true)] + pub fade: bool, + #[prop_or_default] + pub centered: bool, + #[prop_or("Submit".into())] + pub submit_label: AttrValue, + pub on_submit: Callback<()>, + pub title: AttrValue, + pub children: Children, +} + +#[function_component] +pub fn FormModal( + FormModalProps { + id, + fade, + centered, + submit_label, + title, + on_submit, + children, + }: &FormModalProps, +) -> Html { + let form_id = format!("{id}Form"); + + let on_submit = on_submit.clone(); + let onsubmit = Callback::from(move |e: SubmitEvent| { + e.prevent_default(); + + on_submit.emit(()); + }); + + html! { + + +
+ { for children.iter() } +
+
+ + + + +
+ } +} + +#[derive(Properties, PartialEq)] +pub struct ModalToggleProps { + #[prop_or(classes!("btn", "btn-primary"))] + pub classes: Classes, + pub modal_id: AttrValue, + pub children: Children, +} + +#[function_component] +pub fn ModalToggleButton(props: &ModalToggleProps) -> Html { + html! { + + } +} + +#[derive(Properties, PartialEq)] +pub struct ModalContentProps { + pub children: Children, +} + +#[function_component] +pub fn ModalHeader(props: &ModalContentProps) -> Html { + html! { + + } +} + +#[function_component] +pub fn ModalBody(props: &ModalContentProps) -> Html { + html! { + + } +} + +#[function_component] +pub fn ModalFooter(props: &ModalContentProps) -> Html { + html! { + + } +} diff --git a/app/src/main.rs b/app/src/main.rs index 5ac100f..9b1afaa 100644 --- a/app/src/main.rs +++ b/app/src/main.rs @@ -1,18 +1,23 @@ -use api::{ - CreateHouseholdRequest, CreateHouseholdResponse, Household, LoginRequest, LoginResponse, -}; use gloo_storage::{errors::StorageError, LocalStorage, Storage}; +use itertools::Itertools; use log::Level; use serde::{Deserialize, Serialize}; use uuid::Uuid; -use wasm_bindgen::{prelude::*, JsCast}; +use wasm_bindgen::JsCast; use web_sys::HtmlInputElement; use yew::{prelude::*, suspense::use_future}; -use itertools::Itertools; use yew_router::prelude::*; -use crate::sidebar::RegaladeSidebar; +use api::{ + CreateHouseholdRequest, CreateHouseholdResponse, Household, LoginRequest, LoginResponse, +}; +use crate::{ + bootstrap::{bs, FormModal, ModalToggleButton}, + sidebar::RegaladeSidebar, +}; + +mod bootstrap; mod sidebar; const API_ROUTE: &str = match option_env!("REGALADE_API_SERVER_BASE") { @@ -145,17 +150,6 @@ async fn do_new_household(token: String, name: String) -> anyhow::Result { Ok(rsp.id) } -#[wasm_bindgen(js_namespace = bootstrap)] -extern "C" { - type Modal; - - #[wasm_bindgen(static_method_of = Modal, js_name = "getInstance")] - fn get_instance(selector: &str) -> Modal; - - #[wasm_bindgen(method)] - fn hide(this: &Modal); -} - async fn fetch_households(token: String) -> anyhow::Result { let rsp = gloo_net::http::Request::get(api!("household")) .header("Authorization", &format!("Bearer {token}")) @@ -214,7 +208,7 @@ fn HouseholdListSelect() -> HtmlResult { .clone() .into_iter() .sorted_by_key(|(_,i)| i.name.clone()) - .map(mk_household) + .map(mk_household) } }, Err(e) => { @@ -238,9 +232,7 @@ fn HouseholdSelection() -> Html { let err = error.clone(); let tok = token.clone(); - let onsubmit = Callback::from(move |e: SubmitEvent| { - e.prevent_default(); - + let on_submit = Callback::from(move |()| { let document = gloo_utils::document(); let token = tok.as_ref().unwrap().to_owned(); @@ -262,7 +254,7 @@ fn HouseholdSelection() -> Html { log::error!("Could not switch to new household: {e:?}") } - let modal = Modal::get_instance("#newHsModal"); + let modal = bs::Modal::get_instance("#newHsModal"); modal.hide(); navigator.push(&Route::Index); @@ -290,70 +282,33 @@ fn HouseholdSelection() -> Html {
- -
+