diff --git a/backend/api/src/lib.rs b/backend/api/src/lib.rs index ddd78df..a94bf80 100644 --- a/backend/api/src/lib.rs +++ b/backend/api/src/lib.rs @@ -254,6 +254,7 @@ pub async fn main() { .route("/api/create", post(create_book)) .route("/api/update", post(update_book)) .route("/api/delete/:id", get(delete_book)) + .route("/api/authentication_check", get(authentication_check)) .route_layer(RequireAuthorizationLayer::::login()) .route("/api/list", get(list_book)) .route("/api/list_search", get(list_search_book)) @@ -346,6 +347,12 @@ async fn list_users( auth.logout().await; } +//https://openlibrary.org/api/books?bibkeys=ISBN:9780980200447&jscmd=data&format=json +async fn authentication_check( + Extension(user): Extension, +) -> impl IntoResponse { + return true; +} //https://openlibrary.org/api/books?bibkeys=ISBN:9780980200447&jscmd=data&format=json diff --git a/frontend/css/index.css b/frontend/css/index.css index 7b93eaa..f5117f9 100644 --- a/frontend/css/index.css +++ b/frontend/css/index.css @@ -37,6 +37,15 @@ body { background-color: #f1f1f1; /* Fallback color */ } +/* Dropdown Content (Hidden by Default) */ +.dropdown-content { + position: absolute; + background-color: #f1f1f1; + min-width: 160px; + box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2); + z-index: 1; +} + /* Float three header columns side by side */ .header { position: fixed; /* Stay in place */ diff --git a/frontend/src/main.rs b/frontend/src/main.rs index 3a70508..d3439a0 100644 --- a/frontend/src/main.rs +++ b/frontend/src/main.rs @@ -13,6 +13,7 @@ use web_sys::{Event, HtmlInputElement, KeyboardEvent}; // 0.3.5 use dotenv_codegen::dotenv; use itertools::Itertools; use std::collections::HashMap; +use wasm_bindgen::closure::Closure; //use gloo_timers::future::TimeoutFuture; //#[macro_use] //extern crate dotenv_codegen; @@ -90,23 +91,9 @@ pub struct AppState { pub loggedin: RcSignal, pub editmode: RcSignal, pub dropdownselect: RcSignal, + pub scrolling: RcSignal, } -/* 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); @@ -140,6 +127,19 @@ async fn list_users() -> Result, reqwasm::Error> { Ok(res) } + +async fn authentication_check() -> Result { + let backend_url : &'static str = dotenv!("BACKEND_URL"); + let url = format!("{}/api/authentication_check", backend_url); + let resp = Request::get(&url).send().await?; + if resp.status() == 200 { + Ok(true) + } else { + Ok(false) + } +} + + async fn fetch_books(search: String) -> Result, reqwasm::Error> { //dotenvy::dotenv().ok(); let backend_url : &'static str = dotenv!("BACKEND_URL"); @@ -432,6 +432,20 @@ pub fn DropDownUser(cx: Scope, value: StringProp) -> View { #[component] async fn ListDB(cx: Scope<'_>) -> View { let app_state = use_context::(cx); + let callback_signal = use_context::>(cx); + let csignal = callback_signal.clone(); + //callback_signal.clone().set(false); + create_effect(cx, || { + let app_state = app_state.clone(); + let cxsignal = callback_signal.clone(); + if *cxsignal.get() == true { + cxsignal.set(false); + if *app_state.pagedisplay.get() < *app_state.maxpage.get()-1 { + app_state.pagedisplay.set(*app_state.pagedisplay.get()+1); + app_state.scrolling.set(true); + } + } + }); create_effect(cx, || { let app_state = app_state.clone(); @@ -440,6 +454,8 @@ async fn ListDB(cx: Scope<'_>) -> View { app_state.openlibrary.track(); app_state.internalsearch.track(); app_state.refreshing.track(); + //let csignal = csignals2.clone(); + //let tempb = app_state.books.get(); //spawn_local( async move { info!( // "The state changed. Old value: {:?}", @@ -481,6 +497,40 @@ async fn ListDB(cx: Scope<'_>) -> View { }); } } + else if *app_state.scrolling.get()==true { + app_state.scrolling.set(false); + if *app_state.internalsearch.get() == false { + info!("DB triggered"); + spawn_local(async move { + let res = list_books(*app_state.pagedisplay.get(), *app_state.userid.get(), "desc".to_string()) + .await.unwrap(); + let mut currbooks = (*app_state.clone().books.get()).clone(); + currbooks.extend(res.books.iter().cloned()); + app_state.books.set( + currbooks + ); + app_state.maxpage.set( + res.num_pages + ) + }); + } else { + info!("IntSearch triggered"); + + spawn_local(async move { + let res = search_books(app_state.search.get().to_string(), *app_state.pagedisplay.get(), *app_state.userid.get()) + .await.unwrap(); + let mut currbooks = (*app_state.clone().books.get()).clone(); + currbooks.extend(res.books.iter().cloned()); + app_state.books.set( + currbooks + ); + app_state.maxpage.set( + res.num_pages + ) + }); + } + + } } else { if *app_state.refreshing.get() == false { @@ -501,6 +551,22 @@ async fn ListDB(cx: Scope<'_>) -> View { }); + let callback: Closure = Closure::new(move || { + //let csignal = callback_signal.clone(); + csignal.set(true); + 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(); + let docs = create_memo(cx, || app_state.books.get().iter().cloned().collect::>()); view! {cx, p { @@ -1118,14 +1184,17 @@ async fn PageBar(cx: Scope<'_>) -> View { let input_ref = create_node_ref(cx); let handle_add = move |_| { - app_state.pagenum.set(*app_state.pagenum.get()+1); - app_state.refreshing.set(true); - + if *app_state.pagenum.get() < *app_state.maxpage.get()-1 { + app_state.pagenum.set(*app_state.pagenum.get()+1); + app_state.pagedisplay.set(*app_state.pagenum.get()+1); + app_state.refreshing.set(true); + } }; let handle_sub = move |_| { if *app_state.pagenum.get()>1 { app_state.pagenum.set(*app_state.pagenum.get()-1); + app_state.pagedisplay.set(*app_state.pagenum.get()-1); app_state.refreshing.set(true); } }; @@ -1137,6 +1206,7 @@ async fn PageBar(cx: Scope<'_>) -> View { let pg = currpg.get().as_ref().clone().parse::().unwrap_or(1); if pg>0 && pg<*app_state.maxpage.get() { app_state.pagenum.set(pg); + app_state.pagedisplay.set(pg); app_state.refreshing.set(true); } else { currpg.set((*app_state.pagenum.get()).to_string()); @@ -1178,6 +1248,7 @@ async fn LoginScreenUI(cx: Scope<'_>) -> View { let input_refU = create_node_ref(cx); let passval = create_signal(cx, String::new()); let input_refP = create_node_ref(cx); + let node_ref = create_node_ref(cx); let handle_register = move |_| { let app_state = app_state.clone(); @@ -1198,6 +1269,8 @@ async fn LoginScreenUI(cx: Scope<'_>) -> View { }; let handle_login = move |_| { + let app_state = app_state.clone(); + let userstr = (*userval.get()).clone(); let user = AxumUser{ id: 0, name: (*userval.get()).clone(), @@ -1207,30 +1280,59 @@ async fn LoginScreenUI(cx: Scope<'_>) -> View { login_user(user) .await.expect("Couldn't login user"); }); - app_state.loggedin.set(true); - app_state.useridloggedin.set( *(*app_state.userlist.get()).get(&(*userval.get()).clone()).unwrap_or(&0)); - app_state.userid.set( *(*app_state.userlist.get()).get(&(*userval.get()).clone()).unwrap_or(&0)); - app_state.userscreen.set(false); + spawn_local(async move { + let auth = authentication_check().await.unwrap_or(false); + app_state.loggedin.set(auth); + if auth == true { + app_state.useridloggedin.set( *(*app_state.userlist.get()).get(&userstr).unwrap_or(&0)); + app_state.userid.set( *(*app_state.userlist.get()).get(&userstr).unwrap_or(&0)); + app_state.userscreen.set(false); + } + }); + }; + + create_effect(cx, || { + if *app_state.userscreen.get() == true { + let dom_node = node_ref.try_get::(); + if dom_node.is_some() { + dom_node.unwrap().set_attribute("popup-display","true"); + } + } else { + let dom_node = node_ref.try_get::(); + if dom_node.is_some() { + dom_node.unwrap().set_attribute("popup-display","false"); + } + } + }); + let handle_close = move |_| { + app_state.displaying.set(false); + + let dom_node = node_ref.try_get::(); + if dom_node.is_some() { + dom_node.unwrap().set_attribute("popup-display","false"); + } }; view! {cx, - div { + div(class="modal-box", ref=node_ref){ + (if *app_state.userscreen.get() == true { view!{cx, - + div(class="modal-content"){ 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" } - + button(class="close", on:click=handle_close){ "CLOSE" } + } } }else { view!{cx,""} }) } - } + } } @@ -1262,6 +1364,7 @@ fn App(cx: Scope) -> View { loggedin: create_rc_signal(bool::default()), editmode: create_rc_signal(bool::default()), dropdownselect: create_rc_signal(bool::default()), + scrolling: create_rc_signal(bool::default()), }; provide_context(cx, app_state);