Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Space admins can create "Menu/Product Groups" and reorder them for display on their marketplace #2361

Merged
merged 31 commits into from
May 24, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
baed227
Adds tag sorting capability and updates product displays
rosschapman May 8, 2024
1ba0fea
Update app/furniture/marketplace/tags/_form.html.erb
rosschapman May 9, 2024
d7c5421
Improve naming, de-composition and testing of Marketplace::Tag scopes.
anaulin May 11, 2024
010a988
Replace `Marketplace.products_with_no_group_tags` with a scope on
anaulin May 11, 2024
cd5cd4b
Add tagged products to seeds' marketplace.
anaulin May 11, 2024
749db95
Fix lint issues.
anaulin May 11, 2024
7906242
Scopes tag position to bazaar
rosschapman May 14, 2024
616f72f
Merge branch 'main' into tag-sections
rosschapman May 14, 2024
f9372dc
Update app/furniture/marketplace/menu_component.html.erb
rosschapman May 14, 2024
c3a29f9
rolled back
rosschapman May 15, 2024
e7e23ba
Bump nokogiri from 1.16.4 to 1.16.5 (#2404)
dependabot[bot] May 14, 2024
71123b8
Bump postcss-preset-env from 9.5.11 to 9.5.13 (#2402)
dependabot[bot] May 14, 2024
2e89771
Bump aws-sdk-s3 from 1.149.1 to 1.150.0 (#2401)
dependabot[bot] May 14, 2024
b89747d
Remove obsolete docker-compose top-level `version` keyword (#2400)
anaulin May 14, 2024
4f70ea3
Bump square.rb from 37.0.0.20240417 to 38.0.0.20240515 (#2407)
dependabot[bot] May 15, 2024
27d5a36
Bump positioning from 0.2.1 to 0.2.2 (#2410)
dependabot[bot] May 21, 2024
fce6282
Bump rexml from 3.2.6 to 3.2.8 (#2409)
dependabot[bot] May 21, 2024
cdb734c
Bump standard from 1.35.1 to 1.36.0 (#2406)
dependabot[bot] May 21, 2024
161dedd
Bump aws-sdk-s3 from 1.150.0 to 1.151.0 (#2405)
dependabot[bot] May 21, 2024
97ff443
Bump rubocop-rails from 2.24.1 to 2.25.0 (#2411)
dependabot[bot] May 22, 2024
feb54e3
Bump selenium-webdriver from 4.20.1 to 4.21.1 (#2412)
dependabot[bot] May 22, 2024
aae219d
Removes Bazaar association from Tags (#2408)
rosschapman May 23, 2024
cf1e499
Runs yarn after merge
rosschapman May 23, 2024
7bdbd5b
Merge branch 'main' into tag-sections
rosschapman May 23, 2024
94ea17d
Updates styling and adds test placeholder
rosschapman May 23, 2024
a02cd6e
Adds specs
rosschapman May 23, 2024
c42c307
Update seeds
rosschapman May 23, 2024
2b9b494
Merge branch 'main' into tag-sections
rosschapman May 24, 2024
a4bae6b
Oops, add missing dep
rosschapman May 24, 2024
c3a496a
Updates spec
rosschapman May 24, 2024
e6e6b35
Merge branch 'main' into tag-sections
rosschapman May 24, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions app/components/svg_component.rb
Original file line number Diff line number Diff line change
Expand Up @@ -118,4 +118,10 @@ def qr_code
<path stroke-linecap="round" stroke-linejoin="round" d="M6.75 6.75h.75v.75h-.75v-.75ZM6.75 16.5h.75v.75h-.75v-.75ZM16.5 6.75h.75v.75h-.75v-.75ZM13.5 13.5h.75v.75h-.75v-.75ZM13.5 19.5h.75v.75h-.75v-.75ZM19.5 13.5h.75v.75h-.75v-.75ZM19.5 19.5h.75v.75h-.75v-.75ZM16.5 16.5h.75v.75h-.75v-.75Z" />
SVG
end

def bars_3
<<~SVG
<path stroke-linecap="round" stroke-linejoin="round" d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5" />
SVG
end
rosschapman marked this conversation as resolved.
Show resolved Hide resolved
end
5 changes: 5 additions & 0 deletions app/furniture/marketplace/breadcrumbs.rb
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,11 @@
link t("marketplace.tags.new.link_to"), marketplace.location(:new, child: :tag)
end

crumb :edit_marketplace_tag do |tag|
parent :marketplace_tags, tag.marketplace
link t("marketplace.tags.edit.link_to"), marketplace.location(:edit, child: :tag)
end

crumb :marketplace_tax_rates do |marketplace|
parent :edit_marketplace, marketplace
link t("marketplace.tax_rates.index.link_to"), marketplace.location(child: :tax_rates)
Expand Down
8 changes: 6 additions & 2 deletions app/furniture/marketplace/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,10 @@ en:
link_to: "Payment Settings"
tags:
index:
link_to: "Tags"
link_to: "Product Tags"
new:
link_to: "Add Tag"
link_to: "Add Product Tag"
edit:
link_to: "Edit Product Tag"
update:
success: "Product Tag saved!"
39 changes: 39 additions & 0 deletions app/furniture/marketplace/marketplace.rb
Original file line number Diff line number Diff line change
Expand Up @@ -136,5 +136,44 @@ def square_order_notifications_enabled?
def default_delivery_area
(delivery_areas.unarchived.size == 1) ? delivery_areas.unarchived.first : nil
end

# Because we've decided to make tagging or assigning to group optional for
# Marketplace Products, we need a method for querying these non-tagged
# Products for display
def products_with_no_group_tags
# A rough mental model of this query
#
# Step 1: Build a list of unarchived marketplace products represented by
# an array of boolean markers that map to the "is_group" column for each
# of their respective tags.
#
# | mp_tag_groups |
# | ------------- |
# | {t, f, t, f} | <-- has some group tags
# | {f, f} | <-- has no group tags
# | {t, t, t} | <-- has all group tags
#
# Step 2: Filter this list and return only the Marketplace Products who's
# corresonding row includes all `f`s.
with_no_group_tags = Product.find_by_sql <<-SQL.squish
select
mp.*
from
marketplace_products mp
full join marketplace_product_tags mpt on mpt.product_id = mp.id
full join marketplace_tags mt on mt.id = mpt.tag_id
where
mp.marketplace_id = '#{id}'
and mp.discarded_at is null
group by
mp.id
having not
't' = any(array_agg(mt.is_group));
SQL

# Step 3: Merge the above with all other products that are missing tags
# which won't be captured by the above query
with_no_group_tags + products.unarchived.where.missing(:tags)
rosschapman marked this conversation as resolved.
Show resolved Hide resolved
end
end
end
17 changes: 14 additions & 3 deletions app/furniture/marketplace/menu_component.html.erb
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
<div class="grid sm:grid-cols-2 lg:grid-cols-3 gap-3">
<%- marketplace.products.with_all_rich_text.unarchived.each do |product| %>
<%= render Marketplace::Menu::ProductComponent.new(product:, cart:)%>
<%- marketplace.tags.ordered_tag_groups.each do |tag| %>
<%- unless tag.products.empty? %>
<h1><%= tag.label %></h1>
<div class="grid lg:grid-cols-3 gap-3">
<%- tag.products.with_all_rich_text.unarchived.each do |product| %>
<%= render Marketplace::Menu::ProductComponent.new(product:, cart:) %>
<%- end %>
</div>
<%- end %>
<%- end %>
<h1>Everything</h1>
<div class="grid lg:grid-cols-3 gap-3">
rosschapman marked this conversation as resolved.
Show resolved Hide resolved
rosschapman marked this conversation as resolved.
Show resolved Hide resolved
<%- marketplace.products_with_no_group_tags.each do |product| %>
<%= render Marketplace::Menu::ProductComponent.new(product:, cart:) %>
<%- end %>
</div>
5 changes: 5 additions & 0 deletions app/furniture/marketplace/tag.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,10 @@ class Tag < Record

attr_accessor :marketplace
location(parent: :marketplace)

positioned
rosschapman marked this conversation as resolved.
Show resolved Hide resolved

rosschapman marked this conversation as resolved.
Show resolved Hide resolved
scope :without_group, -> { where(is_group: false) }
scope :ordered_tag_groups, -> { where(is_group: true).merge(order(position: :asc, updated_at: :desc)) }
rosschapman marked this conversation as resolved.
Show resolved Hide resolved
end
end
2 changes: 1 addition & 1 deletion app/furniture/marketplace/tag_policy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ def space
end

def permitted_attributes(_params = nil)
%i[label]
%i[label is_group position]
end

def update?
Expand Down
12 changes: 8 additions & 4 deletions app/furniture/marketplace/tags/_form.html.erb
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
<%= form_with(model: tag.location) do |form| %>

<%= render "text_field", attribute: :label, form: form %>

<%= form.submit %>
<div class="flex flex-col gap-5">
<div>
<%= render "text_field", attribute: :label, form: form %>
<%= form.label :is_group, "Is this a menu group?" %>
<%= form.check_box :is_group %>
</div>
<%= form.submit %>
</div>
<%- end %>
9 changes: 9 additions & 0 deletions app/furniture/marketplace/tags/edit.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<%
# We must assign the marketplace object explicitly in the current scope
# because of the funky way we relate Tags to the Marketplace through a Bazaar.
# Yet our routing and navigation depends on a `marketplace` object being present
# on a Tag.
mtag.marketplace = marketplace
%>
<%- breadcrumb :edit_marketplace_tag, mtag %>
<%= render "form", tag: mtag %>
51 changes: 41 additions & 10 deletions app/furniture/marketplace/tags/index.html.erb
Original file line number Diff line number Diff line change
@@ -1,16 +1,47 @@
<%- breadcrumb :marketplace_tags, marketplace %>

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

<%- marketplace.tags.each do |tag| %>
<%- tag.marketplace = marketplace %>
<div id="<%= dom_id(tag)%>" class="flex flex-row gap-3">
<span class="flex-grow">
<%= tag.label %>
</span>
</div>
<h1>Product Groups</h1>
<p>Drag and drop to change the order in which groups will display on your Marketplace</p>
<ul data-controller="sortable" data-sortable-animation-value="150" data-sortable-resource-name-value="tag" class="flex flex-col gap-2 p-0">
<%- bazaar.tags.ordered_tag_groups.each do |tag| %>
<%-
# We must assign the marketplace object explicitly in the current scope
# because of the funky way we relate Tags to the Marketplace through a Bazaar.
# Yet our routing and navigation depends on a `marketplace` object being present
# on a Tag.
tag.marketplace = marketplace
rosschapman marked this conversation as resolved.
Show resolved Hide resolved
%>
<li data-sortable-update-url="<%= polymorphic_path(tag.location) %>" id="<%= dom_id(tag)%>" class="items-center rounded-md bg-gray-50 px-2 py-1 font-medium text-gray-600 ring-1 ring-inset ring-gray-500/10 list-none cursor-move">
<%= render SvgComponent.new(icon: "bars_3", classes: "w-6 h-6 inline-block") %>
<%= link_to tag.label, tag.location(:edit) %>
<%- if tag.is_group %>
<span class="inline-flex items-center text-xs justify-center px-1 text-xs bg-gray-200 rounded-full">
group
</span>
<% end %>
</li>
<%- end %>
<%- card.with_footer(variant: :action_bar) do %>
<%- new_tag = bazaar.tags.new %>
<%- if policy(new_tag).create? %>
<%= link_to t("marketplace.tags.new.link_to"), marketplace.location(:new, child: :tag), class: "button w-full" %>
<%- end %>
<%- end %>
</ul>
<h1>Tags</h1>
<p>Add tags to label your products as vegan, discounted, etc...</p>
<%- bazaar.tags.without_group.each do |tag| %>
<%-
# We must assign the marketplace object explicitly in the current scope
# because of the funky way we relate Tags to the Marketplace through a Bazaar.
# Yet our routing and navigation depends on a `marketplace` object being present
# on a Tag.
tag.marketplace = marketplace
%>
rosschapman marked this conversation as resolved.
Show resolved Hide resolved
<span id="<%= dom_id(tag)%>" class="items-center rounded-md bg-gray-50 px-2 py-1 font-medium text-gray-600 ring-1 ring-inset ring-gray-500/10 list-none cursor-move">
<%= link_to tag.label, tag.location(:edit) %>
</span>
<%- end %>

<%- card.with_footer(variant: :action_bar) do %>
<%- new_tag = bazaar.tags.new %>
<%- if policy(new_tag).create? %>
Expand Down
18 changes: 18 additions & 0 deletions app/furniture/marketplace/tags_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,24 @@ def new
authorize(mtag)
end

def edit
authorize(mtag)
end

def update
if authorize(mtag).update(mtag_params)
# POST requests to reorder tags (Stimulus Sortable) are sent with an
# html content-type so they cannot be handled by a JS responder.
if request.xhr?
render json: {}, status: :ok
else
rosschapman marked this conversation as resolved.
Show resolved Hide resolved
redirect_to marketplace.location(child: :tags)
end
rosschapman marked this conversation as resolved.
Show resolved Hide resolved
else
render :edit
end
end

def create
if authorize(mtag).save
redirect_to marketplace.location(child: :tags)
Expand Down
4 changes: 3 additions & 1 deletion app/javascript/controllers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
// ./bin/rails generate stimulus controllerName

import { application } from "./application.js";

import MenuController from "./menu_controller.js";
import Sortable from "@stimulus-components/sortable";

application.register("menu", MenuController);
application.register("sortable", Sortable);
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@
"@rails/actioncable": "^7.1.3",
"@rails/actiontext": "^7.1.3",
"@rails/activestorage": "^7.1.3",
"@rails/request.js": "^0.0.9",
"@sentry/browser": "^7.113.0",
"@stimulus-components/sortable": "^5.0.1",
"@tailwindcss/forms": "^0.5.7",
"@tailwindcss/typography": "^0.5.13",
"@webpack-cli/serve": "^2.0.5",
Expand All @@ -53,6 +55,7 @@
"postcss-flexbugs-fixes": "^5.0.2",
"postcss-import": "^16.1.0",
"postcss-preset-env": "^9.5.9",
"sortablejs": "^1.15.2",
"tailwindcss": "^3.4.3",
"trix": "^2.1.1",
"webpack": "^5.76.0",
Expand Down
2 changes: 1 addition & 1 deletion spec/furniture/marketplace/product_tags_system_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
visit(marketplace)
click_link("Tags")

click_link("Add Tag")
click_link("Add Product Tag")

fill_in("Label", with: "🚫🌾 Gluten Free")

Expand Down
15 changes: 15 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,11 @@
dependencies:
spark-md5 "^3.0.1"

"@rails/request.js@^0.0.9":
version "0.0.9"
resolved "https://registry.yarnpkg.com/@rails/request.js/-/request.js-0.0.9.tgz#89e2a575405dc07eb8a9b3d2fe04289e1f057cd0"
integrity sha512-VleYUyrA3rwKMvYnz7MI9Ada85Vekjb/WVz7NuGgDO24Y3Zy9FFSpDMQW+ea/tlftD+CdX/W/sUosRA9/HkDOQ==

"@sentry-internal/[email protected]":
version "7.113.0"
resolved "https://registry.yarnpkg.com/@sentry-internal/feedback/-/feedback-7.113.0.tgz#90a3c5493e289d589cfde79330fca549a24f41a4"
Expand Down Expand Up @@ -510,6 +515,11 @@
resolved "https://registry.yarnpkg.com/@sindresorhus/merge-streams/-/merge-streams-1.0.0.tgz#9cd84cc15bc865a5ca35fcaae198eb899f7b5c90"
integrity sha512-rUV5WyJrJLoloD4NDN1V1+LDMDWOa4OTsT4yYJwQNpTU6FWxkxHpL7eu4w+DmiH8x/EAM1otkPE1+LaspIbplw==

"@stimulus-components/sortable@^5.0.1":
version "5.0.1"
resolved "https://registry.yarnpkg.com/@stimulus-components/sortable/-/sortable-5.0.1.tgz#622b54bd11ab905ab28bdd8282399dc682d06933"
integrity sha512-03wQ+0fRaa0cYR3ia8+DJ4vW+UnAmBz24N8ChujWbceN79il49l7+hUZr74FNghmdX2OWhrmcr4YoG+VZ5XQ2g==

"@tailwindcss/forms@^0.5.7":
version "0.5.7"
resolved "https://registry.yarnpkg.com/@tailwindcss/forms/-/forms-0.5.7.tgz#db5421f062a757b5f828bc9286ba626c6685e821"
Expand Down Expand Up @@ -2104,6 +2114,11 @@ slash@^5.0.0, slash@^5.1.0:
resolved "https://registry.yarnpkg.com/slash/-/slash-5.1.0.tgz#be3adddcdf09ac38eebe8dcdc7b1a57a75b095ce"
integrity sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==

sortablejs@^1.15.2:
version "1.15.2"
resolved "https://registry.yarnpkg.com/sortablejs/-/sortablejs-1.15.2.tgz#4e9f7bda4718bd1838add9f1866ec77169149809"
integrity sha512-FJF5jgdfvoKn1MAKSdGs33bIqLi3LmsgVTliuX6iITj834F+JRQZN90Z93yql8h0K2t0RwDPBmxwlbZfDcxNZA==

source-map-js@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.0.tgz#16b809c162517b5b8c3e7dcd315a2a5c2612b2af"
Expand Down
Loading