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, } #[auto_scope] fn transactions_page(cx: Scope, state: &TransactionsPageStateRx) -> View { let global_state = Reactor::::from_cx(cx).get_global_state::(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 = 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 = 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() -> Template { 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 { view! {cx, title { "Fast Insiders" } } } #[engine_only_fn] async fn get_build_state( StateGeneratorInfo { path, .. }: StateGeneratorInfo<()>, ) -> Result> { 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(), } }