From 427ce16023613536b8176e6dee7c1580a5980c97 Mon Sep 17 00:00:00 2001 From: Benedikt Peetz Date: Thu, 23 Oct 2025 02:24:29 +0200 Subject: feat(treewide): Make usage more intuitive --- src/pages/buy.rs | 193 +++++++++++++++++++++++++++++++++++++++++++++++++ src/pages/inventory.rs | 54 ++++++++++++++ src/pages/mod.rs | 3 + src/pages/recipies.rs | 8 ++ 4 files changed, 258 insertions(+) create mode 100644 src/pages/buy.rs create mode 100644 src/pages/inventory.rs create mode 100644 src/pages/recipies.rs (limited to 'src/pages') diff --git a/src/pages/buy.rs b/src/pages/buy.rs new file mode 100644 index 0000000..cb4cff4 --- /dev/null +++ b/src/pages/buy.rs @@ -0,0 +1,193 @@ +use leptos::{ + IntoView, component, + prelude::{Get, Read, Show, WriteSignal, expect_context, signal}, + task::spawn_local, + view, +}; +use leptos_router::{NavigateOptions, hooks::use_navigate}; +use log::info; +use reactive_stores::Store; +use rocie_client::{ + apis::Error, + models::{Product, Unit}, +}; +use uuid::Uuid; + +use crate::{ + ConfigState, ConfigStateStoreFields, + api::{ + buy_barcode_wrapper, get_product_by_name, get_product_unit_by_id, + get_products_by_part_name, get_unit_by_id, + }, + components::{async_fetch::AsyncResource, banner::Banner, form::Form, site_header::SiteHeader}, +}; + +#[component] +pub fn Buy() -> impl IntoView { + let (on_submit_errored, on_submit_errored_set) = signal(None); + + view! { + + + + + + + { + Form! { + on_submit = |barcode_number, amount| { + let config = expect_context::>(); + let config = config.config().read(); + + spawn_local(async move { + if let Err(err) = buy_barcode_wrapper(&config, barcode_number).await { + let error = format!("Error in form on-submit for barcode `{barcode_number}`: {err}"); + on_submit_errored_set.set(Some(error)); + } else { + on_submit_errored_set.set(None); + + info!("Bought barcode {barcode_number} {amount} times"); + } + + }); + }; + + + + + } + } + } +} + +#[component] +pub fn AssociateBarcode() -> impl IntoView { + let product_name_signal; + + let (show_units, show_units_set) = signal(false); + + view! { + + + { + Form! { + on_submit = |product_name, amount, unit_id| { + spawn_local(async move { + let navigate = use_navigate(); + + info!("Got product barcode: {product_name} with amount: {amount}, and {unit_id}"); + + navigate("/", NavigateOptions::default()); + }); + }; + + + + + + } + } + } +} + +async fn generate_suggest_products( + optional_product_name: Option, +) -> Result>, leptos::error::Error> { + if let Some(product_name) = optional_product_name + && !product_name.is_empty() + { + let products = get_products_by_part_name(product_name).await?; + Ok(Some(products.into_iter().map(|prod| prod.name).collect())) + } else { + Ok(None) + } +} + +async fn product_unit_fetcher( + optinal_product_name: Option, +) -> Result>, leptos::error::Error> { + if let Some(product_name) = optinal_product_name + && !product_name.is_empty() + { + let value: Option = { + match get_product_by_name(product_name).await { + Ok(ok) => Ok::<_, leptos::error::Error>(Some(ok)), + Err(err) => match err { + Error::ResponseError(ref response_content) => { + match response_content.status.as_u16() { + 404 => Ok(None), + _ => Err(err.into()), + } + } + err => Err(err.into()), + }, + }? + }; + + if let Some(value) = value { + let (_, unit_property) = get_product_unit_by_id(value.id).await?; + + let mut units = Vec::with_capacity(unit_property.units.len()); + for unit_id in unit_property.units { + units.push(get_unit_by_id(unit_id).await?); + } + + Ok(Some(units)) + } else { + Ok(None) + } + } else { + Ok(None) + } +} 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! { + + +
    + { + AsyncFetch! { + @map_error_in_producer + fetcher = get_products(), + producer = render_products, + } + } +
+ } +} + +fn render_products(products: Vec) -> 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::>() +} + +fn format_full_product((product, amount, unit): (Product, ProductAmount, Unit)) -> impl IntoView { + view! { +
    +
  • {product.name}
  • +
  • + + {format!("{} {}", amount.amount.value, unit.short_name)} + +
  • +
+ } +} 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! { } +} -- cgit 1.4.1