use bounce::helmet::Helmet; use cynic::QueryBuilder; use std::rc::Rc; use web_sys::HtmlInputElement; use yew::prelude::*; use yew_router::prelude::*; use yewdux::prelude::*; use crate::{ components, graphql::{self, ReqwestExt}, routes, stores, }; pub enum Msg { UpdateUser(Rc), UpdateNotifications(Rc), Login, LoginDone { user_data: stores::UserData, result: graphql::GraphQLResult, }, } pub struct Login { user: Rc, user_dispatch: Dispatch, notifications: Rc, notifications_dispatch: Dispatch, username: NodeRef, password: NodeRef, loading: bool, error: Option<&'static str>, } impl Component for Login { type Message = Msg; type Properties = (); fn create(ctx: &Context) -> Self { let user_dispatch = Dispatch::subscribe(ctx.link().callback(Msg::UpdateUser)); let notifications_dispatch = Dispatch::subscribe(ctx.link().callback(Msg::UpdateNotifications)); Self { user: user_dispatch.get(), user_dispatch, notifications: notifications_dispatch.get(), notifications_dispatch, username: NodeRef::default(), password: NodeRef::default(), loading: false, error: None, } } fn update(&mut self, ctx: &Context, msg: Self::Message) -> bool { match msg { Msg::UpdateUser(x) => { self.error = None; let prev = self.user.logged_in(); self.user = x; prev != self.user.logged_in() } Msg::UpdateNotifications(x) => { self.notifications = x; false } Msg::Login => { self.error = None; let username = match self.username.cast::().map(|x| x.value()) { Some(x) => { if x.is_empty() { return false; } else { x } } None => { return false; } }; let password = match self.password.cast::().map(|x| x.value()) { Some(x) => { if x.is_empty() { return false; } else { x } } None => { return false; } }; self.loading = true; let operation = graphql::queries::VerifyLogin::build(graphql::queries::VerifyLoginVariables { username: username.to_owned(), password: password.to_owned(), }); ctx.link().send_future(async move { Msg::LoginDone { user_data: stores::UserData { username, password }, result: graphql::client(None).run_graphql(operation).await, } }); true } Msg::LoginDone { user_data, result } => { self.loading = false; match result { Ok(resp) => { if let Some(errors) = resp.errors { self.notifications_dispatch.reduce_mut(|notifs| { for e in errors { notifs.push(stores::Notification::danger(Some( components::notification::NotificationMessage::GraphQLError( e, ), ))); } }); true } else if resp.data.unwrap().verify_login { self.error = None; self.user_dispatch.set(stores::User(Some(user_data))); false } else { const MESSAGE: &str = "Username or password not correct"; self.error = Some(MESSAGE); self.notifications_dispatch.reduce_mut(|notifs| { notifs.push(stores::Notification { notification_type: components::notification::NotificationType::Danger, message: Some( components::notification::NotificationMessage::Text(vec![ MESSAGE.to_string(), ]), ), }); }); true } } Err(e) => { self.notifications_dispatch.reduce_mut(|notifs| { notifs.push(stores::Notification { notification_type: components::notification::NotificationType::Danger, message: Some(components::notification::NotificationMessage::Text( vec![e.to_string()], )), }); }); false } } } } } fn view(&self, ctx: &Context) -> Html { if self.user.logged_in() { ctx.link().navigator().unwrap().push(&routes::Route::Index); } html! { <> { "Login" }

if let Some(message) = self.error {

{ message }

}
} } }