summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorBenedikt Peetz <benedikt.peetz@b-peetz.de>2025-10-23 02:24:29 +0200
committerBenedikt Peetz <benedikt.peetz@b-peetz.de>2025-10-23 02:24:29 +0200
commit427ce16023613536b8176e6dee7c1580a5980c97 (patch)
treeab39dffcf89eacbcb19a251d540c46d9ee5b38d0 /src
parentfeat(buy): Provide basic buy interface (diff)
downloadweb-client-427ce16023613536b8176e6dee7c1580a5980c97.zip
feat(treewide): Make usage more intuitive
Diffstat (limited to '')
-rw-r--r--src/api/mod.rs3
-rw-r--r--src/components/async_fetch.rs32
-rw-r--r--src/components/banner.rs6
-rw-r--r--src/components/container.rs47
-rw-r--r--src/components/input_placeholder.rs15
-rw-r--r--src/components/inventory.rs55
-rw-r--r--src/components/mod.rs4
-rw-r--r--src/components/product_overview.rs38
-rw-r--r--src/components/recipies.rs10
-rw-r--r--src/components/select_placeholder.rs22
-rw-r--r--src/lib.rs11
-rw-r--r--src/pages/buy.rs (renamed from src/components/buy.rs)0
-rw-r--r--src/pages/inventory.rs54
-rw-r--r--src/pages/mod.rs3
-rw-r--r--src/pages/recipies.rs8
15 files changed, 160 insertions, 148 deletions
diff --git a/src/api/mod.rs b/src/api/mod.rs
index 3879223..bc800fb 100644
--- a/src/api/mod.rs
+++ b/src/api/mod.rs
@@ -11,7 +11,8 @@ use rocie_client::{
},
api_get_unit_api::unit_by_id,
api_get_unit_property_api::unit_property_by_id,
- api_set_barcode_api::buy_barcode, configuration::Configuration,
+ api_set_barcode_api::buy_barcode,
+ configuration::Configuration,
},
models::{
BarcodeId, Product, ProductAmount, ProductId, Unit, UnitId, UnitProperty, UnitPropertyId,
diff --git a/src/components/async_fetch.rs b/src/components/async_fetch.rs
index f24e3a5..7bf44a0 100644
--- a/src/components/async_fetch.rs
+++ b/src/components/async_fetch.rs
@@ -15,31 +15,21 @@ pub(crate) use AsyncResource;
macro_rules! AsyncFetch {
(
- fetcher = $fetcher:block
- producer = |$bound_variable:pat_param| $producer:block
+ @map_error_in_producer
+ fetcher = $fetcher:expr,
+ producer = $producer:expr $(,)?
) => {{
- use leptos::{
- prelude::{ElementChild, LocalResource, Suspend, Transition},
- view,
- };
-
- view! {
- <Transition fallback=|| {
- view! { <p>"Loading..."</p> }
- }>
- {move || Suspend::new(async move {
- let resource = { LocalResource::new(move || $fetcher) };
- resource
- .await
- .map(|$bound_variable| $producer)
- })}
- </Transition>
+ AsyncFetch! {
+ @map_error_in_producer
+ from_resource = leptos::prelude::LocalResource::new(move || $fetcher),
+ producer = $producer
}
}};
+
(
@map_error_in_producer
- from_resource = $resource:ident
- producer = |$bound_variable:pat_param| $producer:block
+ from_resource = $resource:expr,
+ producer = $producer:expr $(,)?
) => {{
use leptos::prelude::{ElementChild, Suspend, Transition};
@@ -50,7 +40,7 @@ macro_rules! AsyncFetch {
{move || Suspend::new(async move {
$resource
.await
- .map(|$bound_variable| $producer)
+ .map($producer)
})}
</Transition>
}
diff --git a/src/components/banner.rs b/src/components/banner.rs
index acaaf62..3244a07 100644
--- a/src/components/banner.rs
+++ b/src/components/banner.rs
@@ -9,9 +9,5 @@ pub fn Banner<T>(mut text: T) -> impl IntoView
where
T: FnMut() -> String + Send + 'static,
{
- view! {
- <p class="text-white rounded-lg m-2 p-2 bg-red-600">
- {move || text()}
- </p>
- }
+ view! { <p class="text-white rounded-lg m-2 p-2 bg-red-600">{move || text()}</p> }
}
diff --git a/src/components/container.rs b/src/components/container.rs
index 7a4a64f..83b9584 100644
--- a/src/components/container.rs
+++ b/src/components/container.rs
@@ -11,25 +11,36 @@ pub fn Container(
buttons: Vec<(impl IntoView, &'static str)>,
children: Children,
) -> impl IntoView {
+ assert!(!buttons.is_empty());
+
+ let first_button_path = buttons.first().expect("Should have at least on button").1;
+
view! {
- <div class="p-4 mt-4 mr-4 ml-4 md-2 rounded-lg border-gray-600 border">
- <p class="text-lg text-bold">{header}</p>
- {children()}
+ <button
+ type="button"
+ on:click=|_| {
+ use_navigate()(first_button_path, NavigateOptions::default());
+ }
+ >
+ <div class="p-4 mt-4 mr-4 ml-4 md-2 text-justify rounded-lg border-gray-600 border">
+ <p class="text-lg text-bold">{header}</p>
+ {children()}
- <ul class="flex flex-row gap-1 pt-2 overflow-x-auto">
- {buttons
- .into_iter()
- .map(|(name, path)| {
- view! {
- <li class="bg-green-400/40 p-2 first:rounded-l-full last:rounded-r-full">
- <button on:click=move |_| {
- use_navigate()(path, NavigateOptions::default());
- }>{name}</button>
- </li>
- }
- })
- .collect::<Vec<_>>()}
- </ul>
- </div>
+ <ul class="flex flex-row gap-1 pt-2 overflow-x-auto">
+ {buttons
+ .into_iter()
+ .map(|(name, path)| {
+ view! {
+ <li class="bg-green-400/40 p-2 first:rounded-l-full last:rounded-r-full">
+ <button on:click=move |_| {
+ use_navigate()(path, NavigateOptions::default());
+ }>{name}</button>
+ </li>
+ }
+ })
+ .collect::<Vec<_>>()}
+ </ul>
+ </div>
+ </button>
}
}
diff --git a/src/components/input_placeholder.rs b/src/components/input_placeholder.rs
index 99b3196..0589363 100644
--- a/src/components/input_placeholder.rs
+++ b/src/components/input_placeholder.rs
@@ -96,12 +96,7 @@ pub fn InputPlaceholder(
{label}
</label>
- <Show
- when=move || {
- !autocomplete_signal.get().is_empty()
- }
- fallback=move || ()
- >
+ <Show when=move || { !autocomplete_signal.get().is_empty() } fallback=move || ()>
<div class="\
absolute \
top-0 \
@@ -139,7 +134,7 @@ pub fn InputPlaceholder(
provide_auto_completion(
auto_complete,
autocomplete_set,
- reactive
+ reactive,
)
})
}}
@@ -178,10 +173,10 @@ fn provide_auto_completion(
autocomplete_set.set(item2.clone());
reactive
.expect(
- "Should be set, \
- when autocomplete is used")
+ "Should be set, \
+ when autocomplete is used",
+ )
.set(Some(item2.clone()));
-
info!("Set autocomplete to {item2}.");
}
>
diff --git a/src/components/inventory.rs b/src/components/inventory.rs
deleted file mode 100644
index 5855b33..0000000
--- a/src/components/inventory.rs
+++ /dev/null
@@ -1,55 +0,0 @@
-use leptos::{
- IntoView, component,
- prelude::{ClassAttribute, ElementChild},
- view,
-};
-
-use crate::{
- api::{get_full_product_by_id, get_products},
- components::{async_fetch::AsyncFetch, site_header::SiteHeader},
-};
-
-#[component]
-pub fn Inventory() -> impl IntoView {
- view! {
- <SiteHeader logo=icondata_io::IoArrowBack back_location="/" name="Inventory" />
-
- <ul class="flex flex-col p-2 m-2">
- {
- AsyncFetch! {
- fetcher = {get_products()}
- producer = |products| {
- products
- .into_iter()
- .map(|product| {
- view! {
- {AsyncFetch! {
- fetcher = {get_full_product_by_id(product.id)}
- producer = |(product, amount, unit)| {
- view! {
- <ul class="my-3">
- <li class="m-2">{product.name}</li>
- <li class="m-2">
- <span class="bg-gray-200 p-1 px-2 rounded-lg">
- {
- format!(
- "{} {}",
- amount.amount.value,
- unit.short_name
- )
- }
- </span>
- </li>
- </ul>
- }
- }
- }}
- }
- })
- .collect::<Vec<_>>()
- }
- }
- }
- </ul>
- }
-}
diff --git a/src/components/mod.rs b/src/components/mod.rs
index ca2ac10..efc4842 100644
--- a/src/components/mod.rs
+++ b/src/components/mod.rs
@@ -2,16 +2,14 @@ use std::sync::atomic::{AtomicU32, Ordering};
// Generic
pub mod async_fetch;
+pub mod banner;
pub mod container;
pub mod form;
pub mod icon_p;
pub mod input_placeholder;
pub mod select_placeholder;
-pub mod banner;
// Specific
-pub mod buy;
-pub mod inventory;
pub mod product_overview;
pub mod recipies;
pub mod site_header;
diff --git a/src/components/product_overview.rs b/src/components/product_overview.rs
index 777baef..5413dc1 100644
--- a/src/components/product_overview.rs
+++ b/src/components/product_overview.rs
@@ -11,33 +11,31 @@ pub fn ProductOverview() -> impl IntoView {
<Container
header="Inventory"
buttons=vec![
- (
- view! { <IconP icon=icondata_io::IoClipboardOutline text="Inventory" /> },
- "inventory",
- ),
+ (view! { <IconP icon=icondata_io::IoClipboard text="Inventory" /> }, "inventory"),
(view! { <IconP icon=icondata_io::IoPricetags text="Consume" /> }, "consume"),
(view! { <IconP icon=icondata_io::IoStorefront text="Buy" /> }, "buy"),
]
>
{
AsyncFetch! {
- fetcher = {get_products()}
- producer = |products| {
- let products_num = products.len();
- let plural_s = if products_num == 1 { "" } else { "s" };
- let products_value = 2;
- let products_currency = "EUR";
+ @map_error_in_producer
+ fetcher = get_products(),
+ producer = |products| {
+ let products_num = products.len();
+ let plural_s = if products_num == 1 { "" } else { "s" };
+ let products_value = 2;
+ let products_currency = "EUR";
- view! {
- <p>
- {format!(
- "You have {products_num} product{plural_s} \
- in stock with a value \
- of {products_value} {products_currency}.",
- )}
- </p>
- }
- }
+ view! {
+ <p>
+ {format!(
+ "You have {products_num} product{plural_s} \
+ in stock with a value \
+ of {products_value} {products_currency}.",
+ )}
+ </p>
+ }
+ }
}
}
</Container>
diff --git a/src/components/recipies.rs b/src/components/recipies.rs
index 1bd3a0d..f7903e4 100644
--- a/src/components/recipies.rs
+++ b/src/components/recipies.rs
@@ -1,11 +1,17 @@
use leptos::{IntoView, component, prelude::ElementChild, view};
-use crate::components::container::Container;
+use crate::components::{container::Container, icon_p::IconP};
#[component]
pub fn Recipies() -> impl IntoView {
view! {
- <Container header="Recipies" buttons=vec![("Mealplan", "mealplan")]>
+ <Container
+ header="Recipies"
+ buttons=vec![
+ (view! { <IconP icon=icondata_io::IoFastFood text="Recipies" /> }, "recipies"),
+ (view! { <IconP icon=icondata_io::IoCalendarSharp text="Mealplan" /> }, "mealplan"),
+ ]
+ >
<p>"You have 0 recipies."</p>
</Container>
}
diff --git a/src/components/select_placeholder.rs b/src/components/select_placeholder.rs
index 2e0f783..7289793 100644
--- a/src/components/select_placeholder.rs
+++ b/src/components/select_placeholder.rs
@@ -41,16 +41,18 @@ pub fn SelectPlaceholder(
"
node_ref=node_ref
>
- {move || AsyncFetch! {
- @map_error_in_producer
- from_resource = options
- producer = |options| {
- options
- .into_iter()
- .map(|(label, value)| {
- view! { <option value=value>{label}</option> }
- })
- .collect_view()
+ {move || {
+ AsyncFetch! {
+ @map_error_in_producer
+ from_resource = options,
+ producer = |options| {
+ options
+ .into_iter()
+ .map(|(label, value)| {
+ view! { <option value=value>{label}</option> }
+ })
+ .collect_view()
+ }
}
}}
</select>
diff --git a/src/lib.rs b/src/lib.rs
index 3813ebb..b5ca65a 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -30,9 +30,8 @@ use leptos_router::{
use reactive_stores::Store;
use rocie_client::apis::configuration::Configuration;
-use crate::{
- components::{buy::Buy, inventory::Inventory},
- pages::{home::Home, not_found::NotFound},
+use crate::pages::{
+ buy::Buy, home::Home, inventory::Inventory, not_found::NotFound, recipies::Recipies,
};
#[derive(Debug, Clone, Store)]
@@ -84,6 +83,12 @@ pub fn App() -> impl IntoView {
view! { <Buy /> }
}
/>
+ <Route
+ path=path!("/recipies")
+ view=move || {
+ view! { <Recipies /> }
+ }
+ />
</Routes>
</Router>
}
diff --git a/src/components/buy.rs b/src/pages/buy.rs
index cb4cff4..cb4cff4 100644
--- a/src/components/buy.rs
+++ b/src/pages/buy.rs
diff --git a/src/pages/inventory.rs b/src/pages/inventory.rs
new file mode 100644
index 0000000..e5ff6ae
--- /dev/null
+++ b/src/pages/inventory.rs
@@ -0,0 +1,54 @@
+use leptos::{
+ IntoView, component,
+ prelude::{ClassAttribute, ElementChild},
+ view,
+};
+use rocie_client::models::{Product, ProductAmount, Unit};
+
+use crate::{
+ api::{get_full_product_by_id, get_products},
+ components::{async_fetch::AsyncFetch, site_header::SiteHeader},
+};
+
+#[component]
+pub fn Inventory() -> impl IntoView {
+ view! {
+ <SiteHeader logo=icondata_io::IoArrowBack back_location="/" name="Inventory" />
+
+ <ul class="flex flex-col p-2 m-2">
+ {
+ AsyncFetch! {
+ @map_error_in_producer
+ fetcher = get_products(),
+ producer = render_products,
+ }
+ }
+ </ul>
+ }
+}
+
+fn render_products(products: Vec<Product>) -> impl IntoView {
+ products
+ .into_iter()
+ .map(|product| {
+ AsyncFetch! {
+ @map_error_in_producer
+ fetcher = get_full_product_by_id(product.id),
+ producer = format_full_product,
+ }
+ })
+ .collect::<Vec<_>>()
+}
+
+fn format_full_product((product, amount, unit): (Product, ProductAmount, Unit)) -> impl IntoView {
+ view! {
+ <ul class="my-3">
+ <li class="m-2">{product.name}</li>
+ <li class="m-2">
+ <span class="bg-gray-200 p-1 px-2 rounded-lg">
+ {format!("{} {}", amount.amount.value, unit.short_name)}
+ </span>
+ </li>
+ </ul>
+ }
+}
diff --git a/src/pages/mod.rs b/src/pages/mod.rs
index 8829694..a6057cd 100644
--- a/src/pages/mod.rs
+++ b/src/pages/mod.rs
@@ -1,2 +1,5 @@
+pub mod buy;
pub mod home;
+pub mod inventory;
pub mod not_found;
+pub mod recipies;
diff --git a/src/pages/recipies.rs b/src/pages/recipies.rs
new file mode 100644
index 0000000..1fc9dcc
--- /dev/null
+++ b/src/pages/recipies.rs
@@ -0,0 +1,8 @@
+use leptos::{IntoView, component, view};
+
+use crate::components::site_header::SiteHeader;
+
+#[component]
+pub fn Recipies() -> impl IntoView {
+ view! { <SiteHeader logo=icondata_io::IoArrowBack back_location="/" name="Recipies" /> }
+}