Files
packager/rust/src/components/inventory.rs

353 lines
14 KiB
Rust
Raw Normal View History

2023-05-08 22:31:01 +02:00
use maud::{html, Markup};
2023-05-08 00:05:45 +02:00
use crate::models::*;
2023-05-10 00:42:42 +02:00
use crate::ClientState;
2023-05-08 22:31:01 +02:00
use uuid::uuid;
2023-05-08 00:05:45 +02:00
pub struct Inventory {
2023-05-08 22:31:01 +02:00
doc: Markup,
2023-05-08 00:05:45 +02:00
}
impl Inventory {
2023-05-10 00:42:42 +02:00
pub async fn build(state: ClientState, categories: Vec<Category>) -> Result<Self, Error> {
2023-05-08 00:05:45 +02:00
let doc = html!(
2023-05-08 22:31:01 +02:00
div id="pkglist-item-manager" {
div ."p-8" ."grid" ."grid-cols-4" ."gap-3" {
div ."col-span-2" {
2023-05-10 01:02:37 +02:00
({<InventoryCategoryList as Into<Markup>>::into(InventoryCategoryList::build(&categories))})
2023-05-08 22:31:01 +02:00
}
div ."col-span-2" {
h1 ."text-2xl" ."mb-5" ."text-center" { "Items" }
@if state.active_category_id.is_some() {
2023-05-10 01:02:37 +02:00
({<InventoryItemList as Into<Markup>>::into(InventoryItemList::build(categories.iter().find(|category| category.active).unwrap().items()))})
2023-05-08 22:31:01 +02:00
}
2023-05-10 01:02:37 +02:00
({<InventoryNewItemForm as Into<Markup>>::into(InventoryNewItemForm::build(&state, &categories))})
2023-05-08 22:31:01 +02:00
}
}
}
2023-05-08 00:05:45 +02:00
);
Ok(Self { doc })
}
}
2023-05-10 00:48:25 +02:00
impl From<Inventory> for Markup {
fn from(val: Inventory) -> Self {
val.doc
2023-05-08 00:05:45 +02:00
}
}
pub struct InventoryCategoryList {
2023-05-08 22:31:01 +02:00
doc: Markup,
2023-05-08 00:05:45 +02:00
}
impl InventoryCategoryList {
2023-05-10 01:02:37 +02:00
pub fn build(categories: &Vec<Category>) -> Self {
2023-05-08 00:05:45 +02:00
let biggest_category_weight: u32 = categories
.iter()
2023-05-10 01:02:37 +02:00
.map(Category::total_weight)
2023-05-08 00:05:45 +02:00
.max()
.unwrap_or(1);
let doc = html!(
2023-05-08 22:31:01 +02:00
div {
h1 ."text-2xl" ."mb-5" ."text-center" { "Categories" }
table
."table"
."table-auto"
."border-collapse"
."border-spacing-0"
."border"
."w-full"
{
colgroup {
col style="width:50%" {}
col style="width:50%" {}
}
thead ."bg-gray-200" {
tr ."h-10" {
th ."border" ."p-2" { "Name" }
th ."border" ."p-2" { "Weight" }
}
}
tbody {
@for category in categories {
tr class={@if category.active {
"h-10 hover:bg-purple-100 m-3 h-full outline outline-2 outline-indigo-300"
} @else {
"h-10 hover:bg-purple-100 m-3 h-full"
}} {
td
class=@if category.active {
"border p-0 m-0 font-bold"
} @else {
"border p-0 m-0"
} {
a
2023-05-08 00:05:45 +02:00
id="select-category"
2023-05-08 22:31:01 +02:00
href=(
2023-05-08 00:05:45 +02:00
format!(
"/inventory/category/{id}",
id=category.id
)
2023-05-08 22:31:01 +02:00
)
// hx-post=(
// format!(
// "/inventory/category/{id}/items",
// id=category.id
// )
// )
// hx-swap="outerHTML"
// hx-target="#items"
."inline-block" ."p-2" ."m-0" ."w-full"
{
(category.name.clone())
2023-05-08 00:05:45 +02:00
}
2023-05-08 22:31:01 +02:00
}
td ."border" ."p-2" ."m-0" style="position:relative;" {
p {
(category.total_weight().to_string())
}
div ."bg-blue-600" ."h-1.5"
style=(
2023-05-08 00:05:45 +02:00
format!(
"width: {width}%;position:absolute;left:0;bottom:0;right:0;",
width=(
2023-05-10 01:02:37 +02:00
f64::from(category.total_weight())
/ f64::from(biggest_category_weight)
2023-05-08 00:05:45 +02:00
* 100.0
)
)
2023-05-08 22:31:01 +02:00
) {}
}
}
}
tr ."h-10" ."hover:bg-purple-200" ."bg-gray-300" ."font-bold" {
td ."border" ."p-0" ."m-0" {
p ."p-2" ."m-2" { "Sum" }
}
td ."border" ."p-0" ."m-0" {
p ."p-2" ."m-2" {
2023-05-10 01:02:37 +02:00
(categories.iter().map(Category::total_weight).sum::<u32>().to_string())
2023-05-08 22:31:01 +02:00
}
}
}
}
}
}
2023-05-08 00:05:45 +02:00
);
2023-05-10 01:02:37 +02:00
Self { doc }
2023-05-08 00:05:45 +02:00
}
}
2023-05-10 00:48:25 +02:00
impl From<InventoryCategoryList> for Markup {
fn from(val: InventoryCategoryList) -> Self {
val.doc
2023-05-08 00:05:45 +02:00
}
}
pub struct InventoryItemList {
2023-05-08 22:31:01 +02:00
doc: Markup,
2023-05-08 00:05:45 +02:00
}
impl InventoryItemList {
2023-05-10 01:02:37 +02:00
pub fn build(items: &Vec<Item>) -> Self {
2023-05-08 22:31:01 +02:00
let biggest_item_weight: u32 = items.iter().map(|item| item.weight).max().unwrap_or(1);
let doc = html!(
div #items {
@if items.is_empty() {
p ."text-lg" ."text-center" ."py-5" ."text-gray-400" { "[Empty]" }
} @else {
table
."table"
."table-auto"
."border-collapse"
."border-spacing-0"
."border"
."w-full"
{
thead ."bg-gray-200" {
tr ."h-10" {
th ."border" ."p-2" { "Name" }
th ."border" ."p-2" { "Weight" }
}
}
tbody {
@for item in items {
tr ."h-10" ."even:bg-gray-100" ."hover:bg-purple-100" {
td ."border" ."p-0" {
a
."p-2" ."w-full" ."inline-block"
href=(
format!("/inventory/item/{id}/", id=item.id)
) {
(item.name.clone())
}
}
td ."border" ."p-2" style="position:relative;" {
p { (item.weight.to_string()) }
div ."bg-blue-600" ."h-1.5" style=(format!("
width: {width}%;
position:absolute;
left:0;
bottom:0;
2023-05-10 01:02:37 +02:00
right:0;", width=(f64::from(item.weight) / f64::from(biggest_item_weight) * 100.0))) {}
2023-05-08 22:31:01 +02:00
}
2023-05-10 00:42:42 +02:00
td
."border"
."bg-red-200"
."hover:bg-red-400"
."cursor-pointer"
."w-8"
."text-center"
{
a
href = (format!("/inventory/item/{id}/delete", id = item.id))
{
button {
span ."mdi" ."mdi-delete" ."text-xl" {}
}
}
}
2023-05-08 22:31:01 +02:00
}
}
}
}
}
}
);
2023-05-10 01:02:37 +02:00
Self { doc }
2023-05-08 22:31:01 +02:00
}
}
2023-05-10 00:48:25 +02:00
impl From<InventoryItemList> for Markup {
fn from(val: InventoryItemList) -> Self {
val.doc
2023-05-08 22:31:01 +02:00
}
}
pub struct InventoryNewItemForm {
doc: Markup,
}
impl InventoryNewItemForm {
2023-05-10 01:02:37 +02:00
pub fn build(state: &ClientState, categories: &Vec<Category>) -> Self {
2023-05-08 00:05:45 +02:00
let doc = html!(
2023-05-08 22:31:01 +02:00
form
name="new-item"
id="new-item"
action="/inventory/item/"
target="_self"
method="post"
."mt-8" ."p-5" ."border-2" ."border-gray-200" {
div ."mb-5" ."flex" ."flex-row" ."items-center" {
span ."mdi" ."mdi-playlist-plus" ."text-2xl" ."mr-4" {}
p ."inline" ."text-xl" { "Add new item" }
}
div ."w-11/12" ."mx-auto" {
div ."pb-8" {
div ."flex" ."flex-row" ."justify-center" ."items-start"{
2023-05-10 00:42:42 +02:00
label for="name" .font-bold ."w-1/2" ."p-2" ."text-center" { "Name" }
2023-05-08 22:31:01 +02:00
span ."w-1/2" {
2023-05-10 00:42:42 +02:00
input type="text" id="new-item-name" name="new-item-name"
2023-05-08 22:31:01 +02:00
."block"
."w-full"
."p-2"
."bg-gray-50"
."border-2"
."rounded"
."focus:outline-none"
."focus:bg-white"
."focus:border-purple-500"
{
}
}
}
}
div ."flex" ."flex-row" ."justify-center" ."items-center" ."pb-8" {
2023-05-10 00:42:42 +02:00
label for="weight" .font-bold ."w-1/2" .text-center { "Weight" }
2023-05-08 22:31:01 +02:00
span ."w-1/2" {
input
type="text"
2023-05-10 00:42:42 +02:00
id="new-item-weight"
name="new-item-weight"
2023-05-08 22:31:01 +02:00
."block"
."w-full"
."p-2"
."bg-gray-50"
."border-2"
."border-gray-300"
."rounded"
."focus:outline-none"
."focus:bg-white"
."focus:border-purple-500"
{
}
}
}
div ."flex" ."flex-row" ."justify-center" ."items-center" ."pb-8" {
label for="item-category" .font-bold ."w-1/2" .text-center { "Category" }
span ."w-1/2" {
select
2023-05-10 00:42:42 +02:00
id="new-item-category-id"
name="new-item-category-id"
2023-05-08 22:31:01 +02:00
."block"
."w-full"
."p-2"
."bg-gray-50"
."border-2"
."border-gray-300"
."rounded"
."focus:outline-none"
."focus:bg-white"
."focus:border-purple-500" {
@for category in categories {
@if state.active_category_id.map_or(false, |id| id == category.id) {
option value=(category.id) selected="true" {
(category.name)
}
} @else {
option value=(category.id) {
(category.name)
2023-05-08 08:53:39 +02:00
}
2023-05-08 22:31:01 +02:00
}
}
}
}
}
input type="submit" value="Add"
."py-2"
."border-2"
."rounded"
."border-gray-300"
."mx-auto"
."w-full" {
}
}
}
2023-05-08 00:05:45 +02:00
);
2023-05-10 01:02:37 +02:00
Self { doc }
2023-05-08 00:05:45 +02:00
}
}
2023-05-10 00:48:25 +02:00
impl From<InventoryNewItemForm> for Markup {
fn from(val: InventoryNewItemForm) -> Self {
val.doc
2023-05-08 00:05:45 +02:00
}
}
2023-05-08 22:31:01 +02:00
// impl InventoryItemList {
// pub fn to_string(self) -> String {
// self.doc.into_string()
// }
// }
//ItemList