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.
fast-insiders/client/src/templates/transactions.rs

138 lines
4.8 KiB

use perseus::prelude::*;
use serde::{Deserialize, Serialize};
use sycamore::prelude::*;
use crate::{
api::routes::transaction::get_transactions,
api::types::{company::Company, transaction::TransactionCompany},
components::{
base_async_select::{AsyncSelectRx, BaseAsyncSelect},
base_button::{BaseButton, BaseButtonStateRx},
main_content_container::MainContentContainer,
paginated_data_table::{PaginatedTable, PaginatedTableStateRx},
the_header::TheHeader,
},
global_state::AppStateRx,
};
#[derive(Serialize, Deserialize, Clone, ReactiveState)]
#[rx(alias = "TransactionsPageStateRx")]
pub struct TransactionsPageState {
pub company_slug: Option<String>,
}
#[auto_scope]
fn transactions_page<G: Html>(cx: Scope, state: &TransactionsPageStateRx) -> View<G> {
let global_state = Reactor::<G>::from_cx(cx).get_global_state::<AppStateRx>(cx);
let dark_mode = &global_state.dark_mode;
let expand = create_signal(cx, false);
let filter_expand = BaseButtonStateRx {
label: create_signal(cx, "Filters".to_string()),
disabled: create_signal(cx, false),
clicked: create_signal(cx, false),
};
create_effect(cx, move || {
if *filter_expand.clicked.get() {
filter_expand.clicked.set(false);
expand.set(!*expand.get());
}
});
let paginated_table_state: PaginatedTableStateRx<TransactionCompany, _, _> =
PaginatedTableStateRx {
record_label: "transactions".to_owned(),
route: get_transactions,
filter: (*state.company_slug.get()).clone(),
table_class: create_ref(cx, "".to_string()),
};
let async_select_prop: AsyncSelectRx<Company> = AsyncSelectRx {
remote_list: create_signal(cx, format!("{}company/", "http://localhost:8000/v1/")),
selected_item: create_signal(cx, None),
};
let search_button = BaseButtonStateRx {
label: create_signal(cx, "Search".to_string()),
disabled: create_memo(cx, move || async_select_prop.selected_item.get().is_none()),
clicked: create_signal(cx, false),
};
create_effect(cx, || {
if *search_button.clicked.get() {
search_button.clicked.set(false);
navigate(&format!(
"/transactions/{}",
(*async_select_prop.selected_item.get())
.clone()
.map_or("".to_string(), |c| c.slug)
));
}
});
view! {cx,
main (class=if *dark_mode.get() { "dark" } else { "" }) {
div (class="bg-slate-200 dark:bg-slate-700 text-slate-700 dark:text-slate-100 font-sans") {
TheHeader()
MainContentContainer(useless_prop=1) {
a (class="hover:underline", href="/transactions") {
h1 (
class="text-center text-lg"
) {
"Insider Transactions published by the AMF"
}
}
BaseButton(filter_expand)
div (id="filters",
class=format!("p-2 border rounded-lg border-slate-200 dark:border-slate-800 bg-slate-200 dark:bg-slate-700 transition-all ease-in {}",
if *expand.get() { "h-40 visible" } else { "h-0 collapse" },
)
)
{
div (class="w-80") {
p () {"Search for a company:"}
BaseAsyncSelect(async_select_prop)
BaseButton(search_button)
}
}
PaginatedTable(paginated_table_state)
}
}
}
}
}
pub fn get_template<G: Html>() -> Template<G> {
Template::build("transactions")
.head(head)
.build_state_fn(get_build_state)
.build_paths_fn(get_build_paths)
.incremental_generation()
.view_with_state(transactions_page)
.build()
}
#[engine_only_fn]
fn head(cx: Scope) -> View<SsrNode> {
view! {cx,
title { "Fast Insiders" }
}
}
#[engine_only_fn]
async fn get_build_state(
StateGeneratorInfo { path, .. }: StateGeneratorInfo<()>,
) -> Result<TransactionsPageState, BlamedError<std::io::Error>> {
let company_slug = if path.is_empty() { None } else { Some(path) };
Ok(TransactionsPageState { company_slug })
}
#[engine_only_fn]
async fn get_build_paths() -> BuildPaths {
BuildPaths {
paths: vec!["".to_string()],
extra: ().into(),
}
}