This commit is contained in:
2023-05-17 17:31:48 +02:00
parent 04abb53f4a
commit 4b4a61d3bb
4 changed files with 83 additions and 59 deletions

View File

@@ -14,15 +14,17 @@ impl Inventory {
div id="pkglist-item-manager" {
div ."p-8" ."grid" ."grid-cols-4" ."gap-3" {
div ."col-span-2" {
({<InventoryCategoryList as Into<Markup>>::into(InventoryCategoryList::build(&categories))})
(InventoryCategoryList::build(&state, &categories).into_markup())
}
div ."col-span-2" {
h1 ."text-2xl" ."mb-5" ."text-center" { "Items" }
@if state.active_category_id.is_some() {
({<InventoryItemList as Into<Markup>>::into(InventoryItemList::build(categories.iter().find(|category| category.active).unwrap().items(), state.edit_item))})
@if let Some(active_category_id) = state.active_category_id {
(InventoryItemList::build(&state, categories.iter().find(|category| category.id == active_category_id)
.ok_or(Error::NotFoundError { description: format!("no category with id {}", active_category_id) })?
.items())
.into_markup())
}
({<InventoryNewItemForm as Into<Markup>>::into(InventoryNewItemForm::build(&state, &categories))})
(InventoryNewItemForm::build(&state, &categories).into_markup())
}
}
}
@@ -43,7 +45,7 @@ pub struct InventoryCategoryList {
}
impl InventoryCategoryList {
pub fn build(categories: &Vec<Category>) -> Self {
pub fn build(state: &ClientState, categories: &Vec<Category>) -> Self {
let biggest_category_weight: u32 = categories
.iter()
.map(Category::total_weight)
@@ -68,20 +70,20 @@ impl InventoryCategoryList {
}
thead ."bg-gray-200" {
tr ."h-10" {
th ."border" ."p-2" { "Name" }
th ."border" ."p-2" ."w-3/5" { "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"
tr class={@if state.active_category_id.map_or(false, |id| category.id == id) {
"h-10 hover:bg-purple-100 m-3 h-full outline outline-2 outline-indigo-300 pointer-events-none"
} @else {
"h-10 hover:bg-purple-100 m-3 h-full"
}} {
td
class=@if category.active {
class=@if state.active_category_id.map_or(false, |id| category.id == id) {
"border p-0 m-0 font-bold"
} @else {
"border p-0 m-0"
@@ -142,6 +144,10 @@ impl InventoryCategoryList {
Self { doc }
}
fn into_markup(self) -> Markup {
self.doc
}
}
impl From<InventoryCategoryList> for Markup {
@@ -155,14 +161,14 @@ pub struct InventoryItemList {
}
impl InventoryItemList {
pub fn build(items: &Vec<Item>, edit_item: Option<Uuid>) -> Self {
pub fn build(state: &ClientState, items: &Vec<Item>) -> Self {
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 {
@if let Some(edit_item) = edit_item {
@if let Some(edit_item) = state.edit_item {
form
name="edit-item"
id="edit-item"
@@ -174,6 +180,7 @@ impl InventoryItemList {
table
."table"
."table-auto"
.table-fixed
."border-collapse"
."border-spacing-0"
."border"
@@ -181,16 +188,18 @@ impl InventoryItemList {
{
thead ."bg-gray-200" {
tr ."h-10" {
th ."border" ."p-2" { "Name" }
th ."border" ."p-2" ."w-3/5" { "Name" }
th ."border" ."p-2" { "Weight" }
th ."border" ."p-2" ."w-10" {}
th ."border" ."p-2" ."w-10" {}
}
}
tbody {
@for item in items {
@if edit_item.map_or(false, |edit_item| edit_item == item.id) {
@if state.edit_item.map_or(false, |edit_item| edit_item == item.id) {
tr ."h-10" {
td ."border" ."p-2" ."bg-blue-100" {
input ."w-full"
td ."border" ."bg-blue-300" ."px-2" ."py-0" .flex {
input ."block" ."w-full" ."bg-blue-100"
type="text"
id="edit-item-name"
name="edit-item-name"
@@ -198,23 +207,29 @@ impl InventoryItemList {
value=(item.name)
{}
}
td ."border" ."p-2" ."bg-blue-100" {
input ."w-full"
type="number"
id="edit-item-weight"
name="edit-item-weight"
form="edit-item"
value=(item.weight)
{}
td ."border" ."bg-blue-300" ."px-2" ."py-0" {
// div ."h-full" ."w-full" {
// input ."block" ."w-full" ."bg-blue-100"
// type="number"
// id="edit-item-weight"
// name="edit-item-weight"
// form="edit-item"
// value=(item.weight)
// {}
// }
}
td ."border" ."p-2" ."bg-green-100" {
button type="submit" form="edit-item" {
span ."mdi" ."mdi-content-save" ."text-xl" {}
td ."border-none" ."bg-green-100" ."hover:bg-green-200" .flex ."p-0" {
div .aspect-square .w-full .h-full .flex {
button type="submit" form="edit-item" .m-auto .w-full .h-full {
span ."mdi" ."mdi-content-save" ."text-xl" .m-auto {}
}
}
}
td ."border" ."p-2" ."bg-red-100" {
a href=(format!("/inventory/item/{id}/cancel", id = item.id)) {
span ."mdi" ."mdi-cancel" ."text-xl" {}
td ."border-none" ."bg-red-100" ."hover:bg-red-200" ."p-0" {
div .aspect-square .flex .w-full .h-full {
a href=(format!("/inventory/item/{id}/cancel", id = item.id)) .flex .m-auto .w-full .h-full {
span ."mdi" ."mdi-cancel" ."text-xl" .m-auto {}
}
}
}
}
@@ -247,10 +262,12 @@ impl InventoryItemList {
."w-8"
."text-center"
{
a href = (format!("?edit_item={id}", id = item.id))
{
button {
span ."mdi" ."mdi-pencil" ."text-xl" {}
div .aspect-square .flex .w-full .h-full {
a href = (format!("?edit_item={id}", id = item.id)) ."m-auto"
{
button {
span ."mdi" ."mdi-pencil" ."text-xl" {}
}
}
}
}
@@ -262,10 +279,12 @@ impl InventoryItemList {
."w-8"
."text-center"
{
a href = (format!("/inventory/item/{id}/delete", id = item.id))
{
button {
span ."mdi" ."mdi-delete" ."text-xl" {}
div .aspect-square .flex .w-full .h-full {
a href = (format!("/inventory/item/{id}/delete", id = item.id)) ."m-auto"
{
button {
span ."mdi" ."mdi-delete" ."text-xl" {}
}
}
}
}
@@ -280,6 +299,10 @@ impl InventoryItemList {
Self { doc }
}
fn into_markup(self) -> Markup {
self.doc
}
}
impl From<InventoryItemList> for Markup {
@@ -363,17 +386,12 @@ impl InventoryNewItemForm {
."rounded"
."focus:outline-none"
."focus:bg-white"
."focus:border-purple-500" {
."focus:border-purple-500"
autocomplete="off" // https://stackoverflow.com/a/10096033
{
@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)
}
option value=(category.id) selected[state.active_category_id.map_or(false, |id| id == category.id)] {
(category.name)
}
}
}
@@ -393,6 +411,10 @@ impl InventoryNewItemForm {
Self { doc }
}
fn into_markup(self) -> Markup {
self.doc
}
}
impl From<InventoryNewItemForm> for Markup {

View File

@@ -56,8 +56,7 @@ impl Root {
}} { "Trips" }
}
}
// div hx-boost="true" {
div {
div hx-boost="true" {
(body)
}
}

View File

@@ -169,12 +169,6 @@ async fn inventory(
.populate_items(&state.database_pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, Html::from(e.to_string())))?;
if let Some(active_id) = active_id {
if category.id == active_id {
category.active = true;
}
}
}
Ok((
@@ -183,7 +177,12 @@ async fn inventory(
Root::build(
Inventory::build(state.client_state, categories)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, Html::from(e.to_string())))?
.map_err(|e| match e {
Error::NotFoundError { description } => {
(StatusCode::NOT_FOUND, Html::from(description))
}
_ => (StatusCode::INTERNAL_SERVER_ERROR, Html::from(e.to_string())),
})?
.into(),
&TopLevelPage::Inventory,
)

View File

@@ -12,6 +12,7 @@ use futures::TryStreamExt;
pub enum Error {
SqlError { description: String },
UuidError { description: String },
NotFoundError { description: String },
}
impl fmt::Display for Error {
@@ -23,6 +24,9 @@ impl fmt::Display for Error {
Self::UuidError { description } => {
write!(f, "UUID error: {description}")
}
Self::NotFoundError { description } => {
write!(f, "Not found: {description}")
}
}
}
}
@@ -78,12 +82,12 @@ impl TryFrom<SqliteRow> for Trip {
}
}
#[derive(Debug)]
pub struct Category {
pub id: Uuid,
pub name: String,
pub description: String,
items: Option<Vec<Item>>,
pub active: bool,
}
impl TryFrom<SqliteRow> for Category {
@@ -99,7 +103,6 @@ impl TryFrom<SqliteRow> for Category {
name: name.to_string(),
description: description.to_string(),
items: None,
active: false,
})
}
}
@@ -138,6 +141,7 @@ impl<'a> Category {
}
}
#[derive(Debug)]
pub struct Item {
pub id: Uuid,
pub name: String,