Skip to content

Commit

Permalink
🥔✨ Marketplace: UI to manage OrderNotificationMethod
Browse files Browse the repository at this point in the history
- #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`
  • Loading branch information
zspencer committed Jun 29, 2023
1 parent d425c08 commit 621b907
Show file tree
Hide file tree
Showing 20 changed files with 291 additions and 12 deletions.
17 changes: 17 additions & 0 deletions app/furniture/marketplace/breadcrumbs.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
14 changes: 14 additions & 0 deletions app/furniture/marketplace/locales/en.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@

en:
activerecord:
attributes:
marketplace/order/notification_method:
contact_location: "Email Address"
errors:
models:
marketplace/delivery:
Expand Down Expand Up @@ -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"
Expand Down
8 changes: 8 additions & 0 deletions app/furniture/marketplace/management_component.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -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? %>
</nav>
<% end %>
<% end %>
2 changes: 1 addition & 1 deletion app/furniture/marketplace/marketplace.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
7 changes: 0 additions & 7 deletions app/furniture/marketplace/marketplaces/_form.html.erb

This file was deleted.

1 change: 0 additions & 1 deletion app/furniture/marketplace/marketplaces/edit.html.erb
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
<%- breadcrumb :edit_marketplace, marketplace %>
<%= render Marketplace::ManagementComponent.new(marketplace: marketplace) do %>
<%= render "form", marketplace: marketplace %>
<p class="flex justify-between my-5 flex-wrap">
<%- if marketplace.stripe_api_key? %>
<%- if marketplace.stripe_account_connected? %>
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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 %>

<div class="font-bold">
<%= contact_location %>
</div>

<footer class="mt-3 flex flex-row justify-between">
<%= render edit_button if edit_button? %>
<%= render destroy_button if destroy_button? %>
</footer>
<%- end %>
38 changes: 38 additions & 0 deletions app/furniture/marketplace/order/notification_method_component.rb
Original file line number Diff line number Diff line change
@@ -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
17 changes: 17 additions & 0 deletions app/furniture/marketplace/order/notification_method_policy.rb
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<%= form_with(model: order_notification_method.location) do |form| %>
<%= render "email_field", attribute: :contact_location, form: form %>
<%= form.submit %>
<%- end %>
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<%- breadcrumb :edit_marketplace_order_notification_method, order_notification_method %>
<%= render "form", order_notification_method: order_notification_method %>
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<%- breadcrumb(:marketplace_order_notification_methods, marketplace) %>
<%= render Marketplace::ManagementComponent.new(marketplace: marketplace) do %>
<section class="mt-3">
<main>

<%= render Marketplace::Order::NotificationMethodComponent.with_collection(order_notification_methods) %>

</main>

<div class="text-center mt-3">
<%- 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 %>
</div>
</section>
<% end %>
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<%- breadcrumb :new_marketplace_order_notification_method, order_notification_method %>
<%= render "form", order_notification_method: order_notification_method %>
55 changes: 55 additions & 0 deletions app/furniture/marketplace/order/notification_methods_controller.rb
Original file line number Diff line number Diff line change
@@ -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
2 changes: 2 additions & 0 deletions app/furniture/marketplace/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
2 changes: 1 addition & 1 deletion app/views/application/_email_field.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
<%= form.label attribute %>
<%= form.email_field attribute %>
<%= render partial: "error", locals: { model: form.object, attribute: attribute } %>
</div>
</div>
5 changes: 5 additions & 0 deletions spec/factories/furniture/marketplace.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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) }
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 621b907

Please sign in to comment.