pub mod components; use components::{ChannelSummaryList, StatsOverview, UserSummaryList}; use leptos::prelude::*; use shared_types::dashboard::{DashboardChannel, DashboardStats, DashboardUser}; use std::sync::Arc; use wasm_bindgen_futures::spawn_local; #[derive(Clone, PartialEq)] enum DashboardTab { Stats, Users, Channels, } #[component] pub fn DashboardPanel() -> impl IntoView { let active_tab = RwSignal::new(DashboardTab::Stats); let stats = RwSignal::new(None::); let stats_loading = RwSignal::new(false); let stats_error = RwSignal::new(None::); let users = RwSignal::new(Vec::::new()); let users_loading = RwSignal::new(false); let users_error = RwSignal::new(None::); let users_search = RwSignal::new(String::new()); let users_cursor = RwSignal::new(None::); let channels = RwSignal::new(Vec::::new()); let channels_loading = RwSignal::new(false); let channels_error = RwSignal::new(None::); let channels_search = RwSignal::new(String::new()); let channels_cursor = RwSignal::new(None::); let fetch_stats: Arc = Arc::new(move || { stats_loading.set(true); stats_error.set(None); spawn_local(async move { match crate::api::dashboard::get_dashboard_stats().await { Ok(data) => stats.set(Some(data)), Err(err) => stats_error.set(Some(format!("Failed to load stats: {}", err))), } stats_loading.set(false); }); }); let fetch_users: Arc = Arc::new(move |reset: bool| { if users_loading.get() { return; } users_loading.set(true); users_error.set(None); let cursor = if reset { None } else { users_cursor.get() }; let search = users_search.get(); spawn_local(async move { let search_ref = (!search.trim().is_empty()).then_some(search.trim()); match crate::api::dashboard::get_dashboard_users(Some(20), cursor.as_deref(), search_ref).await { Ok(page) => { if reset { users.set(page.data); } else { let mut current = users.get(); current.extend(page.data); users.set(current); } users_cursor.set(page.next_cursor); } Err(err) => users_error.set(Some(format!("Failed to load users: {}", err))), } users_loading.set(false); }); }); let fetch_channels: Arc = Arc::new(move |reset: bool| { if channels_loading.get() { return; } channels_loading.set(true); channels_error.set(None); let cursor = if reset { None } else { channels_cursor.get() }; let search = channels_search.get(); spawn_local(async move { let search_ref = (!search.trim().is_empty()).then_some(search.trim()); match crate::api::dashboard::get_dashboard_channels(Some(20), cursor.as_deref(), search_ref, None).await { Ok(page) => { if reset { channels.set(page.data); } else { let mut current = channels.get(); current.extend(page.data); channels.set(current); } channels_cursor.set(page.next_cursor); } Err(err) => channels_error.set(Some(format!("Failed to load channels: {}", err))), } channels_loading.set(false); }); }); { let fetch_stats = fetch_stats.clone(); let fetch_users = fetch_users.clone(); let fetch_channels = fetch_channels.clone(); create_effect(move |_| { fetch_stats(); fetch_users(true); fetch_channels(true); }); } view! {

"Dashboard Guild"

"Pantau statistik, profil pengguna, dan aktivitas kanal komunitas IMPHNEN."

} } #[component] fn DashboardTabButton( tab: DashboardTab, active_tab: RwSignal, label: &'static str, icon: &'static str, ) -> impl IntoView { let tab_for_class = tab.clone(); let tab_for_aria = tab.clone(); let tab_for_click = tab; view! { } }