app,server: Allow to display a recipe

This commit is contained in:
traxys 2023-06-25 15:13:15 +02:00
parent f3788e31a9
commit 1a0ffb2d89
5 changed files with 159 additions and 4 deletions

View file

@ -515,7 +515,7 @@ fn switch(route: Route) -> Html {
},
Route::Recipe { id } => html! {
<GlobalStateRedirector {route}>
{format!("RECIPE {id}")}
<recipe::RecipeViewer {id} />
</GlobalStateRedirector>
},
Route::SearchRecipe => html!{

View file

@ -1,3 +1,4 @@
use api::RecipeInfo;
use uuid::Uuid;
use yew::{prelude::*, suspense::use_future};
use yew_router::prelude::*;
@ -34,7 +35,7 @@ fn RecipeListInner(props: &RecipeListProps) -> HtmlResult {
Ok(match &*state {
Ok(l) => html! {
<div class="container text-center">
<div class="row row-cols-2 row-cols-sm-2 row-cols-md-4 g-2 mb-1">
<div class="row row-cols-2 row-cols-sm-2 row-cols-md-4 g-2 mb-2">
{for l.recipes.iter().map(|(id, name)| html!{
<div class="col" key={*id}>
<div class="p-3 border rounded border-light-subtle h-100">
@ -82,3 +83,89 @@ pub fn RecipeList() -> Html {
</div>
}
}
#[derive(PartialEq, Eq, Clone, Properties)]
pub struct RecipeViewerProps {
pub id: i64,
}
#[derive(PartialEq, Eq, Clone, Properties)]
struct RecipeViewerInnerProps {
id: i64,
token: String,
household: Uuid,
}
async fn fetch_recipe(token: String, household: Uuid, id: i64) -> anyhow::Result<RecipeInfo> {
let rsp = gloo_net::http::Request::get(api!("household/{household}/recipe/{id}"))
.header("Authorization", &format!("Bearer {token}"))
.send()
.await?;
if !rsp.ok() {
let body = rsp.text().await.unwrap_or_default();
anyhow::bail!("Could not get recipe (code={}): {body}", rsp.status());
}
Ok(rsp.json().await?)
}
#[function_component]
fn RecipeViewerInner(props: &RecipeViewerInnerProps) -> HtmlResult {
let recipe = use_future(|| fetch_recipe(props.token.clone(), props.household, props.id))?;
Ok(match &*recipe {
Ok(r) => html! {<>
<h1>{&r.name}</h1>
<hr />
<div class="text-start">
<h2>{"Ingredients"}</h2>
<ul class="list-group">
{for r.ingredients.iter().map(|(id, info, amount)| html!{
<li key={*id} class="list-group-item">
{format!("{amount}{} {}", info.unit.as_deref().unwrap_or(""), info.name)}
</li>
})}
</ul>
</div>
<hr />
<div class="text-start">
<h2>{"Steps"}</h2>
<ul class="list-group list-group-flush">
{for r.steps.iter().map(|text| html!{
<li class="list-group-item">{text}</li>
})}
</ul>
</div>
</>},
Err(e) => html! {
<div class={classes!("alert", "alert-danger")} role="alert">
{format!("Error fetching recipe: {e}")}
</div>
},
})
}
#[function_component]
pub fn RecipeViewer(props: &RecipeViewerProps) -> Html {
let global_state = use_state(RegaladeGlobalState::get);
let fallback = html! {
<div class="spinner-border" role="status">
<span class="visually-hidden">{"Loading ..."}</span>
</div>
};
html! {
<div class="d-flex align-items-center justify-content-center w-100">
<div class={classes!("container", "text-center", "rounded", "border", "pt-2", "m-2")}>
<Suspense {fallback}>
<RecipeViewerInner
id={props.id}
token={global_state.token.token.clone()}
household={global_state.household.id}
/>
</Suspense>
</div>
</div>
}
}