all: Set steps to be a single Vec & fix 'ingerdient' typo

This commit is contained in:
traxys 2023-06-25 21:37:28 +02:00
parent b01f08ba2f
commit 0c7e52bd8b
9 changed files with 78 additions and 81 deletions

View file

@ -89,7 +89,7 @@ pub struct CreateRecipeRequest {
pub name: String, pub name: String,
pub rating: u8, pub rating: u8,
pub ingredients: Vec<(i64, f64)>, pub ingredients: Vec<(i64, f64)>,
pub steps: Vec<String>, pub steps: String,
} }
#[derive(Serialize, Deserialize, Clone, Debug)] #[derive(Serialize, Deserialize, Clone, Debug)]
@ -105,7 +105,7 @@ pub struct ListRecipesResponse {
#[derive(Serialize, Deserialize, Clone, Debug)] #[derive(Serialize, Deserialize, Clone, Debug)]
pub struct RecipeInfo { pub struct RecipeInfo {
pub name: String, pub name: String,
pub steps: Vec<String>, pub steps: String,
pub ingredients: Vec<(i64, IngredientInfo, f64)>, pub ingredients: Vec<(i64, IngredientInfo, f64)>,
} }

View file

@ -421,7 +421,7 @@ fn AddIngredientInner(props: &AddIngredientProps) -> HtmlResult {
} }
Err(e) => { Err(e) => {
err.set(Some(format!("Could not add ingredient: {e}"))); err.set(Some(format!("Could not add ingredient: {e}")));
}, }
} }
}); });
} }
@ -612,8 +612,8 @@ fn RecipeViewerInner(props: &RecipeViewerInnerProps) -> HtmlResult {
}})} }})}
</ul> </ul>
<AddIngredient <AddIngredient
token={props.token.clone()} token={props.token.clone()}
household={props.household} household={props.household}
recipe={props.id} recipe={props.id}
update={update.clone()} update={update.clone()}
/> />
@ -622,7 +622,7 @@ fn RecipeViewerInner(props: &RecipeViewerInnerProps) -> HtmlResult {
<div class="text-start"> <div class="text-start">
<h2>{"Steps"}</h2> <h2>{"Steps"}</h2>
<ul class="list-group list-group-flush"> <ul class="list-group list-group-flush">
{for r.steps.iter().map(|text| html!{ {for r.steps.split('\n').map(|text| html!{
<li class="list-group-item">{text}</li> <li class="list-group-item">{text}</li>
})} })}
</ul> </ul>

View file

@ -290,26 +290,9 @@ pub fn RecipeCreator() -> Html {
}) })
}; };
let steps = use_state(im::Vector::new); let steps = use_state(String::new);
let on_step_change = {
let s = steps.clone(); let steps = steps.clone();
let on_add_step = Callback::from(move |_| {
let mut steps = (*s).clone();
steps.push_back(String::new());
s.set(steps);
});
let mk_step_del = |idx| {
let s = steps.clone();
Callback::from(move |_| {
let mut steps = (*s).clone();
steps.remove(idx);
s.set(steps);
})
};
let mk_step_change = |idx| {
let s = steps.clone();
Callback::from(move |e: Event| { Callback::from(move |e: Event| {
let Some(target) = e.target() else { let Some(target) = e.target() else {
return; return;
@ -319,9 +302,7 @@ pub fn RecipeCreator() -> Html {
return; return;
}; };
let mut steps = (*s).clone(); steps.set(target.value());
steps[idx] = target.value();
s.set(steps);
}) })
}; };
@ -376,7 +357,7 @@ pub fn RecipeCreator() -> Html {
.iter() .iter()
.map(|rcp_ig: &RecipeIngredient| (rcp_ig.id, rcp_ig.amount / (*pc) as f64)) .map(|rcp_ig: &RecipeIngredient| (rcp_ig.id, rcp_ig.amount / (*pc) as f64))
.collect(), .collect(),
steps: (*s).iter().cloned().collect(), steps: (*s).clone(),
}, },
) )
.await .await
@ -519,27 +500,11 @@ pub fn RecipeCreator() -> Html {
</div> </div>
<div> <div>
<h2>{"Steps"}</h2> <h2>{"Steps"}</h2>
<ul class="list-group list-group-flush"> <textarea
{for (*steps).iter().enumerate().map(|(idx, step)| { class="form-control"
html!{ value={(*steps).clone()}
<li class="list-group-item"> onchange={on_step_change}
<textarea />
class="form-control"
value={step.clone()}
onchange={mk_step_change(idx)}
/>
<button
class="btn btn-danger mt-1"
onclick={mk_step_del(idx)}
>
{"Remove"}
</button>
</li>
}
})
}
</ul>
<button class="btn btn-primary" onclick={on_add_step}>{"Add Step"}</button>
</div> </div>
<hr /> <hr />
<ModalToggleButton classes={classes!("btn", "btn-lg", "btn-primary")} modal_id="newRcpModal"> <ModalToggleButton classes={classes!("btn", "btn-lg", "btn-primary")} modal_id="newRcpModal">

View file

@ -32,10 +32,10 @@ impl Related<super::household::Entity> for Entity {
impl Related<super::recipe::Entity> for Entity { impl Related<super::recipe::Entity> for Entity {
fn to() -> RelationDef { fn to() -> RelationDef {
super::recipe_ingerdients::Relation::Recipe.def() super::recipe_ingredients::Relation::Recipe.def()
} }
fn via() -> Option<RelationDef> { fn via() -> Option<RelationDef> {
Some(super::recipe_ingerdients::Relation::Ingredient.def().rev()) Some(super::recipe_ingredients::Relation::Ingredient.def().rev())
} }
} }

View file

@ -6,5 +6,5 @@ pub mod household;
pub mod household_members; pub mod household_members;
pub mod ingredient; pub mod ingredient;
pub mod recipe; pub mod recipe;
pub mod recipe_ingerdients; pub mod recipe_ingredients;
pub mod user; pub mod user;

View file

@ -4,5 +4,5 @@ pub use super::household::Entity as Household;
pub use super::household_members::Entity as HouseholdMembers; pub use super::household_members::Entity as HouseholdMembers;
pub use super::ingredient::Entity as Ingredient; pub use super::ingredient::Entity as Ingredient;
pub use super::recipe::Entity as Recipe; pub use super::recipe::Entity as Recipe;
pub use super::recipe_ingerdients::Entity as RecipeIngerdients; pub use super::recipe_ingredients::Entity as RecipeIngredients;
pub use super::user::Entity as User; pub use super::user::Entity as User;

View file

@ -35,10 +35,10 @@ impl Related<super::household::Entity> for Entity {
impl Related<super::ingredient::Entity> for Entity { impl Related<super::ingredient::Entity> for Entity {
fn to() -> RelationDef { fn to() -> RelationDef {
super::recipe_ingerdients::Relation::Ingredient.def() super::recipe_ingredients::Relation::Ingredient.def()
} }
fn via() -> Option<RelationDef> { fn via() -> Option<RelationDef> {
Some(super::recipe_ingerdients::Relation::Recipe.def().rev()) Some(super::recipe_ingredients::Relation::Recipe.def().rev())
} }
} }

View file

@ -0,0 +1,48 @@
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
#[sea_orm(table_name = "recipe_ingredients")]
pub struct Model {
#[sea_orm(primary_key, auto_increment = false)]
pub recipe_id: i64,
#[sea_orm(primary_key, auto_increment = false)]
pub ingredient_id: i64,
#[sea_orm(column_type = "Double")]
pub amount: f64,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {
#[sea_orm(
belongs_to = "super::ingredient::Entity",
from = "Column::IngredientId",
to = "super::ingredient::Column::Id",
on_update = "Restrict",
on_delete = "Restrict"
)]
Ingredient,
#[sea_orm(
belongs_to = "super::recipe::Entity",
from = "Column::RecipeId",
to = "super::recipe::Column::Id",
on_update = "Restrict",
on_delete = "Restrict"
)]
Recipe,
}
impl Related<super::ingredient::Entity> for Entity {
fn to() -> RelationDef {
Relation::Ingredient.def()
}
}
impl Related<super::recipe::Entity> for Entity {
fn to() -> RelationDef {
Relation::Recipe.def()
}
}
impl ActiveModelBehavior for ActiveModel {}

View file

@ -11,7 +11,7 @@ use axum::{
}; };
use sea_orm::{prelude::*, ActiveValue, TransactionTrait}; use sea_orm::{prelude::*, ActiveValue, TransactionTrait};
use crate::entity::{ingredient, prelude::*, recipe, recipe_ingerdients, recipe_steps}; use crate::entity::{ingredient, prelude::*, recipe, recipe_ingredients};
use super::{ use super::{
household::AuthorizedHousehold, ingredients::IngredientExtractor, AppState, JsonResult, household::AuthorizedHousehold, ingredients::IngredientExtractor, AppState, JsonResult,
@ -31,19 +31,11 @@ pub(super) async fn create_recipe(
name: ActiveValue::Set(request.name), name: ActiveValue::Set(request.name),
ranking: ActiveValue::Set(request.rating as i32), ranking: ActiveValue::Set(request.rating as i32),
household: ActiveValue::Set(household.id), household: ActiveValue::Set(household.id),
steps: ActiveValue::Set(request.steps),
..Default::default() ..Default::default()
}; };
let recipe = model.insert(txn).await?; let recipe = model.insert(txn).await?;
for (num, text) in request.steps.into_iter().enumerate() {
let model = recipe_steps::ActiveModel {
num: ActiveValue::Set(num as _),
recipe_id: ActiveValue::Set(recipe.id),
text: ActiveValue::Set(text),
};
model.insert(txn).await?;
}
for (ig, amount) in request.ingredients { for (ig, amount) in request.ingredients {
if 0 == household if 0 == household
@ -57,7 +49,7 @@ pub(super) async fn create_recipe(
)))?; )))?;
} }
let model = recipe_ingerdients::ActiveModel { let model = recipe_ingredients::ActiveModel {
recipe_id: ActiveValue::Set(recipe.id), recipe_id: ActiveValue::Set(recipe.id),
ingredient_id: ActiveValue::Set(ig), ingredient_id: ActiveValue::Set(ig),
amount: ActiveValue::Set(amount), amount: ActiveValue::Set(amount),
@ -130,14 +122,6 @@ pub(super) async fn fetch_recipe(
State(state): State<AppState>, State(state): State<AppState>,
RecipeExtractor(recipe): RecipeExtractor, RecipeExtractor(recipe): RecipeExtractor,
) -> JsonResult<RecipeInfo> { ) -> JsonResult<RecipeInfo> {
let steps = recipe
.find_related(RecipeSteps)
.all(&state.db)
.await?
.into_iter()
.map(|m| m.text)
.collect();
let recipe_ingredients = recipe.find_related(Ingredient).all(&state.db).await?; let recipe_ingredients = recipe.find_related(Ingredient).all(&state.db).await?;
let mut ingredients = Vec::new(); let mut ingredients = Vec::new();
@ -149,7 +133,7 @@ pub(super) async fn fetch_recipe(
name: ingredient.name, name: ingredient.name,
unit: ingredient.unit, unit: ingredient.unit,
}, },
RecipeIngerdients::find_by_id((recipe.id, ingredient.id)) RecipeIngredients::find_by_id((recipe.id, ingredient.id))
.one(&state.db) .one(&state.db)
.await? .await?
.expect("Ingredient should exist as it was fetched") .expect("Ingredient should exist as it was fetched")
@ -159,7 +143,7 @@ pub(super) async fn fetch_recipe(
Ok(RecipeInfo { Ok(RecipeInfo {
name: recipe.name, name: recipe.name,
steps, steps: recipe.steps,
ingredients, ingredients,
} }
.into()) .into())
@ -187,7 +171,7 @@ pub(super) async fn edit_ig_amount(
IngredientExtractor(ingredient): IngredientExtractor, IngredientExtractor(ingredient): IngredientExtractor,
Json(req): Json<RecipeIngredientEditRequest>, Json(req): Json<RecipeIngredientEditRequest>,
) -> JsonResult<EmptyResponse> { ) -> JsonResult<EmptyResponse> {
let active_model = recipe_ingerdients::ActiveModel { let active_model = recipe_ingredients::ActiveModel {
recipe_id: ActiveValue::Set(recipe.id), recipe_id: ActiveValue::Set(recipe.id),
ingredient_id: ActiveValue::Set(ingredient.id), ingredient_id: ActiveValue::Set(ingredient.id),
amount: ActiveValue::Set(req.amount), amount: ActiveValue::Set(req.amount),
@ -203,7 +187,7 @@ pub(super) async fn delete_ig(
RecipeExtractor(recipe): RecipeExtractor, RecipeExtractor(recipe): RecipeExtractor,
IngredientExtractor(ingredient): IngredientExtractor, IngredientExtractor(ingredient): IngredientExtractor,
) -> JsonResult<EmptyResponse> { ) -> JsonResult<EmptyResponse> {
RecipeIngerdients::delete_by_id((recipe.id, ingredient.id)) RecipeIngredients::delete_by_id((recipe.id, ingredient.id))
.exec(&state.db) .exec(&state.db)
.await?; .await?;
@ -216,7 +200,7 @@ pub(super) async fn add_ig_request(
IngredientExtractor(ingredient): IngredientExtractor, IngredientExtractor(ingredient): IngredientExtractor,
Json(req): Json<AddRecipeIngredientRequest>, Json(req): Json<AddRecipeIngredientRequest>,
) -> JsonResult<EmptyResponse> { ) -> JsonResult<EmptyResponse> {
let model = recipe_ingerdients::ActiveModel { let model = recipe_ingredients::ActiveModel {
recipe_id: ActiveValue::Set(recipe.id), recipe_id: ActiveValue::Set(recipe.id),
ingredient_id: ActiveValue::Set(ingredient.id), ingredient_id: ActiveValue::Set(ingredient.id),
amount: ActiveValue::Set(req.amount), amount: ActiveValue::Set(req.amount),