From c9eb49410bfb36946c73e533f786044da4842b2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrian=20Wo=C5=BAniak?= Date: Tue, 17 May 2022 16:04:29 +0200 Subject: [PATCH] Shopping cart --- api/src/routes/public.rs | 25 ++- shared/model/src/api.rs | 7 + web/src/api/admin.rs | 7 +- web/src/api/public.rs | 4 + web/src/i18n/pl.rs | 19 +- web/src/lib.rs | 11 +- web/src/model.rs | 34 +++ web/src/pages.rs | 3 +- web/src/pages/public.rs | 1 + web/src/pages/public/checkout.rs | 0 web/src/pages/public/listing.rs | 10 +- web/src/pages/public/shopping_cart.rs | 304 ++++++++++++++++++++++++-- web/src/session.rs | 1 + web/src/shared.rs | 1 + web/src/shared/view.rs | 4 +- 15 files changed, 404 insertions(+), 27 deletions(-) create mode 100644 web/src/pages/public/checkout.rs diff --git a/api/src/routes/public.rs b/api/src/routes/public.rs index 80980c0..596c083 100644 --- a/api/src/routes/public.rs +++ b/api/src/routes/public.rs @@ -1,8 +1,10 @@ pub mod api_v1; -use actix_web::web::{Path, ServiceConfig}; +use actix_web::web::{Data, Json, Path, ServiceConfig}; use actix_web::{get, HttpResponse}; pub use api_v1::{Error as V1Error, ShoppingCartError as V1ShoppingCartError}; +use config::SharedAppConfig; +use model::api::Config; #[macro_export] macro_rules! public_send_db { @@ -57,6 +59,26 @@ async fn landing() -> HttpResponse { HttpResponse::NotImplemented().body("") } +#[get("/config.json")] +async fn client_config(config: Data) -> Json { + let (optional_payment, currency) = { + let lock = config.lock(); + let p = lock.payment(); + (p.optional_payment(), p.currency()) + }; + Json(Config { + coupons: false, + pay_methods: match optional_payment { + true => vec![ + model::PaymentMethod::PayU, + model::PaymentMethod::PaymentOnTheSpot, + ], + false => vec![model::PaymentMethod::PayU], + }, + currency, + }) +} + #[get("/pay-on-site")] async fn pay_on_site() -> HttpResponse { HttpResponse::Ok().body("

Pay on Site

") @@ -93,5 +115,6 @@ pub fn configure(config: &mut ServiceConfig) { config .service(landing) .service(svg) + .service(client_config) .configure(api_v1::configure); } diff --git a/shared/model/src/api.rs b/shared/model/src/api.rs index e7eb056..19d8571 100644 --- a/shared/model/src/api.rs +++ b/shared/model/src/api.rs @@ -11,6 +11,13 @@ pub struct Failure { pub errors: Vec, } +#[derive(Serialize, Deserialize, Debug, Default)] +pub struct Config { + pub pay_methods: Vec, + pub coupons: bool, + pub currency: String, +} + #[cfg_attr(feature = "dummy", derive(fake::Dummy))] #[derive(Serialize, Deserialize, Debug)] #[serde(transparent)] diff --git a/web/src/api/admin.rs b/web/src/api/admin.rs index 6f21789..b2bf0ea 100644 --- a/web/src/api/admin.rs +++ b/web/src/api/admin.rs @@ -1,8 +1,11 @@ -use seed::fetch::{Header, Method, Request}; +use seed::fetch::{Method, Request}; use crate::api::{perform, NetRes}; -pub async fn sign_in(identity: String, password: model::Password) -> NetRes { +pub async fn sign_in( + identity: String, + password: model::Password, +) -> NetRes { use model::api::admin::SignInInput; let input = if identity.contains('@') { diff --git a/web/src/api/public.rs b/web/src/api/public.rs index 4c05850..14fe26d 100644 --- a/web/src/api/public.rs +++ b/web/src/api/public.rs @@ -3,6 +3,10 @@ use seed::fetch::{Header, Method, Request}; use crate::api::perform; +pub async fn config() -> super::NetRes { + perform(Request::new("/config.json").method(Method::Get)).await +} + pub async fn fetch_products() -> super::NetRes { perform(Request::new("/api/v1/products").method(Method::Get)).await } diff --git a/web/src/i18n/pl.rs b/web/src/i18n/pl.rs index 17357e9..f5af407 100644 --- a/web/src/i18n/pl.rs +++ b/web/src/i18n/pl.rs @@ -47,5 +47,22 @@ pub fn define(i18n: &mut I18n) { .define("Quantity", "Ilość") .define("Unit price", "Cena jednostkowa") .define("Total price", "Cena łączna") - .define("Delivery", "Sposób dostawy"); + .define("Delivery", "Sposób dostawy") + .define("Coupon Code", "Kod rabatowy") + .define( + "If you have a coupon code, please enter it in the box below", + "Jeśli posiadasz kod kuponu, wpisz go w poniższe pole.", + ) + .define("Apply coupon", "Zastosuj kupon") + .define("Instruction for seller", "Instrukcje dla sprzedawcy") + .define( + "If you have some information for the seller you can leave them in the box below", + "Jeśli masz jakieś informacje dla sprzedawcy, możesz je zostawić w poniższym polu", + ) + .define("Order Details", "Szczegóły zamówienia") + .define("Shipping and additional costs are calculated based on values you have entered", "Koszty wysyłki i koszty dodatkowe są obliczane na podstawie wprowadzonych przez użytkownika wartości") + .define("Subtotal", "Suma częściowa") + .define("New Subtotal", "Łącznie") + .define("Total", "Łącznie") + .define("Proceed to checkout", "Przejdź do kasy"); } diff --git a/web/src/lib.rs b/web/src/lib.rs index ad545c5..1fc6e5a 100644 --- a/web/src/lib.rs +++ b/web/src/lib.rs @@ -13,6 +13,7 @@ pub mod shopping_cart; use seed::empty; use seed::prelude::*; +use crate::api::NetRes; use crate::i18n::I18n; use crate::model::Model; use crate::pages::{AdminPage, Msg, Page, PublicPage}; @@ -105,7 +106,9 @@ macro_rules! fetch_page { } fn init(url: Url, orders: &mut impl Orders) -> Model { - orders.subscribe(Msg::UrlChanged); + orders + .subscribe(Msg::UrlChanged) + .perform_cmd(async { Msg::Config(crate::api::public::config().await) }); let mut model = Model { url: url.clone().set_path(&[] as &[&str]), @@ -120,6 +123,7 @@ fn init(url: Url, orders: &mut impl Orders) -> Model { i18n: I18n::load(), cart: Default::default(), + config: model::Config::default(), #[cfg(debug_assertions)] debug_modal: false, }; @@ -144,6 +148,11 @@ fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders) { Msg::NoOp => { orders.skip(); } + Msg::Config(res) => { + if let NetRes::Success(config) = res { + model.config = config.into(); + } + } Msg::Shared(msg) => { shared::update(msg, model, orders); } diff --git a/web/src/model.rs b/web/src/model.rs index 1f52207..ad36c21 100644 --- a/web/src/model.rs +++ b/web/src/model.rs @@ -13,11 +13,45 @@ pub struct Model { pub shared: crate::shared::Model, pub i18n: I18n, pub cart: shopping_cart::ShoppingCart, + pub config: Config, #[cfg(debug_assertions)] pub debug_modal: bool, } +#[derive(Debug)] +pub struct Config { + pub pay_methods: Vec<::model::PaymentMethod>, + pub coupons: bool, + pub currency: &'static rusty_money::iso::Currency, +} + +impl Default for Config { + fn default() -> Self { + Self { + pay_methods: vec![], + coupons: false, + currency: rusty_money::iso::PLN, + } + } +} + +impl From<::model::api::Config> for Config { + fn from( + model::api::Config { + pay_methods, + coupons, + currency, + }: model::api::Config, + ) -> Self { + Self { + pay_methods, + coupons, + currency: rusty_money::iso::find(¤cy).unwrap_or(rusty_money::iso::PLN), + } + } +} + #[derive(Debug, Default)] pub struct Products { pub categories: Vec, diff --git a/web/src/pages.rs b/web/src/pages.rs index d7efda0..8c11040 100644 --- a/web/src/pages.rs +++ b/web/src/pages.rs @@ -4,12 +4,13 @@ pub mod public; use seed::app::{subs, Orders}; use seed::{struct_urls, Url}; -use crate::shared; +use crate::{shared, NetRes}; #[derive(Debug)] pub enum Msg { #[cfg(debug_assertions)] NoOp, + Config(NetRes<::model::api::Config>), Public(public::Msg), Admin(admin::Msg), UrlChanged(subs::UrlChanged), diff --git a/web/src/pages/public.rs b/web/src/pages/public.rs index 22864d0..cf3a360 100644 --- a/web/src/pages/public.rs +++ b/web/src/pages/public.rs @@ -1,3 +1,4 @@ +pub mod checkout; pub mod listing; pub mod product; pub mod shopping_cart; diff --git a/web/src/pages/public/checkout.rs b/web/src/pages/public/checkout.rs new file mode 100644 index 0000000..e69de29 diff --git a/web/src/pages/public/listing.rs b/web/src/pages/public/listing.rs index 0b0dec8..62f1531 100644 --- a/web/src/pages/public/listing.rs +++ b/web/src/pages/public/listing.rs @@ -73,7 +73,8 @@ pub fn update(msg: ListingMsg, model: &mut ListingPage, orders: &mut impl Orders orders.skip().perform_cmd({ async { crate::Msg::Public( - ListingMsg::ProductsFetched(crate::api::public::fetch_products().await).into(), + ListingMsg::ProductsFetched(crate::api::public::fetch_products().await) + .into(), ) } }); @@ -85,7 +86,8 @@ pub fn update(msg: ListingMsg, model: &mut ListingPage, orders: &mut impl Orders .filter_product_ids(|product| filter_product(model, product)); model.visible_products = ids; } - ListingMsg::ProductsFetched(NetRes::Error(_)) | ListingMsg::ProductsFetched(NetRes::Http(_)) => { + ListingMsg::ProductsFetched(NetRes::Error(_)) + | ListingMsg::ProductsFetched(NetRes::Http(_)) => { model.errors.push("Failed to load products".into()); } } @@ -120,9 +122,9 @@ pub fn view(model: &crate::Model, page: &ListingPage) -> Node { } fn product(model: &crate::Model, product: &model::api::Product) -> Node { - use rusty_money::{iso, Money}; + use rusty_money::Money; - let price = Money::from_minor(**product.price as i64, iso::PLN).to_string(); + let price = Money::from_minor(**product.price as i64, model.config.currency).to_string(); let _description = product.short_description.as_str(); let name = product.name.as_str(); let img = product diff --git a/web/src/pages/public/shopping_cart.rs b/web/src/pages/public/shopping_cart.rs index 8d8d08f..87828af 100644 --- a/web/src/pages/public/shopping_cart.rs +++ b/web/src/pages/public/shopping_cart.rs @@ -52,8 +52,13 @@ pub fn view(model: &crate::Model, page: &ShoppingCartPage) -> Node { C!["flex justify-center my-6"], div![ C!["flex flex-col w-full p-8 text-gray-800 bg-white shadow-lg pin-r pin-y md:w-4/5 lg:w-4/5"], - products(model, page) - ] + div![ + C!["flex-1"], + products(model, page), + div![C!["pb-6 mt-6"]], + summary(model, page), + ] + ] ]; div![ @@ -62,18 +67,284 @@ pub fn view(model: &crate::Model, page: &ShoppingCartPage) -> Node { ] } -fn products(model: &crate::Model, page: &ShoppingCartPage) -> Node { +fn summary(model: &crate::Model, page: &ShoppingCartPage) -> Node { div![ - C!["flex-1"], - table![ - C!["w-full text-sm lg:text-base"], - attrs!["cellspacing" => 0], - products_head(model), - products_body(model, page), + C!["my-4 mt-6 -mx-2 lg:flex"], + summary_left(model, page), + summary_right::view(model, page) + ] +} + +fn summary_left(model: &crate::Model, page: &ShoppingCartPage) -> Node { + div![ + C!["lg:px-2 lg:w-1/2"], + IF![model.config.coupons => div![C!["p-4 bg-gray-100 rounded-full"], h1![C!["ml-2 font-bold uppercase"], model.i18n.t("Coupon Code")]]], + IF![model.config.coupons => coupon_form(model, page)], + div![ + C!["p-4 bg-gray-100 rounded-full", IF![model.config.coupons => "mt-6"]], + div![ + C!["ml-2 font-bold uppercase"], + model.i18n.t("Instruction for seller") + ] + ], + div![C!["p-4"], p![C!["mb-4 italic"], model.i18n.t("If you have some information for the seller you can leave them in the box below")]], + textarea![C!["w-full h-24 p-2 bg-gray-100 rounded border-none"]] + ] +} + +fn coupon_form(model: &crate::Model, _page: &ShoppingCartPage) -> Node { + div![ + C!["p-4"], + p![ + C!["mb-4 italic"], + model + .i18n + .t("If you have a coupon code, please enter it in the box below") + ], + div![ + C!["justify-center md:flex"], + form![ + div![ + C!["flex items-center w-full h-13 pl-3 bg-white bg-gray-100 border rounded-full"], + input![C!["w-full bg-gray-100 outline-none appearance-none focus:outline-none active:outline-none"]], + button![ + C!["text-sm flex items-center px-3 py-1 text-white bg-gray-800 rounded-full outline-none md:px-4 hover:bg-gray-700 focus:outline-none active:outline-none"], + gift_icon(), + span![C!["font-medium"], model.i18n.t("Apply coupon")] + ] + ] + ] ] ] } +fn gift_icon() -> Node { + svg![ + attrs![ + "aria-hidden" => "true", + "data-prefix" => "fas", + "data-icon" => "gift", + "class" => "w-8", + "xmlns" => "http://www.w3.org/2000/svg", + "viewBox" => "0 0 512 512" + ], + path![attrs![ + "fill" => "currentColor", + "d" => "M32 448c0 17.7 14.3 32 32 32h160V320H32v128zm256 32h160c17.7 0 32-14.3 32-32V320H288v160zm192-320h-42.1c6.2-12.1 10.1-25.5 10.1-40 0-48.5-39.5-88-88-88-41.6 0-68.5 21.3-103 68.3-34.5-47-61.4-68.3-103-68.3-48.5 0-88 39.5-88 88 0 14.5 3.8 27.9 10.1 40H32c-17.7 0-32 14.3-32 32v80c0 8.8 7.2 16 16 16h480c8.8 0 16-7.2 16-16v-80c0-17.7-14.3-32-32-32zm-326.1 0c-22.1 0-40-17.9-40-40s17.9-40 40-40c19.9 0 34.6 3.3 86.1 80h-86.1zm206.1 0h-86.1c51.4-76.5 65.7-80 86.1-80 22.1 0 40 17.9 40 40s-17.9 40-40 40z" + ]] + ] +} + +mod summary_right { + use rusty_money::Money; + use seed::prelude::*; + use seed::*; + + use crate::pages::public::shopping_cart::ShoppingCartPage; + use crate::pages::Urls; + + pub fn view(model: &crate::Model, page: &ShoppingCartPage) -> Node { + let subtotal_value = model + .cart + .items + .values() + .filter_map(|item: &crate::shopping_cart::Item| { + page.products + .products + .get(&item.product_id) + .map(|product| (item, product)) + }) + .map( + |(item, product): (&crate::shopping_cart::Item, &model::api::Product)| { + **(product.price * item.quantity) + }, + ) + .sum::() as i64; + div![ + C!["lg:px-2 lg:w-1/2"], + div![ + C!["p-4 bg-gray-100 rounded-full"], + h1![ + C!["ml-2 font-bold uppercase"], + model.i18n.t("Order Details") + ] + ], + div![ + C!["p-4"], + p![C!["mb-6 italic"], model.i18n.t("Shipping and additional costs are calculated based on values you have entered")], + subtotal(model, page, subtotal_value), + coupon_subtotal(model, page), + new_subtotal(model, page, subtotal_value), + total(model, page, subtotal_value), + checkout(model), + ] + ] + } + + fn checkout(model: &crate::Model) -> Node { + a![ + attrs![At::Href => Urls::new(&model.url).checkout()], + button![ + C!["flex justify-center w-full px-10 py-3 mt-6 font-medium text-white uppercase bg-gray-800 rounded-full shadow item-center hover:bg-gray-700 focus:shadow-outline focus:outline-none"], + cart_icon(), + span![ + C!["ml-2 mt-5px"], + model.i18n.t("Proceed to checkout") + ], + ev(Ev::Click, move |ev| { + ev.prevent_default() + }) + ] + ] + } + + fn subtotal( + model: &crate::Model, + _page: &ShoppingCartPage, + subtotal_value: i64, + ) -> Node { + let subtotal = Money::from_minor(subtotal_value, model.config.currency); + + div![ + C!["flex justify-between border-b"], + div![ + C!["lg:px-4 lg:py-2 m-2 text-lg lg:text-xl font-bold text-center text-gray-800"], + model.i18n.t("Subtotal") + ], + div![ + C!["lg:px-4 lg:py-2 m-2 lg:text-lg font-bold text-center text-gray-900"], + subtotal.to_string() + ] + ] + } + + fn coupon_subtotal(model: &crate::Model, _page: &ShoppingCartPage) -> Node { + if !model.config.coupons { + return empty![]; + } + + // TODO! Coupons + let coupon = "90off"; + let coupon_discount = 1654; + + div![ + C!["flex justify-between pt-4 border-b"], + div![ + C!["flex lg:px-4 lg:py-2 m-2 text-lg lg:text-xl font-bold text-gray-800"], + form![button![C!["mr-2 mt-1 lg:mt-2"], trash_icon()]], + model.i18n.t("Coupon"), + " ", + format!("{:?}", coupon) + ], + div![ + C!["lg:px-4 lg:py-2 m-2 lg:text-lg font-bold text-center text-green-700"], + format!( + "-{}", + Money::from_minor(coupon_discount, model.config.currency) + ) + ] + ] + } + + fn new_subtotal( + model: &crate::Model, + _page: &ShoppingCartPage, + subtotal_value: i64, + ) -> Node { + // TODO! Coupons and Delivery + let coupon_discount = 0; + + if !model.config.coupons { + return empty![]; + } + + let new_subtotal = + Money::from_minor(subtotal_value - coupon_discount, model.config.currency); + + div![ + C!["flex justify-between pt-4 border-b"], + div![ + C!["lg:px-4 lg:py-2 m-2 text-lg lg:text-xl font-bold text-center text-gray-800"], + model.i18n.t("New Subtotal") + ], + div![ + C!["lg:px-4 lg:py-2 m-2 lg:text-lg font-bold text-center text-gray-900"], + new_subtotal.to_string() + ] + ] + } + + fn total( + model: &crate::Model, + _page: &ShoppingCartPage, + subtotal_value: i64, + ) -> Node { + // TODO! Coupons and Delivery + let coupon_discount = 0; + let delivery_cost = 0; + + let new_subtotal = Money::from_minor( + subtotal_value - coupon_discount + delivery_cost, + model.config.currency, + ); + + div![ + C!["flex justify-between pt-4 border-b"], + div![ + C!["lg:px-4 lg:py-2 m-2 text-lg lg:text-xl font-bold text-center text-gray-800"], + model.i18n.t("Total") + ], + div![ + C!["lg:px-4 lg:py-2 m-2 lg:text-lg font-bold text-center text-gray-900"], + new_subtotal.to_string() + ] + ] + } + + fn trash_icon() -> Node { + svg![ + attrs![ + "aria-hidden" => "true", + "data-prefix" => "far", + "data-icon" => "trash-alt", + "class" => "w-4 text-red-600 hover:text-red-800", + "xmlns" => "http://www.w3.org/2000/svg", + "viewBox" => "0 0 448 512" + ], + path![attrs![ + "fill" => "currentColor", + "d" => "M268 416h24a12 12 0 0012-12V188a12 12 0 00-12-12h-24a12 12 0 00-12 12v216a12 12 0 0012 12zM432 80h-82.41l-34-56.7A48 48 0 00274.41 0H173.59a48 48 0 00-41.16 23.3L98.41 80H16A16 16 0 000 96v16a16 16 0 0016 16h16v336a48 48 0 0048 48h288a48 48 0 0048-48V128h16a16 16 0 0016-16V96a16 16 0 00-16-16zM171.84 50.91A6 6 0 01177 48h94a6 6 0 015.15 2.91L293.61 80H154.39zM368 464H80V128h288zm-212-48h24a12 12 0 0012-12V188a12 12 0 00-12-12h-24a12 12 0 00-12 12v216a12 12 0 0012 12z" + ]] + ] + } + + fn cart_icon() -> Node { + svg![ + attrs![ + "aria-hidden" => "true", + "data-prefix" => "far", + "data-icon" => "credit-card", + "class" => "w-8", + "xmlns" => "http://www.w3.org/2000/svg", + "viewBox" => "0 0 576 512" + ], + path![attrs![ + "fill" => "currentColor", + "d" => "M527.9 32H48.1C21.5 32 0 53.5 0 80v352c0 26.5 21.5 48 48.1 48h479.8c26.6 0 48.1-21.5 48.1-48V80c0-26.5-21.5-48-48.1-48zM54.1 80h467.8c3.3 0 6 2.7 6 6v42H48.1V86c0-3.3 2.7-6 6-6zm467.8 352H54.1c-3.3 0-6-2.7-6-6V256h479.8v170c0 3.3-2.7 6-6 6zM192 332v40c0 6.6-5.4 12-12 12h-72c-6.6 0-12-5.4-12-12v-40c0-6.6 5.4-12 12-12h72c6.6 0 12 5.4 12 12zm192 0v40c0 6.6-5.4 12-12 12H236c-6.6 0-12-5.4-12-12v-40c0-6.6 5.4-12 12-12h136c6.6 0 12 5.4 12 12z" + ]] + ] + } +} + +fn products(model: &crate::Model, page: &ShoppingCartPage) -> Node { + table![ + C!["w-full text-sm lg:text-base"], + attrs!["cellspacing" => 0], + products_head(model), + products_body(model, page), + ] +} + fn products_head(model: &crate::Model) -> Node { thead![tr![ C!["h-12 uppercase"], @@ -120,7 +391,6 @@ fn item_view( item: &crate::shopping_cart::Item, product: &model::api::Product, ) -> Node { - use rusty_money::iso::PLN; use rusty_money::Money; let img = product @@ -139,7 +409,7 @@ fn item_view( td![ C!["hidden pb-4 md:table-cell"], a![ - attrs![At::Href => product_url.clone()], + attrs![At::Href => &product_url], img![attrs![ At::Src => img, At::Class => "w-20 rounded", @@ -148,7 +418,7 @@ fn item_view( ] ], td![a![ - attrs![At::Href => product_url.clone()], + attrs![At::Href => &product_url], p![C!["mb-2 md:ml-4"], product.name.as_str()], form![ ev(Ev::Submit, move |ev| { @@ -177,7 +447,7 @@ fn item_view( attrs![ At::Type => "number", At::Value => **item.quantity, - At::Class => "w-full font-semibold text-center text-gray-700 bg-gray-200 outline-none focus:outline-none hover:text-black focus:text-black" + At::Class => "w-full font-semibold text-center text-gray-700 bg-gray-200 outline-none focus:outline-none hover:text-black focus:text-black border-none" ], ev(Ev::Change, move |ev| { ev.stop_propagation(); @@ -200,14 +470,18 @@ fn item_view( C!["hidden text-right md:table-cell"], span![ C!["text-sm lg:text-base font-medium"], - Money::from_minor(**product.price as i64, PLN).to_string() + Money::from_minor(**product.price as i64, model.config.currency).to_string() ] ], td![ C!["text-right"], span![ C!["text-sm lg:text-base font-medium"], - Money::from_minor(**(product.price * item.quantity) as i64, PLN).to_string() + Money::from_minor( + **(product.price * item.quantity) as i64, + model.config.currency + ) + .to_string() ] ] ] diff --git a/web/src/session.rs b/web/src/session.rs index baca0d1..b975863 100644 --- a/web/src/session.rs +++ b/web/src/session.rs @@ -120,6 +120,7 @@ pub fn update(msg: SessionMsg, model: &mut Model, orders: &mut impl Orders) access_token, refresh_token, exp, + role: _, })) => { orders .skip() diff --git a/web/src/shared.rs b/web/src/shared.rs index 77e7dc8..2f4383e 100644 --- a/web/src/shared.rs +++ b/web/src/shared.rs @@ -77,6 +77,7 @@ fn handle_auth_pair( access_token, refresh_token, exp, + role: _, } = pair; model.access_token = Some(access_token); diff --git a/web/src/shared/view.rs b/web/src/shared/view.rs index 8d50973..8863641 100644 --- a/web/src/shared/view.rs +++ b/web/src/shared/view.rs @@ -149,7 +149,7 @@ pub mod cart_dropdown { let price = rusty_money::Money::from_minor( **(product.price * item.quantity) as i64, - rusty_money::iso::PLN, + model.config.currency, ) .to_string(); div![ @@ -204,7 +204,7 @@ pub mod cart_dropdown { let sum: i32 = filter_products!(model, products) .map(|(item, product): (&Item, &model::api::Product)| **item.quantity * **product.price) .sum(); - let sum = rusty_money::Money::from_minor(sum as i64, rusty_money::iso::PLN); + let sum = rusty_money::Money::from_minor(sum as i64, model.config.currency); div![ C!["p-4 justify-center flex"],