Fixing web
This commit is contained in:
parent
f98d1e6903
commit
ee5bc43962
@ -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<model::ShoppingCartItem> = 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(_) => {}
|
||||
|
@ -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,
|
||||
}
|
||||
|
@ -290,6 +290,25 @@ pub struct Product {
|
||||
pub photos: Vec<Photo>,
|
||||
}
|
||||
|
||||
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<Category>,
|
||||
pub price: crate::Price,
|
||||
pub available: bool,
|
||||
pub quantity_unit: crate::QuantityUnit,
|
||||
pub deliver_days_flag: crate::Days,
|
||||
pub photos: Vec<Photo>,
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
}
|
||||
|
@ -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<model::api
|
||||
|
||||
pub async fn update_cart_item(
|
||||
access_token: &AccessTokenString,
|
||||
product_id: model::ProductId,
|
||||
product_variant_id: ProductVariantId,
|
||||
quantity: model::Quantity,
|
||||
quantity_unit: model::QuantityUnit,
|
||||
) -> NetRes<model::api::UpdateItemOutput> {
|
||||
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,
|
||||
},
|
||||
|
@ -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<model::api::Category>,
|
||||
pub product_ids: Vec<model::ProductId>,
|
||||
pub products: HashMap<model::ProductId, model::api::Product>,
|
||||
pub product_ids: Vec<ProductId>,
|
||||
pub products: HashMap<ProductId, model::api::Product>,
|
||||
pub product_variant_ids: Vec<ProductVariantId>,
|
||||
pub product_variants: HashMap<ProductVariantId, model::api::v2::ProductVariant>,
|
||||
}
|
||||
|
||||
impl Products {
|
||||
@ -102,13 +106,18 @@ impl Products {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn filter_product_ids<F>(&self, filter: F) -> Vec<model::ProductId>
|
||||
pub fn filter_product_variant_ids<F>(&self, filter: F) -> Vec<ProductVariantId>
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
@ -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<Msg> {
|
||||
fn product_view(
|
||||
model: &crate::Model,
|
||||
product: &model::api::v2::ProductVariant,
|
||||
item: &Item,
|
||||
) -> Node<Msg> {
|
||||
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)
|
||||
},
|
||||
)
|
||||
|
@ -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<String>,
|
||||
pub filters: HashSet<String>,
|
||||
pub visible_products: Vec<model::ProductId>,
|
||||
pub visible_product_variants: Vec<ProductVariantId>,
|
||||
|
||||
pub products: Products,
|
||||
}
|
||||
@ -31,7 +32,7 @@ pub fn init(url: Url, orders: &mut impl Orders<ListingMsg>) -> 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<crate::Msg> {
|
||||
let products: Vec<Node<crate::Msg>> = if page.visible_products.is_empty() {
|
||||
let products: Vec<Node<crate::Msg>> = 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<crate::Msg> {
|
||||
]
|
||||
}
|
||||
|
||||
fn product(model: &crate::Model, product: &model::api::Product) -> Node<crate::Msg> {
|
||||
fn product(model: &crate::Model, product: &model::api::v2::ProductVariant) -> Node<crate::Msg> {
|
||||
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<crate::M
|
||||
.add_path_part((*product.id as i32).to_string());
|
||||
|
||||
let quantity_unit = product.quantity_unit;
|
||||
let product_id = product.id;
|
||||
let product_variant_id = product.id;
|
||||
|
||||
div![
|
||||
C!["w-full px-4 lg:px-0"],
|
||||
@ -174,7 +175,7 @@ fn product(model: &crate::Model, product: &model::api::Product) -> Node<crate::M
|
||||
ev.prevent_default();
|
||||
ev.stop_propagation();
|
||||
crate::Msg::from(CartMsg::AddItem {
|
||||
product_id,
|
||||
product_variant_id,
|
||||
quantity_unit,
|
||||
quantity: Quantity::try_from(1).unwrap_or_default()
|
||||
})
|
||||
|
@ -167,14 +167,15 @@ mod summary_right {
|
||||
.values()
|
||||
.filter_map(|item: &crate::shopping_cart::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)| {
|
||||
**(product.price * item.quantity)
|
||||
},
|
||||
|(item, product): (
|
||||
&crate::shopping_cart::Item,
|
||||
&model::api::v2::ProductVariant,
|
||||
)| { **(product.price * item.quantity) },
|
||||
)
|
||||
.sum::<i32>() as i64;
|
||||
div![
|
||||
@ -391,12 +392,12 @@ fn products_body(model: &crate::Model, page: &ShoppingCartPage) -> Node<crate::M
|
||||
.values()
|
||||
.filter_map(|item: &crate::shopping_cart::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): (&crate::shopping_cart::Item, &model::api::v2::ProductVariant)| {
|
||||
item_view(model, item, product)
|
||||
},
|
||||
);
|
||||
@ -406,7 +407,7 @@ fn products_body(model: &crate::Model, page: &ShoppingCartPage) -> Node<crate::M
|
||||
fn item_view(
|
||||
model: &crate::Model,
|
||||
item: &crate::shopping_cart::Item,
|
||||
product: &model::api::Product,
|
||||
product: &model::api::v2::ProductVariant,
|
||||
) -> Node<crate::Msg> {
|
||||
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,
|
||||
}))
|
||||
|
@ -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<Msg> {
|
||||
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<Msg> {
|
||||
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);
|
||||
|
@ -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<ProductId, Item>;
|
||||
#[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<Msg>) {
|
||||
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<Msg>) {
|
||||
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<Msg>) {
|
||||
|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,
|
||||
},
|
||||
|
Loading…
Reference in New Issue
Block a user