mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-01-24 20:36:49 +00:00
Adding product property filter to shop page
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
Darkswarm.filter 'propertiesOf', ->
|
||||
(objects)->
|
||||
properties = {}
|
||||
for object in objects
|
||||
for property in object.properties
|
||||
properties[property.id] = property
|
||||
properties
|
||||
@@ -1,27 +1,28 @@
|
||||
Darkswarm.factory 'Products', ($resource, Enterprises, Dereferencer, Taxons, Cart, Variants) ->
|
||||
Darkswarm.factory 'Products', ($resource, Enterprises, Dereferencer, Taxons, Properties, Cart, Variants) ->
|
||||
new class Products
|
||||
constructor: ->
|
||||
@update()
|
||||
|
||||
|
||||
# TODO: don't need to scope this into object
|
||||
# Already on object as far as controller scope is concerned
|
||||
products: null
|
||||
loading: true
|
||||
|
||||
update: =>
|
||||
@loading = true
|
||||
@loading = true
|
||||
@products = $resource("/shop/products").query (products)=>
|
||||
@extend() && @dereference()
|
||||
@registerVariants()
|
||||
@registerVariants()
|
||||
@registerVariantsWithCart()
|
||||
@loading = false
|
||||
@
|
||||
|
||||
|
||||
dereference: ->
|
||||
for product in @products
|
||||
product.supplier = Enterprises.enterprises_by_id[product.supplier.id]
|
||||
Dereferencer.dereference product.taxons, Taxons.taxons_by_id
|
||||
|
||||
Dereferencer.dereference product.properties, Properties.properties_by_id
|
||||
|
||||
# May return different objects! If the variant has already been registered
|
||||
# by another service, we fetch those
|
||||
registerVariants: ->
|
||||
@@ -45,7 +46,7 @@ Darkswarm.factory 'Products', ($resource, Enterprises, Dereferencer, Taxons, Car
|
||||
prices = (v.price for v in product.variants)
|
||||
product.price = Math.min.apply(null, prices)
|
||||
product.hasVariants = product.variants?.length > 0
|
||||
|
||||
|
||||
product.primaryImage = product.images[0]?.small_url if product.images
|
||||
product.primaryImageOrMissing = product.primaryImage || "/assets/noimage/small.png"
|
||||
product.largeImage = product.images[0]?.large_url if product.images
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
Darkswarm.factory "Properties", (properties)->
|
||||
new class Properties
|
||||
# Populate ProductProperties.properties from json in page.
|
||||
properties: properties
|
||||
properties_by_id: {}
|
||||
constructor: ->
|
||||
# Map properties to id/object pairs for lookup.
|
||||
for property in @properties
|
||||
@properties_by_id[property.id] = property
|
||||
@@ -21,6 +21,10 @@ module InjectionHelper
|
||||
inject_json_ams "taxons", Spree::Taxon.all, Api::TaxonSerializer
|
||||
end
|
||||
|
||||
def inject_properties
|
||||
inject_json_ams "properties", Spree::Property.all, Api::IdNameSerializer
|
||||
end
|
||||
|
||||
def inject_currency_config
|
||||
inject_json_ams "currencyConfig", {}, Api::CurrencyConfigSerializer
|
||||
end
|
||||
|
||||
3
app/serializers/api/id_name_serializer.rb
Normal file
3
app/serializers/api/id_name_serializer.rb
Normal file
@@ -0,0 +1,3 @@
|
||||
class Api::IdNameSerializer < ActiveModel::Serializer
|
||||
attributes :id, :name
|
||||
end
|
||||
@@ -35,7 +35,7 @@ class Api::CachedProductSerializer < ActiveModel::Serializer
|
||||
|
||||
has_many :variants, serializer: Api::VariantSerializer
|
||||
has_many :taxons, serializer: Api::IdSerializer
|
||||
has_many :properties, serializer: Api::PropertySerializer
|
||||
has_many :properties, serializer: Api::IdSerializer
|
||||
has_many :images, serializer: Api::ImageSerializer
|
||||
|
||||
has_one :supplier, serializer: Api::IdSerializer
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
= inject_json "user", "current_user"
|
||||
= inject_json "railsFlash", "flash"
|
||||
= inject_taxons
|
||||
= inject_properties
|
||||
= inject_current_order
|
||||
= inject_currency_config
|
||||
|
||||
@@ -37,6 +38,6 @@
|
||||
|
||||
%section{ role: "main" }
|
||||
= yield
|
||||
|
||||
|
||||
#footer
|
||||
%loading
|
||||
|
||||
@@ -1,15 +1,5 @@
|
||||
.filter-box.filter-box-shopfront.animate-hide.text-right
|
||||
%single-line-selectors{ objects: "Products.products | products:query | taxonsOf", "active-selectors" => "activeTaxons"}
|
||||
|
||||
-# .filter-box.property-box-shopfront.animate-hide.text-right
|
||||
-# %ul
|
||||
-# %li
|
||||
-# %a Organic Certified
|
||||
-# %li
|
||||
-# %a Free Range
|
||||
-# %li
|
||||
-# %a Biodynamic
|
||||
-# %li
|
||||
-# %a
|
||||
-# + 2 more
|
||||
-# %span.caret
|
||||
.filter-box.property-box-shopfront.animate-hide.text-right
|
||||
%single-line-selectors{ objects: "Products.products | products:query | propertiesOf", "active-selectors" => "activeProperties"}
|
||||
|
||||
@@ -15,7 +15,7 @@ feature "As a consumer I want to shop with a distributor", js: true do
|
||||
let(:product) { create(:simple_product, supplier: supplier) }
|
||||
let(:order) { create(:order, distributor: distributor) }
|
||||
|
||||
before do
|
||||
before do
|
||||
set_order order
|
||||
end
|
||||
|
||||
@@ -28,23 +28,23 @@ feature "As a consumer I want to shop with a distributor", js: true do
|
||||
visit shop_path
|
||||
page.should have_text distributor.name
|
||||
find("#tab_about a").click
|
||||
first("distributor img")['src'].should == distributor.logo.url(:thumb)
|
||||
first("distributor img")['src'].should == distributor.logo.url(:thumb)
|
||||
end
|
||||
|
||||
it "shows the producers for a distributor" do
|
||||
exchange = Exchange.find(oc1.exchanges.to_enterprises(distributor).outgoing.first.id)
|
||||
exchange = Exchange.find(oc1.exchanges.to_enterprises(distributor).outgoing.first.id)
|
||||
exchange.variants << product.master
|
||||
|
||||
visit shop_path
|
||||
find("#tab_producers a").click
|
||||
page.should have_content supplier.name
|
||||
page.should have_content supplier.name
|
||||
end
|
||||
|
||||
describe "selecting an order cycle" do
|
||||
let(:exchange1) { Exchange.find(oc1.exchanges.to_enterprises(distributor).outgoing.first.id) }
|
||||
|
||||
it "selects an order cycle if only one is open" do
|
||||
exchange1.update_attribute :pickup_time, "turtles"
|
||||
exchange1.update_attribute :pickup_time, "turtles"
|
||||
visit shop_path
|
||||
page.should have_selector "option[selected]", text: 'turtles'
|
||||
end
|
||||
@@ -52,8 +52,8 @@ feature "As a consumer I want to shop with a distributor", js: true do
|
||||
describe "with multiple order cycles" do
|
||||
let(:exchange2) { Exchange.find(oc2.exchanges.to_enterprises(distributor).outgoing.first.id) }
|
||||
before do
|
||||
exchange1.update_attribute :pickup_time, "frogs"
|
||||
exchange2.update_attribute :pickup_time, "turtles"
|
||||
exchange1.update_attribute :pickup_time, "frogs"
|
||||
exchange2.update_attribute :pickup_time, "turtles"
|
||||
end
|
||||
|
||||
it "shows a select with all order cycles, but doesn't show the products by default" do
|
||||
@@ -62,20 +62,20 @@ feature "As a consumer I want to shop with a distributor", js: true do
|
||||
page.should have_selector "option", text: 'turtles'
|
||||
page.should_not have_selector("input.button.right", visible: true)
|
||||
end
|
||||
|
||||
|
||||
it "shows products after selecting an order cycle" do
|
||||
product.master.update_attribute(:display_name, "kitten")
|
||||
product.master.update_attribute(:display_as, "rabbit")
|
||||
exchange1.variants << product.master ## add product to exchange
|
||||
visit shop_path
|
||||
page.should_not have_content product.name
|
||||
page.should_not have_content product.name
|
||||
Spree::Order.last.order_cycle.should == nil
|
||||
|
||||
select "frogs", :from => "order_cycle_id"
|
||||
page.should have_selector "products"
|
||||
page.should have_content "Next order closing in 2 days"
|
||||
page.should have_content "Next order closing in 2 days"
|
||||
Spree::Order.last.order_cycle.should == oc1
|
||||
page.should have_content product.name
|
||||
page.should have_content product.name
|
||||
page.should have_content product.master.display_name
|
||||
page.should have_content product.master.display_as
|
||||
|
||||
@@ -88,10 +88,10 @@ feature "As a consumer I want to shop with a distributor", js: true do
|
||||
describe "after selecting an order cycle with products visible" do
|
||||
let(:variant1) { create(:variant, product: product, price: 20) }
|
||||
let(:variant2) { create(:variant, product: product, price: 30) }
|
||||
let(:exchange) { Exchange.find(oc1.exchanges.to_enterprises(distributor).outgoing.first.id) }
|
||||
let(:exchange) { Exchange.find(oc1.exchanges.to_enterprises(distributor).outgoing.first.id) }
|
||||
|
||||
before do
|
||||
exchange.update_attribute :pickup_time, "frogs"
|
||||
exchange.update_attribute :pickup_time, "frogs"
|
||||
exchange.variants << product.master
|
||||
exchange.variants << variant1
|
||||
exchange.variants << variant2
|
||||
@@ -134,7 +134,7 @@ feature "As a consumer I want to shop with a distributor", js: true do
|
||||
set_order_cycle(order, oc1)
|
||||
visit shop_path
|
||||
end
|
||||
|
||||
|
||||
it "should save group buy data to ze cart" do
|
||||
fill_in "variants[#{product.master.id}]", with: 5
|
||||
fill_in "variant_attributes[#{product.master.id}][max_quantity]", with: 9
|
||||
@@ -145,7 +145,7 @@ feature "As a consumer I want to shop with a distributor", js: true do
|
||||
li.max_quantity.should == 9
|
||||
li.quantity.should == 5
|
||||
end
|
||||
|
||||
|
||||
# TODO move to controller test
|
||||
pending "adding a product with a max quantity less than quantity results in max_quantity==quantity" do
|
||||
fill_in "variants[#{product.master.id}]", with: 5
|
||||
@@ -165,7 +165,7 @@ feature "As a consumer I want to shop with a distributor", js: true do
|
||||
set_order_cycle(order, oc1)
|
||||
visit shop_path
|
||||
end
|
||||
|
||||
|
||||
it "should save group buy data to the cart" do
|
||||
fill_in "variants[#{variant.id}]", with: 6
|
||||
fill_in "variant_attributes[#{variant.id}][max_quantity]", with: 7
|
||||
@@ -213,4 +213,3 @@ feature "As a consumer I want to shop with a distributor", js: true do
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -4,19 +4,23 @@ describe 'ProductsCtrl', ->
|
||||
event = null
|
||||
Products = null
|
||||
Cart = {}
|
||||
Taxons = null
|
||||
|
||||
beforeEach ->
|
||||
module('Darkswarm')
|
||||
Products =
|
||||
Products =
|
||||
all: ->
|
||||
update: ->
|
||||
products: ["testy mctest"]
|
||||
loading: false
|
||||
OrderCycle =
|
||||
order_cycle: {}
|
||||
|
||||
inject ($controller) ->
|
||||
scope = {}
|
||||
ctrl = $controller 'ProductsCtrl', {$scope: scope, Products: Products, OrderCycle: OrderCycle, Cart: Cart}
|
||||
Taxons:
|
||||
taxons: []
|
||||
|
||||
inject ($rootScope, $controller) ->
|
||||
scope = $rootScope
|
||||
ctrl = $controller 'ProductsCtrl', {$scope: scope, Products: Products, OrderCycle: OrderCycle, Cart: Cart, Taxons: Taxons}
|
||||
|
||||
it 'fetches products from Products', ->
|
||||
expect(scope.Products.products).toEqual ['testy mctest']
|
||||
|
||||
@@ -4,13 +4,15 @@ describe 'Products service', ->
|
||||
Enterprises = null
|
||||
Variants = null
|
||||
Cart = null
|
||||
CurrentHubMock = {}
|
||||
CurrentHubMock = {}
|
||||
currentOrder = null
|
||||
product = null
|
||||
productWithImage = null
|
||||
properties = null
|
||||
taxons = null
|
||||
|
||||
beforeEach ->
|
||||
product =
|
||||
product =
|
||||
test: "cats"
|
||||
supplier:
|
||||
id: 9
|
||||
@@ -27,16 +29,23 @@ describe 'Products service', ->
|
||||
]
|
||||
currentOrder =
|
||||
line_items: []
|
||||
properties =
|
||||
{ id: 1, name: "some property" }
|
||||
taxons =
|
||||
{ id: 2, name: "some taxon" }
|
||||
|
||||
module 'Darkswarm'
|
||||
module ($provide)->
|
||||
$provide.value "CurrentHub", CurrentHubMock
|
||||
$provide.value "currentOrder", currentOrder
|
||||
$provide.value "CurrentHub", CurrentHubMock
|
||||
$provide.value "currentOrder", currentOrder
|
||||
$provide.value "taxons", taxons
|
||||
$provide.value "properties", properties
|
||||
null
|
||||
|
||||
inject ($injector, _$httpBackend_)->
|
||||
Products = $injector.get("Products")
|
||||
Enterprises = $injector.get("Enterprises")
|
||||
Properties = $injector.get("Properties")
|
||||
Variants = $injector.get("Variants")
|
||||
Cart = $injector.get("Cart")
|
||||
$httpBackend = _$httpBackend_
|
||||
@@ -44,20 +53,32 @@ describe 'Products service', ->
|
||||
it "Fetches products from the backend on init", ->
|
||||
$httpBackend.expectGET("/shop/products").respond([product])
|
||||
$httpBackend.flush()
|
||||
expect(Products.products[0].test).toEqual "cats"
|
||||
expect(Products.products[0].test).toEqual "cats"
|
||||
|
||||
it "dereferences suppliers", ->
|
||||
Enterprises.enterprises_by_id =
|
||||
Enterprises.enterprises_by_id =
|
||||
{id: 9, name: "test"}
|
||||
$httpBackend.expectGET("/shop/products").respond([{supplier : {id: 9}, master: {}}])
|
||||
$httpBackend.flush()
|
||||
expect(Products.products[0].supplier).toBe Enterprises.enterprises_by_id["9"]
|
||||
|
||||
it "dereferences taxons", ->
|
||||
product.taxons = [2]
|
||||
$httpBackend.expectGET("/shop/products").respond([product])
|
||||
$httpBackend.flush()
|
||||
expect(Products.products[0].taxons[1]).toBe taxons[0]
|
||||
|
||||
it "dereferences properties", ->
|
||||
product.properties = [1]
|
||||
$httpBackend.expectGET("/shop/products").respond([product])
|
||||
$httpBackend.flush()
|
||||
expect(Products.products[0].properties[1]).toBe properties[0]
|
||||
|
||||
it "registers variants with Variants service", ->
|
||||
product.variants = [{id: 1}]
|
||||
$httpBackend.expectGET("/shop/products").respond([product])
|
||||
$httpBackend.flush()
|
||||
expect(Products.products[0].variants[0]).toBe Variants.variants[1]
|
||||
expect(Products.products[0].variants[0]).toBe Variants.variants[1]
|
||||
|
||||
it "registers variants with the Cart", ->
|
||||
product.variants = [{id: 8}]
|
||||
@@ -0,0 +1,16 @@
|
||||
describe "Properties service", ->
|
||||
Properties = null
|
||||
properties = [
|
||||
{id: 1, name: "Property1"}
|
||||
{id: 2, name: "Property2"}
|
||||
]
|
||||
|
||||
beforeEach ->
|
||||
module('Darkswarm')
|
||||
angular.module('Darkswarm').value 'properties', properties
|
||||
|
||||
inject ($injector)->
|
||||
Properties = $injector.get("Properties")
|
||||
|
||||
it "caches properties in an id-referenced hash", ->
|
||||
expect(Properties.properties_by_id[1]).toBe properties[0]
|
||||
Reference in New Issue
Block a user