meal filtering feature
ci/woodpecker/push/fmt Pipeline was successful
ci/woodpecker/push/test Pipeline failed

This commit is contained in:
2026-08-08 16:19:49 -04:00
parent 975cf38170
commit 35de0e1990
7 changed files with 274 additions and 56 deletions
+39 -2
View File
@@ -340,6 +340,7 @@ struct AddMealForm {
#[derive(Debug, Deserialize)]
struct MealPickerQuery {
picker: Option<i64>,
q: Option<String>,
}
async fn home() -> Redirect {
@@ -897,15 +898,50 @@ async fn meals_page(
State(state): State<AppState>,
user: CurrentUser,
Query(query): Query<MealPickerQuery>,
headers: HeaderMap,
) -> Result<Response, AppError> {
let meals = state.meals.list_meals().await?;
let q = query.q.clone().unwrap_or_default();
let meals = state.meals.list_meals(&q).await?;
let meal_categories = state.meals.list_meal_categories().await?;
let is_htmx = headers
.get("hx-request")
.and_then(|value| value.to_str().ok())
.is_some_and(|value| value == "true");
// A boosted navigation (e.g. the category form's POST redirect) also sends
// `HX-Request: true`, but must render the full page, not just the results
// fragment. Only a live search (an `hx-get` on the filter box) swaps the
// fragment. htmx marks boosted requests with `HX-Boosted: true`.
let is_boosted = headers
.get("hx-boosted")
.and_then(|value| value.to_str().ok())
.is_some_and(|value| value == "true");
if let Some(list_id) = query.picker {
return Ok(html_response(views::meal_picker(
if query.q.is_some() {
// Live search inside the picker: swap only the grouped rows, keeping
// the modal and search box focused. The initial picker load has no
// `q`, so it falls through to the full modal below.
return Ok(html_response(views::meal_picker_results(
&meals,
&meal_categories,
list_id,
&user.session.csrf_token,
)));
}
let picker = views::meal_picker(
&meals,
&meal_categories,
list_id,
&user.session.csrf_token,
&q,
);
return Ok(html_response(picker));
}
if is_htmx && !is_boosted {
// Live search on the meals page: swap only the grouped results.
return Ok(html_response(views::meal_results(
&meals,
&meal_categories,
&q,
)));
}
Ok(html_response(views::meals_page(
@@ -913,6 +949,7 @@ async fn meals_page(
&meals,
&meal_categories,
&user.session.csrf_token,
&q,
)))
}