* Support for lang in URL as /fr/recipe/view/42

* Create a pages module in the frontend crate
This commit is contained in:
Greg Burri 2025-03-26 01:49:02 +01:00
parent b812525f4b
commit 418d31a127
12 changed files with 117 additions and 80 deletions

110
frontend/src/pages/home.rs Normal file
View file

@ -0,0 +1,110 @@
use gloo::events::EventListener;
use wasm_bindgen::prelude::*;
use wasm_bindgen_futures::spawn_local;
use web_sys::{Element, HtmlInputElement};
use crate::{
calendar,
recipe_scheduler::RecipeScheduler,
shopping_list::ShoppingList,
utils::{SelectorExt, by_id, get_locale, selector},
};
pub fn setup_page(is_user_logged: bool) {
let recipe_scheduler = RecipeScheduler::new(!is_user_logged);
calendar::setup(
selector(".calendar"),
calendar::CalendarOptions {
can_select_date: false,
with_link_and_remove: true,
},
recipe_scheduler,
);
let shopping_list = ShoppingList::new(!is_user_logged);
spawn_local(async move {
let item_template: Element = selector("#hidden-templates .shopping-item");
let container: Element = by_id("shopping-list");
let container_checked: Element = by_id("shopping-list-checked");
let date_format =
selector::<Element>("#hidden-templates .calendar-date-format").inner_html();
for item in shopping_list.get_items().await.unwrap() {
let item_element = item_template.deep_clone();
// item_element.set_id(format!("shopping-item-{}", ));
item_element
.selector::<Element>(".item-name")
.set_inner_html(&item.name);
if let Some(quantity_value) = item.quantity_value {
item_element
.selector::<Element>(".item-quantity")
.set_inner_html(&format!("{} {}", quantity_value, item.quantity_unit));
}
// Display associated sheduled recipe information if it exists.
if let (Some(recipe_id), Some(recipe_title), Some(date)) =
(item.recipe_id, item.recipe_title, item.date)
{
let recipe_element = item_element.selector::<Element>(".item-scheduled-recipe a");
recipe_element.set_inner_html(&format!(
"{} @ {}",
recipe_title,
date.format_localized(&date_format, get_locale()),
));
recipe_element
.set_attribute("href", &format!("/recipe/view/{}", recipe_id))
.unwrap();
}
EventListener::new(
// TODO: Find the right place to move the item based on:
// 1) recipe id, 2) name, 3) shopping entry id
// Se shopping_list.rs@L30
&item_element.selector(".item-is-checked"),
"change",
move |event| {
let input: HtmlInputElement = event.target().unwrap().dyn_into().unwrap();
spawn_local(async move {
shopping_list
.set_item_checked(item.id, input.checked())
.await
.unwrap();
let item_element = input.parent_element().unwrap();
item_element.remove();
// TODO: Find the correct place to insert the element.
if input.checked() {
by_id::<Element>("shopping-list-checked")
.append_child(&item_element)
.unwrap();
} else {
by_id::<Element>("shopping-list")
.append_child(&item_element)
.unwrap();
}
});
},
)
.forget();
EventListener::new(&item_element, "click", move |event| {
let target: Element = event.target().unwrap().dyn_into().unwrap();
// if target.class_name() == "item-is-checked"
})
.forget();
if item.is_checked {
item_element
.selector::<HtmlInputElement>(".item-is-checked")
.set_checked(true);
container_checked.append_child(&item_element).unwrap();
} else {
container.append_child(&item_element).unwrap();
}
}
});
}

View file

@ -0,0 +1,3 @@
pub mod home;
pub mod recipe_edit;
pub mod recipe_view;

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,92 @@
use common::utils::substitute_with_names;
use gloo::events::EventListener;
use wasm_bindgen_futures::spawn_local;
use web_sys::{Element, HtmlInputElement};
use crate::{
calendar, modal_dialog,
recipe_scheduler::{RecipeScheduler, ScheduleRecipeResult},
toast::{self, Level},
utils::{SelectorExt, get_locale, selector},
};
pub fn setup_page(recipe_id: i64, is_user_logged: bool) {
let recipe_scheduler = RecipeScheduler::new(!is_user_logged);
let add_to_planner: Element = selector("#recipe-view .add-to-planner");
EventListener::new(&add_to_planner, "click", move |_event| {
spawn_local(async move {
if let Some((date, servings, add_ingredients_to_shopping_list)) =
modal_dialog::show_and_initialize_with_ok(
"#hidden-templates .date-and-servings",
async |element| {
calendar::setup(
element.selector(".calendar"),
calendar::CalendarOptions {
can_select_date: true,
with_link_and_remove: false,
},
recipe_scheduler,
)
},
|element, calendar_state| {
let servings_element: HtmlInputElement =
element.selector("#input-servings");
let add_ingredients_element: HtmlInputElement =
element.selector("#input-add-ingredients-to-shopping-list");
(
calendar_state.get_selected_date(),
servings_element.value_as_number() as u32,
add_ingredients_element.checked(),
)
},
)
.await
{
if let Ok(result) = recipe_scheduler
.shedule_recipe(recipe_id, date, servings, add_ingredients_to_shopping_list)
.await
{
toast::show_element_and_initialize(
match result {
ScheduleRecipeResult::Ok => Level::Success,
ScheduleRecipeResult::RecipeAlreadyScheduledAtThisDate => {
Level::Warning
}
},
match result {
ScheduleRecipeResult::Ok => {
"#hidden-templates .calendar-add-to-planner-success"
}
ScheduleRecipeResult::RecipeAlreadyScheduledAtThisDate => {
"#hidden-templates .calendar-add-to-planner-already-exists"
}
},
|element| {
let title =
selector::<Element>("#recipe-view .recipe-title").inner_html();
let date_format =
selector::<Element>("#hidden-templates .calendar-date-format")
.inner_html();
element.set_inner_html(&substitute_with_names(
&element.inner_html(),
&["{title}", "{date}"],
&[
&title,
&date
.format_localized(&date_format, get_locale())
.to_string(),
],
));
},
);
}
}
});
})
.forget();
}