Update to dioxus 0.4
This commit is contained in:
parent
c36ce14b3b
commit
183f8a75d2
10 changed files with 328 additions and 586 deletions
169
app/src/main.rs
169
app/src/main.rs
|
|
@ -6,16 +6,13 @@ use api::{
|
|||
LoginResponse, UserInfo,
|
||||
};
|
||||
use dioxus::prelude::*;
|
||||
use dioxus_router::{use_route, use_router, Redirect, Route, Router};
|
||||
use dioxus_router::prelude::*;
|
||||
use gloo_storage::{errors::StorageError, LocalStorage, Storage};
|
||||
use itertools::Itertools;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::{
|
||||
bootstrap::{bs, FormModal, ModalToggleButton, Spinner},
|
||||
sidebar::Page,
|
||||
};
|
||||
use crate::bootstrap::{bs, FormModal, ModalToggleButton, Spinner};
|
||||
|
||||
mod bootstrap;
|
||||
mod ingredients;
|
||||
|
|
@ -46,33 +43,6 @@ macro_rules! api {
|
|||
}};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! to_owned_props {
|
||||
// Rule matching simple symbols without a path
|
||||
($es:ident $(, $($rest:tt)*)?) => {
|
||||
#[allow(unused_mut)]
|
||||
let mut $es = $es.to_owned();
|
||||
$( to_owned_props![$($rest)*] )?
|
||||
};
|
||||
|
||||
// We need to find the last element in a path, for this we need to unstack the path part by
|
||||
// part using, separating what we have with a '@'
|
||||
($($deref:ident).+ $(, $($rest:tt)*)?) => {
|
||||
to_owned_props![@ $($deref).+ $(, $($rest)*)?]
|
||||
};
|
||||
|
||||
// Take the head of the path and add it to the list of $deref
|
||||
($($deref:ident)* @ $head:ident $( . $tail:ident)+ $(, $($rest:tt)*)?) => {
|
||||
to_owned_props![$($deref)* $head @ $($tail).+ $(, $($rest)*)?]
|
||||
};
|
||||
// We have exhausted the path, use the last as a name
|
||||
($($deref:ident)* @ $last:ident $(, $($rest:tt)*)? ) => {
|
||||
#[allow(unused_mut)]
|
||||
let mut $last = $($deref .)* $last .to_owned();
|
||||
$(to_owned_props![$($rest)*])?
|
||||
};
|
||||
}
|
||||
|
||||
#[derive(Props)]
|
||||
pub struct ErrorProps<'a> {
|
||||
error: &'a Option<String>,
|
||||
|
|
@ -158,26 +128,28 @@ pub struct HouseholdInfo {
|
|||
name: String,
|
||||
}
|
||||
|
||||
#[derive(Props)]
|
||||
pub struct RedirectorProps<'a> {
|
||||
children: Element<'a>,
|
||||
}
|
||||
|
||||
pub fn LoginRedirect<'a>(cx: Scope<'a, RedirectorProps<'a>>) -> Element {
|
||||
let router = use_router(cx);
|
||||
pub fn LoginRedirect(cx: Scope) -> Element {
|
||||
let navigator = use_navigator(cx);
|
||||
|
||||
let token = match LocalStorage::get::<LoginInfo>("token") {
|
||||
Ok(v) => v,
|
||||
Ok(v) => Some(v),
|
||||
Err(StorageError::KeyNotFound(_)) => {
|
||||
router.navigate_to("/login");
|
||||
return None;
|
||||
}
|
||||
Err(e) => unreachable!("Could not get token: {e:?}"),
|
||||
};
|
||||
|
||||
use_shared_state_provider(cx, || token);
|
||||
use_shared_state_provider(cx, || token.clone());
|
||||
|
||||
cx.render(rsx! {&cx.props.children})
|
||||
cx.render(match token {
|
||||
Some(_) => rsx! {
|
||||
Outlet::<Route> {}
|
||||
},
|
||||
None => {
|
||||
navigator.push(Route::Login);
|
||||
rsx! {{}}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async fn do_login(username: String, password: String) -> anyhow::Result<()> {
|
||||
|
|
@ -242,20 +214,20 @@ fn Openid(cx: Scope) -> Element {
|
|||
|
||||
fn Login(cx: Scope) -> Element {
|
||||
let error = use_state(cx, || None::<String>);
|
||||
let router = use_router(cx);
|
||||
let navigator = use_navigator(cx);
|
||||
|
||||
let on_submit = move |e: Event<FormData>| {
|
||||
to_owned![error, router];
|
||||
to_owned![error, navigator];
|
||||
cx.spawn(async move {
|
||||
match do_login(
|
||||
e.values["username"].to_string(),
|
||||
e.values["password"].to_string(),
|
||||
e.values["username"][0].to_string(),
|
||||
e.values["password"][0].to_string(),
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(_) => {
|
||||
error.set(None);
|
||||
router.navigate_to("/");
|
||||
navigator.push(Route::Index);
|
||||
}
|
||||
Err(e) => {
|
||||
error.set(Some(format!("Could not log in: {e}")));
|
||||
|
|
@ -357,11 +329,11 @@ fn CreateHousehold(cx: Scope) -> Element {
|
|||
|
||||
let members = use_ref(cx, Vec::<(Uuid, String)>::new);
|
||||
|
||||
let router = use_router(cx);
|
||||
let navigator = use_navigator(cx);
|
||||
|
||||
let token = login.read().token.clone();
|
||||
let on_submit = move |_| {
|
||||
to_owned![members, name, error, token, router];
|
||||
to_owned![members, name, error, token, navigator];
|
||||
|
||||
cx.spawn(async move {
|
||||
match do_new_household(token.clone(), name.to_string()).await {
|
||||
|
|
@ -387,7 +359,7 @@ fn CreateHousehold(cx: Scope) -> Element {
|
|||
let modal = bs::Modal::get_instance("#newHsModal");
|
||||
modal.hide();
|
||||
|
||||
router.navigate_to("/");
|
||||
navigator.push(Route::Index);
|
||||
error.set(None);
|
||||
}
|
||||
Err(e) => {
|
||||
|
|
@ -490,7 +462,7 @@ async fn fetch_households(token: String) -> anyhow::Result<api::Households> {
|
|||
fn HouseholdListSelect(cx: Scope) -> Element {
|
||||
let login = use_login(cx);
|
||||
let households = use_future(cx, (), |_| fetch_households(login.read().token.clone()));
|
||||
let router = use_router(cx);
|
||||
let navigator = use_navigator(cx);
|
||||
|
||||
cx.render(match households.value() {
|
||||
Some(Ok(response)) => {
|
||||
|
|
@ -511,7 +483,7 @@ fn HouseholdListSelect(cx: Scope) -> Element {
|
|||
return;
|
||||
}
|
||||
|
||||
router.navigate_to("/");
|
||||
navigator.push(Route::Index);
|
||||
};
|
||||
rsx! {button { key: "{id}", class: "btn btn-secondary m-1", onclick: onclick, "{info.name}" }}
|
||||
});
|
||||
|
|
@ -542,60 +514,69 @@ fn Index(cx: Scope) -> Element {
|
|||
cx.render(rsx! {"INDEX"})
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[derive(Deserialize, PartialEq, Clone)]
|
||||
struct OidcQuery {
|
||||
token: String,
|
||||
username: String,
|
||||
}
|
||||
|
||||
fn OidcRedirect(cx: Scope) -> Element {
|
||||
let auth = use_route(cx).query::<OidcQuery>();
|
||||
#[derive(PartialEq, Props)]
|
||||
struct OidcProps {
|
||||
token: String,
|
||||
username: String,
|
||||
}
|
||||
|
||||
cx.render(match auth {
|
||||
None => rsx! {"No authentication query, internal error."},
|
||||
Some(v) => {
|
||||
match LocalStorage::set(
|
||||
"token",
|
||||
LoginInfo {
|
||||
token: v.token,
|
||||
name: v.username,
|
||||
},
|
||||
) {
|
||||
Ok(_) => {
|
||||
gloo_utils::window().location().replace("/").unwrap();
|
||||
rsx! {{}}
|
||||
}
|
||||
Err(_) => rsx! {"Could not store authentication, try again."},
|
||||
fn OidcRedirect(cx: Scope<OidcProps>) -> Element {
|
||||
cx.render({
|
||||
match LocalStorage::set(
|
||||
"token",
|
||||
LoginInfo {
|
||||
token: cx.props.token.clone(),
|
||||
name: cx.props.username.clone(),
|
||||
},
|
||||
) {
|
||||
Ok(_) => {
|
||||
gloo_utils::window().location().replace("/").unwrap();
|
||||
rsx! {{}}
|
||||
}
|
||||
Err(_) => rsx! {"Could not store authentication, try again."},
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
use ingredients::Ingredients;
|
||||
use recipe::{RecipeCreator, RecipeList, RecipeView};
|
||||
|
||||
#[rustfmt::skip]
|
||||
#[derive(Clone, Routable)]
|
||||
enum Route {
|
||||
#[route("/login")]
|
||||
Login,
|
||||
#[route("/login/oidc?:token?:username")]
|
||||
OidcRedirect { token: String, username: String },
|
||||
|
||||
#[layout(LoginRedirect)]
|
||||
#[route("/household_selection")]
|
||||
HouseholdSelection,
|
||||
#[end_layout]
|
||||
|
||||
#[layout(RegaladeSidebar)]
|
||||
#[route("/")]
|
||||
Index,
|
||||
#[route("/ingredients")]
|
||||
Ingredients,
|
||||
#[route("/recipe_creator")]
|
||||
RecipeCreator,
|
||||
#[nest("/recipe")]
|
||||
#[route("/")]
|
||||
RecipeList,
|
||||
#[route("/:id")]
|
||||
RecipeView {id: i64}
|
||||
}
|
||||
|
||||
fn App(cx: Scope) -> Element {
|
||||
cx.render(rsx! {
|
||||
Router {
|
||||
Route { to: Page::Home.to(),
|
||||
RegaladeSidebar { current: Page::Home, Index {} }
|
||||
}
|
||||
Route { to: Page::Ingredients.to(),
|
||||
RegaladeSidebar { current: Page::Ingredients, ingredients::Ingredients {} }
|
||||
}
|
||||
Route { to: Page::RecipeCreator.to(),
|
||||
RegaladeSidebar { current: Page::RecipeCreator, recipe::RecipeCreator {} }
|
||||
}
|
||||
Route { to: Page::RecipeList.to(),
|
||||
RegaladeSidebar { current: Page::RecipeList, recipe::RecipeList {} }
|
||||
}
|
||||
Route { to: "/recipe/:recipe_id",
|
||||
RegaladeSidebar { current: Page::RecipeList, recipe::RecipeView {} }
|
||||
}
|
||||
Route { to: "/login", Login {} }
|
||||
Route { to: "/login/oidc", OidcRedirect {} }
|
||||
Route { to: "/household_selection",
|
||||
LoginRedirect { HouseholdSelection {} }
|
||||
}
|
||||
Route { to: "", "Not found" }
|
||||
}
|
||||
Router::<Route> {}
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue