From ee5bc439628c24bac2aeb818d7c73cee7e6e736e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrian=20Wo=C5=BAniak?= Date: Wed, 23 Nov 2022 16:31:11 +0100 Subject: [PATCH] Fixing web --- crates/cart_manager/src/actions.rs | 14 ++++----- crates/channels/src/carts.rs | 4 ++- crates/model/src/api.rs | 21 ++++++++++++- crates/web/src/api/public.rs | 9 +++--- crates/web/src/model.rs | 21 +++++++++---- crates/web/src/pages/public/checkout.rs | 20 ++++++++----- crates/web/src/pages/public/listing.rs | 31 ++++++++++---------- crates/web/src/pages/public/shopping_cart.rs | 27 +++++++++-------- crates/web/src/shared/view.rs | 15 ++++++++-- crates/web/src/shopping_cart.rs | 29 +++++++++--------- 10 files changed, 120 insertions(+), 71 deletions(-) diff --git a/crates/cart_manager/src/actions.rs b/crates/cart_manager/src/actions.rs index 9d85345..cd08139 100644 --- a/crates/cart_manager/src/actions.rs +++ b/crates/cart_manager/src/actions.rs @@ -57,7 +57,7 @@ pub async fn modify_item(msg: modify_item::Input, db: Database) -> modify_item:: }; let dbm = ActiveCartItemByProduct { - product_id: msg.product_id, + product_variant_id: msg.product_variant_id, }; let item: Option = match dbm.run(&mut t).await { Ok(res) => res, @@ -83,7 +83,7 @@ pub async fn modify_item(msg: modify_item::Input, db: Database) -> modify_item:: Some(item) => { let dbm = UpdateShoppingCartItem { id: item.id, - product_id: msg.product_id, + product_variant_id: msg.product_variant_id, shopping_cart_id: cart.id, quantity: msg.quantity, quantity_unit: msg.quantity_unit, @@ -99,7 +99,7 @@ pub async fn modify_item(msg: modify_item::Input, db: Database) -> modify_item:: } None => { let dbm = CreateShoppingCartItem { - product_id: msg.product_id, + product_variant_id: msg.product_variant_id, shopping_cart_id: cart.id, quantity: msg.quantity, quantity_unit: msg.quantity_unit, @@ -127,7 +127,7 @@ pub async fn remove_product( let dbm = RemoveCartItem { shopping_cart_id: msg.shopping_cart_id, shopping_cart_item_id: Some(msg.shopping_cart_item_id), - product_id: None, + product_variant_id: None, }; let mut t = begin_t!(db); @@ -185,7 +185,7 @@ pub async fn modify_cart( msg.items .iter() .fold(HashSet::with_capacity(msg.items.len()), |mut agg, item| { - agg.insert(item.product_id); + agg.insert(item.product_variant_id); agg }); @@ -202,12 +202,12 @@ pub async fn modify_cart( for item in items .into_iter() - .filter(|item| !existing.contains(&item.product_id)) + .filter(|item| !existing.contains(&item.product_variant_id)) { let dbm = RemoveCartItem { shopping_cart_id: cart.id, shopping_cart_item_id: Some(item.id), - product_id: None, + product_variant_id: None, }; match dbm.run(&mut t).await { Ok(_) => {} diff --git a/crates/channels/src/carts.rs b/crates/channels/src/carts.rs index f0f15bb..0373c78 100644 --- a/crates/channels/src/carts.rs +++ b/crates/channels/src/carts.rs @@ -40,12 +40,14 @@ pub mod remove_product { } pub mod modify_item { + use model::v2::ProductVariantId; + use super::Error; #[derive(Debug, serde::Serialize, serde::Deserialize)] pub struct Input { pub buyer_id: model::AccountId, - pub product_id: model::ProductId, + pub product_variant_id: ProductVariantId, pub quantity: model::Quantity, pub quantity_unit: model::QuantityUnit, } diff --git a/crates/model/src/api.rs b/crates/model/src/api.rs index 45b1b7d..51b48ef 100644 --- a/crates/model/src/api.rs +++ b/crates/model/src/api.rs @@ -290,6 +290,25 @@ pub struct Product { pub photos: Vec, } +pub mod v2 { + use crate::api::{Category, Photo}; + + #[derive(Debug, Hash, serde::Serialize, serde::Deserialize)] + pub struct ProductVariant { + pub id: crate::ProductVariantId, + pub product_id: crate::ProductId, + pub name: crate::ProductName, + pub short_description: crate::ProductShortDesc, + pub long_description: crate::ProductLongDesc, + pub category: Option, + pub price: crate::Price, + pub available: bool, + pub quantity_unit: crate::QuantityUnit, + pub deliver_days_flag: crate::Days, + pub photos: Vec, + } +} + impl<'path> From<( crate::Product, @@ -452,7 +471,7 @@ pub struct DeleteItemOutput { #[derive(Serialize, Deserialize, Debug)] pub struct UpdateItemInput { - pub product_id: ProductId, + pub product_variant_id: ProductVariantId, pub quantity: Quantity, pub quantity_unit: QuantityUnit, } diff --git a/crates/web/src/api/public.rs b/crates/web/src/api/public.rs index 708134d..d841b54 100644 --- a/crates/web/src/api/public.rs +++ b/crates/web/src/api/public.rs @@ -1,4 +1,5 @@ use model::api::OrderAddressInput; +use model::v2::ProductVariantId; use model::{AccessTokenString, AddressId, PaymentMethod, RefreshTokenString}; use seed::fetch::{Header, Method, Request}; @@ -66,12 +67,12 @@ pub async fn sign_up(input: model::api::CreateAccountInput) -> NetRes NetRes { let input = model::api::UpdateItemInput { - product_id, + product_variant_id, quantity, quantity_unit, }; @@ -97,11 +98,11 @@ pub async fn update_cart( .into_iter() .map( |crate::shopping_cart::Item { - product_id, + product_variant_id, quantity, quantity_unit, }| model::api::UpdateItemInput { - product_id, + product_variant_id, quantity, quantity_unit, }, diff --git a/crates/web/src/model.rs b/crates/web/src/model.rs index f2cb62b..ab6151f 100644 --- a/crates/web/src/model.rs +++ b/crates/web/src/model.rs @@ -1,5 +1,7 @@ use std::collections::{HashMap, HashSet}; +use model::v2::ProductVariantId; +use model::ProductId; use seed::Url; use crate::{shopping_cart, I18n, Page}; @@ -72,8 +74,10 @@ impl From<::model::api::Config> for Config { #[derive(Debug, Default)] pub struct Products { pub categories: Vec, - pub product_ids: Vec, - pub products: HashMap, + pub product_ids: Vec, + pub products: HashMap, + pub product_variant_ids: Vec, + pub product_variants: HashMap, } impl Products { @@ -102,13 +106,18 @@ impl Products { }; } - pub fn filter_product_ids(&self, filter: F) -> Vec + pub fn filter_product_variant_ids(&self, filter: F) -> Vec where - F: Fn(&model::api::Product) -> bool, + F: Fn(&model::api::v2::ProductVariant) -> bool, { - self.product_ids + self.product_variant_ids .iter() - .filter_map(|id| self.products.get(id).filter(|&p| filter(p)).map(|p| p.id)) + .filter_map(|id| { + self.product_variants + .get(id) + .filter(|&p| filter(p)) + .map(|p| p.id) + }) .collect() } } diff --git a/crates/web/src/pages/public/checkout.rs b/crates/web/src/pages/public/checkout.rs index 6dda61e..5efd820 100644 --- a/crates/web/src/pages/public/checkout.rs +++ b/crates/web/src/pages/public/checkout.rs @@ -177,18 +177,22 @@ mod left_side { .values() .filter_map(|item: &Item| { page.products - .products - .get(&item.product_id) + .product_variants + .get(&item.product_variant_id) .map(|product| (item, product)) }) - .map(|(item, product)| product_view(model, product, item)); + .map(|(item, variant)| product_view(model, variant, item)); div![ C!["w-full mx-auto text-gray-800 font-light mb-6 border-b border-gray-200 pb-6"], products ] } - fn product_view(model: &crate::Model, product: &model::api::Product, item: &Item) -> Node { + fn product_view( + model: &crate::Model, + product: &model::api::v2::ProductVariant, + item: &Item, + ) -> Node { let img = product .photos .first() @@ -236,14 +240,14 @@ mod left_side { .cart .items .values() - .filter_map(|item: &crate::shopping_cart::Item| { + .filter_map(|item: &Item| { page.products - .products - .get(&item.product_id) + .product_variants + .get(&item.product_variant_id) .map(|product| (item, product)) }) .map( - |(item, product): (&crate::shopping_cart::Item, &model::api::Product)| { + |(item, product): (&Item, &model::api::v2::ProductVariant)| { **(product.price * item.quantity) }, ) diff --git a/crates/web/src/pages/public/listing.rs b/crates/web/src/pages/public/listing.rs index 62f1531..6dde10a 100644 --- a/crates/web/src/pages/public/listing.rs +++ b/crates/web/src/pages/public/listing.rs @@ -1,5 +1,6 @@ use std::collections::HashSet; +use model::v2::ProductVariantId; use model::Quantity; use seed::app::Orders; use seed::prelude::*; @@ -14,7 +15,7 @@ use crate::shopping_cart::CartMsg; pub struct ListingPage { pub errors: Vec, pub filters: HashSet, - pub visible_products: Vec, + pub visible_product_variants: Vec, pub products: Products, } @@ -31,7 +32,7 @@ pub fn init(url: Url, orders: &mut impl Orders) -> ListingPage { products: Products::default(), filters: url_to_filters(url), errors: vec![], - visible_products: vec![], + visible_product_variants: vec![], } } @@ -54,12 +55,12 @@ pub fn page_changed(url: Url, model: &mut ListingPage) { let ids = { model .products - .filter_product_ids(|product| filter_product(&*model, product)) + .filter_product_variant_ids(|product| filter_product(&*model, product)) }; - model.visible_products = ids; + model.visible_product_variants = ids; } -fn filter_product(model: &ListingPage, product: &model::api::Product) -> bool { +fn filter_product(model: &ListingPage, product: &model::api::v2::ProductVariant) -> bool { product .category .as_ref() @@ -83,8 +84,8 @@ pub fn update(msg: ListingMsg, model: &mut ListingPage, orders: &mut impl Orders model.products.update(products.0); let ids = model .products - .filter_product_ids(|product| filter_product(model, product)); - model.visible_products = ids; + .filter_product_variant_ids(|product| filter_product(model, product)); + model.visible_product_variants = ids; } ListingMsg::ProductsFetched(NetRes::Error(_)) | ListingMsg::ProductsFetched(NetRes::Http(_)) => { @@ -94,17 +95,17 @@ pub fn update(msg: ListingMsg, model: &mut ListingPage, orders: &mut impl Orders } pub fn view(model: &crate::Model, page: &ListingPage) -> Node { - let products: Vec> = if page.visible_products.is_empty() { + let products: Vec> = if page.visible_product_variants.is_empty() { page.products - .product_ids + .product_variant_ids .iter() - .filter_map(|id| page.products.products.get(id)) + .filter_map(|id| page.products.product_variants.get(id)) .map(|p| product(model, p)) .collect() } else { - page.visible_products + page.visible_product_variants .iter() - .filter_map(|id| page.products.products.get(id)) + .filter_map(|id| page.products.product_variants.get(id)) .map(|p| product(model, p)) .collect() }; @@ -121,7 +122,7 @@ pub fn view(model: &crate::Model, page: &ListingPage) -> Node { ] } -fn product(model: &crate::Model, product: &model::api::Product) -> Node { +fn product(model: &crate::Model, product: &model::api::v2::ProductVariant) -> Node { use rusty_money::Money; let price = Money::from_minor(**product.price as i64, model.config.currency).to_string(); @@ -138,7 +139,7 @@ fn product(model: &crate::Model, product: &model::api::Product) -> Node Node() as i64; div![ @@ -391,12 +392,12 @@ fn products_body(model: &crate::Model, page: &ShoppingCartPage) -> Node Node Node { use rusty_money::Money; @@ -416,7 +417,7 @@ fn item_view( .map(|photo| photo.url.as_str()) .unwrap_or_default(); - let product_id = product.id; + let product_variant_id = product.id; let quantity_unit = product.quantity_unit; let product_url = Urls::new(&model.url) .product() @@ -441,7 +442,7 @@ fn item_view( ev(Ev::Submit, move |ev| { ev.prevent_default(); ev.stop_propagation(); - crate::Msg::from(CartMsg::Remove(product_id)) + crate::Msg::from(CartMsg::Remove(product_variant_id)) }), button![ attrs![At::Type => "submit", At::Class => "text-gray-700 md:ml-4 text-red-600"], @@ -449,7 +450,7 @@ fn item_view( ev(Ev::Click, move |ev| { ev.prevent_default(); ev.stop_propagation(); - crate::Msg::from(CartMsg::Remove(product_id)) + crate::Msg::from(CartMsg::Remove(product_variant_id)) }) ] ] @@ -474,7 +475,7 @@ fn item_view( let quantity = Quantity::from_u32(value); Some(crate::Msg::from(CartMsg::ModifyItem { - product_id, + product_variant_id, quantity_unit, quantity, })) diff --git a/crates/web/src/shared/view.rs b/crates/web/src/shared/view.rs index 5a8801a..d920907 100644 --- a/crates/web/src/shared/view.rs +++ b/crates/web/src/shared/view.rs @@ -125,8 +125,19 @@ pub mod cart_dropdown { }; } + macro_rules! filter_product_variants { + ($model: expr, $products: expr) => { + $model + .cart + .items + .values() + .filter_map(|item: &Item| filter_product(item, $products, item.product_variant_id)) + }; + } + pub fn view(model: &Model, products: &crate::model::Products) -> Node { - let items = filter_products!(model, products).map(|(it, product)| item(model, it, product)); + let items = + filter_product_variants!(model, products).map(|(it, product)| item(model, it, product)); div![ C![ "absolute w-full rounded-b border-t-0 z-10", @@ -201,7 +212,7 @@ pub mod cart_dropdown { } fn checkout(model: &Model, products: &crate::model::Products) -> Node { - let sum: i32 = filter_products!(model, products) + let sum: i32 = filter_product_variants!(model, products) .map(|(item, product): (&Item, &model::api::Product)| **item.quantity * **product.price) .sum(); let sum = rusty_money::Money::from_minor(sum as i64, model.config.currency); diff --git a/crates/web/src/shopping_cart.rs b/crates/web/src/shopping_cart.rs index 9ac5fc1..f89a867 100644 --- a/crates/web/src/shopping_cart.rs +++ b/crates/web/src/shopping_cart.rs @@ -1,3 +1,4 @@ +use model::v2::ProductVariantId; use model::{PaymentMethod, ProductId, Quantity, QuantityUnit}; use seed::prelude::*; use serde::{Deserialize, Serialize}; @@ -10,14 +11,14 @@ pub enum CartMsg { AddItem { quantity: Quantity, quantity_unit: QuantityUnit, - product_id: ProductId, + product_variant_id: ProductVariantId, }, ModifyItem { quantity: Quantity, quantity_unit: QuantityUnit, - product_id: ProductId, + product_variant_id: ProductVariantId, }, - Remove(ProductId), + Remove(ProductVariantId), Hover, Leave, /// Send current non-empty cart to server @@ -38,7 +39,7 @@ pub type Items = indexmap::IndexMap; #[derive(Debug, Copy, Clone, Serialize, Deserialize)] pub struct Item { #[serde(rename = "i")] - pub product_id: ProductId, + pub product_variant_id: ProductVariantId, #[serde(rename = "q")] pub quantity: Quantity, #[serde(rename = "u")] @@ -68,14 +69,14 @@ pub fn update(msg: CartMsg, model: &mut Model, orders: &mut impl Orders) { CartMsg::AddItem { quantity, quantity_unit, - product_id, + product_variant_id, } => { { let items: &mut Items = &mut model.cart.items; - let entry: &mut Item = items.entry(product_id).or_insert_with(|| Item { + let entry: &mut Item = items.entry(product_variant_id).or_insert_with(|| Item { quantity: Quantity::from_u32(0), quantity_unit, - product_id, + product_variant_id, }); entry.quantity = entry.quantity + quantity; entry.quantity_unit = quantity_unit; @@ -84,18 +85,18 @@ pub fn update(msg: CartMsg, model: &mut Model, orders: &mut impl Orders) { sync_cart(model, orders); } CartMsg::ModifyItem { - product_id, + product_variant_id, quantity_unit, quantity, } => { if **quantity == 0 { - model.cart.items.remove(&product_id); + model.cart.items.remove(&product_variant_id); } else { let items: &mut Items = &mut model.cart.items; - let entry: &mut Item = items.entry(product_id).or_insert_with(|| Item { + let entry: &mut Item = items.entry(product_variant_id).or_insert_with(|| Item { quantity, quantity_unit, - product_id, + product_variant_id, }); entry.quantity = quantity; entry.quantity_unit = quantity_unit; @@ -125,15 +126,15 @@ pub fn update(msg: CartMsg, model: &mut Model, orders: &mut impl Orders) { |mut set, model::api::ShoppingCartItem { id: _, - product_id, + product_variant_id, shopping_cart_id: _, quantity, quantity_unit, }| { set.insert( - product_id, + product_variant_id, Item { - product_id, + product_variant_id, quantity, quantity_unit, },