Merge branch 'master' of github.com:openfoodfoundation/openfoodnetwork into sign_up_email_i18n

This commit is contained in:
Maikel Linke
2016-08-19 09:27:17 +10:00
154 changed files with 3490 additions and 1679 deletions

View File

@@ -45,7 +45,7 @@ script:
after_success:
- >
if [ "$GITHUB_DEPLOY" = "true" -a "$TRAVIS_PULL_REQUEST" = "false" -a -n "$TRAVIS_BRANCH" -a -n "$GITHUB_API_SECRET" ]; then
if [ "$GITHUB_DEPLOY" = "true" -a "$TRAVIS_PULL_REQUEST" = "false" -a -n "$TRAVIS_BRANCH" -a "$TRAVIS_BRANCH" != "transifex" -a -n "$GITHUB_API_SECRET" ]; then
description="`git show "$TRAVIS_BRANCH" -s --oneline --no-color`"
data="{
\"ref\":\"$TRAVIS_BRANCH\",

View File

@@ -21,7 +21,6 @@ gem 'spree_paypal_express', :github => "openfoodfoundation/better_spree_paypal_e
gem 'delayed_job_active_record'
gem 'daemons'
gem 'comfortable_mexican_sofa'
# Fix bug in simple_form preventing collection_check_boxes usage within form_for block
# When merged, revert to upstream gem

View File

@@ -121,7 +121,6 @@ GEM
rack-cache (~> 1.2)
rack-test (~> 0.6.1)
sprockets (~> 2.2.1)
active_link_to (1.0.0)
active_model_serializers (0.8.3)
activemodel (>= 3.0)
activemerchant (1.57.0)
@@ -202,10 +201,6 @@ GEM
coffee-script-source (1.10.0)
colorize (0.7.7)
columnize (0.9.0)
comfortable_mexican_sofa (1.6.24)
active_link_to (~> 1.0.0)
paperclip (>= 2.3.0)
rails (>= 3.0.0)
compass (1.0.3)
chunky_png (~> 1.2)
compass-core (~> 1.0.2)
@@ -226,7 +221,7 @@ GEM
safe_yaml (~> 0.9.0)
css_parser (1.3.5)
addressable
css_splitter (0.4.1)
css_splitter (0.4.5)
sprockets (>= 2.0.0)
daemons (1.2.2)
dalli (2.7.2)
@@ -456,7 +451,7 @@ GEM
railties (>= 3.1)
money (5.1.1)
i18n (~> 0.6.0)
multi_json (1.12.0)
multi_json (1.12.1)
multi_xml (0.5.5)
newrelic_rpm (3.12.0.288)
nokogiri (1.6.7.2)
@@ -659,7 +654,6 @@ DEPENDENCIES
bugsnag
capybara
coffee-rails (~> 3.2.1)
comfortable_mexican_sofa
compass-rails
css_splitter
custom_error_message!
@@ -735,4 +729,4 @@ DEPENDENCIES
wkhtmltopdf-binary
BUNDLED WITH
1.11.2
1.12.5

View File

@@ -2,7 +2,7 @@
# Add your own tasks in files placed in lib/tasks ending in .rake,
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
require File.expand_path('../config/application', __FILE__)
require_relative 'config/application'
Openfoodnetwork::Application.load_tasks

View File

@@ -24,7 +24,7 @@ angular.module("admin.indexUtils").directive "objForUpdate", (switchClass, pendi
scope.savedValue = value
scope.success = ->
switchClass( element, "update-success", ["update-pending", "update-error"], 3000 )
switchClass( element, "update-success", ["update-pending", "update-error"], 5000 )
scope.pending = ->
switchClass( element, "update-pending", ["update-error", "update-success"], false )

View File

@@ -1,10 +1,2 @@
Darkswarm.controller "CartCtrl", ($scope, Cart, $timeout) ->
$scope.Cart = Cart
initializing = true
$scope.$watchCollection "Cart.line_items_present()", ->
if initializing
$timeout ->
initializing = false
else
$scope.Cart.orderChanged()

View File

@@ -1,4 +1,4 @@
Darkswarm.controller "EnterprisesCtrl", ($scope, $rootScope, $timeout, Enterprises, Search, $document, HashNavigation, FilterSelectorsService, EnterpriseModal, enterpriseMatchesNameQueryFilter, distanceWithinKmFilter) ->
Darkswarm.controller "EnterprisesCtrl", ($scope, $rootScope, $timeout, $location, Enterprises, Search, $document, HashNavigation, FilterSelectorsService, EnterpriseModal, enterpriseMatchesNameQueryFilter, distanceWithinKmFilter) ->
$scope.Enterprises = Enterprises
$scope.producers_to_filter = Enterprises.producers
$scope.filterSelectors = FilterSelectorsService.createSelectors()
@@ -21,6 +21,12 @@ Darkswarm.controller "EnterprisesCtrl", ($scope, $rootScope, $timeout, Enterpris
Enterprises.calculateDistance query, $scope.firstNameMatch()
$rootScope.$broadcast 'enterprisesChanged'
$timeout ->
if $location.search()['show_closed']?
$scope.showClosedShops()
$scope.$watch "filtersActive", (value) ->
$scope.$broadcast 'filtersToggled'
$rootScope.$on "enterprisesChanged", ->
$scope.filterEnterprises()
@@ -30,7 +36,7 @@ Darkswarm.controller "EnterprisesCtrl", ($scope, $rootScope, $timeout, Enterpris
# When filter settings change, this could change which name match is at the top, or even
# result in no matches. This affects the reference point that the distance matches are
# calculated from, so we need to recalculate distances.
$scope.$watch '[activeTaxons, shippingTypes, show_profiles]', ->
$scope.$watch '[activeTaxons, activeProperties, shippingTypes, show_profiles]', ->
$timeout ->
Enterprises.calculateDistance $scope.query, $scope.firstNameMatch()
$rootScope.$broadcast 'enterprisesChanged'
@@ -69,6 +75,8 @@ Darkswarm.controller "EnterprisesCtrl", ($scope, $rootScope, $timeout, Enterpris
$scope.showClosedShops = ->
delete $scope.filterExpression['active']
$location.search('show_closed', '1')
$scope.hideClosedShops = ->
$scope.filterExpression['active'] = true
$location.search('show_closed', null)

View File

@@ -8,3 +8,6 @@ Darkswarm.controller "GroupEnterprisesCtrl", ($scope, Search, FilterSelectorsSer
$scope.$watch "query", (query)->
Search.search query
$scope.$watch "filtersActive", (value) ->
$scope.$broadcast 'filtersToggled'

View File

@@ -1,3 +1,7 @@
Darkswarm.controller "GroupsCtrl", ($scope, Groups) ->
Darkswarm.controller "GroupsCtrl", ($scope, Groups, Search) ->
$scope.Groups = Groups
$scope.order = 'position'
$scope.query = Search.search()
$scope.$watch "query", (query)->
Search.search query

View File

@@ -1,5 +0,0 @@
Darkswarm.controller "LineItemCtrl", ($scope)->
$scope.$watch '[line_item.quantity, line_item.max_quantity]', (newValue, oldValue)->
if newValue != oldValue
$scope.Cart.orderChanged()
, true

View File

@@ -1,18 +1,41 @@
Darkswarm.controller "ProductsCtrl", ($scope, $rootScope, Products, OrderCycle, FilterSelectorsService, Cart, Taxons, Properties) ->
Darkswarm.controller "ProductsCtrl", ($scope, $filter, $rootScope, Products, OrderCycle, FilterSelectorsService, Cart, Taxons, Properties) ->
$scope.Products = Products
$scope.Cart = Cart
$scope.query = ""
$scope.taxonSelectors = FilterSelectorsService.createSelectors()
$scope.propertySelectors = FilterSelectorsService.createSelectors()
$scope.filtersActive = true
$scope.limit = 3
$scope.limit = 10
$scope.order_cycle = OrderCycle.order_cycle
# $scope.infiniteDisabled = true
# All of this logic basically just replicates the functionality filtering an ng-repeat
# except that it allows us to filter a separate list before rendering, meaning that
# we can get much better performance when applying filters by resetting the limit on the
# number of products being rendered each time a filter is changed.
$scope.$watch "Products.loading", (newValue, oldValue) ->
$scope.updateFilteredProducts()
$scope.$broadcast("loadFilterSelectors") if !newValue
$scope.incrementLimit = ->
if $scope.limit < Products.products.length
$scope.limit = $scope.limit + 1
$scope.limit += 10
$scope.updateVisibleProducts()
$scope.$watch 'query', -> $scope.updateFilteredProducts()
$scope.$watchCollection 'activeTaxons', -> $scope.updateFilteredProducts()
$scope.$watchCollection 'activeProperties', -> $scope.updateFilteredProducts()
$scope.updateFilteredProducts = ->
$scope.limit = 10
f1 = $filter('products')(Products.products, $scope.query)
f2 = $filter('taxons')(f1, $scope.activeTaxons)
$scope.filteredProducts = $filter('properties')(f2, $scope.activeProperties)
$scope.updateVisibleProducts()
$scope.updateVisibleProducts = ->
$scope.visibleProducts = $filter('limitTo')($scope.filteredProducts, $scope.limit)
$scope.searchKeypress = (e)->
code = e.keyCode || e.which

View File

@@ -1,9 +1,15 @@
Darkswarm.directive "enterpriseModal", ($modal)->
Darkswarm.directive "enterpriseModal", ($modal, Enterprises, EnterpriseResource) ->
restrict: 'E'
replace: true
template: "<a ng-transclude></a>"
transclude: true
link: (scope, elem, attrs, ctrl)->
elem.on "click", (ev)=>
link: (scope, elem, attrs, ctrl) ->
elem.on "click", (ev) =>
ev.stopPropagation()
params =
id: scope.enterprise.id
EnterpriseResource.relatives params, (data) =>
Enterprises.addEnterprises data
scope.enterprise = Enterprises.enterprises_by_id[scope.enterprise.id]
Enterprises.dereferenceEnterprise scope.enterprise
scope.modalInstance = $modal.open(controller: ctrl, templateUrl: 'enterprise_modal.html', scope: scope)

View File

@@ -0,0 +1,21 @@
Darkswarm.directive 'mapOsmTiles', ($timeout) ->
restrict: 'E'
require: '^googleMap'
scope: {}
link: (scope, elem, attrs, ctrl) ->
$timeout =>
map = ctrl.getMap()
map.mapTypes.set 'OSM', new google.maps.ImageMapType
getTileUrl: (coord, zoom) ->
# "Wrap" x (logitude) at 180th meridian properly
# NB: Don't touch coord.x because coord param is by reference, and changing its x property breaks something in Google's lib
tilesPerGlobe = 1 << zoom
x = coord.x % tilesPerGlobe
if x < 0
x = tilesPerGlobe + x
# Wrap y (latitude) in a like manner if you want to enable vertical infinite scroll
'http://tile.openstreetmap.org/' + zoom + '/' + x + '/' + coord.y + '.png'
tileSize: new google.maps.Size(256, 256)
name: 'OpenStreetMap'
maxZoom: 18

View File

@@ -1,46 +1,54 @@
Darkswarm.directive 'mapSearch', ($timeout)->
Darkswarm.directive 'mapSearch', ($timeout, Search) ->
# Install a basic search field in a map
restrict: 'E'
require: '^googleMap'
require: ['^googleMap', 'ngModel']
replace: true
template: '<input id="pac-input" placeholder="' + t('location_placeholder') + '"></input>'
link: (scope, elem, attrs, ctrl)->
template: '<input id="pac-input" ng-model="query" placeholder="' + t('location_placeholder') + '"></input>'
scope: {}
controller: ($scope) ->
$scope.query = Search.search()
$scope.$watch 'query', (query) ->
Search.search query
link: (scope, elem, attrs, ctrls) ->
[ctrl, model] = ctrls
scope.input = document.getElementById("pac-input")
$timeout =>
map = ctrl.getMap()
# Use OSM tiles server
map.mapTypes.set 'OSM', new (google.maps.ImageMapType)(
getTileUrl: (coord, zoom) ->
# "Wrap" x (logitude) at 180th meridian properly
# NB: Don't touch coord.x because coord param is by reference, and changing its x property breakes something in Google's lib
tilesPerGlobe = 1 << zoom
x = coord.x % tilesPerGlobe
if x < 0
x = tilesPerGlobe + x
# Wrap y (latitude) in a like manner if you want to enable vertical infinite scroll
'http://tile.openstreetmap.org/' + zoom + '/' + x + '/' + coord.y + '.png'
tileSize: new (google.maps.Size)(256, 256)
name: 'OpenStreetMap'
maxZoom: 18)
searchBox = scope.createSearchBox map
scope.bindSearchResponse map, searchBox
scope.biasResults map, searchBox
scope.performUrlSearch map
input = (document.getElementById("pac-input"))
map.controls[google.maps.ControlPosition.TOP_LEFT].push input
searchBox = new google.maps.places.SearchBox((input))
scope.createSearchBox = (map) ->
map.controls[google.maps.ControlPosition.TOP_LEFT].push scope.input
return new google.maps.places.SearchBox(scope.input)
google.maps.event.addListener searchBox, "places_changed", ->
places = searchBox.getPlaces()
return if places.length is 0
# For each place, get the icon, place name, and location.
markers = []
bounds = new google.maps.LatLngBounds()
for place in places
#map.setCenter place.geometry.location
map.fitBounds place.geometry.viewport
#map.fitBounds bounds
scope.bindSearchResponse = (map, searchBox) ->
google.maps.event.addListener searchBox, "places_changed", =>
scope.showSearchResult map, searchBox
# Bias the SearchBox results towards places that are within the bounds of the
# current map's viewport.
scope.showSearchResult = (map, searchBox) ->
places = searchBox.getPlaces()
for place in places when place.geometry.viewport?
map.fitBounds place.geometry.viewport
scope.$apply ->
model.$setViewValue elem.val()
# When the map loads, and we have a search from ?query, perform that search
scope.performUrlSearch = (map) ->
google.maps.event.addListenerOnce map, "idle", =>
google.maps.event.trigger(scope.input, 'focus');
google.maps.event.trigger(scope.input, 'keydown', {keyCode: 13});
# Bias the SearchBox results towards places that are within the bounds of the
# current map's viewport.
scope.biasResults = (map, searchBox) ->
google.maps.event.addListener map, "bounds_changed", ->
bounds = map.getBounds()
searchBox.setBounds bounds

View File

@@ -1,6 +1,9 @@
Darkswarm.directive "shopVariant", ->
Darkswarm.directive "shopVariant", ->
restrict: 'E'
replace: true
templateUrl: 'shop_variant.html'
scope:
variant: '='
controller: ($scope, Cart) ->
$scope.$watchGroup ['variant.line_item.quantity', 'variant.line_item.max_quantity'], ->
Cart.adjust($scope.variant.line_item)

View File

@@ -6,40 +6,15 @@ Darkswarm.directive 'singleLineSelectors', ($timeout, $filter) ->
objects: "&"
activeSelectors: "="
selectorName: "@activeSelectors"
link: (scope,element,attrs) ->
link: (scope, element, attrs) ->
scope.fitting = false
scope.overFlowSelectors = ->
return [] unless scope.allSelectors?
$filter('filter')(scope.allSelectors, { fits: false })
scope.selectedOverFlowSelectors = ->
$filter('filter')(scope.overFlowSelectors(), { active: true })
# had to duplicate this to make overflow selectors work
scope.emit = ->
scope.activeSelectors = scope.allSelectors.filter (selector)->
selector.active
.map (selector)->
selector.object.id
# From: http://stackoverflow.com/questions/4298612/jquery-how-to-call-resize-event-only-once-its-finished-resizing
debouncer = (func, timeout) ->
timeoutID = undefined
timeout = timeout or 50
->
subject = this
args = arguments
clearTimeout timeoutID
timeoutID = setTimeout(->
func.apply subject, Array::slice.call(args)
, timeout)
loadWidths = ->
$(element).find("li").not(".more").each (i) ->
scope.allSelectors[i].width = $(this).outerWidth(true)
return null # So we don't exit the loop weirdly
scope.refit = ->
if scope.allSelectors?
scope.fitting = true
selector.fits = true for selector in scope.allSelectors
$timeout(loadWidths, 0, true).then ->
$timeout fit, 0, true
fit = ->
used = $(element).find("li.more").outerWidth(true)
@@ -61,12 +36,45 @@ Darkswarm.directive 'singleLineSelectors', ($timeout, $filter) ->
available += selector.width
scope.fitting = false
loadWidths = ->
$(element).find("li").not(".more").each (i) ->
if i < scope.allSelectors.length
scope.allSelectors[i].width = $(this).outerWidth(true)
return null # So we don't exit the loop weirdly
scope.overFlowSelectors = ->
return [] unless scope.allSelectors?
$filter('filter')(scope.allSelectors, { fits: false })
scope.selectedOverFlowSelectors = ->
$filter('filter')(scope.overFlowSelectors(), { active: true })
# had to duplicate this to make overflow selectors work
scope.emit = ->
scope.activeSelectors = scope.allSelectors.filter (selector)->
selector.active
.map (selector) ->
selector.object.id
# From: http://stackoverflow.com/questions/4298612/jquery-how-to-call-resize-event-only-once-its-finished-resizing
debouncer = (func, timeout) ->
timeoutID = undefined
timeout = timeout or 50
->
subject = this
args = arguments
clearTimeout timeoutID
timeoutID = setTimeout(->
func.apply subject, Array::slice.call(args)
, timeout)
# -- Event management
scope.$watchCollection "allSelectors", ->
if scope.allSelectors?
scope.fitting = true
selector.fits = true for selector in scope.allSelectors
$timeout(loadWidths, 0, true).then ->
$timeout fit, 0, true
scope.refit()
scope.$on "filtersToggled", ->
scope.refit()
$(window).resize debouncer (e) ->
scope.fitting = true

View File

@@ -0,0 +1,15 @@
Darkswarm.directive "ofnSmoothScrollTo", ($location, $document)->
# Onclick sets $location.hash to attrs.ofnScrollTo
# Then triggers $document.scrollTo
restrict: 'A'
link: (scope, element, attrs)->
element.bind 'click', (ev)->
ev.stopPropagation()
$location.hash attrs.ofnScrollTo
target = $("a[name='#{attrs.ofnSmoothScrollTo}']")
# Scrolling is confused by our position:fixed top bar and page alert bar
# - add an offset to scroll to the correct location, plus 5px buffer
offset = $("nav.top-bar").height()
offset += $(".page-alert.move-down").height()
offset += 5
$document.scrollTo target, offset, 1000

View File

@@ -1,7 +1,8 @@
Darkswarm.filter 'products', (Matcher)->
(products, text)->
Darkswarm.filter 'products', (Matcher) ->
(products, text) ->
products ||= []
text ?= ""
products.filter (product)=>
return products if text == ""
products.filter (product) =>
propertiesToMatch = [product.name, product.supplier.name, product.primary_taxon.name]
Matcher.match propertiesToMatch, text

View File

@@ -11,7 +11,15 @@ Darkswarm.factory 'Cart', (CurrentOrder, Variants, $timeout, $http, $modal, $roo
for line_item in @line_items
line_item.variant.line_item = line_item
Variants.register line_item.variant
line_item.variant.extended_name = @extendedVariantName(line_item.variant)
adjust: (line_item) =>
line_item.total_price = line_item.variant.price_with_fees * line_item.quantity
if line_item.quantity > 0
@line_items.push line_item unless line_item in @line_items
else
index = @line_items.indexOf(line_item)
@line_items.splice(index, 1) if index >= 0
@orderChanged()
orderChanged: =>
@unsaved()
@@ -48,7 +56,7 @@ Darkswarm.factory 'Cart', (CurrentOrder, Variants, $timeout, $http, $modal, $roo
# TODO: These changes to quantity/max_quantity trigger another cart update, which
# is unnecessary.
for li in @line_items_present()
for li in @line_items when li.quantity > 0
if stockLevels[li.variant.id]?
li.variant.count_on_hand = stockLevels[li.variant.id].on_hand
if li.quantity > li.variant.count_on_hand
@@ -67,7 +75,7 @@ Darkswarm.factory 'Cart', (CurrentOrder, Variants, $timeout, $http, $modal, $roo
data: =>
variants = {}
for li in @line_items_present()
for li in @line_items when li.quantity > 0
variants[li.variant.id] =
quantity: li.quantity
max_quantity: li.max_quantity
@@ -89,45 +97,21 @@ Darkswarm.factory 'Cart', (CurrentOrder, Variants, $timeout, $http, $modal, $roo
$(window).bind "beforeunload", ->
t 'order_not_saved_yet'
line_items_present: =>
@line_items.filter (li)->
li.quantity > 0
total_item_count: =>
@line_items_present().reduce (sum,li) ->
@line_items.reduce (sum,li) ->
sum = sum + li.quantity
, 0
empty: =>
@line_items_present().length == 0
@line_items.length == 0
total: =>
@line_items_present().map (li)->
li.variant.totalPrice()
@line_items.map (li)->
li.total_price
.reduce (t, price)->
t + price
, 0
register_variant: (variant)=>
exists = @line_items.some (li)-> li.variant == variant
@create_line_item(variant) unless exists
clear: ->
@line_items = []
storage.clearAll() # One day this will have to be moar GRANULAR
create_line_item: (variant)->
variant.extended_name = @extendedVariantName(variant)
variant.line_item =
variant: variant
quantity: null
max_quantity: null
@line_items.push variant.line_item
extendedVariantName: (variant) =>
if variant.product_name == variant.name_to_display
variant.product_name
else
name = "#{variant.product_name} - #{variant.name_to_display}"
name += " (#{variant.options_text})" if variant.options_text
name

View File

@@ -1,6 +1,17 @@
Darkswarm.factory 'Dereferencer', ->
new class Dereferencer
dereference: (array, data)->
if array
for object, i in array
array[i] = data[object.id]
dereference: (array, data) ->
@dereference_from(array, array, data)
dereference_from: (source, target, data) ->
unreferenced = []
if source && target
for object, i in source
# skip empty entries in sparse array
continue unless source.hasOwnProperty(i)
key = object?.id
if data.hasOwnProperty(key)
target[i] = data[key]
else
unreferenced[i] = object
unreferenced

View File

@@ -0,0 +1,8 @@
Darkswarm.factory 'EnterpriseResource', ($resource) ->
$resource('/enterprise/:id.json', {}, {
'relatives':
method: 'GET'
url: '/enterprises/:id/relatives.json'
isArray: true
cache: true
})

View File

@@ -1,4 +1,4 @@
Darkswarm.factory 'Enterprises', (enterprises, CurrentHub, Taxons, Dereferencer, visibleFilter, Matcher, Geo, $rootScope)->
Darkswarm.factory 'Enterprises', (enterprises, CurrentHub, Taxons, Dereferencer, visibleFilter, Matcher, Geo, $rootScope) ->
new class Enterprises
enterprises_by_id: {}
constructor: ->
@@ -9,7 +9,6 @@ Darkswarm.factory 'Enterprises', (enterprises, CurrentHub, Taxons, Dereferencer,
@enterprises_by_id[enterprise.id] = enterprise
# Replace enterprise and taxons ids with actual objects.
@dereferenceEnterprises()
@dereferenceTaxons()
@visible_enterprises = visibleFilter @enterprises
@producers = @visible_enterprises.filter (enterprise)->
enterprise.category in ["producer_hub", "producer_shop", "producer"]
@@ -20,13 +19,27 @@ Darkswarm.factory 'Enterprises', (enterprises, CurrentHub, Taxons, Dereferencer,
if CurrentHub.hub?.id
CurrentHub.hub = @enterprises_by_id[CurrentHub.hub.id]
for enterprise in @enterprises
Dereferencer.dereference enterprise.hubs, @enterprises_by_id
Dereferencer.dereference enterprise.producers, @enterprises_by_id
@dereferenceEnterprise enterprise
dereferenceTaxons: ->
for enterprise in @enterprises
Dereferencer.dereference enterprise.taxons, Taxons.taxons_by_id
Dereferencer.dereference enterprise.supplied_taxons, Taxons.taxons_by_id
dereferenceEnterprise: (enterprise) ->
@dereferenceProperty(enterprise, 'hubs', @enterprises_by_id)
@dereferenceProperty(enterprise, 'producers', @enterprises_by_id)
@dereferenceProperty(enterprise, 'taxons', Taxons.taxons_by_id)
@dereferenceProperty(enterprise, 'supplied_taxons', Taxons.taxons_by_id)
dereferenceProperty: (enterprise, property, data) ->
# keep unreferenced enterprise ids
# in case we dereference again after adding more enterprises
enterprise.unreferenced |= {}
collection = enterprise[property]
unreferenced = enterprise.unreferenced[property] || collection
enterprise.unreferenced[property] =
Dereferencer.dereference_from unreferenced, collection, data
addEnterprises: (new_enterprises) ->
return unless new_enterprises && new_enterprises.length
for enterprise in new_enterprises
@enterprises_by_id[enterprise.id] = enterprise
flagMatching: (query) ->
for enterprise in @enterprises

View File

@@ -17,7 +17,6 @@ Darkswarm.factory 'Products', ($resource, Enterprises, Dereferencer, Taxons, Pro
@extend()
@dereference()
@registerVariants()
@registerVariantsWithCart()
@loading = false
extend: ->
@@ -44,15 +43,7 @@ Darkswarm.factory 'Products', ($resource, Enterprises, Dereferencer, Taxons, Pro
registerVariants: ->
for product in @products
if product.variants
product.variants = (Variants.register variant for variant in product.variants)
variant.product = product for variant in product.variants
if product.master
product.master.product = product
product.master = Variants.register product.master
registerVariantsWithCart: ->
for product in @products
if product.variants
for variant in product.variants
Cart.register_variant variant
Cart.register_variant product.master if product.master
product.variants = for variant in product.variants
variant = Variants.register variant
variant.product = product
variant

View File

@@ -9,8 +9,21 @@ Darkswarm.factory 'Variants', ->
@variants[variant.id] ||= @extend variant
extend: (variant)->
# Add totalPrice method to calculate line item total. This should be on a line item!
variant.totalPrice = ->
variant.price_with_fees * variant.line_item.quantity
variant.basePricePercentage = Math.round(variant.price / variant.price_with_fees * 100)
variant.extended_name = @extendedVariantName(variant)
variant.base_price_percentage = Math.round(variant.price / variant.price_with_fees * 100)
variant.line_item ||= @lineItemFor(variant) # line_item may have been initialised in Cart#constructor
variant.line_item.total_price = variant.price_with_fees * variant.line_item.quantity
variant
extendedVariantName: (variant) =>
if variant.product_name == variant.name_to_display
variant.product_name
else
name = "#{variant.product_name} - #{variant.name_to_display}"
name += " (#{variant.options_text})" if variant.options_text
name
lineItemFor: (variant) ->
variant: variant
quantity: null
max_quantity: null

View File

@@ -1,2 +1,2 @@
/* ng-infinite-scroll - v1.0.0 - 2013-02-23 */
var mod;mod=angular.module("infinite-scroll",[]),mod.directive("infiniteScroll",["$rootScope","$window","$timeout",function(i,n,e){return{link:function(t,l,o){var r,c,f,a;return n=angular.element(n),f=0,null!=o.infiniteScrollDistance&&t.$watch(o.infiniteScrollDistance,function(i){return f=parseInt(i,10)}),a=!0,r=!1,null!=o.infiniteScrollDisabled&&t.$watch(o.infiniteScrollDisabled,function(i){return a=!i,a&&r?(r=!1,c()):void 0}),c=function(){var e,c,u,d;return d=n.height()+n.scrollTop(),e=l.offset().top+l.height(),c=e-d,u=n.height()*f>=c,u&&a?i.$$phase?t.$eval(o.infiniteScroll):t.$apply(o.infiniteScroll):u?r=!0:void 0},n.on("scroll",c),t.$on("$destroy",function(){return n.off("scroll",c)}),e(function(){return o.infiniteScrollImmediateCheck?t.$eval(o.infiniteScrollImmediateCheck)?c():void 0:c()},0)}}}]);
/* ng-infinite-scroll - v1.3.0 - 2016-06-30 */
angular.module("infinite-scroll",[]).value("THROTTLE_MILLISECONDS",null).directive("infiniteScroll",["$rootScope","$window","$interval","THROTTLE_MILLISECONDS",function(a,b,c,d){return{scope:{infiniteScroll:"&",infiniteScrollContainer:"=",infiniteScrollDistance:"=",infiniteScrollDisabled:"=",infiniteScrollUseDocumentBottom:"=",infiniteScrollListenForEvent:"@"},link:function(e,f,g){var h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z;return z=angular.element(b),u=null,v=null,j=null,k=null,r=!0,y=!1,x=null,i=!1,q=function(a){return a=a[0]||a,isNaN(a.offsetHeight)?a.document.documentElement.clientHeight:a.offsetHeight},s=function(a){if(a[0].getBoundingClientRect&&!a.css("none"))return a[0].getBoundingClientRect().top+t(a)},t=function(a){return a=a[0]||a,isNaN(window.pageYOffset)?a.document.documentElement.scrollTop:a.ownerDocument.defaultView.pageYOffset},p=function(){var b,d,g,h,l;return k===z?(b=q(k)+t(k[0].document.documentElement),g=s(f)+q(f)):(b=q(k),d=0,void 0!==s(k)&&(d=s(k)),g=s(f)-d+q(f)),y&&(g=q((f[0].ownerDocument||f[0].document).documentElement)),h=g-b,l=h<=q(k)*u+1,l?(j=!0,v?e.$$phase||a.$$phase?e.infiniteScroll():e.$apply(e.infiniteScroll):void 0):(i&&c.cancel(i),j=!1)},w=function(a,b){var d,e,f;return f=null,e=0,d=function(){return e=(new Date).getTime(),c.cancel(f),f=null,a.call()},function(){var g,h;return g=(new Date).getTime(),h=b-(g-e),h<=0?(c.cancel(f),f=null,e=g,a.call()):f?void 0:f=c(d,h,1)}},null!=d&&(p=w(p,d)),e.$on("$destroy",function(){if(k.unbind("scroll",p),null!=x&&(x(),x=null),i)return c.cancel(i)}),n=function(a){return u=parseFloat(a)||0},e.$watch("infiniteScrollDistance",n),n(e.infiniteScrollDistance),m=function(a){if(v=!a,v&&j)return j=!1,p()},e.$watch("infiniteScrollDisabled",m),m(e.infiniteScrollDisabled),o=function(a){return y=a},e.$watch("infiniteScrollUseDocumentBottom",o),o(e.infiniteScrollUseDocumentBottom),h=function(a){if(null!=k&&k.unbind("scroll",p),k=a,null!=a)return k.bind("scroll",p)},h(z),e.infiniteScrollListenForEvent&&(x=a.$on(e.infiniteScrollListenForEvent,p)),l=function(a){if(null!=a&&0!==a.length){if(a.nodeType&&1===a.nodeType?a=angular.element(a):"function"==typeof a.append?a=angular.element(a[a.length-1]):"string"==typeof a&&(a=angular.element(document.querySelector(a))),null!=a)return h(a);throw new Error("invalid infinite-scroll-container attribute.")}},e.$watch("infiniteScrollContainer",l),l(e.infiniteScrollContainer||[]),null!=g.infiniteScrollParent&&h(angular.element(f.parent())),null!=g.infiniteScrollImmediateCheck&&(r=e.$eval(g.infiniteScrollImmediateCheck)),i=c(function(){return r&&p(),c.cancel(i)})}}}]),"undefined"!=typeof module&&"undefined"!=typeof exports&&module.exports===exports&&(module.exports="infinite-scroll");

View File

@@ -9,4 +9,4 @@
"ng-model" => "variant.line_item.quantity",
"ofn-on-hand" => "{{variant.on_demand && 9999 || variant.count_on_hand }}",
"ng-disabled" => "!variant.on_demand && variant.count_on_hand == 0",
name: "variants[{{variant.id}}]", id: "variants_{{variant.id}}"}
name: "variants[{{::variant.id}}]", id: "variants_{{::variant.id}}"}

View File

@@ -1,4 +1,5 @@
.small-5.medium-3.large-3.columns.text-right{"ng-if" => "::variant.product.group_buy"}
%span.bulk-input-container
%span.bulk-input
%input.bulk.first{type: :number,
@@ -6,18 +7,18 @@
integer: true,
min: 0,
"ng-model" => "variant.line_item.quantity",
placeholder: "{{'shop_variant_quantity_min' | t}}",
placeholder: "{{::'shop_variant_quantity_min' | t}}",
"ofn-disable-scroll" => true,
"ofn-on-hand" => "{{variant.on_demand && 9999 || variant.count_on_hand }}",
name: "variants[{{variant.id}}]", id: "variants_{{variant.id}}"}
name: "variants[{{::variant.id}}]", id: "variants_{{::variant.id}}"}
%span.bulk-input
%input.bulk.second{type: :number,
"ng-disabled" => "!variant.line_item.quantity",
integer: true,
min: 0,
"ng-model" => "variant.line_item.max_quantity",
placeholder: "{{'shop_variant_quantity_max' | t}}",
placeholder: "{{::'shop_variant_quantity_max' | t}}",
"ofn-disable-scroll" => true,
min: "{{variant.line_item.quantity}}",
name: "variant_attributes[{{variant.id}}][max_quantity]",
id: "variants_{{variant.id}}_max"}
name: "variant_attributes[{{::variant.id}}][max_quantity]",
id: "variants_{{::variant.id}}_max"}

View File

@@ -2,7 +2,7 @@
%span.joyride-nub.right
.joyride-content-wrapper
.collapsed{"ng-show" => "!expanded"}
%price-percentage{percentage: 'variant.basePricePercentage'}
%price-percentage{percentage: 'variant.base_price_percentage'}
%a{"ng-click" => "expanded = !expanded"}
%span{"ng-bind" => "::'price_breakdown' | t"}
%i.ofn-i_005-caret-down
@@ -10,26 +10,26 @@
.expanded{"ng-show" => "expanded"}
%ul
%li.cost
.right {{ variant.price | localizeCurrency }}
.right {{ ::variant.price | localizeCurrency }}
%span{"ng-bind" => "::'item_cost' | t"}
%li.admin-fee{"ng-if" => "::variant.fees.admin"}
.right {{ variant.fees.admin | localizeCurrency }}
.right {{ ::variant.fees.admin | localizeCurrency }}
%span{"ng-bind" => "::'admin_fee' | t"}
%li.sales-fee{"ng-if" => "::variant.fees.sales"}
.right {{ variant.fees.sales | localizeCurrency }}
.right {{ ::variant.fees.sales | localizeCurrency }}
%span{"ng-bind" => "::'sales_fee' | t"}
%li.packing-fee{"ng-if" => "::variant.fees.packing"}
.right {{ variant.fees.packing | localizeCurrency }}
.right {{ ::variant.fees.packing | localizeCurrency }}
%span{"ng-bind" => "::'packing_fee' | t"}
%li.transport-fee{"ng-if" => "::variant.fees.transport"}
.right {{ variant.fees.transport | localizeCurrency }}
.right {{ ::variant.fees.transport | localizeCurrency }}
%span{"ng-bind" => "::'transport_fee' | t"}
%li.fundraising-fee{"ng-if" => "::variant.fees.fundraising"}
.right {{ variant.fees.fundraising | localizeCurrency }}
.right {{ ::variant.fees.fundraising | localizeCurrency }}
%span{"ng-bind" => "::'fundraising_fee' | t"}
%li.total
%strong
.right = {{ variant.price_with_fees | localizeCurrency }}
.right = {{ ::variant.price_with_fees | localizeCurrency }}
&nbsp;
%a{"ng-click" => "expanded = !expanded"}

View File

@@ -1,5 +1,4 @@
.progress
.right {{'fees' | t}}
.right {{::'fees' | t}}
.meter
{{'item_cost' | t}}
{{::'item_cost' | t}}

View File

@@ -1,23 +1,23 @@
.variants.row
.small-12.medium-4.large-4.columns.variant-name
.table-cell
.inline {{ variant.name_to_display }}
.inline {{ ::variant.name_to_display }}
.bulk-buy.inline{"ng-if" => "::variant.product.group_buy"}
%i.ofn-i_056-bulk><
%em><
\ {{'bulk' | t}}
\ {{::'bulk' | t}}
%ng-include{src: "'partials/shop_variant_no_group_buy.html'"}
%ng-include{src: "'partials/shop_variant_with_group_buy.html'"}
.small-3.medium-1.large-1.columns.variant-unit
.table-cell
%em {{ variant.unit_to_display }}
%em {{ ::variant.unit_to_display }}
.small-4.medium-2.large-2.columns.variant-price
.table-cell.price
%i.ofn-i_009-close
{{ variant.price_with_fees | localizeCurrency }}
{{ ::variant.price_with_fees | localizeCurrency }}
-# Now in a template in app/assets/javascripts/templates !
%price-breakdown{"price-breakdown" => "_", variant: "variant",
@@ -27,5 +27,5 @@
.small-12.medium-2.large-2.columns.total-price.text-right
.table-cell
%strong{"ng-class" => "{filled: variant.totalPrice()}"}
{{ variant.totalPrice() | localizeCurrency }}
%strong{"ng-class" => "{filled: variant.line_item.total_price}"}
{{ variant.line_item.total_price | localizeCurrency }}

View File

@@ -1,4 +0,0 @@
html {
height: auto;
background-color: transparent;
}

View File

@@ -92,6 +92,12 @@
span.filter-label
opacity: 0.75
// singleLineSelectors directive provides a drop-down that can overlap
// content. Ensure that the dropdown appears above the content.
.filter-row
position: relative
z-index: 100
.filter-shopfront
&.taxon-selectors, &.property-selectors
background: transparent

View File

@@ -30,7 +30,7 @@ footer
background-color: transparent
border: none
padding: 0
a.alert-cta
.alert-cta
@include csstrans
width: 100%
border: 1px solid rgba($dark-grey, 0.35)
@@ -44,7 +44,7 @@ footer
color: #333
strong
letter-spacing: 0.5px
&:hover, &:active, &:focus
a:hover, a:active, a:focus
text-decoration: none
border-color: white
&, & *

View File

@@ -4,11 +4,7 @@
// Search page
#groups
background-color: lighten($clr-brick, 56%)
background-image: url("/assets/groups.svg")
background-position: center 50px
background-repeat: no-repeat
background-size: 922px 922px
@include groupsbg
@include sidepaddingSm
@include panepadding
h1, p.text
@@ -23,13 +19,13 @@
text-align: right
a
font-size: 1.5em
.groups-header
border: 2px solid $clr-brick-light-bright
@include border-radius-mixed(0.5em, 0.5em, 0, 0)
margin: -1rem 0 1rem
padding: 1rem 0.9375rem
@media screen and (min-width: 640px)
@media screen and (min-width: 640px)
border: 0 none
@include border-radius(0)
margin: 0
@@ -44,12 +40,12 @@
.ofn-i_035-groups
font-size: 120%
vertical-align: middle
// Individual Page
#group-page
.group-logo, .group-header
text-align: center
.group-logo
text-align: center
.group-logo
padding-bottom: 1em
max-height: 200px
.group-name
@@ -57,7 +53,7 @@
@media screen and (min-width: 768px)
.group-logo, .group-header
text-align: left
.group-logo
.group-logo
max-height: 120px
float: left
padding-right: 1em
@@ -72,18 +68,18 @@
margin-right: 2px
text-transform: capitalize
@include headingFont
@include border-radius(1em 0.25em 0 0)
@include border-radius(1em 0.25em 0 0)
@include gradient($disabled-light, $disabled-bright)
@media screen and (min-width: 768px)
.tabs dd a
padding: 0.5rem 1rem 0.25em
font-size: 0.875rem
@include border-radius(1.5em 0.25em 0 0)
@include border-radius(1.5em 0.25em 0 0)
@media screen and (min-width: 1024px)
.tabs dd a
padding: 0.75rem 1.5rem 0.5em
font-size: 1rem
@include border-radius(2em 0.25em 0 0)
@include border-radius(2em 0.25em 0 0)
.tabs dd.active a
@include gradient(white, white)
margin-bottom: -1px
@@ -110,4 +106,3 @@
background-image: none
padding-top: 0
padding-bottom: 0

View File

@@ -4,7 +4,6 @@
@import animations
@import variables
// Styling for big panes on homepage \\
#panes
.pane
@@ -22,9 +21,15 @@
#system.pane
background-color: white
#brand-story.pane, #cta.pane, #shops.pane
#brand-story.pane, #cta.pane, #shops.pane, #sell.pane
@include tiledPane
#connect.pane
@include groupsbg
#learn.pane
@include hubsbg
#stats.pane
background-image: url("/assets/home/background-blurred-oranges.jpg")
background-position: center center
@@ -94,10 +99,6 @@
@media all and (max-width: 640px)
font-size: 45px
a
color: $brand-colour
.home-icon-box-bottom
margin-top: 1rem
width: 100%
@@ -147,3 +148,9 @@
#shops-signup.pane
background-color: $brand-colour
#sell-detail.pane
margin: 50px 0
.row
padding-top: 25px
padding-bottom: 25px

View File

@@ -170,3 +170,23 @@
// W3C
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='$gradient-clr1', endColorstr='$gradient-clr2',GradientType=0 )
// IE6-8
@mixin producersbg
background-color: lighten($clr-turquoise, 68%)
background-image: url("/assets/producers.svg")
background-position: center 50px
background-repeat: no-repeat
background-size: 922px 763px
@mixin hubsbg
background-color: $brand-colour
background-image: url("/assets/hubs-bg.jpg")
background-position: center center
@mixin groupsbg
background-color: lighten($clr-brick, 56%)
background-image: url("/assets/groups.svg")
background-position: center 50px
background-repeat: no-repeat
background-size: 922px 922px

View File

@@ -21,13 +21,13 @@
font-size: 10px
line-height: 24px
a.alert-cta
.alert-cta
&, & *
@include csstrans
color: #333
strong
letter-spacing: 0.5px
&:hover, &:active, &:focus
a:hover, a:active, a:focus
&, & *
text-decoration: none
color: white

View File

@@ -2,11 +2,7 @@
@import mixins
.producers
background-color: lighten($clr-turquoise, 68%)
background-image: url("/assets/producers.svg")
background-position: center 50px
background-repeat: no-repeat
background-size: 922px 763px
@include producersbg
@include sidepaddingSm
@include panepadding
a

View File

@@ -18,11 +18,9 @@
#producer-case-studies, #shops-case-studies
@include hubsbg
padding-top: 100px
padding-bottom: 100px
background-color: $brand-colour
background-image: url("/assets/hubs-bg.jpg")
background-position: center center
-webkit-filter: brightness(1.1)
filter: brightness(1.1)
h2

View File

@@ -1,3 +1,5 @@
require 'open_food_network/enterprise_injection_data'
class EnterprisesController < BaseController
layout "darkswarm"
helper Spree::ProductsHelper
@@ -11,18 +13,29 @@ class EnterprisesController < BaseController
respond_to :js, only: :permalink_checker
def check_permalink
return render text: params[:permalink], status: 409 if Enterprise.find_by_permalink params[:permalink]
path = Rails.application.routes.recognize_path( "/#{ params[:permalink].to_s }" )
if path && path[:controller] == "cms_content"
render text: params[:permalink], status: 200
else
render text: params[:permalink], status: 409
def relatives
respond_to do |format|
format.json do
enterprise = Enterprise.find(params[:id])
enterprises = enterprise.andand.relatives.andand.activated
render(json: enterprises,
each_serializer: Api::EnterpriseSerializer,
data: OpenFoodNetwork::EnterpriseInjectionData.new)
end
end
end
def check_permalink
render text: params[:permalink], status: 409 and return if Enterprise.find_by_permalink params[:permalink]
begin
Rails.application.routes.recognize_path( "/#{ params[:permalink].to_s }" )
render text: params[:permalink], status: 409
rescue ActionController::RoutingError
render text: params[:permalink], status: 200
end
end
private

View File

@@ -9,4 +9,8 @@ class HomeController < BaseController
@num_orders = Spree::Order.complete.count
end
end
def sell
end
end

View File

@@ -2,13 +2,15 @@ module Admin
module BusinessModelConfigurationHelper
def monthly_bill_description
plus = monthly_bill_includes_fixed? && monthly_bill_includes_rate? ? " + " : ""
ts = trial_description.empty? ? "": " "
ms = minimum_description.empty? ? "": " "
if fixed_description.empty? && rate_description.empty?
t(:free).upcase
elsif monthly_bill_includes_cap? && monthly_bill_includes_rate? # only care about cap if there is a rate too
"#{fixed_description}#{plus}#{rate_description}{joiner}#{cap_description} #{t(:per_month).upcase}#{tax_description.upcase}"
elsif monthly_bill_includes_rate_limits? && monthly_bill_includes_rate? # only care about cap/min-bill-to if there is a rate too
"#{trial_description}#{ts}#{fixed_description}#{plus}#{rate_description}#{ms}#{minimum_description}#{cap_description} #{t(:per_month).upcase}#{tax_description.upcase}"
else
"#{fixed_description}#{plus}#{rate_description} #{t(:per_month).upcase}#{tax_description.upcase}"
"#{trial_description}#{ts}#{fixed_description}#{plus}#{rate_description} #{t(:per_month).upcase}#{tax_description.upcase}"
end
end
@@ -26,13 +28,22 @@ module Admin
def cap_description
cap_amount = Spree::Money.new(Spree::Config[:account_invoices_monthly_cap], { currency: Spree::Config[:currency] }).rounded
monthly_bill_includes_cap? ? "#{t(:capped_at_cap, cap: cap_amount).upcase}" : ""
monthly_bill_includes_cap? ? ", #{t(:capped_at_cap, cap: cap_amount).upcase}" : ""
end
def tax_description
Spree::Config[:account_invoices_tax_rate] > 0 ? ", #{t(:plus_tax).upcase}" : ""
end
def trial_description
Spree::Config[:shop_trial_length_days] > 0 ? "#{t(:free_trial).upcase} #{t(:then).upcase}" : ""
end
def minimum_description
mbt_amount = Spree::Money.new(Spree::Config[:minimum_billable_turnover], { currency: Spree::Config[:currency] }).rounded
monthly_bill_includes_min_turnover? ? "#{t(:min_bill_turnover_desc, mbt_amount: mbt_amount).upcase}" : ""
end
def monthly_bill_includes_fixed?
Spree::Config[:account_invoices_monthly_fixed] > 0
end
@@ -44,5 +55,13 @@ module Admin
def monthly_bill_includes_cap?
Spree::Config[:account_invoices_monthly_cap] > 0
end
def monthly_bill_includes_min_turnover?
Spree::Config[:minimum_billable_turnover] > 1
end
def monthly_bill_includes_rate_limits?
monthly_bill_includes_min_turnover? || monthly_bill_includes_cap?
end
end
end

View File

@@ -1,14 +1,10 @@
module ApplicationHelper
include FoundationRailsHelper::FlashHelper
def home_page_cms_content
if controller.controller_name == 'home' && controller.action_name == 'index'
cms_page_content(:content, Cms::Page.find_by_full_path('/'))
end
def feature?(feature)
OpenFoodNetwork::FeatureToggle.enabled? feature
end
def ng_form_for(name, *args, &block)
options = args.extract_options!

View File

@@ -6,6 +6,7 @@ module CheckoutHelper
# Remove empty tax adjustments and (optionally) shipping fees
adjustments.reject! { |a| a.originator_type == 'Spree::TaxRate' && a.amount == 0 }
adjustments.reject! { |a| a.originator_type == 'Spree::ShippingMethod' } if exclude.include? :shipping
adjustments.reject! { |a| a.originator_type == 'Spree::PaymentMethod' } if exclude.include? :payment
adjustments.reject! { |a| a.source_type == 'Spree::LineItem' } if exclude.include? :line_item
enterprise_fee_adjustments = adjustments.select { |a| a.originator_type == 'EnterpriseFee' && a.source_type != 'Spree::LineItem' }

View File

@@ -5,6 +5,19 @@ module InjectionHelper
inject_json_ams "enterprises", Enterprise.activated.includes(address: :state).all, Api::EnterpriseSerializer, enterprise_injection_data
end
def inject_enterprise_and_relatives
inject_json_ams "enterprises", current_distributor.relatives_including_self.activated.includes(address: :state).all, Api::EnterpriseSerializer, enterprise_injection_data
end
def inject_shop_enterprises
ocs = if current_order_cycle
[current_order_cycle]
else
OrderCycle.not_closed.with_distributor(current_distributor)
end
inject_json_ams "enterprises", current_distributor.plus_relatives_and_oc_producers(ocs).activated.includes(address: :state).all, Api::EnterpriseSerializer, enterprise_injection_data
end
def inject_group_enterprises
inject_json_ams "group_enterprises", @group.enterprises.activated.all, Api::EnterpriseSerializer, enterprise_injection_data
end

View File

@@ -67,10 +67,6 @@ module OrderCyclesHelper
@order_cycles_simple_form ||= @order_cycle.coordinator.sells == 'own'
end
def order_cycles_enabled?
OpenFoodNetwork::FeatureToggle.enabled? :order_cycles
end
def pickup_time(order_cycle = current_order_cycle)
order_cycle.exchanges.to_enterprises(current_distributor).outgoing.first.pickup_time
end

View File

@@ -176,6 +176,16 @@ class Enterprise < ActiveRecord::Base
joins(:enterprise_roles).where('enterprise_roles.user_id = ?', user.id)
end
}
scope :relatives_of_one_union_others, lambda { |one, others|
where("
enterprises.id IN
(SELECT child_id FROM enterprise_relationships WHERE enterprise_relationships.parent_id=?)
OR enterprises.id IN
(SELECT parent_id FROM enterprise_relationships WHERE enterprise_relationships.child_id=?)
OR enterprises.id IN
(?)
", one, one, others)
}
# Force a distinct count to work around relation count issue https://github.com/rails/rails/issues/5554
def self.distinct_count
@@ -220,6 +230,11 @@ class Enterprise < ActiveRecord::Base
", self.id, self.id)
end
def plus_relatives_and_oc_producers(order_cycles)
oc_producer_ids = Exchange.in_order_cycle(order_cycles).incoming.pluck :sender_id
Enterprise.relatives_of_one_union_others(id, oc_producer_ids | [id])
end
def relatives_including_self
Enterprise.where(id: relatives.pluck(:id) | [id])
end

View File

@@ -74,11 +74,7 @@ Spree::Order.class_eval do
# -- Methods
def products_available_from_new_distribution
# Check that the line_items in the current order are available from a newly selected distribution
if OpenFoodNetwork::FeatureToggle.enabled? :order_cycles
errors.add(:base, "Distributor or order cycle cannot supply the products in your cart") unless DistributionChangeValidator.new(self).can_change_to_distribution?(distributor, order_cycle)
else
errors.add(:distributor_id, "cannot supply the products in your cart") unless DistributionChangeValidator.new(self).can_change_to_distributor?(distributor)
end
errors.add(:base, "Distributor or order cycle cannot supply the products in your cart") unless DistributionChangeValidator.new(self).can_change_to_distribution?(distributor, order_cycle)
end
def empty_with_clear_shipping_and_payments!

View File

@@ -5,7 +5,12 @@ module Spree
after_save :ensure_correct_adjustment, :update_order
def ensure_correct_adjustment
if adjustment
# Don't charge for invalid payments.
# PayPalExpress always creates a payment that is invalidated later.
# Unknown: What about failed payments?
if state == "invalid"
adjustment.andand.destroy
elsif adjustment
adjustment.originator = payment_method
adjustment.label = adjustment_label
adjustment.save

View File

@@ -1,5 +0,0 @@
Deface::Override.new(:virtual_path => "spree/admin/shared/_configuration_menu",
:name => "add_cms_admin_to_admin_configurations_menu",
:insert_bottom => "[data-hook='admin_configurations_sidebar_menu']",
:text => "<li><%= link_to 'CMS Admin', main_app.cms_admin_path %></li>",
:original => '29e0ab9c171ffab1988cb439b5d42300b78fe088' )

View File

@@ -1,5 +0,0 @@
Deface::Override.new(:virtual_path => "spree/checkout/_delivery",
:insert_before => "fieldset#shipping_method",
:text => "<%= cms_snippet_content(Cms::Snippet.find_by_identifier('distribution')) %>",
:name => "add_cms_checkout_distribution",
:original => '3b417788fb9a63f464fdaeb8202f483f20518f80')

View File

@@ -1,5 +0,0 @@
Deface::Override.new(:virtual_path => "spree/shared/_main_nav_bar",
:name => "add_cms_tabs_to_main_nav_bar",
:insert_after => "li#home-link",
:partial => "spree/shared/cms_tabs",
:original => '05c6495f8760e58eb68e2cce67433cf7f5299fa4')

View File

@@ -1,5 +0,0 @@
Deface::Override.new(:virtual_path => "spree/orders/edit",
:insert_after => "h1",
:text => "<%= cms_snippet_content(Cms::Snippet.find_by_identifier('cart')) %>",
:name => "add_cms_to_cart",
:original => '206a92e6f50966b057e877321b573bc293787894')

View File

@@ -1,9 +0,0 @@
Deface::Override.new(:virtual_path => "spree/products/index",
:insert_after => "[data-hook='homepage_products']",
:partial => 'spree/shared/multi_cart.html',
:name => 'multi_cart_home')
Deface::Override.new(:virtual_path => "spree/home/index",
:insert_after => "[data-hook='homepage_products']",
:partial => 'spree/shared/multi_cart.html',
:name => 'multi_cart_products')

View File

@@ -1,14 +0,0 @@
Deface::Override.new(:virtual_path => "spree/home/index",
:insert_before => "[data-hook='homepage_products']",
:partial => "order_cycles/selection",
:name => "order_cycle_selection_home")
Deface::Override.new(:virtual_path => "spree/products/index",
:insert_before => "[data-hook='homepage_products']",
:partial => "order_cycles/selection",
:name => "order_cycle_selection_products")
Deface::Override.new(:virtual_path => "spree/taxons/show",
:insert_top => "[data-hook='homepage_products']",
:partial => "order_cycles/selection",
:name => "order_cycle_selection_taxon")

View File

@@ -1,7 +0,0 @@
# In sidebar, always render both taxonomies and filters
Deface::Override.new(:virtual_path => "spree/home/index",
:replace => "[data-hook='homepage_sidebar_navigation']",
:partial => 'spree/sidebar',
:name => 'sidebar_home_index',
:original => 'f5a06c5f558ec681c172ad62ddcf8f84ad0a99c4')

View File

@@ -1,7 +0,0 @@
# In sidebar, always render both taxonomies and filters
Deface::Override.new(:virtual_path => "spree/products/index",
:replace => "[data-hook='homepage_sidebar_navigation']",
:partial => 'spree/sidebar',
:name => 'sidebar_product_index',
:original => 'd9d1b3d18721e1c68eeaac898ca006bf8afb176c')

View File

@@ -1,7 +0,0 @@
# In sidebar, always render both taxonomies and filters
Deface::Override.new(:virtual_path => "spree/taxons/show",
:replace => "[data-hook='taxon_sidebar_navigation']",
:partial => 'spree/sidebar',
:name => 'sidebar_taxons_show',
:original => '697641363ffdb1fce91d8eea7cc883e983236ed2')

View File

@@ -1,5 +0,0 @@
Deface::Override.new(:virtual_path => "spree/home/index",
:replace => "[data-hook='homepage_products']",
:partial => "spree/shared/products_by_distribution",
:name => "split_products_by_distribution_on_home",
:original => '589053f6f3e534b0be729081bdfc0378beb29cca')

View File

@@ -1,5 +0,0 @@
Deface::Override.new(:virtual_path => "spree/products/index",
:replace => "[data-hook='homepage_products']",
:partial => "spree/shared/products_by_distribution",
:name => "split_products_by_distribution_on_products_home",
:original => '22097416de0a5851d43c572301779de06ed84d17')

View File

@@ -1,5 +0,0 @@
Deface::Override.new(:virtual_path => "spree/products/index",
:replace => "[data-hook='search_results']",
:partial => "spree/shared/products_by_distribution",
:name => "split_products_by_distribution_on_products_search",
:original => '5a764faee41bd3f2bb13b60bfeb61e63fede9fac')

View File

@@ -1,5 +0,0 @@
Deface::Override.new(:virtual_path => "spree/taxons/show",
:replace => "[data-hook='taxon_products']",
:partial => "spree/shared/products_by_distribution",
:name => "split_products_by_distribution_on_taxons_show",
:original => '27b6ecd3954022246568b3ddf5e80462aa511ece')

View File

@@ -1,7 +0,0 @@
/ replace_contents "[data-hook='homepage_products']"
- if current_order_cycle
- if @products.empty?
%h6.search-results-title= t(:no_products_found)
- else
= render :partial => 'spree/shared/products', :locals => { :products => @products, :taxon => @taxon }

View File

@@ -21,6 +21,7 @@ end
class Api::UncachedEnterpriseSerializer < ActiveModel::Serializer
attributes :orders_close_at, :active
has_many :properties, serializer: Api::PropertySerializer
def orders_close_at
options[:data].earliest_closing_times[object.id]
@@ -29,6 +30,14 @@ class Api::UncachedEnterpriseSerializer < ActiveModel::Serializer
def active
options[:data].active_distributors.andand.include? object
end
def properties
# This results in 3 queries per enterprise
product_properties = Spree::Property.applied_by(object)
producer_properties = object.properties
OpenFoodNetwork::PropertyMerge.merge product_properties, producer_properties
end
end
class Api::CachedEnterpriseSerializer < ActiveModel::Serializer
@@ -49,8 +58,6 @@ class Api::CachedEnterpriseSerializer < ActiveModel::Serializer
attributes :taxons, :supplied_taxons
has_one :address, serializer: Api::AddressSerializer
has_many :properties, serializer: Api::PropertySerializer
def taxons
ids_to_objs options[:data].distributed_taxons[object.id]
end
@@ -59,14 +66,6 @@ class Api::CachedEnterpriseSerializer < ActiveModel::Serializer
ids_to_objs options[:data].supplied_taxons[object.id]
end
def properties
# This results in 3 queries per enterprise
product_properties = Spree::Property.applied_by(object)
producer_properties = object.properties
OpenFoodNetwork::PropertyMerge.merge product_properties, producer_properties
end
def pickup
services = options[:data].shipping_method_services[object.id]
services ? services[:pickup] : false

View File

@@ -9,7 +9,7 @@
= t :checkout_cart_total
%td.cart-total.text-right= display_checkout_subtotal(@order)
- checkout_adjustments_for(current_order, exclude: [:shipping, :line_item]).reject{ |a| a.amount == 0 }.each do |adjustment|
- checkout_adjustments_for(current_order, exclude: [:shipping, :payment, :line_item]).reject{ |a| a.amount == 0 }.each do |adjustment|
%tr
%th= adjustment.label
%td.text-right= adjustment.display_amount.to_html

View File

@@ -1,7 +1,7 @@
- content_for(:title) do
= t :checkout_title
= inject_enterprises
= inject_enterprise_and_relatives
.darkswarm.footer-pad
- content_for :order_cycle_form do

View File

@@ -5,7 +5,7 @@
- content_for(:image) do
= current_distributor.logo.url
= inject_enterprises
= inject_shop_enterprises
%shop.darkswarm
- content_for :order_cycle_form do

View File

@@ -40,6 +40,7 @@
.map-container
%map{"ng-if" => "(isActive(\'/map\') && (mapShowed = true)) || mapShowed"}
%google-map{options: "map.additional_options", center: "map.center", zoom: "map.zoom", styles: "map.styles", draggable: "true"}
%map-osm-tiles
%map-search
%markers{models: "mapMarkers", fit: "true",
coords: "'self'", icon: "'icon'", click: "'reveal'"}
@@ -66,7 +67,7 @@
.small-12.columns
.active_table
%producer.active_table_node.row.animate-repeat{id: "{{producer.path}}",
"ng-repeat" => "producer in filteredEnterprises = (group_producers | searchEnterprises:query | taxons:activeTaxons)",
"ng-repeat" => "producer in filteredEnterprises = (group_producers | searchEnterprises:query | taxons:activeTaxons | properties:activeProperties)",
"ng-controller" => "GroupEnterpriseNodeCtrl",
"ng-class" => "{'closed' : !open(), 'open' : open(), 'inactive' : !producer.active}",
id: "{{producer.hash}}"}

View File

@@ -0,0 +1,7 @@
#connect.pane
.row
.small-12.medium-6.medium-offset-3.columns.text-center
%h2= t :label_connect
%p.text-normal= t :connect_body
%a.button.transparent{href: "https://openfoodnetwork.org/au/connect/"}
= t :connect_cta

View File

@@ -0,0 +1,7 @@
#learn.pane
.row
.small-12.medium-6.medium-offset-3.columns.text-center
%h2= t :label_learn
%p.text-normal= t :learn_body
%a.button.transparent{href: "https://openfoodnetwork.org/au/learn/"}
= t :learn_cta

View File

@@ -0,0 +1,9 @@
#tagline
.row
.small-12.text-center.columns
%h1
/ TODO: Rohan - logo asset & width is content manageable:
%img{src: "/assets/logo-white-notext.png", width: "250", title: Spree::Config.site_name}
%br/
%a.button.transparent{href: "/shops"}
= t :home_shop

View File

@@ -3,23 +3,21 @@
%div{"ng-controller" => "HomeCtrl"}
= render partial: "shared/menu/alert"
#tagline
.row
.small-12.text-center.columns
%h1
/ TODO: Rohan - logo asset & width is content manageable:
%img{src: "/assets/logo-white-notext.png", width: "250", title: Spree::Config.site_name}
%br/
%a.button.transparent{href: "/shops"}
= t :home_shop
= render "shared/menu/alert"
= render "home/tagline"
#panes
= render partial: "home/brandstory"
= render partial: "home/system"
= render partial: "home/cta"
= render partial: "home/stats"
= render "home/brandstory"
= render partial: "shared/footer"
- if feature? :connect_learn_homepage
= render "home/learn"
= render "home/connect"
= render "home/system"
- else
= render "home/system"
= render "home/cta"
= render "home/stats"
= render "shared/footer"

View File

@@ -0,0 +1,50 @@
- content_for(:title) do
= t :sell_title
#panes
#sell.pane
.row.header
.small-12.medium-12.columns.text-center
%h2
= t :sell_headline
.row.content
.small-12.medium-6.medium-offset-3.columns.text-center
%p.text-big
= t :sell_motivation
#sell-detail.pane
.row
.small-12.medium-4.columns.text-center
%h3= t :sell_producers
%p
= t :sell_producers_detail
%a{href: "https://openfoodnetwork.org/user-guide/"}= t(:sell_user_guide)
%a.button.transparent{href: signup_producers_path}
= t :register_title
.small-12.medium-4.columns.text-center
%h3= t :sell_hubs
%p
= t :sell_hubs_detail
%a{href: "https://openfoodnetwork.org/user-guide/"}= t(:sell_user_guide)
%a.button.transparent{href: signup_shops_path}
= t :register_title
.small-12.medium-4.columns.text-center
%h3= t :sell_groups
%p
= t :sell_groups_detail
%a{href: "https://openfoodnetwork.org/user-guide/"}= t(:sell_user_guide)
%a.button.transparent{href: signup_groups_path}
= t :register_title
.row
.small-12.medium-12.columns.text-center
%p= t :sell_listing_price
%p
= t :sell_embed
%a{href: "hello@openfoodnetwork.org".reverse, target: '_blank', mailto: true}
= t :sell_ask_services
= render "shared/footer"

View File

@@ -1 +0,0 @@
%li= link_to 'Spree Admin', spree.admin_path

View File

@@ -6,6 +6,7 @@
.map-container{"fill-vertical" => true}
%map{"ng-controller" => "MapCtrl"}
%google-map{options: "map.additional_options", center: "map.center", zoom: "map.zoom", styles: "map.styles", draggable: "true"}
%map-osm-tiles
%map-search
%markers{models: "OfnMap.enterprises", fit: "true",
coords: "'self'", icon: "'icon'", click: "'reveal'"}

View File

@@ -1,34 +0,0 @@
/ %script = Spree.api_key = raw(try_spree_current_user.try(:spree_api_key).to_s.inspect)
= t :ofn_cart_headline
= spree_current_user.andand.email
%div{ 'ng-app' => 'store', 'ng-controller' => 'CartCtrl', 'ng-init' => "loadCart(#{spree_current_user.andand.cart.andand.id});" }
{{cart}} {{state}}
%br
%br
%ul
%li(ng-repeat="order in cart.orders")
%strong
= t :ofn_cart_distributor
{{order.distributor}}
%strong
= t :ofn_cart_oc
{{order.order_cycle.andand.name}}
%strong
= t :ofn_cart_from
{{order.order_cycle.andand.orders_open_at}}
%strong
= t :ofn_cart_to
{{order.order_cycle.andand.orders_close_at}}
%ul
%li(ng-repeat="line_item in order.line_items")
%strong
= t :ofn_cart_product
{{line_item.name}}
%strong
= t :ofn_cart_quatity
{{line_item.quantity}}
%button
= t :ofn_cart_send
%br

View File

@@ -1,18 +0,0 @@
- if order_cycles_enabled?
#distribution-choice
- if current_distributor.present?
%p
%strong
= t :ocs_choice_distributor
= current_distributor.name
- if current_order_cycle.present?
%p
%strong
= t :ocs_choice_oc
= current_order_cycle.name
- if current_distributor.nil? && current_order_cycle.nil?
%p
= t :ocs_choice_text

View File

@@ -1,17 +0,0 @@
.columns.two= image_tag 'pickup.png'
.columns.nine
%h2
= t :ocs_closed_headline
%p
- if most_recently_closed = OrderCycle.most_recently_closed_for(@enterprise)
= t :ocs_closed_time, time: distance_of_time_in_words_to_now(most_recently_closed.orders_close_at)
= t :ocs_closed_contact
- if next_oc = OrderCycle.first_opening_for(@enterprise)
%h4
= t :ocs_closed_opens, time: distance_of_time_in_words_to_now(next_oc.orders_open_at)
%p
= t(:ocs_closed_email, email: current_distributor.email_address) if current_distributor.email_address
%br/
= t(:ocs_closed_phone, phone: current_distributor.phone) if current_distributor.phone

View File

@@ -1,12 +0,0 @@
.columns.six
%h1
= t :ocs_pickup_time, pickup_time: pickup_time
%i
= link_to t(:ocs_change_date), spree.clear_orders_path, :id => 'reset_order_cycle'
= t :ocs_change_date_notice
.columns.five
.row
%strong
= t :ocs_close_time
.countdown-panel
%h1= distance_of_time_in_words_to_now(current_order_cycle.orders_close_at)

View File

@@ -1,12 +0,0 @@
.columns.two= image_tag 'pickup.png'
.columns.six
%h2
= t :ocs_when_headline
%p
= t :ocs_when_text
.columns.three
= form_for current_order(true), :html => {:id => 'order_cycle_select'} do |f|
= f.hidden_field :distributor_id, :value => @enterprise.id
.order-cycles
= f.select :order_cycle_id, order_cycle_options, {include_blank: t(:ocs_when_closing)}
= hidden_field_tag :commit, t(:ocs_when_choose)

View File

@@ -1,15 +0,0 @@
- if order_cycles_enabled?
#distribution-selection.row
- if current_order_cycle# && current_order_cycle.exchanges.to_enterprises(current_distributor).outgoing.any?
= render partial: "order_cycles/orders_current"
- elsif order_cycle_options.empty?
= render partial: "order_cycles/orders_closed"
- else
= render partial: "order_cycles/orders_open"
%p
%strong= link_to t(:ocs_list), shop_path

View File

@@ -3,7 +3,7 @@
.small-12.medium-6.columns.text-right
&nbsp;
.row.animate-show{"ng-show" => "filtersActive"}
.row.animate-show.filter-row{"ng-show" => "filtersActive"}
.small-12.columns
.row.filter-box
.small-12.columns
@@ -12,4 +12,12 @@
= t :producers_filter
= t :producers_filter_type
%filter-selector.small-block-grid-2.medium-block-grid-4.large-block-grid-6{"selector-set" => "filterSelectors", objects: "producers_to_filter | searchEnterprises:query | taxonsOf", "active-selectors" => "activeTaxons"}
%h5.tdhead
.light
= t :producers_filter
= t :producers_filter_property
.filter-shopfront.property-selectors
%single-line-selectors{ selectors: "filterSelectors", objects: "producers_to_filter | searchEnterprises:query | propertiesOf", "active-selectors" => "activeProperties"}
= render partial: 'shared/components/filter_box'

View File

@@ -16,7 +16,7 @@
.small-12.columns
.active_table
%producer.active_table_node.row.animate-repeat{id: "{{producer.path}}",
"ng-repeat" => "producer in filteredEnterprises = (Enterprises.producers | visible | searchEnterprises:query | taxons:activeTaxons)",
"ng-repeat" => "producer in filteredEnterprises = (Enterprises.producers | visible | searchEnterprises:query | taxons:activeTaxons | properties:activeProperties)",
"ng-controller" => "ProducerNodeCtrl",
"ng-class" => "{'closed' : !open(), 'open' : open(), 'inactive' : !producer.active}",
id: "{{producer.hash}}"}

View File

@@ -1,19 +0,0 @@
-# Include all stylesheets except reset (which overrides Spree styles)
-# Then restore styles which override Spree's
-# See cms/app/views/layouts/cms_admin/_head.html.erb
= stylesheet_link_tag 'comfortable_mexican_sofa/structure',
'comfortable_mexican_sofa/typography',
'comfortable_mexican_sofa/form',
'comfortable_mexican_sofa/content',
'comfortable_mexican_sofa/files',
'comfortable_mexican_sofa/elrte',
'comfortable_mexican_sofa/codemirror',
'comfortable_mexican_sofa/jquery_ui',
'comfortable_mexican_sofa/dialogs',
'comfortable_mexican_sofa/widgets',
'admin/restore_spree_from_cms'
= javascript_include_tag('comfortable_mexican_sofa/application')
%meta{:name => "cms-admin-path", :content => ComfortableMexicanSofa.config.admin_route_prefix}
%meta{:name => "cms-locale", :content => I18n.locale}

View File

@@ -0,0 +1,12 @@
:css
.page-alert .alert-box { background-color: #fdddac; }
.alert-cta
%h6
Open Food Network
%strong
= link_to t(:label_connect), "https://openfoodnetwork.org/au/connect/", target: '_blank'
and
%strong
= link_to t(:label_learn), "https://openfoodnetwork.org/au/learn/", target: '_blank'
\- Go exploring and get inspired!

View File

@@ -113,17 +113,9 @@
%h4
= t :footer_join_headline
%p
%a{href: "/producers/signup"}
= t :footer_join_producers
%p
%a{href: "/shops/signup"}
= t :footer_join_hubs
%p
%a{href: "/groups/signup"}
= t :footer_join_groups
%p
%a{href: "http://www.openfoodnetwork.org/platform/food-system-partners/", target: "_blank"}
= t :footer_join_partners
= t :footer_join_body
%a{href: "/sell"}
= t :footer_join_cta
.medium-2.columns.text-center
/ Placeholder

View File

@@ -0,0 +1,5 @@
- if feature? :connect_learn_homepage
= render "shared/connect_learn_call"
- else
= render "shared/register_call"

View File

@@ -1,7 +1,8 @@
%a.alert-cta{href: registration_path, target: "_blank"}
.alert-cta
%h6
= t '.selling_on_ofn'
&nbsp;
%strong
= t '.register'
%i.ofn-i_054-point-right
%a{href: registration_path, target: "_blank"}
= t '.selling_on_ofn'
&nbsp;
%strong
= t '.register'
%i.ofn-i_054-point-right

View File

@@ -1,4 +1,4 @@
.text-center.page-alert.fixed{ "ofn-page-alert" => true }
.alert-box
= render 'shared/register_call'
= render 'shared/page_alert'
%a.close{ ng: { click: "close()" } } &times;

View File

@@ -17,8 +17,7 @@
%a.button.primary.tiny{href: checkout_path, "ng-disabled" => "Cart.dirty || Cart.empty()"}
= t 'checkout'
%table
%tr.product-cart{"ng-repeat" => "line_item in Cart.line_items_present()",
"ng-controller" => "LineItemCtrl", "id" => "cart-variant-{{ line_item.variant.id }}"}
%tr.product-cart{"ng-repeat" => "line_item in Cart.line_items", "id" => "cart-variant-{{ line_item.variant.id }}"}
%td
%small
%strong
@@ -33,9 +32,9 @@
%small
\=
%strong
.total-price.right {{ line_item.variant.totalPrice() | localizeCurrency }}
.total-price.right {{ line_item.total_price | localizeCurrency }}
%table{"ng-show" => "Cart.line_items_present().length > 0"}
%table{"ng-show" => "Cart.line_items.length > 0"}
%tr.total-cart
%td
%em

View File

@@ -17,14 +17,25 @@
%a{href: main_app.producers_path}
%span.nav-primary
= t 'label_producers'
%li
%a{href: main_app.groups_path}
%span.nav-primary
= t 'label_groups'
%li
%a{href: ContentConfig.footer_about_url}
%span.nav-primary
= t 'label_about'
- if feature? :connect_learn_homepage
%li
%a{href: "https://openfoodnetwork.org/au/connect/"}
%span.nav-primary
= t 'label_connect'
%li
%a{href: "https://openfoodnetwork.org/au/learn/"}
%span.nav-primary
= t 'label_learn'
- else
%li
%a{href: main_app.groups_path}
%span.nav-primary
= t 'label_groups'
%li
%a{href: ContentConfig.footer_about_url}
%span.nav-primary
= t 'label_about'
%ul.right
- if spree_current_user.nil?
= render 'shared/signed_out'

View File

@@ -41,15 +41,15 @@
%i.ofn-i_036-producers
= t 'label_producers'
%li.li-menu
%a{href: main_app.groups_path}
%a{href: "https://openfoodnetwork.org/au/connect/"}
%span.nav-primary
%i.ofn-i_035-groups
= t 'label_groups'
= t 'label_connect'
%li.li-menu
%a{href: ContentConfig.footer_about_url}
%a{href: "https://openfoodnetwork.org/au/learn/"}
%span.nav-primary
%i.ofn-i_013-help
= t 'label_about'
= t 'label_learn'
%li
- if spree_current_user.nil?

View File

@@ -1,6 +1,5 @@
.footer-pad.small-12.columns
%products{"ng-controller" => "ProductsCtrl", "ng-show" => "order_cycle.order_cycle_id != null", "ng-cloak" => true,
"infinite-scroll" => "incrementLimit()", "infinite-scroll-distance" => "1"}
%products{"ng-controller" => "ProductsCtrl", "ng-show" => "order_cycle.order_cycle_id != null", "ng-cloak" => true }
// TODO: Needs an ng-show to slide content down
.row.animate-slide{ "ng-show" => "query || appliedPropertiesList() || appliedTaxonsList()" }
@@ -29,12 +28,18 @@
.small-12.medium-6.large-6.large-offset-1.columns
= render partial: "shop/products/filters"
%div.pad-top
%product.animate-repeat{"ng-controller" => "ProductNodeCtrl", "ng-repeat" => "product in filteredProducts = (Products.products | products:query | taxons:activeTaxons | properties: activeProperties) track by product.id ", "id" => "product-{{ product.id }}"}
%div.pad-top{ "infinite-scroll" => "incrementLimit()", "infinite-scroll-distance" => "1", "infinite-scroll-disabled" => 'filteredProducts.length <= limit' }
%product.animate-repeat{"ng-controller" => "ProductNodeCtrl", "ng-repeat" => "product in visibleProducts track by product.id", "id" => "product-{{ product.id }}"}
= render "shop/products/summary"
%shop-variant{variant: 'product.master', "ng-if" => "::!product.hasVariants", "id" => "variant-{{ product.master.id }}"}
%shop-variant{variant: 'variant', "ng-repeat" => "variant in product.variants track by variant.id", "id" => "variant-{{ variant.id }}", "ng-class" => "{'out-of-stock': !variant.on_demand && variant.count_on_hand == 0}"}
-# Load more button, which can be used to initiate infinite scrolling.
-# %product{ "ng-hide" => "Products.loading || !infiniteDisabled || limit >= filteredProducts.length" }
-# .row.summary
-# .small-12.columns.text-center
-# %a.button{ ng: { click: 'infiniteDisabled = false; incrementLimit();' } }
-# Load More Products
%product{"ng-show" => "Products.loading"}
.row.summary
.small-12.columns.text-center

View File

@@ -18,4 +18,4 @@
%span{"ng-bind" => "::enterprise.name"}
.small-2.medium-2.large-1.columns.text-center
.taxon-flag
%render-svg{path: "{{product.primary_taxon.icon}}"}
%render-svg{path: "{{::product.primary_taxon.icon}}"}

View File

@@ -1,4 +0,0 @@
= render :partial => 'order_cycles/choice'
= render :partial => 'spree/shared/taxonomies'
= render :partial => 'spree/shared/filters'
= render :partial => 'spree/products/source_sidebar'

View File

@@ -1,7 +1,7 @@
- content_for(:title) do
= t :orders_edit_title
= inject_enterprises
= inject_enterprise_and_relatives
.darkswarm
- content_for :order_cycle_form do

View File

@@ -1,17 +1,9 @@
- content_for(:title) do
= t :orders_show_title
= inject_enterprises
= inject_enterprise_and_relatives if current_distributor.present?
.darkswarm
- content_for :order_cycle_form do
%strong.avenir
= t :orders_show_time
- if @order.order_cycle
= @order.order_cycle.pickup_time_for(@order.distributor)
- else
= @order.distributor.next_collection_at
= render "shopping_shared/details" if current_distributor.present?
%fieldset#order_summary.footer-pad{"data-hook" => ""}

View File

@@ -7,7 +7,7 @@
- elsif !distributor_available_for?(order, @product)
= render 'add_to_cart_distributor_unavailable'
- elsif !order_cycle_available_for?(order, @product) and order_cycles_enabled?
- elsif !order_cycle_available_for?(order, @product)
= render 'add_to_cart_order_cycle_unavailable'
- else

View File

@@ -1,28 +0,0 @@
%nav#filters
%div#distributor_filter
%h6.filter_name Shop by Distributor
%ul.filter_choices
- order = current_order(false)
- validator = DistributionChangeValidator.new(order)
- @sidebar_distributors.each do |distributor|
%li.nowrap
- if order.nil? || order.distributor == distributor || validator.can_change_to_distributor?(distributor)
= link_to distributor.name, [main_app, distributor]
- else
%abbr(title="One or more of the products in your cart is not available from this distributor")= distributor.name
- if @total_distributors > @sidebar_distributors.length
- distributors_more = @total_distributors - @sidebar_distributors.length
%span.filter_more
= "#{distributors_more} more..."
= button_to 'Browse All Distributors', main_app.distributors_enterprises_path, :method => :get
%div#supplier_filter
%h6.filter_name Shop by Supplier
%ul.filter_choices
- @sidebar_suppliers.each do |supplier|
%li.nowrap= link_to supplier.name, [main_app, supplier]
- if @total_suppliers > @sidebar_suppliers.length
- suppliers_more = @total_suppliers - @sidebar_suppliers.length
%span.filter_more
= "#{suppliers_more} more..."
= button_to 'Browse All Suppliers', main_app.suppliers_enterprises_path, :method => :get

View File

@@ -1,3 +0,0 @@
- if @cms_site
- @cms_site.pages.root.children.published.each do |page|
%li= link_to page.label, page.full_path

Some files were not shown because too many files have changed in this diff Show More