Add a bit more structure to searching.

This commit is contained in:
Bill Thiede 2023-03-11 21:15:59 -08:00
parent cb8b00f8d1
commit 4390d24492

View File

@ -14,6 +14,8 @@ use seed::{prelude::*, *};
use serde::de::Deserialize; use serde::de::Deserialize;
use wasm_timer::Instant; use wasm_timer::Instant;
const SEARCH_RESULTS_PER_PAGE: usize = 20;
// ------ ------ // ------ ------
// Init // Init
// ------ ------ // ------ ------
@ -32,12 +34,23 @@ fn init(url: Url, orders: &mut impl Orders<Msg>) -> Model {
orders.send_msg(Msg::ShowPrettyRequest(tid)); orders.send_msg(Msg::ShowPrettyRequest(tid));
} }
Some("s") => { Some("s") => {
query = url.next_hash_path_part().unwrap_or("").to_string(); query = url
orders.send_msg(Msg::SearchRequest(query.clone())); .next_hash_path_part()
.map(|q| Url::decode_uri_component(q).unwrap_or("".to_string()))
.unwrap_or("".to_string());
orders.send_msg(Msg::SearchRequest {
query: query.to_string(),
page: 0,
results_per_page: SEARCH_RESULTS_PER_PAGE,
});
} }
p => { p => {
log!(p); log!(p);
orders.send_msg(Msg::SearchRequest("".to_string())); orders.send_msg(Msg::SearchRequest {
query: "".to_string(),
page: 0,
results_per_page: SEARCH_RESULTS_PER_PAGE,
});
} }
}; };
orders.subscribe(|uc: subs::UrlChanged| { orders.subscribe(|uc: subs::UrlChanged| {
@ -85,7 +98,11 @@ enum Msg {
Noop, Noop,
RefreshStart, RefreshStart,
RefreshDone(Option<FetchError>), RefreshDone(Option<FetchError>),
SearchRequest(String), SearchRequest {
query: String,
page: usize,
results_per_page: usize,
},
SearchResult(fetch::Result<shared::SearchResult>), SearchResult(fetch::Result<shared::SearchResult>),
ShowRequest(String), ShowRequest(String),
ShowResult(fetch::Result<ThreadSet>), ShowResult(fetch::Result<ThreadSet>),
@ -111,14 +128,18 @@ fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
}; };
} }
Msg::SearchRequest(query) => { Msg::SearchRequest {
info!("searching for '{query}'"); query,
page,
results_per_page,
} => {
info!("searching for '{query}' pg {page} # / pg {results_per_page}");
model.query = query.clone(); model.query = query.clone();
let url = Url::new().set_hash_path(["s", &query]); let url = Url::new().set_hash_path(["s", &query]);
orders.request_url(url); orders.request_url(url);
orders orders.skip().perform_cmd(async move {
.skip() Msg::SearchResult(search_request(&query, page, results_per_page).await)
.perform_cmd(async move { Msg::SearchResult(search_request(&query).await) }); });
} }
Msg::SearchResult(Ok(response_data)) => { Msg::SearchResult(Ok(response_data)) => {
debug!("fetch ok {:#?}", response_data); debug!("fetch ok {:#?}", response_data);
@ -160,12 +181,11 @@ fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
Msg::NextPage => { Msg::NextPage => {
match &model.context { match &model.context {
Context::Search(sr) => { Context::Search(sr) => {
orders.send_msg(Msg::SearchRequest(format!( orders.send_msg(Msg::SearchRequest {
"{}?page={}&results_per_page={}", query: sr.query.clone(),
Url::encode_uri_component(&sr.query), page: sr.page + 1,
sr.page + 1, results_per_page: sr.results_per_page,
sr.results_per_page });
)));
} }
Context::Thread(_) => (), // do nothing (yet?) Context::Thread(_) => (), // do nothing (yet?)
Context::None => (), // do nothing (yet?) Context::None => (), // do nothing (yet?)
@ -174,12 +194,11 @@ fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
Msg::PreviousPage => { Msg::PreviousPage => {
match &model.context { match &model.context {
Context::Search(sr) => { Context::Search(sr) => {
orders.send_msg(Msg::SearchRequest(format!( orders.send_msg(Msg::SearchRequest {
"{}?page={}&results_per_page={}", query: sr.query.clone(),
Url::encode_uri_component(&sr.query), page: sr.page.saturating_sub(1),
sr.page.saturating_sub(1), results_per_page: sr.results_per_page,
sr.results_per_page });
)));
} }
Context::Thread(_) => (), // do nothing (yet?) Context::Thread(_) => (), // do nothing (yet?)
Context::None => (), // do nothing (yet?) Context::None => (), // do nothing (yet?)
@ -188,8 +207,12 @@ fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
} }
} }
async fn search_request(query: &str) -> fetch::Result<shared::SearchResult> { async fn search_request(
Request::new(api::search(query)) query: &str,
page: usize,
results_per_page: usize,
) -> fetch::Result<shared::SearchResult> {
Request::new(api::search(query, page, results_per_page))
.method(Method::Get) .method(Method::Get)
.fetch() .fetch()
.await? .await?
@ -199,12 +222,15 @@ async fn search_request(query: &str) -> fetch::Result<shared::SearchResult> {
} }
mod api { mod api {
use seed::Url;
const BASE_URL: &str = "/api"; const BASE_URL: &str = "/api";
pub fn refresh() -> String { pub fn refresh() -> String {
format!("{BASE_URL}/refresh") format!("{BASE_URL}/refresh")
} }
pub fn search(query: &str) -> String { pub fn search(query: &str, page: usize, results_per_page: usize) -> String {
format!("{BASE_URL}/search/{query}") let query = Url::encode_uri_component(query);
format!("{BASE_URL}/search/{query}?page={page}&results_per_page={results_per_page}")
} }
pub fn show(tid: &str) -> String { pub fn show(tid: &str) -> String {
format!("{BASE_URL}/show/{tid}") format!("{BASE_URL}/show/{tid}")
@ -400,9 +426,11 @@ fn tags_chiclet(tags: &[String], is_mobile: bool) -> impl Iterator<Item = Node<M
"replied" => span![classes, style, i![C!["fa-solid", "fa-reply"]]], "replied" => span![classes, style, i![C!["fa-solid", "fa-reply"]]],
_ => span![classes, style, &tag], _ => span![classes, style, &tag],
}, },
ev(Ev::Click, move |_| Msg::SearchRequest( ev(Ev::Click, move |_| Msg::SearchRequest {
Url::encode_uri_component(format!("tag:{tag}")) query: format!("tag:{tag}"),
)), page: 0,
results_per_page: SEARCH_RESULTS_PER_PAGE,
})
] ]
}) })
} }
@ -621,12 +649,20 @@ fn view_header(query: &str, refresh_request: &RefreshingState) -> Node<Msg> {
a![ a![
C!["navbar-item", "button"], C!["navbar-item", "button"],
"Unread", "Unread",
ev(Ev::Click, |_| Msg::SearchRequest("is:unread".to_string())), ev(Ev::Click, |_| Msg::SearchRequest {
query: "is:unread".to_string(),
page: 0,
results_per_page: SEARCH_RESULTS_PER_PAGE,
}),
], ],
a![ a![
C!["navbar-item", "button"], C!["navbar-item", "button"],
"All", "All",
ev(Ev::Click, |_| Msg::SearchRequest("".to_string())), ev(Ev::Click, |_| Msg::SearchRequest {
query: "".to_string(),
page: 0,
results_per_page: SEARCH_RESULTS_PER_PAGE,
}),
], ],
input![ input![
C!["navbar-item", "input"], C!["navbar-item", "input"],
@ -635,12 +671,18 @@ fn view_header(query: &str, refresh_request: &RefreshingState) -> Node<Msg> {
At::AutoFocus => true.as_at_value(); At::AutoFocus => true.as_at_value();
At::Value => query, At::Value => query,
}, },
input_ev(Ev::Input, |q| Msg::SearchRequest( input_ev(Ev::Input, |q| Msg::SearchRequest {
Url::encode_uri_component(q) query: Url::encode_uri_component(q),
)), page: 0,
results_per_page: SEARCH_RESULTS_PER_PAGE,
}),
// Resend search on enter. // Resend search on enter.
keyboard_ev(Ev::KeyUp, move |e| if e.key_code() == 0x0d { keyboard_ev(Ev::KeyUp, move |e| if e.key_code() == 0x0d {
Msg::SearchRequest(Url::encode_uri_component(query)) Msg::SearchRequest {
query: Url::encode_uri_component(query),
page: 0,
results_per_page: SEARCH_RESULTS_PER_PAGE,
}
} else { } else {
Msg::Noop Msg::Noop
}), }),