Skip to content

Commit

Permalink
Marketplace: VendorRepresentative manages Products
Browse files Browse the repository at this point in the history
- #2044

OK this should probably be split into a number of smaller steps, each
with reasonable test coverage; but I wanted to get something working so
we can turn the keys over to the folks at Oaklandia.

This makes it so:

- A `Neighborhood` `Operator` or `Space` `Member` can add a
  `VendorRepresentative` to a `Marketplace`
- The `VendorRepresentative` can add, remove, and update `Products`

YOLO YOLO YOLO
  • Loading branch information
zspencer committed Feb 8, 2024
1 parent b2e74ba commit 1768518
Show file tree
Hide file tree
Showing 16 changed files with 200 additions and 2 deletions.
10 changes: 10 additions & 0 deletions app/components/svg_component.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ class SvgComponent < ApplicationComponent
#
# Format: { symbol: method returning path for symbol }
ICON_MAPPINGS = {
cake: :cake,
cart: :cart,
money: :money,
exclamation_triangle: :exclamation_triangle,
Expand Down Expand Up @@ -119,4 +120,13 @@ def pencil
<path stroke-linecap="round" stroke-linejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 0 1 1.13-1.897L16.863 4.487Zm0 0L19.5 7.125" />
SVG
end

def cake
<<~SVG
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
<path stroke-linecap="round" stroke-linejoin="round" d="M12 8.25v-1.5m0 1.5c-1.355 0-2.697.056-4.024.166C6.845 8.51 6 9.473 6 10.608v2.513m6-4.871c1.355 0 2.697.056 4.024.166C17.155 8.51 18 9.473 18 10.608v2.513M15 8.25v-1.5m-6 1.5v-1.5m12 9.75-1.5.75a3.354 3.354 0 0 1-3 0 3.354 3.354 0 0 0-3 0 3.354 3.354 0 0 1-3 0 3.354 3.354 0 0 0-3 0 3.354 3.354 0 0 1-3 0L3 16.5m15-3.379a48.474 48.474 0 0 0-6-.371c-2.032 0-4.034.126-6 .371m12 0c.39.049.777.102 1.163.16 1.07.16 1.837 1.094 1.837 2.175v5.169c0 .621-.504 1.125-1.125 1.125H4.125A1.125 1.125 0 0 1 3 20.625v-5.17c0-1.08.768-2.014 1.837-2.174A47.78 47.78 0 0 1 6 13.12M12.265 3.11a.375.375 0 1 1-.53 0L12 2.845l.265.265Zm-3 0a.375.375 0 1 1-.53 0L9 2.845l.265.265Zm6 0a.375.375 0 1 1-.53 0L15 2.845l.265.265Z" />
</svg>
SVG
end
end
10 changes: 10 additions & 0 deletions app/furniture/marketplace/breadcrumbs.rb
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,16 @@
link t("marketplace.products.edit.link_to", name: product.name), product.location(:edit)
end

crumb :marketplace_vendor_representatives do |marketplace|
parent :edit_marketplace, marketplace
link t("marketplace.vendor_representatives.index.link_to"), marketplace.location(child: :vendor_representatives)
end

crumb :new_marketplace_vendor_representative do |vendor_representative|
parent :edit_marketplace, vendor_representative.marketplace
link t("marketplace.vendor_representatives.new.link_to"), marketplace.location(:new, child: :vendor_representative)
end

crumb :marketplace_delivery_areas do |marketplace|
parent :edit_marketplace, marketplace
link t("marketplace.delivery_areas.index.link_to"), marketplace.location(child: :delivery_areas)
Expand Down
5 changes: 5 additions & 0 deletions app/furniture/marketplace/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,11 @@ en:
link_to: Edit Tax Rate '%{name}'
destroy:
link_to: Remove Tax Rate '%{name}'
vendor_representatives:
index:
link_to: "Vendor Representatives"
new:
link_to: "Add a Representative"
cart_products:
destroy:
success: "Removed %{quantity} %{product} from Cart"
Expand Down
1 change: 1 addition & 0 deletions app/furniture/marketplace/management_component.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
<%= render button({child: :orders}, icon: :cart) if policy(marketplace.orders).index? %>
<%= render button({child: :notification_methods}, icon: :bell) if policy(marketplace.notification_methods).index? %>
<%= render button({child: :flyer}, icon: :receipt_percent) if policy(marketplace.flyer).show? %>
<%= render button({child: :vendor_representatives}, icon: :cake) if policy(marketplace.vendor_representatives).index? %>
</nav>
<% end %>
<% end %>
Expand Down
1 change: 1 addition & 0 deletions app/furniture/marketplace/marketplace.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ class Marketplace < Furniture
has_many :delivery_areas, inverse_of: :marketplace, dependent: :destroy

has_many :notification_methods, inverse_of: :marketplace, dependent: :destroy
has_many :vendor_representatives, inverse_of: :marketplace, dependent: :destroy

setting :stripe_account
alias_method :vendor_stripe_account, :stripe_account
Expand Down
4 changes: 3 additions & 1 deletion app/furniture/marketplace/marketplace_policy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ def show?
end

def create?
current_person.operator? || current_person.member_of?(marketplace.space)
current_person.operator? ||
current_person.member_of?(marketplace.space) ||
marketplace.vendor_representatives.exists?(person: current_person)
end

alias_method :update?, :create?
Expand Down
2 changes: 2 additions & 0 deletions app/furniture/marketplace/product_policy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@ def permitted_attributes(_params = nil)

def update?
return false unless current_person.authenticated?
return true if marketplace.vendor_representatives.exists?(person: current_person)

super
end

alias_method :create?, :update?

def show?
Expand Down
1 change: 1 addition & 0 deletions app/furniture/marketplace/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ def self.append_routes(router)
router.resource :stripe_account, only: [:show, :new, :create]
router.resources :stripe_events
router.resources :tax_rates
router.resources :vendor_representatives
router.resources :payment_settings, only: [:index]
end
end
Expand Down
26 changes: 26 additions & 0 deletions app/furniture/marketplace/vendor_representative.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
class Marketplace
class VendorRepresentative < Record
self.table_name = :marketplace_vendor_representatives

belongs_to :marketplace, inverse_of: :vendor_representatives
has_one :room, through: :marketplace
belongs_to :person

attribute :email_address, :string
validates :email_address, uniqueness: true, presence: true

location(parent: :marketplace)

def claimed?
person.present?
end

def claimable?
matching_person.present?
end

def matching_person
Person.joins(:authentication_methods).find_by(authentication_methods: {contact_location: email_address})
end
end
end
27 changes: 27 additions & 0 deletions app/furniture/marketplace/vendor_representative_policy.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# frozen_string_literal: true

class Marketplace
class VendorRepresentativePolicy < Policy
alias_method :vendor_representative, :object
def permitted_attributes(_params = nil)
%i[email_address person_id]
end

def update?
return false unless current_person.authenticated?

super
end
alias_method :create?, :update?

def show?
true
end

class Scope < ApplicationScope
def resolve
scope.all
end
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<%= render CardComponent.new(dom_id: dom_id(vendor_representative)) do %>
<%= form_with model: vendor_representative.location do |f| %>
<%= render "email_field", { attribute: :email_address, form: f } %>

<%= f.submit %>
<%- end %>
<%- end %>
35 changes: 35 additions & 0 deletions app/furniture/marketplace/vendor_representatives/index.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<%- breadcrumb :marketplace_vendor_representatives, marketplace %>

<%= render CardComponent.new do |card| %>

<%- marketplace.vendor_representatives.each do |vendor_representative| %>
<div class="flex flex-row gap-3">
<span class="flex-initial">
<%- if vendor_representative.claimed? %>
<%- else %>
<%- if vendor_representative.claimable? %>
<%= button_to "👍", vendor_representative.location, method: :put, params: { vendor_representative: { person_id: vendor_representative.matching_person.id } }%>
<%- else %>
<span class="button">🛌</span>
<%- end %>
<%- end %>
</span>
<span class="flex-grow">
<%= vendor_representative.email_address %>
</span>
<span class="flex-initial">
<%- if policy(vendor_representative).destroy? %>
<%= button_to "🗑️", vendor_representative.location, method: :delete %>
<%- end %>
</span>
</div>
<%- end %>

<%- card.with_footer(variant: :action_bar) do %>
<%- new_vendor_representative = marketplace.vendor_representatives.new %>
<%- if policy(new_vendor_representative).create? %>
<%= link_to t("marketplace.vendor_representatives.new.link_to"), marketplace.location(:new, child: :vendor_representative), class: "button w-full" %>
<%- end %>
<%- end %>
<%- end %>
3 changes: 3 additions & 0 deletions app/furniture/marketplace/vendor_representatives/new.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<%- breadcrumb :new_marketplace_vendor_representative, vendor_representative %>

<%= render "form", vendor_representative: vendor_representative %>
45 changes: 45 additions & 0 deletions app/furniture/marketplace/vendor_representatives_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# frozen_string_literal: true

class Marketplace
class VendorRepresentativesController < Controller
expose :vendor_representative, scope: -> { vendor_representatives }, model: VendorRepresentative
expose :vendor_representatives, -> { policy_scope(marketplace.vendor_representatives) }

def new
authorize(vendor_representative)
end

def create
authorize(vendor_representative).save

if vendor_representative.persisted?
redirect_to marketplace.location(child: :vendor_representatives), notice: t(".success", name: vendor_representative.email_address)
else
render :new, status: :unprocessable_entity
end
end

def index
skip_authorization
end

def update
if authorize(vendor_representative).update(vendor_representative_params)
redirect_to marketplace.location(child: :vendor_representatives), notice: t(".success", name: vendor_representative.email_address)

else
redirect_to marketplace.location(child: :vendor_representatives), notice: t(".failure", name: vendor_representative.email_address)

end
end

def destroy
authorize(vendor_representative).destroy
redirect_to marketplace.location(child: :vendor_representatives), notice: t(".success", name: vendor_representative.email_address)
end

def vendor_representative_params
policy(VendorRepresentative).permit(params.require(:vendor_representative))
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
class MarketplaceCreateVendorRepresentatives < ActiveRecord::Migration[7.1]
def change
create_table :marketplace_vendor_representatives, id: :uuid do |t|
t.references :marketplace, type: :uuid, foreign_key: {to_table: :furnitures}
t.references :person, type: :uuid, foreign_key: true, null: true

t.string :email_address
t.timestamps
end
end
end
14 changes: 13 additions & 1 deletion db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.

ActiveRecord::Schema[7.1].define(version: 2024_02_01_014607) do
ActiveRecord::Schema[7.1].define(version: 2024_02_07_040004) do
# These are extensions that must be enabled in order to support this database
enable_extension "pgcrypto"
enable_extension "plpgsql"
Expand Down Expand Up @@ -233,6 +233,16 @@
t.index ["marketplace_id"], name: "index_marketplace_tax_rates_on_marketplace_id"
end

create_table "marketplace_vendor_representatives", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
t.uuid "marketplace_id"
t.uuid "person_id"
t.string "email_address"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["marketplace_id"], name: "index_marketplace_vendor_representatives_on_marketplace_id"
t.index ["person_id"], name: "index_marketplace_vendor_representatives_on_person_id"
end

create_table "media", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
Expand Down Expand Up @@ -324,6 +334,8 @@
add_foreign_key "marketplace_shoppers", "people"
add_foreign_key "marketplace_tax_rates", "furnitures", column: "marketplace_id"
add_foreign_key "marketplace_tax_rates", "spaces", column: "bazaar_id"
add_foreign_key "marketplace_vendor_representatives", "furnitures", column: "marketplace_id"
add_foreign_key "marketplace_vendor_representatives", "people"
add_foreign_key "memberships", "invitations"
add_foreign_key "rooms", "media", column: "hero_image_id"
add_foreign_key "space_agreements", "spaces"
Expand Down

0 comments on commit 1768518

Please sign in to comment.