mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-03-28 06:15:17 +00:00
Merge branch 'master' of github.com:openfoodfoundation/openfoodnetwork into sign_up_email_i18n
This commit is contained in:
@@ -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\",
|
||||
|
||||
1
Gemfile
1
Gemfile
@@ -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
|
||||
|
||||
12
Gemfile.lock
12
Gemfile.lock
@@ -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
|
||||
|
||||
2
Rakefile
2
Rakefile
@@ -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
|
||||
|
||||
|
||||
@@ -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 )
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -8,3 +8,6 @@ Darkswarm.controller "GroupEnterprisesCtrl", ($scope, Search, FilterSelectorsSer
|
||||
|
||||
$scope.$watch "query", (query)->
|
||||
Search.search query
|
||||
|
||||
$scope.$watch "filtersActive", (value) ->
|
||||
$scope.$broadcast 'filtersToggled'
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
Darkswarm.factory 'EnterpriseResource', ($resource) ->
|
||||
$resource('/enterprise/:id.json', {}, {
|
||||
'relatives':
|
||||
method: 'GET'
|
||||
url: '/enterprises/:id/relatives.json'
|
||||
isArray: true
|
||||
cache: true
|
||||
})
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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}}"}
|
||||
|
||||
@@ -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"}
|
||||
|
||||
@@ -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 }}
|
||||
|
||||
|
||||
%a{"ng-click" => "expanded = !expanded"}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
.progress
|
||||
.right {{'fees' | t}}
|
||||
.right {{::'fees' | t}}
|
||||
.meter
|
||||
{{'item_cost' | t}}
|
||||
|
||||
{{::'item_cost' | t}}
|
||||
|
||||
@@ -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 }}
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
html {
|
||||
height: auto;
|
||||
background-color: transparent;
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
&, & *
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -9,4 +9,8 @@ class HomeController < BaseController
|
||||
@num_orders = Spree::Order.complete.count
|
||||
end
|
||||
end
|
||||
|
||||
def sell
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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!
|
||||
|
||||
|
||||
@@ -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' }
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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!
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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' )
|
||||
@@ -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')
|
||||
@@ -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')
|
||||
@@ -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')
|
||||
@@ -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')
|
||||
@@ -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")
|
||||
@@ -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')
|
||||
@@ -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')
|
||||
@@ -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')
|
||||
@@ -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')
|
||||
@@ -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')
|
||||
@@ -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')
|
||||
@@ -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')
|
||||
@@ -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 }
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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}}"}
|
||||
|
||||
7
app/views/home/_connect.html.haml
Normal file
7
app/views/home/_connect.html.haml
Normal 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
|
||||
7
app/views/home/_learn.html.haml
Normal file
7
app/views/home/_learn.html.haml
Normal 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
|
||||
9
app/views/home/_tagline.html.haml
Normal file
9
app/views/home/_tagline.html.haml
Normal 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
|
||||
@@ -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"
|
||||
|
||||
50
app/views/home/sell.html.haml
Normal file
50
app/views/home/sell.html.haml
Normal 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"
|
||||
@@ -1 +0,0 @@
|
||||
%li= link_to 'Spree Admin', spree.admin_path
|
||||
@@ -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'"}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
.small-12.medium-6.columns.text-right
|
||||
|
||||
|
||||
.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'
|
||||
|
||||
@@ -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}}"}
|
||||
|
||||
@@ -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}
|
||||
12
app/views/shared/_connect_learn_call.html.haml
Normal file
12
app/views/shared/_connect_learn_call.html.haml
Normal 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!
|
||||
@@ -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
|
||||
|
||||
5
app/views/shared/_page_alert.html.haml
Normal file
5
app/views/shared/_page_alert.html.haml
Normal file
@@ -0,0 +1,5 @@
|
||||
- if feature? :connect_learn_homepage
|
||||
= render "shared/connect_learn_call"
|
||||
|
||||
- else
|
||||
= render "shared/register_call"
|
||||
@@ -1,7 +1,8 @@
|
||||
%a.alert-cta{href: registration_path, target: "_blank"}
|
||||
.alert-cta
|
||||
%h6
|
||||
= t '.selling_on_ofn'
|
||||
|
||||
%strong
|
||||
= t '.register'
|
||||
%i.ofn-i_054-point-right
|
||||
%a{href: registration_path, target: "_blank"}
|
||||
= t '.selling_on_ofn'
|
||||
|
||||
%strong
|
||||
= t '.register'
|
||||
%i.ofn-i_054-point-right
|
||||
|
||||
@@ -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()" } } ×
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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?
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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}}"}
|
||||
|
||||
@@ -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'
|
||||
@@ -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
|
||||
|
||||
@@ -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" => ""}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
Reference in New Issue
Block a user