app: Isolate RecipeInfoView in a separate component
This commit is contained in:
parent
5b44cc7dde
commit
8cf5803c1e
1 changed files with 124 additions and 99 deletions
|
|
@ -1,3 +1,5 @@
|
|||
use std::rc::Rc;
|
||||
|
||||
use api::{
|
||||
AddRecipeIngredientRequest, IngredientInfo, RecipeEditRating, RecipeEditStepsRequest,
|
||||
RecipeInfo, RecipeIngredientEditRequest, RecipeRenameRequest,
|
||||
|
|
@ -128,7 +130,7 @@ struct RecipeViewerInnerProps {
|
|||
household: Uuid,
|
||||
}
|
||||
|
||||
async fn fetch_recipe(token: String, household: Uuid, id: i64) -> anyhow::Result<RecipeInfo> {
|
||||
async fn fetch_recipe(token: String, household: Uuid, id: i64) -> anyhow::Result<Rc<RecipeInfo>> {
|
||||
let rsp = gloo_net::http::Request::get(api!("household/{household}/recipe/{id}"))
|
||||
.header("Authorization", &format!("Bearer {token}"))
|
||||
.send()
|
||||
|
|
@ -139,7 +141,7 @@ async fn fetch_recipe(token: String, household: Uuid, id: i64) -> anyhow::Result
|
|||
anyhow::bail!("Could not get recipe (code={}): {body}", rsp.status());
|
||||
}
|
||||
|
||||
Ok(rsp.json().await?)
|
||||
Ok(Rc::new(rsp.json().await?))
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Properties)]
|
||||
|
|
@ -756,25 +758,23 @@ fn EditRating(props: &EditRatingProps) -> Html {
|
|||
</>}
|
||||
}
|
||||
|
||||
#[derive(Properties, PartialEq, Clone)]
|
||||
struct RecipeInfoProps {
|
||||
token: String,
|
||||
household: Uuid,
|
||||
update: Callback<()>,
|
||||
recipe_id: i64,
|
||||
info: Rc<RecipeInfo>,
|
||||
}
|
||||
|
||||
#[function_component]
|
||||
fn RecipeViewerInner(props: &RecipeViewerInnerProps) -> HtmlResult {
|
||||
let recipe_render = use_state(|| 0u64);
|
||||
let recipe = use_future_with_deps(
|
||||
|_| fetch_recipe(props.token.clone(), props.household, props.id),
|
||||
*recipe_render,
|
||||
)?;
|
||||
|
||||
let update = Callback::from(move |_| {
|
||||
recipe_render.set((*recipe_render).wrapping_add(1));
|
||||
});
|
||||
|
||||
fn RecipeInfoView(props: &RecipeInfoProps) -> Html {
|
||||
let error = use_state(|| None::<String>);
|
||||
|
||||
let mk_del_ig = |&id| {
|
||||
let update = update.clone();
|
||||
let update = props.update.clone();
|
||||
let token = props.token.clone();
|
||||
let household = props.household;
|
||||
let recipe = props.id;
|
||||
let recipe = props.recipe_id;
|
||||
let err = error.clone();
|
||||
Callback::from(move |_| {
|
||||
let update = update.clone();
|
||||
|
|
@ -794,23 +794,22 @@ fn RecipeViewerInner(props: &RecipeViewerInnerProps) -> HtmlResult {
|
|||
})
|
||||
};
|
||||
|
||||
Ok(match &*recipe {
|
||||
Ok(r) => html! {<>
|
||||
<h1>{&r.name} <RecipeRating rating={r.rating} /> </h1>
|
||||
html! {<>
|
||||
<h1>{&props.info.name} <RecipeRating rating={props.info.rating} /> </h1>
|
||||
<div class="mt-2">
|
||||
<EditName
|
||||
token={props.token.clone()}
|
||||
id={props.id}
|
||||
id={props.recipe_id}
|
||||
household={props.household}
|
||||
name={r.name.clone()}
|
||||
update={update.clone()}
|
||||
name={props.info.name.clone()}
|
||||
update={props.update.clone()}
|
||||
/>
|
||||
<EditRating
|
||||
token={props.token.clone()}
|
||||
recipe={props.id}
|
||||
recipe={props.recipe_id}
|
||||
household={props.household}
|
||||
rating={r.rating + 1}
|
||||
update={update.clone()}
|
||||
rating={props.info.rating + 1}
|
||||
update={props.update.clone()}
|
||||
/>
|
||||
</div>
|
||||
if let Some(e) = &*error {
|
||||
|
|
@ -822,7 +821,7 @@ fn RecipeViewerInner(props: &RecipeViewerInnerProps) -> HtmlResult {
|
|||
<div class="text-start">
|
||||
<h2>{"Ingredients"}</h2>
|
||||
<ul class="list-group mb-2">
|
||||
{for r.ingredients.iter().map(|(id, info, amount)| {
|
||||
{for props.info.ingredients.iter().map(|(id, info, amount)| {
|
||||
let delete_modal_id = format!("rcpRmIg{id}");
|
||||
let amount_rounded = amount.round();
|
||||
html!{
|
||||
|
|
@ -848,11 +847,11 @@ fn RecipeViewerInner(props: &RecipeViewerInnerProps) -> HtmlResult {
|
|||
</ModalToggleButton>
|
||||
<EditIngredient
|
||||
token={props.token.clone()}
|
||||
recipe={props.id}
|
||||
recipe={props.recipe_id}
|
||||
ingredient={*id}
|
||||
household={props.household}
|
||||
amount={*amount}
|
||||
update={update.clone()}
|
||||
update={props.update.clone()}
|
||||
/>
|
||||
</div>
|
||||
</li>
|
||||
|
|
@ -861,27 +860,53 @@ fn RecipeViewerInner(props: &RecipeViewerInnerProps) -> HtmlResult {
|
|||
<AddIngredient
|
||||
token={props.token.clone()}
|
||||
household={props.household}
|
||||
recipe={props.id}
|
||||
update={update.clone()}
|
||||
recipe={props.recipe_id}
|
||||
update={props.update.clone()}
|
||||
/>
|
||||
</div>
|
||||
<hr />
|
||||
<div class="text-start">
|
||||
<h2>{"Steps"}</h2>
|
||||
<ul class="list-group list-group-flush">
|
||||
{for r.steps.split('\n').map(|text| html!{
|
||||
{for props.info.steps.split('\n').map(|text| html!{
|
||||
<li class="list-group-item">{text}</li>
|
||||
})}
|
||||
</ul>
|
||||
<EditSteps
|
||||
token={props.token.clone()}
|
||||
household={props.household}
|
||||
recipe={props.id}
|
||||
steps={r.steps.clone()}
|
||||
update={update}
|
||||
recipe={props.recipe_id}
|
||||
steps={props.info.steps.clone()}
|
||||
update={props.update.clone()}
|
||||
/>
|
||||
</div>
|
||||
</>},
|
||||
</>}
|
||||
}
|
||||
|
||||
#[function_component]
|
||||
fn RecipeViewerInner(props: &RecipeViewerInnerProps) -> HtmlResult {
|
||||
let recipe_render = use_state(|| 0u64);
|
||||
let recipe = use_future_with_deps(
|
||||
|_| fetch_recipe(props.token.clone(), props.household, props.id),
|
||||
*recipe_render,
|
||||
)?;
|
||||
|
||||
let update = Callback::from(move |_| {
|
||||
recipe_render.set((*recipe_render).wrapping_add(1));
|
||||
});
|
||||
|
||||
Ok(match &*recipe {
|
||||
Ok(r) => {
|
||||
html! {
|
||||
<RecipeInfoView
|
||||
token={props.token.clone()}
|
||||
recipe_id={props.id}
|
||||
info={r.clone()}
|
||||
household={props.household}
|
||||
{update}
|
||||
/>
|
||||
}
|
||||
}
|
||||
Err(e) => html! {
|
||||
<div class={classes!("alert", "alert-danger")} role="alert">
|
||||
{format!("Error fetching recipe: {e}")}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue