Recipe edit (WIP): Buttons to add steps and inrgedients
This commit is contained in:
parent
6876a254e1
commit
d4962c98ff
9 changed files with 182 additions and 15 deletions
4
Cargo.lock
generated
4
Cargo.lock
generated
|
|
@ -391,9 +391,9 @@ checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.2.5"
|
version = "1.2.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c31a0499c1dc64f458ad13872de75c0eb7e3fdb0e67964610c914b034fc5956e"
|
checksum = "8d6dbb628b8f8555f86d0323c2eb39e3ec81901f4b83e091db8a6a76d316a333"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"shlex",
|
"shlex",
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -121,7 +121,7 @@ CREATE TABLE [Ingredient] (
|
||||||
|
|
||||||
[step_id] INTEGER NOT NULL,
|
[step_id] INTEGER NOT NULL,
|
||||||
|
|
||||||
[name] TEXT NOT NULL,
|
[name] TEXT NOT NULL DEFAULT '',
|
||||||
[comment] TEXT NOT NULL DEFAULT '',
|
[comment] TEXT NOT NULL DEFAULT '',
|
||||||
[quantity_value] REAL,
|
[quantity_value] REAL,
|
||||||
[quantity_unit] TEXT NOT NULL DEFAULT '',
|
[quantity_unit] TEXT NOT NULL DEFAULT '',
|
||||||
|
|
|
||||||
|
|
@ -304,6 +304,23 @@ ORDER BY [name]
|
||||||
.map_err(DBError::from)
|
.map_err(DBError::from)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn add_recipe_step(&self, group_id: i64) -> Result<i64> {
|
||||||
|
let db_result = sqlx::query("INSERT INTO [Step] ([group_id]) VALUES ($1)")
|
||||||
|
.bind(group_id)
|
||||||
|
.execute(&self.pool)
|
||||||
|
.await?;
|
||||||
|
Ok(db_result.last_insert_rowid())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn rm_recipe_step(&self, step_id: i64) -> Result<()> {
|
||||||
|
sqlx::query("DELETE FROM [Step] WHERE [id] = $1")
|
||||||
|
.bind(step_id)
|
||||||
|
.execute(&self.pool)
|
||||||
|
.await
|
||||||
|
.map(|_| ())
|
||||||
|
.map_err(DBError::from)
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn set_step_action(&self, step_id: i64, action: &str) -> Result<()> {
|
pub async fn set_step_action(&self, step_id: i64, action: &str) -> Result<()> {
|
||||||
sqlx::query("UPDATE [Step] SET [action] = $2 WHERE [id] = $1")
|
sqlx::query("UPDATE [Step] SET [action] = $2 WHERE [id] = $1")
|
||||||
.bind(step_id)
|
.bind(step_id)
|
||||||
|
|
@ -314,6 +331,23 @@ ORDER BY [name]
|
||||||
.map_err(DBError::from)
|
.map_err(DBError::from)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn add_recipe_ingredient(&self, step_id: i64) -> Result<i64> {
|
||||||
|
let db_result = sqlx::query("INSERT INTO [Ingredient] ([step_id]) VALUES ($1)")
|
||||||
|
.bind(step_id)
|
||||||
|
.execute(&self.pool)
|
||||||
|
.await?;
|
||||||
|
Ok(db_result.last_insert_rowid())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn rm_recipe_ingredient(&self, ingredient_id: i64) -> Result<()> {
|
||||||
|
sqlx::query("DELETE FROM [Ingredient] WHERE [id] = $1")
|
||||||
|
.bind(ingredient_id)
|
||||||
|
.execute(&self.pool)
|
||||||
|
.await
|
||||||
|
.map(|_| ())
|
||||||
|
.map_err(DBError::from)
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn set_ingredient_name(&self, ingredient_id: i64, name: &str) -> Result<()> {
|
pub async fn set_ingredient_name(&self, ingredient_id: i64, name: &str) -> Result<()> {
|
||||||
sqlx::query("UPDATE [Ingredient] SET [name] = $2 WHERE [id] = $1")
|
sqlx::query("UPDATE [Ingredient] SET [name] = $2 WHERE [id] = $1")
|
||||||
.bind(ingredient_id)
|
.bind(ingredient_id)
|
||||||
|
|
|
||||||
|
|
@ -58,6 +58,6 @@ pub struct Ingredient {
|
||||||
pub id: i64,
|
pub id: i64,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub comment: String,
|
pub comment: String,
|
||||||
pub quantity_value: f64,
|
pub quantity_value: Option<f64>,
|
||||||
pub quantity_unit: String,
|
pub quantity_unit: String,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -109,10 +109,20 @@ async fn main() {
|
||||||
"/recipe/set_group_comment",
|
"/recipe/set_group_comment",
|
||||||
put(services::ron::set_group_comment),
|
put(services::ron::set_group_comment),
|
||||||
)
|
)
|
||||||
|
.route("/recipe/add_step", post(services::ron::add_step))
|
||||||
|
.route("/recipe/remove_step", delete(services::ron::rm_step))
|
||||||
.route(
|
.route(
|
||||||
"/recipe/set_step_action",
|
"/recipe/set_step_action",
|
||||||
put(services::ron::set_step_action),
|
put(services::ron::set_step_action),
|
||||||
)
|
)
|
||||||
|
.route(
|
||||||
|
"/recipe/add_ingredient",
|
||||||
|
post(services::ron::add_ingredient),
|
||||||
|
)
|
||||||
|
.route(
|
||||||
|
"/recipe/remove_ingredient",
|
||||||
|
delete(services::ron::rm_ingredient),
|
||||||
|
)
|
||||||
.route(
|
.route(
|
||||||
"/recipe/set_ingredient_name",
|
"/recipe/set_ingredient_name",
|
||||||
put(services::ron::set_ingredient_name),
|
put(services::ron::set_ingredient_name),
|
||||||
|
|
|
||||||
|
|
@ -355,6 +355,32 @@ pub async fn set_group_comment(
|
||||||
Ok(StatusCode::OK)
|
Ok(StatusCode::OK)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[debug_handler]
|
||||||
|
pub async fn add_step(
|
||||||
|
State(connection): State<db::Connection>,
|
||||||
|
Extension(user): Extension<Option<model::User>>,
|
||||||
|
ExtractRon(ron): ExtractRon<common::ron_api::AddRecipeStep>,
|
||||||
|
) -> Result<impl IntoResponse> {
|
||||||
|
check_user_rights_recipe_group(&connection, &user, ron.group_id).await?;
|
||||||
|
let step_id = connection.add_recipe_step(ron.group_id).await?;
|
||||||
|
|
||||||
|
Ok(ron_response(
|
||||||
|
StatusCode::OK,
|
||||||
|
common::ron_api::AddRecipeStepResult { step_id },
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[debug_handler]
|
||||||
|
pub async fn rm_step(
|
||||||
|
State(connection): State<db::Connection>,
|
||||||
|
Extension(user): Extension<Option<model::User>>,
|
||||||
|
ExtractRon(ron): ExtractRon<common::ron_api::RemoveRecipeStep>,
|
||||||
|
) -> Result<impl IntoResponse> {
|
||||||
|
check_user_rights_recipe_step(&connection, &user, ron.step_id).await?;
|
||||||
|
connection.rm_recipe_step(ron.step_id).await?;
|
||||||
|
Ok(StatusCode::OK)
|
||||||
|
}
|
||||||
|
|
||||||
#[debug_handler]
|
#[debug_handler]
|
||||||
pub async fn set_step_action(
|
pub async fn set_step_action(
|
||||||
State(connection): State<db::Connection>,
|
State(connection): State<db::Connection>,
|
||||||
|
|
@ -366,6 +392,32 @@ pub async fn set_step_action(
|
||||||
Ok(StatusCode::OK)
|
Ok(StatusCode::OK)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[debug_handler]
|
||||||
|
pub async fn add_ingredient(
|
||||||
|
State(connection): State<db::Connection>,
|
||||||
|
Extension(user): Extension<Option<model::User>>,
|
||||||
|
ExtractRon(ron): ExtractRon<common::ron_api::AddRecipeIngredient>,
|
||||||
|
) -> Result<impl IntoResponse> {
|
||||||
|
check_user_rights_recipe_step(&connection, &user, ron.step_id).await?;
|
||||||
|
let ingredient_id = connection.add_recipe_ingredient(ron.step_id).await?;
|
||||||
|
|
||||||
|
Ok(ron_response(
|
||||||
|
StatusCode::OK,
|
||||||
|
common::ron_api::AddRecipeIngredientResult { ingredient_id },
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[debug_handler]
|
||||||
|
pub async fn rm_ingredient(
|
||||||
|
State(connection): State<db::Connection>,
|
||||||
|
Extension(user): Extension<Option<model::User>>,
|
||||||
|
ExtractRon(ron): ExtractRon<common::ron_api::RemoveRecipeIngredient>,
|
||||||
|
) -> Result<impl IntoResponse> {
|
||||||
|
check_user_rights_recipe_ingredient(&connection, &user, ron.ingredient_id).await?;
|
||||||
|
connection.rm_recipe_ingredient(ron.ingredient_id).await?;
|
||||||
|
Ok(StatusCode::OK)
|
||||||
|
}
|
||||||
|
|
||||||
#[debug_handler]
|
#[debug_handler]
|
||||||
pub async fn set_ingredient_name(
|
pub async fn set_ingredient_name(
|
||||||
State(connection): State<db::Connection>,
|
State(connection): State<db::Connection>,
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,7 @@
|
||||||
<div id="groups-container">
|
<div id="groups-container">
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<input id="button-add-group" type="button" value="Add a group" />
|
<input id="input-add-group" type="button" value="Add a group" />
|
||||||
|
|
||||||
<div id="hidden-templates">
|
<div id="hidden-templates">
|
||||||
<div class="group">
|
<div class="group">
|
||||||
|
|
@ -78,7 +78,7 @@
|
||||||
|
|
||||||
<div class="steps"></div>
|
<div class="steps"></div>
|
||||||
|
|
||||||
<input class="button-add-step" type="button" value="Add a step" />
|
<input class="input-add-step" type="button" value="Add a step" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="step">
|
<div class="step">
|
||||||
|
|
@ -89,7 +89,7 @@
|
||||||
|
|
||||||
<div class="ingredients"></div>
|
<div class="ingredients"></div>
|
||||||
|
|
||||||
<input class="button-add-ingedient" type="button" value="Add an ingredient"/>
|
<input class="input-add-ingredient" type="button" value="Add an ingredient"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="ingredient">
|
<div class="ingredient">
|
||||||
|
|
|
||||||
|
|
@ -92,12 +92,42 @@ pub struct SetGroupComment {
|
||||||
pub comment: String,
|
pub comment: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone)]
|
||||||
|
pub struct AddRecipeStep {
|
||||||
|
pub group_id: i64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone)]
|
||||||
|
pub struct AddRecipeStepResult {
|
||||||
|
pub step_id: i64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone)]
|
||||||
|
pub struct RemoveRecipeStep {
|
||||||
|
pub step_id: i64,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone)]
|
#[derive(Serialize, Deserialize, Clone)]
|
||||||
pub struct SetStepAction {
|
pub struct SetStepAction {
|
||||||
pub step_id: i64,
|
pub step_id: i64,
|
||||||
pub action: String,
|
pub action: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone)]
|
||||||
|
pub struct AddRecipeIngredient {
|
||||||
|
pub step_id: i64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone)]
|
||||||
|
pub struct AddRecipeIngredientResult {
|
||||||
|
pub ingredient_id: i64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone)]
|
||||||
|
pub struct RemoveRecipeIngredient {
|
||||||
|
pub ingredient_id: i64,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone)]
|
#[derive(Serialize, Deserialize, Clone)]
|
||||||
pub struct SetIngredientName {
|
pub struct SetIngredientName {
|
||||||
pub ingredient_id: i64,
|
pub ingredient_id: i64,
|
||||||
|
|
@ -142,7 +172,7 @@ pub struct Ingredient {
|
||||||
pub id: i64,
|
pub id: i64,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub comment: String,
|
pub comment: String,
|
||||||
pub quantity_value: f64,
|
pub quantity_value: Option<f64>,
|
||||||
pub quantity_unit: String,
|
pub quantity_unit: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -220,6 +220,25 @@ pub fn recipe_edit(recipe_id: i64) -> Result<(), JsValue> {
|
||||||
})
|
})
|
||||||
.forget();
|
.forget();
|
||||||
|
|
||||||
|
// Add step button.
|
||||||
|
let add_step_button: HtmlInputElement = group_element.select(".input-add-step");
|
||||||
|
EventListener::new(&add_step_button, "click", move |_event| {
|
||||||
|
spawn_local(async move {
|
||||||
|
let body = ron_api::AddRecipeStep { group_id };
|
||||||
|
let response: ron_api::AddRecipeStepResult =
|
||||||
|
request::post("recipe/add_step", body).await.unwrap();
|
||||||
|
create_step_element(
|
||||||
|
&by_id::<Element>(&format!("group-{}", group_id)),
|
||||||
|
&ron_api::Step {
|
||||||
|
id: response.step_id,
|
||||||
|
action: "".to_string(),
|
||||||
|
ingredients: vec![],
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.forget();
|
||||||
|
|
||||||
group_element
|
group_element
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -249,6 +268,27 @@ pub fn recipe_edit(recipe_id: i64) -> Result<(), JsValue> {
|
||||||
})
|
})
|
||||||
.forget();
|
.forget();
|
||||||
|
|
||||||
|
// Add ingredient button.
|
||||||
|
let add_ingredient_button: HtmlInputElement = step_element.select(".input-add-ingredient");
|
||||||
|
EventListener::new(&add_ingredient_button, "click", move |_event| {
|
||||||
|
spawn_local(async move {
|
||||||
|
let body = ron_api::AddRecipeIngredient { step_id };
|
||||||
|
let response: ron_api::AddRecipeIngredientResult =
|
||||||
|
request::post("recipe/add_ingredient", body).await.unwrap();
|
||||||
|
create_ingredient_element(
|
||||||
|
&by_id::<Element>(&format!("step-{}", step_id)),
|
||||||
|
&ron_api::Ingredient {
|
||||||
|
id: response.ingredient_id,
|
||||||
|
name: "".to_string(),
|
||||||
|
comment: "".to_string(),
|
||||||
|
quantity_value: None,
|
||||||
|
quantity_unit: "".to_string(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.forget();
|
||||||
|
|
||||||
step_element
|
step_element
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -259,7 +299,7 @@ pub fn recipe_edit(recipe_id: i64) -> Result<(), JsValue> {
|
||||||
let ingredient_id = ingredient.id;
|
let ingredient_id = ingredient.id;
|
||||||
let ingredient_element: Element = select_and_clone("#hidden-templates .ingredient");
|
let ingredient_element: Element = select_and_clone("#hidden-templates .ingredient");
|
||||||
ingredient_element
|
ingredient_element
|
||||||
.set_attribute("id", &format!("step-{}", ingredient.id))
|
.set_attribute("id", &format!("ingredient-{}", ingredient.id))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
step_element.append_child(&ingredient_element).unwrap();
|
step_element.append_child(&ingredient_element).unwrap();
|
||||||
|
|
||||||
|
|
@ -301,8 +341,12 @@ pub fn recipe_edit(recipe_id: i64) -> Result<(), JsValue> {
|
||||||
|
|
||||||
// Ingredient quantity.
|
// Ingredient quantity.
|
||||||
let quantity: HtmlInputElement = ingredient_element.select(".input-ingredient-quantity");
|
let quantity: HtmlInputElement = ingredient_element.select(".input-ingredient-quantity");
|
||||||
quantity.set_value(&ingredient.quantity_value.to_string());
|
quantity.set_value(
|
||||||
let mut current_quantity = ingredient.quantity_value;
|
&ingredient
|
||||||
|
.quantity_value
|
||||||
|
.map_or("".to_string(), |q| q.to_string()),
|
||||||
|
);
|
||||||
|
let mut current_quantity = quantity.value_as_number();
|
||||||
EventListener::new(&quantity.clone(), "blur", move |_event| {
|
EventListener::new(&quantity.clone(), "blur", move |_event| {
|
||||||
let n = quantity.value_as_number();
|
let n = quantity.value_as_number();
|
||||||
if n.is_nan() {
|
if n.is_nan() {
|
||||||
|
|
@ -367,11 +411,9 @@ pub fn recipe_edit(recipe_id: i64) -> Result<(), JsValue> {
|
||||||
|
|
||||||
// Add a new group.
|
// Add a new group.
|
||||||
{
|
{
|
||||||
let button_add_group = document().get_element_by_id("button-add-group").unwrap();
|
let button_add_group: HtmlInputElement = by_id("input-add-group");
|
||||||
let on_click_add_group = EventListener::new(&button_add_group, "click", move |_event| {
|
let on_click_add_group = EventListener::new(&button_add_group, "click", move |_event| {
|
||||||
log!("Click!");
|
|
||||||
let body = ron_api::AddRecipeGroup { recipe_id };
|
let body = ron_api::AddRecipeGroup { recipe_id };
|
||||||
|
|
||||||
spawn_local(async move {
|
spawn_local(async move {
|
||||||
let response: ron_api::AddRecipeGroupResult =
|
let response: ron_api::AddRecipeGroupResult =
|
||||||
request::post("recipe/add_group", body).await.unwrap();
|
request::post("recipe/add_group", body).await.unwrap();
|
||||||
|
|
@ -381,7 +423,6 @@ pub fn recipe_edit(recipe_id: i64) -> Result<(), JsValue> {
|
||||||
comment: "".to_string(),
|
comment: "".to_string(),
|
||||||
steps: vec![],
|
steps: vec![],
|
||||||
});
|
});
|
||||||
// group_html.set_attribute("id", "test").unwrap();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
on_click_add_group.forget();
|
on_click_add_group.forget();
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue