Add a calendar to schedule a recipe to a chosen date (WIP)
This commit is contained in:
parent
d9449de02b
commit
9d3f9e9c60
15 changed files with 441 additions and 62 deletions
19
Cargo.lock
generated
19
Cargo.lock
generated
|
|
@ -149,9 +149,9 @@ checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
|
|||
|
||||
[[package]]
|
||||
name = "axum"
|
||||
version = "0.8.2"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "efea76243612a2436fb4074ba0cf3ba9ea29efdeb72645d8fc63f116462be1de"
|
||||
checksum = "6d6fd624c75e18b3b4c6b9caf42b1afe24437daaee904069137d8bab077be8b8"
|
||||
dependencies = [
|
||||
"axum-core",
|
||||
"axum-macros",
|
||||
|
|
@ -184,12 +184,12 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "axum-core"
|
||||
version = "0.5.1"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eab1b0df7cded837c40dacaa2e1c33aa17c84fc3356ae67b5645f1e83190753e"
|
||||
checksum = "df1362f362fd16024ae199c1970ce98f9661bf5ef94b9808fee734bc3698b733"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"http 1.2.0",
|
||||
"http-body",
|
||||
"http-body-util",
|
||||
|
|
@ -204,9 +204,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "axum-extra"
|
||||
version = "0.11.0"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "543f0799d22486525744f06a3580b64f3e51d97aba73ea0e09040969c0034722"
|
||||
checksum = "460fc6f625a1f7705c6cf62d0d070794e94668988b1c38111baeec177c715f7b"
|
||||
dependencies = [
|
||||
"axum",
|
||||
"axum-core",
|
||||
|
|
@ -700,6 +700,7 @@ dependencies = [
|
|||
name = "frontend"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"common",
|
||||
"console_error_panic_hook",
|
||||
"futures",
|
||||
|
|
@ -2067,9 +2068,9 @@ checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497"
|
|||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.43"
|
||||
version = "0.38.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a78891ee6bf2340288408954ac787aa063d8e8817e9f53abb37c695c6d834ef6"
|
||||
checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"errno",
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ edition = "2021"
|
|||
common = { path = "../common" }
|
||||
|
||||
axum = { version = "0.8", features = ["macros"] }
|
||||
axum-extra = { version = "0.11", features = ["cookie"] }
|
||||
axum-extra = { version = "0.10", features = ["cookie"] }
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
tower = { version = "0.5", features = ["util"] }
|
||||
tower-http = { version = "0.6", features = ["fs", "trace"] }
|
||||
|
|
|
|||
46
backend/scss/calendar.scss
Normal file
46
backend/scss/calendar.scss
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
.calendar {
|
||||
.month-selector {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
|
||||
.prev {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.next {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.month {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.month.current {
|
||||
display: inline;
|
||||
}
|
||||
}
|
||||
|
||||
ul.weekdays {
|
||||
margin: 0;
|
||||
padding: 20px 0;
|
||||
|
||||
li {
|
||||
display: inline-block;
|
||||
width: 14%;
|
||||
text-align: center;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
ul.days {
|
||||
margin: 0;
|
||||
padding: 20px 0;
|
||||
|
||||
li {
|
||||
display: inline-block;
|
||||
width: 14%;
|
||||
text-align: center;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
#modal-dialog {
|
||||
// visibility: hidden;
|
||||
color: white;
|
||||
max-width: 300px;
|
||||
margin-left: -125px;
|
||||
width: 500px;
|
||||
margin-left: -250px;
|
||||
background-color: black;
|
||||
text-align: center;
|
||||
border-radius: 2px;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
@use 'toast.scss';
|
||||
@use 'modal-dialog.scss';
|
||||
@use 'calendar.scss';
|
||||
|
||||
$color-1: #B29B89;
|
||||
$color-2: #89B29B;
|
||||
|
|
@ -123,6 +124,10 @@ body {
|
|||
h1 {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#hidden-templates {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
#recipe-edit {
|
||||
|
|
@ -163,10 +168,6 @@ body {
|
|||
background-color: red;
|
||||
}
|
||||
}
|
||||
|
||||
#hidden-templates {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
form {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use std::{fs::File, sync::LazyLock};
|
||||
use std::{borrow::Borrow, fs::File, sync::LazyLock};
|
||||
|
||||
use ron::de::from_reader;
|
||||
use serde::Deserialize;
|
||||
|
|
@ -114,6 +114,27 @@ pub enum Sentence {
|
|||
RecipeOneServing,
|
||||
RecipeSomeServings,
|
||||
RecipeEstimatedTimeMinAbbreviation,
|
||||
|
||||
// Calendar.
|
||||
CalendarMondayAbbreviation,
|
||||
CalendarTuesdayAbbreviation,
|
||||
CalendarWednesdayAbbreviation,
|
||||
CalendarThursdayAbbreviation,
|
||||
CalendarFridayAbbreviation,
|
||||
CalendarSaturdayAbbreviation,
|
||||
CalendarSundayAbbreviation,
|
||||
CalendarJanuary,
|
||||
CalendarFebruary,
|
||||
CalendarMarch,
|
||||
CalendarApril,
|
||||
CalendarMay,
|
||||
CalendarJune,
|
||||
CalendarJuly,
|
||||
CalendarAugust,
|
||||
CalendarSeptember,
|
||||
CalendarOctober,
|
||||
CalendarNovember,
|
||||
CalendarDecember,
|
||||
}
|
||||
|
||||
pub const DEFAULT_LANGUAGE_CODE: &str = "en";
|
||||
|
|
@ -131,7 +152,10 @@ impl Tr {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn t(&self, sentence: Sentence) -> &'static str {
|
||||
pub fn t<T>(&self, sentence: T) -> &'static str
|
||||
where
|
||||
T: Borrow<Sentence>,
|
||||
{
|
||||
self.lang.get(sentence)
|
||||
}
|
||||
|
||||
|
|
@ -196,10 +220,15 @@ impl Language {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get(&'static self, sentence: Sentence) -> &'static str {
|
||||
pub fn get<T>(&'static self, sentence: T) -> &'static str
|
||||
where
|
||||
T: Borrow<Sentence>,
|
||||
{
|
||||
let sentence_cloned: Sentence = sentence.borrow().clone();
|
||||
|
||||
let text: &str = self
|
||||
.translation
|
||||
.get(sentence.clone() as usize)
|
||||
.get(sentence_cloned as usize)
|
||||
.unwrap()
|
||||
.as_ref();
|
||||
if text.is_empty() && self.code != DEFAULT_LANGUAGE_CODE {
|
||||
|
|
|
|||
45
backend/templates/calendar.html
Normal file
45
backend/templates/calendar.html
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
<div class="calendar">
|
||||
<div class="month-selector">
|
||||
<span class="prev">PREV</span>
|
||||
<span class="year" ></span>
|
||||
|
||||
{% for month in [
|
||||
Sentence::CalendarJanuary,
|
||||
Sentence::CalendarFebruary,
|
||||
Sentence::CalendarMarch,
|
||||
Sentence::CalendarApril,
|
||||
Sentence::CalendarMay,
|
||||
Sentence::CalendarJune,
|
||||
Sentence::CalendarJuly,
|
||||
Sentence::CalendarAugust,
|
||||
Sentence::CalendarSeptember,
|
||||
Sentence::CalendarOctober,
|
||||
Sentence::CalendarNovember,
|
||||
Sentence::CalendarDecember,
|
||||
] %}
|
||||
<span class="month">{{ tr.t(*month) }}</span>
|
||||
{% endfor %}
|
||||
|
||||
<span class="next">NEXT</span>
|
||||
</div>
|
||||
<ul class="weekdays">
|
||||
{% for day in [
|
||||
Sentence::CalendarMondayAbbreviation,
|
||||
Sentence::CalendarTuesdayAbbreviation,
|
||||
Sentence::CalendarWednesdayAbbreviation,
|
||||
Sentence::CalendarThursdayAbbreviation,
|
||||
Sentence::CalendarFridayAbbreviation,
|
||||
Sentence::CalendarSaturdayAbbreviation,
|
||||
Sentence::CalendarSundayAbbreviation,
|
||||
] %}
|
||||
<li class="weekday">{{ tr.t(*day) }}</li>
|
||||
{% endfor %}
|
||||
|
||||
<ul class="days">
|
||||
{% for i in 0..7 %}
|
||||
{% for j in 0..5 %}
|
||||
<li id="day-{{i}}{{j}}"></li>
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
|
|
@ -5,8 +5,11 @@
|
|||
<div class="content" id="recipe-view">
|
||||
<h2 class="recipe-title" >{{ recipe.title }}</h2>
|
||||
|
||||
{% if user.is_some() && crate::data::model::can_user_edit_recipe(&user.as_ref().unwrap(), &recipe) %}
|
||||
<a class="edit-recipe" href="/recipe/edit/{{ recipe.id }}" >Edit</a>
|
||||
{% if let Some(user) = user %}
|
||||
{% if crate::data::model::can_user_edit_recipe(user, recipe) %}
|
||||
<a class="edit-recipe" href="/recipe/edit/{{ recipe.id }}" >Edit</a>
|
||||
{% endif %}
|
||||
<span class="add-to-planner">Add to planner</span>
|
||||
{% endif %}
|
||||
|
||||
<div class="tags">
|
||||
|
|
@ -27,7 +30,6 @@
|
|||
{% else %}
|
||||
{% endmatch %}
|
||||
|
||||
|
||||
{% match recipe.estimated_time %}
|
||||
{% when Some(time) %}
|
||||
{{ time +}} {{+ tr.t(Sentence::RecipeEstimatedTimeMinAbbreviation) }}
|
||||
|
|
@ -76,6 +78,10 @@
|
|||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
<div id="hidden-templates">
|
||||
{% include "calendar.html" %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
|
@ -99,6 +99,26 @@
|
|||
(RecipeOneServing, "1 serving"),
|
||||
(RecipeSomeServings, "{} servings"),
|
||||
(RecipeEstimatedTimeMinAbbreviation, "min"),
|
||||
|
||||
(CalendarMondayAbbreviation, "Mon"),
|
||||
(CalendarTuesdayAbbreviation, "Tue"),
|
||||
(CalendarWednesdayAbbreviation, "Wed"),
|
||||
(CalendarThursdayAbbreviation, "Thu"),
|
||||
(CalendarFridayAbbreviation, "Fri"),
|
||||
(CalendarSaturdayAbbreviation, "Sat"),
|
||||
(CalendarSundayAbbreviation, "Sun"),
|
||||
(CalendarJanuary, "January"),
|
||||
(CalendarFebruary, "February"),
|
||||
(CalendarMarch, "March"),
|
||||
(CalendarApril, "April"),
|
||||
(CalendarMay, "May"),
|
||||
(CalendarJune, "June"),
|
||||
(CalendarJuly, "July"),
|
||||
(CalendarAugust, "August"),
|
||||
(CalendarSeptember, "September"),
|
||||
(CalendarOctober, "October"),
|
||||
(CalendarNovember, "November"),
|
||||
(CalendarDecember, "December"),
|
||||
]
|
||||
),
|
||||
(
|
||||
|
|
@ -201,6 +221,26 @@
|
|||
(RecipeOneServing, "pour 1 personne"),
|
||||
(RecipeSomeServings, "pour {} personnes"),
|
||||
(RecipeEstimatedTimeMinAbbreviation, "min"),
|
||||
|
||||
(CalendarMondayAbbreviation, "Lun"),
|
||||
(CalendarTuesdayAbbreviation, "Mar"),
|
||||
(CalendarWednesdayAbbreviation, "Mer"),
|
||||
(CalendarThursdayAbbreviation, "Jeu"),
|
||||
(CalendarFridayAbbreviation, "Ven"),
|
||||
(CalendarSaturdayAbbreviation, "Sam"),
|
||||
(CalendarSundayAbbreviation, "Dim"),
|
||||
(CalendarJanuary, "Janvier"),
|
||||
(CalendarFebruary, "Février"),
|
||||
(CalendarMarch, "Mars"),
|
||||
(CalendarApril, "Avril"),
|
||||
(CalendarMay, "Mai"),
|
||||
(CalendarJune, "Juin"),
|
||||
(CalendarJuly, "Juillet"),
|
||||
(CalendarAugust, "Août"),
|
||||
(CalendarSeptember, "Septembre"),
|
||||
(CalendarOctober, "Octobre"),
|
||||
(CalendarNovember, "Novembre"),
|
||||
(CalendarDecember, "Décembre"),
|
||||
]
|
||||
)
|
||||
]
|
||||
|
|
@ -13,6 +13,8 @@ default = ["console_error_panic_hook"]
|
|||
[dependencies]
|
||||
common = { path = "../common" }
|
||||
|
||||
chrono = "0.4"
|
||||
|
||||
ron = "0.8"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
thiserror = "2"
|
||||
|
|
|
|||
121
frontend/src/calendar.rs
Normal file
121
frontend/src/calendar.rs
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
use std::{
|
||||
ops::{AddAssign, SubAssign},
|
||||
sync::{
|
||||
atomic::{AtomicI32, AtomicU32, Ordering},
|
||||
Arc,
|
||||
},
|
||||
};
|
||||
|
||||
use chrono::{offset::Local, Datelike, Days, NaiveDate, Weekday};
|
||||
use gloo::{console::log, events::EventListener};
|
||||
use wasm_bindgen::prelude::*;
|
||||
use wasm_bindgen_futures::spawn_local;
|
||||
use web_sys::Element;
|
||||
|
||||
use crate::utils::{by_id, SelectorExt};
|
||||
|
||||
pub fn setup(calendar: &Element) {
|
||||
let prev: Element = calendar.selector(".prev");
|
||||
let next: Element = calendar.selector(".next");
|
||||
|
||||
let current_month = Arc::new(AtomicU32::new(Local::now().month()));
|
||||
let current_year = Arc::new(AtomicI32::new(Local::now().year()));
|
||||
|
||||
display_month(calendar, Local::now().year(), Local::now().month());
|
||||
|
||||
let calendar_clone = calendar.clone();
|
||||
let current_month_clone = current_month.clone();
|
||||
let current_year_clone = current_year.clone();
|
||||
EventListener::new(&prev, "click", move |_event| {
|
||||
let mut m = current_month_clone.load(Ordering::Relaxed) - 1;
|
||||
if m == 0 {
|
||||
current_year_clone.fetch_sub(1, Ordering::Relaxed);
|
||||
m = 12
|
||||
}
|
||||
current_month_clone.store(m, Ordering::Relaxed);
|
||||
display_month(
|
||||
&calendar_clone,
|
||||
current_year_clone.load(Ordering::Relaxed),
|
||||
m,
|
||||
);
|
||||
})
|
||||
.forget();
|
||||
|
||||
let calendar_clone = calendar.clone();
|
||||
let current_month_clone = current_month.clone();
|
||||
let current_year_clone = current_year.clone();
|
||||
EventListener::new(&next, "click", move |_event| {
|
||||
let mut m = current_month_clone.load(Ordering::Relaxed) + 1;
|
||||
if m == 13 {
|
||||
current_year_clone.fetch_add(1, Ordering::Relaxed);
|
||||
m = 1
|
||||
}
|
||||
current_month_clone.store(m, Ordering::Relaxed);
|
||||
display_month(
|
||||
&calendar_clone,
|
||||
current_year_clone.load(Ordering::Relaxed),
|
||||
m,
|
||||
);
|
||||
})
|
||||
.forget();
|
||||
|
||||
// now.weekday()
|
||||
|
||||
// console!(now.to_string());
|
||||
}
|
||||
|
||||
// fn translate_month(month: u32) -> &'static str {
|
||||
// match
|
||||
// }
|
||||
|
||||
fn display_month(calendar: &Element, year: i32, month: u32) {
|
||||
log!(year, month);
|
||||
|
||||
calendar
|
||||
.selector::<Element>(".year")
|
||||
.set_inner_html(&year.to_string());
|
||||
|
||||
for (i, m) in calendar
|
||||
.selector_all::<Element>(".month")
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
{
|
||||
if i as u32 + 1 == month {
|
||||
m.set_class_name("month current");
|
||||
} else {
|
||||
m.set_class_name("month");
|
||||
}
|
||||
}
|
||||
|
||||
// calendar
|
||||
// .selector::<Element>(".month")
|
||||
// .set_inner_html(&month.to_string());
|
||||
|
||||
let mut current = NaiveDate::from_ymd_opt(year, month, 1).unwrap();
|
||||
|
||||
// let mut day = Local:: ;
|
||||
while (current - Days::new(1)).month() == month {
|
||||
current = current - Days::new(1);
|
||||
}
|
||||
|
||||
while current.weekday() != Weekday::Mon {
|
||||
current = current - Days::new(1);
|
||||
}
|
||||
|
||||
for i in 0..7 {
|
||||
for j in 0..5 {
|
||||
let li: Element = by_id(&format!("day-{}{}", i, j));
|
||||
li.set_inner_html(¤t.day().to_string());
|
||||
|
||||
if current == Local::now().date_naive() {
|
||||
li.set_class_name("current-month today");
|
||||
} else if current.month() == month {
|
||||
li.set_class_name("current-month");
|
||||
} else {
|
||||
li.set_class_name("");
|
||||
}
|
||||
|
||||
current = current + Days::new(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
mod calendar;
|
||||
mod modal_dialog;
|
||||
mod on_click;
|
||||
mod recipe_edit;
|
||||
mod recipe_view;
|
||||
mod request;
|
||||
mod toast;
|
||||
mod utils;
|
||||
|
|
@ -20,16 +22,24 @@ pub fn main() -> Result<(), JsValue> {
|
|||
let location = window().location().pathname()?;
|
||||
let path: Vec<&str> = location.split('/').skip(1).collect();
|
||||
|
||||
if let ["recipe", "edit", id] = path[..] {
|
||||
let id = id.parse::<i64>().unwrap(); // TODO: remove unwrap.
|
||||
if let Err(error) = recipe_edit::setup_page(id) {
|
||||
log!(error);
|
||||
// if let ["recipe", "edit", id] = path[..] {
|
||||
match path[..] {
|
||||
["recipe", "edit", id] => {
|
||||
let id = id.parse::<i64>().unwrap(); // TODO: remove unwrap.
|
||||
if let Err(error) = recipe_edit::setup_page(id) {
|
||||
log!(error);
|
||||
}
|
||||
}
|
||||
|
||||
// Disable: user editing data are now submitted as classic form data.
|
||||
// ["user", "edit"] => {
|
||||
// handles::user_edit(document)?;
|
||||
// }
|
||||
["recipe", "view", id] => {
|
||||
let id = id.parse::<i64>().unwrap(); // TODO: remove unwrap.
|
||||
if let Err(error) = recipe_view::setup_page(id) {
|
||||
log!(error);
|
||||
}
|
||||
}
|
||||
_ => (), // Disable: user editing data are now submitted as classic form data.
|
||||
// ["user", "edit"] => {
|
||||
// handles::user_edit(document)?;
|
||||
// }
|
||||
}
|
||||
|
||||
let select_language: HtmlSelectElement = by_id("select-website-language");
|
||||
|
|
|
|||
|
|
@ -1,16 +1,39 @@
|
|||
use futures::{future::FutureExt, pin_mut, select};
|
||||
use web_sys::{Element, HtmlDialogElement};
|
||||
|
||||
use crate::utils::{by_id, SelectorExt};
|
||||
use crate::{
|
||||
on_click,
|
||||
utils::{by_id, selector_and_clone, SelectorExt},
|
||||
};
|
||||
|
||||
use crate::on_click;
|
||||
pub enum DialogContent<'a, T>
|
||||
where
|
||||
T: Fn(&Element),
|
||||
{
|
||||
Text(&'a str),
|
||||
CloneFromElement(&'a str, T),
|
||||
}
|
||||
|
||||
pub async fn show(message: &str) -> bool {
|
||||
pub async fn show<T>(content: DialogContent<'_, T>) -> bool
|
||||
where
|
||||
T: Fn(&Element),
|
||||
{
|
||||
let dialog: HtmlDialogElement = by_id("modal-dialog");
|
||||
|
||||
let input_ok: Element = dialog.selector(".ok");
|
||||
let input_cancel: Element = dialog.selector(".cancel");
|
||||
|
||||
dialog.selector::<Element>(".content").set_inner_html(message);
|
||||
let content_element = dialog.selector::<Element>(".content");
|
||||
|
||||
match content {
|
||||
DialogContent::Text(message) => content_element.set_inner_html(message),
|
||||
DialogContent::CloneFromElement(element_selector, initilizer) => {
|
||||
let element: Element = selector_and_clone(element_selector);
|
||||
content_element.set_inner_html("");
|
||||
content_element.append_child(&element).unwrap();
|
||||
initilizer(&element);
|
||||
}
|
||||
}
|
||||
|
||||
dialog.show_modal().unwrap();
|
||||
|
||||
|
|
|
|||
|
|
@ -20,22 +20,6 @@ use crate::{
|
|||
utils::{by_id, selector, selector_and_clone, SelectorExt},
|
||||
};
|
||||
|
||||
async fn reload_recipes_list(current_recipe_id: i64) {
|
||||
match Request::get("/fragments/recipes_list")
|
||||
.query([("current_recipe_id", current_recipe_id.to_string())])
|
||||
.send()
|
||||
.await
|
||||
{
|
||||
Err(error) => {
|
||||
toast::show(Level::Info, &format!("Internal server error: {}", error));
|
||||
}
|
||||
Ok(response) => {
|
||||
let list = document().get_element_by_id("recipes-list").unwrap();
|
||||
list.set_outer_html(&response.text().await.unwrap());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn setup_page(recipe_id: i64) -> Result<(), JsValue> {
|
||||
// Title.
|
||||
{
|
||||
|
|
@ -266,10 +250,10 @@ pub fn setup_page(recipe_id: i64) -> Result<(), JsValue> {
|
|||
EventListener::new(&delete_button, "click", move |_event| {
|
||||
let title: HtmlInputElement = by_id("input-title");
|
||||
spawn_local(async move {
|
||||
if modal_dialog::show(&format!(
|
||||
if modal_dialog::show(modal_dialog::DialogContent::<fn(&Element)>::Text(&format!(
|
||||
"Are you sure to delete the recipe '{}'",
|
||||
title.value()
|
||||
))
|
||||
)))
|
||||
.await
|
||||
{
|
||||
let body = ron_api::Id { id: recipe_id };
|
||||
|
|
@ -314,7 +298,7 @@ pub fn setup_page(recipe_id: i64) -> Result<(), JsValue> {
|
|||
// Add a new group.
|
||||
{
|
||||
let button_add_group: HtmlInputElement = by_id("input-add-group");
|
||||
let on_click_add_group = EventListener::new(&button_add_group, "click", move |_event| {
|
||||
EventListener::new(&button_add_group, "click", move |_event| {
|
||||
let body = ron_api::Id { id: recipe_id };
|
||||
spawn_local(async move {
|
||||
let response: ron_api::Id = request::post("recipe/add_group", body).await.unwrap();
|
||||
|
|
@ -325,8 +309,8 @@ pub fn setup_page(recipe_id: i64) -> Result<(), JsValue> {
|
|||
steps: vec![],
|
||||
});
|
||||
});
|
||||
});
|
||||
on_click_add_group.forget();
|
||||
})
|
||||
.forget();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
@ -397,7 +381,12 @@ fn create_group_element(group: &ron_api::Group) -> Element {
|
|||
.selector::<HtmlInputElement>(".input-group-name")
|
||||
.value();
|
||||
spawn_local(async move {
|
||||
if modal_dialog::show(&format!("Are you sure to delete the group '{}'", name)).await {
|
||||
if modal_dialog::show(modal_dialog::DialogContent::<fn(&Element)>::Text(&format!(
|
||||
"Are you sure to delete the group '{}'",
|
||||
name
|
||||
)))
|
||||
.await
|
||||
{
|
||||
let body = ron_api::Id { id: group_id };
|
||||
let _ = request::delete::<(), _>("recipe/remove_group", body).await;
|
||||
let group_element = by_id::<Element>(&format!("group-{}", group_id));
|
||||
|
|
@ -530,7 +519,12 @@ fn create_step_element(group_element: &Element, step: &ron_api::Step) -> Element
|
|||
.selector::<HtmlTextAreaElement>(".text-area-step-action")
|
||||
.value();
|
||||
spawn_local(async move {
|
||||
if modal_dialog::show(&format!("Are you sure to delete the step '{}'", action)).await {
|
||||
if modal_dialog::show(modal_dialog::DialogContent::<fn(&Element)>::Text(&format!(
|
||||
"Are you sure to delete the step '{}'",
|
||||
action
|
||||
)))
|
||||
.await
|
||||
{
|
||||
let body = ron_api::Id { id: step_id };
|
||||
let _ = request::delete::<(), _>("recipe/remove_step", body).await;
|
||||
let step_element = by_id::<Element>(&format!("step-{}", step_id));
|
||||
|
|
@ -675,12 +669,17 @@ fn create_ingredient_element(step_element: &Element, ingredient: &ron_api::Ingre
|
|||
.selector::<HtmlInputElement>(".input-ingredient-name")
|
||||
.value();
|
||||
spawn_local(async move {
|
||||
if modal_dialog::show(&format!("Are you sure to delete the ingredient '{}'", name))
|
||||
.await
|
||||
if modal_dialog::show(modal_dialog::DialogContent::<fn(&Element)>::Text(&format!(
|
||||
"Are you sure to delete the ingredient '{}'",
|
||||
name
|
||||
)))
|
||||
.await
|
||||
{
|
||||
let body = ron_api::Id { id: ingredient_id };
|
||||
let _ = request::delete::<(), _>("recipe/remove_ingredient", body).await;
|
||||
by_id::<Element>(&format!("ingredient-{}", ingredient_id)).remove();
|
||||
let ingredient_element = by_id::<Element>(&format!("ingredient-{}", ingredient_id));
|
||||
ingredient_element.next_element_sibling().unwrap().remove();
|
||||
ingredient_element.remove();
|
||||
}
|
||||
});
|
||||
})
|
||||
|
|
@ -689,6 +688,22 @@ fn create_ingredient_element(step_element: &Element, ingredient: &ron_api::Ingre
|
|||
ingredient_element
|
||||
}
|
||||
|
||||
async fn reload_recipes_list(current_recipe_id: i64) {
|
||||
match Request::get("/fragments/recipes_list")
|
||||
.query([("current_recipe_id", current_recipe_id.to_string())])
|
||||
.send()
|
||||
.await
|
||||
{
|
||||
Err(error) => {
|
||||
toast::show(Level::Info, &format!("Internal server error: {}", error));
|
||||
}
|
||||
Ok(response) => {
|
||||
let list = document().get_element_by_id("recipes-list").unwrap();
|
||||
list.set_outer_html(&response.text().await.unwrap());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum CursorPosition {
|
||||
UpperPart,
|
||||
LowerPart,
|
||||
|
|
|
|||
40
frontend/src/recipe_view.rs
Normal file
40
frontend/src/recipe_view.rs
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
use gloo::{
|
||||
console::console,
|
||||
events::EventListener,
|
||||
net::http::Request,
|
||||
utils::{document, window},
|
||||
};
|
||||
use wasm_bindgen::prelude::*;
|
||||
use wasm_bindgen_futures::spawn_local;
|
||||
use web_sys::{
|
||||
DragEvent, Element, HtmlDivElement, HtmlInputElement, HtmlSelectElement, HtmlTextAreaElement,
|
||||
KeyboardEvent,
|
||||
};
|
||||
|
||||
use common::ron_api;
|
||||
|
||||
use crate::{
|
||||
calendar, modal_dialog, request,
|
||||
toast::{self, Level},
|
||||
utils::{by_id, selector, selector_and_clone, SelectorExt},
|
||||
};
|
||||
|
||||
pub fn setup_page(recipe_id: i64) -> Result<(), JsValue> {
|
||||
let add_to_planner: Element = selector("#recipe-view .add-to-planner");
|
||||
EventListener::new(&add_to_planner, "click", move |_event| {
|
||||
// console!("CLICK".to_string());
|
||||
spawn_local(async move {
|
||||
modal_dialog::show(modal_dialog::DialogContent::CloneFromElement(
|
||||
"#hidden-templates .calendar",
|
||||
|element| {
|
||||
// console!("SETUP...".to_string());
|
||||
calendar::setup(element);
|
||||
},
|
||||
))
|
||||
.await;
|
||||
});
|
||||
})
|
||||
.forget();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue