From ce7c67d599a2de2a535dc71b816b64c36a3597c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20K=C3=B6rber?= Date: Tue, 29 Aug 2023 21:34:00 +0200 Subject: [PATCH] add ready ui --- rust/src/main.rs | 62 ++++++++++- rust/src/view/trip/packagelist.rs | 176 ++++++++++++++++++++++++++++-- 2 files changed, 224 insertions(+), 14 deletions(-) diff --git a/rust/src/main.rs b/rust/src/main.rs index 0ecc249..2ee4725 100644 --- a/rust/src/main.rs +++ b/rust/src/main.rs @@ -210,6 +210,14 @@ async fn main() -> Result<(), StartError> { "/:id/packagelist/item/:id/unpack", post(trip_item_packagelist_set_unpack_htmx), ) + .route( + "/:id/packagelist/item/:id/ready", + post(trip_item_packagelist_set_ready_htmx), + ) + .route( + "/:id/packagelist/item/:id/unready", + post(trip_item_packagelist_set_unready_htmx), + ) .route("/:id/state/:id", post(trip_state_set)) .route("/:id/total_weight", get(trip_total_weight_htmx)) .route("/:id/type/:id/add", get(trip_type_add)) @@ -1194,7 +1202,7 @@ async fn trip_item_packagelist_set_pack_htmx( message: format!("an item with id {item_id} does not exist"), }))?; - Ok(view::trip::packagelist::TripPackageListRow::build( + Ok(view::trip::packagelist::TripPackageListRowReady::build( trip_id, &item, )) } @@ -1220,7 +1228,57 @@ async fn trip_item_packagelist_set_unpack_htmx( message: format!("an item with id {item_id} does not exist"), }))?; - Ok(view::trip::packagelist::TripPackageListRow::build( + Ok(view::trip::packagelist::TripPackageListRowReady::build( + trip_id, &item, + )) +} + +async fn trip_item_packagelist_set_ready_htmx( + State(state): State, + Path((trip_id, item_id)): Path<(Uuid, Uuid)>, +) -> Result { + trip_item_set_state( + &state, + trip_id, + item_id, + models::trips::TripItemStateKey::Ready, + true, + ) + .await?; + + let item = models::trips::TripItem::find(&state.database_pool, trip_id, item_id) + .await? + .ok_or(Error::Request(RequestError::NotFound { + message: format!("an item with id {item_id} does not exist"), + }))?; + + Ok(view::trip::packagelist::TripPackageListRowUnready::build( + trip_id, &item, + )) +} + +async fn trip_item_packagelist_set_unready_htmx( + State(state): State, + Path((trip_id, item_id)): Path<(Uuid, Uuid)>, +) -> Result { + trip_item_set_state( + &state, + trip_id, + item_id, + models::trips::TripItemStateKey::Ready, + false, + ) + .await?; + + // note that this cannot fail due to a missing item, as trip_item_set_state would already + // return 404. but error handling cannot hurt ;) + let item = models::trips::TripItem::find(&state.database_pool, trip_id, item_id) + .await? + .ok_or(Error::Request(RequestError::NotFound { + message: format!("an item with id {item_id} does not exist"), + }))?; + + Ok(view::trip::packagelist::TripPackageListRowUnready::build( trip_id, &item, )) } diff --git a/rust/src/view/trip/packagelist.rs b/rust/src/view/trip/packagelist.rs index 0a6fde9..f367bc1 100644 --- a/rust/src/view/trip/packagelist.rs +++ b/rust/src/view/trip/packagelist.rs @@ -3,9 +3,9 @@ use uuid::Uuid; use crate::models; -pub struct TripPackageListRow; +pub struct TripPackageListRowReady; -impl TripPackageListRow { +impl TripPackageListRowReady { pub fn build(trip_id: Uuid, item: &models::trips::TripItem) -> Markup { html!( li @@ -79,9 +79,85 @@ impl TripPackageListRow { } } -pub struct TripPackageListCategoryBlock; +pub struct TripPackageListRowUnready; -impl TripPackageListCategoryBlock { +impl TripPackageListRowUnready { + pub fn build(trip_id: Uuid, item: &models::trips::TripItem) -> Markup { + html!( + li + ."flex" + ."flex-row" + ."justify-between" + ."items-stretch" + ."bg-green-50"[item.ready] + ."bg-red-50"[!item.ready] + ."hover:bg-white"[!item.ready] + ."h-full" + { + span + ."p-2" + { + (item.item.name) + } + @if item.ready { + a + href={ + "/trips/" (trip_id) + "/items/" (item.item.id) + "/unready" + } + hx-post={ + "/trips/" (trip_id) + "/packagelist/item/" + (item.item.id) "/unready" + } + hx-target="closest li" + hx-swap="outerHTML" + ."flex" + ."flex-row" + ."aspect-square" + { + span + ."mdi" + ."m-auto" + ."text-xl" + ."mdi-check" + {} + } + } @else { + a + href={ + "/trips/" (trip_id) + "/items/" (item.item.id) + "/ready" + } + hx-post={ + "/trips/" (trip_id) + "/packagelist/item/" + (item.item.id) "/ready" + } + hx-target="closest li" + hx-swap="outerHTML" + ."flex" + ."flex-row" + ."aspect-square" + { + span + ."mdi" + ."m-auto" + ."text-xl" + ."mdi-checkbox-blank-outline" + {} + } + } + } + ) + } +} + +pub struct TripPackageListCategoryBlockReady; + +impl TripPackageListCategoryBlockReady { pub fn build(trip: &models::trips::Trip, category: &models::trips::TripCategory) -> Markup { let empty = !category .items @@ -125,8 +201,8 @@ impl TripPackageListCategoryBlock { ."flex" ."flex-col" { - @for item in category.items.as_ref().unwrap() { - (TripPackageListRow::build(trip.id, item)) + @for item in category.items.as_ref().unwrap().iter().filter(|item| item.picked) { + (TripPackageListRowReady::build(trip.id, item)) } } } @@ -135,6 +211,61 @@ impl TripPackageListCategoryBlock { } } +pub struct TripPackageListCategoryBlockUnready; + +impl TripPackageListCategoryBlockUnready { + pub fn build(trip: &models::trips::Trip, category: &models::trips::TripCategory) -> Markup { + let empty = !category + .items + .as_ref() + .unwrap() + .iter() + .any(|item| item.picked); + + html!( + div + ."inline-block" + ."w-full" + ."mb-5" + ."border" + ."border-2" + ."border-gray-300" + ."opacity-30"[empty] + { + div + ."bg-gray-100" + ."border-b-2" + ."border-gray-300" + ."p-3" + { + h3 { (category.category.name) } + } + @if empty { + div + ."flex" + ."p-1" + { + span + ."text-sm" + ."m-auto" + { + "no items picked" + } + } + } @else { + ul + ."flex" + ."flex-col" + { + @for item in category.items.as_ref().unwrap().iter().filter(|item| item.picked) { + (TripPackageListRowUnready::build(trip.id, item)) + } + } + } + } + ) + } +} pub struct TripPackageList; impl TripPackageList { @@ -147,6 +278,14 @@ impl TripPackageList { // .iter() // .all(|item| !item.picked || item.packed) // }); + let has_unready_items: bool = trip.categories.as_ref().unwrap().iter().any(|category| { + category + .items + .as_ref() + .unwrap() + .iter() + .any(|item| item.picked && !item.ready) + }); html!( div ."p-8" @@ -183,12 +322,25 @@ impl TripPackageList { "Finish packing" } } - div - ."columns-3" - ."gap-5" - { - @for category in trip.categories() { - (TripPackageListCategoryBlock::build(trip, category)) + @if has_unready_items { + p { "There are items that are not yet ready, get them!"} + div + ."columns-3" + ."gap-5" + { + @for category in trip.categories() { + (TripPackageListCategoryBlockUnready::build(trip, category)) + } + } + } @else { + p { "All items are ready, pack the following things:" } + div + ."columns-3" + ."gap-5" + { + @for category in trip.categories() { + (TripPackageListCategoryBlockReady::build(trip, category)) + } } } }