Start cart

This commit is contained in:
Adrian Woźniak 2022-05-15 14:05:26 +02:00
parent 09d7369b0c
commit e215bbe003
No known key found for this signature in database
GPG Key ID: 0012845A89C7352B
7 changed files with 138 additions and 34 deletions

View File

@ -8,6 +8,7 @@ mod model;
mod pages; mod pages;
pub mod session; pub mod session;
pub mod shared; pub mod shared;
pub mod shopping_cart;
use seed::empty; use seed::empty;
use seed::prelude::*; use seed::prelude::*;
@ -81,10 +82,12 @@ fn init(url: Url, orders: &mut impl Orders<Msg>) -> Model {
.and_then(|el: web_sys::Element| el.get_attribute("href")), .and_then(|el: web_sys::Element| el.get_attribute("href")),
shared: shared::Model::default(), shared: shared::Model::default(),
i18n: I18n::load(), i18n: I18n::load(),
cart: Default::default(),
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
debug_modal: false, debug_modal: false,
}; };
shopping_cart::init(&mut model, orders);
session::init(&mut model, orders); session::init(&mut model, orders);
shared::init(&mut model, orders); shared::init(&mut model, orders);
@ -101,7 +104,7 @@ fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
orders.skip(); orders.skip();
} }
Msg::Shared(msg) => { Msg::Shared(msg) => {
shared::update(msg, &mut model.shared, orders); shared::update(msg, model, orders);
} }
Msg::UrlChanged(subs::UrlChanged(url)) => model.page.page_changed(url, orders), Msg::UrlChanged(subs::UrlChanged(url)) => model.page.page_changed(url, orders),
Msg::Public(pages::public::Msg::Listing(msg)) => { Msg::Public(pages::public::Msg::Listing(msg)) => {

View File

@ -1,6 +1,6 @@
use seed::Url; use seed::Url;
use crate::{I18n, Page}; use crate::{I18n, Page, shopping_cart};
#[derive(Debug)] #[derive(Debug)]
pub struct Model { pub struct Model {
@ -10,6 +10,7 @@ pub struct Model {
pub logo: Option<String>, pub logo: Option<String>,
pub shared: crate::shared::Model, pub shared: crate::shared::Model,
pub i18n: I18n, pub i18n: I18n,
pub cart: shopping_cart::ShoppingCart,
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
pub debug_modal: bool, pub debug_modal: bool,
} }

View File

@ -13,7 +13,7 @@ pub enum Msg {
Public(public::Msg), Public(public::Msg),
Admin(admin::Msg), Admin(admin::Msg),
UrlChanged(subs::UrlChanged), UrlChanged(subs::UrlChanged),
Shared(shared::Msg), Shared(shared::SharedMsg),
Session(crate::session::SessionMsg), Session(crate::session::SessionMsg),
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
Debug(crate::debug::DebugMsg), Debug(crate::debug::DebugMsg),

View File

@ -2,8 +2,9 @@ use chrono::{NaiveDateTime, TimeZone};
use model::{AccessTokenString, RefreshTokenString}; use model::{AccessTokenString, RefreshTokenString};
use seed::prelude::*; use seed::prelude::*;
use crate::pages::AdminPage;
use crate::shared::notification::NotificationMsg; use crate::shared::notification::NotificationMsg;
use crate::{Model, Msg}; use crate::{pages, Model, Msg, Page, PublicPage};
#[derive(Debug)] #[derive(Debug)]
pub enum SessionMsg { pub enum SessionMsg {
@ -29,11 +30,40 @@ pub fn init(model: &mut Model, orders: &mut impl Orders<Msg>) {
.ok() .ok()
.map(model::RefreshTokenString::new); .map(model::RefreshTokenString::new);
model.shared.exp = LocalStorage::get::<_, String>("exp").ok().and_then(|s| { model.shared.exp = LocalStorage::get::<_, String>("exp").ok().and_then(|s| {
seed::log!("Parsing ", s);
chrono::DateTime::parse_from_rfc3339(&s) chrono::DateTime::parse_from_rfc3339(&s)
.ok() .ok()
.map(|t| t.naive_utc()) .map(|t| t.naive_utc())
}) });
redirect_on_session(model, orders);
}
pub fn redirect_on_session(model: &Model, orders: &mut impl Orders<Msg>) {
seed::log!(&model.page, model.shared.me.is_some());
match &model.page {
Page::Admin(admin) => match admin {
AdminPage::Landing => {}
AdminPage::Dashboard => {}
AdminPage::Products => {}
AdminPage::Product => {}
},
Page::Public(public) if model.shared.me.is_some() => match public {
PublicPage::SignUp(_) | PublicPage::SignIn(_) => {
let url = model.url.clone().set_path(&[] as &[&str]);
url.go_and_push();
orders.send_msg(crate::Msg::UrlChanged(subs::UrlChanged(url)));
orders.force_render_now();
}
_ => {}
},
Page::Public(public) => match public {
PublicPage::Listing(_) => {}
PublicPage::Product(_) => {}
PublicPage::SignIn(_) => {}
PublicPage::SignUp(_) => {}
PublicPage::ShoppingCart => {}
PublicPage::Checkout => {}
},
}
} }
pub fn update(msg: SessionMsg, model: &mut Model, orders: &mut impl Orders<Msg>) { pub fn update(msg: SessionMsg, model: &mut Model, orders: &mut impl Orders<Msg>) {
@ -103,7 +133,7 @@ pub fn update(msg: SessionMsg, model: &mut Model, orders: &mut impl Orders<Msg>)
errors.into_iter().for_each(|msg| { errors.into_iter().for_each(|msg| {
orders orders
.skip() .skip()
.send_msg(Msg::Shared(crate::shared::Msg::Notification( .send_msg(Msg::Shared(crate::shared::SharedMsg::Notification(
NotificationMsg::Error(msg), NotificationMsg::Error(msg),
))); )));
}); });
@ -133,7 +163,7 @@ pub fn update(msg: SessionMsg, model: &mut Model, orders: &mut impl Orders<Msg>)
_ => { _ => {
orders orders
.skip() .skip()
.send_msg(Msg::Shared(crate::shared::Msg::Notification( .send_msg(Msg::Shared(crate::shared::SharedMsg::Notification(
NotificationMsg::Error("Request failed".into()), NotificationMsg::Error("Request failed".into()),
))); )));
} }

View File

@ -1,15 +1,17 @@
use seed::app::Orders; use seed::app::Orders;
use crate::session::redirect_on_session;
pub mod notification; pub mod notification;
pub mod view; pub mod view;
#[derive(Debug)] #[derive(Debug)]
pub enum Msg { pub enum SharedMsg {
LoadMe, LoadMe,
MeLoaded(crate::api::NetRes<model::Account>), MeLoaded(crate::api::NetRes<model::Account>),
SignIn(model::api::SignInInput), SignIn(model::api::SignInInput),
SignedIn(crate::api::NetRes<model::api::SessionOutput>), SignedIn(crate::api::NetRes<model::api::SessionOutput>),
Notification(crate::shared::notification::NotificationMsg), Notification(notification::NotificationMsg),
} }
#[derive(Debug, Default)] #[derive(Debug, Default)]
@ -22,38 +24,38 @@ pub struct Model {
} }
pub fn init(_model: &mut crate::Model, orders: &mut impl Orders<crate::Msg>) { pub fn init(_model: &mut crate::Model, orders: &mut impl Orders<crate::Msg>) {
orders.send_msg(crate::Msg::Shared(Msg::LoadMe)); orders.send_msg(crate::Msg::Shared(SharedMsg::LoadMe));
} }
pub fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders<crate::Msg>) { pub fn update(msg: SharedMsg, model: &mut crate::Model, orders: &mut impl Orders<crate::Msg>) {
match msg { match msg {
Msg::LoadMe => { SharedMsg::LoadMe => {
seed::log!("1"); if let Some(token) = model.shared.access_token.as_ref().cloned() {
if let Some(token) = model.access_token.as_ref().cloned() {
seed::log!("2");
orders.skip().perform_cmd(async move { orders.skip().perform_cmd(async move {
seed::log!("3"); crate::Msg::Shared(SharedMsg::MeLoaded(
Msg::MeLoaded(crate::api::public::fetch_me(token).await) crate::api::public::fetch_me(token).await,
))
}); });
} }
} }
Msg::MeLoaded(crate::api::NetRes::Success(account)) => { SharedMsg::MeLoaded(crate::api::NetRes::Success(account)) => {
model.me = Some(account); model.shared.me = Some(account);
redirect_on_session(model, orders);
} }
Msg::MeLoaded(crate::api::NetRes::Error(_error)) => {} SharedMsg::MeLoaded(crate::api::NetRes::Error(_error)) => {}
Msg::MeLoaded(crate::api::NetRes::Http(_error)) => {} SharedMsg::MeLoaded(crate::api::NetRes::Http(_error)) => {}
Msg::SignIn(input) => { SharedMsg::SignIn(input) => {
orders orders.skip().perform_cmd(async {
.skip() SharedMsg::SignedIn(crate::api::public::sign_in(input).await)
.perform_cmd(async { Msg::SignedIn(crate::api::public::sign_in(input).await) }); });
} }
Msg::SignedIn(crate::api::NetRes::Success(pair)) => { SharedMsg::SignedIn(crate::api::NetRes::Success(pair)) => {
handle_auth_pair(pair, model, orders); handle_auth_pair(pair, &mut model.shared, orders);
} }
Msg::SignedIn(crate::api::NetRes::Error(_err)) => {} SharedMsg::SignedIn(crate::api::NetRes::Error(_err)) => {}
Msg::SignedIn(crate::api::NetRes::Http(_err)) => {} SharedMsg::SignedIn(crate::api::NetRes::Http(_err)) => {}
Msg::Notification(msg) => { SharedMsg::Notification(msg) => {
notification::update(msg, model, orders); notification::update(msg, &mut model.shared, orders);
} }
} }
} }

View File

@ -13,7 +13,7 @@ pub enum NotificationMsg {
Clear, Clear,
} }
impl From<NotificationMsg> for shared::Msg { impl From<NotificationMsg> for shared::SharedMsg {
fn from(msg: NotificationMsg) -> Self { fn from(msg: NotificationMsg) -> Self {
Self::Notification(msg) Self::Notification(msg)
} }
@ -152,7 +152,7 @@ pub fn message(id: uuid::Uuid, message: &str, icon: Type) -> Node<Msg> {
ev(Ev::Click, move |ev| { ev(Ev::Click, move |ev| {
ev.prevent_default(); ev.prevent_default();
ev.stop_propagation(); ev.stop_propagation();
Msg::Shared(shared::Msg::Notification(NotificationMsg::Close(id))) Msg::Shared(shared::SharedMsg::Notification(NotificationMsg::Close(id)))
}) })
] ]
] ]

68
web/src/shopping_cart.rs Normal file
View File

@ -0,0 +1,68 @@
use model::{ProductId, Quantity, QuantityUnit};
use seed::prelude::*;
use serde::{Deserialize, Serialize};
use crate::{Model, Msg};
#[derive(Debug)]
pub enum CartMsg {
AddItem {
quantity: Quantity,
quantity_unit: QuantityUnit,
product_id: ProductId,
},
ModifyItem {
quantity: Quantity,
quantity_unit: QuantityUnit,
product_id: ProductId,
},
}
pub type Items = indexmap::IndexMap<model::ProductId, Item>;
#[derive(Debug, Serialize, Deserialize)]
pub struct Item {
product_id: ProductId,
quantity: Quantity,
quantity_unit: QuantityUnit,
}
#[derive(Debug, Default, Serialize, Deserialize)]
pub struct ShoppingCart {
pub cart_id: Option<model::ShoppingCartId>,
pub items: Items,
}
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>) {
match msg {
CartMsg::AddItem {
quantity,
quantity_unit,
product_id,
} => {
{
let items: &mut Items = &mut model.cart.items;
let entry = items.entry(product_id).or_insert_with(|| Item {
quantity,
quantity_unit,
product_id,
});
entry.quantity = quantity;
entry.quantity_unit = quantity_unit;
}
store_local(&model.cart);
}
CartMsg::ModifyItem { .. } => {}
}
}
fn load_local() -> ShoppingCart {
LocalStorage::get("ct").unwrap_or_default()
}
fn store_local(cart: &ShoppingCart) {
LocalStorage::insert("ct", cart).ok();
}