add meal carry over feature
This commit is contained in:
+89
-1
@@ -1307,7 +1307,10 @@ pub fn list_meals_panel(
|
||||
}
|
||||
}
|
||||
@if editable {
|
||||
button class="button button-small add-meal-button" hx-get=(format!("/meals?picker={}", list_id)) hx-target="#meal-picker" hx-swap="innerHTML" { "+ Add meal" }
|
||||
div class="list-meals-actions" {
|
||||
button class="button button-small add-meal-button" hx-get=(format!("/meals?picker={}", list_id)) hx-target="#meal-picker" hx-swap="innerHTML" { "+ Add meal" }
|
||||
button class="button button-small carry-over-button" hx-get=(format!("/lists/{}/carry", list_id)) hx-target="#meal-picker" hx-swap="innerHTML" { "Carry over" }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1322,6 +1325,91 @@ pub fn list_meals_panel(
|
||||
}
|
||||
}
|
||||
|
||||
/// The carry-over modal: a picker of active source lists (newest first,
|
||||
/// excluding the current list) that the user can import meals from.
|
||||
pub fn carry_over_modal(sources: &[GroceryList], dest_list_id: i64) -> Markup {
|
||||
html! {
|
||||
div class="meal-picker-backdrop" onclick="if (event.target === this) this.remove()" {
|
||||
div class="meal-picker-modal" role="dialog" aria-modal="true" aria-label="Carry over meals" {
|
||||
div class="meal-picker-header" {
|
||||
div {
|
||||
p class="eyebrow" { "CARRY OVER" }
|
||||
h2 { "Carry over meals" }
|
||||
}
|
||||
button class="meal-picker-close" type="button" aria-label="Close" onclick="this.closest('.meal-picker-backdrop').remove()" { "✕" }
|
||||
}
|
||||
p class="muted carry-intro" { "Import meals from another list. Their ingredients are not re-added — they were already purchased." }
|
||||
@if sources.is_empty() {
|
||||
div class="meal-picker-empty" {
|
||||
p { "No other lists to carry from." }
|
||||
}
|
||||
} @else {
|
||||
div class="carry-source-picker" {
|
||||
label for="carry-source" { "From list" }
|
||||
select
|
||||
id="carry-source"
|
||||
name="source"
|
||||
hx-get=(format!("/lists/{}/carry/meals", dest_list_id))
|
||||
hx-trigger="change"
|
||||
hx-target="#carry-results"
|
||||
hx-swap="innerHTML"
|
||||
{
|
||||
option value="" selected disabled { "Choose a list…" }
|
||||
@for source in sources {
|
||||
option value=(source.id) { (source.name) }
|
||||
}
|
||||
}
|
||||
}
|
||||
div id="carry-results" class="carry-results" {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The selectable meal rows for a chosen source list inside the carry modal.
|
||||
pub fn carry_source_meals(
|
||||
list_meals: &[ListMeal],
|
||||
source_id: i64,
|
||||
dest_list_id: i64,
|
||||
csrf_token: &str,
|
||||
) -> Markup {
|
||||
html! {
|
||||
@if list_meals.is_empty() {
|
||||
div class="meal-picker-empty" {
|
||||
p { "This list has no meals to carry over." }
|
||||
}
|
||||
} @else {
|
||||
form
|
||||
hx-post=(format!("/lists/{}/carry", dest_list_id))
|
||||
hx-target="#list-items"
|
||||
hx-swap="morph:outerHTML"
|
||||
hx-on::after-request="if (event.detail.successful) this.closest('.meal-picker-backdrop').remove()"
|
||||
class="carry-form"
|
||||
{
|
||||
input type="hidden" name="csrf" value=(csrf_token);
|
||||
input type="hidden" name="source_list_id" value=(source_id);
|
||||
// Collected as a comma-separated list by the checkboxes below;
|
||||
// the form extractor does not coalesce repeated keys into a Vec.
|
||||
input id="carry-selected" type="hidden" name="list_meal_ids" value="";
|
||||
div class="carry-list" {
|
||||
@for meal in list_meals {
|
||||
label class="carry-row" {
|
||||
input
|
||||
type="checkbox"
|
||||
value=(meal.id)
|
||||
onchange="var form=this.closest('form'); var box=form.querySelector('#carry-selected'); box.value=Array.from(form.querySelectorAll('input[type=checkbox]:checked')).map(function(c){return c.value}).join(',');";
|
||||
span class="carry-row-icon" { "🍽" }
|
||||
span class="carry-row-name" { (meal.name) }
|
||||
}
|
||||
}
|
||||
}
|
||||
button class="button button-primary carry-submit" type="submit" { "Carry over" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn presence_panel(presence: &[PresenceUser], out_of_band: bool) -> Markup {
|
||||
if out_of_band {
|
||||
html! {
|
||||
|
||||
Reference in New Issue
Block a user