1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
|
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<String>);
impl FromStr for OptionalString {
type Err = Infallible;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if s.is_empty() {
Ok(Self(None))
} else {
Ok(Self(Some(s.to_owned())))
}
}
}
struct OptionalParentId(Option<ProductParentId>);
impl FromStr for OptionalParentId {
type Err = uuid::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
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! {
<CatchErrors>
<LoginWall back=move || "/create-product-parent".to_owned()>
<SiteHeader
logo=icondata_io::IoArrowBack
back_location="/"
name="Create Product Parent"
/>
<Show when=move || error_message.get().is_some()>
<Banner text=move || error_message.get().expect("Is some") />
</Show>
{
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}"))),
}
});
};
<Input
name=name,
rust_type=String,
html_type="text",
label="Product Name",
/>
<Input
name=description,
rust_type=OptionalString,
html_type="text",
label="Product Description"
/>
<Select
name=parent,
rust_type=OptionalParentId,
label="Parent",
options=AsyncResource! {
() -> Result<Vec<(String, String)>, leptos::error::Error> {
let parents = product_parents_wrapped().await?;
Ok(
iter::once(("No parent".to_owned(), String::new()))
.chain(
parents
.into_iter()
.map(|prop| (prop.name, prop.id.to_string()))
)
.collect()
)
}
},
/>
}
}
</LoginWall>
</CatchErrors>
}
}
|