From fbd35658ec2127e6bc2f95eb25d8ced558dcf1fd Mon Sep 17 00:00:00 2001 From: Vinod J M Date: Sat, 31 Dec 2022 12:19:16 +0530 Subject: [PATCH] user-auth store frontend v1 --- frontend/src/main.rs | 209 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 175 insertions(+), 34 deletions(-) diff --git a/frontend/src/main.rs b/frontend/src/main.rs index 976bda2..27119ea 100644 --- a/frontend/src/main.rs +++ b/frontend/src/main.rs @@ -12,6 +12,7 @@ use wasm_bindgen::JsCast; use web_sys::{Event, HtmlInputElement, KeyboardEvent}; // 0.3.5 use dotenv_codegen::dotenv; use itertools::Itertools; +use std::collections::HashMap; //use gloo_timers::future::TimeoutFuture; //#[macro_use] //extern crate dotenv_codegen; @@ -50,12 +51,20 @@ struct PaginatedBookUIList { books: Vec, } +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct AxumUser { + pub id: i32, + pub password_hash: String, + pub name: String, +} + #[derive(Debug, Default, Clone)] pub struct AppState { pub books: RcSignal>, pub search: RcSignal, pub openlibrary: RcSignal, pub internalsearch: RcSignal, + pub pagedisplay: RcSignal, pub pagenum: RcSignal, pub maxpage: RcSignal, pub adding: RcSignal, @@ -68,7 +77,12 @@ pub struct AppState { pub updatingrequest: RcSignal, pub addingrequest: RcSignal, pub deleteid: RcSignal, - pub deleterequest: RcSignal + pub deleterequest: RcSignal, + pub userlist: RcSignal>, + pub userid: RcSignal, + pub userscreen: RcSignal, + pub loggedin: RcSignal, + pub editmode: RcSignal, } #[derive(Route)] @@ -81,6 +95,54 @@ enum AppRoutes { NotFound, } +/* TODO + let callback: Closure = Closure::new(move || { + info!("Got scroll event"); + }); + + let window = web_sys::window().expect("Failed to get window"); + window + .add_event_listener_with_callback_and_bool( + "scroll", + callback.as_ref().unchecked_ref(), + false, // Changing this to true does not help :/ + ) + .expect("Failed to set listener"); + callback.forget();*/ + +async fn login_user(user: AxumUser) -> Result { + let backend_url : &'static str = dotenv!("BACKEND_URL"); + let url = format!("{}/api/login", backend_url); + let resp = Request::post(&url).body(serde_wasm_bindgen::to_value(&serde_json::to_string(&user).unwrap()).unwrap()).header("content-type","application/json").send().await?; + Ok(resp) +} + +async fn register_user(user: AxumUser) -> Result { + let backend_url : &'static str = dotenv!("BACKEND_URL"); + let url = format!("{}/api/register", backend_url); + let resp = Request::post(&url).body(serde_wasm_bindgen::to_value(&serde_json::to_string(&user).unwrap()).unwrap()).header("content-type","application/json").send().await?; + Ok(resp) +} + +async fn logout_user() -> Result { + let backend_url : &'static str = dotenv!("BACKEND_URL"); + let url = format!("{}/api/logout", backend_url); + let resp = Request::post(&url).send().await?; + Ok(resp) +} + +async fn list_users() -> Result, reqwasm::Error> { + let backend_url : &'static str = dotenv!("BACKEND_URL"); + let url = format!("{}/api/list_users", backend_url); + let resp = Request::post(&url).send().await?; + let users = resp.json::>().await?; + let mut res = HashMap::new(); + for user in users { + res.insert(user.name, user.id); + } + Ok(res) +} + async fn fetch_books(search: String) -> Result, reqwasm::Error> { //dotenvy::dotenv().ok(); let backend_url : &'static str = dotenv!("BACKEND_URL"); @@ -161,6 +223,7 @@ pub fn Header(cx: Scope) -> View { let value3 = create_signal(cx, String::new()); let input_ref3 = create_node_ref(cx); + let editchecked = create_signal(cx, false); let handle_submit = |event: Event| { let event: KeyboardEvent = event.unchecked_into(); @@ -211,32 +274,6 @@ pub fn Header(cx: Scope) -> View { }; - let click_searchOL = |_| { - - let mut task = value.get().as_ref().clone(); - task = task.trim().to_string(); - - if !task.is_empty() { - app_state.search.set(task); - app_state.openlibrary.set(true); - app_state.internalsearch.set(false); - } - }; - - let click_searchall = |_| { - - let mut task = value2.get().as_ref().clone(); - task = task.trim().to_string(); - - if !task.is_empty() { - app_state.search.set(task); - app_state.openlibrary.set(false); - app_state.internalsearch.set(true); - app_state.refreshing.set(true); - - } - }; - let click_addbook = |_| { app_state.adding.set(true); app_state.updating.set(false); @@ -273,28 +310,66 @@ pub fn Header(cx: Scope) -> View { }); } }; + + let click_logout = |_| { + spawn_local(async move { + logout_user().await.unwrap(); + }); + }; + + let click_userscreen = |_| { + app_state.userscreen.set(true); + }; + + let toggle_editmode = |_| { + app_state.editmode.set(*editchecked.get()); + }; + view! { cx, header(class="header") { + div(class="header-button"){ + (if *app_state.loggedin.get() == false { + view!{ cx, + button(on:click=click_userscreen) { "Register/Login" } + } + } else { + view!{cx, + button(on:click=click_logout) { "Log Out" } + input( + class="toggle", + type="checkbox", + on:input=toggle_editmode, + bind:checked=editchecked + ) + } + }) + } + (if *app_state.loggedin.get() == false { + view!{ cx, div(class="header-column"){ input(ref=input_ref, class="new-todo", - placeholder="Search openlibrary", + placeholder="Search internet (openlibrary)", bind:value=value, on:keyup=handle_submit, ) - button(on:click=click_searchOL) { "Search OpenLibrary" } - } + } } + } else { + view!{cx, } + }) div(class="header-column"){ - button(on:click=click_listall) { "List All DB" } + button(on:click=click_listall) { "All books" } input(ref=input_ref2, class="new-todo", - placeholder="Search internal DB", + placeholder="Search your library", bind:value=value2, on:keyup=handle_submit_seachall, ) - button(on:click=click_searchall) { "Search internal" } } + + (if *app_state.editmode.get() == false { + view!{ cx, div(class="header-column"){ button(on:click=click_addbook) { "+ Add New" } @@ -306,9 +381,13 @@ pub fn Header(cx: Scope) -> View { ) button(on:click=click_addbulk) { "Add bulk ISBNs" } } + } } else { + view!{cx, ""} + }) + div(class="header-page-column"){ PageBar{} - } + } } } } @@ -995,6 +1074,61 @@ async fn PageBar(cx: Scope<'_>) -> View { } +#[component] +async fn LoginScreenUI(cx: Scope<'_>) -> View { + let app_state = use_context::(cx); + let userval = create_signal(cx, String::new()); + let input_refU = create_node_ref(cx); + let passval = create_signal(cx, String::new()); + let input_refP = create_node_ref(cx); + + let handle_register = move |_| { + let user = AxumUser{ + id: 0, + name: (*userval.get()).clone(), + password_hash: (*passval.get()).clone(), + }; + spawn_local(async move { + register_user(user) + .await.expect("Couldn't register user"); + }); + app_state.userscreen.set(false); + }; + + let handle_login = move |_| { + let user = AxumUser{ + id: 0, + name: (*userval.get()).clone(), + password_hash: (*passval.get()).clone(), + }; + spawn_local(async move { + login_user(user) + .await.expect("Couldn't login user"); + }); + app_state.userscreen.set(false); + }; + + view! {cx, + div { + (if *app_state.userscreen.get() == true { + view!{cx, + + input(ref=input_refU,bind:value=userval) + input(ref=input_refP,bind:value=passval) + + button(on:click=handle_login){ "LOGIN" } + button(on:click=handle_register){ "REGISTER" } + + } + }else { + view!{cx,""} + }) + } + + } +} + + #[component] fn App(cx: Scope) -> View { let app_state = AppState { @@ -1002,6 +1136,7 @@ fn App(cx: Scope) -> View { search: create_rc_signal(String::default()), openlibrary: create_rc_signal(bool::default()), internalsearch: create_rc_signal(bool::default()), + pagedisplay: create_rc_signal(1), pagenum: create_rc_signal(1), maxpage: create_rc_signal(1), adding: create_rc_signal(bool::default()), @@ -1015,6 +1150,11 @@ fn App(cx: Scope) -> View { addingrequest: create_rc_signal(bool::default()), deleteid: create_rc_signal(-1), deleterequest: create_rc_signal(bool::default()), + userlist: create_rc_signal(HashMap::new()), + userid: create_rc_signal(0), + userscreen: create_rc_signal(bool::default()), + loggedin: create_rc_signal(bool::default()), + editmode: create_rc_signal(bool::default()), }; provide_context(cx, app_state); view! { @@ -1022,6 +1162,7 @@ fn App(cx: Scope) -> View { div { Header {} div(class="main"){ + LoginScreenUI{} AddingUI{} SelectedUI{} ListOL {}