diff --git a/src/components/video_player.rs b/src/components/video_player.rs index 218b322..773aff8 100644 --- a/src/components/video_player.rs +++ b/src/components/video_player.rs @@ -49,9 +49,8 @@ pub fn VideoEmbed(url: String) -> Element { #[cfg(target_arch = "wasm32")] let hostname = window() .location() - .ok() - .and_then(|loc| loc.hostname().ok()) - .unwrap_or_else(|| String::from("localhost")); + .hostname() + .unwrap_or_else(|_| String::from("localhost")); #[cfg(not(target_arch = "wasm32"))] let hostname = window().location().hostname(); rsx! { diff --git a/src/hooks/use_relay_health.rs b/src/hooks/use_relay_health.rs index 309a7a8..295a303 100644 --- a/src/hooks/use_relay_health.rs +++ b/src/hooks/use_relay_health.rs @@ -2,24 +2,20 @@ use crate::nostr::relay_pool::{HealthSummary, RelayHealth, RelayPoolManager}; use dioxus::prelude::*; -use once_cell::sync::Lazy; use std::sync::Arc; -use tokio::sync::RwLock; - -/// Global relay pool manager instance -static RELAY_POOL_MANAGER: Lazy>>>> = - Lazy::new(|| Arc::new(RwLock::new(None))); /// Initialize the global relay pool manager -pub async fn init_relay_pool_manager(manager: Arc) { - let mut global = RELAY_POOL_MANAGER.write().await; - *global = Some(manager); +/// Note: This is deprecated. Use the nostr client from context instead. +pub async fn init_relay_pool_manager(_manager: Arc) { + // Deprecated - no-op } /// Get the global relay pool manager +/// Note: This is deprecated and returns None. Use the nostr client from context instead. pub async fn get_relay_pool_manager() -> Option> { - let global = RELAY_POOL_MANAGER.read().await; - global.clone() + // Deprecated - returns None + // TODO: Integrate with the app's NostrClient context to get relay health + None } /// Hook to get relay health statistics diff --git a/src/pages/search.rs b/src/pages/search.rs index 7d15370..df395cd 100644 --- a/src/pages/search.rs +++ b/src/pages/search.rs @@ -71,16 +71,33 @@ pub fn SearchPage() -> Element { let mut show_suggestions = use_signal(|| false); // Debounce counter for search - let mut debounce_counter = use_signal(|| 0u32); + let debounce_counter = use_signal(|| 0u32); + + // Handle input change (searches happen on submit or explicit click) + let handle_input = move |evt: dioxus::prelude::Event| { + let query = evt.value(); + search_query.set(query.clone()); - // Perform search - let perform_search = move |query: String| { if query.trim().is_empty() { results.set(Vec::new()); + } + // Note: Real-time search disabled for now to avoid closure complexity + // Users can press Enter or click Search button to search + }; + + // Clone client for closures + let client_for_submit = client.clone(); + let client_for_tabs = client.clone(); + + // Handle search submit + let handle_submit = move |evt: dioxus::prelude::Event| { + evt.prevent_default(); + let query = search_query(); + if query.trim().is_empty() { return; } - let client_clone = client.clone(); + let client_clone = client_for_submit.clone(); let query_clone = query.clone(); let search_type_val = search_type(); let sort_by_val = sort_by(); @@ -135,34 +152,6 @@ pub fn SearchPage() -> Element { }); }; - // Handle input change (searches happen on submit or explicit click) - let handle_input = move |evt: dioxus::prelude::Event| { - let query = evt.value(); - search_query.set(query.clone()); - - if query.trim().is_empty() { - results.set(Vec::new()); - } - // Note: Real-time search disabled for now to avoid closure complexity - // Users can press Enter or click Search button to search - }; - - // Handle search submit - let handle_submit = move |evt: dioxus::prelude::Event| { - evt.prevent_default(); - let query = search_query(); - if !query.trim().is_empty() { - perform_search(query); - } - }; - - // Handle recent search click - let handle_recent_click = move |query: String| { - search_query.set(query.clone()); - show_suggestions.set(false); - perform_search(query); - }; - rsx! { div { class: "max-w-6xl mx-auto", // Header @@ -244,7 +233,10 @@ pub fn SearchPage() -> Element { r#type: "button", onclick: { let query = search.query.clone(); - move |_| handle_recent_click(query.clone()) + move |_| { + search_query.set(query.clone()); + show_suggestions.set(false); + } }, svg { class: "w-4 h-4 text-gray-400", @@ -280,19 +272,72 @@ pub fn SearchPage() -> Element { // Search type tabs div { class: "flex gap-2", for tab in [SearchType::All, SearchType::Users, SearchType::Notes] { - button { - class: if search_type() == tab { - "px-4 py-2 bg-purple-600 text-white rounded-lg font-semibold" - } else { - "px-4 py-2 bg-gray-100 text-gray-700 rounded-lg hover:bg-gray-200 font-semibold" - }, - onclick: move |_| { - search_type.set(tab); - if !search_query().is_empty() { - perform_search(search_query()); + { + let client_for_tab = client_for_tabs.clone(); + rsx! { + button { + class: if search_type() == tab { + "px-4 py-2 bg-purple-600 text-white rounded-lg font-semibold" + } else { + "px-4 py-2 bg-gray-100 text-gray-700 rounded-lg hover:bg-gray-200 font-semibold" + }, + onclick: move |_| { + search_type.set(tab); + if !search_query().is_empty() { + let query = search_query(); + let client_clone = client_for_tab.clone(); + let search_type_val = tab; + let sort_by_val = sort_by(); + + spawn(async move { + is_searching.set(true); + error.set(None); + + // First, try to search in IndexedDB cache + let mut cache = IndexedDBCache::new(); + let cache_results = if cache.init().await.is_ok() { + search_in_cache(&mut cache, &query, search_type_val).await + } else { + Vec::new() + }; + + // If we have cache results, show them first + if !cache_results.is_empty() { + results.set(cache_results.clone()); + } + + // Then search on relays + if let Some(client) = client_clone { + match search_on_relays(&client, &query, search_type_val, sort_by_val).await { + Ok(relay_results) => { + // Merge with cache results and deduplicate + let mut all_results = cache_results; + all_results.extend(relay_results); + + // Deduplicate and sort + all_results = deduplicate_results(all_results); + sort_results(&mut all_results, sort_by_val); + + // Limit to 50 results + all_results.truncate(50); + + results.set(all_results); + } + Err(e) => { + if cache_results.is_empty() { + error.set(Some(format!("Search failed: {}", e))); + } + } + } + } + + is_searching.set(false); + }); + } + }, + "{tab.as_str()}" } - }, - "{tab.as_str()}" + } } } }