feat: added loader to signin widget and restructured signin flow
This commit is contained in:
parent
35d0ca8945
commit
d39277e182
|
@ -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) },
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
14
src/main.rs
14
src/main.rs
|
@ -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();
|
||||||
|
|
||||||
response.1.emit(match response.0 {
|
|
||||||
Ok(token) => {
|
|
||||||
new_state.set_token(token);
|
new_state.set_token(token);
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
Err(e) => Err(e),
|
|
||||||
});
|
|
||||||
|
|
||||||
cloned_state.set(new_state);
|
cloned_state.set(new_state);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|
|
@ -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)
|
||||||
|
@ -72,17 +66,9 @@ pub fn TopBar() -> Html {
|
||||||
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>
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>
|
||||||
|
|
||||||
|
if !state.submitted {
|
||||||
<div class="center-x">
|
<div class="center-x">
|
||||||
<button class="auth-submit" onclick={onsubmit}>{"Sign In"}</button>
|
<button class="auth-submit" type="submit">{"Sign In"}</button>
|
||||||
</div>
|
</div>
|
||||||
|
} else {
|
||||||
<div class="center-x">
|
<div class="center-x">
|
||||||
<p class="auth-status">{props.status.clone()}</p>
|
<div class="spinner"></div>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<div class="center-x">
|
||||||
|
<p class="auth-status">{state.deref().status.clone()}</p>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue