mentorenwahl/frontend/src/routes/login.rs

173 lines
6.9 KiB
Rust

use graphql_client::reqwest::post_graphql;
use web_sys::HtmlInputElement;
use yew::prelude::*;
use yew_router::prelude::*;
use yew_side_effect::title::Title;
use crate::components;
use crate::cookies;
use crate::graphql;
use crate::layouts;
use crate::routes;
#[derive(Properties, PartialEq)]
pub struct LoginProps {
pub token: Option<String>,
pub logged_in: bool,
}
pub enum Msg {
Submit,
Login(Option<Vec<String>>),
}
pub struct Login {
username: NodeRef,
password: NodeRef,
fetching: bool,
errors: Option<Vec<String>>,
}
impl Component for Login {
type Message = Msg;
type Properties = LoginProps;
fn create(_ctx: &Context<Self>) -> Self {
Self {
username: NodeRef::default(),
password: NodeRef::default(),
fetching: false,
errors: None,
}
}
fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
match msg {
Msg::Submit => {
if let (Some(username), Some(password)) = (
self.username.cast::<HtmlInputElement>().map(|x| x.value()),
self.password.cast::<HtmlInputElement>().map(|x| x.value()),
) {
if !username.is_empty() && !password.is_empty() {
self.fetching = true;
ctx.link().send_future(async {
let response = post_graphql::<graphql::mutations::login::Login, _>(
&graphql::client(None).unwrap(),
graphql::URL.as_str(),
graphql::mutations::login::login::Variables { username, password },
)
.await
.unwrap();
if response.errors.is_some() {
cookies::logout_clear();
} else {
let data = response.data.unwrap().login.unwrap();
wasm_cookies::set(
cookies::TOKEN,
&data.token,
&wasm_cookies::CookieOptions::default(),
);
if data.user.admin {
wasm_cookies::set(
cookies::ADMIN,
"1",
&wasm_cookies::CookieOptions::default(),
);
} else {
wasm_cookies::delete(cookies::ADMIN);
}
}
Msg::Login(components::graphql_errors::convert(response.errors))
});
true
} else {
false
}
} else {
false
}
}
Msg::Login(errors) => {
self.fetching = false;
self.errors = errors;
if self.errors.is_none() {
ctx.link().history().unwrap().push(routes::Route::Home);
false
} else {
true
}
}
}
}
fn view(&self, ctx: &Context<Self>) -> Html {
if ctx.props().logged_in {
ctx.link().history().unwrap().push(routes::Route::Home);
}
html! {
<>
<Title value="Login" />
<layouts::main::Main token={ctx.props().token.to_owned()} logged_in={false}>
<div class={classes!("columns")}>
<div class={classes!("column", "is-one-third", "mx-auto")}>
<form onsubmit={ctx.link().callback(|e: FocusEvent| { e.prevent_default(); Msg::Submit })} class={classes!("box")}>
<div class={classes!("field")}>
<p class={classes!("control", "has-icons-left")}>
<input ref={self.username.clone()}
class={classes!("input")}
type="username"
placeholder="Benutzername"
/>
<span class={classes!("icon", "is-small", "is-left")}>
<i class={classes!("fas", "fa-envelope")} />
</span>
</p>
</div>
<div class={classes!("field")}>
<p class={classes!("control", "has-icons-left")}>
<input ref={self.password.clone()}
class={classes!("input")}
type="password"
placeholder="Passwort"
/>
<span class={classes!("icon", "is-small", "is-left")}>
<i class={classes!("fas", "fa-lock")} />
</span>
</p>
</div>
<div class={classes!("field")}>
<p class="control">
<button
class={classes!(
"button",
"is-fullwidth",
"is-success",
if self.fetching { Some("is-loading") } else { None }
)}
type="submit"
>
<span class={classes!("icon", "is-small")}>
<i class={classes!("fas", "fa-right-to-bracket")} />
</span>
<span>{ "Login" }</span>
</button>
</p>
</div>
<components::graphql_errors::GraphQLErrors errors={self.errors.clone()} />
</form>
</div>
</div>
</layouts::main::Main>
</>
}
}
}