Skip to content

Commit

Permalink
🌸 Marketplace: Distinguish the Cart from the Menu
Browse files Browse the repository at this point in the history
- #2043
- #1326

While we definitely need a `Cart`; treating the `Cart` as the `Menu` is
a clunky ducky way of operating.
  • Loading branch information
zspencer committed Jan 21, 2024
1 parent 1ca919b commit 8d0723e
Show file tree
Hide file tree
Showing 18 changed files with 147 additions and 201 deletions.
4 changes: 4 additions & 0 deletions app/furniture/marketplace/cart_product.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ def price_total
product.price * quantity
end

def quantity_picker
QuantityPicker.new(cart_product: self)
end

private

def editable_cart
Expand Down
6 changes: 6 additions & 0 deletions app/furniture/marketplace/cart_product/quantity_picker.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
class Marketplace
class CartProduct::QuantityPicker < Model
attr_accessor :cart_product
delegate :location, :quantity, to: :cart_product
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<div class="flex flex-row justify-between items-center">
<%- if quantity_picker.quantity < 1%>
<span></span>
<%- 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 %>

<span class="py-2 px-2 my-1 text-lg"><%= quantity_picker.quantity %></span>

<%= button_to("➕", quantity_picker.location, method: :put, params: { cart_product: { quantity: quantity_picker.quantity + 1 } }) %>
</div>
22 changes: 2 additions & 20 deletions app/furniture/marketplace/cart_product_component.html.erb
Original file line number Diff line number Diff line change
@@ -1,16 +1,7 @@
<tr id="<%= dom_id %>">
<td class="w-full max-w-0 py-4 pl-4 pr-3 text-sm font-medium text-gray-900 sm:w-auto sm:max-w-none sm:pl-6">
<%- if product.photo.present? %>
<figure class="w-40 text-center relative">
<%= image_tag product.photo.variant(resize_to_limit: [150, 150]).processed.url, class: "mx-auto h-40 overflow-hidden object-center rounded-lg"
%>
<figcaption class="mt-2">
<%=product.name%>
</figcaption>
</figure>
<%- else %>

<%= product.name %>
<%- end %>

<dl class="font-normal lg:hidden">
<dt class="sr-only"><%= product.class.human_attribute_name(:price) %></dt>
Expand All @@ -27,15 +18,6 @@
<%= humanized_money_with_symbol(product.price) %>
</td>
<td class="py-4 pl-3 pr-4 text-right text-sm font-medium sm:pr-6">
<div class="flex flex-row justify-between items-center">
<%= render "buttons/minus", title: t('marketplace.cart_product_component.remove'), method: remove_method,
disabled: cart_product.quantity.zero?,
href: remove_href %>

<span data-cart-product-quantity class="py-2 px-2 my-1 text-lg"><%= quantity %></span>

<%= render "buttons/plus", method: add_method, title: t('marketplace.cart_product_component.add'),
href: add_href %>
</div>
<%= render cart_product.quantity_picker %>
</td>
</tr>
32 changes: 2 additions & 30 deletions app/furniture/marketplace/cart_product_component.rb
Original file line number Diff line number Diff line change
@@ -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)
Expand All @@ -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
95 changes: 29 additions & 66 deletions app/furniture/marketplace/cart_products_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions app/furniture/marketplace/carts/_cart.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
</tr>
</thead>
<tbody class="divide-y divide-gray-200 bg-white">
<%- 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 %>
</tbody>
<%= render "marketplace/carts/footer", cart: cart %>
Expand Down
3 changes: 0 additions & 3 deletions app/furniture/marketplace/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
4 changes: 4 additions & 0 deletions app/furniture/marketplace/marketplace_component.html.erb
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
<div class="grid grid-cols-1 gap-6">


<%= render delivery_area_component %>
<%= render Marketplace::MenuComponent.new(marketplace:, cart:) %>
<%= render cart %>
</div>
34 changes: 34 additions & 0 deletions app/furniture/marketplace/menu/product_component.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<%= render CardComponent.new(dom_id: dom_id(product)) do |card| %>
<%- card.with_header do %>
<% if product.photo.present? %>
<figure>
<%= image_tag hero_image, class: "w-full" %>
<figcaption class="px-4">
<h3><%= name %></h3>
<%- if product.archived? %>
<span class="italic">(archived)</span>
<%- end %>
</figcaption>
</figure>
<%- else %>
<h3 class="px-4"><%= name %></h3>
<% end %>
<%- end %>
<div class="text-sm italic">
<%= description %>
</div>

<div class="text-right mt-3">
<p><%= price %></p>
</div>

<%- 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 %>
9 changes: 9 additions & 0 deletions app/furniture/marketplace/menu/product_component.rb
Original file line number Diff line number Diff line change
@@ -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
5 changes: 5 additions & 0 deletions app/furniture/marketplace/menu_component.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<div class="grid sm:grid-cols-2 lg:grid-cols-3 gap-3">
<%- marketplace.products.unarchived.each do |product| %>
<%= render Marketplace::Menu::ProductComponent.new(product:, cart:)%>
<%- end %>
</div>
11 changes: 11 additions & 0 deletions app/furniture/marketplace/menu_component.rb
Original file line number Diff line number Diff line change
@@ -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
3 changes: 3 additions & 0 deletions app/furniture/marketplace/products/show.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<%- breadcrumb :marketplace_product, product %>
<h3><%= product.name %></h3>
<p><%= product.description %></p>
4 changes: 4 additions & 0 deletions app/furniture/marketplace/products_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ def index
skip_authorization
end

def show
authorize(product)
end

def edit
authorize(product)
end
Expand Down
4 changes: 2 additions & 2 deletions spec/furniture/marketplace/buying_products_system_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
21 changes: 14 additions & 7 deletions spec/furniture/marketplace/cart_product_component_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Loading

0 comments on commit 8d0723e

Please sign in to comment.