You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
132 lines
5.0 KiB
132 lines
5.0 KiB
use std::rc::Rc;
|
|
|
|
use serde::Deserialize;
|
|
use sycamore::prelude::*;
|
|
|
|
use crate::{
|
|
api::types::paginated_response::{IntoTableData, PaginatedResponse},
|
|
components::{
|
|
base_table::{BaseTable, TableContentRx},
|
|
loading::Loading,
|
|
},
|
|
};
|
|
|
|
#[derive(Clone)]
|
|
pub struct PaginatedTableStateRx<M, F, C>
|
|
where
|
|
M: 'static,
|
|
C: Fn(Option<String>, i64, i64) -> F,
|
|
F: std::future::Future<Output = Result<PaginatedResponse<M>, ()>>,
|
|
{
|
|
pub route: C,
|
|
pub filter: Option<String>,
|
|
}
|
|
|
|
impl<M, F, C> PaginatedTableStateRx<M, F, C>
|
|
where
|
|
M: 'static,
|
|
C: Fn(Option<String>, i64, i64) -> F,
|
|
F: std::future::Future<Output = Result<PaginatedResponse<M>, ()>>,
|
|
{
|
|
async fn get_data(&self, page: i64, size: i64) -> Result<PaginatedResponse<M>, ()> {
|
|
(self.route)(self.filter.clone(), page, size).await
|
|
}
|
|
}
|
|
|
|
#[component(PaginatedTable<G>)]
|
|
pub fn component<M, F, C>(state: PaginatedTableStateRx<M, F, C>) -> View<G>
|
|
where
|
|
M: 'static + Clone,
|
|
PaginatedResponse<M>: IntoTableData<G>,
|
|
for<'de> M: Deserialize<'de>,
|
|
C: Fn(Option<String>, i64, i64) -> F + 'static,
|
|
F: std::future::Future<Output = Result<PaginatedResponse<M>, ()>> + 'static,
|
|
{
|
|
let paginated_data: Signal<Option<PaginatedResponse<M>>> = Signal::new(None);
|
|
let table_prop: TableContentRx<G> = TableContentRx {
|
|
headers_view: Signal::new(vec![]),
|
|
data_view: Signal::new(vec![vec![]]),
|
|
};
|
|
let table_prop2 = table_prop.clone();
|
|
let page: Signal<i64> = Signal::new(0);
|
|
let n_page: Signal<i64> = Signal::new(1);
|
|
let n_rows: Signal<i64> = Signal::new(0);
|
|
|
|
let page_up = cloned!((page, paginated_data, n_page) => move |_| {
|
|
n_page.set((*paginated_data.get()).as_ref().map_or(0, |t| t.num_pages));
|
|
if *page.get() + 1 < *n_page.get() {
|
|
page.set((*page.get()).min(*n_page.get() - 1) + 1)
|
|
}
|
|
});
|
|
let page_down = cloned!((page) => move |_| {
|
|
if *page.get() > 0 {
|
|
page.set((*page.get()-1).max(0));
|
|
}
|
|
});
|
|
|
|
let page_size_string = Signal::new("20".to_string());
|
|
let page_size_string2 = page_size_string.clone();
|
|
let state_rc = Rc::new(state);
|
|
create_effect(
|
|
cloned!((page_size_string, paginated_data, page, n_page, n_rows, state_rc) => move || {
|
|
let page = *page.get();
|
|
let page_size_s = page_size_string.get();
|
|
let page_size = page_size_s.parse().unwrap_or(20);
|
|
if G::IS_BROWSER {
|
|
perseus::spawn_local(
|
|
cloned!((table_prop2, page, paginated_data, n_page, n_rows, state_rc) => async move {
|
|
let res = state_rc.get_data(page, page_size).await.unwrap();
|
|
paginated_data.set(Some(res.clone()));
|
|
n_rows.set(res.count);
|
|
let table_content = res.into_table_data();
|
|
table_prop2.data_view.set(table_content.data_view);
|
|
table_prop2.headers_view.set(table_content.headers_view);
|
|
n_page.set((*paginated_data.get()).as_ref().map_or(0, |t| t.num_pages));
|
|
}),
|
|
);
|
|
}
|
|
}),
|
|
);
|
|
|
|
view! {
|
|
(cloned!((n_rows, page_size_string, page_down, page_up, page, n_page, page_size_string2) =>
|
|
view! {
|
|
p (class="text-right") { (format!("{} transactions", n_rows.get())) }
|
|
div (class="flex flex-row justify-between") {
|
|
select (bind:value=page_size_string,
|
|
class="p-2 justify-end text-slate-700 dark:text-slate-100 bg-slate-200 dark:bg-slate-800 rounded-md",
|
|
id="size-select",
|
|
) {
|
|
option (value="20") { "20" }
|
|
option (value="10") { "10" }
|
|
option (value="30", selected=page_size_string2.get().eq(&Rc::new("30".to_string()))) { "30" }
|
|
option (value="40") { "40" }
|
|
option (value="50") { "50" }
|
|
}
|
|
div (class="flex flex-row p-2 bg-slate-200 dark:bg-slate-800 rounded-md") {
|
|
button (on:click=page_down,class="m-1 hover:font-bold") {
|
|
"<<"
|
|
}
|
|
div (class="m-1 align-middle text-center") {
|
|
(format!("{}/{}",*page.get() + 1, *n_page.get()) )
|
|
}
|
|
button (on:click=page_up, class="m-1 hover:font-bold") {
|
|
">>"
|
|
}
|
|
}
|
|
}
|
|
}))
|
|
(if paginated_data.get().is_some() {
|
|
view! {
|
|
BaseTable(table_prop.clone())
|
|
}
|
|
} else {
|
|
view! {
|
|
div (class="flex flex-row justify-center") {
|
|
Loading()
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|