Sync cart
This commit is contained in:
parent
a84fda2382
commit
b1b4d083b7
@ -1,3 +1,7 @@
|
||||
#![feature(drain_filter)]
|
||||
|
||||
use std::collections::HashSet;
|
||||
|
||||
use database_manager::{query_db, Database};
|
||||
use model::{
|
||||
AccountId, ProductId, Quantity, QuantityUnit, ShoppingCartId, ShoppingCartItem,
|
||||
@ -60,8 +64,10 @@ pub enum Error {
|
||||
ShoppingCartFailed,
|
||||
#[error("Shopping cart is not available for unknown reason")]
|
||||
CartNotAvailable,
|
||||
#[error("Failed to add item to cart")]
|
||||
CantAddItem,
|
||||
#[error("Failed to modify item to cart")]
|
||||
CantModifyItem,
|
||||
#[error("Failed to modify cart")]
|
||||
CantModifyCart,
|
||||
#[error("{0}")]
|
||||
Db(#[from] database_manager::Error),
|
||||
#[error("Unable to update cart item")]
|
||||
@ -89,7 +95,7 @@ impl CartManager {
|
||||
}
|
||||
|
||||
#[derive(actix::Message)]
|
||||
#[rtype(result = "Result<ShoppingCartItem>")]
|
||||
#[rtype(result = "Result<Option<ShoppingCartItem>>")]
|
||||
pub struct ModifyItem {
|
||||
pub buyer_id: AccountId,
|
||||
pub product_id: ProductId,
|
||||
@ -97,9 +103,12 @@ pub struct ModifyItem {
|
||||
pub quantity_unit: QuantityUnit,
|
||||
}
|
||||
|
||||
cart_async_handler!(ModifyItem, modify_item, ShoppingCartItem);
|
||||
cart_async_handler!(ModifyItem, modify_item, Option<ShoppingCartItem>);
|
||||
|
||||
async fn modify_item(msg: ModifyItem, db: actix::Addr<Database>) -> Result<ShoppingCartItem> {
|
||||
async fn modify_item(
|
||||
msg: ModifyItem,
|
||||
db: actix::Addr<Database>,
|
||||
) -> Result<Option<ShoppingCartItem>> {
|
||||
let _cart = query_db!(
|
||||
db,
|
||||
database_manager::EnsureActiveShoppingCart {
|
||||
@ -127,11 +136,17 @@ async fn modify_item(msg: ModifyItem, db: actix::Addr<Database>) -> Result<Shopp
|
||||
database_manager::ActiveCartItemByProduct {
|
||||
product_id: msg.product_id
|
||||
},
|
||||
Error::CantAddItem
|
||||
Error::CantModifyItem
|
||||
);
|
||||
|
||||
match item {
|
||||
Some(item) => Ok(query_db!(
|
||||
Some(item) if **item.quantity == 0 => Ok(query_db!(
|
||||
db,
|
||||
database_manager::DeleteShoppingCartItem { id: item.id },
|
||||
passthrough Error::Db,
|
||||
Error::CantModifyItem
|
||||
)),
|
||||
Some(item) => Ok(Some(query_db!(
|
||||
db,
|
||||
database_manager::UpdateShoppingCartItem {
|
||||
id: item.id,
|
||||
@ -141,9 +156,9 @@ async fn modify_item(msg: ModifyItem, db: actix::Addr<Database>) -> Result<Shopp
|
||||
quantity_unit: msg.quantity_unit,
|
||||
},
|
||||
passthrough Error::Db,
|
||||
Error::CantAddItem
|
||||
)),
|
||||
None => Ok(query_db!(
|
||||
Error::CantModifyItem
|
||||
))),
|
||||
None => Ok(Some(query_db!(
|
||||
db,
|
||||
database_manager::CreateShoppingCartItem {
|
||||
product_id: msg.product_id,
|
||||
@ -152,8 +167,8 @@ async fn modify_item(msg: ModifyItem, db: actix::Addr<Database>) -> Result<Shopp
|
||||
quantity_unit: msg.quantity_unit,
|
||||
},
|
||||
passthrough Error::Db,
|
||||
Error::CantAddItem
|
||||
)),
|
||||
Error::CantModifyItem
|
||||
))),
|
||||
}
|
||||
}
|
||||
|
||||
@ -170,68 +185,101 @@ pub(crate) async fn remove_product(
|
||||
msg: RemoveProduct,
|
||||
db: actix::Addr<Database>,
|
||||
) -> Result<Option<ShoppingCartItem>> {
|
||||
match db
|
||||
.send(database_manager::RemoveCartItem {
|
||||
Ok(query_db!(
|
||||
db,
|
||||
database_manager::RemoveCartItem {
|
||||
shopping_cart_id: msg.shopping_cart_id,
|
||||
shopping_cart_item_id: Some(msg.shopping_cart_item_id),
|
||||
product_id: None,
|
||||
})
|
||||
.await
|
||||
{
|
||||
Ok(Ok(row)) => Ok(row),
|
||||
Ok(Err(db_err)) => {
|
||||
log::error!("{db_err}");
|
||||
Err(Error::UpdateFailed)
|
||||
}
|
||||
Err(act_err) => {
|
||||
log::error!("{act_err:?}");
|
||||
Err(Error::UpdateFailed)
|
||||
}
|
||||
}
|
||||
},
|
||||
Error::UpdateFailed
|
||||
))
|
||||
}
|
||||
|
||||
#[derive(actix::Message)]
|
||||
#[rtype(result = "Result<Option<ShoppingCartItem>>")]
|
||||
pub struct ChangeQuantity {
|
||||
pub shopping_cart_id: ShoppingCartId,
|
||||
pub shopping_cart_item_id: ShoppingCartItemId,
|
||||
pub quantity: Quantity,
|
||||
pub quantity_unit: QuantityUnit,
|
||||
#[rtype(result = "Result<Vec<ShoppingCartItem>>")]
|
||||
pub struct ModifyCart {
|
||||
pub buyer_id: AccountId,
|
||||
pub items: Vec<ModifyItem>,
|
||||
}
|
||||
|
||||
cart_async_handler!(ChangeQuantity, change_quantity, Option<ShoppingCartItem>);
|
||||
cart_async_handler!(ModifyCart, modify_cart, Vec<ShoppingCartItem>);
|
||||
|
||||
pub(crate) async fn change_quantity(
|
||||
msg: ChangeQuantity,
|
||||
db: actix::Addr<Database>,
|
||||
) -> Result<Option<ShoppingCartItem>> {
|
||||
if **msg.quantity == 0 {
|
||||
return remove_product(
|
||||
RemoveProduct {
|
||||
shopping_cart_id: msg.shopping_cart_id,
|
||||
shopping_cart_item_id: msg.shopping_cart_item_id,
|
||||
},
|
||||
db,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
let item: ShoppingCartItem = query_db!(
|
||||
async fn modify_cart(msg: ModifyCart, db: actix::Addr<Database>) -> Result<Vec<ShoppingCartItem>> {
|
||||
let _cart = query_db!(
|
||||
db,
|
||||
database_manager::FindShoppingCartItem {
|
||||
id: msg.shopping_cart_item_id,
|
||||
database_manager::EnsureActiveShoppingCart {
|
||||
buyer_id: msg.buyer_id,
|
||||
},
|
||||
Error::NotExists(msg.shopping_cart_item_id)
|
||||
Error::ShoppingCartFailed
|
||||
);
|
||||
let mut carts: Vec<model::ShoppingCart> = query_db!(
|
||||
db,
|
||||
database_manager::AccountShoppingCarts {
|
||||
account_id: msg.buyer_id,
|
||||
state: Some(ShoppingCartState::Active),
|
||||
},
|
||||
passthrough Error::Db,
|
||||
Error::CartNotAvailable
|
||||
);
|
||||
let cart = if carts.is_empty() {
|
||||
return Err(Error::CartNotAvailable);
|
||||
} else {
|
||||
carts.remove(0)
|
||||
};
|
||||
|
||||
let existing =
|
||||
msg.items
|
||||
.iter()
|
||||
.fold(HashSet::with_capacity(msg.items.len()), |mut agg, item| {
|
||||
agg.insert(item.product_id);
|
||||
agg
|
||||
});
|
||||
|
||||
let mut items: Vec<model::ShoppingCartItem> = query_db!(
|
||||
db,
|
||||
database_manager::CartItems {
|
||||
shopping_cart_id: cart.id
|
||||
},
|
||||
Error::CantModifyCart
|
||||
);
|
||||
|
||||
Ok(Some(query_db!(
|
||||
db,
|
||||
database_manager::UpdateShoppingCartItem {
|
||||
id: msg.shopping_cart_item_id,
|
||||
product_id: item.product_id,
|
||||
shopping_cart_id: item.shopping_cart_id,
|
||||
quantity: msg.quantity,
|
||||
quantity_unit: msg.quantity_unit,
|
||||
},
|
||||
Error::ChangeQuantity
|
||||
)))
|
||||
for item in items.drain_filter(|item| !existing.contains(&item.product_id)) {
|
||||
query_db!(
|
||||
db,
|
||||
database_manager::RemoveCartItem {
|
||||
shopping_cart_id: cart.id,
|
||||
shopping_cart_item_id: Some(item.id),
|
||||
product_id: None,
|
||||
},
|
||||
Error::CantModifyCart
|
||||
);
|
||||
}
|
||||
|
||||
let mut out = Vec::with_capacity(items.len());
|
||||
|
||||
for ShoppingCartItem {
|
||||
id: _,
|
||||
product_id,
|
||||
shopping_cart_id: _,
|
||||
quantity,
|
||||
quantity_unit,
|
||||
} in items
|
||||
{
|
||||
if let Some(item) = modify_item(
|
||||
ModifyItem {
|
||||
buyer_id: msg.buyer_id,
|
||||
product_id,
|
||||
quantity,
|
||||
quantity_unit,
|
||||
},
|
||||
db.clone(),
|
||||
)
|
||||
.await?
|
||||
{
|
||||
out.push(item);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(out)
|
||||
}
|
||||
|
@ -190,6 +190,38 @@ RETURNING id, product_id, shopping_cart_id, quantity, quantity_unit
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(actix::Message)]
|
||||
#[rtype(result = "Result<Option<ShoppingCartItem>>")]
|
||||
pub struct DeleteShoppingCartItem {
|
||||
pub id: ShoppingCartItemId,
|
||||
}
|
||||
|
||||
db_async_handler!(
|
||||
DeleteShoppingCartItem,
|
||||
delete_shopping_cart_item,
|
||||
Option<ShoppingCartItem>
|
||||
);
|
||||
|
||||
pub(crate) async fn delete_shopping_cart_item(
|
||||
msg: DeleteShoppingCartItem,
|
||||
db: PgPool,
|
||||
) -> Result<Option<ShoppingCartItem>> {
|
||||
sqlx::query_as(
|
||||
r#"
|
||||
DELETE FROM shopping_cart_items
|
||||
WHERE id = $1
|
||||
RETURNING id, product_id, shopping_cart_id, quantity, quantity_unit
|
||||
"#,
|
||||
)
|
||||
.bind(msg.id)
|
||||
.fetch_optional(&db)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
log::error!("{e:?}");
|
||||
super::Error::ShoppingCartItem(Error::CantUpdate(msg.id))
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(actix::Message)]
|
||||
#[rtype(result = "Result<ShoppingCartItem>")]
|
||||
pub struct FindShoppingCartItem {
|
||||
|
@ -110,7 +110,7 @@ impl Responder for Error {
|
||||
}),
|
||||
},
|
||||
Error::Public(PublicError::ApiV1(
|
||||
V1Error::AddItem | V1Error::RemoveItem | V1Error::AddOrder,
|
||||
V1Error::ModifyItem | V1Error::RemoveItem | V1Error::AddOrder,
|
||||
)) => HttpResponse::BadRequest()
|
||||
.content_type("application/json")
|
||||
.json(Failure {
|
||||
|
@ -17,7 +17,7 @@ pub enum Error {
|
||||
#[error("Failed to remove shopping cart item")]
|
||||
RemoveItem,
|
||||
#[error("Failed to add shopping cart item")]
|
||||
AddItem,
|
||||
ModifyItem,
|
||||
|
||||
#[error("Failed to create order")]
|
||||
AddOrder,
|
||||
|
@ -93,11 +93,11 @@ async fn update_cart_item(
|
||||
cart: Data<Addr<CartManager>>,
|
||||
tm: Data<Addr<TokenManager>>,
|
||||
credentials: BearerAuth,
|
||||
Json(payload): Json<api::CreateItemInput>,
|
||||
) -> Result<Json<api::CreateItemOutput>> {
|
||||
Json(payload): Json<api::UpdateItemInput>,
|
||||
) -> Result<Json<api::UpdateItemOutput>> {
|
||||
let token = credentials.require_user(tm.into_inner()).await?;
|
||||
|
||||
let item: model::ShoppingCartItem = query_cart!(
|
||||
let item: Option<model::ShoppingCartItem> = query_cart!(
|
||||
cart,
|
||||
cart_manager::ModifyItem {
|
||||
buyer_id: token.account_id(),
|
||||
@ -105,13 +105,55 @@ async fn update_cart_item(
|
||||
quantity: payload.quantity,
|
||||
quantity_unit: payload.quantity_unit,
|
||||
},
|
||||
routes::Error::Public(super::Error::AddItem.into()),
|
||||
routes::Error::Public(super::Error::ModifyItem.into()),
|
||||
routes::Error::Public(PublicError::DatabaseConnection)
|
||||
);
|
||||
|
||||
Ok(Json(api::CreateItemOutput {
|
||||
success: true,
|
||||
shopping_cart_item: item.into(),
|
||||
match item {
|
||||
Some(item) => Ok(Json(api::UpdateItemOutput {
|
||||
shopping_cart_item: item.into(),
|
||||
})),
|
||||
None => Err(routes::Error::Public(super::Error::ModifyItem.into())),
|
||||
}
|
||||
}
|
||||
|
||||
#[put("/shopping-cart")]
|
||||
async fn update_cart(
|
||||
cart: Data<Addr<CartManager>>,
|
||||
tm: Data<Addr<TokenManager>>,
|
||||
credentials: BearerAuth,
|
||||
Json(payload): Json<api::UpdateCartInput>,
|
||||
) -> Result<Json<api::UpdateCartOutput>> {
|
||||
let token = credentials.require_user(tm.into_inner()).await?;
|
||||
let items = payload
|
||||
.items
|
||||
.into_iter()
|
||||
.map(
|
||||
|model::api::UpdateItemInput {
|
||||
product_id,
|
||||
quantity,
|
||||
quantity_unit,
|
||||
}| cart_manager::ModifyItem {
|
||||
buyer_id: token.account_id(),
|
||||
product_id,
|
||||
quantity,
|
||||
quantity_unit,
|
||||
},
|
||||
)
|
||||
.collect();
|
||||
|
||||
let items: Vec<model::ShoppingCartItem> = query_cart!(
|
||||
cart,
|
||||
cart_manager::ModifyCart {
|
||||
buyer_id: token.account_id(),
|
||||
items
|
||||
},
|
||||
routes::Error::Public(super::Error::ModifyItem.into()),
|
||||
routes::Error::Public(PublicError::DatabaseConnection)
|
||||
);
|
||||
|
||||
Ok(Json(api::UpdateCartOutput {
|
||||
items: items.into_iter().map(Into::into).collect(),
|
||||
}))
|
||||
}
|
||||
|
||||
@ -229,6 +271,8 @@ pub(crate) fn configure(config: &mut ServiceConfig) {
|
||||
.service(shopping_cart)
|
||||
.service(delete_cart_item)
|
||||
.service(create_order)
|
||||
.service(update_cart)
|
||||
.service(update_cart_item)
|
||||
.service(me)
|
||||
.service(verify_token)
|
||||
.service(refresh_token);
|
||||
|
@ -366,18 +366,27 @@ pub struct DeleteItemOutput {
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct CreateItemInput {
|
||||
pub struct UpdateItemInput {
|
||||
pub product_id: ProductId,
|
||||
pub quantity: Quantity,
|
||||
pub quantity_unit: QuantityUnit,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct CreateItemOutput {
|
||||
pub success: bool,
|
||||
pub struct UpdateItemOutput {
|
||||
pub shopping_cart_item: ShoppingCartItem,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct UpdateCartInput {
|
||||
pub items: Vec<UpdateItemInput>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct UpdateCartOutput {
|
||||
pub items: Vec<ShoppingCartItem>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct SearchRequest {
|
||||
/// Match string
|
||||
|
@ -2,6 +2,7 @@ use model::{AccessTokenString, RefreshTokenString};
|
||||
use seed::fetch::{Header, Method, Request};
|
||||
|
||||
use crate::api::perform;
|
||||
use crate::NetRes;
|
||||
|
||||
pub async fn config() -> super::NetRes<model::api::Config> {
|
||||
perform(Request::new("/config").method(Method::Get)).await
|
||||
@ -65,3 +66,54 @@ pub async fn sign_up(
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn update_cart_item(
|
||||
access_token: &AccessTokenString,
|
||||
product_id: model::ProductId,
|
||||
quantity: model::Quantity,
|
||||
quantity_unit: model::QuantityUnit,
|
||||
) -> NetRes<model::api::UpdateItemOutput> {
|
||||
let input = model::api::UpdateItemInput {
|
||||
product_id,
|
||||
quantity,
|
||||
quantity_unit,
|
||||
};
|
||||
perform(
|
||||
Request::new("/api/v1/shopping-cart-item")
|
||||
.method(Method::Put)
|
||||
.header(Header::bearer(access_token.as_str()))
|
||||
.json(&input)
|
||||
.map_err(crate::api::NetRes::Http)?,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn update_cart(
|
||||
access_token: AccessTokenString,
|
||||
items: Vec<crate::shopping_cart::Item>,
|
||||
) -> NetRes<model::api::UpdateCartOutput> {
|
||||
let input = model::api::UpdateCartInput {
|
||||
items: items
|
||||
.into_iter()
|
||||
.map(
|
||||
|crate::shopping_cart::Item {
|
||||
product_id,
|
||||
quantity,
|
||||
quantity_unit,
|
||||
}| model::api::UpdateItemInput {
|
||||
product_id,
|
||||
quantity,
|
||||
quantity_unit,
|
||||
},
|
||||
)
|
||||
.collect(),
|
||||
};
|
||||
perform(
|
||||
Request::new("/api/v1/shopping-cart")
|
||||
.method(Method::Put)
|
||||
.header(Header::bearer(access_token.as_str()))
|
||||
.json(&input)
|
||||
.map_err(crate::api::NetRes::Http)?,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
@ -169,13 +169,6 @@ fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
|
||||
let page = fetch_page!(public model, SignIn);
|
||||
pages::public::sign_in::update(msg, page, &mut orders.proxy(Into::into))
|
||||
}
|
||||
Msg::Public(pages::public::PublicMsg::SignUp(
|
||||
pages::public::sign_up::RegisterMsg::AccountCreated(res),
|
||||
)) => {
|
||||
orders
|
||||
.skip()
|
||||
.send_msg(Msg::Session(SessionMsg::TokenRefreshed(res)));
|
||||
}
|
||||
Msg::Public(pages::public::PublicMsg::SignUp(msg)) => {
|
||||
let page = fetch_page!(public model, SignUp);
|
||||
pages::public::sign_up::update(msg, page, &mut orders.proxy(Into::into))
|
||||
|
@ -62,7 +62,6 @@ pub fn view(model: &crate::Model, page: &SignInPage) -> Node<crate::Msg> {
|
||||
]
|
||||
.map_msg(Into::into);
|
||||
|
||||
// crate::shared::view::public_navbar(model),
|
||||
div![super::layout::view(model, content, None)]
|
||||
}
|
||||
|
||||
|
@ -1,10 +1,11 @@
|
||||
use std::str::FromStr;
|
||||
|
||||
use model::{Email, Login, Password, PasswordConfirmation};
|
||||
use seed::prelude::*;
|
||||
use seed::*;
|
||||
|
||||
use crate::pages::Urls;
|
||||
use crate::shopping_cart::CartMsg;
|
||||
use crate::SessionMsg;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum RegisterMsg {
|
||||
@ -38,18 +39,18 @@ pub fn page_changed(_url: Url, _model: &mut SignUpPage) {}
|
||||
pub fn update(msg: RegisterMsg, model: &mut SignUpPage, orders: &mut impl Orders<crate::Msg>) {
|
||||
match msg {
|
||||
RegisterMsg::LoginChanged(value) => {
|
||||
model.login = Login::new(value);
|
||||
model.login = model::Login::new(value);
|
||||
}
|
||||
RegisterMsg::EmailChanged(value) => {
|
||||
if let Ok(email) = Email::from_str(&value) {
|
||||
if let Ok(email) = model::Email::from_str(&value) {
|
||||
model.email = email;
|
||||
}
|
||||
}
|
||||
RegisterMsg::PasswordChanged(value) => {
|
||||
model.password = Password::new(value);
|
||||
model.password = model::Password::new(value);
|
||||
}
|
||||
RegisterMsg::PasswordConfirmationChanged(value) => {
|
||||
model.password_confirmation = PasswordConfirmation::new(value);
|
||||
model.password_confirmation = model::PasswordConfirmation::new(value);
|
||||
}
|
||||
RegisterMsg::Submit => {
|
||||
let email = model.email.clone();
|
||||
@ -72,7 +73,12 @@ pub fn update(msg: RegisterMsg, model: &mut SignUpPage, orders: &mut impl Orders
|
||||
)
|
||||
});
|
||||
}
|
||||
RegisterMsg::AccountCreated(_) => {}
|
||||
RegisterMsg::AccountCreated(res) => {
|
||||
orders
|
||||
.skip()
|
||||
.send_msg(crate::Msg::Session(SessionMsg::TokenRefreshed(res)))
|
||||
.send_msg(crate::Msg::Cart(CartMsg::Sync));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,8 @@ use model::{ProductId, Quantity, QuantityUnit};
|
||||
use seed::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{Model, Msg};
|
||||
use crate::shared::notification::NotificationMsg;
|
||||
use crate::{Model, Msg, NetRes};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum CartMsg {
|
||||
@ -19,6 +20,9 @@ pub enum CartMsg {
|
||||
Remove(ProductId),
|
||||
Hover,
|
||||
Leave,
|
||||
/// Send current non-empty cart to server
|
||||
Sync,
|
||||
SyncResult(NetRes<model::api::UpdateCartOutput>),
|
||||
}
|
||||
|
||||
impl From<CartMsg> for Msg {
|
||||
@ -29,7 +33,7 @@ impl From<CartMsg> for Msg {
|
||||
|
||||
pub type Items = indexmap::IndexMap<ProductId, Item>;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
|
||||
pub struct Item {
|
||||
pub product_id: ProductId,
|
||||
pub quantity: Quantity,
|
||||
@ -48,7 +52,7 @@ pub fn init(model: &mut Model, _orders: &mut impl Orders<Msg>) {
|
||||
model.cart = load_local();
|
||||
}
|
||||
|
||||
pub fn update(msg: CartMsg, model: &mut Model, _orders: &mut impl Orders<Msg>) {
|
||||
pub fn update(msg: CartMsg, model: &mut Model, orders: &mut impl Orders<Msg>) {
|
||||
match msg {
|
||||
CartMsg::AddItem {
|
||||
quantity,
|
||||
@ -96,6 +100,27 @@ pub fn update(msg: CartMsg, model: &mut Model, _orders: &mut impl Orders<Msg>) {
|
||||
CartMsg::Leave => {
|
||||
model.cart.hover = false;
|
||||
}
|
||||
CartMsg::Sync => {
|
||||
if let Some(access_token) = model.shared.access_token.as_ref().cloned() {
|
||||
let items: Vec<Item> = model.cart.items.values().map(Clone::clone).collect();
|
||||
orders.perform_cmd(async {
|
||||
crate::Msg::from(CartMsg::SyncResult(
|
||||
crate::api::public::update_cart(access_token, items).await,
|
||||
))
|
||||
});
|
||||
}
|
||||
}
|
||||
CartMsg::SyncResult(NetRes::Success(cart)) => {
|
||||
// cart.items
|
||||
}
|
||||
CartMsg::SyncResult(NetRes::Error(failure)) => {
|
||||
for msg in failure.errors {
|
||||
orders.send_msg(NotificationMsg::Error(msg).into());
|
||||
}
|
||||
}
|
||||
CartMsg::SyncResult(NetRes::Http(_cart)) => {
|
||||
orders.send_msg(NotificationMsg::Error("Unable to sync cart".into()).into());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user