Ingredients can now be remove from shopping list when a recipe is unscheduled.

This commit is contained in:
Greg Burri 2025-02-12 02:05:38 +01:00
parent a3f2b4a86a
commit da5ea57787
7 changed files with 92 additions and 36 deletions

View file

@ -795,7 +795,7 @@ VALUES ($1, $2)
recipe_id: i64,
date: NaiveDate,
servings: u32,
add_ingredients_element: bool,
add_ingredients_to_shopping_list: bool,
) -> Result<AddScheduledRecipeResult> {
let mut tx = self.tx().await?;
@ -823,7 +823,7 @@ VALUES ($1, $2, $3, $4)
}
Ok(insert_result) => {
if add_ingredients_element {
if add_ingredients_to_shopping_list {
sqlx::query(
r#"
INSERT INTO [ShoppingEntry] ([ingredient_id], [user_id], [recipe_scheduled_id], [servings])
@ -853,7 +853,27 @@ INSERT INTO [ShoppingEntry] ([ingredient_id], [user_id], [recipe_scheduled_id],
user_id: i64,
recipe_id: i64,
date: NaiveDate,
remove_ingredients_from_shopping_list: bool,
) -> Result<()> {
let mut tx = self.tx().await?;
if remove_ingredients_from_shopping_list {
sqlx::query(
r#"
DELETE FROM [ShoppingEntry]
WHERE [recipe_scheduled_id] IN (
SELECT [id] FROM [RecipeScheduled]
WHERE [user_id] = $1 AND [recipe_id] = $2 AND [date] = $3
)
"#,
)
.bind(user_id)
.bind(recipe_id)
.bind(date)
.execute(&mut *tx)
.await?;
}
sqlx::query(
r#"
DELETE FROM [RecipeScheduled]
@ -863,10 +883,12 @@ INSERT INTO [ShoppingEntry] ([ingredient_id], [user_id], [recipe_scheduled_id],
.bind(user_id)
.bind(recipe_id)
.bind(date)
.execute(&self.pool)
.await
.map(|_| ())
.map_err(DBError::from)
.execute(&mut *tx)
.await?;
tx.commit().await?;
Ok(())
}
pub async fn get_scheduled_recipes(

View file

@ -681,12 +681,17 @@ pub async fn schedule_recipe(
pub async fn rm_scheduled_recipe(
State(connection): State<db::Connection>,
Extension(user): Extension<Option<model::User>>,
ExtractRon(ron): ExtractRon<common::ron_api::ScheduledRecipe>,
ExtractRon(ron): ExtractRon<common::ron_api::RemoveScheduledRecipe>,
) -> Result<impl IntoResponse> {
check_user_rights_recipe(&connection, &user, ron.recipe_id).await?;
if let Some(user) = user {
connection
.rm_scheduled_recipe(user.id, ron.recipe_id, ron.date)
.rm_scheduled_recipe(
user.id,
ron.recipe_id,
ron.date,
ron.remove_ingredients_from_shopping_list,
)
.await?;
}
Ok(StatusCode::OK)

View file

@ -146,6 +146,7 @@ pub enum Sentence {
CalendarAddToPlannerAlreadyExists,
CalendarDateFormat, // See https://docs.rs/chrono/latest/chrono/format/strftime/index.html.
CalendarAddIngredientsToShoppingList,
CalendarRemoveIngredientsFromShoppingList,
CalendarUnscheduleConfirmation,
}

View file

@ -50,7 +50,18 @@
<div class="scheduled-recipe-with-link-and-remove"><a></a><span class="remove-scheduled-recipe">X</span></div>
<div class="scheduled-recipe"></div>
<span class="unschedule-confirmation">{{ tr.t(Sentence::CalendarUnscheduleConfirmation) }}</span>
<div class="unschedule-confirmation">
<div>{{ tr.t(Sentence::CalendarUnscheduleConfirmation) }}</div>
<input
id="input-remove-ingredients-from-shopping-list"
type="checkbox"
checked
/>
<label for="input-remove-ingredients-from-shopping-list">
{{ tr.t(Sentence::CalendarRemoveIngredientsFromShoppingList) }}
</label>
</div>
<span class="calendar-date-format">{{ tr.t(Sentence::CalendarDateFormat) }}</span>
</div>
</div>

View file

@ -130,6 +130,7 @@
(CalendarAddToPlannerAlreadyExists, "Recipe {title} has already been scheduled for {date}"),
(CalendarDateFormat, "%A, %-d %B, %C%y"), // See https://docs.rs/chrono/latest/chrono/format/strftime/index.html.
(CalendarAddIngredientsToShoppingList, "Add ingredients to shopping list"),
(CalendarRemoveIngredientsFromShoppingList, "Remove ingredients from shopping list"),
(CalendarUnscheduleConfirmation, "Are you sure to remove {title} on {date}"),
]
),
@ -264,6 +265,7 @@
(CalendarAddToPlannerAlreadyExists, "La recette {title} a été déjà été agendée pour le {date}"),
(CalendarDateFormat, "%A %-d %B %C%y"), // See https://docs.rs/chrono/latest/chrono/format/strftime/index.html.
(CalendarAddIngredientsToShoppingList, "Ajouter les ingrédients à la liste de course"),
(CalendarRemoveIngredientsFromShoppingList, "Enlever les ingrédients de la liste de course"),
(CalendarUnscheduleConfirmation, "Êtes-vous sûr de vouloir enlever {title} du {date}"),
]
)

View file

@ -204,9 +204,10 @@ pub enum ScheduleRecipeResult {
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct ScheduledRecipe {
pub struct RemoveScheduledRecipe {
pub recipe_id: i64,
pub date: NaiveDate,
pub remove_ingredients_from_shopping_list: bool,
}
/*** Shopping list ***/

View file

@ -2,11 +2,15 @@ use std::{cell::RefCell, rc::Rc};
use chrono::{offset::Local, Datelike, Days, Months, NaiveDate, Weekday};
use common::{ron_api, utils::substitute_with_names};
use gloo::{console::log, events::EventListener, utils::document};
use gloo::{
console::log,
events::EventListener,
utils::{document, window},
};
use scanf::sscanf;
use wasm_bindgen::prelude::*;
use wasm_bindgen_futures::spawn_local;
use web_sys::Element;
use web_sys::{Element, HtmlInputElement};
use crate::{
modal_dialog,
@ -140,11 +144,13 @@ pub fn setup(
let title = target.previous_element_sibling().unwrap().inner_html();
if modal_dialog::show_and_initialize(
if let Some(remove_ingredients_from_shopping_list) =
modal_dialog::show_and_initialize_with_ok(
"#hidden-templates-calendar .unschedule-confirmation",
async |element| {
let date_format =
selector::<Element>("#hidden-templates-calendar .calendar-date-format")
let date_format = selector::<Element>(
"#hidden-templates-calendar .calendar-date-format",
)
.inner_html();
element.set_inner_html(&substitute_with_names(
&element.inner_html(),
@ -157,14 +163,22 @@ pub fn setup(
],
));
},
|element, _| {
let remove_ingredients_element: HtmlInputElement =
element.selector("#input-remove-ingredients-from-shopping-list");
remove_ingredients_element.checked()
},
)
.await
.is_some()
{
let body = ron_api::ScheduledRecipe { recipe_id, date };
let body = ron_api::RemoveScheduledRecipe {
recipe_id,
date,
remove_ingredients_from_shopping_list,
};
let _ =
request::delete::<(), _>("calendar/remove_scheduled_recipe", body).await;
target.parent_element().unwrap().remove();
window().location().reload().unwrap();
}
});
}