From 97ff810154f86e7d6e87124509cdd54be478764c Mon Sep 17 00:00:00 2001
From: Zee Spencer <50284+zspencer@users.noreply.github.com>
Date: Wed, 14 Jun 2023 18:33:10 -0700
Subject: [PATCH] =?UTF-8?q?=F0=9F=A5=94=E2=9C=A8=20`Marketplace`:=20UI=20t?=
=?UTF-8?q?o=20manage=20`OrderNotificationMethod`?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- https://github.com/zinc-collective/convene/issues/1511
🧹 `Marketplace`: Move into `Order::NotificationMethod` (#1564)
The top-level `marketplace` namespace is getting pretty cluttered, and
since this relates pretty squarely to the `Order` domain, and there is
already an `Order::PlacedMailer` and `Order::ReceivedMailer` it seemed
like a reasonable place to put it.
🥗 Request specs for `Order::NotificationMethods`
---
app/furniture/marketplace/breadcrumbs.rb | 17 ++++
app/furniture/marketplace/locales/en.yml | 14 +++
.../marketplace/management_component.html.erb | 8 ++
app/furniture/marketplace/marketplace.rb | 2 +-
.../marketplace/marketplaces/_form.html.erb | 7 --
.../marketplace/marketplaces/edit.html.erb | 1 -
.../notification_method.rb} | 2 +-
.../notification_method_component.html.erb | 11 +++
.../order/notification_method_component.rb | 38 ++++++++
.../order/notification_method_policy.rb | 17 ++++
.../order/notification_methods/_form.html.erb | 6 ++
.../order/notification_methods/edit.html.erb | 2 +
.../order/notification_methods/index.html.erb | 23 +++++
.../order/notification_methods/new.html.erb | 2 +
.../order/notification_methods_controller.rb | 55 ++++++++++++
app/furniture/marketplace/routes.rb | 2 +
app/views/application/_email_field.html.erb | 2 +-
spec/factories/furniture/marketplace.rb | 5 ++
.../notification_method_spec.rb} | 2 +-
...ication_methods_controller_request_spec.rb | 87 +++++++++++++++++++
20 files changed, 291 insertions(+), 12 deletions(-)
delete mode 100644 app/furniture/marketplace/marketplaces/_form.html.erb
rename app/furniture/marketplace/{order_notification_method.rb => order/notification_method.rb} (87%)
create mode 100644 app/furniture/marketplace/order/notification_method_component.html.erb
create mode 100644 app/furniture/marketplace/order/notification_method_component.rb
create mode 100644 app/furniture/marketplace/order/notification_method_policy.rb
create mode 100644 app/furniture/marketplace/order/notification_methods/_form.html.erb
create mode 100644 app/furniture/marketplace/order/notification_methods/edit.html.erb
create mode 100644 app/furniture/marketplace/order/notification_methods/index.html.erb
create mode 100644 app/furniture/marketplace/order/notification_methods/new.html.erb
create mode 100644 app/furniture/marketplace/order/notification_methods_controller.rb
rename spec/furniture/marketplace/{order_notification_method_spec.rb => order/notification_method_spec.rb} (62%)
create mode 100644 spec/furniture/marketplace/order/notification_methods_controller_request_spec.rb
diff --git a/app/furniture/marketplace/breadcrumbs.rb b/app/furniture/marketplace/breadcrumbs.rb
index d5472a309..74c21e21f 100644
--- a/app/furniture/marketplace/breadcrumbs.rb
+++ b/app/furniture/marketplace/breadcrumbs.rb
@@ -27,6 +27,23 @@
link t("marketplace.orders.index.link_to"), marketplace.location(child: :orders)
end
+crumb :marketplace_order_notification_methods do |marketplace|
+ parent :edit_marketplace, marketplace
+ link t("marketplace.order.notification_methods.index.link_to"), marketplace.location(child: :order_notification_methods)
+end
+
+crumb :new_marketplace_order_notification_method do |order_notification_method|
+ parent :marketplace_order_notification_methods, order_notification_method.marketplace
+ link t("marketplace.order.notification_methods.index.link_to"),
+ order_notification_method.marketplace.location(child: :order_notification_methods)
+end
+
+crumb :edit_marketplace_order_notification_method do |order_notification_method|
+ parent :marketplace_order_notification_methods, order_notification_method.marketplace
+ link t("marketplace.order.notification_methods.edit.link_to", contact_location: order_notification_method.contact_location)
+ order_notification_method.marketplace.location(child: :order_notification_methods)
+end
+
crumb :marketplace_products do |marketplace|
parent :edit_marketplace, marketplace
link t("marketplace.products.index.link_to"), marketplace.location(child: :products)
diff --git a/app/furniture/marketplace/locales/en.yml b/app/furniture/marketplace/locales/en.yml
index 31b2631f1..0137ba428 100644
--- a/app/furniture/marketplace/locales/en.yml
+++ b/app/furniture/marketplace/locales/en.yml
@@ -1,6 +1,9 @@
en:
activerecord:
+ attributes:
+ marketplace/order/notification_method:
+ contact_location: "Email Address"
errors:
models:
marketplace/delivery:
@@ -57,6 +60,17 @@ en:
notification:
subject: "Order Received for %{marketplace_name}: %{order_id}"
placed_at: "Received At %{placed_at}"
+ notification_methods:
+ new:
+ link_to: "Add Order Notification"
+ index:
+ link_to: "Order Notifications"
+ edit:
+ link_to: "Edit Order Notification '%{contact_location}'"
+ update:
+ success: "Order Notification '%{contact_location}' Saved!"
+ destroy:
+ success: "Order Notification to '%{contact_location}' Removed!"
orders:
index:
link_to: "Order History"
diff --git a/app/furniture/marketplace/management_component.html.erb b/app/furniture/marketplace/management_component.html.erb
index fac21c4a6..5e1732aa9 100644
--- a/app/furniture/marketplace/management_component.html.erb
+++ b/app/furniture/marketplace/management_component.html.erb
@@ -45,6 +45,14 @@
href: marketplace.location(child: :orders),
turbo_stream: false, method: :get, scheme: :secondary
) if policy(marketplace.orders).index? %>
+
+
+ <%= render ButtonComponent.new(
+ label: t("marketplace.order.notification_methods.index.link_to"),
+ icon: :bell,
+ href: marketplace.location(child: :order_notification_methods),
+ method: :get, turbo_stream: false, scheme: :secondary
+ ) if policy(marketplace.order_notification_methods).index? %>
<% end %>
<% end %>
diff --git a/app/furniture/marketplace/marketplace.rb b/app/furniture/marketplace/marketplace.rb
index 9891838ff..850ac73fd 100644
--- a/app/furniture/marketplace/marketplace.rb
+++ b/app/furniture/marketplace/marketplace.rb
@@ -15,7 +15,7 @@ class Marketplace < Furniture
has_many :delivery_areas, inverse_of: :marketplace, dependent: :destroy
- has_many :order_notification_methods, inverse_of: :marketplace, dependent: :destroy
+ has_many :order_notification_methods, inverse_of: :marketplace, dependent: :destroy, class_name: "Order::NotificationMethod"
setting :notify_emails
setting :stripe_account
diff --git a/app/furniture/marketplace/marketplaces/_form.html.erb b/app/furniture/marketplace/marketplaces/_form.html.erb
deleted file mode 100644
index 0ae9d9546..000000000
--- a/app/furniture/marketplace/marketplaces/_form.html.erb
+++ /dev/null
@@ -1,7 +0,0 @@
-
- <%= form_with model: marketplace.location do |f| %>
- <%= render "text_field", { attribute: :notify_emails, form: f } %>
-
- <%= f.submit %>
- <% end %>
-
diff --git a/app/furniture/marketplace/marketplaces/edit.html.erb b/app/furniture/marketplace/marketplaces/edit.html.erb
index c5a4fe856..3fb84e232 100644
--- a/app/furniture/marketplace/marketplaces/edit.html.erb
+++ b/app/furniture/marketplace/marketplaces/edit.html.erb
@@ -1,7 +1,6 @@
<%- breadcrumb :edit_marketplace, marketplace %>
<%= render Marketplace::ManagementComponent.new(marketplace: marketplace) do %>
- <%= render "form", marketplace: marketplace %>
<%- if marketplace.stripe_api_key? %>
<%- if marketplace.stripe_account_connected? %>
diff --git a/app/furniture/marketplace/order_notification_method.rb b/app/furniture/marketplace/order/notification_method.rb
similarity index 87%
rename from app/furniture/marketplace/order_notification_method.rb
rename to app/furniture/marketplace/order/notification_method.rb
index dd5fe3fa3..4f75f8e64 100644
--- a/app/furniture/marketplace/order_notification_method.rb
+++ b/app/furniture/marketplace/order/notification_method.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
class Marketplace
- class OrderNotificationMethod < Record
+ class Order::NotificationMethod < Record
self.table_name = :marketplace_order_notification_methods
location(parent: :marketplace)
belongs_to :marketplace, inverse_of: :order_notification_methods
diff --git a/app/furniture/marketplace/order/notification_method_component.html.erb b/app/furniture/marketplace/order/notification_method_component.html.erb
new file mode 100644
index 000000000..87d94587d
--- /dev/null
+++ b/app/furniture/marketplace/order/notification_method_component.html.erb
@@ -0,0 +1,11 @@
+<%= render CardComponent.new(dom_id: dom_id(notification_method), classes: "flex flex-col justify-between gap-y-2 w-full") do %>
+
+
+ <%= contact_location %>
+
+
+
+<%- end %>
diff --git a/app/furniture/marketplace/order/notification_method_component.rb b/app/furniture/marketplace/order/notification_method_component.rb
new file mode 100644
index 000000000..919d9df56
--- /dev/null
+++ b/app/furniture/marketplace/order/notification_method_component.rb
@@ -0,0 +1,38 @@
+class Marketplace
+ class Order
+ class NotificationMethodComponent < ApplicationComponent
+ attr_accessor :notification_method
+ delegate :contact_location, to: :notification_method
+
+ def initialize(notification_method:, **kwargs)
+ super(**kwargs)
+
+ self.notification_method = notification_method
+ end
+
+ def edit_button
+ super(title: t("marketplace.order.notification_methods.edit.link_to", contact_location: contact_location),
+ href: notification_method.location(:edit))
+ end
+
+ def edit_button?
+ notification_method.persisted? && policy(notification_method).edit?
+ end
+
+ def destroy_button
+ return unless destroy_button?
+
+ ButtonComponent.new(label: "#{t("icons.destroy")} #{t("destroy.link_to")}",
+ title: t("marketplace.order.notification_methods.destroy.link_to", contact_location: contact_location),
+ href: notification_method.location, turbo_stream: true,
+ method: :delete,
+ confirm: t("destroy.confirm"),
+ scheme: :secondary)
+ end
+
+ def destroy_button?
+ notification_method.persisted? && policy(notification_method).destroy?
+ end
+ end
+ end
+end
diff --git a/app/furniture/marketplace/order/notification_method_policy.rb b/app/furniture/marketplace/order/notification_method_policy.rb
new file mode 100644
index 000000000..c43bf1e02
--- /dev/null
+++ b/app/furniture/marketplace/order/notification_method_policy.rb
@@ -0,0 +1,17 @@
+class Marketplace
+ class Order
+ class NotificationMethodPolicy < Policy
+ def permitted_attributes(_)
+ [:contact_location]
+ end
+
+ class Scope < ApplicationScope
+ def resolve
+ return scope.all if person.operator?
+
+ scope.joins(marketplace: [:room]).where(rooms: {space_id: person.spaces})
+ end
+ end
+ end
+ end
+end
diff --git a/app/furniture/marketplace/order/notification_methods/_form.html.erb b/app/furniture/marketplace/order/notification_methods/_form.html.erb
new file mode 100644
index 000000000..9bed31552
--- /dev/null
+++ b/app/furniture/marketplace/order/notification_methods/_form.html.erb
@@ -0,0 +1,6 @@
+<%= form_with(model: order_notification_method.location) do |form| %>
+
+<%= render "email_field", attribute: :contact_location, form: form %>
+<%= form.submit %>
+
+<%- end %>
diff --git a/app/furniture/marketplace/order/notification_methods/edit.html.erb b/app/furniture/marketplace/order/notification_methods/edit.html.erb
new file mode 100644
index 000000000..d2e84a7e5
--- /dev/null
+++ b/app/furniture/marketplace/order/notification_methods/edit.html.erb
@@ -0,0 +1,2 @@
+<%- breadcrumb :edit_marketplace_order_notification_method, order_notification_method %>
+<%= render "form", order_notification_method: order_notification_method %>
diff --git a/app/furniture/marketplace/order/notification_methods/index.html.erb b/app/furniture/marketplace/order/notification_methods/index.html.erb
new file mode 100644
index 000000000..c687545ef
--- /dev/null
+++ b/app/furniture/marketplace/order/notification_methods/index.html.erb
@@ -0,0 +1,23 @@
+<%- breadcrumb(:marketplace_order_notification_methods, marketplace) %>
+
+<%= render Marketplace::ManagementComponent.new(marketplace: marketplace) do %>
+
+
+
+ <%= render Marketplace::Order::NotificationMethodComponent.with_collection(order_notification_methods) %>
+
+
+
+
+ <%- order_notification_methods = marketplace.order_notification_methods.new %>
+ <%- if policy(order_notification_methods).create? %>
+ <%= render ButtonComponent.new(
+ label: "#{t('marketplace.order.notification_methods.new.link_to')} #{t('icons.new')}",
+ title: t('marketplace.order.notification_methods.new.link_to'),
+ href: marketplace.location(:new, child: :order_notification_method),
+ method: :get,
+ scheme: :secondary) %>
+ <%- end %>
+
+
+<% end %>
diff --git a/app/furniture/marketplace/order/notification_methods/new.html.erb b/app/furniture/marketplace/order/notification_methods/new.html.erb
new file mode 100644
index 000000000..b54ec183a
--- /dev/null
+++ b/app/furniture/marketplace/order/notification_methods/new.html.erb
@@ -0,0 +1,2 @@
+<%- breadcrumb :new_marketplace_order_notification_method, order_notification_method %>
+<%= render "form", order_notification_method: order_notification_method %>
diff --git a/app/furniture/marketplace/order/notification_methods_controller.rb b/app/furniture/marketplace/order/notification_methods_controller.rb
new file mode 100644
index 000000000..38683bbd9
--- /dev/null
+++ b/app/furniture/marketplace/order/notification_methods_controller.rb
@@ -0,0 +1,55 @@
+class Marketplace
+ class Order
+ class NotificationMethodsController < Controller
+ def new
+ order_notification_method
+ end
+
+ def edit
+ order_notification_method
+ end
+
+ def update
+ if order_notification_method.update(order_notification_method_params)
+ redirect_to marketplace.location(child: :order_notification_methods), notice: t(".success", contact_location: order_notification_method.contact_location)
+ else
+ render :edit, status: :unprocessable_entity
+ end
+ end
+
+ def create
+ if order_notification_method.save
+ redirect_to marketplace.location(child: :order_notification_methods)
+ else
+ render :new, status: :unprocessable_entity
+ end
+ end
+
+ def destroy
+ order_notification_method.destroy
+
+ redirect_to marketplace.location(child: :order_notification_methods), notice: t(".success", contact_location: order_notification_method.contact_location)
+ end
+
+ helper_method def order_notification_methods
+ @order_notification_methods ||= marketplace.order_notification_methods
+ end
+
+ helper_method def order_notification_method
+ @order_notification_method ||= if params[:id]
+ order_notification_methods.find(params[:id])
+ elsif params[:order_notification_method]
+ order_notification_methods.new(order_notification_method_params)
+ else
+ order_notification_methods.new
+ end.tap do |order_notification_method|
+ authorize(order_notification_method)
+ end
+ end
+
+ def order_notification_method_params
+ policy(NotificationMethod).permit(params.require(:order_notification_method))
+ end
+ end
+ end
+end
diff --git a/app/furniture/marketplace/routes.rb b/app/furniture/marketplace/routes.rb
index ee3a0d55f..32b10f393 100644
--- a/app/furniture/marketplace/routes.rb
+++ b/app/furniture/marketplace/routes.rb
@@ -4,6 +4,8 @@ def self.append_routes(router)
router.resources :marketplaces, only: [:show, :edit, :update], module: "marketplace" do
router.resources :stripe_events
+ router.resources :order_notification_methods, controller: "order/notification_methods"
+
router.resources :carts, only: [] do
router.resources :cart_products
router.resource :checkout, only: [:show, :create]
diff --git a/app/views/application/_email_field.html.erb b/app/views/application/_email_field.html.erb
index 94e5f836f..8d8b5b80a 100644
--- a/app/views/application/_email_field.html.erb
+++ b/app/views/application/_email_field.html.erb
@@ -2,4 +2,4 @@
<%= form.label attribute %>
<%= form.email_field attribute %>
<%= render partial: "error", locals: { model: form.object, attribute: attribute } %>
-
\ No newline at end of file
+
diff --git a/spec/factories/furniture/marketplace.rb b/spec/factories/furniture/marketplace.rb
index 93bba0ed2..5f3d7d31d 100644
--- a/spec/factories/furniture/marketplace.rb
+++ b/spec/factories/furniture/marketplace.rb
@@ -111,6 +111,11 @@
cart { association(:marketplace_cart, marketplace: marketplace) }
end
+ factory :marketplace_order_notification_method, class: "Marketplace::Order::NotificationMethod" do
+ marketplace
+ contact_location { Faker::Internet.email }
+ end
+
factory :marketplace_order, class: "Marketplace::Order" do
marketplace
shopper { association(:marketplace_shopper) }
diff --git a/spec/furniture/marketplace/order_notification_method_spec.rb b/spec/furniture/marketplace/order/notification_method_spec.rb
similarity index 62%
rename from spec/furniture/marketplace/order_notification_method_spec.rb
rename to spec/furniture/marketplace/order/notification_method_spec.rb
index bc7a720cd..757706ab2 100644
--- a/spec/furniture/marketplace/order_notification_method_spec.rb
+++ b/spec/furniture/marketplace/order/notification_method_spec.rb
@@ -1,5 +1,5 @@
require "rails_helper"
-RSpec.describe Marketplace::OrderNotificationMethod, type: :model do
+RSpec.describe Marketplace::Order::NotificationMethod, type: :model do
it { is_expected.to belong_to(:marketplace).inverse_of(:order_notification_methods) }
end
diff --git a/spec/furniture/marketplace/order/notification_methods_controller_request_spec.rb b/spec/furniture/marketplace/order/notification_methods_controller_request_spec.rb
new file mode 100644
index 000000000..a96d8bdd8
--- /dev/null
+++ b/spec/furniture/marketplace/order/notification_methods_controller_request_spec.rb
@@ -0,0 +1,87 @@
+require "rails_helper"
+
+RSpec.describe Marketplace::Order::NotificationMethodsController, type: :request do
+ let(:marketplace) { create(:marketplace) }
+ let(:space) { marketplace.space }
+ let(:room) { marketplace.room }
+ let(:member) { create(:membership, space: space).member }
+ let(:order_notification_method) { create(:marketplace_order_notification_method, marketplace: marketplace) }
+
+ before do
+ sign_in(space, member)
+ end
+
+ describe "#new" do
+ subject(:perform_request) do
+ get polymorphic_path(marketplace.location(:new, child: :order_notification_method))
+ response
+ end
+
+ it { is_expected.to have_rendered(:new) }
+ end
+
+ describe "#create" do
+ subject(:perform_request) do
+ post polymorphic_path(marketplace.location(child: :order_notification_methods)),
+ params: {order_notification_method: order_notification_method_attributes}
+ response
+ end
+
+ let(:order_notification_method_attributes) { attributes_for(:marketplace_order_notification_method) }
+
+ specify { expect { perform_request }.to change(marketplace.order_notification_methods, :count).by(1) }
+
+ describe "the created order notification" do
+ let(:created_order_notification_method) { marketplace.order_notification_methods.last }
+
+ before { perform_request }
+
+ specify { expect(created_order_notification_method.contact_method).to eql("email") }
+ specify { expect(created_order_notification_method.contact_location).to eql(order_notification_method_attributes[:contact_location]) }
+ end
+
+ describe "when request is invalid" do
+ let(:order_notification_method_attributes) { {} }
+
+ it { is_expected.to have_rendered(:new) }
+ end
+ end
+
+ describe "#edit" do
+ subject(:perform_request) do
+ get polymorphic_path(order_notification_method.location(:edit))
+ response
+ end
+
+ it { is_expected.to have_rendered(:edit) }
+ end
+
+ describe "#update" do
+ subject(:perform_request) do
+ put polymorphic_path(order_notification_method.location),
+ params: {order_notification_method: order_notification_method_attributes}
+ order_notification_method.reload
+ response
+ end
+
+ let(:order_notification_method_attributes) { attributes_for(:marketplace_order_notification_method) }
+
+ specify { expect { perform_request }.to change(order_notification_method, :contact_location).to order_notification_method_attributes[:contact_location] }
+
+ it { is_expected.to redirect_to(polymorphic_path(marketplace.location(child: :order_notification_methods))) }
+ end
+
+ describe "#destroy" do
+ subject(:perform_request) do
+ delete polymorphic_path(order_notification_method.location)
+
+ response
+ end
+
+ it "destroys the NotificationMethod" do
+ expect { perform_request && order_notification_method.reload }.to(raise_error(ActiveRecord::RecordNotFound))
+ end
+
+ it { is_expected.to redirect_to(polymorphic_path(marketplace.location(child: :order_notification_methods))) }
+ end
+end