diff --git a/app/furniture/marketplace/cart_product.rb b/app/furniture/marketplace/cart_product.rb index 61b585f29..dce1b0e2b 100644 --- a/app/furniture/marketplace/cart_product.rb +++ b/app/furniture/marketplace/cart_product.rb @@ -25,6 +25,10 @@ def price_total product.price * quantity end + def quantity_picker + QuantityPicker.new(cart_product: self) + end + private def editable_cart diff --git a/app/furniture/marketplace/cart_product/quantity_picker.rb b/app/furniture/marketplace/cart_product/quantity_picker.rb new file mode 100644 index 000000000..6a454472b --- /dev/null +++ b/app/furniture/marketplace/cart_product/quantity_picker.rb @@ -0,0 +1,6 @@ +class Marketplace + class CartProduct::QuantityPicker < Model + attr_accessor :cart_product + delegate :location, :quantity, to: :cart_product + end +end diff --git a/app/furniture/marketplace/cart_product/quantity_pickers/_quantity_picker.html.erb b/app/furniture/marketplace/cart_product/quantity_pickers/_quantity_picker.html.erb new file mode 100644 index 000000000..1993d6eaf --- /dev/null +++ b/app/furniture/marketplace/cart_product/quantity_pickers/_quantity_picker.html.erb @@ -0,0 +1,13 @@ +
+ <%- if quantity_picker.quantity < 1%> + + <%- elsif quantity_picker.quantity == 1 %> + <%= button_to("🗑️", quantity_picker.location, method: :delete) %> + <%- else %> + <%= button_to("➖", quantity_picker.location, method: :put, params: { cart_product: { quantity: quantity_picker.quantity - 1 } }) %> + <%- end %> + + <%= quantity_picker.quantity %> + + <%= button_to("➕", quantity_picker.location, method: :put, params: { cart_product: { quantity: quantity_picker.quantity + 1 } }) %> +
diff --git a/app/furniture/marketplace/cart_product_component.html.erb b/app/furniture/marketplace/cart_product_component.html.erb index 8af527a27..4ccb04305 100644 --- a/app/furniture/marketplace/cart_product_component.html.erb +++ b/app/furniture/marketplace/cart_product_component.html.erb @@ -1,16 +1,7 @@ - <%- if product.photo.present? %> -
- <%= image_tag product.photo.variant(resize_to_limit: [150, 150]).processed.url, class: "mx-auto h-40 overflow-hidden object-center rounded-lg" - %> -
- <%=product.name%> -
-
- <%- else %> + <%= product.name %> - <%- end %>
<%= product.class.human_attribute_name(:price) %>
@@ -27,15 +18,6 @@ <%= humanized_money_with_symbol(product.price) %> -
- <%= render "buttons/minus", title: t('marketplace.cart_product_component.remove'), method: remove_method, - disabled: cart_product.quantity.zero?, - href: remove_href %> - - <%= quantity %> - - <%= render "buttons/plus", method: add_method, title: t('marketplace.cart_product_component.add'), - href: add_href %> -
+ <%= render cart_product.quantity_picker %> diff --git a/app/furniture/marketplace/cart_product_component.rb b/app/furniture/marketplace/cart_product_component.rb index d89c9ed64..06df98d22 100644 --- a/app/furniture/marketplace/cart_product_component.rb +++ b/app/furniture/marketplace/cart_product_component.rb @@ -1,7 +1,7 @@ class Marketplace class CartProductComponent < ApplicationComponent attr_accessor :cart_product - delegate :name, :description, :location, to: :cart_product + delegate :name, :description, :quantity, :location, to: :cart_product delegate :cart, :product, to: :cart_product def initialize(cart_product:, **kwargs) @@ -10,36 +10,8 @@ def initialize(cart_product:, **kwargs) self.cart_product = cart_product end - def quantity - cart_product.destroyed? ? 0 : cart_product.quantity - end - - def add_quantity - quantity + 1 - end - - def add_method - (add_quantity == 1) ? :post : :put - end - - def add_href - cart_product.location(query_params: {cart_product: {quantity: add_quantity, product_id: product.id}}) - end - - def remove_quantity - [quantity - 1, 0].max - end - - def remove_method - remove_quantity.zero? ? :delete : :put - end - - def remove_href - cart_product.location(query_params: {cart_product: {quantity: remove_quantity, product_id: product.id}}) - end - def dom_id - super(product).gsub("product", "cart_product") + super(cart_product) end end end diff --git a/app/furniture/marketplace/cart_products_controller.rb b/app/furniture/marketplace/cart_products_controller.rb index 363cf57f2..65567b73e 100644 --- a/app/furniture/marketplace/cart_products_controller.rb +++ b/app/furniture/marketplace/cart_products_controller.rb @@ -6,84 +6,47 @@ class CartProductsController < Controller def create authorize(cart_product).save - respond_to do |format| - format.html do - if cart_product.errors.empty? - flash[:notice] = t(".success", - product: cart_product.product.name.pluralize(cart_product.quantity), - quantity: cart_product.quantity) - else - flash[:alert] = t(".failure", - product: cart_product.product.name.pluralize(cart_product.quantity), - quantity: cart_product.quantity) - end - - redirect_to [marketplace.space, marketplace.room] - end - - format.turbo_stream do - render turbo_stream: [ - turbo_stream.replace(cart_product_component.dom_id, cart_product_component), - turbo_stream.replace("cart-footer-#{cart.id}", - partial: "marketplace/carts/footer", locals: {cart: cart}), - turbo_stream.replace("cart-total-#{cart.id}", partial: "marketplace/carts/total", locals: {cart: cart}) - ] - end + if cart_product.errors.empty? + flash[:notice] = t(".success", + product: cart_product.product.name.pluralize(cart_product.quantity), + quantity: cart_product.quantity) + else + flash[:alert] = t(".failure", + product: cart_product.product.name.pluralize(cart_product.quantity), + quantity: cart_product.quantity) end + + redirect_to marketplace.location end def update authorize(cart_product).update(cart_product_params) - respond_to do |format| - format.html do - if cart_product.errors.empty? - flash[:notice] = - t(".success", product: cart_product.product.name.pluralize(cart_product.quantity), - quantity: cart_product.quantity) - else - flash[:alert] = - t(".failure", product: cart_product.product.name.pluralize(cart_product.quantity), - quantity: cart_product.quantity) - end - - redirect_to [marketplace.space, marketplace.room] - end - format.turbo_stream do - render turbo_stream: [ - turbo_stream.replace(cart_product_component.dom_id, cart_product_component), - turbo_stream.replace("cart-footer-#{cart.id}", - partial: "marketplace/carts/footer", locals: {cart: cart}), - turbo_stream.replace("cart-total-#{cart.id}", partial: "marketplace/carts/total", locals: {cart: cart}) - ] - end + if cart_product.errors.empty? + flash[:notice] = + t(".success", product: cart_product.product.name.pluralize(cart_product.quantity), + quantity: cart_product.quantity) + else + flash[:alert] = + t(".failure", product: cart_product.product.name.pluralize(cart_product.quantity), + quantity: cart_product.quantity) end + + redirect_to marketplace.location end def destroy authorize(cart_product).destroy - respond_to do |format| - format.html do - if cart_product.destroyed? - flash[:notice] = - t(".success", product: cart_product.product.name.pluralize(cart_product.quantity), - quantity: cart_product.quantity) - else - flash[:alert] = - t(".failure", product: cart_product.product.name.pluralize(cart_product.quantity), - quantity: cart_product.quantity) - end - redirect_to [marketplace.space, marketplace.room] - end - format.turbo_stream do - render turbo_stream: [ - turbo_stream.replace(cart_product_component.dom_id, cart_product_component), - turbo_stream.replace("cart-footer-#{cart.id}", - partial: "marketplace/carts/footer", locals: {cart: cart}), - turbo_stream.replace("cart-total-#{cart.id}", partial: "marketplace/carts/total", locals: {cart: cart}) - ] - end + if cart_product.destroyed? + flash[:notice] = + t(".success", product: cart_product.product.name.pluralize(cart_product.quantity), + quantity: cart_product.quantity) + else + flash[:alert] = + t(".failure", product: cart_product.product.name.pluralize(cart_product.quantity), + quantity: cart_product.quantity) end + redirect_to marketplace.location end def cart_product_component diff --git a/app/furniture/marketplace/carts/_cart.html.erb b/app/furniture/marketplace/carts/_cart.html.erb index 3142a710c..6e809ccef 100644 --- a/app/furniture/marketplace/carts/_cart.html.erb +++ b/app/furniture/marketplace/carts/_cart.html.erb @@ -16,8 +16,8 @@ - <%- cart.marketplace.products.unarchived.each do |product| %> - <%= render Marketplace::CartProductComponent.new(cart_product: cart.cart_products.find_or_initialize_by(product: product)) %> + <%- cart.cart_products.each do |cart_product| %> + <%= render Marketplace::CartProductComponent.new(cart_product:) %> <%- end %> <%= render "marketplace/carts/footer", cart: cart %> diff --git a/app/furniture/marketplace/locales/en.yml b/app/furniture/marketplace/locales/en.yml index c98027191..7c0fe553d 100644 --- a/app/furniture/marketplace/locales/en.yml +++ b/app/furniture/marketplace/locales/en.yml @@ -124,9 +124,6 @@ en: update: success: "Changed %{quantity} %{product} on Cart" failure: "Could not change %{quantity} %{product} on Cart" - cart_product_component: - remove: Remove from Cart - add: Add to Cart payment_settings: index: link_to: "Payment Settings" diff --git a/app/furniture/marketplace/marketplace_component.html.erb b/app/furniture/marketplace/marketplace_component.html.erb index 836b9e305..ecdc2adaf 100644 --- a/app/furniture/marketplace/marketplace_component.html.erb +++ b/app/furniture/marketplace/marketplace_component.html.erb @@ -1,5 +1,9 @@
+ + <%= render delivery_area_component %> + <%= render Marketplace::MenuComponent.new(marketplace:, cart:) %> + <%= render cart %>
diff --git a/app/furniture/marketplace/menu/product_component.html.erb b/app/furniture/marketplace/menu/product_component.html.erb new file mode 100644 index 000000000..eafbbcb2d --- /dev/null +++ b/app/furniture/marketplace/menu/product_component.html.erb @@ -0,0 +1,34 @@ +<%= render CardComponent.new(dom_id: dom_id(product)) do |card| %> + <%- card.with_header do %> + <% if product.photo.present? %> +
+ <%= image_tag hero_image, class: "w-full" %> +
+

<%= name %>

+ <%- if product.archived? %> + (archived) + <%- end %> +
+
+ <%- else %> +

<%= name %>

+ <% end %> + <%- end %> +
+ <%= description %> +
+ +
+

<%= price %>

+
+ + <%- card.with_footer do %> + <%- cart_product = cart.cart_products.find_by(product:) %> + + <%- if !cart_product %> + <%= button_to("Add to Cart", cart.location(child: :cart_products), method: :post, params: { cart_product: { product_id: product.id, quantity: 1 } }) %> + <%- else %> + <%= render cart_product.quantity_picker %> + <%- end %> + <%- end %> +<%- end %> diff --git a/app/furniture/marketplace/menu/product_component.rb b/app/furniture/marketplace/menu/product_component.rb new file mode 100644 index 000000000..982f19e34 --- /dev/null +++ b/app/furniture/marketplace/menu/product_component.rb @@ -0,0 +1,9 @@ +class Marketplace + class Menu::ProductComponent < ProductComponent + attr_accessor :cart + def initialize(product:, cart:, **kwargs) + super(product:, **kwargs) + self.cart = cart + end + end +end diff --git a/app/furniture/marketplace/menu_component.html.erb b/app/furniture/marketplace/menu_component.html.erb new file mode 100644 index 000000000..0973effae --- /dev/null +++ b/app/furniture/marketplace/menu_component.html.erb @@ -0,0 +1,5 @@ +
+ <%- marketplace.products.unarchived.each do |product| %> + <%= render Marketplace::Menu::ProductComponent.new(product:, cart:)%> + <%- end %> +
diff --git a/app/furniture/marketplace/menu_component.rb b/app/furniture/marketplace/menu_component.rb new file mode 100644 index 000000000..7b913ad89 --- /dev/null +++ b/app/furniture/marketplace/menu_component.rb @@ -0,0 +1,11 @@ +class Marketplace + class MenuComponent < ApplicationComponent + attr_accessor :marketplace, :cart + + def initialize(marketplace:, cart:, **kwargs) + super(**kwargs) + self.marketplace = marketplace + self.cart = cart + end + end +end diff --git a/app/furniture/marketplace/products/show.html.erb b/app/furniture/marketplace/products/show.html.erb new file mode 100644 index 000000000..a3c9a4754 --- /dev/null +++ b/app/furniture/marketplace/products/show.html.erb @@ -0,0 +1,3 @@ +<%- breadcrumb :marketplace_product, product %> +

<%= product.name %>

+

<%= product.description %>

diff --git a/app/furniture/marketplace/products_controller.rb b/app/furniture/marketplace/products_controller.rb index 23f60846c..bb03cd64a 100644 --- a/app/furniture/marketplace/products_controller.rb +++ b/app/furniture/marketplace/products_controller.rb @@ -31,6 +31,10 @@ def index skip_authorization end + def show + authorize(product) + end + def edit authorize(product) end diff --git a/spec/furniture/marketplace/buying_products_system_spec.rb b/spec/furniture/marketplace/buying_products_system_spec.rb index 2ac660d73..c809259c7 100644 --- a/spec/furniture/marketplace/buying_products_system_spec.rb +++ b/spec/furniture/marketplace/buying_products_system_spec.rb @@ -96,8 +96,8 @@ def url_options end def add_product_to_cart(product) - within("##{dom_id(product).gsub("product", "cart_product")}") do - click_link(t("marketplace.cart_product_component.add")) + within("##{dom_id(product)}") do + click_button("Add to Cart") end end diff --git a/spec/furniture/marketplace/cart_product_component_spec.rb b/spec/furniture/marketplace/cart_product_component_spec.rb index a98bb4195..8d17a2cdb 100644 --- a/spec/furniture/marketplace/cart_product_component_spec.rb +++ b/spec/furniture/marketplace/cart_product_component_spec.rb @@ -8,20 +8,27 @@ let(:cart) { create(:marketplace_cart) } let(:marketplace) { cart.marketplace } let(:product) { create(:marketplace_product, :with_description, :with_photo) } - let(:cart_product) { create(:marketplace_cart_product, cart: cart, product: product) } + let(:cart_product) { create(:marketplace_cart_product, cart:, product:, quantity: 5) } let(:component) { described_class.new(cart_product: cart_product, current_person: operator) } it { is_expected.to have_content(product.name) } it { is_expected.to have_content(product.description) } it { is_expected.to have_content(helpers.humanized_money_with_symbol(product.price)) } - it { is_expected.to have_link(I18n.t("marketplace.cart_product_component.add")) } - it { is_expected.to have_link(I18n.t("marketplace.cart_product_component.remove")) } - it { is_expected.to have_css("img[src*='#{product.photo.filename}']") } + it { is_expected.to have_button("➕") } + it { is_expected.to have_button("➖") } - context "when the product is not yet in the cart" do - let(:cart_product) { build(:marketplace_cart_product, cart: cart, product: product, quantity: 0) } + context "when the quantity is 0" do + let(:cart_product) { build(:marketplace_cart_product, cart:, product:, quantity: 0) } - it { is_expected.to have_no_link(I18n.t("marketplace.cart_product_component.remove")) } + it { is_expected.to have_no_button("➖") } + it { is_expected.to have_button("➕") } + end + + context "when the quantity is 1" do + let(:cart_product) { build(:marketplace_cart_product, cart:, product:, quantity: 1) } + + it { is_expected.to have_button("➕") } + it { is_expected.to have_button("🗑️") } end end diff --git a/spec/furniture/marketplace/cart_products_controller_request_spec.rb b/spec/furniture/marketplace/cart_products_controller_request_spec.rb index 99bbdebd2..390c4bc12 100644 --- a/spec/furniture/marketplace/cart_products_controller_request_spec.rb +++ b/spec/furniture/marketplace/cart_products_controller_request_spec.rb @@ -20,30 +20,7 @@ it "Add a Product to the Cart" do perform_request - expect(response).to redirect_to([space, room]) - end - - context "when a turbo stream" do - subject(:perform_request) do - post path, as: :turbo_stream, params: {cart_product: {product_id: product.id, quantity: 1}} - response - end - - it "Replaces the cart product, cart footer and cart total" do - perform_request && cart.reload - - assert_select("turbo-stream[action='replace'][target='cart_product_#{product.id}']") do - assert_select("*[data-cart-product-quantity]", text: "1") - end - - assert_select("turbo-stream[action='replace'][target='cart-footer-#{cart.id}']") - assert_select("turbo-stream[action='replace'][target='cart-total-#{cart.id}'] *[data-cart-total]", text: "Total: #{controller.helpers.humanized_money_with_symbol(cart.price_total)}") - - assert_select("turbo-stream[action='replace'][target='cart-total-#{cart.id}']") do - assert_select("*[data-cart-total]", text: "Total: #{controller.helpers.humanized_money_with_symbol(cart.price_total)}") - assert_select("*[data-cart-product-total]", text: "Products: #{controller.helpers.humanized_money_with_symbol(cart.product_total)}") - end - end + expect(response).to redirect_to(marketplace.location) end end @@ -62,29 +39,7 @@ perform_request cart_product.reload expect(cart_product.quantity).to eq(5) - expect(response).to redirect_to([space, room]) - end - - context "when a turbo stream" do - subject(:perform_request) do - put path, as: :turbo_stream, params: params - end - - it "Replaces the cart product, cart footer and cart total" do - perform_request && cart.reload - - assert_select("turbo-stream[action='replace'][target='cart_product_#{product.id}']") do - assert_select("*[data-cart-product-quantity]", text: "5") - end - - assert_select("turbo-stream[action='replace'][target='cart-footer-#{cart.id}']") - assert_select("turbo-stream[action='replace'][target='cart-total-#{cart.id}'] *[data-cart-total]", text: "Total: #{controller.helpers.humanized_money_with_symbol(cart.price_total)}") - - assert_select("turbo-stream[action='replace'][target='cart-total-#{cart.id}']") do - assert_select("*[data-cart-total]", text: "Total: #{controller.helpers.humanized_money_with_symbol(cart.price_total)}") - assert_select("*[data-cart-product-total]", text: "Products: #{controller.helpers.humanized_money_with_symbol(cart.product_total)}") - end - end + expect(response).to redirect_to(marketplace.location) end end @@ -99,30 +54,7 @@ let(:product) { create(:marketplace_product, marketplace: marketplace) } let(:cart_product) { create(:marketplace_cart_product, cart: cart, product: product) } - it { is_expected.to redirect_to([space, room]) } + it { is_expected.to redirect_to(marketplace.location) } specify { expect { perform_request }.to change { Marketplace::CartProduct.exists?(cart_product.id) }.to(false) } - - context "when a turbo stream" do - subject(:perform_request) do - delete path, as: :turbo_stream - response - end - - it "Replaces the cart product, cart footer and cart total" do - perform_request - - assert_select("turbo-stream[action='replace'][target='cart_product_#{cart_product.product_id}']") do - assert_select("*[data-cart-product-quantity]", text: "0") - end - - assert_select("turbo-stream[action='replace'][target='cart-footer-#{cart.id}']") - assert_select("turbo-stream[action='replace'][target='cart-total-#{cart.id}'] *[data-cart-total]", text: "Total: $0.00") - - assert_select("turbo-stream[action='replace'][target='cart-total-#{cart.id}']") do - assert_select("*[data-cart-total]", text: "Total: $0.00") - assert_select("*[data-cart-product-total]", text: "Products: $0.00") - end - end - end end end