1291 lines
45 KiB
Rust
1291 lines
45 KiB
Rust
use log::info;
|
|
//use std::env;
|
|
//use log::Level;
|
|
use reqwasm::http::Request;
|
|
use serde::{Deserialize, Serialize};
|
|
use serde_json;
|
|
use sycamore::futures::spawn_local;
|
|
use sycamore::prelude::*;
|
|
//use sycamore::suspense::Suspense;
|
|
//use sycamore_router::Route;
|
|
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;
|
|
|
|
#[derive(Deserialize, Serialize, Debug, Default, Clone, PartialEq, Hash, Eq)]
|
|
pub struct BookUI {
|
|
id: i32,
|
|
open_library_key: Option<String>,
|
|
title: String,
|
|
edition_count: Option<i32>,
|
|
first_publish_year: Option<i32>,
|
|
median_page_count: Option<i32>,
|
|
goodread_id: Option<String>,
|
|
description: Option<String>,
|
|
cover: Option<String>,
|
|
location: Option<String>,
|
|
time_added: Option<String>,
|
|
rating: Option<i32>,
|
|
comments: Option<String>,
|
|
author_name: Option<Vec<String>>,
|
|
person: Option<Vec<String>>,
|
|
place: Option<Vec<String>>,
|
|
subject: Option<Vec<String>>,
|
|
time: Option<Vec<String>>,
|
|
isbn: Option<Vec<String>>,
|
|
}
|
|
|
|
#[derive(Prop, Debug)]
|
|
pub struct BookUIProp {
|
|
bookitem: BookUI,
|
|
}
|
|
|
|
#[derive(Prop, Debug, Clone, PartialEq, Hash, Eq)]
|
|
pub struct StringProp {
|
|
value: String,
|
|
}
|
|
|
|
#[derive(Deserialize, Serialize, Debug, Clone)]
|
|
struct PaginatedBookUIList {
|
|
num_pages: u32,
|
|
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)]
|
|
pub struct AppState {
|
|
pub books: RcSignal<Vec<BookUI>>,
|
|
pub search: RcSignal<String>,
|
|
pub openlibrary: RcSignal<bool>,
|
|
pub internalsearch: RcSignal<bool>,
|
|
pub pagedisplay: RcSignal<u32>,
|
|
pub pagenum: RcSignal<u32>,
|
|
pub maxpage: RcSignal<u32>,
|
|
pub adding: RcSignal<bool>,
|
|
pub updating: RcSignal<bool>,
|
|
pub displaying: RcSignal<bool>,
|
|
pub addingbook: RcSignal<BookUI>,
|
|
pub displayingbook: RcSignal<BookUI>,
|
|
pub refreshing: RcSignal<bool>,
|
|
pub apibook: RcSignal<BookUI>,
|
|
pub updatingrequest: RcSignal<bool>,
|
|
pub addingrequest: RcSignal<bool>,
|
|
pub deleteid: RcSignal<i32>,
|
|
pub deleterequest: RcSignal<bool>,
|
|
pub userlist: RcSignal<HashMap<String, i32>>,
|
|
pub userid: RcSignal<i32>,
|
|
pub useridloggedin: RcSignal<i32>,
|
|
pub userscreen: RcSignal<bool>,
|
|
pub loggedin: RcSignal<bool>,
|
|
pub editmode: RcSignal<bool>,
|
|
pub dropdownselect: RcSignal<bool>,
|
|
}
|
|
|
|
/* 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> {
|
|
//dotenvy::dotenv().ok();
|
|
let backend_url : &'static str = dotenv!("BACKEND_URL");
|
|
//env::var("BACKEND_URL").expect("BACKEND_URL is not set in .env file");
|
|
let url = format!("{}/api/search_openlibrary?search={}", backend_url, search);
|
|
let resp = Request::get(&url).send().await?;
|
|
println!("Fetching books\n");
|
|
let body = resp.json::<Vec<BookUI>>().await?;
|
|
Ok(body)
|
|
}
|
|
|
|
async fn search_books(search: String, page: u32, userid:i32) -> Result<PaginatedBookUIList, reqwasm::Error> {
|
|
let backend_url : &'static str = dotenv!("BACKEND_URL");
|
|
//"http://localhost:8081";
|
|
//env::var("BACKEND_URL").expect("BACKEND_URL is not set in .env file");
|
|
let url = format!("{}/api/list_search?search={}&page={}&userid={}",backend_url, search, page, userid);
|
|
let resp = Request::get(&url).send().await?;
|
|
println!("Fetching books\n");
|
|
let body = resp.json::<PaginatedBookUIList>().await?;
|
|
Ok(body)
|
|
}
|
|
|
|
async fn add_book(record: BookUI) -> Result<reqwasm::http::Response, reqwasm::Error> {
|
|
let backend_url : &'static str = dotenv!("BACKEND_URL");
|
|
//env::var("BACKEND_URL").expect("BACKEND_URL is not set in .env file");
|
|
let url = format!("{}/api/create", backend_url);
|
|
let resp = Request::post(&url).body(serde_wasm_bindgen::to_value(&serde_json::to_string(&record).unwrap()).unwrap()).header("content-type","application/json").send().await?;
|
|
Ok(resp)
|
|
}
|
|
|
|
async fn add_books_isbns(isbns: String) -> Result<reqwasm::http::Response, reqwasm::Error> {
|
|
let backend_url : &'static str = dotenv!("BACKEND_URL");
|
|
//env::var("BACKEND_URL").expect("BACKEND_URL is not set in .env file");
|
|
let url = format!("{}/api/create_by_isbn?isbns={}", backend_url, isbns);
|
|
let resp = Request::get(&url).send().await?;
|
|
println!("Adding multiple books\n");
|
|
Ok(resp)
|
|
}
|
|
|
|
|
|
async fn update_book(record: BookUI) -> Result<reqwasm::http::Response, reqwasm::Error> {
|
|
let backend_url : &'static str = dotenv!("BACKEND_URL");
|
|
//env::var("BACKEND_URL").expect("BACKEND_URL is not set in .env file");
|
|
let url = format!("{}/api/update", backend_url);
|
|
let resp = Request::post(&url).body(serde_wasm_bindgen::to_value(&serde_json::to_string(&record).unwrap()).unwrap()).header("content-type","application/json").send().await?;
|
|
Ok(resp)
|
|
}
|
|
|
|
async fn delete_book(id: i32) -> Result<reqwasm::http::Response, reqwasm::Error> {
|
|
let backend_url : &'static str = dotenv!("BACKEND_URL");
|
|
//env::var("BACKEND_URL").expect("BACKEND_URL is not set in .env file");
|
|
let url = format!("{}/api/delete/{}", backend_url, id);
|
|
let resp = Request::get(&url).send().await?;
|
|
Ok(resp)
|
|
}
|
|
|
|
async fn list_books(page: u32, userid: i32, sort: String) -> Result<PaginatedBookUIList, reqwasm::Error> {
|
|
let backend_url : &'static str = dotenv!("BACKEND_URL");
|
|
//env::var("BACKEND_URL").expect("BACKEND_URL is not set in .env file");
|
|
let url = format!("{}/api/list?page={}&userid={}&sort={}", backend_url, page, userid, sort);
|
|
let resp = Request::get(&url).send().await?;
|
|
println!("Fetching books\n");
|
|
info!("BACKEND{}",backend_url);
|
|
|
|
let body = resp.json::<PaginatedBookUIList>().await?;
|
|
Ok(body)
|
|
}
|
|
|
|
#[component]
|
|
pub fn Header<G: Html>(cx: Scope) -> View<G> {
|
|
let app_state = use_context::<AppState>(cx);
|
|
let value = create_signal(cx, String::new());
|
|
let input_ref = create_node_ref(cx);
|
|
|
|
let value2 = create_signal(cx, String::new());
|
|
let input_ref2 = create_node_ref(cx);
|
|
|
|
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();
|
|
|
|
if event.key() == "Enter" {
|
|
let mut task = value.get().as_ref().clone();
|
|
task = task.trim().to_string();
|
|
|
|
if !task.is_empty() {
|
|
app_state.search.set(task.clone());
|
|
app_state.openlibrary.set(true);
|
|
app_state.internalsearch.set(false);
|
|
|
|
info!("Fetching search {}\n", task.clone());
|
|
app_state.books.set(Vec::new());
|
|
value.set("".to_string());
|
|
input_ref
|
|
.get::<DomNode>()
|
|
.unchecked_into::<HtmlInputElement>()
|
|
.set_value("");
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
let handle_submit_seachall = |event: Event| {
|
|
let event: KeyboardEvent = event.unchecked_into();
|
|
|
|
if event.key() == "Enter" {
|
|
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);
|
|
info!("Fetching search 2\n");
|
|
}
|
|
}
|
|
};
|
|
|
|
let click_listall = |_| {
|
|
app_state.openlibrary.set(false);
|
|
app_state.internalsearch.set(false);
|
|
app_state.refreshing.set(true);
|
|
|
|
};
|
|
|
|
|
|
let click_addbook = |_| {
|
|
app_state.adding.set(true);
|
|
app_state.updating.set(false);
|
|
app_state.addingbook.set(BookUI::default());
|
|
};
|
|
|
|
|
|
let handle_submit_addbulk = |event: Event| {
|
|
let event: KeyboardEvent = event.unchecked_into();
|
|
|
|
if event.key() == "Enter" {
|
|
let mut task = value3.get().as_ref().clone();
|
|
task = task.trim().to_string();
|
|
|
|
if !task.is_empty() {
|
|
|
|
spawn_local(async move {
|
|
let _temp = add_books_isbns(task).await.unwrap();
|
|
});
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
let click_logout = |_| {
|
|
spawn_local(async move {
|
|
logout_user().await.unwrap();
|
|
});
|
|
app_state.loggedin.set(false);
|
|
app_state.editmode.set(false);
|
|
|
|
};
|
|
|
|
let click_userscreen = |_| {
|
|
app_state.userscreen.set(true);
|
|
};
|
|
|
|
let toggle_editmode = |_| {
|
|
app_state.editmode.set(*editchecked.get());
|
|
app_state.userid.set(*app_state.useridloggedin.get());
|
|
};
|
|
|
|
let dropdown_userselect = |_| {
|
|
let app_state = app_state.clone();
|
|
spawn_local(async move {
|
|
app_state.userlist.set(list_users()
|
|
.await.expect("Couldn't list user"));
|
|
});
|
|
app_state.dropdownselect.set(true);
|
|
};
|
|
|
|
// let users = create_memo(cx, || app_state.userlist.get().keys().cloned().map(|x| StringProp{value: x}).collect::<Vec<StringProp>>());
|
|
let users = create_memo(cx, || app_state.userlist.get().keys().cloned().collect::<Vec<String>>());
|
|
|
|
|
|
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.editmode.get() == true {
|
|
view!{ cx,
|
|
div(class="header-column"){
|
|
input(ref=input_ref,
|
|
class="new-todo",
|
|
placeholder="Search internet (openlibrary)",
|
|
bind:value=value,
|
|
on:keyup=handle_submit,
|
|
)
|
|
} }
|
|
} else {
|
|
view!{cx, }
|
|
})
|
|
|
|
div(class="header-column"){
|
|
(if *app_state.editmode.get() == false {
|
|
view!{ cx,
|
|
button(on:click=dropdown_userselect) { "Select User" }
|
|
(if *app_state.dropdownselect.get() == true {
|
|
view!{ cx,
|
|
div(class="dropdown-content") {
|
|
Keyed(
|
|
iterable=users,
|
|
view=move |cx, x| view! { cx,
|
|
DropDownUser(value=x)
|
|
},
|
|
key =|x| x.clone() )
|
|
}
|
|
}
|
|
} else {
|
|
view!{cx, ""}
|
|
})
|
|
}} else {
|
|
view!{cx, ""}
|
|
})
|
|
|
|
button(on:click=click_listall) { "All books" }
|
|
input(ref=input_ref2,
|
|
class="new-todo",
|
|
placeholder="Search your library",
|
|
bind:value=value2,
|
|
on:keyup=handle_submit_seachall,
|
|
)
|
|
}
|
|
|
|
(if *app_state.editmode.get() == true {
|
|
view!{ cx,
|
|
div(class="header-column"){
|
|
|
|
button(on:click=click_addbook) { "+ Add New" }
|
|
input(ref=input_ref3,
|
|
class="new-todo",
|
|
placeholder="Add bulk ISBNs",
|
|
bind:value=value3,
|
|
on:keyup=handle_submit_addbulk,
|
|
)
|
|
}
|
|
} } else {
|
|
view!{cx, ""}
|
|
})
|
|
|
|
div(class="header-page-column"){
|
|
PageBar{}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#[component(inline_props)]
|
|
pub fn DropDownUser<G: Html>(cx: Scope, value: StringProp) -> View<G> {
|
|
let app_state = use_context::<AppState>(cx);
|
|
let buttontext = value.clone().value.clone();
|
|
let valueclosure = value.clone();
|
|
|
|
let handle_select_user = move |_| {
|
|
app_state.userid.set( *(*app_state.userlist.get()).get(&(valueclosure.value).clone()).unwrap_or(&0));
|
|
app_state.dropdownselect.set(false);
|
|
};
|
|
|
|
view! { cx,
|
|
button(class="delete", on:click=handle_select_user){ (buttontext) }
|
|
}
|
|
}
|
|
|
|
#[component]
|
|
async fn ListDB<G: Html>(cx: Scope<'_>) -> View<G> {
|
|
let app_state = use_context::<AppState>(cx);
|
|
|
|
create_effect(cx, || {
|
|
let app_state = app_state.clone();
|
|
app_state.search.track();
|
|
app_state.pagenum.track();
|
|
app_state.openlibrary.track();
|
|
app_state.internalsearch.track();
|
|
app_state.refreshing.track();
|
|
//let tempb = app_state.books.get();
|
|
//spawn_local( async move { info!(
|
|
// "The state changed. Old value: {:?}",
|
|
// app_state.books.get()
|
|
//)});
|
|
|
|
if *app_state.openlibrary.get() == false {
|
|
if *app_state.refreshing.get() == true {
|
|
app_state.refreshing.set(false);
|
|
app_state.books.set(Vec::new());
|
|
//TimeoutFuture::new(1000).await;
|
|
//info!("Refresh triggered");
|
|
|
|
if *app_state.internalsearch.get() == false {
|
|
info!("DB triggered");
|
|
spawn_local(async move {
|
|
|
|
let res = list_books(*app_state.pagenum.get(), *app_state.userid.get(), "desc".to_string())
|
|
.await.unwrap();
|
|
app_state.books.set(
|
|
res.books
|
|
);
|
|
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.pagenum.get(), *app_state.userid.get())
|
|
.await.unwrap();
|
|
app_state.books.set(
|
|
res.books
|
|
);
|
|
app_state.maxpage.set(
|
|
res.num_pages
|
|
)
|
|
});
|
|
}
|
|
}
|
|
|
|
} else {
|
|
if *app_state.refreshing.get() == false {
|
|
spawn_local(async move {
|
|
if *app_state.search.get() != "" {
|
|
if *app_state.openlibrary.get() == true {
|
|
app_state.books.set(
|
|
fetch_books(app_state.search.get().to_string() )
|
|
.await
|
|
.unwrap(),
|
|
)
|
|
}
|
|
}
|
|
});
|
|
}
|
|
}
|
|
info!("List Refreshing Done");
|
|
|
|
});
|
|
|
|
let docs = create_memo(cx, || app_state.books.get().iter().cloned().collect::<Vec<_>>());
|
|
view! {cx,
|
|
p {
|
|
(if *app_state.openlibrary.get() == false && *app_state.editmode.get() == false {
|
|
view!{ cx,
|
|
ul {
|
|
Keyed(
|
|
iterable=docs,
|
|
view=|cx, x| view! { cx,
|
|
BookDB_View(bookitem=x)
|
|
},
|
|
key =|x| x.id )
|
|
}
|
|
}
|
|
} else if *app_state.openlibrary.get() == false && *app_state.editmode.get() == true {
|
|
view!{ cx,
|
|
ul {
|
|
Keyed(
|
|
iterable=docs,
|
|
view=|cx, x| view! { cx,
|
|
BookDB(bookitem=x)
|
|
},
|
|
key =|x| x.id )
|
|
}
|
|
}
|
|
} else {
|
|
view!{cx, ""}
|
|
}
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
#[component(inline_props)]
|
|
pub fn BookDB<G: Html>(cx: Scope, bookitem: BookUIProp) -> View<G> {
|
|
let app_state = use_context::<AppState>(cx);
|
|
let bookdelete = bookitem.bookitem.clone();
|
|
let bookupdate = bookitem.bookitem.clone();
|
|
let bookdisplay = bookitem.bookitem.clone();
|
|
let loctitle = bookitem.bookitem.clone().title.clone();
|
|
let locauthors = bookitem.bookitem.clone().author_name.clone().unwrap_or(vec!["".to_string()]).join(", ");
|
|
let locdesc = bookitem.bookitem.clone().description.unwrap_or("".to_string());
|
|
let locloc = bookitem.bookitem.clone().location.unwrap_or("".to_string());
|
|
|
|
//let locref = create_rc_signal(false);
|
|
|
|
let coverurl = bookdisplay.clone().cover.clone().unwrap_or("None".to_string());
|
|
let handle_delete = move |_| {
|
|
app_state.deleteid.set(bookdelete.id);
|
|
app_state.deleterequest.set(true);
|
|
|
|
};
|
|
|
|
create_effect(cx, || {
|
|
let app_state = app_state.clone();
|
|
if *app_state.deleterequest.get() == true {
|
|
spawn_local(async move {
|
|
let temp = delete_book(*app_state.deleteid.get()).await.unwrap();
|
|
println!("{}",temp.status());
|
|
app_state.refreshing.set(true);
|
|
});
|
|
}
|
|
|
|
app_state.deleterequest.set(false);
|
|
|
|
});
|
|
|
|
let handle_update = move |_| {
|
|
app_state.adding.set(false);
|
|
app_state.updating.set(true);
|
|
app_state.addingbook.set(bookupdate.clone());
|
|
};
|
|
|
|
let handle_display = move |_| {
|
|
app_state.displaying.set(true);
|
|
app_state.updating.set(false);
|
|
//info!("Setting displaying book {:?}",bookdisplay);
|
|
app_state.displayingbook.set(bookdisplay.clone());
|
|
};
|
|
view! { cx,
|
|
div(class="column"){
|
|
div(class="card"){
|
|
|
|
div(class="card-buttons"){
|
|
|
|
button(class="delete", on:click=handle_delete){ "DEL-" }
|
|
button(class="update", on:click=handle_update){ "EDIT=" }
|
|
button(class="info", on:click=handle_display){ "INFO+" }
|
|
}
|
|
div(class="card-main"){
|
|
img(src=coverurl,width="100")
|
|
|
|
div(class="card-title"){
|
|
(format!("{}",loctitle))
|
|
}
|
|
div(class="card-authors"){
|
|
(format!("{}",locauthors))
|
|
}
|
|
//div(class="card-image"){
|
|
//}
|
|
}
|
|
|
|
div(class="card-desc"){
|
|
(format!("{}",locloc))
|
|
br{}br{}
|
|
(format!("{}",locdesc))
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
#[component(inline_props)]
|
|
pub fn BookDB_View<G: Html>(cx: Scope, bookitem: BookUIProp) -> View<G> {
|
|
let app_state = use_context::<AppState>(cx);
|
|
let bookdisplay = bookitem.bookitem.clone();
|
|
let loctitle = bookitem.bookitem.clone().title.clone();
|
|
let locauthors = bookitem.bookitem.clone().author_name.clone().unwrap_or(vec!["".to_string()]).join(", ");
|
|
let locdesc = bookitem.bookitem.clone().description.unwrap_or("".to_string());
|
|
let locloc = bookitem.bookitem.clone().location.unwrap_or("".to_string());
|
|
|
|
let coverurl = bookdisplay.clone().cover.clone().unwrap_or("None".to_string());
|
|
let handle_display = move |_| {
|
|
app_state.displaying.set(true);
|
|
app_state.updating.set(false);
|
|
//info!("Setting displaying book {:?}",bookdisplay);
|
|
app_state.displayingbook.set(bookdisplay.clone());
|
|
};
|
|
view! { cx,
|
|
div(class="column"){
|
|
div(class="card"){
|
|
|
|
div(class="card-buttons"){
|
|
|
|
button(class="info", on:click=handle_display){ "INFO+" }
|
|
}
|
|
div(class="card-main"){
|
|
img(src=coverurl,width="100")
|
|
|
|
div(class="card-title"){
|
|
(format!("{}",loctitle))
|
|
}
|
|
div(class="card-authors"){
|
|
(format!("{}",locauthors))
|
|
}
|
|
//div(class="card-image"){
|
|
//}
|
|
}
|
|
|
|
div(class="card-desc"){
|
|
(format!("{}",locloc))
|
|
br{}br{}
|
|
(format!("{}",locdesc))
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
#[component]
|
|
async fn ListOL<G: Html>(cx: Scope<'_>) -> View<G> {
|
|
let app_state = use_context::<AppState>(cx);
|
|
|
|
/*
|
|
create_effect(cx, || {
|
|
app_state.search.track();
|
|
|
|
info!(
|
|
"The state changed B. New value: {}",
|
|
app_state.search.get(),
|
|
);
|
|
});
|
|
*/
|
|
|
|
let docs = create_memo(cx, || app_state.books.get().iter().cloned().collect::<Vec<_>>());
|
|
view! {cx,
|
|
p {
|
|
(if *app_state.openlibrary.get() == true {
|
|
view!{ cx,
|
|
div(class="row") {
|
|
Keyed(
|
|
iterable=docs,
|
|
view=move |cx, x| view! { cx,
|
|
BookOL(bookitem=x)
|
|
|
|
},
|
|
key =|x| x.id )
|
|
}
|
|
}
|
|
} else {
|
|
view!{cx,""}
|
|
}
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
#[component(inline_props)]
|
|
pub fn BookOL<G: Html>(cx: Scope, bookitem: BookUIProp) -> View<G> {
|
|
let book = bookitem.bookitem.clone();
|
|
let bookdisp=book.clone();
|
|
let loctitle = bookitem.bookitem.clone().title.clone();
|
|
let locauthors = bookitem.bookitem.clone().author_name.clone().unwrap_or(vec!["".to_string()]).join(", ");
|
|
let coverurl = bookdisp.cover.clone().unwrap_or("NONE".to_string());
|
|
let app_state = use_context::<AppState>(cx);
|
|
let handle_add = move |_| {
|
|
app_state.adding.set(true);
|
|
app_state.addingbook.set(book.clone());
|
|
};
|
|
|
|
view! { cx,
|
|
div(class="column"){
|
|
div(class="card-openlibrary"){
|
|
button(class="add", on:click=handle_add){ "ADD+" }
|
|
div(class="card-main"){
|
|
img(src=coverurl,width="100")
|
|
|
|
div(class="card-title"){
|
|
(format!("{}",loctitle))
|
|
}
|
|
div(class="card-authors"){
|
|
(format!("{}",locauthors))
|
|
}
|
|
//div(class="card-image"){
|
|
//}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
#[component]
|
|
async fn AddingUI<G: Html>(cx: Scope<'_>) -> View<G> {
|
|
let app_state = use_context::<AppState>(cx);
|
|
|
|
let node_ref = create_node_ref(cx);
|
|
|
|
|
|
let inp_title = create_signal(cx, (*app_state.addingbook.get()).clone().title);
|
|
let inp_olkey = create_signal(cx, (*app_state.addingbook.get()).clone().open_library_key.unwrap_or("".to_string()));
|
|
let inp_editioncount = create_signal(cx, (*app_state.addingbook.get()).clone().edition_count.unwrap_or(0).to_string());
|
|
let inp_publishyear = create_signal(cx, (*app_state.addingbook.get()).clone().first_publish_year.unwrap_or(0).to_string());
|
|
let inp_medianpage = create_signal(cx, (*app_state.addingbook.get()).clone().median_page_count.unwrap_or(0).to_string());
|
|
let inp_goodread = create_signal(cx, (*app_state.addingbook.get()).clone().goodread_id.unwrap_or("".to_string()));
|
|
let inp_desc = create_signal(cx, (*app_state.addingbook.get()).clone().description.unwrap_or("".to_string()));
|
|
let inp_cover = create_signal(cx, (*app_state.addingbook.get()).clone().cover.unwrap_or("".to_string()));
|
|
let inp_location = create_signal(cx, (*app_state.addingbook.get()).clone().location.unwrap_or("".to_string()));
|
|
let inp_rating = create_signal(cx, (*app_state.addingbook.get()).clone().location.unwrap_or("".to_string()));
|
|
let inp_comments = create_signal(cx, (*app_state.addingbook.get()).clone().comments.unwrap_or("".to_string()));
|
|
let inp_author = create_signal(cx, (*app_state.addingbook.get()).clone().author_name.unwrap_or(vec!["".to_string()]).join(", "));
|
|
let inp_person = create_signal(cx, (*app_state.addingbook.get()).clone().person.unwrap_or(vec!["".to_string()]).join(", "));
|
|
let inp_place = create_signal(cx, (*app_state.addingbook.get()).clone().place.unwrap_or(vec!["".to_string()]).join(", "));
|
|
let inp_subject = create_signal(cx, (*app_state.addingbook.get()).clone().subject.unwrap_or(vec!["".to_string()]).join(", "));
|
|
let inp_time = create_signal(cx, (*app_state.addingbook.get()).clone().time.unwrap_or(vec!["".to_string()]).join(", "));
|
|
let inp_isbn = create_signal(cx, (*app_state.addingbook.get()).clone().isbn.unwrap_or(vec!["".to_string()]).join(", "));
|
|
create_effect(cx, || {
|
|
|
|
// info!("{:?}",*app_state.addingbook.get());
|
|
inp_title.set((*app_state.addingbook.get()).clone().title);
|
|
inp_olkey.set((*app_state.addingbook.get()).clone().open_library_key.unwrap_or("".to_string()));
|
|
inp_editioncount.set((*app_state.addingbook.get()).clone().edition_count.unwrap_or(0).to_string());
|
|
inp_publishyear.set((*app_state.addingbook.get()).clone().first_publish_year.unwrap_or(0).to_string());
|
|
inp_medianpage.set((*app_state.addingbook.get()).clone().median_page_count.unwrap_or(0).to_string());
|
|
inp_goodread.set((*app_state.addingbook.get()).clone().goodread_id.unwrap_or("".to_string()));
|
|
inp_desc.set((*app_state.addingbook.get()).clone().description.unwrap_or("".to_string()));
|
|
inp_cover.set((*app_state.addingbook.get()).clone().cover.unwrap_or("".to_string()));
|
|
inp_location.set((*app_state.addingbook.get()).clone().location.unwrap_or("".to_string()));
|
|
inp_rating.set((*app_state.addingbook.get()).clone().location.unwrap_or("".to_string()));
|
|
inp_comments.set((*app_state.addingbook.get()).clone().comments.unwrap_or("".to_string()));
|
|
inp_author.set((*app_state.addingbook.get()).clone().author_name.unwrap_or(vec!["".to_string()]).join(", "));
|
|
inp_person.set((*app_state.addingbook.get()).clone().person.unwrap_or(vec!["".to_string()]).join(", "));
|
|
inp_place.set((*app_state.addingbook.get()).clone().place.unwrap_or(vec!["".to_string()]).join(", "));
|
|
inp_subject.set((*app_state.addingbook.get()).clone().subject.unwrap_or(vec!["".to_string()]).join(", "));
|
|
inp_time.set((*app_state.addingbook.get()).clone().time.unwrap_or(vec!["".to_string()]).join(", "));
|
|
inp_isbn.set((*app_state.addingbook.get()).clone().isbn.unwrap_or(vec!["".to_string()]).join(", "));
|
|
});
|
|
|
|
let handle_cancel = |_| {
|
|
app_state.updating.set(false);
|
|
app_state.adding.set(false);
|
|
|
|
let dom_node = node_ref.try_get::<DomNode>();
|
|
if dom_node.is_some() {
|
|
dom_node.unwrap().set_attribute("popup-display","false");
|
|
}
|
|
|
|
};
|
|
|
|
let handle_add = |_| {
|
|
info!("Adding book");
|
|
let authors: Vec<String> = (*inp_author.get()).clone().split(",").map(str::to_string).collect::<Vec<String>>();
|
|
let persons: Vec<String> = (*inp_person.get()).clone().split(",").map(str::to_string).collect::<Vec<String>>();
|
|
let places: Vec<String> = (*inp_place.get()).clone().split(",").map(|x| x.to_string()).collect::<Vec<String>>();
|
|
let subjects: Vec<String> = (*inp_subject.get()).clone().split(",").map(|x| x.to_string()).collect::<Vec<String>>();
|
|
let times: Vec<String> = (*inp_time.get()).clone().split(",").map(|x| x.to_string()).collect::<Vec<String>>();
|
|
let isbns: Vec<String> = (*inp_isbn.get()).clone().split(",").map(|x| x.to_string()).collect::<Vec<String>>();
|
|
let record : BookUI = BookUI{
|
|
id: app_state.addingbook.get().id.clone(),
|
|
title: (*inp_title.get()).clone(),
|
|
open_library_key: Some((*inp_olkey.get()).clone()),
|
|
edition_count: Some(inp_editioncount.get().parse::<i32>().unwrap_or(0)),
|
|
first_publish_year: Some(inp_publishyear.get().parse::<i32>().unwrap_or(0)),
|
|
median_page_count: Some(inp_medianpage.get().parse::<i32>().unwrap_or(0)),
|
|
goodread_id: Some((*inp_goodread.get()).clone()),
|
|
description: Some((*inp_desc.get()).clone()),
|
|
cover: Some((*inp_cover.get()).clone()),
|
|
location: Some((*inp_location.get()).clone()),
|
|
time_added: Some("NA".to_string()),
|
|
rating: Some(inp_rating.get().parse::<i32>().unwrap_or(0)),
|
|
comments: Some((*inp_comments.get()).clone()),
|
|
author_name: Some(authors),
|
|
person: Some(persons),
|
|
place: Some(places),
|
|
subject: Some(subjects),
|
|
time: Some(times),
|
|
isbn: Some(isbns),
|
|
};
|
|
|
|
app_state.apibook.set(record);
|
|
|
|
app_state.addingbook.set(BookUI::default());
|
|
if *app_state.updating.get()==true {
|
|
app_state.updatingrequest.set(true);
|
|
}
|
|
if *app_state.adding.get()==true {
|
|
app_state.addingrequest.set(true);
|
|
}
|
|
app_state.updating.set(false);
|
|
app_state.adding.set(false);
|
|
//app_state.books.set(vec![BookUI::default()]);
|
|
|
|
|
|
};
|
|
|
|
create_effect(cx, || {
|
|
app_state.apibook.track();
|
|
let app_state = app_state.clone();
|
|
let record = (*app_state.apibook.get()).clone();
|
|
spawn_local(async move {
|
|
info!("Adding effect startedDone");
|
|
|
|
if *app_state.addingrequest.get() == true {
|
|
let temp = add_book(record).await.unwrap();
|
|
info!("Adding Done{}",temp.status());
|
|
app_state.refreshing.set(true);
|
|
app_state.addingrequest.set(false);
|
|
} else if *app_state.updatingrequest.get() == true {
|
|
let temp = update_book(record).await.unwrap();
|
|
info!("Updating Done{}",temp.status());
|
|
app_state.refreshing.set(true);
|
|
app_state.updatingrequest.set(false);
|
|
}
|
|
});
|
|
});
|
|
|
|
create_effect(cx, || {
|
|
if *app_state.updating.get() == true || *app_state.adding.get() == true {
|
|
|
|
let dom_node = node_ref.try_get::<DomNode>();
|
|
if dom_node.is_some() {
|
|
dom_node.unwrap().set_attribute("popup-display","true");
|
|
}
|
|
} else {
|
|
let dom_node = node_ref.try_get::<DomNode>();
|
|
if dom_node.is_some() {
|
|
dom_node.unwrap().set_attribute("popup-display","false");
|
|
}
|
|
}
|
|
});
|
|
|
|
view! {cx,
|
|
div(class="modal-box",ref=node_ref){
|
|
|
|
(if *app_state.adding.get() == true || *app_state.updating.get() == true {
|
|
view!{ cx,
|
|
div(class="modal-content"){
|
|
div(class="input-buttons"){
|
|
button(class="add", on:click=handle_add){ "Add/Update book to DB" }
|
|
button(class="cancel", on:click=handle_cancel){ "Cancel" }
|
|
}
|
|
p {
|
|
div(class="input-field"){
|
|
label{"Title"}
|
|
textarea(bind:value=inp_title, placeholder="Title" )
|
|
}
|
|
div(class="input-field"){
|
|
label{"OpenLib Key"}
|
|
textarea(bind:value=inp_olkey, placeholder="OpenLibrary Key" )
|
|
}
|
|
div(class="input-field"){
|
|
label{"Editions"}
|
|
textarea(bind:value=inp_editioncount, placeholder="Number of editions" )
|
|
}
|
|
div(class="input-field"){
|
|
label{"Publish year"}
|
|
textarea(bind:value=inp_publishyear, placeholder="First publish year" )
|
|
}
|
|
div(class="input-field"){
|
|
label{"Pages"}
|
|
textarea(bind:value=inp_medianpage, placeholder="Page count" )
|
|
}
|
|
div(class="input-field"){
|
|
label{"GoodreadID"}
|
|
textarea(bind:value=inp_goodread, placeholder="GoodRead ID" )
|
|
}
|
|
div(class="input-field"){
|
|
label{"Description"}
|
|
textarea(bind:value=inp_desc, placeholder="Description" )
|
|
}
|
|
div(class="input-field"){
|
|
label{"Cover"}
|
|
textarea(bind:value=inp_cover, placeholder="Cover URL" )
|
|
}
|
|
div(class="input-field"){
|
|
label{"Location"}
|
|
textarea(bind:value=inp_location, placeholder="Location" )
|
|
}
|
|
div(class="input-field"){
|
|
label{"Rating"}
|
|
textarea(bind:value=inp_rating, placeholder="Rating (/10)" )
|
|
}
|
|
div(class="input-field"){
|
|
label{"Comments"}
|
|
textarea(bind:value=inp_comments, placeholder="Comments" )
|
|
}
|
|
div(class="input-field"){
|
|
label{"Authors"}
|
|
textarea(bind:value=inp_author, placeholder="Authors")
|
|
}
|
|
div(class="input-field"){
|
|
label{"Persons"}
|
|
textarea(bind:value=inp_person, placeholder="Persons" )
|
|
}
|
|
div(class="input-field"){
|
|
label{"Places"}
|
|
textarea(bind:value=inp_place, placeholder="Places" )
|
|
}
|
|
div(class="input-field"){
|
|
label{"Subjects"}
|
|
textarea(bind:value=inp_subject, placeholder="Subjects" )
|
|
}
|
|
div(class="input-field"){
|
|
label{"Times"}
|
|
textarea(bind:value=inp_time, placeholder="Times" )
|
|
}
|
|
div(class="input-field"){
|
|
label{"ISBNs"}
|
|
textarea(bind:value=inp_isbn, placeholder="ISBNs" )
|
|
}
|
|
|
|
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
else {
|
|
view!{cx,""}
|
|
})
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
#[component]
|
|
async fn SelectedUI<G: Html>(cx: Scope<'_>) -> View<G> {
|
|
let app_state = use_context::<AppState>(cx);
|
|
let displaybook = create_memo(cx, || app_state.displayingbook.get());
|
|
|
|
let coverurl = create_memo(cx, || app_state.displayingbook.get().clone().cover.clone().unwrap_or("NONE".to_string()).to_string().clone());
|
|
let node_ref = create_node_ref(cx);
|
|
|
|
let dtitle = create_memo(cx, || app_state.displayingbook.get().title.clone());
|
|
let dollink = create_memo(cx, || {
|
|
let olkey = app_state.displayingbook.get().open_library_key.clone().unwrap_or("".to_string());
|
|
format!("https://openlibrary.org{}",olkey)
|
|
}
|
|
);
|
|
let deditions = create_memo(cx, || app_state.displayingbook.get().edition_count.unwrap_or(0) );
|
|
let dpubyr = create_memo(cx, || app_state.displayingbook.get().first_publish_year.unwrap_or(0) );
|
|
let dpages = create_memo(cx, || app_state.displayingbook.get().median_page_count.unwrap_or(0) );
|
|
let dgoodread = create_memo(cx, || {
|
|
let goodreadid = app_state.displayingbook.get().goodread_id.clone().unwrap_or("".to_string());
|
|
format!("https://goodreads.com/en/book/show/{}",goodreadid)
|
|
}
|
|
);
|
|
let ddesc = create_memo(cx, || app_state.displayingbook.get().description.clone().unwrap_or("".to_string()) );
|
|
let dlocation = create_memo(cx, || app_state.displayingbook.get().location.clone().unwrap_or("".to_string()) );
|
|
let dcomments = create_memo(cx, || app_state.displayingbook.get().comments.clone().unwrap_or("".to_string()) );
|
|
let dtags = create_memo(cx, || {
|
|
let persons = app_state.displayingbook.get().person.clone().unwrap_or(vec!["".to_string()]).iter().filter(|word| !word.is_empty()).map(|s| format!("#{}",s.clone())).collect::<Vec<String>>().join(", ");
|
|
let places = app_state.displayingbook.get().place.clone().unwrap_or(vec!["".to_string()]).iter().filter(|word| !word.is_empty()).map(|s| format!("#{}",s.clone())).collect::<Vec<String>>().join(", ");
|
|
let subjects = app_state.displayingbook.get().subject.clone().unwrap_or(vec!["".to_string()]).iter().filter(|word| !word.is_empty()).map(|s| format!("#{}",s.clone())).collect::<Vec<String>>().join(", ");
|
|
let times = app_state.displayingbook.get().time.clone().unwrap_or(vec!["".to_string()]).iter().filter(|word| !word.is_empty()).map(|s| format!("#{}",s.clone())).collect::<Vec<String>>().join(", ");
|
|
let alltags = vec![persons,places,subjects,times].iter().filter(|word| !word.is_empty()).join(", ");
|
|
format!("{}",alltags)
|
|
}
|
|
);
|
|
let disbn = create_memo(cx, || {
|
|
app_state.displayingbook.get().isbn.clone().unwrap_or(vec!["".to_string()])[0].clone()
|
|
});
|
|
let dauthors = create_memo(cx, || {
|
|
app_state.displayingbook.get().author_name.clone().unwrap_or(vec!["".to_string()]).join(", ")
|
|
});
|
|
|
|
let handle_close = move |_| {
|
|
app_state.displaying.set(false);
|
|
|
|
let dom_node = node_ref.try_get::<DomNode>();
|
|
if dom_node.is_some() {
|
|
dom_node.unwrap().set_attribute("popup-display","false");
|
|
}
|
|
};
|
|
|
|
let handle_edit = move |_| {
|
|
app_state.displaying.set(false);
|
|
let dom_node = node_ref.try_get::<DomNode>();
|
|
if dom_node.is_some() {
|
|
dom_node.unwrap().set_attribute("popup-display","false");
|
|
}
|
|
|
|
app_state.addingbook.set((*(*displaybook.get())).clone());
|
|
app_state.updating.set(true);
|
|
};
|
|
|
|
|
|
create_effect(cx, || {
|
|
if *app_state.displaying.get() == true {
|
|
let dom_node = node_ref.try_get::<DomNode>();
|
|
if dom_node.is_some() {
|
|
dom_node.unwrap().set_attribute("popup-display","true");
|
|
}
|
|
} else {
|
|
let dom_node = node_ref.try_get::<DomNode>();
|
|
if dom_node.is_some() {
|
|
dom_node.unwrap().set_attribute("popup-display","false");
|
|
}
|
|
}
|
|
});
|
|
|
|
|
|
view! {cx,
|
|
div(class="modal-box", ref=node_ref){
|
|
|
|
(if *app_state.displaying.get() == true {
|
|
view!{ cx,
|
|
|
|
div(class="modal-content"){
|
|
|
|
div(class="more-info"){
|
|
div(class="more-info-buttons"){
|
|
button(class="close", on:click=handle_close){ "CLOSE" }
|
|
button(class="close", on:click=handle_edit){ "EDIT" }
|
|
}
|
|
img(src=coverurl.get(),width="200")
|
|
label{"Title: "}
|
|
(format!("{}",dtitle.get()))
|
|
br{}
|
|
label{"Authors: "}
|
|
(format!("{}",dauthors.get()))
|
|
br{}
|
|
label{"Location: "}
|
|
(format!("{}",dlocation.get()))
|
|
br{}
|
|
label{"Editions: "}
|
|
(format!("{}",deditions.get()))
|
|
br{}
|
|
label{"Publish Year: "}
|
|
(format!("{}",dpubyr.get()))
|
|
br{}
|
|
label{"Page Count: "}
|
|
(format!("{}",dpages.get()))
|
|
br{}
|
|
label{"Openlibrary Link: "}
|
|
a(href=dollink.get().clone()){(format!("{}",dollink.get()))}
|
|
br{}
|
|
label{"GoodReads Link: "}
|
|
a(href=dgoodread.get().clone()){(format!("{}",dgoodread.get()))}
|
|
br{}
|
|
label{"ISBN: "}
|
|
(format!("{}",disbn.get()))
|
|
br{}
|
|
label{"Description: "}
|
|
(format!("{}",ddesc.get()))
|
|
br{}
|
|
label{"Comments: "}
|
|
(format!("{}",dcomments.get()))
|
|
br{}
|
|
label{"Tags: "}
|
|
(format!("{}",dtags.get()))
|
|
br{}
|
|
}
|
|
}
|
|
}}
|
|
else {
|
|
view!{cx,""}
|
|
})
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
#[component]
|
|
async fn PageBar<G: Html>(cx: Scope<'_>) -> View<G> {
|
|
let app_state = use_context::<AppState>(cx);
|
|
let currpg = create_signal(cx, (*app_state.pagenum.get()).to_string());
|
|
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);
|
|
|
|
};
|
|
|
|
let handle_sub = move |_| {
|
|
if *app_state.pagenum.get()>1 {
|
|
app_state.pagenum.set(*app_state.pagenum.get()-1);
|
|
app_state.refreshing.set(true);
|
|
}
|
|
};
|
|
|
|
let handle_submit = |event: Event| {
|
|
let event: KeyboardEvent = event.unchecked_into();
|
|
|
|
if event.key() == "Enter" {
|
|
let pg = currpg.get().as_ref().clone().parse::<u32>().unwrap_or(1);
|
|
if pg>0 && pg<*app_state.maxpage.get() {
|
|
app_state.pagenum.set(pg);
|
|
app_state.refreshing.set(true);
|
|
} else {
|
|
currpg.set((*app_state.pagenum.get()).to_string());
|
|
}
|
|
|
|
}
|
|
};
|
|
view! {cx,
|
|
div {
|
|
(if *app_state.openlibrary.get() == false || *app_state.internalsearch.get() == true {
|
|
view!{ cx,
|
|
label{"PAGE "}
|
|
input(ref=input_ref,bind:value=currpg,on:keyup=handle_submit,class="page-input")
|
|
label{(format!(" / {}",*app_state.maxpage.get()))}
|
|
(if *app_state.pagenum.get()>1 {
|
|
view!{cx, button(class="page", on:click=handle_sub){ "-" }}
|
|
} else {
|
|
view!{cx,""}
|
|
})
|
|
(if *app_state.pagenum.get()<*app_state.maxpage.get() {
|
|
view!{cx, button(class="page", on:click=handle_add){ "+" }}
|
|
} else {
|
|
view!{cx,""}
|
|
})
|
|
}
|
|
}else {
|
|
view!{cx,""}
|
|
})
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
|
|
#[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 app_state = app_state.clone();
|
|
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");
|
|
});
|
|
spawn_local(async move {
|
|
app_state.userlist.set(list_users()
|
|
.await.expect("Couldn't list 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.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);
|
|
};
|
|
|
|
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<G: Html>(cx: Scope) -> View<G> {
|
|
let app_state = AppState {
|
|
books: create_rc_signal(Vec::new()),
|
|
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()),
|
|
updating: create_rc_signal(bool::default()),
|
|
addingbook: create_rc_signal(BookUI::default()),
|
|
displaying: create_rc_signal(bool::default()),
|
|
displayingbook: create_rc_signal(BookUI::default()),
|
|
refreshing: create_rc_signal(true),
|
|
apibook: create_rc_signal(BookUI::default()),
|
|
updatingrequest: create_rc_signal(bool::default()),
|
|
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),
|
|
useridloggedin: create_rc_signal(0),
|
|
userscreen: create_rc_signal(bool::default()),
|
|
loggedin: create_rc_signal(bool::default()),
|
|
editmode: create_rc_signal(bool::default()),
|
|
dropdownselect: create_rc_signal(bool::default()),
|
|
};
|
|
provide_context(cx, app_state);
|
|
|
|
|
|
view! {
|
|
cx,
|
|
div {
|
|
Header {}
|
|
div(class="main"){
|
|
LoginScreenUI{}
|
|
AddingUI{}
|
|
SelectedUI{}
|
|
ListOL {}
|
|
ListDB{}
|
|
}
|
|
//PageBar{}
|
|
}
|
|
}
|
|
}
|
|
|
|
fn main() {
|
|
console_error_panic_hook::set_once();
|
|
console_log::init_with_level(log::Level::Debug).unwrap();
|
|
|
|
sycamore::render(|cx| view! { cx, App {} });
|
|
}
|