// rocie - An enterprise grocery management system - Web app // // Copyright (C) 2026 Benedikt Peetz // SPDX-License-Identifier: GPL-3.0-or-later // // This file is part of Rocie. // // You should have received a copy of the License along with this program. // If not, see . use std::{convert::Infallible, iter, str::FromStr}; use leptos::{ IntoView, component, prelude::{Get, Show, signal}, task::spawn_local, view, }; use leptos_router::{NavigateOptions, hooks::use_navigate}; use rocie_client::models::{ProductParentId, ProductParentStub}; use rocie_macros::Form; use crate::{ api::{get_config, product_parents_wrapped, register_product_parent_external_wrapped}, components::{ async_fetch::AsyncResource, banner::Banner, catch_errors::CatchErrors, login_wall::LoginWall, site_header::SiteHeader, }, }; struct OptionalString(Option); impl FromStr for OptionalString { type Err = Infallible; fn from_str(s: &str) -> Result { if s.is_empty() { Ok(Self(None)) } else { Ok(Self(Some(s.to_owned()))) } } } struct OptionalParentId(Option); impl FromStr for OptionalParentId { type Err = uuid::Error; fn from_str(s: &str) -> Result { if s.is_empty() { Ok(Self(None)) } else { Ok(Self(Some(ProductParentId { value: s.parse()? }))) } } } #[component] pub fn CreateProductParent() -> impl IntoView { let (error_message, error_message_set) = signal(None); view! { { Form! { on_submit = |name, description, parent| { let config = get_config!(); let navigate = use_navigate(); spawn_local(async move { match register_product_parent_external_wrapped(&config, ProductParentStub { description: description.0.map(|d| d.trim().to_owned()), name: name.trim().to_owned(), parent: parent.0, } ).await { Ok(_id) => { navigate("/create-product-parent", NavigateOptions::default()); } Err(err) => error_message_set.set(Some(format!("Failed to create product: {err}"))), } }); };