From f6a3fb9c4d8dd86f78c9f75a23c1ac35bf35d4eb Mon Sep 17 00:00:00 2001
From: Benedikt Peetz
Date: Thu, 19 Mar 2026 07:45:14 +0100
Subject: feat(treewide): Commit MVP
---
src/api/mod.rs | 221 +++++++++++++++++--
src/components/async_fetch.rs | 12 +-
src/components/buy.rs | 1 +
src/components/catch_errors.rs | 40 ++++
src/components/checkbox_placeholder.rs | 54 +++++
src/components/container.rs | 52 ++---
src/components/inventory.rs | 4 +-
src/components/login_wall.rs | 42 ++++
src/components/mod.rs | 7 +
src/components/product_overview.rs | 19 +-
src/components/product_parent_overview.rs | 37 ++++
src/components/recipies.rs | 20 +-
src/components/textarea_placeholder.rs | 60 ++++++
src/components/unit_overview.rs | 37 +++-
src/lib.rs | 60 +++++-
src/pages/associate_barcode.rs | 96 +++++----
src/pages/buy.rs | 63 ++++--
src/pages/create_product.rs | 109 +++++++---
src/pages/create_product_parent.rs | 126 +++++++++++
src/pages/create_recipe.rs | 108 ++++++++++
src/pages/home.rs | 46 ++--
src/pages/inventory.rs | 68 +++---
src/pages/login.rs | 81 +++++++
src/pages/mod.rs | 83 ++++++-
src/pages/not_found.rs | 7 +-
src/pages/product.rs | 52 +++++
src/pages/products.rs | 68 ++++++
src/pages/provision.rs | 93 ++++++++
src/pages/recipe.rs | 344 ++++++++++++++++++++++++++++++
src/pages/recipies.rs | 74 ++++++-
src/pages/units.rs | 78 +++++++
31 files changed, 1932 insertions(+), 230 deletions(-)
create mode 100644 src/components/catch_errors.rs
create mode 100644 src/components/checkbox_placeholder.rs
create mode 100644 src/components/login_wall.rs
create mode 100644 src/components/product_parent_overview.rs
create mode 100644 src/components/textarea_placeholder.rs
create mode 100644 src/pages/create_product_parent.rs
create mode 100644 src/pages/create_recipe.rs
create mode 100644 src/pages/login.rs
create mode 100644 src/pages/product.rs
create mode 100644 src/pages/products.rs
create mode 100644 src/pages/provision.rs
create mode 100644 src/pages/recipe.rs
create mode 100644 src/pages/units.rs
(limited to 'src')
diff --git a/src/api/mod.rs b/src/api/mod.rs
index 3bc870c..eb9ca3a 100644
--- a/src/api/mod.rs
+++ b/src/api/mod.rs
@@ -1,20 +1,38 @@
use leptos::error::Error;
use rocie_client::{
apis::{
- api_get_inventory_api::amount_by_id,
- api_get_product_api::{
- product_by_id, product_by_name, product_suggestion_by_name, products_in_storage,
- products_registered,
+ api_get_auth_inventory_api::amount_by_id,
+ api_get_auth_product_api::{
+ product_by_id, product_by_name, product_suggestion_by_name,
+ products_by_product_parent_id_direct, products_by_product_parent_id_indirect,
+ products_in_storage, products_registered, products_without_product_parent,
},
- api_get_unit_api::unit_by_id,
- api_get_unit_property_api::{unit_properties, unit_property_by_id},
- api_set_barcode_api::buy_barcode,
- api_set_product_api::{associate_barcode, register_product},
+ api_get_auth_product_parent_api::{
+ product_parents, product_parents_toplevel, product_parents_under,
+ },
+ api_get_auth_recipe_api::{
+ recipe_by_id, recipe_by_name, recipes, recipes_by_recipe_parent_id_direct,
+ recipes_by_recipe_parent_id_indirect, recipes_without_recipe_parent,
+ },
+ api_get_auth_recipe_parent_api::{
+ recipe_parents, recipe_parents_toplevel, recipe_parents_under,
+ },
+ api_get_auth_unit_api::{unit_by_id, units, units_by_property_id},
+ api_get_auth_unit_property_api::{unit_properties, unit_property_by_id},
+ api_get_no_auth_state_api::{can_be_provisioned, is_logged_in},
+ api_set_auth_barcode_api::buy_barcode,
+ api_set_auth_product_api::{associate_barcode, register_product},
+ api_set_auth_product_parent_api::register_product_parent,
+ api_set_auth_recipe_api::add_recipe,
+ api_set_auth_recipe_parent_api::register_recipe_parent,
+ api_set_no_auth_user_api::{login, provision},
configuration::Configuration,
},
models::{
- Barcode, BarcodeId, Product, ProductAmount, ProductId, ProductStub, Unit, UnitId,
- UnitProperty, UnitPropertyId,
+ Barcode, BarcodeId, LoginInfo, Product, ProductAmount, ProductId, ProductParent,
+ ProductParentId, ProductParentStub, ProductStub, ProvisionInfo, Recipe, RecipeId,
+ RecipeParent, RecipeParentId, RecipeParentStub, RecipeStub, Unit, UnitId, UnitProperty,
+ UnitPropertyId, UserId, UserStub,
},
};
@@ -89,22 +107,179 @@ macro_rules! mk_wrapper {
}
}
-mk_wrapper!(product_by_id(product_id: ProductId) -> Product as product_by_id_wrapped);
+mk_wrapper!(
+ is_logged_in() -> bool
+ as is_logged_in_wrapped
+);
+mk_wrapper!(
+ can_be_provisioned() -> bool
+ as can_be_provisioned_wrapped
+);
+
+mk_wrapper!(
+ @external_config
+ login(&config, login_info: LoginInfo) -> ()
+ as login_external_wrapped
+);
+mk_wrapper!(
+ @external_config
+ provision(&config, provsion_info: ProvisionInfo) -> UserId
+ as provision_external_wrapped
+);
+
+mk_wrapper!(
+ product_by_id(product_id: ProductId) -> Product
+ as product_by_id_wrapped
+);
+
+mk_wrapper!(
+ product_by_name(name: &str) -> Product
+ as product_by_name_wrapped
+);
+mk_wrapper!(
+ @treat_404_as_None
+ product_by_name(name: &str) -> Option
+ as product_by_name_404_wrapped
+);
+mk_wrapper!(
+ @external_config
+ product_by_name(&config, name: &str) -> Product
+ as product_by_name_external_wrapped
+);
+
+mk_wrapper!(
+ product_suggestion_by_name(part_name: &str) -> Vec
+ as product_suggestion_by_name_wrapped
+);
+
+mk_wrapper!(
+ units() -> Vec
+ as units_wrapped
+);
+mk_wrapper!(
+ units_by_property_id(id: UnitPropertyId) -> Vec
+ as units_by_property_id_wrapped
+);
+mk_wrapper!(
+ unit_by_id(unit_id: UnitId) -> Unit
+ as unit_by_id_wrapped
+);
+mk_wrapper!(
+ unit_property_by_id(unit_id: UnitPropertyId) -> UnitProperty
+ as unit_property_by_id_wrapped
+);
+mk_wrapper!(
+ unit_properties() -> Vec
+ as unit_properties_wrapped
+);
-mk_wrapper!(@treat_404_as_None product_by_name(name: &str) -> Option as product_by_name_404_wrapped);
-mk_wrapper!(@external_config product_by_name(&config, name: &str) -> Product as product_by_name_external_wrapped);
+mk_wrapper!(
+ @treat_404_as_None
+ amount_by_id(product_id: ProductId) -> Option
+ as amount_by_id_404_wrapped
+);
-mk_wrapper!(product_suggestion_by_name(part_name: &str) -> Vec as product_suggestion_by_name_wrapped);
+mk_wrapper!(
+ products_registered() -> Vec
+ as products_registered_wrapped
+);
+mk_wrapper!(
+ products_in_storage() -> Vec
+ as products_in_storage_wrapped
+);
+mk_wrapper!(
+ products_without_product_parent() -> Vec
+ as products_without_product_parent_wrapped
+);
+mk_wrapper!(
+ products_by_product_parent_id_indirect(product_parent_id: ProductParentId) -> Vec
+ as products_by_product_parent_id_indirect_wrapped
+);
+mk_wrapper!(
+ products_by_product_parent_id_direct(product_parent_id: ProductParentId) -> Vec
+ as products_by_product_parent_id_direct_wrapped
+);
-mk_wrapper!(unit_by_id(unit_id: UnitId) -> Unit as unit_by_id_wrapped);
-mk_wrapper!(unit_property_by_id(unit_id: UnitPropertyId) -> UnitProperty as unit_property_by_id_wrapped);
-mk_wrapper!(unit_properties() -> Vec as unit_properties_wrapped);
+mk_wrapper!(
+ @external_config
+ register_product_parent(&config, product_parent_stub: ProductParentStub) -> ProductParentId
+ as register_product_parent_external_wrapped
+);
+mk_wrapper!(
+ product_parents_toplevel() -> Vec
+ as product_parents_toplevel_wrapped
+);
+mk_wrapper!(
+ @treat_404_as_None
+ product_parents_under(id: ProductParentId) -> Option>
+ as product_parents_under_404_wrapped
+);
+mk_wrapper!(
+ product_parents() -> Vec
+ as product_parents_wrapped
+);
-mk_wrapper!(amount_by_id(product_id: ProductId) -> ProductAmount as amount_by_id_wrapped);
+mk_wrapper!(
+ recipes() -> Vec
+ as recipes_wrapped
+);
+mk_wrapper!(
+ recipes_without_recipe_parent() -> Vec
+ as recipes_without_recipe_parent_wrapped
+);
+mk_wrapper!(
+ @external_config
+ add_recipe(&config, stub: RecipeStub) -> RecipeId
+ as add_recipe_external_wrapped
+);
+mk_wrapper!(
+ recipes_by_recipe_parent_id_indirect(recipe_parent_id: RecipeParentId) -> Vec
+ as recipes_by_recipe_parent_id_indirect_wrapped
+);
+mk_wrapper!(
+ recipes_by_recipe_parent_id_direct(recipe_parent_id: RecipeParentId) -> Vec
+ as recipes_by_recipe_parent_id_direct_wrapped
+);
+mk_wrapper!(
+ recipe_by_name(name: &str) -> Recipe
+ as recipe_by_name_wrapped
+);
+mk_wrapper!(
+ recipe_by_id(id: RecipeId) -> Recipe
+ as recipe_by_id_wrapped
+);
-mk_wrapper!(products_registered() -> Vec as products_registered_wrapped);
-mk_wrapper!(products_in_storage() -> Vec as products_in_storage_wrapped);
+mk_wrapper!(
+ @external_config
+ register_recipe_parent(&config, recipe_parent_stub: RecipeParentStub) -> RecipeParentId
+ as register_recipe_parent_external_wrapped
+);
+mk_wrapper!(
+ recipe_parents_toplevel() -> Vec
+ as recipe_parents_toplevel_wrapped
+);
+mk_wrapper!(
+ @treat_404_as_None
+ recipe_parents_under(id: RecipeParentId) -> Option>
+ as recipe_parents_under_404_wrapped
+);
+mk_wrapper!(
+ recipe_parents() -> Vec
+ as recipe_parents_wrapped
+);
-mk_wrapper!(@external_config buy_barcode(&config, barcode_number: BarcodeId, times: u32) -> () as buy_barcode_external_wrapped);
-mk_wrapper!(@external_config register_product(&config, product_stub: ProductStub) -> ProductId as register_product_external_wrapped);
-mk_wrapper!(@external_config associate_barcode(&config, id: ProductId, barcode: Barcode) -> () as associate_barcode_external_wrapped);
+mk_wrapper!(
+ @external_config
+ buy_barcode(&config, barcode_number: BarcodeId, times: u32) -> ()
+ as buy_barcode_external_wrapped
+);
+mk_wrapper!(
+ @external_config
+ register_product(&config, product_stub: ProductStub) -> ProductId
+ as register_product_external_wrapped
+);
+mk_wrapper!(
+ @external_config
+ associate_barcode(&config, id: ProductId, barcode: Barcode) -> ()
+ as associate_barcode_external_wrapped
+);
diff --git a/src/components/async_fetch.rs b/src/components/async_fetch.rs
index 7bf44a0..43469a7 100644
--- a/src/components/async_fetch.rs
+++ b/src/components/async_fetch.rs
@@ -37,11 +37,13 @@ macro_rules! AsyncFetch {
"Loading..."
}
}>
- {move || Suspend::new(async move {
- $resource
- .await
- .map($producer)
- })}
+ {
+ Suspend::new(async move {
+ $resource
+ .await
+ .map($producer)
+ })
+ }
}
}};
diff --git a/src/components/buy.rs b/src/components/buy.rs
index e69de29..8b13789 100644
--- a/src/components/buy.rs
+++ b/src/components/buy.rs
@@ -0,0 +1 @@
+
diff --git a/src/components/catch_errors.rs b/src/components/catch_errors.rs
new file mode 100644
index 0000000..d5a452d
--- /dev/null
+++ b/src/components/catch_errors.rs
@@ -0,0 +1,40 @@
+use leptos::{
+ IntoView, component,
+ error::ErrorBoundary,
+ prelude::{Children, ClassAttribute, CollectView, ElementChild, Get},
+ view,
+};
+
+use crate::components::site_header::SiteHeader;
+
+#[component]
+pub(crate) fn CatchErrors(children: Children) -> impl IntoView {
+ view! {
+
+
+ "Uh oh! Something went wrong!"
+
+ "Errors: "
+
+ {move || {
+ errors
+ .get()
+ .into_iter()
+ .map(|(_, e)| {
+ view! {
+ - {e.to_string()}
+ }
+ })
+ .collect_view()
+ }}
+
+ }
+ }>{children()}
+ }
+}
diff --git a/src/components/checkbox_placeholder.rs b/src/components/checkbox_placeholder.rs
new file mode 100644
index 0000000..a1aaa0c
--- /dev/null
+++ b/src/components/checkbox_placeholder.rs
@@ -0,0 +1,54 @@
+use leptos::{
+ IntoView, component,
+ html::Input,
+ prelude::{ClassAttribute, ElementChild, GlobalAttributes, NodeRef, NodeRefAttribute},
+ view,
+};
+
+use crate::components::get_id;
+
+#[component]
+pub fn CheckboxPlaceholder(
+ label: &'static str,
+ node_ref: NodeRef,
+) -> impl IntoView {
+ let id = get_id();
+
+ view! {
+
+
+
+
+
+ }
+}
diff --git a/src/components/container.rs b/src/components/container.rs
index d6d2f03..3b56713 100644
--- a/src/components/container.rs
+++ b/src/components/container.rs
@@ -1,46 +1,38 @@
use leptos::{
IntoView, component,
- prelude::{Children, ClassAttribute, ElementChild, OnAttribute},
+ prelude::{Children, ClassAttribute, ElementChild},
view,
};
-use leptos_router::{NavigateOptions, hooks::use_navigate};
+use leptos_router::components::A;
#[component]
pub fn Container(
- header: impl IntoView,
- buttons: Vec<(impl IntoView, &'static str)>,
+ header: impl IntoView + 'static,
+ buttons: Vec<(impl IntoView + 'static, &'static str)>,
children: Children,
) -> impl IntoView {
assert!(!buttons.is_empty());
- let first_button_path = buttons.first().expect("Should have at least on button").1;
+ // TODO: Add the direct link to the first button back. <2026-02-15>
+ // let first_button_path = buttons.first().expect("Should have at least on button").1;
view! {
-