diff --git a/backend/sql/version_1.sql b/backend/sql/version_1.sql
index 640fb9e..19b233c 100644
--- a/backend/sql/version_1.sql
+++ b/backend/sql/version_1.sql
@@ -257,9 +257,7 @@ CREATE TABLE [ShoppingEntry] (
-- In both cases [name], [quantity_value], [quantity_unit] and [Servings] are used to display
-- the entry instead of [Ingredient] data.
[ingredient_id] INTEGER,
-
- -- Can be null when manually added (entry is not linked to a recipe).
- [recipe_scheduled_id] INTEGER,
+ [recipe_scheduled_id] INTEGER, -- Can be null when manually added.
[is_checked] INTEGER NOT NULL DEFAULT FALSE,
@@ -271,7 +269,16 @@ CREATE TABLE [ShoppingEntry] (
CHECK (
length([name]) <= 255 AND
- ([is_checked] = TRUE OR [is_checked] = FALSE)
+ ([is_checked] = TRUE OR [is_checked] = FALSE) AND
+ (
+ [recipe_scheduled_id] IS NULL OR
+ (
+ [name] = '' AND
+ [quantity_value] IS NULL AND
+ [quantity_unit] = '' AND
+ [servings] IS NULL
+ )
+ )
),
FOREIGN KEY([user_id]) REFERENCES [User]([id]) ON DELETE CASCADE,
diff --git a/backend/templates/calendar.html b/backend/templates/calendar.html
index b75fecb..b46d4bb 100644
--- a/backend/templates/calendar.html
+++ b/backend/templates/calendar.html
@@ -33,7 +33,7 @@
-
+
{% let day_names = [
Sentence::CalendarMondayAbbreviation,
Sentence::CalendarTuesdayAbbreviation,
@@ -52,10 +52,12 @@
{% endfor %}
- {# The last row may be hidden if 5 rows is enough to display all days. #}
- {% for i in 0..6 %}
+
+
+
+ {% for i in 0..5 %}
{% for j in 0..7 %}
- {# All days of the current selected month will have the class 'current-month'. #}
+ {# All days of the current selected month will have the class 'current-month' #}
-
@@ -66,7 +68,11 @@
-
✖{{ context.tr.t(Sentence::CalendarUnschedule) }}
+
✖
+
+ {{ context.tr.t(Sentence::CalendarUnschedule) }}
+
+
diff --git a/frontend/src/calendar.rs b/frontend/src/calendar.rs
index dfb97d4..23f5583 100644
--- a/frontend/src/calendar.rs
+++ b/frontend/src/calendar.rs
@@ -167,28 +167,22 @@ pub fn setup(
EventListener::new(&days, "click", move |event| {
let target: Element = event.target().unwrap().dyn_into().unwrap();
- // FIXME: Replace by an if let + condition when available in stable.
- match target.selector_upwards::
(".day") {
- Some(element) if options.can_select_date => {
- let first_day = first_grid_day(
- state_clone.get_displayed_date(),
- options.first_day_of_the_week,
- );
- let day_grid_id = element.id();
- let day_offset = day_grid_id[9..10].parse::().unwrap() * 7
- + day_grid_id[10..11].parse::().unwrap();
- state_clone.set_selected_date(first_day + Days::new(day_offset));
- display_month(
- &calendar_clone,
- state_clone.clone(),
- options,
- recipe_scheduler,
- );
- }
- _ => (),
- }
-
- if target.class_name().contains("remove-scheduled-recipe") {
+ if target.class_name() == "number" && options.can_select_date {
+ let first_day = first_grid_day(
+ state_clone.get_displayed_date(),
+ options.first_day_of_the_week,
+ );
+ let day_grid_id = target.parent_element().unwrap().id();
+ let day_offset = day_grid_id[9..10].parse::().unwrap() * 7
+ + day_grid_id[10..11].parse::().unwrap();
+ state_clone.set_selected_date(first_day + Days::new(day_offset));
+ display_month(
+ &calendar_clone,
+ state_clone.clone(),
+ options,
+ recipe_scheduler,
+ );
+ } else if target.class_name().contains("remove-scheduled-recipe") {
spawn_local(async move {
// Element id format example: "scheduled-recipe-1-2025-05-15".
let element_id = target.parent_element().unwrap().id();
@@ -245,6 +239,8 @@ pub fn setup(
state
}
+const NB_CALENDAR_ROW: u64 = 5;
+
fn display_month(
calendar: &Element,
state: CalendarState,
@@ -272,48 +268,34 @@ fn display_month(
let first_day = first_grid_day(date, options.first_day_of_the_week);
let mut current = first_day;
- let nb_of_weeks = {
- let nb_days_previous_month = if date.month0() == first_day.month0() {
- 0
- } else {
- (date.with_day(1).unwrap() - first_day).num_days()
- };
- if date.num_days_in_month() + nb_days_previous_month as u8 > 5 * 7 {
- 6
- } else {
- 5
- }
- };
-
- gloo::console::log!(nb_of_weeks);
-
- for i in 0..6 {
+ for i in 0..NB_CALENDAR_ROW {
for j in 0..7 {
let day_element: Element = by_id(&format!("day-grid-{}{}", i, j));
+
let day_content: Element = day_element.selector(".number");
+ day_content.set_inner_html(¤t.day().to_string());
- if i < nb_of_weeks {
- day_content.set_inner_html(¤t.day().to_string());
+ let mut class_name = String::new();
- let mut classes = vec!["day".to_string()];
-
- if current.month() == date.month() {
- classes.push("current-month".to_string());
+ if current.month() == date.month() {
+ if !class_name.is_empty() {
+ class_name += " ";
}
- if current == Local::now().date_naive() {
- classes.push("today".to_string());
- }
-
- if options.can_select_date && current == state.get_selected_date() {
- classes.push("selected-day".to_string());
- }
-
- day_element.set_class_name(&classes.join(" "));
- } else {
- gloo::console::log!("ok");
- day_element.set_class_name("");
- day_content.set_inner_html("");
+ class_name += "current-month";
}
+ if current == Local::now().date_naive() {
+ if !class_name.is_empty() {
+ class_name += " ";
+ }
+ class_name += "today";
+ }
+ if options.can_select_date && current == state.get_selected_date() {
+ if !class_name.is_empty() {
+ class_name += " ";
+ }
+ class_name += "selected-day"
+ }
+ day_element.set_class_name(&class_name);
current = current + Days::new(1);
}
@@ -322,7 +304,7 @@ fn display_month(
// Load and display scheduled recipes.
spawn_local(async move {
let scheduled_recipes = recipe_scheduler
- .get_scheduled_recipes(first_day, first_day + Days::new(nb_of_weeks * 7))
+ .get_scheduled_recipes(first_day, first_day + Days::new(NB_CALENDAR_ROW * 7))
.await
.unwrap();
diff --git a/frontend/src/utils.rs b/frontend/src/utils.rs
index e5929d4..ea68d51 100644
--- a/frontend/src/utils.rs
+++ b/frontend/src/utils.rs
@@ -14,10 +14,6 @@ pub trait SelectorExt {
where
T: JsCast;
- fn selector_upwards(&self, selector: &str) -> Option
- where
- T: JsCast;
-
fn deep_clone(&self) -> Self;
}
@@ -45,25 +41,6 @@ impl SelectorExt for Element {
.collect()
}
- fn selector_upwards(&self, selector: &str) -> Option
- where
- T: JsCast,
- {
- let mut current = self.clone();
- // while let Some(parent) = current.parent_element() {
- loop {
- if let Ok(true) = current.matches(selector) {
- return Some(current.dyn_into::().unwrap());
- }
-
- if let Some(parent) = current.parent_element() {
- current = parent;
- } else {
- return None;
- }
- }
- }
-
fn deep_clone(&self) -> Self {
self.clone_node_with_deep(true)
.unwrap()