summaryrefslogtreecommitdiffstats
path: root/src/pages/associate_barcode.rs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/pages/associate_barcode.rs163
1 files changed, 163 insertions, 0 deletions
diff --git a/src/pages/associate_barcode.rs b/src/pages/associate_barcode.rs
new file mode 100644
index 0000000..20714ff
--- /dev/null
+++ b/src/pages/associate_barcode.rs
@@ -0,0 +1,163 @@
+use leptos::{
+ IntoView, component,
+ prelude::{Get, Show, WriteSignal, signal},
+ task::spawn_local,
+ view,
+};
+use rocie_client::models::{Barcode, BarcodeId, Product, Unit, UnitAmount, UnitId};
+use rocie_macros::Form;
+use uuid::Uuid;
+
+use crate::{
+ api::{
+ associate_barcode_external_wrapped, get_config, product_by_id_wrapped,
+ product_by_name_404_wrapped, product_by_name_external_wrapped,
+ product_suggestion_by_name_wrapped, unit_by_id_wrapped, unit_property_by_id_wrapped,
+ },
+ components::{async_fetch::AsyncResource, banner::Banner, site_header::SiteHeader},
+};
+
+#[component]
+pub fn AssociateBarcode() -> impl IntoView {
+ let product_name_signal;
+
+ let (errors, errors_set) = signal(None);
+
+ let (show_units, show_units_set) = signal(false);
+
+ view! {
+ <SiteHeader logo=icondata_io::IoPricetag back_location="/" name="Buy" />
+
+ <Show when=move || errors.get().is_some()>
+ <Banner text=move || errors.get().expect("Was some") />
+ </Show>
+
+ {
+ Form! {
+ on_submit = |barcode_id, product_name, amount, unit_id| {
+ let config = get_config!();
+
+ spawn_local(async move {
+ let output = async {
+ let product = product_by_name_external_wrapped(&config, &product_name).await?;
+
+ associate_barcode_external_wrapped(&config, product.id, Barcode {
+ amount:UnitAmount {
+ unit: UnitId { value: unit_id },
+ value: u32::from(amount),
+ },
+ id: BarcodeId { value: barcode_id },
+ }).await?;
+
+ Ok::<_, leptos::error::Error>(())
+ };
+
+ match output.await {
+ Ok(()) => (),
+ Err(err) => {
+ errors_set.set(
+ Some(
+ format!("Could not associate barcode: {err}")
+ )
+ );
+ },
+ }
+ });
+ };
+
+ <Input
+ name=barcode_id,
+ rust_type=u32,
+ html_type="number",
+ label="Barcode number",
+ />
+
+ <Input
+ name=product_name,
+ rust_type=String,
+ html_type="text",
+ label="Product Name",
+ reactive=product_name_signal
+ auto_complete=generate_suggest_products
+ />
+
+ <Show
+ when=move || show_units.get(),
+ >
+ <Select
+ name=unit_id,
+ rust_type=Uuid,
+ label="Unit",
+ options=AsyncResource! {
+ (
+ product_name: Option<String> = product_name_signal(),
+ show_units_set: WriteSignal<bool> = show_units_set
+ ) -> Result<Vec<(String, String)>, leptos::error::Error> {
+ let units = product_unit_fetcher(product_name).await?;
+
+ show_units_set.set(units.is_some());
+ if let Some(units) = units {
+ Ok(
+ units
+ .into_iter()
+ .map(|unit| (unit.full_name_singular, unit.id.to_string()))
+ .collect()
+ )
+ } else {
+ Ok(vec![])
+ }
+ }
+ },
+ />
+ </Show>
+
+ <Input
+ name=amount,
+ rust_type=u16,
+ html_type="number",
+ label="Amount"
+ />
+ }
+ }
+ }
+}
+
+async fn generate_suggest_products(
+ optional_product_name: Option<String>,
+) -> Result<Option<Vec<String>>, leptos::error::Error> {
+ if let Some(product_name) = optional_product_name
+ && !product_name.is_empty()
+ {
+ let products = product_suggestion_by_name_wrapped(&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<String>,
+) -> Result<Option<Vec<Unit>>, leptos::error::Error> {
+ if let Some(product_name) = optinal_product_name
+ && !product_name.is_empty()
+ {
+ let maybe_product: Option<Product> = product_by_name_404_wrapped(&product_name).await?;
+
+ if let Some(product) = maybe_product {
+ let unit_property =
+ unit_property_by_id_wrapped(product_by_id_wrapped(product.id).await?.unit_property)
+ .await?;
+
+ let mut units = Vec::with_capacity(unit_property.units.len());
+ for unit_id in unit_property.units {
+ units.push(unit_by_id_wrapped(unit_id).await?);
+ }
+
+ Ok(Some(units))
+ } else {
+ Ok(None)
+ }
+ } else {
+ Ok(None)
+ }
+}