Last active
January 13, 2024 11:40
-
-
Save Enigo/907643366a7cd9f9a84bab0ecd77682e to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use crate::view::loading::LoadingSpinnerGrayNoVh; | |
use crate::Route; | |
use gloo_timers::callback::Timeout; | |
use log::error; | |
use model::model::search::SearchData; | |
use web_sys::wasm_bindgen::JsCast; | |
use web_sys::HtmlInputElement; | |
use yew::prelude::*; | |
use yew_router::prelude::*; | |
#[function_component(Search)] | |
pub fn search() -> Html { | |
let search = use_state(|| String::new()); | |
let search_data = use_state(|| None); | |
let typed_state = use_state(|| false); | |
{ | |
let search = search.clone(); | |
let search_data = search_data.clone(); | |
use_effect_with((search.clone(), *typed_state), move |_| { | |
if !search.is_empty() { | |
let search = search.clone(); | |
wasm_bindgen_futures::spawn_local(async move { | |
match fetch_single_api_response( | |
format!("search?search={}", search.as_str()).as_str(), | |
) | |
.await | |
{ | |
Ok(fetched_search) => { | |
search_data.set(Some(fetched_search)); | |
} | |
Err(e) => { | |
error!("{e}") | |
} | |
} | |
}); | |
} | |
}); | |
} | |
let timeout_state = use_state(|| None); | |
let typed_state_clone = typed_state.clone(); | |
let search_data_clone = search_data.clone(); | |
let search_clone = search.clone(); | |
let oninput = Callback::from(move |e: InputEvent| { | |
if let Some(target) = e.target() { | |
let input = target.dyn_into::<HtmlInputElement>().ok(); | |
if let Some(input) = input { | |
let value = input.value(); | |
if value.is_empty() { | |
search_data_clone.set(None); | |
typed_state_clone.set(false); | |
} else { | |
typed_state_clone.set(true); | |
search_data_clone.set(None); | |
let prev_timeout = timeout_state.clone(); | |
if prev_timeout.is_some() { | |
drop(prev_timeout); | |
} | |
let search = search_clone.clone(); | |
let timeout = Timeout::new(1_000, move || { | |
search.set(value); | |
}); | |
timeout_state.set(Some(timeout)); | |
} | |
} | |
} | |
}); | |
let onsubmit = Callback::from(|e: SubmitEvent| { | |
e.prevent_default(); | |
}); | |
let typed_state_clone = typed_state.clone(); | |
let onfocusin = Callback::from(move |e: FocusEvent| { | |
if let Some(target) = e.target() { | |
let input = target.dyn_into::<HtmlInputElement>().ok(); | |
if let Some(input) = input { | |
let value = input.value(); | |
if !value.is_empty() { | |
typed_state_clone.set(true); | |
search.set(value); | |
} | |
} | |
} | |
}); | |
let typed_state_clone = typed_state.clone(); | |
let search_data_clone = search_data.clone(); | |
let onfocusout = Callback::from(move |_| { | |
let typed_state_clone = typed_state_clone.clone(); | |
let search_data_clone = search_data_clone.clone(); | |
Timeout::new(150, move || { | |
search_data_clone.set(None); | |
typed_state_clone.set(false); | |
}) | |
.forget(); | |
}); | |
let typed_state_clone = typed_state.clone(); | |
let search_data_clone = search_data.clone(); | |
let onclick = Callback::from(move |_| { | |
search_data_clone.set(None); | |
typed_state_clone.set(false); | |
}); | |
let search_result_html = match (*search_data).as_ref() { | |
Some(search_data) => { | |
if search_data.asset_content_data.is_empty() { | |
html! {<li><p class="dropdown-item text-white my-2">{"No results found..."}</p></li>} | |
} else { | |
search_data.asset_content_data.iter().map(|asset| { | |
let onclick = onclick.clone(); | |
html!( | |
<li> | |
<div class="align-items-center text-center text-white m-3" {onclick}> | |
<Link<Route> to={Route::Asset {token_address: asset.token_address.to_string(), token_id: asset.token_id} }> | |
<img src={asset.image_url.clone()} class="img-fluid" width="50%"/> | |
</Link<Route>> | |
<p class="m-0">{asset.name.clone()}</p> | |
</div> | |
</li> | |
) | |
}).collect::<Html>() | |
} | |
} | |
None => { | |
html! { | |
<LoadingSpinnerGrayNoVh /> | |
} | |
} | |
}; | |
html! { | |
<div class="row"> | |
<div class="col-md-8"> | |
<form class="input-group bg-dark border border-white rounded" {onsubmit} {onfocusin} {onfocusout}> | |
<input id="search" type="search" autocomplete="off" class="form-control bg-dark border-0 text-white shadow-none" placeholder="Token Id or Name" aria-label="Search" | |
{oninput}/> | |
<span class="input-group-text bg-dark border-0 rounded text-white"><i class="fas fa-search"></i></span> | |
<div class="w-100"> | |
<ul class={format!("dropdown-menu bg-gray border border-top-0 border-1 border-white w-100 max-vh-90 p-0 overflow-auto {}", if *typed_state.clone() {"show"} else {"hide"})}> | |
{ search_result_html } | |
</ul> | |
</div> | |
</form> | |
</div> | |
</div> | |
} | |
} | |
async fn fetch_single_api_response(endpoint: &str) -> reqwest::Result<SearchData> { | |
let result = reqwest::get(format!("http://localhost:8081/api/{}", endpoint)) | |
.await? | |
.json::<SearchData>() | |
.await?; | |
return Ok(result); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment