Adding product property filter to shop page

This commit is contained in:
Rob Harrington
2015-03-06 11:22:52 +11:00
parent 55b8918ea1
commit 06f10398da
12 changed files with 105 additions and 50 deletions

View File

@@ -0,0 +1,7 @@
Darkswarm.filter 'propertiesOf', ->
(objects)->
properties = {}
for object in objects
for property in object.properties
properties[property.id] = property
properties

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -0,0 +1,3 @@
class Api::IdNameSerializer < ActiveModel::Serializer
attributes :id, :name
end

View File

@@ -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

View File

@@ -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

View File

@@ -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"}

View File

@@ -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

View File

@@ -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']

View File

@@ -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}]

View File

@@ -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]