app: Allow to list recipes

This commit is contained in:
traxys 2023-06-25 14:12:09 +02:00
parent 80e3d7ee86
commit f3788e31a9
3 changed files with 136 additions and 6 deletions

View file

@ -22,6 +22,7 @@ mod bootstrap;
mod ingredients;
mod recipe_creator;
mod sidebar;
mod recipe;
const API_ROUTE: &str = match option_env!("REGALADE_API_SERVER_BASE") {
None => "http://localhost:8085",
@ -50,11 +51,45 @@ enum Route {
NewRecipe,
#[at("/recipe/:id")]
Recipe { id: i64 },
#[at("/recipe")]
SearchRecipe,
#[at("/404")]
#[not_found]
NotFound,
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
enum RouteKind {
Index,
Ingredients,
NewRecipe,
Recipe,
}
impl Route {
fn kind(&self) -> Option<RouteKind> {
match self {
Route::Index => Some(RouteKind::Index),
Route::Ingredients => Some(RouteKind::Ingredients),
Route::NewRecipe => Some(RouteKind::NewRecipe),
Route::Recipe { .. } => Some(RouteKind::Recipe),
Route::SearchRecipe => Some(RouteKind::Recipe),
_ => None,
}
}
}
impl RouteKind {
fn redirect_to(&self) -> Route {
match self {
RouteKind::Index => Route::Index,
RouteKind::Ingredients => Route::Ingredients,
RouteKind::NewRecipe => Route::NewRecipe,
RouteKind::Recipe => Route::SearchRecipe,
}
}
}
#[function_component]
fn App() -> Html {
html! {
@ -483,6 +518,11 @@ fn switch(route: Route) -> Html {
{format!("RECIPE {id}")}
</GlobalStateRedirector>
},
Route::SearchRecipe => html!{
<GlobalStateRedirector {route}>
<recipe::RecipeList />
</GlobalStateRedirector>
},
Route::NotFound => html! {
"Page not found"
},

84
app/src/recipe.rs Normal file
View file

@ -0,0 +1,84 @@
use uuid::Uuid;
use yew::{prelude::*, suspense::use_future};
use yew_router::prelude::*;
use crate::{api, RegaladeGlobalState, Route};
async fn get_all_recipes(
token: String,
household: Uuid,
) -> anyhow::Result<api::ListRecipesResponse> {
let rsp = gloo_net::http::Request::get(api!("household/{household}/recipe"))
.header("Authorization", &format!("Bearer {token}"))
.send()
.await?;
if !rsp.ok() {
let body = rsp.text().await.unwrap_or_default();
anyhow::bail!("Could not get recipes (code={}): {body}", rsp.status());
}
Ok(rsp.json().await?)
}
#[derive(Debug, Clone, PartialEq, Eq, Properties)]
struct RecipeListProps {
token: String,
household: Uuid,
}
#[function_component]
fn RecipeListInner(props: &RecipeListProps) -> HtmlResult {
let state = use_future(|| get_all_recipes(props.token.clone(), props.household))?;
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">
{for l.recipes.iter().map(|(id, name)| html!{
<div class="col" key={*id}>
<div class="p-3 border rounded border-light-subtle h-100">
<Link<Route>
classes={classes!(
"link-light",
"link-offset-2",
"link-underline-opacity-25",
"link-underline-opacity-100-hover",
)}
to={Route::Recipe { id: *id }}
>
{name}
</Link<Route>>
</div>
</div>
})}
</div>
</div>
},
Err(e) => html! {
<div class={classes!("alert", "alert-danger")} role="alert">
{format!("Error fetching recipes: {e}")}
</div>
},
})
}
#[function_component]
pub fn RecipeList() -> Html {
let fallback = html! {"Loading ..."};
let global_state = use_state(RegaladeGlobalState::get);
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")}>
<h2>{"Recipes"}</h2>
<Suspense {fallback}>
<RecipeListInner
token={global_state.token.token.clone()}
household={global_state.household.id}
/>
</Suspense>
</div>
</div>
}
}

View file

@ -10,13 +10,14 @@ use crate::{
api,
bootstrap::{bs, ConfirmDangerModal, FormModal},
do_add_user_to_household, do_resolve_user, HouseholdInfo, RegaladeGlobalState, Route,
RouteKind,
};
#[derive(PartialEq)]
struct MenuEntry {
icon: &'static str,
label: &'static str,
page: Route,
page: RouteKind,
}
#[derive(Properties, PartialEq)]
@ -298,7 +299,7 @@ fn Sidebar(props: &SidebarProps) -> Html {
)}>
{
for props.entries.iter().map(|e| {
let active = if e.page == props.current {
let active = if Some(e.page) == props.current.kind() {
Some("active")
} else {
None
@ -311,7 +312,7 @@ fn Sidebar(props: &SidebarProps) -> Html {
"text-white",
active,
)}
to={e.page}
to={e.page.redirect_to()}
>
<i class={classes!("fs-4", e.icon)}></i>
<span class={classes!("ms-2", "d-none", "d-sm-inline")}>
@ -433,17 +434,22 @@ pub(crate) fn RegaladeSidebar(props: &RegaladeSidebarProps) -> Html {
MenuEntry {
label: "Home",
icon: "bi-house",
page: Route::Index,
page: RouteKind::Index,
},
MenuEntry {
label: "Recipes",
icon: "bi-book",
page: RouteKind::Recipe,
},
MenuEntry {
label: "Ingredients",
icon: "bi-egg-fill",
page: Route::Ingredients,
page: RouteKind::Ingredients,
},
MenuEntry {
label: "New Recipe",
icon: "bi-clipboard2-plus-fill",
page: Route::NewRecipe,
page: RouteKind::NewRecipe,
},
];