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
|
// rocie - An enterprise grocery management system - Web app
//
// Copyright (C) 2026 Benedikt Peetz <benedikt.peetz@b-peetz.de>
// 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 <https://www.gnu.org/licenses/gpl-3.0.txt>.
use leptos::{
IntoView, component,
prelude::{ClassAttribute, ElementChild},
view,
};
use rocie_client::models::{Product, ProductAmount, ProductId, Unit};
use crate::{
api::{
amount_by_id_404_wrapped, product_by_id_wrapped, products_in_storage_wrapped,
unit_by_id_wrapped,
},
components::{
async_fetch::AsyncFetch, catch_errors::CatchErrors, login_wall::LoginWall,
site_header::SiteHeader,
},
};
#[component]
pub fn Inventory() -> impl IntoView {
view! {
<CatchErrors>
<LoginWall back=move || "/inventory".to_owned()>
<SiteHeader logo=icondata_io::IoArrowBack back_location="/" name="Inventory" />
<ul class="flex flex-col p-2 m-2">
{
AsyncFetch! {
@map_error_in_producer
fetcher = products_in_storage_wrapped(),
producer = render_products,
}
}
</ul>
</LoginWall>
</CatchErrors>
}
}
fn render_products(products: Vec<Product>) -> 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::<Vec<_>>()
}
async fn get_full_product_by_id(
id: ProductId,
) -> Result<Option<(Product, ProductAmount, Unit)>, leptos::error::Error> {
let product = product_by_id_wrapped(id).await?;
let amount = amount_by_id_404_wrapped(id).await?;
if let Some(amount) = amount {
let unit = unit_by_id_wrapped(amount.amount.unit).await?;
Ok(Some((product, amount, unit)))
} else {
Ok(None)
}
}
fn format_full_product(maybe_product: Option<(Product, ProductAmount, Unit)>) -> impl IntoView {
maybe_product.map(|(product, amount, unit)| {
view! {
<ul class="my-3">
<li class="m-2">{product.name}</li>
<li class="m-2">
<span class="bg-gray-200 p-1 px-2 rounded-lg">
{format!("{} {}", amount.amount.value, unit.short_name)}
</span>
</li>
</ul>
}
})
}
|