feat: added loader to signin widget and restructured signin flow

This commit is contained in:
antifallobst 2023-10-07 10:43:32 +02:00
parent 35d0ca8945
commit d39277e182
Signed by: antifallobst
GPG Key ID: 2B4F402172791BAF
4 changed files with 57 additions and 58 deletions

View File

@ -48,13 +48,7 @@ impl Default for Session {
} }
impl Session { impl Session {
pub fn login( pub fn login(&self, username: String, password: String, callback: Callback<Result<String>>) {
&self,
username: String,
password: String,
callback: Callback<(Result<String>, Callback<Result<()>>)>,
status_callback: Callback<Result<()>>,
) {
let url = format!("{}/account/authenticate", &self.base_url); let url = format!("{}/account/authenticate", &self.base_url);
let body = json!({ let body = json!({
@ -90,7 +84,7 @@ impl Session {
}; };
wasm_bindgen_futures::spawn_local( wasm_bindgen_futures::spawn_local(
async move { callback.emit((call.await, status_callback)) }, async move { callback.emit(call.await) },
); );
} }

View File

@ -37,7 +37,7 @@ fn switch(routes: Route) -> Html {
#[derive(Clone, PartialEq)] #[derive(Clone, PartialEq)]
pub struct Callbacks { pub struct Callbacks {
pub sign_in_callback: Callback<(Result<String>, Callback<Result<()>>)>, pub sign_in: Callback<String>,
} }
#[function_component] #[function_component]
@ -47,18 +47,10 @@ fn App() -> Html {
let cloned_state = state.clone(); let cloned_state = state.clone();
let callbacks = use_state(move || Callbacks { let callbacks = use_state(move || Callbacks {
sign_in_callback: Callback::from( sign_in: Callback::from(
move |response: (Result<String>, Callback<Result<()>>)| { move |token: String| {
let mut new_state = cloned_state.deref().clone(); let mut new_state = cloned_state.deref().clone();
new_state.set_token(token);
response.1.emit(match response.0 {
Ok(token) => {
new_state.set_token(token);
Ok(())
}
Err(e) => Err(e),
});
cloned_state.set(new_state); cloned_state.set(new_state);
}, },
), ),

View File

@ -11,15 +11,12 @@ use yew::prelude::*;
pub enum Action { pub enum Action {
ToggleSignIn, ToggleSignIn,
ToggleSignUp, ToggleSignUp,
CloseAuth,
SignInStatus(String),
} }
pub struct State { pub struct State {
sign_in: bool, sign_in: bool,
sign_up: bool, sign_up: bool,
sign_in_status: AttrValue,
} }
impl Default for State { impl Default for State {
@ -27,8 +24,6 @@ impl Default for State {
Self { Self {
sign_in: false, sign_in: false,
sign_up: false, sign_up: false,
sign_in_status: AttrValue::default(),
} }
} }
} }
@ -48,10 +43,9 @@ impl Reducible for State {
state.sign_in = false; state.sign_in = false;
state.sign_up = !self.sign_up; state.sign_up = !self.sign_up;
} }
Action::SignInStatus(s) => { Action::CloseAuth => {
state.sign_in = true; state.sign_in = false;
state.sign_up = false; state.sign_up = false;
state.sign_in_status = s.into();
} }
} }
Rc::new(state) Rc::new(state)
@ -71,18 +65,10 @@ pub fn TopBar() -> Html {
let state = state.clone(); let state = state.clone();
Callback::from(move |_| state.dispatch(Action::ToggleSignUp)) Callback::from(move |_| state.dispatch(Action::ToggleSignUp))
}; };
let sign_up_close = { let close_auth_callback = {
let state = state.clone(); let state = state.clone();
Callback::from(move |_| state.dispatch(Action::ToggleSignUp)) Callback::from(move |_| state.dispatch(Action::CloseAuth))
};
let sign_in_status = {
let state = state.clone();
Callback::from(move |status: Result<()>| match status {
Ok(_) => state.dispatch(Action::ToggleSignIn),
Err(e) => state.dispatch(Action::SignInStatus(e.to_string())),
})
}; };
html! { html! {
@ -100,11 +86,11 @@ pub fn TopBar() -> Html {
</ul> </ul>
if state.sign_in { if state.sign_in {
<SignIn status={state.sign_in_status.clone()} status_callback={sign_in_status}/> <SignIn close={close_auth_callback.clone()}/>
} }
if state.sign_up { if state.sign_up {
<SignUp close={sign_up_close}/> <SignUp close={close_auth_callback.clone()}/>
} }
</nav> </nav>
} }

View File

@ -8,15 +8,16 @@ use yew::prelude::*;
#[derive(PartialEq, Clone, Default, Debug)] #[derive(PartialEq, Clone, Default, Debug)]
struct Data { struct Data {
pub submitted: bool,
pub status: String,
pub username: String, pub username: String,
pub password: String, pub password: String,
pub status: String,
} }
#[derive(Properties, PartialEq)] #[derive(Properties, PartialEq)]
pub struct Props { pub struct Props {
pub status: AttrValue, pub close: Callback<()>,
pub status_callback: Callback<Result<()>>,
} }
#[function_component] #[function_component]
@ -51,20 +52,40 @@ pub fn SignIn(props: &Props) -> Html {
cloned_state.set(data); cloned_state.set(data);
}); });
let status_callback = props.status_callback.clone(); let cloned_state = state.clone();
let onsubmit = Callback::from(move |_| { let callback = callbacks.sign_in.clone();
let state = state.deref().clone(); let close_callback = props.close.clone();
let on_sign_in_api_response = Callback::from(move |response: Result<String>| {
let mut data = cloned_state.deref().clone();
match response {
Ok(token) => {
callback.emit(token);
close_callback.emit(());
}
Err(e) => data.status = e.to_string(),
}
cloned_state.set(data);
});
let callback = on_sign_in_api_response.clone();
let cloned_state = state.clone();
let onsubmit = Callback::from(move |event: SubmitEvent| {
event.prevent_default();
let mut state = cloned_state.deref().clone();
state.submitted = true;
session.login( session.login(
state.username, state.username.clone(),
state.password, state.password.clone(),
callbacks.sign_in_callback.clone(), callback.clone(),
status_callback.clone(),
); );
cloned_state.set(state);
}); });
html! { html! {
<div class="auth-container"> <form class="auth-container" onsubmit={onsubmit}>
<div class="auth-field"> <div class="auth-field">
<label for="username">{"Username"}</label><br/> <label for="username">{"Username"}</label><br/>
<input class="auth-input" type="text" name="username" onchange={on_username_changed}/><br/> <input class="auth-input" type="text" name="username" onchange={on_username_changed}/><br/>
@ -75,13 +96,19 @@ pub fn SignIn(props: &Props) -> Html {
<input class="auth-input" type="password" name="password" onchange={on_password_changed}/><br/> <input class="auth-input" type="password" name="password" onchange={on_password_changed}/><br/>
</div> </div>
<div class="center-x"> if !state.submitted {
<button class="auth-submit" onclick={onsubmit}>{"Sign In"}</button> <div class="center-x">
</div> <button class="auth-submit" type="submit">{"Sign In"}</button>
</div>
} else {
<div class="center-x">
<div class="spinner"></div>
</div>
}
<div class="center-x"> <div class="center-x">
<p class="auth-status">{props.status.clone()}</p> <p class="auth-status">{state.deref().status.clone()}</p>
</div> </div>
</div> </form>
} }
} }