user-auth store frontend v1

This commit is contained in:
2022-12-31 12:19:16 +05:30
parent 0aa37288ee
commit fbd35658ec

View File

@@ -12,6 +12,7 @@ use wasm_bindgen::JsCast;
use web_sys::{Event, HtmlInputElement, KeyboardEvent}; // 0.3.5 use web_sys::{Event, HtmlInputElement, KeyboardEvent}; // 0.3.5
use dotenv_codegen::dotenv; use dotenv_codegen::dotenv;
use itertools::Itertools; use itertools::Itertools;
use std::collections::HashMap;
//use gloo_timers::future::TimeoutFuture; //use gloo_timers::future::TimeoutFuture;
//#[macro_use] //#[macro_use]
//extern crate dotenv_codegen; //extern crate dotenv_codegen;
@@ -50,12 +51,20 @@ struct PaginatedBookUIList {
books: Vec<BookUI>, books: Vec<BookUI>,
} }
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AxumUser {
pub id: i32,
pub password_hash: String,
pub name: String,
}
#[derive(Debug, Default, Clone)] #[derive(Debug, Default, Clone)]
pub struct AppState { pub struct AppState {
pub books: RcSignal<Vec<BookUI>>, pub books: RcSignal<Vec<BookUI>>,
pub search: RcSignal<String>, pub search: RcSignal<String>,
pub openlibrary: RcSignal<bool>, pub openlibrary: RcSignal<bool>,
pub internalsearch: RcSignal<bool>, pub internalsearch: RcSignal<bool>,
pub pagedisplay: RcSignal<u32>,
pub pagenum: RcSignal<u32>, pub pagenum: RcSignal<u32>,
pub maxpage: RcSignal<u32>, pub maxpage: RcSignal<u32>,
pub adding: RcSignal<bool>, pub adding: RcSignal<bool>,
@@ -68,7 +77,12 @@ pub struct AppState {
pub updatingrequest: RcSignal<bool>, pub updatingrequest: RcSignal<bool>,
pub addingrequest: RcSignal<bool>, pub addingrequest: RcSignal<bool>,
pub deleteid: RcSignal<i32>, pub deleteid: RcSignal<i32>,
pub deleterequest: RcSignal<bool> pub deleterequest: RcSignal<bool>,
pub userlist: RcSignal<HashMap<String, i32>>,
pub userid: RcSignal<i32>,
pub userscreen: RcSignal<bool>,
pub loggedin: RcSignal<bool>,
pub editmode: RcSignal<bool>,
} }
#[derive(Route)] #[derive(Route)]
@@ -81,6 +95,54 @@ enum AppRoutes {
NotFound, NotFound,
} }
/* TODO
let callback: Closure<dyn FnMut()> = 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<reqwasm::http::Response, reqwasm::Error> {
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<reqwasm::http::Response, reqwasm::Error> {
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<reqwasm::http::Response, reqwasm::Error> {
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<HashMap<String,i32>, 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::<Vec<AxumUser>>().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<Vec<BookUI>, reqwasm::Error> { async fn fetch_books(search: String) -> Result<Vec<BookUI>, reqwasm::Error> {
//dotenvy::dotenv().ok(); //dotenvy::dotenv().ok();
let backend_url : &'static str = dotenv!("BACKEND_URL"); let backend_url : &'static str = dotenv!("BACKEND_URL");
@@ -161,6 +223,7 @@ pub fn Header<G: Html>(cx: Scope) -> View<G> {
let value3 = create_signal(cx, String::new()); let value3 = create_signal(cx, String::new());
let input_ref3 = create_node_ref(cx); let input_ref3 = create_node_ref(cx);
let editchecked = create_signal(cx, false);
let handle_submit = |event: Event| { let handle_submit = |event: Event| {
let event: KeyboardEvent = event.unchecked_into(); let event: KeyboardEvent = event.unchecked_into();
@@ -211,32 +274,6 @@ pub fn Header<G: Html>(cx: Scope) -> View<G> {
}; };
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 = |_| { let click_addbook = |_| {
app_state.adding.set(true); app_state.adding.set(true);
app_state.updating.set(false); app_state.updating.set(false);
@@ -273,28 +310,66 @@ pub fn Header<G: Html>(cx: Scope) -> View<G> {
}); });
} }
}; };
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, view! { cx,
header(class="header") { 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"){ div(class="header-column"){
input(ref=input_ref, input(ref=input_ref,
class="new-todo", class="new-todo",
placeholder="Search openlibrary", placeholder="Search internet (openlibrary)",
bind:value=value, bind:value=value,
on:keyup=handle_submit, on:keyup=handle_submit,
) )
button(on:click=click_searchOL) { "Search OpenLibrary" } } }
} } else {
view!{cx, }
})
div(class="header-column"){ div(class="header-column"){
button(on:click=click_listall) { "List All DB" } button(on:click=click_listall) { "All books" }
input(ref=input_ref2, input(ref=input_ref2,
class="new-todo", class="new-todo",
placeholder="Search internal DB", placeholder="Search your library",
bind:value=value2, bind:value=value2,
on:keyup=handle_submit_seachall, on:keyup=handle_submit_seachall,
) )
button(on:click=click_searchall) { "Search internal" }
} }
(if *app_state.editmode.get() == false {
view!{ cx,
div(class="header-column"){ div(class="header-column"){
button(on:click=click_addbook) { "+ Add New" } button(on:click=click_addbook) { "+ Add New" }
@@ -306,9 +381,13 @@ pub fn Header<G: Html>(cx: Scope) -> View<G> {
) )
button(on:click=click_addbulk) { "Add bulk ISBNs" } button(on:click=click_addbulk) { "Add bulk ISBNs" }
} }
} } else {
view!{cx, ""}
})
div(class="header-page-column"){ div(class="header-page-column"){
PageBar{} PageBar{}
} }
} }
} }
} }
@@ -995,6 +1074,61 @@ async fn PageBar<G: Html>(cx: Scope<'_>) -> View<G> {
} }
#[component]
async fn LoginScreenUI<G: Html>(cx: Scope<'_>) -> View<G> {
let app_state = use_context::<AppState>(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] #[component]
fn App<G: Html>(cx: Scope) -> View<G> { fn App<G: Html>(cx: Scope) -> View<G> {
let app_state = AppState { let app_state = AppState {
@@ -1002,6 +1136,7 @@ fn App<G: Html>(cx: Scope) -> View<G> {
search: create_rc_signal(String::default()), search: create_rc_signal(String::default()),
openlibrary: create_rc_signal(bool::default()), openlibrary: create_rc_signal(bool::default()),
internalsearch: create_rc_signal(bool::default()), internalsearch: create_rc_signal(bool::default()),
pagedisplay: create_rc_signal(1),
pagenum: create_rc_signal(1), pagenum: create_rc_signal(1),
maxpage: create_rc_signal(1), maxpage: create_rc_signal(1),
adding: create_rc_signal(bool::default()), adding: create_rc_signal(bool::default()),
@@ -1015,6 +1150,11 @@ fn App<G: Html>(cx: Scope) -> View<G> {
addingrequest: create_rc_signal(bool::default()), addingrequest: create_rc_signal(bool::default()),
deleteid: create_rc_signal(-1), deleteid: create_rc_signal(-1),
deleterequest: create_rc_signal(bool::default()), 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); provide_context(cx, app_state);
view! { view! {
@@ -1022,6 +1162,7 @@ fn App<G: Html>(cx: Scope) -> View<G> {
div { div {
Header {} Header {}
div(class="main"){ div(class="main"){
LoginScreenUI{}
AddingUI{} AddingUI{}
SelectedUI{} SelectedUI{}
ListOL {} ListOL {}