app: Allow to list recipes
This commit is contained in:
parent
80e3d7ee86
commit
f3788e31a9
3 changed files with 136 additions and 6 deletions
|
|
@ -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
84
app/src/recipe.rs
Normal 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>
|
||||
}
|
||||
}
|
||||
|
|
@ -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,
|
||||
},
|
||||
];
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue