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 database_manager::{query_db, Database};
|
||||||
use model::{
|
use model::{
|
||||||
AccountId, ProductId, Quantity, QuantityUnit, ShoppingCartId, ShoppingCartItem,
|
AccountId, ProductId, Quantity, QuantityUnit, ShoppingCartId, ShoppingCartItem,
|
||||||
@ -60,8 +64,10 @@ pub enum Error {
|
|||||||
ShoppingCartFailed,
|
ShoppingCartFailed,
|
||||||
#[error("Shopping cart is not available for unknown reason")]
|
#[error("Shopping cart is not available for unknown reason")]
|
||||||
CartNotAvailable,
|
CartNotAvailable,
|
||||||
#[error("Failed to add item to cart")]
|
#[error("Failed to modify item to cart")]
|
||||||
CantAddItem,
|
CantModifyItem,
|
||||||
|
#[error("Failed to modify cart")]
|
||||||
|
CantModifyCart,
|
||||||
#[error("{0}")]
|
#[error("{0}")]
|
||||||
Db(#[from] database_manager::Error),
|
Db(#[from] database_manager::Error),
|
||||||
#[error("Unable to update cart item")]
|
#[error("Unable to update cart item")]
|
||||||
@ -89,7 +95,7 @@ impl CartManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(actix::Message)]
|
#[derive(actix::Message)]
|
||||||
#[rtype(result = "Result<ShoppingCartItem>")]
|
#[rtype(result = "Result<Option<ShoppingCartItem>>")]
|
||||||
pub struct ModifyItem {
|
pub struct ModifyItem {
|
||||||
pub buyer_id: AccountId,
|
pub buyer_id: AccountId,
|
||||||
pub product_id: ProductId,
|
pub product_id: ProductId,
|
||||||
@ -97,9 +103,12 @@ pub struct ModifyItem {
|
|||||||
pub quantity_unit: QuantityUnit,
|
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!(
|
let _cart = query_db!(
|
||||||
db,
|
db,
|
||||||
database_manager::EnsureActiveShoppingCart {
|
database_manager::EnsureActiveShoppingCart {
|
||||||
@ -127,11 +136,17 @@ async fn modify_item(msg: ModifyItem, db: actix::Addr<Database>) -> Result<Shopp
|
|||||||
database_manager::ActiveCartItemByProduct {
|
database_manager::ActiveCartItemByProduct {
|
||||||
product_id: msg.product_id
|
product_id: msg.product_id
|
||||||
},
|
},
|
||||||
Error::CantAddItem
|
Error::CantModifyItem
|
||||||
);
|
);
|
||||||
|
|
||||||
match item {
|
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,
|
db,
|
||||||
database_manager::UpdateShoppingCartItem {
|
database_manager::UpdateShoppingCartItem {
|
||||||
id: item.id,
|
id: item.id,
|
||||||
@ -141,9 +156,9 @@ async fn modify_item(msg: ModifyItem, db: actix::Addr<Database>) -> Result<Shopp
|
|||||||
quantity_unit: msg.quantity_unit,
|
quantity_unit: msg.quantity_unit,
|
||||||
},
|
},
|
||||||
passthrough Error::Db,
|
passthrough Error::Db,
|
||||||
Error::CantAddItem
|
Error::CantModifyItem
|
||||||
)),
|
))),
|
||||||
None => Ok(query_db!(
|
None => Ok(Some(query_db!(
|
||||||
db,
|
db,
|
||||||
database_manager::CreateShoppingCartItem {
|
database_manager::CreateShoppingCartItem {
|
||||||
product_id: msg.product_id,
|
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,
|
quantity_unit: msg.quantity_unit,
|
||||||
},
|
},
|
||||||
passthrough Error::Db,
|
passthrough Error::Db,
|
||||||
Error::CantAddItem
|
Error::CantModifyItem
|
||||||
)),
|
))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -170,68 +185,101 @@ pub(crate) async fn remove_product(
|
|||||||
msg: RemoveProduct,
|
msg: RemoveProduct,
|
||||||
db: actix::Addr<Database>,
|
db: actix::Addr<Database>,
|
||||||
) -> Result<Option<ShoppingCartItem>> {
|
) -> Result<Option<ShoppingCartItem>> {
|
||||||
match db
|
Ok(query_db!(
|
||||||
.send(database_manager::RemoveCartItem {
|
db,
|
||||||
|
database_manager::RemoveCartItem {
|
||||||
shopping_cart_id: msg.shopping_cart_id,
|
shopping_cart_id: msg.shopping_cart_id,
|
||||||
shopping_cart_item_id: Some(msg.shopping_cart_item_id),
|
shopping_cart_item_id: Some(msg.shopping_cart_item_id),
|
||||||
product_id: None,
|
product_id: None,
|
||||||
})
|
},
|
||||||
.await
|
Error::UpdateFailed
|
||||||
{
|
))
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(actix::Message)]
|
#[derive(actix::Message)]
|
||||||
#[rtype(result = "Result<Option<ShoppingCartItem>>")]
|
#[rtype(result = "Result<Vec<ShoppingCartItem>>")]
|
||||||
pub struct ChangeQuantity {
|
pub struct ModifyCart {
|
||||||
pub shopping_cart_id: ShoppingCartId,
|
pub buyer_id: AccountId,
|
||||||
pub shopping_cart_item_id: ShoppingCartItemId,
|
pub items: Vec<ModifyItem>,
|
||||||
pub quantity: Quantity,
|
|
||||||
pub quantity_unit: QuantityUnit,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cart_async_handler!(ChangeQuantity, change_quantity, Option<ShoppingCartItem>);
|
cart_async_handler!(ModifyCart, modify_cart, Vec<ShoppingCartItem>);
|
||||||
|
|
||||||
pub(crate) async fn change_quantity(
|
async fn modify_cart(msg: ModifyCart, db: actix::Addr<Database>) -> Result<Vec<ShoppingCartItem>> {
|
||||||
msg: ChangeQuantity,
|
let _cart = query_db!(
|
||||||
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!(
|
|
||||||
db,
|
db,
|
||||||
database_manager::FindShoppingCartItem {
|
database_manager::EnsureActiveShoppingCart {
|
||||||
id: msg.shopping_cart_item_id,
|
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!(
|
for item in items.drain_filter(|item| !existing.contains(&item.product_id)) {
|
||||||
db,
|
query_db!(
|
||||||
database_manager::UpdateShoppingCartItem {
|
db,
|
||||||
id: msg.shopping_cart_item_id,
|
database_manager::RemoveCartItem {
|
||||||
product_id: item.product_id,
|
shopping_cart_id: cart.id,
|
||||||
shopping_cart_id: item.shopping_cart_id,
|
shopping_cart_item_id: Some(item.id),
|
||||||
quantity: msg.quantity,
|
product_id: None,
|
||||||
quantity_unit: msg.quantity_unit,
|
},
|
||||||
},
|
Error::CantModifyCart
|
||||||
Error::ChangeQuantity
|
);
|
||||||
)))
|
}
|
||||||
|
|
||||||
|
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)]
|
#[derive(actix::Message)]
|
||||||
#[rtype(result = "Result<ShoppingCartItem>")]
|
#[rtype(result = "Result<ShoppingCartItem>")]
|
||||||
pub struct FindShoppingCartItem {
|
pub struct FindShoppingCartItem {
|
||||||
|
@ -110,7 +110,7 @@ impl Responder for Error {
|
|||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
Error::Public(PublicError::ApiV1(
|
Error::Public(PublicError::ApiV1(
|
||||||
V1Error::AddItem | V1Error::RemoveItem | V1Error::AddOrder,
|
V1Error::ModifyItem | V1Error::RemoveItem | V1Error::AddOrder,
|
||||||
)) => HttpResponse::BadRequest()
|
)) => HttpResponse::BadRequest()
|
||||||
.content_type("application/json")
|
.content_type("application/json")
|
||||||
.json(Failure {
|
.json(Failure {
|
||||||
|
@ -17,7 +17,7 @@ pub enum Error {
|
|||||||
#[error("Failed to remove shopping cart item")]
|
#[error("Failed to remove shopping cart item")]
|
||||||
RemoveItem,
|
RemoveItem,
|
||||||
#[error("Failed to add shopping cart item")]
|
#[error("Failed to add shopping cart item")]
|
||||||
AddItem,
|
ModifyItem,
|
||||||
|
|
||||||
#[error("Failed to create order")]
|
#[error("Failed to create order")]
|
||||||
AddOrder,
|
AddOrder,
|
||||||
|
@ -93,11 +93,11 @@ async fn update_cart_item(
|
|||||||
cart: Data<Addr<CartManager>>,
|
cart: Data<Addr<CartManager>>,
|
||||||
tm: Data<Addr<TokenManager>>,
|
tm: Data<Addr<TokenManager>>,
|
||||||
credentials: BearerAuth,
|
credentials: BearerAuth,
|
||||||
Json(payload): Json<api::CreateItemInput>,
|
Json(payload): Json<api::UpdateItemInput>,
|
||||||
) -> Result<Json<api::CreateItemOutput>> {
|
) -> Result<Json<api::UpdateItemOutput>> {
|
||||||
let token = credentials.require_user(tm.into_inner()).await?;
|
let token = credentials.require_user(tm.into_inner()).await?;
|
||||||
|
|
||||||
let item: model::ShoppingCartItem = query_cart!(
|
let item: Option<model::ShoppingCartItem> = query_cart!(
|
||||||
cart,
|
cart,
|
||||||
cart_manager::ModifyItem {
|
cart_manager::ModifyItem {
|
||||||
buyer_id: token.account_id(),
|
buyer_id: token.account_id(),
|
||||||
@ -105,13 +105,55 @@ async fn update_cart_item(
|
|||||||
quantity: payload.quantity,
|
quantity: payload.quantity,
|
||||||
quantity_unit: payload.quantity_unit,
|
quantity_unit: payload.quantity_unit,
|
||||||
},
|
},
|
||||||
routes::Error::Public(super::Error::AddItem.into()),
|
routes::Error::Public(super::Error::ModifyItem.into()),
|
||||||
routes::Error::Public(PublicError::DatabaseConnection)
|
routes::Error::Public(PublicError::DatabaseConnection)
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(Json(api::CreateItemOutput {
|
match item {
|
||||||
success: true,
|
Some(item) => Ok(Json(api::UpdateItemOutput {
|
||||||
shopping_cart_item: item.into(),
|
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(shopping_cart)
|
||||||
.service(delete_cart_item)
|
.service(delete_cart_item)
|
||||||
.service(create_order)
|
.service(create_order)
|
||||||
|
.service(update_cart)
|
||||||
|
.service(update_cart_item)
|
||||||
.service(me)
|
.service(me)
|
||||||
.service(verify_token)
|
.service(verify_token)
|
||||||
.service(refresh_token);
|
.service(refresh_token);
|
||||||
|
@ -366,18 +366,27 @@ pub struct DeleteItemOutput {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
pub struct CreateItemInput {
|
pub struct UpdateItemInput {
|
||||||
pub product_id: ProductId,
|
pub product_id: ProductId,
|
||||||
pub quantity: Quantity,
|
pub quantity: Quantity,
|
||||||
pub quantity_unit: QuantityUnit,
|
pub quantity_unit: QuantityUnit,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
pub struct CreateItemOutput {
|
pub struct UpdateItemOutput {
|
||||||
pub success: bool,
|
|
||||||
pub shopping_cart_item: ShoppingCartItem,
|
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)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
pub struct SearchRequest {
|
pub struct SearchRequest {
|
||||||
/// Match string
|
/// Match string
|
||||||
|
@ -2,6 +2,7 @@ use model::{AccessTokenString, RefreshTokenString};
|
|||||||
use seed::fetch::{Header, Method, Request};
|
use seed::fetch::{Header, Method, Request};
|
||||||
|
|
||||||
use crate::api::perform;
|
use crate::api::perform;
|
||||||
|
use crate::NetRes;
|
||||||
|
|
||||||
pub async fn config() -> super::NetRes<model::api::Config> {
|
pub async fn config() -> super::NetRes<model::api::Config> {
|
||||||
perform(Request::new("/config").method(Method::Get)).await
|
perform(Request::new("/config").method(Method::Get)).await
|
||||||
@ -65,3 +66,54 @@ pub async fn sign_up(
|
|||||||
)
|
)
|
||||||
.await
|
.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);
|
let page = fetch_page!(public model, SignIn);
|
||||||
pages::public::sign_in::update(msg, page, &mut orders.proxy(Into::into))
|
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)) => {
|
Msg::Public(pages::public::PublicMsg::SignUp(msg)) => {
|
||||||
let page = fetch_page!(public model, SignUp);
|
let page = fetch_page!(public model, SignUp);
|
||||||
pages::public::sign_up::update(msg, page, &mut orders.proxy(Into::into))
|
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);
|
.map_msg(Into::into);
|
||||||
|
|
||||||
// crate::shared::view::public_navbar(model),
|
|
||||||
div![super::layout::view(model, content, None)]
|
div![super::layout::view(model, content, None)]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use model::{Email, Login, Password, PasswordConfirmation};
|
|
||||||
use seed::prelude::*;
|
use seed::prelude::*;
|
||||||
use seed::*;
|
use seed::*;
|
||||||
|
|
||||||
use crate::pages::Urls;
|
use crate::pages::Urls;
|
||||||
|
use crate::shopping_cart::CartMsg;
|
||||||
|
use crate::SessionMsg;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum RegisterMsg {
|
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>) {
|
pub fn update(msg: RegisterMsg, model: &mut SignUpPage, orders: &mut impl Orders<crate::Msg>) {
|
||||||
match msg {
|
match msg {
|
||||||
RegisterMsg::LoginChanged(value) => {
|
RegisterMsg::LoginChanged(value) => {
|
||||||
model.login = Login::new(value);
|
model.login = model::Login::new(value);
|
||||||
}
|
}
|
||||||
RegisterMsg::EmailChanged(value) => {
|
RegisterMsg::EmailChanged(value) => {
|
||||||
if let Ok(email) = Email::from_str(&value) {
|
if let Ok(email) = model::Email::from_str(&value) {
|
||||||
model.email = email;
|
model.email = email;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RegisterMsg::PasswordChanged(value) => {
|
RegisterMsg::PasswordChanged(value) => {
|
||||||
model.password = Password::new(value);
|
model.password = model::Password::new(value);
|
||||||
}
|
}
|
||||||
RegisterMsg::PasswordConfirmationChanged(value) => {
|
RegisterMsg::PasswordConfirmationChanged(value) => {
|
||||||
model.password_confirmation = PasswordConfirmation::new(value);
|
model.password_confirmation = model::PasswordConfirmation::new(value);
|
||||||
}
|
}
|
||||||
RegisterMsg::Submit => {
|
RegisterMsg::Submit => {
|
||||||
let email = model.email.clone();
|
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 seed::prelude::*;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{Model, Msg};
|
use crate::shared::notification::NotificationMsg;
|
||||||
|
use crate::{Model, Msg, NetRes};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum CartMsg {
|
pub enum CartMsg {
|
||||||
@ -19,6 +20,9 @@ pub enum CartMsg {
|
|||||||
Remove(ProductId),
|
Remove(ProductId),
|
||||||
Hover,
|
Hover,
|
||||||
Leave,
|
Leave,
|
||||||
|
/// Send current non-empty cart to server
|
||||||
|
Sync,
|
||||||
|
SyncResult(NetRes<model::api::UpdateCartOutput>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<CartMsg> for Msg {
|
impl From<CartMsg> for Msg {
|
||||||
@ -29,7 +33,7 @@ impl From<CartMsg> for Msg {
|
|||||||
|
|
||||||
pub type Items = indexmap::IndexMap<ProductId, Item>;
|
pub type Items = indexmap::IndexMap<ProductId, Item>;
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
|
||||||
pub struct Item {
|
pub struct Item {
|
||||||
pub product_id: ProductId,
|
pub product_id: ProductId,
|
||||||
pub quantity: Quantity,
|
pub quantity: Quantity,
|
||||||
@ -48,7 +52,7 @@ pub fn init(model: &mut Model, _orders: &mut impl Orders<Msg>) {
|
|||||||
model.cart = load_local();
|
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 {
|
match msg {
|
||||||
CartMsg::AddItem {
|
CartMsg::AddItem {
|
||||||
quantity,
|
quantity,
|
||||||
@ -96,6 +100,27 @@ pub fn update(msg: CartMsg, model: &mut Model, _orders: &mut impl Orders<Msg>) {
|
|||||||
CartMsg::Leave => {
|
CartMsg::Leave => {
|
||||||
model.cart.hover = false;
|
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