diff --git a/app/assets/javascripts/admin/all.js b/app/assets/javascripts/admin/all.js
index f8d3ceb721..7dc9d1116f 100644
--- a/app/assets/javascripts/admin/all.js
+++ b/app/assets/javascripts/admin/all.js
@@ -22,6 +22,7 @@
//= require ./payment_methods/payment_methods
//= require ./products/products
//= require ./shipping_methods/shipping_methods
+//= require ./utils/utils
//= require ./users/users
//= require textAngular.min.js
//= require textAngular-sanitize.min.js
diff --git a/app/assets/javascripts/admin/enterprises/controllers/enterprise_controller.js.coffee b/app/assets/javascripts/admin/enterprises/controllers/enterprise_controller.js.coffee
index 46eb4a84c1..cfcf6319af 100644
--- a/app/assets/javascripts/admin/enterprises/controllers/enterprise_controller.js.coffee
+++ b/app/assets/javascripts/admin/enterprises/controllers/enterprise_controller.js.coffee
@@ -1,10 +1,18 @@
angular.module("admin.enterprises")
- .controller "enterpriseCtrl", ($scope, Enterprise, longDescription, PaymentMethods, ShippingMethods) ->
+ .controller "enterpriseCtrl", ($scope, longDescription, NavigationCheck, Enterprise, PaymentMethods, ShippingMethods) ->
$scope.Enterprise = Enterprise.enterprise
$scope.PaymentMethods = PaymentMethods.paymentMethods
$scope.ShippingMethods = ShippingMethods.shippingMethods
+ $scope.navClear = NavigationCheck.clear
+ # htmlVariable is used by textAngular wysiwyg for the long descrtiption.
$scope.htmlVariable = longDescription
+ # Provide a callback for generating warning messages displayed before leaving the page. This is passed in
+ # from a directive "nav-check" in the page - if we pass it here it will be called in the test suite,
+ # and on all new uses of this contoller, and we might not want that .
+ $scope.enterpriseNavCallback = ->
+ "You are editing an enterprise!"
+
for payment_method in $scope.PaymentMethods
payment_method.selected = payment_method.id in $scope.Enterprise.payment_method_ids
diff --git a/app/assets/javascripts/admin/enterprises/enterprises.js.coffee b/app/assets/javascripts/admin/enterprises/enterprises.js.coffee
index 9b67bc14f4..e1e43854d1 100644
--- a/app/assets/javascripts/admin/enterprises/enterprises.js.coffee
+++ b/app/assets/javascripts/admin/enterprises/enterprises.js.coffee
@@ -1 +1 @@
-angular.module("admin.enterprises", ["admin.payment_methods", "admin.shipping_methods", "admin.users", "textAngular"])
\ No newline at end of file
+angular.module("admin.enterprises", ["admin.payment_methods", "admin.utils", "admin.shipping_methods", "admin.users", "textAngular"])
\ No newline at end of file
diff --git a/app/assets/javascripts/admin/enterprises/services/enterprise.js.coffee b/app/assets/javascripts/admin/enterprises/services/enterprise.js.coffee
index b6e6a6147e..26061ef720 100644
--- a/app/assets/javascripts/admin/enterprises/services/enterprise.js.coffee
+++ b/app/assets/javascripts/admin/enterprises/services/enterprise.js.coffee
@@ -1,4 +1,5 @@
angular.module("admin.enterprises")
+ # Populate Enterprise.enterprise with enterprise json array from the page.
.factory 'Enterprise', (enterprise) ->
new class Enterprise
- enterprise: enterprise
\ No newline at end of file
+ enterprise: enterprise
diff --git a/app/assets/javascripts/admin/utils/directives/navigation_check.js.coffee b/app/assets/javascripts/admin/utils/directives/navigation_check.js.coffee
new file mode 100644
index 0000000000..95f52505eb
--- /dev/null
+++ b/app/assets/javascripts/admin/utils/directives/navigation_check.js.coffee
@@ -0,0 +1,9 @@
+angular.module("admin.utils").directive "navCheck", (NavigationCheck)->
+ restrict: 'A'
+ scope:
+ navCallback: '&'
+ link: (scope,element,attributes) ->
+ # Define navigationCallback on a controller in scope, otherwise this default will be used:
+ scope.navCallback ||= ->
+ "You will lose any unsaved work!"
+ NavigationCheck.register(scope.navCallback)
diff --git a/app/assets/javascripts/admin/utils/services/navigation_check.js.coffee b/app/assets/javascripts/admin/utils/services/navigation_check.js.coffee
new file mode 100644
index 0000000000..ff1041474c
--- /dev/null
+++ b/app/assets/javascripts/admin/utils/services/navigation_check.js.coffee
@@ -0,0 +1,46 @@
+angular.module("admin.utils")
+ .factory "NavigationCheck", ($window, $rootScope) ->
+ new class NavigationCheck
+ callbacks = []
+ constructor: ->
+ if $window.addEventListener
+ $window.addEventListener "beforeunload", @onBeforeUnloadHandler
+ else
+ $window.onbeforeunload = @onBeforeUnloadHandler
+
+ $rootScope.$on "$locationChangeStart", @locationChangeStartHandler
+
+
+ # Action for regular browser navigation.
+ onBeforeUnloadHandler: ($event) =>
+ message = @getMessage()
+ if message
+ ($event or $window.event).preventDefault()
+ message
+
+ # Action for angular navigation.
+ locationChangeStartHandler: ($event) =>
+ message = @getMessage()
+ if message and not $window.confirm(message)
+ $event.stopPropagation() if $event.stopPropagation
+ $event.preventDefault() if $event.preventDefault
+ $event.cancelBubble = true
+ $event.returnValue = false
+
+ # Runs callback functions to retreive most recently added non-empty message.
+ getMessage: ->
+ message = null
+ message = callback() ? message for callback in callbacks
+ message
+
+ register: (callback) =>
+ callbacks.push callback
+
+ clear: =>
+ if $window.addEventListener
+ $window.removeEventListener "beforeunload", @onBeforeUnloadHandler
+ else
+ $window.onbeforeunload = null
+
+ $rootScope.$on "$locationChangeStart", null
+
diff --git a/app/assets/javascripts/admin/utils/utils.js.coffee b/app/assets/javascripts/admin/utils/utils.js.coffee
new file mode 100644
index 0000000000..4d58ae930a
--- /dev/null
+++ b/app/assets/javascripts/admin/utils/utils.js.coffee
@@ -0,0 +1 @@
+angular.module("admin.utils", [])
\ No newline at end of file
diff --git a/app/assets/javascripts/darkswarm/controllers/hubs_controller.js.coffee b/app/assets/javascripts/darkswarm/controllers/enterprises_controller.js.coffee
similarity index 63%
rename from app/assets/javascripts/darkswarm/controllers/hubs_controller.js.coffee
rename to app/assets/javascripts/darkswarm/controllers/enterprises_controller.js.coffee
index b44d63eadf..1e43c17465 100644
--- a/app/assets/javascripts/darkswarm/controllers/hubs_controller.js.coffee
+++ b/app/assets/javascripts/darkswarm/controllers/enterprises_controller.js.coffee
@@ -1,13 +1,14 @@
-Darkswarm.controller "HubsCtrl", ($scope, Hubs, Search, $document, $rootScope, HashNavigation, FilterSelectorsService, MapModal) ->
- $scope.Hubs = Hubs
- $scope.hubs = Hubs.visible
+Darkswarm.controller "EnterprisesCtrl", ($scope, Enterprises, Search, $document, $rootScope, HashNavigation, FilterSelectorsService, EnterpriseModal) ->
+ $scope.Enterprises = Enterprises
$scope.totalActive = FilterSelectorsService.totalActive
$scope.clearAll = FilterSelectorsService.clearAll
$scope.filterText = FilterSelectorsService.filterText
$scope.FilterSelectorsService = FilterSelectorsService
$scope.query = Search.search()
+ $scope.openModal = EnterpriseModal.open
+ $scope.activeTaxons = []
$scope.show_profiles = false
- $scope.openModal = MapModal.open
+ $scope.filtersActive = false
$scope.$watch "query", (query)->
Search.search query
diff --git a/app/assets/javascripts/darkswarm/controllers/producers_controller.js.coffee b/app/assets/javascripts/darkswarm/controllers/producers_controller.js.coffee
deleted file mode 100644
index b16dcdfa77..0000000000
--- a/app/assets/javascripts/darkswarm/controllers/producers_controller.js.coffee
+++ /dev/null
@@ -1,14 +0,0 @@
-Darkswarm.controller "ProducersCtrl", ($scope, Producers, $filter, FilterSelectorsService, Search, MapModal) ->
- $scope.Producers = Producers
- $scope.totalActive = FilterSelectorsService.totalActive
- $scope.clearAll = FilterSelectorsService.clearAll
- $scope.filterText = FilterSelectorsService.filterText
- $scope.FilterSelectorsService = FilterSelectorsService
- $scope.filtersActive = false
- $scope.activeTaxons = []
- $scope.query = Search.search()
- $scope.show_profiles = false
- $scope.openModal = MapModal.open
-
- $scope.$watch "query", (query)->
- Search.search query
diff --git a/app/assets/javascripts/darkswarm/controllers/registration_controller.js.coffee b/app/assets/javascripts/darkswarm/controllers/registration/registration_controller.js.coffee
similarity index 84%
rename from app/assets/javascripts/darkswarm/controllers/registration_controller.js.coffee
rename to app/assets/javascripts/darkswarm/controllers/registration/registration_controller.js.coffee
index 2fcc0f32fd..3be0378619 100644
--- a/app/assets/javascripts/darkswarm/controllers/registration_controller.js.coffee
+++ b/app/assets/javascripts/darkswarm/controllers/registration/registration_controller.js.coffee
@@ -3,7 +3,7 @@ Darkswarm.controller "RegistrationCtrl", ($scope, RegistrationService, Enterpris
$scope.enterprise = EnterpriseRegistrationService.enterprise
$scope.select = RegistrationService.select
- $scope.steps = ['details','address','contact','about','images','social']
+ $scope.steps = ['details','contact','type','about','images','social']
$scope.countries = availableCountries
diff --git a/app/assets/javascripts/darkswarm/controllers/registration_form_controller.js.coffee b/app/assets/javascripts/darkswarm/controllers/registration/registration_form_controller.js.coffee
similarity index 100%
rename from app/assets/javascripts/darkswarm/controllers/registration_form_controller.js.coffee
rename to app/assets/javascripts/darkswarm/controllers/registration/registration_form_controller.js.coffee
diff --git a/app/assets/javascripts/darkswarm/controllers/tabs/producers_controller.js.coffee b/app/assets/javascripts/darkswarm/controllers/tabs/producers_controller.js.coffee
index 6db73f7af3..7a5ebb78f3 100644
--- a/app/assets/javascripts/darkswarm/controllers/tabs/producers_controller.js.coffee
+++ b/app/assets/javascripts/darkswarm/controllers/tabs/producers_controller.js.coffee
@@ -1,3 +1,4 @@
-Darkswarm.controller "ProducersTabCtrl", ($scope, CurrentHub, Enterprises) ->
- # Injecting Enterprises so CurrentHub.producers is dereferenced
+Darkswarm.controller "ProducersTabCtrl", ($scope, CurrentHub, Enterprises, EnterpriseModal) ->
+ # Injecting Enterprises so CurrentHub.producers is dereferenced.
+ # We should probably dereference here instead and separate out CurrentHub dereferencing from the Enterprise factory.
$scope.CurrentHub = CurrentHub
diff --git a/app/assets/javascripts/darkswarm/controllers/tabs_controller.js.coffee b/app/assets/javascripts/darkswarm/controllers/tabs_controller.js.coffee
index eb501bcb4a..0bbe0bbd23 100644
--- a/app/assets/javascripts/darkswarm/controllers/tabs_controller.js.coffee
+++ b/app/assets/javascripts/darkswarm/controllers/tabs_controller.js.coffee
@@ -1,18 +1,11 @@
Darkswarm.controller "TabsCtrl", ($scope, $rootScope, $location, OrderCycle) ->
+ # Return active if supplied path matches url hash path.
$scope.active = (path)->
- if !OrderCycle.selected() and $location.hash() == "" and path == "about"
- true
- else
- $location.hash() == path
+ $location.hash() == path
-
- $scope.tabs = ["contact", "about", "groups", "producers"]
- for tab in $scope.tabs
- $scope[tab] =
- path: tab
-
- $scope.select = (tab)->
- if $scope.active(tab.path)
+ # Toggle tab selected status by setting the url hash path.
+ $scope.select = (path)->
+ if $scope.active(path)
$location.hash ""
else
- $location.hash tab.path
+ $location.hash path
diff --git a/app/assets/javascripts/darkswarm/directives/producer_modal.js.coffee b/app/assets/javascripts/darkswarm/directives/enterprise_modal.js.coffee
similarity index 71%
rename from app/assets/javascripts/darkswarm/directives/producer_modal.js.coffee
rename to app/assets/javascripts/darkswarm/directives/enterprise_modal.js.coffee
index af2b13f157..fa6378afe2 100644
--- a/app/assets/javascripts/darkswarm/directives/producer_modal.js.coffee
+++ b/app/assets/javascripts/darkswarm/directives/enterprise_modal.js.coffee
@@ -1,4 +1,4 @@
-Darkswarm.directive "producerModal", ($modal)->
+Darkswarm.directive "enterpriseModal", ($modal)->
restrict: 'E'
replace: true
template: ""
@@ -6,5 +6,4 @@ Darkswarm.directive "producerModal", ($modal)->
link: (scope, elem, attrs, ctrl)->
elem.on "click", (ev)=>
ev.stopPropagation()
- scope.modalInstance = $modal.open(controller: ctrl, templateUrl: 'producer_modal.html', scope: scope)
-
+ scope.modalInstance = $modal.open(controller: ctrl, templateUrl: 'enterprise_modal.html', scope: scope)
diff --git a/app/assets/javascripts/darkswarm/directives/hub_modal.js.coffee b/app/assets/javascripts/darkswarm/directives/hub_modal.js.coffee
deleted file mode 100644
index 6eb0299ab4..0000000000
--- a/app/assets/javascripts/darkswarm/directives/hub_modal.js.coffee
+++ /dev/null
@@ -1,8 +0,0 @@
-Darkswarm.directive "hubModal", ($modal)->
- restrict: 'E'
- replace: true
- template: "{{enterprise.name}}"
- link: (scope, elem, attrs, ctrl)->
- elem.on "click", (ev)=>
- ev.stopPropagation()
- scope.modalInstance = $modal.open(controller: ctrl, templateUrl: 'hub_modal.html', scope: scope)
diff --git a/app/assets/javascripts/darkswarm/directives/inline_alert.js.coffee b/app/assets/javascripts/darkswarm/directives/inline_alert.js.coffee
new file mode 100644
index 0000000000..9b37934375
--- /dev/null
+++ b/app/assets/javascripts/darkswarm/directives/inline_alert.js.coffee
@@ -0,0 +1,7 @@
+Darkswarm.directive "ofnInlineAlert", ->
+ restrict: 'A'
+ scope: true
+ link: (scope, elem, attrs) ->
+ scope.visible = true
+ scope.close = ->
+ scope.visible = false
diff --git a/app/assets/javascripts/darkswarm/directives/inline_flash.js.coffee b/app/assets/javascripts/darkswarm/directives/inline_flash.js.coffee
deleted file mode 100644
index 46550b854f..0000000000
--- a/app/assets/javascripts/darkswarm/directives/inline_flash.js.coffee
+++ /dev/null
@@ -1,6 +0,0 @@
-Darkswarm.directive "ofnInlineFlash", ->
- restrict: 'E'
- controller: ($scope) ->
- $scope.visible = true
- $scope.closeFlash = ->
- $scope.visible = false
diff --git a/app/assets/javascripts/darkswarm/directives/registration_limit_modal.js.coffee b/app/assets/javascripts/darkswarm/directives/registration_limit_modal.js.coffee
index 1fecfbf804..2b38b3d31f 100644
--- a/app/assets/javascripts/darkswarm/directives/registration_limit_modal.js.coffee
+++ b/app/assets/javascripts/darkswarm/directives/registration_limit_modal.js.coffee
@@ -3,7 +3,7 @@ Darkswarm.directive "ofnRegistrationLimitModal", (Navigation, $modal, Loading) -
link: (scope, elem, attr)->
scope.modalInstance = $modal.open
templateUrl: 'registration/limit_reached.html'
- windowClass: "login-modal large"
+ windowClass: "login-modal register-modal xlarge"
backdrop: 'static'
scope.modalInstance.result.then scope.close, scope.close
diff --git a/app/assets/javascripts/darkswarm/filters/capitalize.js.coffee b/app/assets/javascripts/darkswarm/filters/capitalize.js.coffee
index acbd3fd637..5c2272135b 100644
--- a/app/assets/javascripts/darkswarm/filters/capitalize.js.coffee
+++ b/app/assets/javascripts/darkswarm/filters/capitalize.js.coffee
@@ -1,4 +1,5 @@
Darkswarm.filter "capitalize", ->
+ # Convert to basic sentence case.
(input, scope) ->
- input = input.toLowerCase() if input?
+ input = input.toLowerCase() if input?
input.substring(0, 1).toUpperCase() + input.substring(1)
diff --git a/app/assets/javascripts/darkswarm/filters/filter_hubs.js.coffee b/app/assets/javascripts/darkswarm/filters/filter_hubs.js.coffee
deleted file mode 100644
index b6adb84508..0000000000
--- a/app/assets/javascripts/darkswarm/filters/filter_hubs.js.coffee
+++ /dev/null
@@ -1,9 +0,0 @@
-Darkswarm.filter 'hubs', (Matcher)->
- (hubs, text) ->
- hubs ||= []
- text ?= ""
-
- hubs.filter (hub)=>
- Matcher.match [
- hub.name, hub.address.zipcode, hub.address.city, hub.address.state
- ], text
diff --git a/app/assets/javascripts/darkswarm/filters/filter_producers.js.coffee b/app/assets/javascripts/darkswarm/filters/filter_producers.js.coffee
deleted file mode 100644
index ed5b8c1bea..0000000000
--- a/app/assets/javascripts/darkswarm/filters/filter_producers.js.coffee
+++ /dev/null
@@ -1,6 +0,0 @@
-Darkswarm.filter 'filterProducers', (hubsFilter)->
- (producers, text) ->
- producers ||= []
- text ?= ""
- hubsFilter(producers, text)
-
diff --git a/app/assets/javascripts/darkswarm/filters/localize_currency.js.coffee b/app/assets/javascripts/darkswarm/filters/localize_currency.js.coffee
index ffa98c5a33..7087e09fc3 100644
--- a/app/assets/javascripts/darkswarm/filters/localize_currency.js.coffee
+++ b/app/assets/javascripts/darkswarm/filters/localize_currency.js.coffee
@@ -1,15 +1,14 @@
-# Convert number to string currency using injected currency configuration.
-#
-# @requires currencyConfig json - /app/serializers/api/currency_config_serializer.rb
-# @return: string
Darkswarm.filter "localizeCurrency", (currencyConfig)->
+ # Convert number to string currency using injected currency configuration.
(amount) ->
+ # Set country code (eg. "US").
currency_code = if currencyConfig.display_currency then " " + currencyConfig.currency else ""
+ # Set decimal points, 2 or 0 if hide_cents.
decimals = if currencyConfig.hide_cents == "true" then 0 else 2
- # We need to use parseFloat before toFixed as the amount should be a passed in as a string.
+ # We need to use parseFloat before toFixed as the amount should come in as a string.
amount_fixed = parseFloat(amount).toFixed(decimals)
- # Build the final price string.
+ # Build the final price string. TODO use spree decimal point and spacer character settings.
if currencyConfig.symbol_position == 'before'
currencyConfig.symbol + amount_fixed + currency_code
else
diff --git a/app/assets/javascripts/darkswarm/filters/search_enterprises.js.coffee b/app/assets/javascripts/darkswarm/filters/search_enterprises.js.coffee
new file mode 100644
index 0000000000..2c42fe93d3
--- /dev/null
+++ b/app/assets/javascripts/darkswarm/filters/search_enterprises.js.coffee
@@ -0,0 +1,10 @@
+Darkswarm.filter 'searchEnterprises', (Matcher)->
+ # Search multiple fields of enterprises for matching text fragment.
+ (enterprises, text) ->
+ enterprises ||= []
+ text ?= ""
+
+ enterprises.filter (enterprise)=>
+ Matcher.match [
+ enterprise.name, enterprise.address.zipcode, enterprise.address.city, enterprise.address.state
+ ], text
diff --git a/app/assets/javascripts/darkswarm/filters/show_hub_profiles.js.coffee b/app/assets/javascripts/darkswarm/filters/show_hub_profiles.js.coffee
new file mode 100644
index 0000000000..b97a0c35e4
--- /dev/null
+++ b/app/assets/javascripts/darkswarm/filters/show_hub_profiles.js.coffee
@@ -0,0 +1,8 @@
+Darkswarm.filter 'showHubProfiles', ()->
+ # Filter hub_profile enterprises in or out.
+ (enterprises, show_profiles) ->
+ enterprises ||= []
+ show_profiles ?= false
+
+ enterprises.filter (enterprise)=>
+ show_profiles or enterprise.is_distributor
diff --git a/app/assets/javascripts/darkswarm/filters/show_profiles.js.coffee b/app/assets/javascripts/darkswarm/filters/show_profiles.js.coffee
deleted file mode 100644
index e3fce7d2f6..0000000000
--- a/app/assets/javascripts/darkswarm/filters/show_profiles.js.coffee
+++ /dev/null
@@ -1,7 +0,0 @@
-Darkswarm.filter 'showProfiles', ()->
- (enterprises, show_profiles) ->
- enterprises ||= []
- show_profiles ?= true
-
- enterprises.filter (enterprise)=>
- show_profiles or enterprise.has_shopfront
diff --git a/app/assets/javascripts/darkswarm/filters/taxons.js.coffee b/app/assets/javascripts/darkswarm/filters/taxons.js.coffee
index 3eb32ce1a4..a7ccc9b0cc 100644
--- a/app/assets/javascripts/darkswarm/filters/taxons.js.coffee
+++ b/app/assets/javascripts/darkswarm/filters/taxons.js.coffee
@@ -1,13 +1,16 @@
-Darkswarm.filter 'taxons', (Matcher)->
- # Filter anything that responds to object.taxons, and/or object.primary_taxon
+Darkswarm.filter 'taxons', ()->
+ # Filter anything that responds to object.taxons, object.supplied_taxon or object.primary_taxon.
(objects, ids) ->
objects ||= []
ids ?= []
if ids.length == 0
+ # No taxons selected, pass all objects through.
objects
else
objects.filter (obj)->
taxons = obj.taxons
- taxons.concat obj.supplied_taxons if obj.supplied_taxons
+ # Combine object taxons with supplied taxons, if they exist.
+ taxons = taxons.concat obj.supplied_taxons if obj.supplied_taxons
+ # Match primary taxon if it exists, then taxon array.
obj.primary_taxon?.id in ids || taxons.some (taxon)->
taxon.id in ids
diff --git a/app/assets/javascripts/darkswarm/services/authentication_service.js.coffee b/app/assets/javascripts/darkswarm/services/authentication_service.js.coffee
index 5f5ae520e3..f2d7049e67 100644
--- a/app/assets/javascripts/darkswarm/services/authentication_service.js.coffee
+++ b/app/assets/javascripts/darkswarm/services/authentication_service.js.coffee
@@ -1,4 +1,4 @@
-Darkswarm.factory "AuthenticationService", (Navigation, $modal, $location, Redirections)->
+Darkswarm.factory "AuthenticationService", (Navigation, $modal, $location, Redirections, Loading)->
new class AuthenticationService
selectedPath: "/login"
@@ -25,4 +25,9 @@ Darkswarm.factory "AuthenticationService", (Navigation, $modal, $location, Redir
active: Navigation.active
close: ->
- Navigation.navigate "/"
+ if location.pathname == "/"
+ Navigation.navigate "/"
+ else
+ Loading.message = "Taking you back to the home page"
+ location.hash = ""
+ location.pathname = "/"
diff --git a/app/assets/javascripts/darkswarm/services/current_hub.js.coffee b/app/assets/javascripts/darkswarm/services/current_hub.js.coffee
index 5e6a385b8a..ade8d75d18 100644
--- a/app/assets/javascripts/darkswarm/services/current_hub.js.coffee
+++ b/app/assets/javascripts/darkswarm/services/current_hub.js.coffee
@@ -1,3 +1,4 @@
-Darkswarm.factory 'CurrentHub', ($location, $filter, currentHub) ->
+Darkswarm.factory 'CurrentHub', (currentHub) ->
+ # Populate CurrentHub.hub from json in page. This is probably redundant now.
new class CurrentHub
hub: currentHub
diff --git a/app/assets/javascripts/darkswarm/services/current_order.js.coffee b/app/assets/javascripts/darkswarm/services/current_order.js.coffee
index cd2402f0c0..6570ddcd06 100644
--- a/app/assets/javascripts/darkswarm/services/current_order.js.coffee
+++ b/app/assets/javascripts/darkswarm/services/current_order.js.coffee
@@ -1,3 +1,4 @@
Darkswarm.factory 'CurrentOrder', (currentOrder) ->
+ # Populate Currentorder.order from json in page. This is probably redundant now.
new class CurrentOrder
order: currentOrder
diff --git a/app/assets/javascripts/darkswarm/services/enterprise_modal.js.coffee b/app/assets/javascripts/darkswarm/services/enterprise_modal.js.coffee
new file mode 100644
index 0000000000..a0fb3ce5c5
--- /dev/null
+++ b/app/assets/javascripts/darkswarm/services/enterprise_modal.js.coffee
@@ -0,0 +1,8 @@
+Darkswarm.factory "EnterpriseModal", ($modal, $rootScope)->
+ # Build a modal popup for an enterprise.
+ new class EnterpriseModal
+ open: (enterprise)->
+ scope = $rootScope.$new(true) # Spawn an isolate to contain the enterprise
+
+ scope.enterprise = enterprise
+ $modal.open(templateUrl: "enterprise_modal.html", scope: scope)
diff --git a/app/assets/javascripts/darkswarm/services/enterprises.js.coffee b/app/assets/javascripts/darkswarm/services/enterprises.js.coffee
index 50143e006b..6040f1d150 100644
--- a/app/assets/javascripts/darkswarm/services/enterprises.js.coffee
+++ b/app/assets/javascripts/darkswarm/services/enterprises.js.coffee
@@ -1,13 +1,21 @@
-Darkswarm.factory 'Enterprises', (enterprises, CurrentHub, Taxons, Dereferencer)->
+Darkswarm.factory 'Enterprises', (enterprises, CurrentHub, Taxons, Dereferencer, visibleFilter)->
new class Enterprises
- enterprises_by_id: {} # id/object pairs for lookup
+ enterprises_by_id: {}
constructor: ->
+ # Populate Enterprises.enterprises from json in page.
@enterprises = enterprises
+ # Map enterprises to id/object pairs for lookup.
for enterprise in enterprises
@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"]
+ @hubs = @visible_enterprises.filter (enterprise)->
+ enterprise.category in ["hub", "hub_profile", "producer_hub", "producer_shop"]
+
dereferenceEnterprises: ->
if CurrentHub.hub?.id
CurrentHub.hub = @enterprises_by_id[CurrentHub.hub.id]
@@ -16,6 +24,7 @@ Darkswarm.factory 'Enterprises', (enterprises, CurrentHub, Taxons, Dereferencer)
Dereferencer.dereference enterprise.producers, @enterprises_by_id
dereferenceTaxons: ->
- for enterprise in @enterprises
+ for enterprise in @enterprises
Dereferencer.dereference enterprise.taxons, Taxons.taxons_by_id
Dereferencer.dereference enterprise.supplied_taxons, Taxons.taxons_by_id
+
diff --git a/app/assets/javascripts/darkswarm/services/hubs.js.coffee b/app/assets/javascripts/darkswarm/services/hubs.js.coffee
deleted file mode 100644
index ba3d9f3c24..0000000000
--- a/app/assets/javascripts/darkswarm/services/hubs.js.coffee
+++ /dev/null
@@ -1,9 +0,0 @@
-Darkswarm.factory 'Hubs', ($filter, Enterprises, visibleFilter) ->
- new class Hubs
- constructor: ->
- @hubs = @order Enterprises.enterprises.filter (hub)->
- hub.has_hub_listing
- @visible = visibleFilter @hubs
-
- order: (hubs)->
- $filter('orderBy')(hubs, ['-active', '+orders_close_at'])
diff --git a/app/assets/javascripts/darkswarm/services/map.js.coffee b/app/assets/javascripts/darkswarm/services/map.js.coffee
index 43750acdb2..703c3c54bf 100644
--- a/app/assets/javascripts/darkswarm/services/map.js.coffee
+++ b/app/assets/javascripts/darkswarm/services/map.js.coffee
@@ -1,7 +1,7 @@
-Darkswarm.factory "OfnMap", (Enterprises, MapModal, visibleFilter)->
+Darkswarm.factory "OfnMap", (Enterprises, EnterpriseModal, visibleFilter)->
new class OfnMap
constructor: ->
- @enterprises = (@extend(enterprise) for enterprise in visibleFilter(Enterprises.enterprises))
+ @enterprises = (@extend(enterprise) for enterprise in visibleFilter(Enterprises.enterprises))
# Adding methods to each enterprise
@@ -14,4 +14,4 @@ Darkswarm.factory "OfnMap", (Enterprises, MapModal, visibleFilter)->
icon: enterprise.icon
id: enterprise.id
reveal: =>
- MapModal.open enterprise
+ EnterpriseModal.open enterprise
diff --git a/app/assets/javascripts/darkswarm/services/map_modal.js.coffee b/app/assets/javascripts/darkswarm/services/map_modal.js.coffee
deleted file mode 100644
index c9ed30f558..0000000000
--- a/app/assets/javascripts/darkswarm/services/map_modal.js.coffee
+++ /dev/null
@@ -1,12 +0,0 @@
-Darkswarm.factory "MapModal", ($modal, $rootScope)->
- new class MapModal
- open: (enterprise)->
- scope = $rootScope.$new(true) # Spawn an isolate to contain the enterprise
-
- scope.enterprise = enterprise
- if enterprise.is_distributor
- scope.hub = enterprise
- $modal.open(templateUrl: "hub_modal.html", scope: scope)
- else
- scope.producer = enterprise
- $modal.open(templateUrl: "map_modal_producer.html", scope: scope)
diff --git a/app/assets/javascripts/darkswarm/services/matcher.js.coffee b/app/assets/javascripts/darkswarm/services/matcher.js.coffee
index aadd6a4128..9360afdd1f 100644
--- a/app/assets/javascripts/darkswarm/services/matcher.js.coffee
+++ b/app/assets/javascripts/darkswarm/services/matcher.js.coffee
@@ -1,6 +1,7 @@
Darkswarm.factory "Matcher", ->
- new class Matcher
- match: (properties, text)->
- properties.some (prop)->
- prop ||= ""
- prop.toLowerCase().indexOf(text.toLowerCase()) != -1
+ # Match text fragment in an array of strings.
+ new class Matcher
+ match: (properties, text)->
+ properties.some (prop)->
+ prop ||= ""
+ prop.toLowerCase().indexOf(text.toLowerCase()) != -1
diff --git a/app/assets/javascripts/darkswarm/services/producers.js.coffee b/app/assets/javascripts/darkswarm/services/producers.js.coffee
deleted file mode 100644
index 65d8e42c5d..0000000000
--- a/app/assets/javascripts/darkswarm/services/producers.js.coffee
+++ /dev/null
@@ -1,7 +0,0 @@
-Darkswarm.factory 'Producers', (Enterprises, visibleFilter) ->
- new class Producers
- constructor: ->
- @producers = Enterprises.enterprises.filter (enterprise)->
- enterprise.is_primary_producer
- @visible = visibleFilter @producers
-
diff --git a/app/assets/javascripts/darkswarm/services/taxons.js.coffee b/app/assets/javascripts/darkswarm/services/taxons.js.coffee
index cbe6c118e0..984eb0df22 100644
--- a/app/assets/javascripts/darkswarm/services/taxons.js.coffee
+++ b/app/assets/javascripts/darkswarm/services/taxons.js.coffee
@@ -1,8 +1,10 @@
Darkswarm.factory "Taxons", (taxons)->
new class Taxons
- taxons: taxons
+ # Populate Taxons.taxons from json in page.
+ taxons: taxons
taxons_by_id: {}
constructor: ->
+ # Map taxons to id/object pairs for lookup.
for taxon in @taxons
@taxons_by_id[taxon.id] = taxon
diff --git a/app/assets/javascripts/darkswarm/services/variants.js.coffee b/app/assets/javascripts/darkswarm/services/variants.js.coffee
index bc2050e4d4..6562bd9e0b 100644
--- a/app/assets/javascripts/darkswarm/services/variants.js.coffee
+++ b/app/assets/javascripts/darkswarm/services/variants.js.coffee
@@ -5,6 +5,7 @@ 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)
diff --git a/app/assets/javascripts/search/all.js b/app/assets/javascripts/search/all.js
deleted file mode 100644
index c684eed4b1..0000000000
--- a/app/assets/javascripts/search/all.js
+++ /dev/null
@@ -1,18 +0,0 @@
-// This is a manifest file that'll be compiled into including all the files listed below.
-// Add new JavaScript/Coffee code in separate files in this directory and they'll automatically
-// be included in the compiled file accessible from http://example.com/assets/application.js
-// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
-// the compiled file.
-//
-
-//= require jquery
-//= require jquery_ujs
-//= require jquery-ui
-//= require spin
-//= require foundation
-//= require_tree .
-//
-
-// Hacky fix for issue - http://foundation.zurb.com/forum/posts/2112-foundation-5100-syntax-error-in-js
-Foundation.set_namespace = function() {};
-$(function(){ $(document).foundation(); });
diff --git a/app/assets/javascripts/search/gmaps4rails/gmaps4rails.base.js.coffee b/app/assets/javascripts/search/gmaps4rails/gmaps4rails.base.js.coffee
deleted file mode 100644
index 684215a438..0000000000
--- a/app/assets/javascripts/search/gmaps4rails/gmaps4rails.base.js.coffee
+++ /dev/null
@@ -1,444 +0,0 @@
-Gmaps = {}
-
-Gmaps.triggerOldOnload = ->
- Gmaps.oldOnload() if typeof(Gmaps.oldOnload) == 'function'
-
-Gmaps.loadMaps = ->
- #loop through all variable names.
- #there should only be maps inside so it trigger their load function
- for key, value of Gmaps
- searchLoadIncluded = key.search(/load/)
- if searchLoadIncluded == -1
- load_function_name = "load_" + key
- Gmaps[load_function_name]()
-
-window.Gmaps = Gmaps
-
-class @Gmaps4Rails
-
- constructor: ->
- #map config
- @map = null #DEPRECATED: will still contain a copy of serviceObject below as transition
- @serviceObject = null #contains the map we're working on
- @visibleInfoWindow = null #contains the current opened infowindow
- @userLocation = null #contains user's location if geolocalization was performed and successful
-
- #empty slots
- @geolocationSuccess = -> false #triggered when geolocation succeeds. Can be customized.
- @geolocationFailure = -> false #triggered when geolocation fails. If customized, must be like= function(navigator_handles_geolocation){} where 'navigator_handles_geolocation' is a boolean
- @callback = -> false #to let user set a custom callback function
- @customClusterer = -> false #to let user set custom clusterer pictures
- @infobox = -> false #to let user use custom infoboxes
- @jsTemplate = false #to let user create infowindows client side
-
- @default_map_options =
- id: 'map'
- draggable: true
- detect_location: false # should the browser attempt to use geolocation detection features of HTML5?
- center_on_user: false # centers map on the location detected through the browser
- center_latitude: 0
- center_longitude: 0
- zoom: 7
- maxZoom: null
- minZoom: null
- auto_adjust : true # adjust the map to the markers if set to true
- auto_zoom: true # zoom given by auto-adjust
- bounds: [] # adjust map to these limits. Should be [{"lat": , "lng": }]
- raw: {} # raw json to pass additional options
-
- @default_markers_conf =
- #Marker config
- title: ""
- #MarkerImage config
- picture : ""
- width: 22
- length: 32
- draggable: false # how to modify: <%= gmaps( "markers" => { "data" => @object.to_gmaps4rails, "options" => { "draggable" => true }}) %>
- #clustering config
- do_clustering: false # do clustering if set to true
- randomize: false # Google maps can't display two markers which have the same coordinates. This randomizer enables to prevent this situation from happening.
- max_random_distance: 100 # in meters. Each marker coordinate could be altered by this distance in a random direction
- list_container: null # id of the ul that will host links to all markers
- offset: 0 # used when adding_markers to an existing map. Because new markers are concated with previous one, offset is here to prevent the existing from being re-created.
- raw: {} # raw json to pass additional options
-
- #Stored variables
- @markers = [] # contains all markers. A marker contains the following: {"description": , "longitude": , "title":, "latitude":, "picture": "", "width": "", "length": "", "sidebar": "", "serviceObject": google_marker}
- @boundsObject = null # contains current bounds from markers, polylines etc...
- @polygons = [] # contains raw data, array of arrays (first element could be a hash containing options)
- @polylines = [] # contains raw data, array of arrays (first element could be a hash containing options)
- @circles = [] # contains raw data, array of hash
- @markerClusterer = null # contains all marker clusterers
- @markerImages = []
-
- #Polyline Styling
- @polylines_conf = #default style for polylines
- strokeColor: "#FF0000"
- strokeOpacity: 1
- strokeWeight: 2
- clickable: false
- zIndex: null
-
- #tnitializes the map
- initialize : ->
- @serviceObject = @createMap()
- @map = @serviceObject #beware, soon deprecated
- if (@map_options.detect_location == true or @map_options.center_on_user == true)
- @findUserLocation(this)
- #resets sidebar if needed
- @resetSidebarContent()
-
- findUserLocation : (map_object) ->
- if (navigator.geolocation)
- #try to retrieve user's position
- positionSuccessful = (position) ->
- map_object.userLocation = map_object.createLatLng(position.coords.latitude, position.coords.longitude)
- #change map's center to focus on user's geoloc if asked
- if(map_object.map_options.center_on_user == true)
- map_object.centerMapOnUser()
- map_object.geolocationSuccess()
- positionFailure = ->
- map_object.geolocationFailure(true)
-
- navigator.geolocation.getCurrentPosition( positionSuccessful, positionFailure)
- else
- #failure but the navigator doesn't handle geolocation
- map_object.geolocationFailure(false)
-
-
- #////////////////////////////////////////////////////
- #//////////////////// DIRECTIONS ////////////////////
- #////////////////////////////////////////////////////
-
- create_direction : ->
- directionsDisplay = new google.maps.DirectionsRenderer()
- directionsService = new google.maps.DirectionsService()
-
- directionsDisplay.setMap(@serviceObject)
- #display panel only if required
- if @direction_conf.display_panel
- directionsDisplay.setPanel(document.getElementById(@direction_conf.panel_id))
-
- directionsDisplay.setOptions
- suppressMarkers: false
- suppressInfoWindows: false
- suppressPolylines: false
-
- request =
- origin: @direction_conf.origin
- destination: @direction_conf.destination
- waypoints: @direction_conf.waypoints
- optimizeWaypoints: @direction_conf.optimizeWaypoints
- unitSystem: google.maps.DirectionsUnitSystem[@direction_conf.unitSystem]
- avoidHighways: @direction_conf.avoidHighways
- avoidTolls: @direction_conf.avoidTolls
- region: @direction_conf.region
- travelMode: google.maps.DirectionsTravelMode[@direction_conf.travelMode]
- language: "en"
-
- directionsService.route request, (response, status) ->
- if (status == google.maps.DirectionsStatus.OK)
- directionsDisplay.setDirections(response)
-
- #////////////////////////////////////////////////////
- #///////////////////// CIRCLES //////////////////////
- #////////////////////////////////////////////////////
-
- #Loops through all circles
- #Loops through all circles and draws them
- create_circles : ->
- for circle in @circles
- @create_circle circle
-
- create_circle : (circle) ->
- #by convention, default style configuration could be integrated in the first element
- if circle == @circles[0]
- @circles_conf.strokeColor = circle.strokeColor if circle.strokeColor?
- @circles_conf.strokeOpacity = circle.strokeOpacity if circle.strokeOpacity?
- @circles_conf.strokeWeight = circle.strokeWeight if circle.strokeWeight?
- @circles_conf.fillColor = circle.fillColor if circle.fillColor?
- @circles_conf.fillOpacity = circle.fillOpacity if circle.fillOpacity?
-
- if circle.lat? and circle.lng?
- # always check if a config is given, if not, use defaults
- # NOTE: is there a cleaner way to do this? Maybe a hash merge of some sort?
- newCircle = new google.maps.Circle
- center: @createLatLng(circle.lat, circle.lng)
- strokeColor: circle.strokeColor || @circles_conf.strokeColor
- strokeOpacity: circle.strokeOpacity || @circles_conf.strokeOpacity
- strokeWeight: circle.strokeWeight || @circles_conf.strokeWeight
- fillOpacity: circle.fillOpacity || @circles_conf.fillOpacity
- fillColor: circle.fillColor || @circles_conf.fillColor
- clickable: circle.clickable || @circles_conf.clickable
- zIndex: circle.zIndex || @circles_conf.zIndex
- radius: circle.radius
-
- circle.serviceObject = newCircle
- newCircle.setMap(@serviceObject)
-
- # clear circles
- clear_circles : ->
- for circle in @circles
- @clear_circle circle
-
- clear_circle : (circle) ->
- circle.serviceObject.setMap(null)
-
- hide_circles : ->
- for circle in @circles
- @hide_circle circle
-
- hide_circle : (circle) ->
- circle.serviceObject.setMap(null)
-
- show_circles : ->
- for circle in @circles
- @show_circle @circle
-
- show_circle : (circle) ->
- circle.serviceObject.setMap(@serviceObject)
-
- #////////////////////////////////////////////////////
- #///////////////////// POLYGONS /////////////////////
- #////////////////////////////////////////////////////
-
- #polygons is an array of arrays. It loops.
- create_polygons : ->
- for polygon in @polygons
- @create_polygon(polygon)
-
- #creates a single polygon, triggered by create_polygons
- create_polygon : (polygon) ->
- polygon_coordinates = []
-
- #Polygon points are in an Array, that's why looping is necessary
- for point in polygon
- latlng = @createLatLng(point.lat, point.lng)
- polygon_coordinates.push(latlng)
- #first element of an Array could contain specific configuration for this particular polygon. If no config given, use default
- if point == polygon[0]
- strokeColor = point.strokeColor || @polygons_conf.strokeColor
- strokeOpacity = point.strokeOpacity || @polygons_conf.strokeOpacity
- strokeWeight = point.strokeWeight || @polygons_conf.strokeWeight
- fillColor = point.fillColor || @polygons_conf.fillColor
- fillOpacity = point.fillOpacity || @polygons_conf.fillOpacity
- clickable = point.clickable || @polygons_conf.clickable
-
- #Construct the polygon
- new_poly = new google.maps.Polygon
- paths: polygon_coordinates
- strokeColor: strokeColor
- strokeOpacity: strokeOpacity
- strokeWeight: strokeWeight
- fillColor: fillColor
- fillOpacity: fillOpacity
- clickable: clickable
- map: @serviceObject
-
- #save polygon in list
- polygon.serviceObject = new_poly
-
-
-
- #////////////////////////////////////////////////////
- #///////////////////// MARKERS //////////////////////
- #////////////////////////////////////////////////////
-
- #creates, clusterizes and adjusts map
- create_markers : ->
- @createServiceMarkersFromMarkers()
- @clusterize()
-
- #create google.maps Markers from data provided by user
- createServiceMarkersFromMarkers : ->
- for marker, index in @markers
- if not @markers[index].serviceObject?
- #extract options, test if value passed or use default
- Lat = @markers[index].lat
- Lng = @markers[index].lng
-
- #alter coordinates if randomize is true
- if @markers_conf.randomize
- LatLng = @randomize(Lat, Lng)
- #retrieve coordinates from the array
- Lat = LatLng[0]
- Lng = LatLng[1]
-
- #save object
- @markers[index].serviceObject = @createMarker
- "marker_picture": if @markers[index].picture then @markers[index].picture else @markers_conf.picture
- "marker_width": if @markers[index].width then @markers[index].width else @markers_conf.width
- "marker_height": if @markers[index].height then @markers[index].height else @markers_conf.length
- "marker_title": if @markers[index].title then @markers[index].title else null
- "marker_anchor": if @markers[index].marker_anchor then @markers[index].marker_anchor else null
- "shadow_anchor": if @markers[index].shadow_anchor then @markers[index].shadow_anchor else null
- "shadow_picture": if @markers[index].shadow_picture then @markers[index].shadow_picture else null
- "shadow_width": if @markers[index].shadow_width then @markers[index].shadow_width else null
- "shadow_height": if @markers[index].shadow_height then @markers[index].shadow_height else null
- "marker_draggable": if @markers[index].draggable then @markers[index].draggable else @markers_conf.draggable
- "rich_marker": if @markers[index].rich_marker then @markers[index].rich_marker else null
- "zindex": if @markers[index].zindex then @markers[index].zindex else null
- "Lat": Lat
- "Lng": Lng
- "index": index
-
- #add infowindowstuff if enabled
- @createInfoWindow(@markers[index])
- #create sidebar if enabled
- @createSidebar(@markers[index])
-
- @markers_conf.offset = @markers.length
-
- #creates Image Anchor Position or return null if nothing passed
- createImageAnchorPosition : (anchorLocation) ->
- if (anchorLocation == null)
- return null
- else
- return @createPoint(anchorLocation[0], anchorLocation[1])
-
-
- #replace old markers with new markers on an existing map
- replaceMarkers : (new_markers, adjustBounds = true) ->
- @clearMarkers()
- #reset previous markers
- @markers = new Array
- #reset current bounds
- @boundsObject = @createLatLngBounds() if adjustBounds
- #reset sidebar content if exists
- @resetSidebarContent()
- #add new markers
- @markers_conf.offset = 0
- @addMarkers(new_markers, adjustBounds)
-
- #add new markers to on an existing map
- addMarkers : (new_markers, adjustBounds = true) ->
- #update the list of markers to take into account
- @markers = @markers.concat(new_markers)
- #put markers on the map
- @create_markers()
- @adjustMapToBounds() if adjustBounds
-
- #////////////////////////////////////////////////////
- #///////////////////// SIDEBAR //////////////////////
- #////////////////////////////////////////////////////
-
- #//creates sidebar
- createSidebar : (marker_container) ->
- if (@markers_conf.list_container)
- ul = document.getElementById(@markers_conf.list_container)
- li = document.createElement('li')
- aSel = document.createElement('a')
- aSel.href = 'javascript:void(0);'
- html = if marker_container.sidebar? then marker_container.sidebar else "Marker"
- aSel.innerHTML = html
- currentMap = this
- aSel.onclick = @sidebar_element_handler(currentMap, marker_container.serviceObject, 'click')
- li.appendChild(aSel)
- ul.appendChild(li)
-
- #moves map to marker clicked + open infowindow
- sidebar_element_handler : (currentMap, marker, eventType) ->
- return () ->
- currentMap.map.panTo(marker.position)
- google.maps.event.trigger(marker, eventType)
-
-
- resetSidebarContent : ->
- if @markers_conf.list_container isnt null
- ul = document.getElementById(@markers_conf.list_container)
- ul.innerHTML = ""
-
- #////////////////////////////////////////////////////
- #////////////////// MISCELLANEOUS ///////////////////
- #////////////////////////////////////////////////////
-
- #to make the map fit the different LatLng points
- adjustMapToBounds : ->
- #FIRST_STEP: retrieve all bounds
- #create the bounds object only if necessary
- if @map_options.auto_adjust or @map_options.bounds isnt null
- @boundsObject = @createLatLngBounds()
-
- #if autodjust is true, must get bounds from markers polylines etc...
- if @map_options.auto_adjust
- #from markers
- @extendBoundsWithMarkers()
-
- #from polylines:
- @updateBoundsWithPolylines()
-
- #from polygons:
- @updateBoundsWithPolygons()
-
- #from circles
- @updateBoundsWithCircles()
-
- #in every case, I've to take into account the bounds set up by the user
- @extendMapBounds()
-
- #SECOND_STEP: ajust the map to the bounds
- @adaptMapToBounds()
-
- #////////////////////////////////////////////////////
- #/////////////////// POLYLINES //////////////////////
- #////////////////////////////////////////////////////
-
- #replace old markers with new markers on an existing map
- replacePolylines : (new_polylines) ->
- #reset previous polylines and kill them from map
- @destroy_polylines()
- #set new polylines
- @polylines = new_polylines
- #create
- @create_polylines()
- #.... and adjust map boundaries
- @adjustMapToBounds()
-
- destroy_polylines : ->
- for polyline in @polylines
- #delete polylines from map
- polyline.serviceObject.setMap(null)
- #empty array
- @polylines = []
-
- #polylines is an array of arrays. It loops.
- create_polylines : ->
- for polyline in @polylines
- @create_polyline polyline
-
- #////////////////////////////////////////////////////
- #///////////////// Basic functions //////////////////
- #///////////////////tests coded//////////////////////
-
- #//basic function to check existence of a variable
- exists : (var_name) ->
- return (var_name != "" and typeof var_name != "undefined")
-
-
- #randomize
- randomize : (Lat0, Lng0) ->
- #distance in meters between 0 and max_random_distance (positive or negative)
- dx = @markers_conf.max_random_distance * @random()
- dy = @markers_conf.max_random_distance * @random()
- Lat = parseFloat(Lat0) + (180/Math.PI)*(dy/6378137)
- Lng = parseFloat(Lng0) + ( 90/Math.PI)*(dx/6378137)/Math.cos(Lat0)
- return [Lat, Lng]
-
- mergeObjectWithDefault : (object1, object2) ->
- copy_object1 = {}
- for key, value of object1
- copy_object1[key] = value
-
- for key, value of object2
- unless copy_object1[key]?
- copy_object1[key] = value
- return copy_object1
-
- mergeWithDefault : (objectName) ->
- default_object = @["default_" + objectName]
- object = @[objectName]
- @[objectName] = @mergeObjectWithDefault(object, default_object)
- return true
-
- #gives a value between -1 and 1
- random : -> return(Math.random() * 2 -1)
diff --git a/app/assets/javascripts/search/gmaps4rails/gmaps4rails.bing.js.coffee b/app/assets/javascripts/search/gmaps4rails/gmaps4rails.bing.js.coffee
deleted file mode 100644
index 9eb53a6b76..0000000000
--- a/app/assets/javascripts/search/gmaps4rails/gmaps4rails.bing.js.coffee
+++ /dev/null
@@ -1,174 +0,0 @@
-######################################################################################################
-############################################## Bing Maps ##########################################
-######################################################################################################
-
-#// http://wiki.openstreetmap.org/wiki/OpenLayers
-#// http://openlayers.org/dev/examples
-#//http://docs.openlayers.org/contents.html
-
-class @Gmaps4RailsBing extends Gmaps4Rails
-
- constructor: ->
- super
- @map_options =
- type: "road" # aerial, auto, birdseye, collinsBart, mercator, ordnanceSurvey, road
- @markers_conf =
- infobox: "description" #description or htmlContent
-
- @mergeWithDefault("map_options")
- @mergeWithDefault("markers_conf")
-
- #////////////////////////////////////////////////////
- #/////////////// Basic Objects //////////////
- #////////////////////////////////////////////////////
-
- getMapType: ->
- switch @map_options.type
- when "road" then return Microsoft.Maps.MapTypeId.road
- when "aerial" then return Microsoft.Maps.MapTypeId.aerial
- when "auto" then return Microsoft.Maps.MapTypeId.auto
- when "birdseye" then return Microsoft.Maps.MapTypeId.birdseye
- when "collinsBart" then return Microsoft.Maps.MapTypeId.collinsBart
- when "mercator" then return Microsoft.Maps.MapTypeId.mercator
- when "ordnanceSurvey" then return Microsoft.Maps.MapTypeId.ordnanceSurvey
- else return Microsoft.Maps.MapTypeId.auto
-
- createPoint: (lat, lng) ->
- return new Microsoft.Maps.Point(lat, lng)
-
- createLatLng:(lat, lng) ->
- return new Microsoft.Maps.Location(lat, lng)
-
- createLatLngBounds: ->
-
- createMap: ->
- return new Microsoft.Maps.Map(document.getElementById(@map_options.id), {
- credentials: @map_options.provider_key,
- mapTypeId: @getMapType(),
- center: @createLatLng(@map_options.center_latitude, @map_options.center_longitude),
- zoom: @map_options.zoom
- })
-
- createSize: (width, height) ->
- return new google.maps.Size(width, height)
-
- #////////////////////////////////////////////////////
- #////////////////////// Markers /////////////////////
- #////////////////////////////////////////////////////
-
- createMarker: (args) ->
- markerLatLng = @createLatLng(args.Lat, args.Lng)
- marker
- #// Marker sizes are expressed as a Size of X,Y
- if args.marker_picture == ""
- marker = new Microsoft.Maps.Pushpin(@createLatLng(args.Lat, args.Lng), {
- draggable: args.marker_draggable,
- anchor: @createImageAnchorPosition(args.Lat, args.Lng),
- text: args.marker_title
- }
- );
- else
- marker = new Microsoft.Maps.Pushpin(@createLatLng(args.Lat, args.Lng), {
- draggable: args.marker_draggable,
- anchor: @createImageAnchorPosition(args.Lat, args.Lng),
- icon: args.marker_picture,
- height: args.marker_height,
- text: args.marker_title,
- width: args.marker_width
- }
- );
- @addToMap(marker)
- return marker
-
- #// clear markers
- clearMarkers: ->
- for marker in @markers
- @clearMarker marker
-
- clearMarker: (marker) ->
- @removeFromMap(marker.serviceObject)
-
- #//show and hide markers
- showMarkers: ->
- for marker in @markers
- @showMarker marker
-
- showMarker: (marker) ->
- marker.serviceObject.setOptions({ visible: true })
-
- hideMarkers: ->
- for marker in @markers
- @hideMarker marker
-
- hideMarker: (marker) ->
- marker.serviceObject.setOptions({ visible: false })
-
- extendBoundsWithMarkers: ->
- locationsArray = []
- for marker in @markers
- locationsArray.push(marker.serviceObject.getLocation())
- @boundsObject = Microsoft.Maps.LocationRect.fromLocations(locationsArray)
-
- #////////////////////////////////////////////////////
- #/////////////////// Clusterer //////////////////////
- #////////////////////////////////////////////////////
-
- createClusterer: (markers_array) ->
-
- clearClusterer: ->
-
- #//creates clusters
- clusterize: ->
-
- #////////////////////////////////////////////////////
- #/////////////////// INFO WINDOW ////////////////////
- #////////////////////////////////////////////////////
-
- #// creates infowindows
- createInfoWindow: (marker_container) ->
- if marker_container.description?
- #//create the infowindow
- if @markers_conf.infobox == "description"
- marker_container.info_window = new Microsoft.Maps.Infobox(marker_container.serviceObject.getLocation(), { description: marker_container.description, visible: false, showCloseButton: true})
- else
- marker_container.info_window = new Microsoft.Maps.Infobox(marker_container.serviceObject.getLocation(), { htmlContent: marker_container.description, visible: false})
-
- #//add the listener associated
- currentMap = this
- Microsoft.Maps.Events.addHandler(marker_container.serviceObject, 'click', @openInfoWindow(currentMap, marker_container.info_window))
- @addToMap(marker_container.info_window)
-
- openInfoWindow: (currentMap, infoWindow) ->
- return ->
- # Close the latest selected marker before opening the current one.
- if currentMap.visibleInfoWindow
- currentMap.visibleInfoWindow.setOptions({ visible: false })
- infoWindow.setOptions({ visible:true })
- currentMap.visibleInfoWindow = infoWindow
-
- #////////////////////////////////////////////////////
- #/////////////////// Other methods //////////////////
- #////////////////////////////////////////////////////
-
- fitBounds: ->
- @serviceObject.setView({bounds: @boundsObject})
-
- addToMap: (object)->
- @serviceObject.entities.push(object)
-
- removeFromMap: (object)->
- @serviceObject.entities.remove(object)
-
- centerMapOnUser: ->
- @serviceObject.setView({ center: @userLocation})
-
- updateBoundsWithPolylines: ()->
-
- updateBoundsWithPolygons: ()->
-
- updateBoundsWithCircles: ()->
-
- extendMapBounds :->
-
- adaptMapToBounds: ->
- @fitBounds()
\ No newline at end of file
diff --git a/app/assets/javascripts/search/gmaps4rails/gmaps4rails.googlemaps.js.coffee b/app/assets/javascripts/search/gmaps4rails/gmaps4rails.googlemaps.js.coffee
deleted file mode 100644
index ed52ddc15a..0000000000
--- a/app/assets/javascripts/search/gmaps4rails/gmaps4rails.googlemaps.js.coffee
+++ /dev/null
@@ -1,339 +0,0 @@
-#######################################################################################################
-############################################## Google maps ##########################################
-#######################################################################################################
-
-class @Gmaps4RailsGoogle extends Gmaps4Rails
-
- constructor: ->
- super
- #Map settings
- @map_options =
- disableDefaultUI: false
- disableDoubleClickZoom: false
- type: "ROADMAP" # HYBRID, ROADMAP, SATELLITE, TERRAIN
-
- #markers + info styling
- @markers_conf =
- clusterer_gridSize: 50
- clusterer_maxZoom: 5
- custom_cluster_pictures: null
- custom_infowindow_class: null
-
- @mergeWithDefault("map_options")
- @mergeWithDefault("markers_conf")
-
- @kml_options =
- clickable: true
- preserveViewport: false
- suppressInfoWindows: false
-
- #Polygon Styling
- @polygons_conf = # default style for polygons
- strokeColor: "#FFAA00"
- strokeOpacity: 0.8
- strokeWeight: 2
- fillColor: "#000000"
- fillOpacity: 0.35
- clickable: false
-
- #Circle Styling
- @circles_conf = #default style for circles
- fillColor: "#00AAFF"
- fillOpacity: 0.35
- strokeColor: "#FFAA00"
- strokeOpacity: 0.8
- strokeWeight: 2
- clickable: false
- zIndex: null
-
- #Direction Settings
- @direction_conf =
- panel_id: null
- display_panel: false
- origin: null
- destination: null
- waypoints: [] #[{location: "toulouse,fr", stopover: true}, {location: "Clermont-Ferrand, fr", stopover: true}]
- optimizeWaypoints: false
- unitSystem: "METRIC" #IMPERIAL
- avoidHighways: false
- avoidTolls: false
- region: null
- travelMode: "DRIVING" #WALKING, BICYCLING
-
- #////////////////////////////////////////////////////
- #/////////////// Basic Objects //////////////
- #////////////////////////////////////////////////////
-
- createPoint : (lat, lng) ->
- return new google.maps.Point(lat, lng)
-
- createLatLng : (lat, lng) ->
- return new google.maps.LatLng(lat, lng)
-
- createLatLngBounds : ->
- return new google.maps.LatLngBounds()
-
- createMap : ->
- defaultOptions =
- maxZoom: @map_options.maxZoom
- minZoom: @map_options.minZoom
- zoom: @map_options.zoom
- center: @createLatLng(@map_options.center_latitude, @map_options.center_longitude)
- mapTypeId: google.maps.MapTypeId[@map_options.type]
- mapTypeControl: @map_options.mapTypeControl
- disableDefaultUI: @map_options.disableDefaultUI
- disableDoubleClickZoom: @map_options.disableDoubleClickZoom
- draggable: @map_options.draggable
-
- mergedOptions = @mergeObjectWithDefault @map_options.raw, defaultOptions
-
- return new google.maps.Map document.getElementById(@map_options.id), mergedOptions
-
-
- createMarkerImage : (markerPicture, markerSize, origin, anchor, scaledSize) ->
- return new google.maps.MarkerImage(markerPicture, markerSize, origin, anchor, scaledSize)
-
- createSize : (width, height) ->
- return new google.maps.Size(width, height)
-
- #////////////////////////////////////////////////////
- #////////////////////// Markers /////////////////////
- #////////////////////////////////////////////////////
-
- createMarker : (args) ->
- markerLatLng = @createLatLng(args.Lat, args.Lng)
- #Marker sizes are expressed as a Size of X,Y
- if args.marker_picture == "" and args.rich_marker == null
- defaultOptions = {position: markerLatLng, map: @serviceObject, title: args.marker_title, draggable: args.marker_draggable, zIndex: args.zindex}
- mergedOptions = @mergeObjectWithDefault @markers_conf.raw, defaultOptions
- return new google.maps.Marker mergedOptions
-
- if (args.rich_marker != null)
- return new RichMarker({
- position: markerLatLng
- map: @serviceObject
- draggable: args.marker_draggable
- content: args.rich_marker
- flat: if args.marker_anchor == null then false else args.marker_anchor[1]
- anchor: if args.marker_anchor == null then 0 else args.marker_anchor[0]
- zIndex: args.zindex
- })
-
- #default behavior
- #calculate MarkerImage anchor location
- imageAnchorPosition = @createImageAnchorPosition args.marker_anchor
- shadowAnchorPosition = @createImageAnchorPosition args.shadow_anchor
- #create or retrieve existing MarkerImages
- markerImage = @createOrRetrieveImage(args.marker_picture, args.marker_width, args.marker_height, imageAnchorPosition)
- shadowImage = @createOrRetrieveImage(args.shadow_picture, args.shadow_width, args.shadow_height, shadowAnchorPosition)
- defaultOptions = {position: markerLatLng, map: @serviceObject, icon: markerImage, title: args.marker_title, draggable: args.marker_draggable, shadow: shadowImage, zIndex: args.zindex}
- mergedOptions = @mergeObjectWithDefault @markers_conf.raw, defaultOptions
- return new google.maps.Marker mergedOptions
-
- #checks if obj is included in arr Array and returns the position or false
- includeMarkerImage : (arr, obj) ->
- for object, index in arr
- return index if object.url == obj
- return false
-
- #checks if MarkerImage exists before creating a new one
- #returns a MarkerImage or false if ever something wrong is passed as argument
- createOrRetrieveImage : (currentMarkerPicture, markerWidth, markerHeight, imageAnchorPosition) ->
- return null if (currentMarkerPicture == "" or currentMarkerPicture == null )
-
- test_image_index = @includeMarkerImage(@markerImages, currentMarkerPicture)
- switch test_image_index
- when false
- markerImage = @createMarkerImage(currentMarkerPicture, @createSize(markerWidth, markerHeight), null, imageAnchorPosition, null )
- @markerImages.push(markerImage)
- return markerImage
- break
- else
- return @markerImages[test_image_index] if typeof test_image_index == 'number'
- return false
-
- #clear markers
- clearMarkers : ->
- for marker in @markers
- @clearMarker marker
-
- #show and hide markers
- showMarkers : ->
- for marker in @markers
- @showMarker marker
-
- hideMarkers : ->
- for marker in @markers
- @hideMarker marker
-
- clearMarker : (marker) ->
- marker.serviceObject.setMap(null)
-
- showMarker : (marker) ->
- marker.serviceObject.setVisible(true)
-
- hideMarker : (marker) ->
- marker.serviceObject.setVisible(false)
-
- extendBoundsWithMarkers : ->
- for marker in @markers
- @boundsObject.extend(marker.serviceObject.position)
-
- #////////////////////////////////////////////////////
- #/////////////////// Clusterer //////////////////////
- #////////////////////////////////////////////////////
-
- createClusterer : (markers_array) ->
- return new MarkerClusterer( @serviceObject, markers_array, { maxZoom: @markers_conf.clusterer_maxZoom, gridSize: @markers_conf.clusterer_gridSize, styles: @customClusterer() })
-
- clearClusterer : ->
- @markerClusterer.clearMarkers()
-
- #creates clusters
- clusterize : ->
- if @markers_conf.do_clustering == true
- #first clear the existing clusterer if any
- @clearClusterer() if @markerClusterer != null
-
- markers_array = new Array
- for marker in @markers
- markers_array.push(marker.serviceObject)
-
- @markerClusterer = @createClusterer(markers_array)
-
- #////////////////////////////////////////////////////
- #/////////////////// INFO WINDOW ////////////////////
- #////////////////////////////////////////////////////
-
- #// creates infowindows
- createInfoWindow : (marker_container) ->
- if typeof(@jsTemplate) == "function" or marker_container.description?
- marker_container.description = @jsTemplate(marker_container) if typeof(@jsTemplate) == "function"
- if @markers_conf.custom_infowindow_class != null
- #creating custom infowindow
- boxText = document.createElement("div")
- boxText.setAttribute("class", @markers_conf.custom_infowindow_class) #to customize
- boxText.innerHTML = marker_container.description
- marker_container.infowindow = new InfoBox(@infobox(boxText))
- currentMap = this
- google.maps.event.addListener(marker_container.serviceObject, 'click', @openInfoWindow(currentMap, marker_container.infowindow, marker_container.serviceObject))
- else
- #create default infowindow
- marker_container.infowindow = new google.maps.InfoWindow({content: marker_container.description })
- #add the listener associated
- currentMap = this
- google.maps.event.addListener(marker_container.serviceObject, 'click', @openInfoWindow(currentMap, marker_container.infowindow, marker_container.serviceObject))
-
- openInfoWindow : (currentMap, infoWindow, marker) ->
- return ->
- # Close the latest selected marker before opening the current one.
- currentMap.visibleInfoWindow.close() if currentMap.visibleInfoWindow != null
- infoWindow.open(currentMap.serviceObject, marker)
- currentMap.visibleInfoWindow = infoWindow
-
- #////////////////////////////////////////////////////
- #///////////////// KML //////////////////
- #////////////////////////////////////////////////////
-
- createKmlLayer : (kml) ->
- kml_options = kml.options || {}
- kml_options = @mergeObjectWithDefault(kml_options, @kml_options)
- kml = new google.maps.KmlLayer( kml.url, kml_options)
- kml.setMap(@serviceObject)
- return kml
-
- #////////////////////////////////////////////////////
- #/////////////////// POLYLINES //////////////////////
- #////////////////////////////////////////////////////
-
- #creates a single polyline, triggered by create_polylines
- create_polyline : (polyline) ->
- polyline_coordinates = []
-
- #2 cases here, either we have a coded array of LatLng or we have an Array of LatLng
- for element in polyline
- #if we have a coded array
- if element.coded_array?
- decoded_array = new google.maps.geometry.encoding.decodePath(element.coded_array)
- #loop through every point in the array
- for point in decoded_array
- polyline_coordinates.push(point)
-
- #or we have an array of latlng
- else
- #by convention, a single polyline could be customized in the first array or it uses default values
- if element == polyline[0]
- strokeColor = element.strokeColor || @polylines_conf.strokeColor
- strokeOpacity = element.strokeOpacity || @polylines_conf.strokeOpacity
- strokeWeight = element.strokeWeight || @polylines_conf.strokeWeight
- clickable = element.clickable || @polylines_conf.clickable
- zIndex = element.zIndex || @polylines_conf.zIndex
-
- #add latlng if positions provided
- if element.lat? && element.lng?
- latlng = @createLatLng(element.lat, element.lng)
- polyline_coordinates.push(latlng)
-
- # Construct the polyline
- new_poly = new google.maps.Polyline
- path: polyline_coordinates
- strokeColor: strokeColor
- strokeOpacity: strokeOpacity
- strokeWeight: strokeWeight
- clickable: clickable
- zIndex: zIndex
-
- #save polyline
- polyline.serviceObject = new_poly
- new_poly.setMap(@serviceObject)
-
-
- updateBoundsWithPolylines: ()->
- for polyline in @polylines
- polyline_points = polyline.serviceObject.latLngs.getArray()[0].getArray()
- for point in polyline_points
- @boundsObject.extend point
-
- #////////////////////////////////////////////////////
- #///////////////// KML //////////////////
- #////////////////////////////////////////////////////
-
- create_kml : ->
- for kml in @kml
- kml.serviceObject = @createKmlLayer kml
-
- #////////////////////////////////////////////////////
- #/////////////////// Other methods //////////////////
- #////////////////////////////////////////////////////
-
- fitBounds : ->
- @serviceObject.fitBounds(@boundsObject) unless @boundsObject.isEmpty()
-
- centerMapOnUser : ->
- @serviceObject.setCenter(@userLocation)
-
- updateBoundsWithPolygons: ()->
- for polygon in @polygons
- polygon_points = polygon.serviceObject.latLngs.getArray()[0].getArray()
- for point in polygon_points
- @boundsObject.extend point
-
- updateBoundsWithCircles: ()->
- for circle in @circles
- @boundsObject.extend(circle.serviceObject.getBounds().getNorthEast())
- @boundsObject.extend(circle.serviceObject.getBounds().getSouthWest())
-
- extendMapBounds: ()->
- for bound in @map_options.bounds
- #create points from bounds provided
- @boundsObject.extend @createLatLng(bound.lat, bound.lng)
-
- adaptMapToBounds:()->
- #if autozoom is false, take user info into account
- if !@map_options.auto_zoom
- map_center = @boundsObject.getCenter()
- @map_options.center_latitude = map_center.lat()
- @map_options.center_longitude = map_center.lng()
- @serviceObject.setCenter(map_center)
- else
- @fitBounds()
diff --git a/app/assets/javascripts/search/gmaps4rails/gmaps4rails.mapquest.js.coffee b/app/assets/javascripts/search/gmaps4rails/gmaps4rails.mapquest.js.coffee
deleted file mode 100644
index 08fca694d0..0000000000
--- a/app/assets/javascripts/search/gmaps4rails/gmaps4rails.mapquest.js.coffee
+++ /dev/null
@@ -1,145 +0,0 @@
-#######################################################################################################
-############################################## Map Quest #############################################
-#######################################################################################################
-# http://developer.mapquest.com/web/documentation/sdk/javascript/v7.0/api/MQA.Poi.html
-
-class @Gmaps4RailsMapquest extends Gmaps4Rails
-
- constructor: ->
- super
- #Map settings
- @map_options = {type: "map"} #map type (map, sat, hyb)
- @markers_conf = {}
- @mergeWithDefault "markers_conf"
- @mergeWithDefault "map_options"
-
- #////////////////////////////////////////////////////
- #/////////////// Basic Objects //////////////
- #////////////////////////////////////////////////////
-
- createPoint: (lat, lng) ->
- return new MQA.Poi({lat: lat, lng: lng})
-
- createLatLng: (lat, lng) ->
- return {lat: lat, lng: lng}
-
- createLatLngBounds: ->
-
- createMap: ->
- map = new MQA.TileMap( #// Constructs an instance of MQA.TileMap
- document.getElementById(@map_options.id), #//the id of the element on the page you want the map to be added into
- @map_options.zoom, #//intial zoom level of the map
- {lat: @map_options.center_latitude, lng: @map_options.center_longitude},
- @map_options.type) #//map type (map, sat, hyb)
-
- MQA.withModule('zoomcontrol3', (->
- map.addControl(
- new MQA.LargeZoomControl3(),
- new MQA.MapCornerPlacement(MQA.MapCorner.TOP_LEFT)
- )
- ))
- return map
-
- createMarkerImage: (markerPicture, markerSize, origin, anchor, scaledSize) ->
-
- #////////////////////////////////////////////////////
- #////////////////////// Markers /////////////////////
- #////////////////////////////////////////////////////
-
- createMarker: (args)->
- marker = new MQA.Poi( {lat: args.Lat, lng: args.Lng} )
-
- if args.marker_picture != ""
- icon = new MQA.Icon(args.marker_picture, args.marker_height, args.marker_width)
- marker.setIcon(icon)
- if args.marker_anchor != null
- marker.setBias({x: args.marker_anchor[0], y: args.marker_anchor[1]})
-
- if args.shadow_picture != ""
- icon = new MQA.Icon(args.shadow_picture, args.shadow_height, args.shadow_width)
- marker.setShadow(icon)
-
- if args.shadow_anchor != null
- marker.setShadowOffset({x: args.shadow_anchor[0], y: args.shadow_anchor[1]})
-
- @addToMap marker
- return marker
-
-
- #// clear markers
- clearMarkers: ->
- for marker in markers
- @clearMarker marker
-
- #//show and hide markers
- showMarkers: ->
- for marker in markers
- @showMarker marker
-
- hideMarkers: ->
- for marker in markers
- @hideMarker marker
-
- clearMarker: (marker) ->
- @removeFromMap(marker.serviceObject)
-
- showMarker: (marker) ->
- #// marker.serviceObject
-
- hideMarker: (marker) ->
- #// marker.serviceObject
-
- extendBoundsWithMarkers: ->
- if @markers.length >=2
- @boundsObject = new MQA.RectLL(@markers[0].serviceObject.latLng, @markers[1].serviceObject.latLng)
- for marker in @markers
- @boundsObject.extend marker.serviceObject.latLng
-
- #////////////////////////////////////////////////////
- #/////////////////// Clusterer //////////////////////
- #////////////////////////////////////////////////////
-
- createClusterer: (markers_array) ->
-
- clearClusterer: ->
-
- #//creates clusters
- clusterize: ->
-
- #////////////////////////////////////////////////////
- #/////////////////// INFO WINDOW ////////////////////
- #////////////////////////////////////////////////////
-
- #// creates infowindows
- createInfoWindow: (marker_container) ->
- marker_container.serviceObject.setInfoTitleHTML(marker_container.description)
- #//TODO: how to disable the mouseover display when using setInfoContentHTML?
- #//marker_container.serviceObject.setInfoContentHTML(marker_container.description);
-
- #////////////////////////////////////////////////////
- #/////////////////// Other methods //////////////////
- #////////////////////////////////////////////////////
-
- fitBounds: ->
- @serviceObject.zoomToRect @boundsObject if @markers.length >=2
- @serviceObject.setCenter @markers[0].serviceObject.latLng if @markers.length == 1
-
- centerMapOnUser: ->
- @serviceObject.setCenter @userLocation
-
- addToMap: (object) ->
- @serviceObject.addShape object
-
- removeFromMap: (object)->
- @serviceObject.removeShape object
-
- updateBoundsWithPolylines: ()->
-
- updateBoundsWithPolygons: ()->
-
- updateBoundsWithCircles: ()->
-
- extendMapBounds :->
-
- adaptMapToBounds: ->
- @fitBounds()
\ No newline at end of file
diff --git a/app/assets/javascripts/search/gmaps4rails/gmaps4rails.openlayers.js.coffee b/app/assets/javascripts/search/gmaps4rails/gmaps4rails.openlayers.js.coffee
deleted file mode 100644
index 1cddc04e39..0000000000
--- a/app/assets/javascripts/search/gmaps4rails/gmaps4rails.openlayers.js.coffee
+++ /dev/null
@@ -1,261 +0,0 @@
-#######################################################################################################
-############################################## Open Layers ##########################################
-#######################################################################################################
-
-#// http://wiki.openstreetmap.org/wiki/OpenLayers
-#// http://openlayers.org/dev/examples
-#//http://docs.openlayers.org/contents.html
-
-class @Gmaps4RailsOpenlayers extends Gmaps4Rails
-
- constructor: ->
- super
- @map_options = {}
- @mergeWithDefault "map_options"
- @markers_conf = {}
- @mergeWithDefault "markers_conf"
-
- @openMarkers = null
- @markersLayer = null
- @markersControl = null
- @polylinesLayer = null
-
- #////////////////////////////////////////////////////
- #/////////////// Basic Objects ////////////////////
- #////////////////////////////////////////////////////
-
- createPoint: (lat, lng)->
-
- createLatLng: (lat, lng)->
- return new OpenLayers.LonLat(lng, lat).transform(new OpenLayers.Projection("EPSG:4326"), new OpenLayers.Projection("EPSG:900913")) # transform from WGS 1984 to Spherical Mercator Projection
-
- createAnchor: (offset)->
- return null if offset == null
- return new OpenLayers.Pixel(offset[0], offset[1])
-
- createSize: (width, height)->
- return new OpenLayers.Size(width, height)
-
- createLatLngBounds: ->
- return new OpenLayers.Bounds()
-
- createMap: ->
- #//todo add customization: kind of map and other map options
- map = new OpenLayers.Map(@map_options.id)
- map.addLayer(new OpenLayers.Layer.OSM())
- map.setCenter(@createLatLng(@map_options.center_latitude, @map_options.center_longitude), #// Center of the map
- @map_options.zoom) #// Zoom level
- return map
-
- #////////////////////////////////////////////////////
- #////////////////////// Markers /////////////////////
- #////////////////////////////////////////////////////
- #//http://openlayers.org/dev/examples/marker-shadow.html
- createMarker: (args) ->
- style_mark = OpenLayers.Util.extend({}, OpenLayers.Feature.Vector.style['default'])
- style_mark.fillOpacity = 1
-
- #//creating markers' dedicated layer
- if (@markersLayer == null)
- @markersLayer = new OpenLayers.Layer.Vector("Markers", null)
- @serviceObject.addLayer(@markersLayer)
- #//TODO move?
- @markersLayer.events.register("featureselected", @markersLayer, @onFeatureSelect)
- @markersLayer.events.register("featureunselected", @markersLayer, @onFeatureUnselect)
- @markersControl = new OpenLayers.Control.SelectFeature(@markersLayer)
- @serviceObject.addControl(@markersControl)
- @markersControl.activate()
- #//showing default pic if none available
- if args.marker_picture == ""
- #style_mark.graphicWidth = 24
- style_mark.graphicHeight = 30
- style_mark.externalGraphic = "http://openlayers.org/dev/img/marker-blue.png"
- #//creating custom pic
- else
- style_mark.graphicWidth = args.marker_width
- style_mark.graphicHeight = args.marker_height
- style_mark.externalGraphic = args.marker_picture
- #//adding anchor if any
- if args.marker_anchor != null
- style_mark.graphicXOffset = args.marker_anchor[0]
- style_mark.graphicYOffset = args.marker_anchor[1]
- #//adding shadow if any
- if args.shadow_picture != ""
- style_mark.backgroundGraphic = args.shadow_picture
- style_mark.backgroundWidth = args.shadow_width
- style_mark.backgroundHeight = args.shadow_height
- #//adding shadow's anchor if any
- if args.shadow_anchor != null
- style_mark.backgroundXOffset = args.shadow_anchor[0]
- style_mark.backgroundYOffset = args.shadow_anchor[1]
-
- style_mark.graphicTitle = args.marker_title
- marker = new OpenLayers.Feature.Vector(
- new OpenLayers.Geometry.Point(args.Lng, args.Lat),
- null,
- style_mark)
- #//changing coordinates so that it actually appears on the map!
- marker.geometry.transform(new OpenLayers.Projection("EPSG:4326"), new OpenLayers.Projection("EPSG:900913"))
- #//adding layer to the map
- @markersLayer.addFeatures([marker])
-
- return marker
-
- #//clear markers
- clearMarkers: ->
- @clearMarkersLayerIfExists()
- @markersLayer = null
- @boundsObject = new OpenLayers.Bounds()
-
- clearMarkersLayerIfExists: ->
- @serviceObject.removeLayer(@markersLayer) if @markersLayer != null and @serviceObject.getLayer(@markersLayer.id) != null
-
- extendBoundsWithMarkers: ->
- console.log "here"
- for marker in @markers
- @boundsObject.extend(@createLatLng(marker.lat,marker.lng))
-
- #////////////////////////////////////////////////////
- #/////////////////// Clusterer //////////////////////
- #////////////////////////////////////////////////////
- #//too ugly to be considered valid :(
-
- createClusterer: (markers_array)->
- options =
- pointRadius: "${radius}"
- fillColor: "#ffcc66"
- fillOpacity: 0.8
- strokeColor: "#cc6633"
- strokeWidth: "${width}"
- strokeOpacity: 0.8
- funcs =
- context:
- width: (feature) ->
- return (feature.cluster) ? 2 : 1
- radius: (feature) ->
- pix = 2
- pix = Math.min(feature.attributes.count, 7) + 2 if feature.cluster
- return pix
-
- style = new OpenLayers.Style options, funcs
-
- strategy = new OpenLayers.Strategy.Cluster()
-
- clusters = new OpenLayers.Layer.Vector "Clusters",
- strategies: [strategy]
- styleMap: new OpenLayers.StyleMap
- "default": style
- "select":
- fillColor: "#8aeeef"
- strokeColor: "#32a8a9"
-
- @clearMarkersLayerIfExists()
- @serviceObject.addLayer(clusters)
- clusters.addFeatures(markers_array)
- return clusters
-
- clusterize: ->
-
- if @markers_conf.do_clustering == true
- #//first clear the existing clusterer if any
- if @markerClusterer != null
- @clearClusterer()
- markers_array = new Array
- for marker in @markers
- markers_array.push(marker.serviceObject)
- @markerClusterer = @createClusterer markers_array
-
- clearClusterer: ->
- @serviceObject.removeLayer @markerClusterer
-
- #////////////////////////////////////////////////////
- #/////////////////// INFO WINDOW ////////////////////
- #////////////////////////////////////////////////////
-
- #// creates infowindows
- createInfoWindow: (marker_container) ->
- marker_container.serviceObject.infoWindow = marker_container.description if marker_container.description?
-
- onPopupClose: (evt) ->
- #// 'this' is the popup.
- @markersControl.unselect @feature
-
- onFeatureSelect: (evt) ->
- feature = evt.feature
- popup = new OpenLayers.Popup.FramedCloud("featurePopup",
- feature.geometry.getBounds().getCenterLonLat(),
- new OpenLayers.Size(300,200),
- feature.infoWindow,
- null, true, @onPopupClose)
- feature.popup = popup
- popup.feature = feature
- @map.addPopup popup
-
- onFeatureUnselect: (evt) ->
- feature = evt.feature
- if feature.popup
- #//popup.feature = null;
- @map.removePopup feature.popup
- feature.popup.destroy()
- feature.popup = null
-
- #////////////////////////////////////////////////////
- #/////////////////// POLYLINES //////////////////////
- #////////////////////////////////////////////////////
-
- create_polyline : (polyline) ->
-
- if(@polylinesLayer == null)
- @polylinesLayer = new OpenLayers.Layer.Vector("Polylines", null)
- @serviceObject.addLayer(@polylinesLayer)
- @polylinesLayer.events.register("featureselected", @polylinesLayer, @onFeatureSelect)
- @polylinesLayer.events.register("featureunselected", @polylinesLayer, @onFeatureUnselect)
- @polylinesControl = new OpenLayers.Control.DrawFeature(@polylinesLayer, OpenLayers.Handler.Path)
- @serviceObject.addControl(@polylinesControl)
-
- polyline_coordinates = []
-
- for element in polyline
- #by convention, a single polyline could be customized in the first array or it uses default values
- if element == polyline[0]
- strokeColor = element.strokeColor || @polylines_conf.strokeColor
- strokeOpacity = element.strokeOpacity || @polylines_conf.strokeOpacity
- strokeWeight = element.strokeWeight || @polylines_conf.strokeWeight
- clickable = element.clickable || @polylines_conf.clickable
- zIndex = element.zIndex || @polylines_conf.zIndex
-
- #add latlng if positions provided
- if element.lat? && element.lng?
- latlng = new OpenLayers.Geometry.Point(element.lng, element.lat)
- polyline_coordinates.push(latlng)
-
- line_points = new OpenLayers.Geometry.LineString(polyline_coordinates);
- line_style = { strokeColor: strokeColor, strokeOpacity: strokeOpacity, strokeWidth: strokeWeight };
-
- polyline = new OpenLayers.Feature.Vector(line_points, null, line_style);
- polyline.geometry.transform(new OpenLayers.Projection("EPSG:4326"), new OpenLayers.Projection("EPSG:900913"))
-
- @polylinesLayer.addFeatures([polyline])
-
- return polyline
-
- updateBoundsWithPolylines: ()->
-
- updateBoundsWithPolygons: ()->
-
- updateBoundsWithCircles: ()->
-
- # #////////////////////////////////////////////////////
- # #/////////////////// Other methods //////////////////
- # #////////////////////////////////////////////////////
-
- fitBounds: ->
- @serviceObject.zoomToExtent(@boundsObject, true)
-
- centerMapOnUser: ->
- @serviceObject.setCenter @userLocation
-
- extendMapBounds :->
-
- adaptMapToBounds: ->
- @fitBounds()
diff --git a/app/assets/javascripts/search/jquery.backstretch.js b/app/assets/javascripts/search/jquery.backstretch.js
deleted file mode 100644
index 4cb7175e99..0000000000
--- a/app/assets/javascripts/search/jquery.backstretch.js
+++ /dev/null
@@ -1,4 +0,0 @@
-/*! Backstretch - v2.0.4 - 2013-06-19
- * http://srobbin.com/jquery-plugins/backstretch/
- * Copyright (c) 2013 Scott Robbin; Licensed MIT */
-(function(a,d,p){a.fn.backstretch=function(c,b){(c===p||0===c.length)&&a.error("No images were supplied for Backstretch");0===a(d).scrollTop()&&d.scrollTo(0,0);return this.each(function(){var d=a(this),g=d.data("backstretch");if(g){if("string"==typeof c&&"function"==typeof g[c]){g[c](b);return}b=a.extend(g.options,b);g.destroy(!0)}g=new q(this,c,b);d.data("backstretch",g)})};a.backstretch=function(c,b){return a("body").backstretch(c,b).data("backstretch")};a.expr[":"].backstretch=function(c){return a(c).data("backstretch")!==p};a.fn.backstretch.defaults={centeredX:!0,centeredY:!0,duration:5E3,fade:0};var r={left:0,top:0,overflow:"hidden",margin:0,padding:0,height:"100%",width:"100%",zIndex:-999999},s={position:"absolute",display:"none",margin:0,padding:0,border:"none",width:"auto",height:"auto",maxHeight:"none",maxWidth:"none",zIndex:-999999},q=function(c,b,e){this.options=a.extend({},a.fn.backstretch.defaults,e||{});this.images=a.isArray(b)?b:[b];a.each(this.images,function(){a("
")[0].src=this});this.isBody=c===document.body;this.$container=a(c);this.$root=this.isBody?l?a(d):a(document):this.$container;c=this.$container.children(".backstretch").first();this.$wrap=c.length?c:a('
').css(r).appendTo(this.$container);this.isBody||(c=this.$container.css("position"),b=this.$container.css("zIndex"),this.$container.css({position:"static"===c?"relative":c,zIndex:"auto"===b?0:b,background:"none"}),this.$wrap.css({zIndex:-999998}));this.$wrap.css({position:this.isBody&&l?"fixed":"absolute"});this.index=0;this.show(this.index);a(d).on("resize.backstretch",a.proxy(this.resize,this)).on("orientationchange.backstretch",a.proxy(function(){this.isBody&&0===d.pageYOffset&&(d.scrollTo(0,1),this.resize())},this))};q.prototype={resize:function(){try{var a={left:0,top:0},b=this.isBody?this.$root.width():this.$root.innerWidth(),e=b,g=this.isBody?d.innerHeight?d.innerHeight:this.$root.height():this.$root.innerHeight(),j=e/this.$img.data("ratio"),f;j>=g?(f=(j-g)/2,this.options.centeredY&&(a.top="-"+f+"px")):(j=g,e=j*this.$img.data("ratio"),f=(e-b)/2,this.options.centeredX&&(a.left="-"+f+"px"));this.$wrap.css({width:b,height:g}).find("img:not(.deleteable)").css({width:e,height:j}).css(a)}catch(h){}return this},show:function(c){if(!(Math.abs(c)>this.images.length-1)){var b=this,e=b.$wrap.find("img").addClass("deleteable"),d={relatedTarget:b.$container[0]};b.$container.trigger(a.Event("backstretch.before",d),[b,c]);this.index=c;clearInterval(b.interval);b.$img=a("
").css(s).bind("load",function(f){var h=this.width||a(f.target).width();f=this.height||a(f.target).height();a(this).data("ratio",h/f);a(this).fadeIn(b.options.speed||b.options.fade,function(){e.remove();b.paused||b.cycle();a(["after","show"]).each(function(){b.$container.trigger(a.Event("backstretch."+this,d),[b,c])})});b.resize()}).appendTo(b.$wrap);b.$img.attr("src",b.images[c]);return b}},next:function(){return this.show(this.indexe||d.operamini&&"[object OperaMini]"==={}.toString.call(d.operamini)||n&&7458>t||-1e||h&&6>h||"palmGetResource"in d&&e&&534>e||-1=k)})(jQuery,window);
\ No newline at end of file
diff --git a/app/assets/javascripts/search/jquery.offcanvas.js b/app/assets/javascripts/search/jquery.offcanvas.js
deleted file mode 100644
index 4f65c081b9..0000000000
--- a/app/assets/javascripts/search/jquery.offcanvas.js
+++ /dev/null
@@ -1,62 +0,0 @@
-//;(function (window, document, $) {
-// alert($("#sidebarButton").html());
-//}(this, document, jQuery));
-
-
-
-
-//;(function (window, document, $) {
-// // Set the negative margin on the top menu for slide-menu pages
-// var $selector1 = $('#topMenu'),
-// events = 'click.fndtn';
-// if ($selector1.length > 0) $selector1.css("margin-top", $selector1.height() * -1);
-//
-// // Watch for clicks to show the sidebar
-// var $selector2 = $('#sidebarButton');
-// if ($selector2.length > 0) {
-// $('#sidebarButton').on(events, function (e) {
-// console.log("testing one two three");
-// e.preventDefault();
-// $('body').toggleClass('active');
-// });
-// }
-// else {
-// console.log("not supposed to be there");
-// }
-//
-// // Watch for clicks to show the menu for slide-menu pages
-// var $selector3 = $('#menuButton');
-// if ($selector3.length > 0) {
-// $('#menuButton').on(events, function (e) {
-// e.preventDefault();
-// $('body').toggleClass('active-menu');
-// });
-// }
-//
-// // // Adjust sidebars and sizes when resized
-// // $(window).resize(function() {
-// // // if (!navigator.userAgent.match(/Android/i)) $('body').removeClass('active');
-// // var $selector4 = $('#topMenu');
-// // if ($selector4.length > 0) $selector4.css("margin-top", $selector4.height() * -1);
-// // });
-//
-// // Switch panels for the paneled nav on mobile
-// var $selector5 = $('#switchPanels');
-// if ($selector5.length > 0) {
-// $('#switchPanels dd').on(events, function (e) {
-// e.preventDefault();
-// var switchToPanel = $(this).children('a').attr('href'),
-// switchToIndex = $(switchToPanel).index();
-// $(this).toggleClass('active').siblings().removeClass('active');
-// $(switchToPanel).parent().css("left", (switchToIndex * (-100) + '%'));
-// });
-// }
-//
-// $('#nav li a').on(events, function (e) {
-// alert("test");
-// e.preventDefault();
-// var href = $(this).attr('href'),
-// $target = $(href);
-// $('html, body').animate({scrollTop : $target.offset().top}, 300);
-// });
-//}(this, document, jQuery));
diff --git a/app/assets/javascripts/search/modernizr.foundation.js b/app/assets/javascripts/search/modernizr.foundation.js
deleted file mode 100644
index 4eb3d0655f..0000000000
--- a/app/assets/javascripts/search/modernizr.foundation.js
+++ /dev/null
@@ -1,4 +0,0 @@
-/* Modernizr 2.6.2 (Custom Build) | MIT & BSD
- * Build: http://modernizr.com/download/#-inlinesvg-svg-svgclippaths-touch-shiv-mq-cssclasses-teststyles-prefixes-ie8compat-load
- */
-;window.Modernizr=function(a,b,c){function y(a){j.cssText=a}function z(a,b){return y(m.join(a+";")+(b||""))}function A(a,b){return typeof a===b}function B(a,b){return!!~(""+a).indexOf(b)}function C(a,b,d){for(var e in a){var f=b[a[e]];if(f!==c)return d===!1?a[e]:A(f,"function")?f.bind(d||b):f}return!1}var d="2.6.2",e={},f=!0,g=b.documentElement,h="modernizr",i=b.createElement(h),j=i.style,k,l={}.toString,m=" -webkit- -moz- -o- -ms- ".split(" "),n={svg:"http://www.w3.org/2000/svg"},o={},p={},q={},r=[],s=r.slice,t,u=function(a,c,d,e){var f,i,j,k,l=b.createElement("div"),m=b.body,n=m||b.createElement("body");if(parseInt(d,10))while(d--)j=b.createElement("div"),j.id=e?e[d]:h+(d+1),l.appendChild(j);return f=["",'"].join(""),l.id=h,(m?l:n).innerHTML+=f,n.appendChild(l),m||(n.style.background="",n.style.overflow="hidden",k=g.style.overflow,g.style.overflow="hidden",g.appendChild(n)),i=c(l,a),m?l.parentNode.removeChild(l):(n.parentNode.removeChild(n),g.style.overflow=k),!!i},v=function(b){var c=a.matchMedia||a.msMatchMedia;if(c)return c(b).matches;var d;return u("@media "+b+" { #"+h+" { position: absolute; } }",function(b){d=(a.getComputedStyle?getComputedStyle(b,null):b.currentStyle)["position"]=="absolute"}),d},w={}.hasOwnProperty,x;!A(w,"undefined")&&!A(w.call,"undefined")?x=function(a,b){return w.call(a,b)}:x=function(a,b){return b in a&&A(a.constructor.prototype[b],"undefined")},Function.prototype.bind||(Function.prototype.bind=function(b){var c=this;if(typeof c!="function")throw new TypeError;var d=s.call(arguments,1),e=function(){if(this instanceof e){var a=function(){};a.prototype=c.prototype;var f=new a,g=c.apply(f,d.concat(s.call(arguments)));return Object(g)===g?g:f}return c.apply(b,d.concat(s.call(arguments)))};return e}),o.touch=function(){var c;return"ontouchstart"in a||a.DocumentTouch&&b instanceof DocumentTouch?c=!0:u(["@media (",m.join("touch-enabled),("),h,")","{#modernizr{top:9px;position:absolute}}"].join(""),function(a){c=a.offsetTop===9}),c},o.svg=function(){return!!b.createElementNS&&!!b.createElementNS(n.svg,"svg").createSVGRect},o.inlinesvg=function(){var a=b.createElement("div");return a.innerHTML="",(a.firstChild&&a.firstChild.namespaceURI)==n.svg},o.svgclippaths=function(){return!!b.createElementNS&&/SVGClipPath/.test(l.call(b.createElementNS(n.svg,"clipPath")))};for(var D in o)x(o,D)&&(t=D.toLowerCase(),e[t]=o[D](),r.push((e[t]?"":"no-")+t));return e.addTest=function(a,b){if(typeof a=="object")for(var d in a)x(a,d)&&e.addTest(d,a[d]);else{a=a.toLowerCase();if(e[a]!==c)return e;b=typeof b=="function"?b():b,typeof f!="undefined"&&f&&(g.className+=" "+(b?"":"no-")+a),e[a]=b}return e},y(""),i=k=null,function(a,b){function k(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function l(){var a=r.elements;return typeof a=="string"?a.split(" "):a}function m(a){var b=i[a[g]];return b||(b={},h++,a[g]=h,i[h]=b),b}function n(a,c,f){c||(c=b);if(j)return c.createElement(a);f||(f=m(c));var g;return f.cache[a]?g=f.cache[a].cloneNode():e.test(a)?g=(f.cache[a]=f.createElem(a)).cloneNode():g=f.createElem(a),g.canHaveChildren&&!d.test(a)?f.frag.appendChild(g):g}function o(a,c){a||(a=b);if(j)return a.createDocumentFragment();c=c||m(a);var d=c.frag.cloneNode(),e=0,f=l(),g=f.length;for(;e",f="hidden"in a,j=a.childNodes.length==1||function(){b.createElement("a");var a=b.createDocumentFragment();return typeof a.cloneNode=="undefined"||typeof a.createDocumentFragment=="undefined"||typeof a.createElement=="undefined"}()}catch(c){f=!0,j=!0}})();var r={elements:c.elements||"abbr article aside audio bdi canvas data datalist details figcaption figure footer header hgroup mark meter nav output progress section summary time video",shivCSS:c.shivCSS!==!1,supportsUnknownElements:j,shivMethods:c.shivMethods!==!1,type:"default",shivDocument:q,createElement:n,createDocumentFragment:o};a.html5=r,q(b)}(this,b),e._version=d,e._prefixes=m,e.mq=v,e.testStyles=u,g.className=g.className.replace(/(^|\s)no-js(\s|$)/,"$1$2")+(f?" js "+r.join(" "):""),e}(this,this.document),function(a,b,c){function d(a){return"[object Function]"==o.call(a)}function e(a){return"string"==typeof a}function f(){}function g(a){return!a||"loaded"==a||"complete"==a||"uninitialized"==a}function h(){var a=p.shift();q=1,a?a.t?m(function(){("c"==a.t?B.injectCss:B.injectJs)(a.s,0,a.a,a.x,a.e,1)},0):(a(),h()):q=0}function i(a,c,d,e,f,i,j){function k(b){if(!o&&g(l.readyState)&&(u.r=o=1,!q&&h(),l.onload=l.onreadystatechange=null,b)){"img"!=a&&m(function(){t.removeChild(l)},50);for(var d in y[c])y[c].hasOwnProperty(d)&&y[c][d].onload()}}var j=j||B.errorTimeout,l=b.createElement(a),o=0,r=0,u={t:d,s:c,e:f,a:i,x:j};1===y[c]&&(r=1,y[c]=[]),"object"==a?l.data=c:(l.src=c,l.type=a),l.width=l.height="0",l.onerror=l.onload=l.onreadystatechange=function(){k.call(this,r)},p.splice(e,0,u),"img"!=a&&(r||2===y[c]?(t.insertBefore(l,s?null:n),m(k,j)):y[c].push(l))}function j(a,b,c,d,f){return q=0,b=b||"j",e(a)?i("c"==b?v:u,a,b,this.i++,c,d,f):(p.splice(this.i++,0,a),1==p.length&&h()),this}function k(){var a=B;return a.loader={load:j,i:0},a}var l=b.documentElement,m=a.setTimeout,n=b.getElementsByTagName("script")[0],o={}.toString,p=[],q=0,r="MozAppearance"in l.style,s=r&&!!b.createRange().compareNode,t=s?l:n.parentNode,l=a.opera&&"[object Opera]"==o.call(a.opera),l=!!b.attachEvent&&!l,u=r?"object":l?"script":"img",v=l?"script":u,w=Array.isArray||function(a){return"[object Array]"==o.call(a)},x=[],y={},z={timeout:function(a,b){return b.length&&(a.timeout=b[0]),a}},A,B;B=function(a){function b(a){var a=a.split("!"),b=x.length,c=a.pop(),d=a.length,c={url:c,origUrl:c,prefixes:a},e,f,g;for(f=0;f
- $('#cart_adjustments').hide()
-
- $('th.cart-adjustment-header').html('Distribution...')
- $('th.cart-adjustment-header a').click ->
- $('#cart_adjustments').toggle()
- $('th.cart-adjustment-header a').html('Distribution')
- false
diff --git a/app/assets/javascripts/store/controllers/cart.js.coffee b/app/assets/javascripts/store/controllers/cart.js.coffee
deleted file mode 100644
index cc7538249e..0000000000
--- a/app/assets/javascripts/store/controllers/cart.js.coffee
+++ /dev/null
@@ -1,20 +0,0 @@
-'use strict'
-
-angular.module('store', ['ngResource']).
- controller('CartCtrl', ['$scope', '$window', 'CartFactory', ($scope, $window, CartFactory) ->
-
- $scope.state = 'Empty'
-
- $scope.loadCart = (cart_id) ->
- if cart_id?
- CartFactory.load cart_id, (cart) ->
- $scope.cart = cart
- if $scope.cart?.orders?.length > 0
- $scope.state = "There's something there...."
-
- $scope.addVariant = (variant, quantity) ->
-
- ])
- .config(['$httpProvider', ($httpProvider) ->
- $httpProvider.defaults.headers.common['X-CSRF-Token'] = $('meta[name=csrf-token]').attr('content')
- ])
diff --git a/app/assets/javascripts/store/factories/cart.js.coffee b/app/assets/javascripts/store/factories/cart.js.coffee
deleted file mode 100644
index e327fc336d..0000000000
--- a/app/assets/javascripts/store/factories/cart.js.coffee
+++ /dev/null
@@ -1,11 +0,0 @@
-'use strict'
-
-angular.module('store').
- factory('CartFactory', ['$resource', '$window', '$http', ($resource, $window, $http) ->
- Cart = $resource '/open_food_network/cart/:cart_id.json', {},
- { 'show': { method: 'GET'} }
-
- load: (id, callback) ->
- Cart.show {cart_id: id}, (cart) ->
- callback(cart)
- ])
diff --git a/app/assets/javascripts/store/products.js b/app/assets/javascripts/store/products.js
deleted file mode 100644
index 127e8ce28f..0000000000
--- a/app/assets/javascripts/store/products.js
+++ /dev/null
@@ -1,47 +0,0 @@
-/**
- * Update the price on the product details page in real time when the variant or the quantity are changed.
- **/
-
-$(document).ready(function() {
- // Product page with variant choice
- $("#product-variants input[type='radio']").change(products_update_price_with_variant);
- $("#quantity").change(products_update_price_with_variant);
- $("#quantity").change();
-
- // Product page with master price only
- $(".add-to-cart input.title:not(#quantity):not(.max_quantity)").change(products_update_price_without_variant).change();
-
- // Product page other
- $("#distributor_id").change(function() {
- var distributor_html = distributors[$(this).val()];
- if(!distributor_html) {
- distributor_html = 'When you select a distributor for your order, their address and pickup times will be displayed here.';
- }
- $("#product-distributor-details .distributor-details").html(distributor_html);
- });
-});
-
-
-function products_update_price_with_variant() {
- var variant_price = $("#product-variants input[type='radio']:checked").parent().find("span.price").html().trim();
- variant_price = variant_price.substr(2, variant_price.length-3);
-
- var quantity = $("#quantity").val();
-
- $("#product-price span.price").html("$"+(parseFloat(variant_price) * parseInt(quantity)).toFixed(2));
-}
-
-
-function products_update_price_without_variant() {
- var master_price = $("#product-price span.price").data('master-price');
- if(master_price == null) {
- // Store off the master price
- master_price = $("#product-price span.price").html();
- master_price = master_price.substring(1);
- $("#product-price span.price").data('master-price', master_price);
- }
-
- var quantity = $(this).val();
-
- $("#product-price span.price").html("$"+(parseFloat(master_price)*parseInt(quantity)).toFixed(2));
-}
diff --git a/app/assets/javascripts/store/shop_front.js.coffee b/app/assets/javascripts/store/shop_front.js.coffee
deleted file mode 100644
index 1a7044732f..0000000000
--- a/app/assets/javascripts/store/shop_front.js.coffee
+++ /dev/null
@@ -1,4 +0,0 @@
-$(document).ready ->
- $("#order_order_cycle_id").change -> $("#order_cycle_select").submit()
- $("#reset_order_cycle").click -> return false unless confirm "Changing your collection date will clear your cart."
- $(".shop-distributor.empties-cart").click -> return false unless confirm "Changing your location will clear your cart."
diff --git a/app/assets/javascripts/templates/hub_modal.html.haml b/app/assets/javascripts/templates/enterprise_modal.html.haml
similarity index 100%
rename from app/assets/javascripts/templates/hub_modal.html.haml
rename to app/assets/javascripts/templates/enterprise_modal.html.haml
diff --git a/app/assets/javascripts/templates/map_modal_producer.html.haml b/app/assets/javascripts/templates/map_modal_producer.html.haml
deleted file mode 100644
index dff26519d3..0000000000
--- a/app/assets/javascripts/templates/map_modal_producer.html.haml
+++ /dev/null
@@ -1,4 +0,0 @@
-%ng-include{src: "'partials/enterprise_header.html'"}
-%ng-include{src: "'partials/enterprise_details.html'"}
-%ng-include{src: "'partials/hub_actions.html'"}
-%ng-include{src: "'partials/close.html'"}
diff --git a/app/assets/javascripts/templates/partials/enterprise_header.html.haml b/app/assets/javascripts/templates/partials/enterprise_header.html.haml
index 8612ba968e..27a57ed90b 100644
--- a/app/assets/javascripts/templates/partials/enterprise_header.html.haml
+++ b/app/assets/javascripts/templates/partials/enterprise_header.html.haml
@@ -1,13 +1,13 @@
-.highlight{"ng-class" => "{'has_shopfront' : enterprise.has_shopfront}"}
+.highlight{"ng-class" => "{'is_distributor' : enterprise.is_distributor}"}
.highlight-top.row
.small-12.medium-7.large-8.columns
- %h3{"ng-if" => "enterprise.has_shopfront"}
+ %h3{"ng-if" => "enterprise.is_distributor"}
%a{"bo-href" => "enterprise.path", "ofn-empties-cart" => "enterprise", bindonce: true}
%i{"ng-class" => "enterprise.icon_font"}
%span {{ enterprise.name }}
- %h3{"ng-if" => "!enterprise.has_shopfront", "ng-class" => "{'is_producer' : enterprise.is_primary_producer}"}
+ %h3{"ng-if" => "!enterprise.is_distributor", "ng-class" => "{'is_producer' : enterprise.is_primary_producer}"}
%i{"ng-class" => "enterprise.icon_font"}
%span {{ enterprise.name }}
.small-12.medium-5.large-4.columns.text-right.small-only-text-left
%p {{ [enterprise.address.city, enterprise.address.state_name] | printArray}}
- %img.hero-img{"ng-src" => "{{enterprise.promo_image}}"}
\ No newline at end of file
+ %img.hero-img{"ng-src" => "{{enterprise.promo_image}}"}
diff --git a/app/assets/javascripts/templates/partials/hub_actions.html.haml b/app/assets/javascripts/templates/partials/hub_actions.html.haml
index fa9ff4e183..61e74afb42 100644
--- a/app/assets/javascripts/templates/partials/hub_actions.html.haml
+++ b/app/assets/javascripts/templates/partials/hub_actions.html.haml
@@ -1,4 +1,4 @@
-.row.pad-top{bindonce: true, "ng-if" => "enterprise.hubs.length > 0 && enterprise.has_shopfront"}
+.row.pad-top{bindonce: true, "ng-if" => "enterprise.hubs.length > 0 && enterprise.is_distributor"}
.cta-container.small-12.columns
%label
Shop for
diff --git a/app/assets/javascripts/templates/partials/hub_details.html.haml b/app/assets/javascripts/templates/partials/hub_details.html.haml
index 27933cefcb..815200821a 100644
--- a/app/assets/javascripts/templates/partials/hub_details.html.haml
+++ b/app/assets/javascripts/templates/partials/hub_details.html.haml
@@ -1,4 +1,4 @@
-.row.pad-top{bindonce: true, ng: { if: 'enterprise.has_shopfront' } }
+.row.pad-top{bindonce: true, ng: { if: 'enterprise.is_distributor' } }
.cta-container.small-12.columns
.row
.small-4.columns
diff --git a/app/assets/javascripts/templates/producer_modal.html.haml b/app/assets/javascripts/templates/producer_modal.html.haml
deleted file mode 100644
index db6f927e21..0000000000
--- a/app/assets/javascripts/templates/producer_modal.html.haml
+++ /dev/null
@@ -1,3 +0,0 @@
-%ng-include{src: "'partials/enterprise_header.html'"}
-%ng-include{src: "'partials/enterprise_details.html'"}
-%ng-include{src: "'partials/close.html'"}
diff --git a/app/assets/javascripts/templates/registration/about.html.haml b/app/assets/javascripts/templates/registration/about.html.haml
index d014c96d90..5b7d2e6df6 100644
--- a/app/assets/javascripts/templates/registration/about.html.haml
+++ b/app/assets/javascripts/templates/registration/about.html.haml
@@ -1,44 +1,47 @@
.container#registration-about
- .header
- %h2 Nice one!
- %h5
- Now let's flesh out the details about
- %span.brick{"ng-show" => "enterprise.is_distributor"}
- {{ enterprise.name }}
- %span.turquoise{"ng-show" => "!enterprise.is_distributor" }
- {{ enterprise.name }}
-
%ng-include{ src: "'registration/steps.html'" }
+ .row
+ .small-12.columns
+ %header
+ %h2 Nice one!
+ %h5
+ Now let's flesh out the details about
+ %span{ ng: { class: "{brick: !enterprise.is_primary_producer, turquoise: enterprise.is_primary_producer}" } }
+ {{ enterprise.name }}
+
%form{ name: 'about', novalidate: true, ng: { controller: "RegistrationFormCtrl", submit: "update('images',about)" } }
.row
.small-12.columns
- .alert-box.alert{"data-alert" => ""}
- {{ enterprise.name }} won't be visible on the Open Food Network until you enter a long and short description.
- %a.close{:href => "#"} ×
-
- .alert-box.info{"data-alert" => ""}
- {{ enterprise.name }} has been created on the Open Food Network. If you leave at any point from here onwards, your enterprise will be saved, and you can always login to the admin section to update or continue filling out your enterprise details.
- %a.close{:href => "#"} ×
+ .alert-box.info{ "ofn-inline-alert" => true, ng: { show: "visible" } }
+ %h6 Success! {{ enterprise.name }} added to the Open Food Network
+ %span If you exit the wizard at any stage, login and go to admin to edit or update your enterprise details.
+ %a.close{ ng: { click: "close()" } } ×
.small-12.large-8.columns
.row
.small-12.columns
- %label{ for: 'enterprise_description' } Short Description:
- %input.chunky.small-12.columns{ id: 'enterprise_description', placeholder: "A short sentence describing your enterprise", ng: { model: 'enterprise.description' } }
+ .field
+ %label{ for: 'enterprise_description' } Short Description:
+ %input.chunky{ id: 'enterprise_description', placeholder: "A short sentence describing your enterprise", ng: { model: 'enterprise.description' } }
.row
.small-12.columns
- %label{ for: 'enterprise_long_desc' } Long Description:
- %textarea.chunky.small-12.columns{ id: 'enterprise_long_desc', rows: 6, placeholder: "This is your opportunity to tell the story of your enterprise - what makes you different and wonderful? We'd suggest keeping your description to under 600 characters or 150 words.", ng: { model: 'enterprise.long_description' } }
- %small {{ enterprise.long_description.length }} characters / up to 600 recommended
+ .field
+ %label{ for: 'enterprise_long_desc' } Long Description:
+ %textarea.chunky{ id: 'enterprise_long_desc', rows: 6, placeholder: "This is your opportunity to tell the story of your enterprise - what makes you different and wonderful? We'd suggest keeping your description to under 600 characters or 150 words.", ng: { model: 'enterprise.long_description' } }
+ %small {{ enterprise.long_description.length }} characters / up to 600 recommended
.small-12.large-4.columns
.row
.small-12.columns
- %label{ for: 'enterprise_abn' } ABN:
- %input.chunky.small-12.columns{ id: 'enterprise_abn', placeholder: "eg. 99 123 456 789", ng: { model: 'enterprise.abn' } }
+ .field
+ %label{ for: 'enterprise_abn' } ABN:
+ %input.chunky{ id: 'enterprise_abn', placeholder: "eg. 99 123 456 789", ng: { model: 'enterprise.abn' } }
.row
.small-12.columns
- %label{ for: 'enterprise_acn' } ACN:
- %input.chunky.small-12.columns{ id: 'enterprise_acn', placeholder: "eg. 123 456 789", ng: { model: 'enterprise.acn' } }
+ .field
+ %label{ for: 'enterprise_acn' } ACN:
+ %input.chunky{ id: 'enterprise_acn', placeholder: "eg. 123 456 789", ng: { model: 'enterprise.acn' } }
+
.row.buttons.pad-top
.small-12.columns
- %input.button.primary{ type: "submit", value: "Continue" }
+ %input.button.primary.right{ type: "submit", value: "Continue" }
+
diff --git a/app/assets/javascripts/templates/registration/address.html.haml b/app/assets/javascripts/templates/registration/address.html.haml
deleted file mode 100644
index 6fe39e9285..0000000000
--- a/app/assets/javascripts/templates/registration/address.html.haml
+++ /dev/null
@@ -1,60 +0,0 @@
-.container#registration-address
- .header
- %h2
- Greetings
- %span{ ng: { class: "{brick: enterprise.is_distributor, turquoise: !enterprise.is_distributor}" } }
- {{ enterprise.name }}
-
- %h5 Now we need to know where you are
- %ng-include{ src: "'registration/steps.html'" }
- %form{ name: 'address', novalidate: true, ng: { controller: "RegistrationFormCtrl", submit: "selectIfValid('contact',address)" } }
- .row.content
- .small-12.medium-12.large-7.columns
- .row
- .small-12.columns.field
- %label{ for: 'enterprise_address' } Address:
- %input.chunky.small-12.columns{ id: 'enterprise_address', name: 'address1', required: true, placeholder: "eg. 123 Cranberry Drive", required: true, ng: { model: 'enterprise.address.address1' } }
- %span.error.small-12.columns{ ng: { show: "address.address1.$error.required && submitted" } }
- You need to enter an address.
- .row
- .small-12.large-8.columns.field
- %label{ for: 'enterprise_city' } Suburb:
- %input.chunky.small-12.columns{ id: 'enterprise_city', name: 'city', required: true, placeholder: "eg. Northcote", ng: { model: 'enterprise.address.city' } }
- %span.error.small-12.columns{ ng: { show: "address.city.$error.required && submitted" } }
- You need to enter a suburb.
- .small-12.large-4.columns.field
- %label{ for: 'enterprise_zipcode' } Postcode:
- %input.chunky.small-12.columns{ id: 'enterprise_zipcode', name: 'zipcode', required: true, placeholder: "eg. 3070", ng: { model: 'enterprise.address.zipcode' } }
- %span.error.small-12.columns{ ng: { show: "address.zipcode.$error.required && submitted" } }
- You need to enter a postcode.
- .row
- .small-12.large-8.columns.field
- %label{ for: 'enterprise_country' } Country:
- %select.chunky.small-12.columns{ id: 'enterprise_country', name: 'country', required: true, ng: { model: 'enterprise.country', options: 'c as c.name for c in countries' } }
- %span.error.small-12.columns{ ng: { show: "address.country.$error.required && submitted" } }
- You need to enter a country.
- .small-12.large-4.columns.field
- %label{ for: 'enterprise_state' } State:
- %select.chunky.small-12.columns{ id: 'enterprise_state', name: 'state', ng: { model: 'enterprise.address.state_id', options: 's.id as s.abbr for s in enterprise.country.states', show: 'countryHasStates()', required: 'countryHasStates()' } }
- %span.error.small-12.columns{ ng: { show: "address.state.$error.required && submitted" } }
- You need to enter a state.
- .small-12.medium-12.large-5.hide-for-small-only
- // This is the location area
- / %h6
- / Location display
- / %i.ofn-i_013-help.has-tip{ 'data-tooltip' => true, title: "Choose how you want to display your enterprise's address on the Open Food Network. By default, full location is shown everywhere including street name and number."}
- / .row
- / .small-12.columns
- / %label.indent-checkbox
- / %input{ type: 'checkbox', id: 'enterpise_suburb_only', ng: { model: 'enterprise.suburb_only' } }
- / Hide my street name and street number from the public (ie. only show the suburb)
- / .small-12.columns
- / %label.indent-checkbox
- / %input{ type: 'checkbox', id: 'enterprise_on_map', ng: { model: 'enterprise.on_map' } }
- / Blur my location on the map (show an approximate, not exact pin)
-
- .row.buttons
- .small-12.columns
- %input.button.secondary{ type: "button", value: "Back", ng: { click: "select('details')" } }
-
- %input.button.primary{ type: "submit", value: "Continue" }
diff --git a/app/assets/javascripts/templates/registration/contact.html.haml b/app/assets/javascripts/templates/registration/contact.html.haml
index c7262248d0..916a614c0b 100644
--- a/app/assets/javascripts/templates/registration/contact.html.haml
+++ b/app/assets/javascripts/templates/registration/contact.html.haml
@@ -1,12 +1,13 @@
.container#registration-contact
- .header
- %h2 Last step to create your enterprise!
- %h5
- Who is responsible for managing
- %span{ ng: { class: "{brick: enterprise.is_distributor, turquoise: !enterprise.is_distributor}" } }
- {{ enterprise.name }}?
%ng-include{ src: "'registration/steps.html'" }
- %form{ name: 'contact', novalidate: true, ng: { controller: "RegistrationFormCtrl", submit: "create(contact)" } }
+ .row
+ .small-12.columns
+ %header
+ %h2 Greetings!
+ %h5
+ Who is responsible for managing {{ enterprise.name }}?
+
+ %form{ name: 'contact', novalidate: true, ng: { controller: "RegistrationFormCtrl", submit: "selectIfValid('type',contact)" } }
.row.content
.small-12.medium-12.large-7.columns
.row
@@ -39,8 +40,8 @@
/ .small-12.columns
/ %label.indent-checkbox
/ %input{ type: 'checkbox', id: 'contact_phone_profile', ng: { model: 'enterprise.phone_in_profile' } } Display phone in profile
+
.row.buttons
.small-12.columns
- %input.button.secondary{ type: "button", value: "Back", ng: { click: "select('address')" } }
-
- %input.button.primary{ type: "submit", value: "Continue" }
+ %input.button.secondary{ type: "button", value: "Back", ng: { click: "select('details')" } }
+ %input.button.primary.right{ type: "submit", value: "Continue" }
diff --git a/app/assets/javascripts/templates/registration/details.html.haml b/app/assets/javascripts/templates/registration/details.html.haml
index bb358a1864..f1c0503f78 100644
--- a/app/assets/javascripts/templates/registration/details.html.haml
+++ b/app/assets/javascripts/templates/registration/details.html.haml
@@ -1,42 +1,77 @@
.container#registration-details{bindonce: true}
- .header
- %h2 Let's Get Started
- %h5{ bo: { if: "enterprise.type != 'single'" } } Woot! First we need to know what sort of enterprise you are:
- %h5{ bo: { if: "enterprise.type == 'single'" } } Woot! First we need to know the name of your farm:
%ng-include{ src: "'registration/steps.html'" }
- %form{ name: 'details', novalidate: true, ng: { controller: "RegistrationFormCtrl", submit: "selectIfValid('address',details)" } }
- .row
- .small-12.columns.field
- %label{ for: 'enterprise_name', bo: { if: "enterprise.type != 'single'" } } Enterprise Name:
- %label{ for: 'enterprise_name', bo: { if: "enterprise.type == 'single'" } } Farm Name:
- %input.chunky.small-12.columns{ id: 'enterprise_name', name: 'name', placeholder: "eg. Charlie's Awesome Farm", required: true, ng: { model: 'enterprise.name' } }
- %span.error.small-12.columns{ ng: { show: "details.name.$error.required && submitted" } }
- You need to enter a name for your enterprise!
+ .row
+ .small-12.columns
+ %header
+ %h2 Let's Get Started
+ %h5{ bo: { if: "enterprise.type != 'own'" } } Woot! First we need to know a little bit about your enterprise:
+ %h5{ bo: { if: "enterprise.type == 'own'" } } Woot! First we need to know a little bit about your farm:
- .row#enterprise-types{ 'data-equalizer' => true, bo: { if: "enterprise.type != 'single'" } }
- .small-12.columns.field
+ %form{ name: 'details', novalidate: true, ng: { controller: "RegistrationFormCtrl", submit: "selectIfValid('contact',details)" } }
+
+ .row
+ .small-12.medium-9.large-12.columns.end
+ .field
+ %label{ for: 'enterprise_name', bo: { if: "enterprise.type != 'own'" } } Enterprise Name:
+ %label{ for: 'enterprise_name', bo: { if: "enterprise.type == 'own'" } } Farm Name:
+ %input.chunky{ id: 'enterprise_name', name: 'name', placeholder: "e.g. Charlie's Awesome Farm", required: true, ng: { model: 'enterprise.name' } }
+ %span.error{ ng: { show: "details.name.$error.required && submitted" } }
+ Please choose a unique name for your enterprise
+
+ .row
+ .small-12.medium-9.large-6.columns
+ .field
+ %label{ for: 'enterprise_address' } Address line 1:
+ %input.chunky{ id: 'enterprise_address', name: 'address1', required: true, placeholder: "e.g. 123 Cranberry Drive", required: true, ng: { model: 'enterprise.address.address1' } }
+ %span.error{ ng: { show: "details.address1.$error.required && submitted" } }
+ Please enter an address
+ .field
+ %label{ for: 'enterprise_address2' } Address line 2:
+ %input.chunky{ id: 'enterprise_address2', name: 'address2', required: false, placeholder: "", required: false, ng: { model: 'enterprise.address.address2' } }
+
+ .small-12.medium-9.large-6.columns.end
.row
- .small-12.columns
- %label Choose one:
+ .small-12.medium-8.large-8.columns
+ .field
+ %label{ for: 'enterprise_city' } Suburb:
+ %input.chunky{ id: 'enterprise_city', name: 'city', required: true, placeholder: "e.g. Northcote", ng: { model: 'enterprise.address.city' } }
+ %span.error{ ng: { show: "details.city.$error.required && submitted" } }
+ Please enter a suburb
+ .small-12.medium-4.large-4.columns
+ .field
+ %label{ for: 'enterprise_zipcode' } Postcode:
+ %input.chunky{ id: 'enterprise_zipcode', name: 'zipcode', required: true, placeholder: "e.g. 3070", ng: { model: 'enterprise.address.zipcode' } }
+ %span.error{ ng: { show: "details.zipcode.$error.required && submitted" } }
+ Postcode required
.row
- .small-12.medium-4.large-4.columns{ 'data-equalizer-watch' => true }
- %a.panel#producer-panel{ href: "#", ng: { click: "enterprise.is_distributor = false; enterprise.is_primary_producer = true", class: "{selected: (!enterprise.is_distributor && enterprise.is_primary_producer)}" } }
- .left
- / %render-svg{ path: "/assets/map-icon-producer.svg" }
- %h4 I'm A Producer
- %p Producers make yummy things to eat &/or drink. You're a producer if you grow it, raise it, brew it, bake it, ferment it, milk it or mould it.
- .small-12.medium-4.large-4.columns{ 'data-equalizer-watch' => true }
- %a.panel#hub-panel{ href: "#", ng: { click: "enterprise.is_distributor = true; enterprise.is_primary_producer = false", class: "{selected: (enterprise.is_distributor && !enterprise.is_primary_producer)}" } }
- .left
- / %render-svg{ path: "/assets/map-icon-hub.svg" }
- %h4 I'm A Hub
- %p Hubs connect the producer to the eater. Hubs can be co-ops, independent retailers, buying groups, wholesalers, CSA box schemes, farm-gate stalls, etc.
- .small-12.medium-4.large-4.columns{ 'data-equalizer-watch' => true }
- %a.panel#both-panel{ href: "#", ng: { click: "enterprise.is_distributor = true; enterprise.is_primary_producer = true", class: "{selected: (enterprise.is_distributor && enterprise.is_primary_producer)}" } }
- .left
- / %render-svg{path: "/assets/map-icon-both.svg"}
- %h4 I'm Both
- %p Hey there, Jack-of-all-trades! Not only do you produce things to eat &/or drink, you also want to sell your yummies through an Open Food Network shopfront.
+ .small-12.medium-4.large-4.columns
+ .field
+ %label{ for: 'enterprise_state' } State:
+ %select.chunky{ id: 'enterprise_state', name: 'state', ng: { model: 'enterprise.address.state_id', options: 's.id as s.abbr for s in enterprise.country.states', show: 'countryHasStates()', required: 'countryHasStates()' } }
+ %span.error{ ng: { show: "details.state.$error.required && submitted" } }
+ State required
+ .small-12.medium-8.large-8.columns
+ .field
+ %label{ for: 'enterprise_country' } Country:
+ %select.chunky{ id: 'enterprise_country', name: 'country', required: true, ng: { model: 'enterprise.country', options: 'c as c.name for c in countries' } }
+ %span.error{ ng: { show: "details.country.$error.required && submitted" } }
+ Please select a country
+ / .small-12.medium-12.large-5.hide-for-small-only
+ / %h6
+ / Location display
+ / %i.ofn-i_013-help.has-tip{ 'data-tooltip' => true, title: "Choose how you want to display your enterprise's address on the Open Food Network. By default, full location is shown everywhere including street name and number."}
+ / .row
+ / .small-12.columns
+ / %label.indent-checkbox
+ / %input{ type: 'checkbox', id: 'enterpise_suburb_only', ng: { model: 'enterprise.suburb_only' } }
+ / Hide my street name and street number from the public (ie. only show the suburb)
+ / .small-12.columns
+ / %label.indent-checkbox
+ / %input{ type: 'checkbox', id: 'enterprise_on_map', ng: { model: 'enterprise.on_map' } }
+ / Blur my location on the map (show an approximate, not exact pin)
+
+
.row.buttons
.small-12.columns
+ %hr
%input.button.primary.right{ type: "submit", value: "Continue" }
diff --git a/app/assets/javascripts/templates/registration/finished.html.haml b/app/assets/javascripts/templates/registration/finished.html.haml
index 75489c607a..f647a2d8bb 100644
--- a/app/assets/javascripts/templates/registration/finished.html.haml
+++ b/app/assets/javascripts/templates/registration/finished.html.haml
@@ -1,18 +1,24 @@
.container#registration-finished
- .header
- %h2 Well done!
- %h5
- You have successfully completed the profile for
- %span.brick{"ng-show" => "enterprise.is_distributor"}
- {{ enterprise.name }}
- %span.turquoise{"ng-show" => "!enterprise.is_distributor" }
- {{ enterprise.name }}
- .content{ style: 'text-align: center'}
- %h3 Why not check it out on the Open Food Network?
- %a.button.primary{ type: "button", href: "/map" } Go to Map Page >
+ .row
+ .small-12.columns.pad-top
+ %header
+ %h2 Finished!
+ .panel.callout
+ %p
+ Thanks for filling out the details for
+ %span{ ng: { class: "{brick: !enterprise.is_primary_producer, turquoise: enterprise.is_primary_producer}" } }
+ {{ enterprise.name }}
+ %p You can change or update your enterprise at any stage by logging into Open Food Network and going to Admin.
+ .row
+ .small-12.columns.text-center
+ %h4
+ Activate
+ %span{ ng: { class: "{brick: !enterprise.is_primary_producer, turquoise: enterprise.is_primary_producer}" } }
+ {{ enterprise.name }}
- %br
- %br
+ %p
+ We've sent a confirmation email to
+ %strong {{ enterprise.email }}.
+ %br Please follow the instructions there to make your enterprise visible on the Open Food Network.
- %h3 Next step - add some products:
- %a.button.primary{ type: "button", href: "/admin/products/new" } Add a Product >
+ %a.button.primary{ type: "button", href: "/" } Open Food Network home >
diff --git a/app/assets/javascripts/templates/registration/images.html.haml b/app/assets/javascripts/templates/registration/images.html.haml
index 889bc4596f..5b2ac39b5a 100644
--- a/app/assets/javascripts/templates/registration/images.html.haml
+++ b/app/assets/javascripts/templates/registration/images.html.haml
@@ -1,20 +1,22 @@
.container#registration-images{ 'nv-file-drop' => true, uploader: "imageUploader", options:"{ alias: imageStep }", ng: { controller: "EnterpriseImageCtrl" } }
- .header
- %h2 Thanks!
- %h5 Let's upload some pretty pictures so your profile looks great! :)
%ng-include{ src: "'registration/steps.html'" }
+ .row
+ .small-12.columns
+ %header
+ %h2 Thanks!
+ %h5 Let's upload some pretty pictures so your profile looks great! :)
+
%form{ name: 'images', novalidate: true, ng: { controller: "RegistrationFormCtrl", submit: "select('social')" } }
.row{ ng: { repeat: 'image_step in imageSteps', show: "imageStep == image_step" } }
%ng-include{ src: "'registration/images/'+ image_step + '.html'" }
.row.buttons.pad-top{ ng: { if: "imageStep == 'logo'" } }
.small-12.columns
- %input.button.primary{ type: "button", value: "Back", ng: { click: "select('about')" } }
+ %input.button.secondary{ type: "button", value: "Back", ng: { click: "select('about')" } }
- %input.button.primary{ type: "button", value: "Continue", ng: { click: "imageSelect('promo')" } }
+ %input.button.primary.right{ type: "button", value: "Continue", ng: { click: "imageSelect('promo')" } }
.row.buttons.pad-top{ ng: { if: "imageStep == 'promo'" } }
.small-12.columns
- %input.button.primary{ type: "button", value: "Back", ng: { click: "imageSelect('logo')" } }
-
- %input.button.primary{ type: "submit", value: "Continue" }
+ %input.button.secondary{ type: "button", value: "Back", ng: { click: "imageSelect('logo')" } }
+ %input.button.primary.right{ type: "submit", value: "Continue" }
diff --git a/app/assets/javascripts/templates/registration/images/logo.html.haml b/app/assets/javascripts/templates/registration/images/logo.html.haml
index 803b103a58..4b19c14cff 100644
--- a/app/assets/javascripts/templates/registration/images/logo.html.haml
+++ b/app/assets/javascripts/templates/registration/images/logo.html.haml
@@ -36,6 +36,10 @@
.row.pad-top
.small-12.columns.center
#image-placeholder.logo
- %img{ ng: { show: "imageSrc()", src: '{{ imageSrc() }}' } }
- .message{ ng: { hide: "imageSrc()" } }
+ %img{ ng: { show: "imageSrc() && !imageUploader.isUploading", src: '{{ imageSrc() }}' } }
+ .message{ ng: { hide: "imageSrc() || imageUploader.isUploading" } }
Your logo will appear here for review once uploaded
+ .loading{ ng: { hide: "!imageUploader.isUploading" } }
+ %img.spinner{ src: "/assets/loading.gif" }
+ %br/
+ Uploading...
diff --git a/app/assets/javascripts/templates/registration/images/promo.html.haml b/app/assets/javascripts/templates/registration/images/promo.html.haml
index f134834d5c..d98721dc6d 100644
--- a/app/assets/javascripts/templates/registration/images/promo.html.haml
+++ b/app/assets/javascripts/templates/registration/images/promo.html.haml
@@ -34,6 +34,10 @@
.row.pad-top
.small-12.columns.center
#image-placeholder.promo
- %img{ ng: { show: "imageSrc()", src: '{{ imageSrc() }}' } }
- .message{ ng: { hide: "imageSrc()" } }
+ %img{ ng: { show: "imageSrc() && !imageUploader.isUploading", src: '{{ imageSrc() }}' } }
+ .message{ ng: { hide: "imageSrc() || imageUploader.isUploading" } }
Your logo will appear here for review once uploaded
+ .loading{ ng: { hide: "!imageUploader.isUploading" } }
+ %img.spinner{ src: "/assets/loading.gif" }
+ %br/
+ Uploading...
diff --git a/app/assets/javascripts/templates/registration/introduction.html.haml b/app/assets/javascripts/templates/registration/introduction.html.haml
index ccefdefbe0..60a8547b4a 100644
--- a/app/assets/javascripts/templates/registration/introduction.html.haml
+++ b/app/assets/javascripts/templates/registration/introduction.html.haml
@@ -1,39 +1,45 @@
-%div
- .header
- %h2 Hi there!
- %h4 This wizard will step you through creating a profile
- .row
- .small-12.medium-3.large-2.columns.text-right.hide-for-small-only
- %img{:src => "/assets/potatoes.png"}
- .small-12.medium-9.large-10.columns
- %p
- Your profile gives you an online presence on the
- %strong Open Food Network,
- allowing you to easily connect with potential customers or partners. You can always choose to update your info later, as well as choose to upgrade your Profile to and Online Store, where you can sell products, track orders and receive payments. Creating a profile takes about 5-10 minutes.
- .row{ 'data-equalizer' => true }
- .small-12.medium-6.large-6.columns.pad-top{ 'data-equalizer-watch' => true }
- %h5 You'll need the following:
- %ul.check-list
- %li
- Your enterprise address and contact details
- %li
- Your logo image
- %li
- A pretty picture for your profile header
- %li
- Some 'About Us' text
-
- .small-12.medium-6.large-6.columns{ 'data-equalizer-watch' => true}
- .highlight-box
- %h5 Your profile entitles you to:
- %ul.small-block-grid-1
- %li
- %i.ofn-i_020-search
- A searchable listing
- %li
- %i.ofn-i_040-hub
- A pin on the OFN map
- .row
- .small-12.columns
+.row
+ .small-12.columns
+ %header
+ %h2 Hi there!
+ %h4
+ %small
+ %i.ofn-i_040-hub
+ Create your enterprise profile
+ .hide-for-large-up
%hr
- %input.button.primary{ type: "button", value: "Let's get started!", ng: { click: "select('details')" } }
+ %input.button.small.primary{ type: "button", value: "Let's get started!", ng: { click: "select('details')" } }
+ %hr
+
+.row{ 'data-equalizer' => true }
+ .small-12.medium-12.large-6.columns.pad-top{ 'data-equalizer-watch' => true }
+ %h5 You'll need:
+ %ul.check-list
+ %li
+ 5-10 minutes
+ %li
+ Enterprise address
+ %li
+ Primary contact details
+ %li
+ Your logo image
+ %li
+ Landscape image for your profile
+ %li
+ 'About Us' text
+
+ .small-9.medium-8.large-5.columns.pad-top.end{ 'data-equalizer-watch' => true}
+ %h5
+ What do I get?
+ %p
+ Your profile helps people
+ %strong find
+ and
+ %strong contact
+ you on the Open Food Network.
+ %p Use this space to tell the story of your enterprise, to help drive connections to your social and online presence.
+
+.row.show-for-large-up
+ .small-12.columns
+ %hr
+ %input.button.primary.right{ type: "button", value: "Let's get started!", ng: { click: "select('details')" } }
diff --git a/app/assets/javascripts/templates/registration/limit_reached.html.haml b/app/assets/javascripts/templates/registration/limit_reached.html.haml
index e2131c1727..778d980289 100644
--- a/app/assets/javascripts/templates/registration/limit_reached.html.haml
+++ b/app/assets/javascripts/templates/registration/limit_reached.html.haml
@@ -1,15 +1,16 @@
-%div
- .header.center
- %h2 Oh no!
- %h4 You have reached the limit!
- .row
- .small-12.medium-3.large-2.columns.text-right.hide-for-small-only
- %img{:src => "/assets/potatoes.png"}
- .small-12.medium-9.large-10.columns
- %p
- You have reached the limit for the number of enterprises you are allowed to own on the
- %strong Open Food Network.
- .row
- .small-12.columns
- %hr
- %input.button.primary{ type: "button", value: "Return to the homepage", ng: { click: "close()" } }
+.row
+ .small-12.columns
+ %header
+ %h2 Oh no!
+ %h4 You have reached the limit!
+.row
+ .small-12.medium-3.large-2.columns.text-right.hide-for-small-only
+ %img{:src => "/assets/potatoes.png"}
+ .small-12.medium-9.large-10.columns
+ %p
+ You have reached the limit for the number of enterprises you are allowed to own on the
+ %strong Open Food Network.
+.row
+ .small-12.columns
+ %hr
+ %input.button.primary{ type: "button", value: "Return to the homepage", ng: { click: "close()" } }
diff --git a/app/assets/javascripts/templates/registration/social.html.haml b/app/assets/javascripts/templates/registration/social.html.haml
index 1b3490ffa0..4f448734f1 100644
--- a/app/assets/javascripts/templates/registration/social.html.haml
+++ b/app/assets/javascripts/templates/registration/social.html.haml
@@ -1,35 +1,49 @@
.container#registration-social
- .header
- %h2 Last step!
- %h5 How can people find {{ enterprise.name }} online?
%ng-include{ src: "'registration/steps.html'" }
+
+ .row
+ .small-12.columns
+ %header
+ %h2 Final step!
+ %h5
+ How can people find
+ %span{ ng: { class: "{brick: !enterprise.is_primary_producer, turquoise: enterprise.is_primary_producer}" } }
+ {{ enterprise.name }}
+ online?
+
%form{ name: 'social', novalidate: true, ng: { controller: "RegistrationFormCtrl", submit: "update('finished',social)" } }
.row.content
.small-12.large-7.columns
.row
.small-12.columns
- %label{ for: 'enterprise_website' } Website:
- %input.chunky.small-12.columns{ id: 'enterprise_website', placeholder: "eg. openfoodnetwork.org.au", ng: { model: 'enterprise.website' } }
+ .field
+ %label{ for: 'enterprise_website' } Website:
+ %input.chunky{ id: 'enterprise_website', placeholder: "eg. openfoodnetwork.org.au", ng: { model: 'enterprise.website' } }
.row
.small-12.columns
- %label{ for: 'enterprise_facebook' } Facebook:
- %input.chunky.small-12.columns{ id: 'enterprise_facebook', placeholder: "eg. www.facebook.com/PageNameHere", ng: { model: 'enterprise.facebook' } }
+ .field
+ %label{ for: 'enterprise_facebook' } Facebook:
+ %input.chunky{ id: 'enterprise_facebook', placeholder: "eg. www.facebook.com/PageNameHere", ng: { model: 'enterprise.facebook' } }
.row
.small-12.columns
- %label{ for: 'enterprise_linkedin' } LinkedIn:
- %input.chunky.small-12.columns{ id: 'enterprise_linkedin', placeholder: "eg. www.linkedin.com/YourNameHere", ng: { model: 'enterprise.linkedin' } }
+ .field
+ %label{ for: 'enterprise_linkedin' } LinkedIn:
+ %input.chunky{ id: 'enterprise_linkedin', placeholder: "eg. www.linkedin.com/YourNameHere", ng: { model: 'enterprise.linkedin' } }
.small-12.large-5.columns
.row
.small-12.columns
- %label{ for: 'enterprise_twitter' } Twitter:
- %input.chunky.small-12.columns{ id: 'enterprise_twitter', placeholder: "eg. @twitter_handle", ng: { model: 'enterprise.twitter' } }
+ .field
+ %label{ for: 'enterprise_twitter' } Twitter:
+ %input.chunky{ id: 'enterprise_twitter', placeholder: "eg. @twitter_handle", ng: { model: 'enterprise.twitter' } }
.row
.small-12.columns
- %label{ for: 'enterprise_instagram' } Instagram:
- %input.chunky.small-12.columns{ id: 'enterprise_instagram', placeholder: "eg. @instagram_handle", ng: { model: 'enterprise.instagram' } }
+ .field
+ %label{ for: 'enterprise_instagram' } Instagram:
+ %input.chunky{ id: 'enterprise_instagram', placeholder: "eg. @instagram_handle", ng: { model: 'enterprise.instagram' } }
.row.buttons
.small-12.columns
%input.button.secondary{ type: "button", value: "Back", ng: { click: "select('images')" } }
-
- %input.button.primary{ type: "submit", value: "Continue" }
+ %input.button.primary.right{ type: "submit", value: "Continue" }
+
+
diff --git a/app/assets/javascripts/templates/registration/steps.html.haml b/app/assets/javascripts/templates/registration/steps.html.haml
index 65e3cb6b48..8b420de293 100644
--- a/app/assets/javascripts/templates/registration/steps.html.haml
+++ b/app/assets/javascripts/templates/registration/steps.html.haml
@@ -1,5 +1,3 @@
.row#progress-bar
.small-12.medium-2.columns.item{ ng: { repeat: 'step in steps', class: "{active: (currentStep() == step),'show-for-medium-up': (currentStep() != step)}" } }
{{ $index+1 + ". " + step }}
-
-
\ No newline at end of file
diff --git a/app/assets/javascripts/templates/registration/type.html.haml b/app/assets/javascripts/templates/registration/type.html.haml
new file mode 100644
index 0000000000..48d45cb66a
--- /dev/null
+++ b/app/assets/javascripts/templates/registration/type.html.haml
@@ -0,0 +1,46 @@
+.container#registration-type{bindonce: true}
+
+ %ng-include{ src: "'registration/steps.html'" }
+
+ .row
+ .small-12.columns
+ %header
+ %h2
+ Last step to add
+ %span{ ng: { class: "{brick: !enterprise.is_primary_producer, turquoise: enterprise.is_primary_producer}" } }
+ {{ enterprise.name }}!
+ %h4
+ Are you a producer?
+
+ %form{ name: 'type', novalidate: true, ng: { controller: "RegistrationFormCtrl", submit: "create(type)" } }
+ .row#enterprise-types{ 'data-equalizer' => true, bo: { if: "enterprise.type != 'own'" } }
+ .small-12.columns.field
+ .row
+ .small-12.medium-6.large-6.columns{ 'data-equalizer-watch' => true }
+ %a.btnpanel#producer-panel{ href: "#", ng: { click: "enterprise.is_primary_producer = true", class: "{selected: enterprise.is_primary_producer}" } }
+ %i.ofn-i_059-producer
+ %h4 Yes, I'm a producer
+
+ .small-12.medium-6.large-6.columns{ 'data-equalizer-watch' => true }
+ %a.btnpanel#hub-panel{ href: "#", ng: { click: "enterprise.is_primary_producer = false", class: "{selected: enterprise.is_primary_producer == false}" } }
+ %i.ofn-i_063-hub
+ %h4 No, I'm not a producer
+
+ .row
+ .small-12.columns
+ %input.chunky{ id: 'enterprise_is_primary_producer', name: 'is_primary_producer', hidden: true, required: true, ng: { model: 'enterprise.is_primary_producer' } }
+ %span.error{ ng: { show: "type.is_primary_producer.$error.required && submitted" } }
+ Please choose one. Are you are producer?
+ .row
+ .small-12.columns
+ .panel.callout
+ .left
+ %i.ofn-i_013-help
+
+ %p Producers make yummy things to eat &/or drink. You're a producer if you grow it, raise it, brew it, bake it, ferment it, milk it or mould it.
+ / %p Hubs connect the producer to the eater. Hubs can be co-ops, independent retailers, buying groups, wholesalers, CSA box schemes, farm-gate stalls, etc.
+
+ .row.buttons
+ .small-12.columns
+ %input.button.secondary{ type: "button", value: "Back", ng: { click: "select('contact')" } }
+ %input.button.primary.right{ type: "submit", value: "Continue" }
diff --git a/app/assets/stylesheets/admin/alert.css.sass b/app/assets/stylesheets/admin/alert.css.sass
new file mode 100644
index 0000000000..d86cb38f55
--- /dev/null
+++ b/app/assets/stylesheets/admin/alert.css.sass
@@ -0,0 +1,15 @@
+.alert
+ border: 3px solid #919191
+ border-radius: 6px
+ margin-bottom: 20px
+ color: #919191
+ padding: 5px 10px
+ h6
+ color: #919191
+ .message
+ font-weight: bold
+ &:hover
+ border-color: #DA5354
+ color: #DA5354
+ h6
+ color: #DA5354
diff --git a/app/assets/stylesheets/darkswarm/producer_node.css.sass b/app/assets/stylesheets/darkswarm/producer_node.css.sass
index 22541055f4..7bac2dde6d 100644
--- a/app/assets/stylesheets/darkswarm/producer_node.css.sass
+++ b/app/assets/stylesheets/darkswarm/producer_node.css.sass
@@ -32,7 +32,7 @@
span
text-decoration: underline
- &.has_shopfront, &.has_shopfront i.ofn-i_059-producer, &.has_shopfront i.ofn-i_060-producer-reversed
+ &.is_distributor, &.is_distributor i.ofn-i_059-producer, &.is_distributor i.ofn-i_060-producer-reversed
color: $clr-brick
&:hover, &:active, &:focus
color: $clr-brick-bright
diff --git a/app/assets/stylesheets/darkswarm/registration.css.sass b/app/assets/stylesheets/darkswarm/registration.css.sass
index 3261fc0fd4..f63eb30421 100644
--- a/app/assets/stylesheets/darkswarm/registration.css.sass
+++ b/app/assets/stylesheets/darkswarm/registration.css.sass
@@ -2,44 +2,25 @@
@import mixins
#registration-modal
- .header
+ header
text-align: center
- background-color: #efefef
- padding-bottom: 1rem
+ // background-color: #efefef
+ @media all and (max-width: 64em)
+ text-align: left
.container
background-color: #ffffff
- .content
- // margin-bottom: 15px
i
font-size: 150%
- .buttons
-
- ofn-inline-flash
- display: block
- padding: 15px
- position: relative
- margin-bottom: 10px
- &.brick
- background-color: $clr-brick-light
- border: 2px solid $clr-brick
- color: $clr-brick
- &.turquoise
- background-color: $clr-turquoise-light
- border: 2px solid $clr-turquoise
- color: $clr-turquoise
- .close-button
- position: absolute
- top: 0px
- right: 0px
-
.field
- margin-bottom: 15px
+ margin-bottom: 1em
- input.chunky
+ .chunky
padding: 8px
- font-size: 105%
+ font-size: 1rem
+ margin: 0
+ width: 100%
label.indent-checkbox
display: block
@@ -51,9 +32,9 @@
label
margin-bottom: 3px
- ol, ul
- // font-size: 80%
+ ol, ul, p
font-size: 0.875rem
+ ol, ul
padding: 0
margin: 0
ol
@@ -62,22 +43,24 @@
.highlight-box
background: white
padding: 1rem 1.2rem
- @media all and (max-width: 640px)
+ @media all and (max-width: 64em)
margin-top: 1rem
#progress-bar
margin-bottom: 15px
.item
- padding: 12px 0px
+ font-size: 0.75rem
+ padding: 10px 0px
text-transform: uppercase
text-align: center
- background-color: #333
- border: 2px solid #333
+ background-color: $clr-blue
+ border: 2px solid $clr-blue
color: #fff
.item.active
- background-color: #cccccc
- border: 2px solid #333
- color: #333
+ background-color: $disabled-light
+ border: 2px solid $clr-blue
+ color: $clr-blue
+ font-weight: 700
@include box-shadow(inset 0 0 1px 0 #fff)
@@ -110,39 +93,57 @@
font-size: 18px
font-weight: bold
color: #373737
- background-color: #e1e1e1
+ background-color: #f1f1f1
text-align: center
border: 3px dashed #494949
margin-left: auto
margin-right: auto
+ .spinner
+ width: 100px
&.logo
.message
padding-top: 6em
+ .loading
+ padding-top: 4em
width: 306px
height: 306px
&.promo
.message
padding-top: 4em
+ .loading
+ padding-top: 1em
width: 726px
height: 166px
-#registration-details
+#registration-type
#enterprise-types
- a.panel
+ a.btnpanel
display: block
+ padding: 1rem
+ margin-bottom: 1rem
background-color: #efefef
color: black
- @media all and (min-width: 768px)
- min-height: 200px
+ text-align: center
+ border: 1px solid transparent
+ i
+ font-size: 3rem
+ h4
+ margin-top: 1rem
+
&:hover
background-color: #fff
+
producer-panel:hover
+ border: 1px solid $clr-turquoise
&, & *
color: $clr-turquoise
+
hub-panel:hover, both-panel:hover
+ border: 1px solid $clr-brick
&, & *
color: $clr-brick
+
&.selected
&, & *
color: #fff
diff --git a/app/assets/stylesheets/darkswarm/ui.css.sass b/app/assets/stylesheets/darkswarm/ui.css.sass
index 3bbce61552..d18adae1b4 100644
--- a/app/assets/stylesheets/darkswarm/ui.css.sass
+++ b/app/assets/stylesheets/darkswarm/ui.css.sass
@@ -74,8 +74,10 @@ button.success, .button.success
.profile-checkbox
display: inline-block
- input[type="checkbox"] + label
+ label
margin: 0 0.2rem
+ float: right
+
// Responsive
@media screen and (min-width: 768px)
diff --git a/app/assets/stylesheets/distributors.css.scss b/app/assets/stylesheets/distributors.css.scss
deleted file mode 100644
index de8cd669a0..0000000000
--- a/app/assets/stylesheets/distributors.css.scss
+++ /dev/null
@@ -1,3 +0,0 @@
-// Place all the styles related to the distributors controller here.
-// They will automatically be included in application.css.
-// You can use Sass (SCSS) here: http://sass-lang.com/
diff --git a/app/assets/stylesheets/groups.css.scss b/app/assets/stylesheets/groups.css.scss
deleted file mode 100644
index c2a5f9013b..0000000000
--- a/app/assets/stylesheets/groups.css.scss
+++ /dev/null
@@ -1,3 +0,0 @@
-// Place all the styles related to the groups controller here.
-// They will automatically be included in application.css.
-// You can use Sass (SCSS) here: http://sass-lang.com/
diff --git a/app/assets/stylesheets/shop/checkout.css.scss b/app/assets/stylesheets/shop/checkout.css.scss
deleted file mode 100644
index 727d410b19..0000000000
--- a/app/assets/stylesheets/shop/checkout.css.scss
+++ /dev/null
@@ -1,3 +0,0 @@
-// Place all the styles related to the Shop::Checkout controller here.
-// They will automatically be included in application.css.
-// You can use Sass (SCSS) here: http://sass-lang.com/
diff --git a/app/assets/stylesheets/store/openfoodnetwork.css.scss b/app/assets/stylesheets/store/openfoodnetwork.css.scss
deleted file mode 100644
index f98642cc22..0000000000
--- a/app/assets/stylesheets/store/openfoodnetwork.css.scss
+++ /dev/null
@@ -1,381 +0,0 @@
-@import "screen";
-@import "compass/css3/border-radius";
-
-/* General purpose styles */
-
-a:hover {
- color: lighten($link_text_color, 20) !important;
-}
-
-/* Cleared div for clearing previous floating elements */
-div.cleared {
- clear: both;
-}
-
-p.hint {
- margin: 0 0 0.5em 0;
- padding: 0;
- color: #6a6a6a;
-}
-
-table {
- tbody, tfoot {
- tr {
- &.alt, &.odd {
- background-color: lighten($link_text_color, 75) !important;
- }
- }
- }
-}
-
-
-
-/* Style current distributor in main nav bar */
-#header {
- margin-bottom: 40px;
-
- #logo {
- position: relative;
- margin-top: 40px;
- padding-top: 10px;
-
- h1 {
- position: absolute;
- top: 10px;
- left: 0px;
- }
-
- .change-location {
- position: absolute;
- top: 22px;
- right: -104px;
- }
- }
-}
-
-nav #main-nav-bar {
- position: absolute;
- top: 0px;
- left: 10px;
- width: 100%;
-
- #link-to-cart {
- position: relative;
- top: 40px;
- right: 16px;
- }
-
- li {
- current-distribution {
- float: right;
- clear: right;
- margin: 0.5em 5px 0 0;
-
- a {
- font-size: 12px;
- padding: 0;
- }
- }
- }
-}
-
-nav#top-nav-bar {
- position: relative;
- z-index: 999;
- margin-top: 20px;
-}
-
-
-/* Based on Spree's nav#taxonomies style. Copied instead of
- * extended with SASS because SASS does not allow extending
- * nested selectors.
- */
-nav#filters {
- .filter_name {
- text-transform: uppercase;
- border-bottom: 1px solid lighten($body_text_color, 60);
- margin-bottom: 5px;
- font-size: $main_navigation_header_font_size;
- }
-
- .filter_choices {
- padding-left: 20px;
- margin-bottom: 5px;
- list-style: disc outside;
-
- li {
- a {
- font-size: $main_navigation_font_size;
- }
- span.inactive {
- color: #999;
- }
- }
- }
-
- input[type=submit] {
- margin-bottom: 15px;
- }
-}
-
-
-/* Distributor and order cycle selection and display */
-#distribution-choice {
- margin-bottom: 2em;
- padding: 5px;
- border: 2px solid #ccc;
- @include border-radius(10px);
-}
-
-#distribution-selection {
- overflow: auto;
- margin-bottom: 2em;
- padding: 20px;
- background-color: #f3f3f3;
-
- .distributors {
- float: left;
- margin-right: 4em;
-
- option.local {
- background-color: #cfc;
- }
- option.remote {
- background-color: #fcc;
- }
- }
-
- .order-cycles {
-
- select {
- padding: 10px;
- margin-top: 15px;
- border: 2px solid white;
- width: 100%;
- }
-
- float: left;
-
- tr.local {
- background-color: #cfc;
- }
- tr.remote {
- background-color: #fcc;
- }
- }
-}
-
-.countdown-panel {
- background: url("../countdown.png") no-repeat left;
- min-height: 60px;
- min-width: 70px;
- padding-left: 77px;
-}
-
-
-/* Style the product source on the product details page in the
- * same manner as the product properties table above it.
- */
-#product-source {
- @extend #product-properties;
-}
-#product-properties td, #product-source td {
- width: 50%;
-}
-
-
-/* Apply Spree's ul#products style to ul.product-listing. When viewing products
- * split by distributor, a separate product listing is displayed for local and
- * remote products, so the #products id is removed to avoid its duplication.
- */
-ul.product-listing {
- &:after {
- content: " ";
- display: block;
- clear: both;
- visibility: hidden;
- line-height: 0;
- height: 0;
- }
-
- li {
- text-align: center;
- font-weight: bold;
- margin-bottom: 20px;
-
- a {
- display: block;
-
- &.info {
- height: 35px;
- margin-top: 5px;
- font-size: $product_list_name_font_size;
- color: $product_link_text_color;
- border-bottom: 1px solid lighten($body_text_color, 60);
- overflow: hidden;
- }
- }
-
- .product-image {
- border: 1px solid lighten($body_text_color, 60);
- padding: 5px;
- min-height: 110px;
- background-color: $product_background_color;
-
- &:hover {
- border-color: $link_text_color;
- }
-
- }
-
- .price {
- color: $link_text_color;
- font-size: $product_list_price_font_size;
- padding-top: 5px;
- display: block;
- }
- }
-}
-
-
-/* Enterprise description */
-.enterprise-description {
- margin-bottom: 2em;
-}
-
-
-/* Supplier page distributor listing */
-#supplier-distributors li a.inactive {
- color: #999;
-}
-
-
-/* Highlight local products in distributor-split product listings */
-#products-local ul {
- margin-bottom: 1em;
- padding: 10px;
- @include border-radius(10px);
- background-color: #def;
-}
-
-
-/* Distributor details on product details page */
-fieldset#product-distributor-details {
- float: right;
- margin-top: 0;
- width: 250px;
- @extend #shipping;
-}
-
-#product-variants {
- float: none;
-
- ul {
- list-style-type: none;
- }
-}
-
-
-/* Add to cart form on product details page */
-#cart-form {
- .error-distributor {
- font-size: 120%;
- font-weight: bold;
- color: #f00;
-
- a {
- color: #f00;
- text-decoration: underline;
- }
- }
-
- .distributor-fixed {
- }
-}
-
-
-/* View cart form */
-#subtotal {
- width: 100%;
-}
-.links {
- float: right;
- text-align: right;
-}
-#empty-cart {
- float: left;
- margin-top: 15px !important;
-
- p {
- padding: 0;
- }
-}
-
-/* Checkout address page */
-#checkout .alternative-available-distributors {
- padding-top: 30px;
-}
-
-
-/* Delivery fees table on checkout page */
-#delivery-fees {
- clear: both;
- padding-top: 6em;
-
- table#delivery {
- width: 100%;
-
- tbody {
- tr {
- td.item-shipping-cost, td.item-shipping-method {
- text-align: center;
- }
- td.item-shipping-cost {
- @extend span.price;
- @extend span.price.selling;
- }
- }
- }
- }
-
- .subtotal {
- width: 100%;
- text-align: right;
- text-transform: uppercase;
- margin-top: 15px;
-
- span.order-total {
- @extend span.price;
- }
- }
-}
-
-/* Alert for EFT Payment during checkout process */
-div#eft-payment-alert {
- border: 2px solid red;
- padding-left: 5px;
-}
-
-/* Large 'Save and Continue/Process My Order' button under Order Summary on the checkout pages */
-#add_new_save_checkout_button {
- display: none;
- margin-top: 30px;
- padding-top: 10px;
- border-top: 1px solid #d9d9db;
-}
-
-.secondary {
- color: #6A6A6A;
-}
-
-.hide {
- display: none;
-}
-
-
-/* Distributor details */
-.distributor-details .next-collection-at {
- font-size: 20px;
- font-weight: bold;
- color: #de790c;
-}
diff --git a/app/assets/stylesheets/store/variables.css.scss b/app/assets/stylesheets/store/variables.css.scss
deleted file mode 100644
index 4cb074ae48..0000000000
--- a/app/assets/stylesheets/store/variables.css.scss
+++ /dev/null
@@ -1,64 +0,0 @@
-/*--------------------------------------*/
-/* Colors
-/*--------------------------------------*/
-$c_green: #8dba53 !default; /* Spree green */
-$c_red: #e45353 !default; /* Error red */
-
-$layout_background_color: #FFFFFF !default;
-$title_text_color: #404042 !default;
-$body_text_color: #404042 !default;
-$link_text_color: #00ADEE !default;
-
-$product_background_color: #FFFFFF !default;
-$product_title_text_color: #404042 !default;
-$product_body_text_color: #404042 !default;
-$product_link_text_color: #BBBBBB !default;
-
-/*--------------------------------------*/
-/* Fonts import from remote
-/*--------------------------------------*/
-@import url(//fonts.googleapis.com/css?family=Ubuntu:400,700,400italic,700italic|&subset=latin,cyrillic,greek,greek-ext,latin-ext,cyrillic-ext);
-
-/*--------------------------------------*/
-/* Font families
-/*--------------------------------------*/
-$ff_base: 'Ubuntu', sans-serif !default;
-
-/*--------------------------------------
- | Font sizes
- |--------------------------------------
- |- Navigation
- | */
- $header_navigation_font_size: 14px !default;
- $horizontal_navigation_font_size: 16px !default;
- $main_navigation_header_font_size: 14px !default;
- $main_navigation_font_size: 12px !default;
-/*|------------------------------------
- |- Product Listing
- | */
- $product_list_name_font_size: 12px !default;
- $product_list_price_font_size: 16px !default;
- $product_list_header_font_size: 20px !default;
- $product_list_search_font_size: 14px !default;
-/*|------------------------------------
- |- Product Details
- | */
- $product_detail_name_font_size: 24px !default;
- $product_detail_description_font_size: 12px !default;
- $product_detail_price_font_size: 20px !default;
- $product_detail_title_font_size: 14px !default;
-/*|------------------------------------
- |- Basic
- | */
- $heading_font_size: 24px !default;
- $sub_heading_font_size: 14px !default;
- $button_font_size: 12px !default;
- $input_box_font_size: 13px !default;
- $base_font_size: 12px !default;
- $border_color: lighten($body_text_color, 60) !default;
- $default_border: 1px solid $border_color !default;
- $button_border_color: rgba(0, 138, 189, .75) !default;
- $table_head_color: lighten($body_text_color, 60) !default;
-
-
-@import "./store/variables_changes.css.scss";
diff --git a/app/assets/stylesheets/store/variables_changes.css.scss b/app/assets/stylesheets/store/variables_changes.css.scss
deleted file mode 100644
index c4007abd2f..0000000000
--- a/app/assets/stylesheets/store/variables_changes.css.scss
+++ /dev/null
@@ -1 +0,0 @@
-$link_text_color: #006066;
diff --git a/app/controllers/admin/enterprises_controller.rb b/app/controllers/admin/enterprises_controller.rb
index bde7bff431..7d38e408d6 100644
--- a/app/controllers/admin/enterprises_controller.rb
+++ b/app/controllers/admin/enterprises_controller.rb
@@ -3,11 +3,11 @@ module Admin
before_filter :load_enterprise_set, :only => :index
before_filter :load_countries, :except => :index
before_filter :load_methods_and_fees, :only => [:new, :edit, :update, :create]
- before_filter :check_type, only: :update
- before_filter :check_bulk_type, only: :bulk_update
+ before_filter :check_can_change_sells, only: :update
+ before_filter :check_can_change_bulk_sells, only: :bulk_update
before_filter :override_owner, only: :create
- before_filter :check_owner, only: :update
- before_filter :check_bulk_owner, only: :bulk_update
+ before_filter :check_can_change_owner, only: :update
+ before_filter :check_can_change_bulk_owner, only: :bulk_update
helper 'spree/products'
include OrderCyclesHelper
@@ -50,7 +50,8 @@ module Admin
end
def collection
- Enterprise.managed_by(spree_current_user).order('is_distributor DESC, is_primary_producer ASC, name')
+ # TODO was ordered with is_distributor DESC as well, not sure why or how we want ot sort this now
+ Enterprise.managed_by(spree_current_user).order('is_primary_producer ASC, name')
end
def collection_actions
@@ -63,29 +64,29 @@ module Admin
@enterprise_fees = EnterpriseFee.managed_by(spree_current_user).for_enterprise(@enterprise).order(:fee_type, :name).all
end
- def check_bulk_type
+ def check_can_change_bulk_sells
unless spree_current_user.admin?
params[:enterprise_set][:collection_attributes].each do |i, enterprise_params|
- enterprise_params.delete :type
+ enterprise_params.delete :sells
end
end
end
- def check_type
- params[:enterprise].delete :type unless spree_current_user.admin?
+ def check_can_change_sells
+ params[:enterprise].delete :sells unless spree_current_user.admin?
end
def override_owner
params[:enterprise][:owner_id] = spree_current_user.id unless spree_current_user.admin?
end
- def check_owner
+ def check_can_change_owner
unless ( spree_current_user == @enterprise.owner ) || spree_current_user.admin?
params[:enterprise].delete :owner_id
end
end
- def check_bulk_owner
+ def check_can_change_bulk_owner
unless spree_current_user.admin?
params[:enterprise_set][:collection_attributes].each do |i, enterprise_params|
enterprise_params.delete :owner_id
diff --git a/app/controllers/devise/confirmations_controller_decorator.rb b/app/controllers/devise/confirmations_controller_decorator.rb
new file mode 100644
index 0000000000..ef34f28445
--- /dev/null
+++ b/app/controllers/devise/confirmations_controller_decorator.rb
@@ -0,0 +1,7 @@
+Devise::ConfirmationsController.class_eval do
+ protected
+ # Override of devise method in Devise::ConfirmationsController
+ def after_confirmation_path_for(resource_name, resource)
+ spree.admin_path
+ end
+end
\ No newline at end of file
diff --git a/app/controllers/registration_controller.rb b/app/controllers/registration_controller.rb
index 4fae68bb79..5a21d28a44 100644
--- a/app/controllers/registration_controller.rb
+++ b/app/controllers/registration_controller.rb
@@ -2,17 +2,12 @@ require 'open_food_network/spree_api_key_loader'
class RegistrationController < BaseController
include OpenFoodNetwork::SpreeApiKeyLoader
- before_filter :load_spree_api_key, only: [:index, :store]
+ before_filter :load_spree_api_key, only: [:index]
before_filter :check_user, except: :authenticate
layout 'registration'
def index
- @enterprise_attributes = { type: 'profile' }
- end
-
- def store
- @enterprise_attributes = { is_distributor: true, is_primary_producer: true, type: 'single' }
- render :index
+ @enterprise_attributes = { sells: 'none' }
end
private
diff --git a/app/controllers/spree/admin/image_settings_controller_decorator.rb b/app/controllers/spree/admin/image_settings_controller_decorator.rb
new file mode 100644
index 0000000000..5fe7dae551
--- /dev/null
+++ b/app/controllers/spree/admin/image_settings_controller_decorator.rb
@@ -0,0 +1,11 @@
+Spree::Admin::ImageSettingsController.class_eval do
+ # Spree stores attachent definitions in JSON. This converts the style name and format to
+ # strings. However, when paperclip encounters these, it doesn't recognise the format.
+ # Here we solve that problem by converting format and style name to symbols.
+ def update_paperclip_settings_with_format_styles
+ update_paperclip_settings_without_format_styles
+ Spree::Image.reformat_styles
+ end
+
+ alias_method_chain :update_paperclip_settings, :format_styles
+end
diff --git a/app/controllers/spree/admin/overview_controller_decorator.rb b/app/controllers/spree/admin/overview_controller_decorator.rb
index a2288dab88..4ae1c1b095 100644
--- a/app/controllers/spree/admin/overview_controller_decorator.rb
+++ b/app/controllers/spree/admin/overview_controller_decorator.rb
@@ -1,6 +1,7 @@
Spree::Admin::OverviewController.class_eval do
def index
- @enterprises = Enterprise.managed_by(spree_current_user).order('is_distributor DESC, is_primary_producer ASC, name')
+ # TODO was sorted with is_distributor DESC as well, not sure why or how we want ot sort this now
+ @enterprises = Enterprise.managed_by(spree_current_user).order('is_primary_producer ASC, name')
@product_count = Spree::Product.active.managed_by(spree_current_user).count
@order_cycle_count = OrderCycle.active.managed_by(spree_current_user).count
end
diff --git a/app/controllers/spree/admin/reports_controller_decorator.rb b/app/controllers/spree/admin/reports_controller_decorator.rb
index 0abfd783b5..22dd41549f 100644
--- a/app/controllers/spree/admin/reports_controller_decorator.rb
+++ b/app/controllers/spree/admin/reports_controller_decorator.rb
@@ -6,24 +6,6 @@ require 'open_food_network/order_grouper'
require 'open_food_network/customers_report'
Spree::Admin::ReportsController.class_eval do
- # Fetches user's distributors, suppliers and order_cycles
- before_filter :load_data, only: [:customers, :products_and_inventory]
-
- # Render a partial for orders and fulfillment description
- respond_override :index => { :html => { :success => lambda {
- @reports[:orders_and_fulfillment][:description] =
- render_to_string(partial: 'orders_and_fulfillment_description', layout: false, locals: {report_types: REPORT_TYPES[:orders_and_fulfillment]}).html_safe
- @reports[:products_and_inventory][:description] =
- render_to_string(partial: 'products_and_inventory_description', layout: false, locals: {report_types: REPORT_TYPES[:products_and_inventory]}).html_safe
- @reports[:customers][:description] =
- render_to_string(partial: 'customers_description', layout: false, locals: {report_types: REPORT_TYPES[:customers]}).html_safe
- } } }
-
- # OVERRIDING THIS so we use a method not a constant for available reports
- def index
- @reports = available_reports
- respond_with(@reports)
- end
REPORT_TYPES = {
orders_and_fulfillment: [
@@ -42,6 +24,26 @@ Spree::Admin::ReportsController.class_eval do
]
}
+ # Fetches user's distributors, suppliers and order_cycles
+ before_filter :load_data, only: [:customers, :products_and_inventory]
+
+ # Render a partial for orders and fulfillment description
+ respond_override :index => { :html => { :success => lambda {
+ @reports[:orders_and_fulfillment][:description] =
+ render_to_string(partial: 'orders_and_fulfillment_description', layout: false, locals: {report_types: REPORT_TYPES[:orders_and_fulfillment]}).html_safe
+ @reports[:products_and_inventory][:description] =
+ render_to_string(partial: 'products_and_inventory_description', layout: false, locals: {report_types: REPORT_TYPES[:products_and_inventory]}).html_safe
+ @reports[:customers][:description] =
+ render_to_string(partial: 'customers_description', layout: false, locals: {report_types: REPORT_TYPES[:customers]}).html_safe
+ } } }
+
+
+ # Overide spree reports list.
+ def index
+ @reports = authorized_reports
+ respond_with(@reports)
+ end
+
# This action is short because we refactored it like bosses
def customers
@report_types = REPORT_TYPES[:customers]
@@ -592,28 +594,29 @@ Spree::Admin::ReportsController.class_eval do
private
def load_data
+ # Load distributors either owned by the user or selling their enterprises products.
my_distributors = Enterprise.is_distributor.managed_by(spree_current_user)
my_suppliers = Enterprise.is_primary_producer.managed_by(spree_current_user)
distributors_of_my_products = Enterprise.with_distributed_products_outer.merge(Spree::Product.in_any_supplier(my_suppliers))
@distributors = my_distributors | distributors_of_my_products
+ # Load suppliers either owned by the user or supplying products their enterprises distribute.
suppliers_of_products_I_distribute = my_distributors.map { |d| Spree::Product.in_distributor(d) }.flatten.map(&:supplier).uniq
@suppliers = my_suppliers | suppliers_of_products_I_distribute
@order_cycles = OrderCycle.active_or_complete.accessible_by(spree_current_user).order('orders_close_at DESC')
end
- def available_reports
+ def authorized_reports
reports = {
:orders_and_distributors => {:name => "Orders And Distributors", :description => "Orders with distributor details"},
:bulk_coop => {:name => "Bulk Co-Op", :description => "Reports for Bulk Co-Op orders"},
:payments => {:name => "Payment Reports", :description => "Reports for Payments"},
:orders_and_fulfillment => {:name => "Orders & Fulfillment Reports", :description => ''},
:customers => {:name => "Customers", :description => 'Customer details'},
- :products_and_inventory => {:name => "Products & Inventory", :description => ''}
+ :products_and_inventory => {:name => "Products & Inventory", :description => ''},
+ :sales_total => { :name => "Sales Total", :description => "Sales Total For All Orders" }
}
- if spree_current_user.has_spree_role? 'admin'
- reports[:sales_total] = { :name => "Sales Total", :description => "Sales Total For All Orders" }
- end
- reports
+ # Return only reports the user is authorized to view.
+ reports.select { |action| can? action, :report }
end
def total_units(line_items)
diff --git a/app/helpers/admin/image_settings_helper.rb b/app/helpers/admin/image_settings_helper.rb
new file mode 100644
index 0000000000..10c34fe372
--- /dev/null
+++ b/app/helpers/admin/image_settings_helper.rb
@@ -0,0 +1,21 @@
+module Admin
+ module ImageSettingsHelper
+ def admin_image_settings_format_options
+ [['Unchanged', ''], ['PNG', 'png'], ['JPEG', 'jpg']]
+ end
+
+ def admin_image_settings_geometry_from_style(style)
+ geometry, format = admin_image_settings_split_style style
+ geometry
+ end
+
+ def admin_image_settings_format_from_style(style)
+ geometry, format = admin_image_settings_split_style style
+ format
+ end
+
+ def admin_image_settings_split_style(style)
+ [style, nil].flatten[0..1]
+ end
+ end
+end
diff --git a/app/mailers/enterprise_mailer.rb b/app/mailers/enterprise_mailer.rb
index 73c09e1e56..4e37d112e0 100644
--- a/app/mailers/enterprise_mailer.rb
+++ b/app/mailers/enterprise_mailer.rb
@@ -1,8 +1,16 @@
+require 'devise/mailers/helpers'
class EnterpriseMailer < Spree::BaseMailer
- def creation_confirmation(enterprise)
- find_enterprise(enterprise)
- subject = "#{@enterprise.name} is now on #{Spree::Config[:site_name]}"
- mail(:to => @enterprise.owner.email, :from => from_address, :subject => subject)
+ include Devise::Mailers::Helpers
+
+ def confirmation_instructions(record, token, opts={})
+ @token = token
+ find_enterprise(record)
+ opts = {
+ subject: "Please confirm your email for #{@enterprise.name}",
+ to: [ @enterprise.owner.email, @enterprise.email ].uniq,
+ from: from_address,
+ }
+ devise_mail(record, :confirmation_instructions, opts)
end
private
diff --git a/app/mailers/spree/user_mailer_decorator.rb b/app/mailers/spree/user_mailer_decorator.rb
index ff8bdc4691..dd21a3d0d7 100644
--- a/app/mailers/spree/user_mailer_decorator.rb
+++ b/app/mailers/spree/user_mailer_decorator.rb
@@ -1,5 +1,5 @@
Spree::UserMailer.class_eval do
-
+
def signup_confirmation(user)
@user = user
mail(:to => user.email, :from => from_address,
diff --git a/app/models/enterprise.rb b/app/models/enterprise.rb
index dfb7945878..0cc6fd19b9 100644
--- a/app/models/enterprise.rb
+++ b/app/models/enterprise.rb
@@ -1,12 +1,14 @@
class Enterprise < ActiveRecord::Base
- TYPES = %w(full single profile)
+ SELLS = %w(none own any)
ENTERPRISE_SEARCH_RADIUS = 100
+ devise :confirmable, reconfirmable: true
+
self.inheritance_column = nil
acts_as_gmappable :process_geocoding => false
- after_create :send_creation_email
+ before_create :check_email
has_and_belongs_to_many :groups, class_name: 'EnterpriseGroup'
has_many :producer_properties, foreign_key: 'producer_id'
@@ -34,7 +36,7 @@ class Enterprise < ActiveRecord::Base
path: 'public/images/enterprises/logos/:id/:style/:basename.:extension'
has_attached_file :promo_image,
- styles: { large: "1200x260#", medium: "720x156#", thumb: "100x100>" },
+ styles: { large: ["1200x260#", :jpg], medium: ["720x156#", :jpg], thumb: ["100x100>", :jpg] },
url: '/images/enterprises/promo_images/:id/:style/:basename.:extension',
path: 'public/images/enterprises/promo_images/:id/:style/:basename.:extension'
@@ -47,11 +49,12 @@ class Enterprise < ActiveRecord::Base
validates :name, presence: true
- validates :type, presence: true, inclusion: {in: TYPES}
+ validates :sells, presence: true, inclusion: {in: SELLS}
validates :address, presence: true, associated: true
validates :email, presence: true
validates_presence_of :owner
validate :enforce_ownership_limit, if: lambda { owner_id_changed? && !owner_id.nil? }
+ validates_length_of :description, :maximum => 255
before_validation :ensure_owner_is_manager, if: lambda { owner_id_changed? && !owner_id.nil? }
before_validation :set_unused_address_fields
@@ -59,8 +62,10 @@ class Enterprise < ActiveRecord::Base
scope :by_name, order('name')
scope :visible, where(:visible => true)
+ scope :confirmed, where('confirmed_at IS NOT NULL')
+ scope :unconfirmed, where('confirmed_at IS NULL')
scope :is_primary_producer, where(:is_primary_producer => true)
- scope :is_distributor, where(:is_distributor => true)
+ scope :is_distributor, where('sells != ?', 'none')
scope :supplying_variant_in, lambda { |variants| joins(:supplied_products => :variants_including_master).where('spree_variants.id IN (?)', variants).select('DISTINCT enterprises.*') }
scope :with_supplied_active_products_on_hand, lambda {
joins(:supplied_products)
@@ -211,36 +216,30 @@ class Enterprise < ActiveRecord::Base
Spree::Variant.joins(:product => :product_distributions).where('product_distributions.distributor_id=?', self.id)
end
- # Replaces currententerprse type field.
- def sells
- # Type: full - single - profile becomes Sells: all - own - none
- # Remove this return later.
- return "none" if !is_distributor || type == "profile"
- return "own" if type == "single" || suppliers == [self]
- "all"
+ def is_distributor
+ self.sells != "none"
end
# Simplify enterprise categories for frontend logic and icons, and maybe other things.
- def enterprise_category
+ def category
# Make this crazy logic human readable so we can argue about it sanely.
- # This can be simplified later, it's like this for readablitlty during changes.
- category = is_primary_producer ? "producer_" : "non_producer_"
- category << "sell_" + sells
+ cat = self.is_primary_producer ? "producer_" : "non_producer_"
+ cat << "sells_" + self.sells
# Map backend cases to front end cases.
- case category
- when "producer_sell_all"
- "producer_hub" # Producer hub who sells own and others produce and supplies other hubs.
- when "producer_sell_own"
- "producer_shop" # Producer with shopfront and supplies other hubs.
- when "producer_sell_none"
- "producer" # Producer only supplies through others.
- when "non_producer_sell_all"
- "hub" # Hub selling others products in order cycles.
- when "non_producer_sell_own"
- "hub" # Wholesaler selling through own shopfront?
- when "non_producer_sell_none"
- "hub_profile" # Hub selling outside the system.
+ case cat
+ when "producer_sells_any"
+ :producer_hub # Producer hub who sells own and others produce and supplies other hubs.
+ when "producer_sells_own"
+ :producer_shop # Producer with shopfront and supplies other hubs.
+ when "producer_sells_none"
+ :producer # Producer only supplies through others.
+ when "non_producer_sells_any"
+ :hub # Hub selling others products in order cycles.
+ when "non_producer_sells_own"
+ :hub # Wholesaler selling through own shopfront? Does this need a separate name? Should it exist?
+ when "non_producer_sells_none"
+ :hub_profile # Hub selling outside the system.
end
end
@@ -260,14 +259,20 @@ class Enterprise < ActiveRecord::Base
select('DISTINCT spree_taxons.*')
end
+ protected
+
+ def devise_mailer
+ EnterpriseMailer
+ end
+
private
- def send_creation_email
- EnterpriseMailer.creation_confirmation(self).deliver
+ def check_email
+ skip_confirmation! if owner.enterprises.confirmed.map(&:email).include?(email)
end
def strip_url(url)
- url.andand.sub /(https?:\/\/)?/, ''
+ url.andand.sub(/(https?:\/\/)?/, '')
end
def set_unused_address_fields
diff --git a/app/models/enterprise_group.rb b/app/models/enterprise_group.rb
index cdc9d9932a..6e61b1a564 100644
--- a/app/models/enterprise_group.rb
+++ b/app/models/enterprise_group.rb
@@ -15,7 +15,7 @@ class EnterpriseGroup < ActiveRecord::Base
path: 'public/images/enterprise_groups/logos/:id/:style/:basename.:extension'
has_attached_file :promo_image,
- styles: {large: "1200x260#"},
+ styles: {large: ["1200x260#", :jpg]},
url: '/images/enterprise_groups/promo_images/:id/:style/:basename.:extension',
path: 'public/images/enterprise_groups/promo_images/:id/:style/:basename.:extension'
diff --git a/app/models/spree/ability_decorator.rb b/app/models/spree/ability_decorator.rb
index 5fdb4c2342..1fb824d09c 100644
--- a/app/models/spree/ability_decorator.rb
+++ b/app/models/spree/ability_decorator.rb
@@ -1,6 +1,8 @@
class AbilityDecorator
include CanCan::Ability
+ # All abilites are allocated from this initialiser, currently in 5 chunks.
+ # Spree also defines other abilities.
def initialize(user)
add_base_abilities user if is_new_user? user
add_enterprise_management_abilities user if can_manage_enterprises? user
@@ -9,27 +11,31 @@ class AbilityDecorator
add_relationship_management_abilities user if can_manage_relationships? user
end
-
+ # New users have no enterprises.
def is_new_user?(user)
user.enterprises.blank?
end
+ # Users can manage an enterprise if they have one.
def can_manage_enterprises?(user)
user.enterprises.present?
end
+ # Users can manage products if they have an enterprise.
def can_manage_products?(user)
- can_manage_enterprises? user
+ can_manage_enterprises?(user) && user.enterprises.is_primary_producer.present?
end
+ # Users can manage orders if they have a sells own/any enterprise.
def can_manage_orders?(user)
- ( user.enterprises.map(&:type) & %w(single full) ).any?
+ ( user.enterprises.map(&:sells) & %w(own any) ).any?
end
def can_manage_relationships?(user)
can_manage_enterprises? user
end
+ # New users can create an enterprise, and gain other permissions from doing this.
def add_base_abilities(user)
can [:create], Enterprise
end
@@ -47,6 +53,12 @@ class AbilityDecorator
can [:read, :edit, :update, :bulk_update], Enterprise do |enterprise|
user.enterprises.include? enterprise
end
+
+ # All enterprises can have fees, though possibly suppliers don't need them?
+ can [:index, :create], EnterpriseFee
+ can [:admin, :read, :edit, :bulk_update, :destroy], EnterpriseFee do |enterprise_fee|
+ user.enterprises.include? enterprise_fee.enterprise
+ end
end
def add_product_management_abilities(user)
@@ -66,6 +78,9 @@ class AbilityDecorator
can [:admin, :index, :read, :search], Spree::Taxon
can [:admin, :index, :read, :create, :edit], Spree::Classification
+
+ # Reports page
+ can [:admin, :index, :customers, :orders_and_distributors, :group_buys, :bulk_coop, :payments, :orders_and_fulfillment, :products_and_inventory], :report
end
def add_order_management_abilities(user)
@@ -76,7 +91,7 @@ class AbilityDecorator
# during the order creation process from the admin backend
order.distributor.nil? || user.enterprises.include?(order.distributor)
end
- can [:admin, :bulk_management], Spree::Order if user.admin? || user.enterprises.any?(&:is_distributor?)
+ can [:admin, :bulk_management], Spree::Order if user.admin? || user.enterprises.any?(&:is_distributor)
can [:admin, :create], Spree::LineItem
can [:admin, :index, :read, :create, :edit, :update, :fire], Spree::Payment
@@ -90,11 +105,6 @@ class AbilityDecorator
end
can [:for_order_cycle], Enterprise
- can [:index, :create], EnterpriseFee
- can [:admin, :read, :edit, :bulk_update, :destroy], EnterpriseFee do |enterprise_fee|
- user.enterprises.include? enterprise_fee.enterprise
- end
-
can [:admin, :index, :read, :create, :edit, :update], ExchangeVariant
can [:admin, :index, :read, :create, :edit, :update], Exchange
can [:admin, :index, :read, :create, :edit, :update], ExchangeFee
@@ -111,7 +121,7 @@ class AbilityDecorator
end
# Reports page
- can [:admin, :index, :customers, :orders_and_distributors, :group_buys, :bulk_coop, :payments, :orders_and_fulfillment, :products_and_inventory], :report
+ can [:admin, :index, :customers, :group_buys, :bulk_coop, :payments, :orders_and_distributors, :orders_and_fulfillment, :products_and_inventory], :report
end
diff --git a/app/models/spree/image_decorator.rb b/app/models/spree/image_decorator.rb
new file mode 100644
index 0000000000..7d86aae3a6
--- /dev/null
+++ b/app/models/spree/image_decorator.rb
@@ -0,0 +1,23 @@
+Spree::Image.class_eval do
+ # Spree stores attachent definitions in JSON. This converts the style name and format to
+ # strings. However, when paperclip encounters these, it doesn't recognise the format.
+ # Here we solve that problem by converting format and style name to symbols.
+ # See also: ImageSettingsController decorator.
+ #
+ # eg. {'mini' => ['48x48>', 'png']} is converted to {mini: ['48x48>', :png]}
+ def self.format_styles(styles)
+ styles_a = styles.map do |name, style|
+ style[1] = style[1].to_sym if style.is_a? Array
+ [name.to_sym, style]
+ end
+
+ Hash[styles_a]
+ end
+
+ def self.reformat_styles
+ Spree::Image.attachment_definitions[:attachment][:styles] =
+ format_styles(Spree::Image.attachment_definitions[:attachment][:styles])
+ end
+
+ reformat_styles
+end
diff --git a/app/overrides/spree/admin/image_settings/edit/add_image_format.html.haml.deface b/app/overrides/spree/admin/image_settings/edit/add_image_format.html.haml.deface
new file mode 100644
index 0000000000..deb79b5bbf
--- /dev/null
+++ b/app/overrides/spree/admin/image_settings/edit/add_image_format.html.haml.deface
@@ -0,0 +1,11 @@
+/ replace_contents '#styles_list'
+
+- @styles.each_with_index do |(style_name, style_value), index|
+ .field.three.columns
+ = label_tag "attachment_styles[#{style_name}]", style_name
+ %a.destroy_style.with-tip{:alt => t(:destroy), :href => "#", :title => t(:destroy)}
+ %i.icon-trash
+ = text_field_tag "attachment_styles[#{style_name}][]", admin_image_settings_geometry_from_style(style_value), :class => 'fullwidth'
+ %br/
+ - current_format = admin_image_settings_format_from_style(style_value) || ''
+ = select_tag "attachment_styles[#{style_name}][]", options_for_select(admin_image_settings_format_options, current_format), :class => 'fullwidth', :id => "attachment_styles_format_#{style_name}"
diff --git a/app/serializers/api/admin/enterprise_serializer.rb b/app/serializers/api/admin/enterprise_serializer.rb
index 7b82ad0cae..e6d00b7aae 100644
--- a/app/serializers/api/admin/enterprise_serializer.rb
+++ b/app/serializers/api/admin/enterprise_serializer.rb
@@ -1,3 +1,3 @@
class Api::Admin::EnterpriseSerializer < ActiveModel::Serializer
- attributes :name, :id, :is_primary_producer, :is_distributor, :payment_method_ids, :shipping_method_ids
+ attributes :name, :id, :is_primary_producer, :is_distributor, :sells, :category, :payment_method_ids, :shipping_method_ids
end
diff --git a/app/serializers/api/enterprise_serializer.rb b/app/serializers/api/enterprise_serializer.rb
index 6841337024..a2aa506d2f 100644
--- a/app/serializers/api/enterprise_serializer.rb
+++ b/app/serializers/api/enterprise_serializer.rb
@@ -17,9 +17,6 @@ end
class Api::UncachedEnterpriseSerializer < ActiveModel::Serializer
attributes :orders_close_at, :active
- #TODO: Remove these later
- attributes :icon, :icon_font, :producer_icon_font, :has_shopfront, :has_hub_listing, :enterprise_category
-
def orders_close_at
OrderCycle.first_closing_for(object).andand.orders_close_at
end
@@ -28,60 +25,6 @@ class Api::UncachedEnterpriseSerializer < ActiveModel::Serializer
@options[:active_distributors].andand.include? object
end
- def enterprise_category
- object.enterprise_category
- end
-
- def has_shopfront
- object.is_distributor && object.type != 'profile'
- end
-
- # Used to select enterprises for hub listing
- def has_hub_listing
- has_shopfront || object.enterprise_category == "hub_profile"
- end
-
- # Map svg icons.
- def icon
- icons = {
- "hub" => "/assets/map_005-hub.svg",
- "hub_profile" => "/assets/map_006-hub-profile.svg",
- "producer_hub" => "/assets/map_005-hub.svg",
- "producer_shop" => "/assets/map_003-producer-shop.svg",
- "producer" => "/assets/map_001-producer-only.svg",
- "producer_profile" => "/assets/map_002-producer-only-profile.svg",
- }
- icons[object.enterprise_category]
- end
-
- # Choose regular icon font for enterprises.
- def icon_font
- icon_fonts = {
- "hub" => "ofn-i_063-hub",
- "hub_profile" => "ofn-i_064-hub-reversed",
- "producer_hub" => "ofn-i_063-hub",
- "producer_shop" => "ofn-i_059-producer",
- "producer" => "ofn-i_059-producer",
- "producer_profile" => "ofn-i_060-producer-reversed",
- }
- icon_fonts[object.enterprise_category]
- end
-
- # Choose producer page icon font - yes, sadly its got to be different.
- # This duplicates some code but covers the producer page edge case where
- # producer-hub has a producer icon without needing to duplicate the category logic in angular.
- def producer_icon_font
- icon_fonts = {
- "hub" => "",
- "hub_profile" => "",
- "producer_hub" => "ofn-i_059-producer",
- "producer_shop" => "ofn-i_059-producer",
- "producer" => "ofn-i_059-producer",
- "producer_profile" => "ofn-i_060-producer-reversed",
- "empty" => "",
- }
- icon_fonts[object.enterprise_category]
- end
end
@@ -92,8 +35,8 @@ class Api::CachedEnterpriseSerializer < ActiveModel::Serializer
attributes :name, :id, :description, :latitude, :longitude,
:long_description, :website, :instagram, :linkedin, :twitter,
:facebook, :is_primary_producer, :is_distributor, :phone, :visible,
- :email, :hash, :logo, :promo_image, :path,
- :pickup, :delivery
+ :email, :hash, :logo, :promo_image, :path, :pickup, :delivery,
+ :icon, :icon_font, :producer_icon_font, :category
has_many :distributed_taxons, key: :taxons, serializer: Api::IdSerializer
has_many :supplied_taxons, serializer: Api::IdSerializer
@@ -102,6 +45,10 @@ class Api::CachedEnterpriseSerializer < ActiveModel::Serializer
has_one :address, serializer: Api::AddressSerializer
+ def visible
+ object.visible && object.confirmed?
+ end
+
def pickup
object.shipping_methods.where(:require_ship_address => false).present?
end
@@ -131,4 +78,42 @@ class Api::CachedEnterpriseSerializer < ActiveModel::Serializer
def path
"/enterprises/#{object.to_param}/shop"
end
+
+ # Map svg icons.
+ def icon
+ icons = {
+ :hub => "/assets/map_005-hub.svg",
+ :hub_profile => "/assets/map_006-hub-profile.svg",
+ :producer_hub => "/assets/map_005-hub.svg",
+ :producer_shop => "/assets/map_003-producer-shop.svg",
+ :producer => "/assets/map_001-producer-only.svg",
+ }
+ icons[object.category]
+ end
+
+ # Choose regular icon font for enterprises.
+ def icon_font
+ icon_fonts = {
+ :hub => "ofn-i_063-hub",
+ :hub_profile => "ofn-i_064-hub-reversed",
+ :producer_hub => "ofn-i_063-hub",
+ :producer_shop => "ofn-i_059-producer",
+ :producer => "ofn-i_059-producer",
+ }
+ icon_fonts[object.category]
+ end
+
+ # Choose producer page icon font - yes, sadly its got to be different.
+ # This duplicates some code but covers the producer page edge case where
+ # producer-hub has a producer icon without needing to duplicate the category logic in angular.
+ def producer_icon_font
+ icon_fonts = {
+ :hub => "",
+ :hub_profile => "",
+ :producer_hub => "ofn-i_059-producer",
+ :producer_shop => "ofn-i_059-producer",
+ :producer => "ofn-i_059-producer",
+ }
+ icon_fonts[object.category]
+ end
end
diff --git a/app/serializers/api/state_serializer.rb b/app/serializers/api/state_serializer.rb
index bcf9221ec5..7a76e340b4 100644
--- a/app/serializers/api/state_serializer.rb
+++ b/app/serializers/api/state_serializer.rb
@@ -1,3 +1,7 @@
class Api::StateSerializer < ActiveModel::Serializer
attributes :id, :name, :abbr
+
+ def abbr
+ object.abbr.upcase
+ end
end
\ No newline at end of file
diff --git a/app/views/admin/enterprises/_form.html.haml b/app/views/admin/enterprises/_form.html.haml
index 921807b425..20bd174de9 100644
--- a/app/views/admin/enterprises/_form.html.haml
+++ b/app/views/admin/enterprises/_form.html.haml
@@ -32,13 +32,9 @@
.row
.three.columns.alpha
- %label Enterprise Type(s)
- .with-tip{'data-powertip' => "Select 'Producer' if you are a primary producer of food. Select 'Hub' if you want a shop-front. You can choose either or both."}
+ %label Primary Producer
+ .with-tip{'data-powertip' => "Select 'Producer' if you are a primary producer of food."}
%a What's this?
- .two.columns
- = f.check_box :is_distributor, 'ng-model' => 'Enterprise.is_distributor'
-
- = f.label :is_distributor, 'Hub'
.five.columns.omega
= f.check_box :is_primary_producer, 'ng-model' => 'Enterprise.is_primary_producer'
@@ -47,21 +43,21 @@
.row
.alpha.eleven.columns
.three.columns.alpha
- = f.label :type, 'Profile type'
- .with-tip{'data-powertip' => "Full - enterprise may have products and relationships.
Single - enterprise may have products but no relationships.
Profile - enterprise has a profile but no products or relationships.
"}
+ = f.label :sells, 'Sells'
+ .with-tip{'data-powertip' => "None - enterprise does not sell to customers directly.
Own - Enterprise sells own products to customers.
Any - Enterprise can sell own or other enterprises products.
"}
%a What's this?
.two.columns
- = f.radio_button :type, "full"
+ = f.radio_button :sells, "none", 'ng-model' => 'Enterprise.sells'
- = f.label :type, "Full", value: "full"
+ = f.label :sells, "None", value: "none"
.two.columns
- = f.radio_button :type, "single"
+ = f.radio_button :sells, "own", 'ng-model' => 'Enterprise.sells'
- = f.label :type, "Single", value: "single"
+ = f.label :sells, "Own", value: "own"
.four.columns.omega
- = f.radio_button :type, "profile"
+ = f.radio_button :sells, "any", 'ng-model' => 'Enterprise.sells'
- = f.label :type, "Profile", value: "profile"
+ = f.label :sells, "Any", value: "any"
.row
.three.columns.alpha
%label Visible in search?
@@ -177,7 +173,7 @@
.alpha.three.columns
= f.label :description, 'Short Description'
.omega.eight.columns
- = f.text_field :description, placeholder: 'Tell us about your enterprise in one or two sentences'
+ = f.text_field :description, maxlength: 255, placeholder: 'Tell us about your enterprise in one or two sentences'
.row
.alpha.three.columns
= f.label :long_description, 'About Us'
diff --git a/app/views/admin/enterprises/_ng_form.html.haml b/app/views/admin/enterprises/_ng_form.html.haml
index 18e9d6ed36..e3ebe95877 100644
--- a/app/views/admin/enterprises/_ng_form.html.haml
+++ b/app/views/admin/enterprises/_ng_form.html.haml
@@ -3,7 +3,7 @@
= admin_inject_payment_methods
= admin_inject_shipping_methods
-.sixteen.columns.alpha{ ng: { app: 'admin.enterprises', controller: 'enterpriseCtrl' } }
+.sixteen.columns.alpha{ ng: { app: 'admin.enterprises', controller: 'enterpriseCtrl' }, nav: { check: '', callback: 'enterpriseNavCallback()' }}
.eleven.columns.alpha
= render 'form', f: f
.one.column
diff --git a/app/views/admin/enterprises/_sidebar.html.haml b/app/views/admin/enterprises/_sidebar.html.haml
index ac4966fa80..a4c149c9e9 100644
--- a/app/views/admin/enterprises/_sidebar.html.haml
+++ b/app/views/admin/enterprises/_sidebar.html.haml
@@ -1,6 +1,6 @@
+- if can? :admin, EnterpriseFee
+ = render 'sidebar_enterprise_fees', f: f
- if can? :admin, Spree::PaymentMethod
= render 'sidebar_payment_methods', f: f
- if can? :admin, Spree::ShippingMethod
= render 'sidebar_shipping_methods', f: f
-- if can? :admin, EnterpriseFee
- = render 'sidebar_enterprise_fees', f: f
diff --git a/app/views/admin/enterprises/_sidebar_enterprise_fees.html.haml b/app/views/admin/enterprises/_sidebar_enterprise_fees.html.haml
index 50de7e07d9..566d87b832 100644
--- a/app/views/admin/enterprises/_sidebar_enterprise_fees.html.haml
+++ b/app/views/admin/enterprises/_sidebar_enterprise_fees.html.haml
@@ -1,5 +1,5 @@
- enterprise_fees_color = @enterprise_fees.count > 0 ? "blue" : "red"
-.sidebar_item.four.columns.alpha#enterprise_fees{ ng: { show: 'Enterprise.is_distributor' } }
+.sidebar_item.four.columns.alpha#enterprise_fees{ ng: { show: 'Enterprise.category != "producer_hub"' } }
.four.columns.alpha.header{ class: "#{enterprise_fees_color}" }
%span.four.columns.alpha.centered Enterprise Fees
.four.columns.alpha.list{ class: "#{enterprise_fees_color}" }
diff --git a/app/views/admin/enterprises/_sidebar_payment_methods.html.haml b/app/views/admin/enterprises/_sidebar_payment_methods.html.haml
index cb31cc7fff..2d8a174e5c 100644
--- a/app/views/admin/enterprises/_sidebar_payment_methods.html.haml
+++ b/app/views/admin/enterprises/_sidebar_payment_methods.html.haml
@@ -1,4 +1,4 @@
-.sidebar_item.four.columns.alpha#payment_methods{ ng: { show: 'Enterprise.is_distributor' } }
+.sidebar_item.four.columns.alpha#payment_methods{ ng: { show: 'Enterprise.sells != "none"' } }
.four.columns.alpha.header{ ng: { class: "paymentMethodsColor()" } }
%span.four.columns.alpha.centered Payment Methods
.four.columns.alpha.list{ ng: { class: "paymentMethodsColor()" } }
diff --git a/app/views/admin/enterprises/_sidebar_shipping_methods.html.haml b/app/views/admin/enterprises/_sidebar_shipping_methods.html.haml
index 14f65fb755..3e9a0434c0 100644
--- a/app/views/admin/enterprises/_sidebar_shipping_methods.html.haml
+++ b/app/views/admin/enterprises/_sidebar_shipping_methods.html.haml
@@ -1,4 +1,4 @@
-.sidebar_item.four.columns.alpha#shipping_methods{ ng: { show: 'Enterprise.is_distributor' } }
+.sidebar_item.four.columns.alpha#shipping_methods{ ng: { show: 'Enterprise.sells != "none"' } }
.four.columns.alpha.header{ ng: { class: "shippingMethodsColor()" } }
%span.four.columns.alpha.centered Shipping Methods
.four.columns.alpha.list{ ng: { class: "shippingMethodsColor()" } }
diff --git a/app/views/admin/enterprises/edit.html.haml b/app/views/admin/enterprises/edit.html.haml
index 6a8d48b24b..3c132bf5e2 100644
--- a/app/views/admin/enterprises/edit.html.haml
+++ b/app/views/admin/enterprises/edit.html.haml
@@ -4,7 +4,7 @@
Editing:
= @enterprise.name
-= form_for [main_app, :admin, @enterprise] do |f|
+= form_for [main_app, :admin, @enterprise], html: { "ng-app" => 'admin.enterprises', "ng-submit" => "navClear()", "ng-controller" => 'enterpriseCtrl' , "nav-check" => '', "nav-callback" => 'enterpriseNavCallback()' } do |f|
= render 'ng_form', f: f
.twelve.columns.alpha
= render partial: 'spree/admin/shared/edit_resource_links'
diff --git a/app/views/admin/enterprises/index.html.haml b/app/views/admin/enterprises/index.html.haml
index 03e5335155..ee1bdde996 100644
--- a/app/views/admin/enterprises/index.html.haml
+++ b/app/views/admin/enterprises/index.html.haml
@@ -8,7 +8,7 @@
= render 'admin/shared/enterprises_sub_menu'
-= form_for @enterprise_set, :url => main_app.bulk_update_admin_enterprises_path do |f|
+= form_for @enterprise_set, url: main_app.bulk_update_admin_enterprises_path do |f|
%table#listing_enterprises.index
%colgroup
%col{style: "width: 25%;"}/
@@ -23,9 +23,9 @@
%tr{"data-hook" => "enterprises_header"}
%th Name
%th Role
- %th Visible?
- if spree_current_user.admin?
- %th Type
+ %th Sells
+ %th Visible?
- if spree_current_user.admin?
%th Owner
%th
@@ -37,12 +37,9 @@
%td
= enterprise_form.check_box :is_primary_producer
Producer
- %br/
- = enterprise_form.check_box :is_distributor
- Hub
- %td= enterprise_form.check_box :visible
- if spree_current_user.admin?
- %td= enterprise_form.select :type, Enterprise::TYPES, {}, class: 'select2 fullwidth'
+ %td= enterprise_form.select :sells, Enterprise::SELLS, {}, class: 'select2 fullwidth'
+ %td= enterprise_form.check_box :visible
- if spree_current_user.admin?
%td= enterprise_form.select :owner_id, enterprise.users.map{ |e| [ e.email, e.id ] }, {}, class: "select2 fullwidth"
%td{"data-hook" => "admin_users_index_row_actions"}
diff --git a/app/views/admin/enterprises/new.html.haml b/app/views/admin/enterprises/new.html.haml
index 32f6ea0a8d..3df3551f47 100644
--- a/app/views/admin/enterprises/new.html.haml
+++ b/app/views/admin/enterprises/new.html.haml
@@ -3,7 +3,7 @@
- content_for :page_title do
New Enterprise
-= form_for [main_app, :admin, @enterprise] do |f|
- = render partial: 'ng_form', :locals => { f: f }
+= form_for [main_app, :admin, @enterprise], html: { "ng-app" => 'admin.enterprises', "ng-submit" => "navClear()", "ng-controller" => 'enterpriseCtrl' , "nav-check" => '', "nav-callback" => 'enterpriseNavCallback()' } do |f|
+ = render 'ng_form', f: f
.twelve.columns.alpha
= render partial: 'spree/admin/shared/new_resource_links'
diff --git a/app/views/admin/order_cycles/_row.html.haml b/app/views/admin/order_cycles/_row.html.haml
index 75e84de025..3b8c6f34bc 100644
--- a/app/views/admin/order_cycles/_row.html.haml
+++ b/app/views/admin/order_cycles/_row.html.haml
@@ -5,12 +5,12 @@
%td= order_cycle_form.text_field :orders_open_at, :class => 'datetimepicker', :value => order_cycle.orders_open_at
%td= order_cycle_form.text_field :orders_close_at, :class => 'datetimepicker', :value => order_cycle.orders_close_at
%td.suppliers
- - order_cycle.suppliers.managed_by(spree_current_user).each do |s|
+ - order_cycle.suppliers.merge(OpenFoodNetwork::Permissions.new(spree_current_user).order_cycle_enterprises).each do |s|
= s.name
%br/
%td= order_cycle.coordinator.name
%td.distributors
- - order_cycle.distributors.managed_by(spree_current_user).each do |d|
+ - order_cycle.distributors.merge(OpenFoodNetwork::Permissions.new(spree_current_user).order_cycle_enterprises).each do |d|
= d.name
%br/
diff --git a/app/views/admin/order_cycles/index.html.haml b/app/views/admin/order_cycles/index.html.haml
index 1fac06f507..f9f832d83d 100644
--- a/app/views/admin/order_cycles/index.html.haml
+++ b/app/views/admin/order_cycles/index.html.haml
@@ -5,8 +5,6 @@
%li#new_order_cycle_link
= button_link_to "New Order Cycle", main_app.new_admin_order_cycle_path, :icon => 'icon-plus', :id => 'admin_new_order_cycle_link'
-
-
= form_for @order_cycle_set, :url => main_app.bulk_update_admin_order_cycles_path do |f|
%table.index#listing_order_cycles
%colgroup
diff --git a/app/views/checkout/_shipping.html.haml b/app/views/checkout/_shipping.html.haml
index 27089527a2..5ba5ed15e4 100644
--- a/app/views/checkout/_shipping.html.haml
+++ b/app/views/checkout/_shipping.html.haml
@@ -83,4 +83,4 @@
.row
.small-12.columns.text-right
- %button.primary{"ng-disabled" => "shipping.$invalid", "ng-click" => "next($event)", "ofn-focus" => "accordion['shipping']"} Next
+ %button.primary{"ng-disabled" => "shipping.$invalid", "ng-click" => "next($event)"} Next
diff --git a/app/views/enterprise_mailer/confirmation_instructions.html.haml b/app/views/enterprise_mailer/confirmation_instructions.html.haml
new file mode 100644
index 0000000000..19bab3f5ee
--- /dev/null
+++ b/app/views/enterprise_mailer/confirmation_instructions.html.haml
@@ -0,0 +1,100 @@
+/ ORIGINAL & UGLY:
+/ %p= "Welcome #{@resource.contact}!"
+/ %p= "Please confirm your email address for #{@resource.name}."
+/ %p= "Click the link below to activate your enterprise:"
+/ %p= link_to 'Confirm this email address', confirmation_url(@resource, :confirmation_token => @resource.confirmation_token)
+
+
+%html{:style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;", :xmlns => "http://www.w3.org/1999/xhtml"}
+ %head{:style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;"}
+ / If you delete this meta tag, Half Life 3 will never be released.
+ %meta{:content => "width=device-width", :name => "viewport", :style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;"}/
+ %meta{:content => "text/html; charset=UTF-8", "http-equiv" => "Content-Type", :style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;"}/
+ %title{:style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;"} Open Food Network
+ %link{:href => "http://rohanmitchell.com/random/template/basic-email-template/stylesheets/email.css", :rel => "stylesheet", :style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;", :type => "text/css"}/
+ %body{:bgcolor => "#FFFFFF", :style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;-webkit-font-smoothing: antialiased;-webkit-text-size-adjust: none;height: 100%;width: 100%!important;"}
+ / HEADER
+ %table.head-wrap{:bgcolor => "#333333", :style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;width: 100%;"}
+ %tr{:style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;"}
+ %td{:style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;"}
+ %td.header.container{:style => "margin: 0 auto!important;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;display: block!important;max-width: 600px!important;clear: both!important;"}
+ .content{:style => "margin: 0 auto;padding: 15px;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;max-width: 600px;display: block;"}
+ %table{:bgcolor => "#333333", :style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;width: 100%;"}
+ %tr{:style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;"}
+ %td{:style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;"}
+ %img{:src => "https://openfoodnetwork.org.au/assets/ofn_logo_beta-8e4dfc79deb25def2d107dea52dce492.png", :style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;max-width: 100%;", :width => "200"}/
+ %td{:align => "right", :style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;"}
+ %h6.collapse{:style => "margin: 0!important;padding: 0;font-family: \"HelveticaNeue-Light\", \"Helvetica Neue Light\", \"Helvetica Neue\", Helvetica, Arial, \"Lucida Grande\", sans-serif;line-height: 1.1;margin-bottom: 15px;color: #999;font-weight: 900;font-size: 14px;text-transform: uppercase;"} Open Food Network
+ %td{:style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;"}
+ / /HEADER
+ / BODY
+ %table.body-wrap{:style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;width: 100%;"}
+ %tr{:style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;"}
+ %td{:style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;"}
+ %td.container{:bgcolor => "#FFFFFF", :style => "margin: 0 auto!important;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;display: block!important;max-width: 600px!important;clear: both!important;"}
+ .content{:style => "margin: 0 auto;padding: 15px;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;max-width: 600px;display: block;"}
+ %table{:style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;width: 100%;"}
+ %tr{:style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;"}
+ %td{:style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;"}
+ %h3{:style => "margin: 0;padding: 0;font-family: \"HelveticaNeue-Light\", \"Helvetica Neue Light\", \"Helvetica Neue\", Helvetica, Arial, \"Lucida Grande\", sans-serif;line-height: 1.1;margin-bottom: 15px;color: #000;font-weight: 500;font-size: 27px;"}= "Welcome, #{@resource.contact}!"
+ %p.lead{:style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;margin-bottom: 10px;font-weight: normal;font-size: 17px;line-height: 1.6;"}
+ = "Please confirm email address for your enterprise "
+ %strong
+ = "#{@resource.name}."
+ %p
+ / Callout Panel
+ %p.callout{:style => "margin: 0; padding: 15px;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;margin-bottom: 15px;font-weight: normal;font-size: 14px;line-height: 1.6;background-color: #e1f0f5;"}
+ = "Click the link below to confirm email and to activate your enterprise. This link can be used only once:"
+ %br
+ %strong
+ = link_to 'Confirm this email address »', confirmation_url(@resource, :confirmation_token => @resource.confirmation_token)
+ / /Callout Panel
+ %p
+ %p{:style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;margin-bottom: 10px;font-weight: normal;font-size: 14px;line-height: 1.6;"}= "We're so excited that you're joining the Open Food Network! Don't hestitate to get in touch if you have any questions."
+ %p
+ / social & contact
+ %table.social{:style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;background-color: #ebebeb;width: 100%;", :width => "100%"}
+ %tr{:style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;"}
+ %td{:style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;"}
+ / column 1
+ %table.column{:align => "left", :style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;width: 280px;float: left;min-width: 279px;"}
+ %tr{:style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;"}
+ %td{:style => "margin: 0;padding: 15px;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;"}
+ %h5{:style => "margin: 0;padding: 0;font-family: \"HelveticaNeue-Light\", \"Helvetica Neue Light\", \"Helvetica Neue\", Helvetica, Arial, \"Lucida Grande\", sans-serif;line-height: 1.1;margin-bottom: 15px;color: #000;font-weight: 900;font-size: 17px;"} Connect with Us:
+ %p{:style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;margin-bottom: 10px;font-weight: normal;font-size: 14px;line-height: 1.6;"}
+ %a.soc-btn.fb{:href => "https://www.facebook.com/OpenFoodNet", :style => "margin: 0;padding: 3px 7px;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;color: #FFF;font-size: 12px;margin-bottom: 10px;text-decoration: none;font-weight: bold;display: block;text-align: center;background-color: #3B5998!important;", :target => "_blank"} Facebook
+ %a.soc-btn.tw{:href => "https://twitter.com/OpenFoodNet", :style => "margin: 0;padding: 3px 7px;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;color: #FFF;font-size: 12px;margin-bottom: 10px;text-decoration: none;font-weight: bold;display: block;text-align: center;background-color: #1daced!important;", :target => "_blank"} Twitter
+ %a.soc-btn.li{:href => "http://www.linkedin.com/groups/Open-Food-Foundation-4743336", :style => "margin: 0;padding: 3px 7px;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;color: #FFF;font-size: 12px;margin-bottom: 10px;text-decoration: none;font-weight: bold;display: block;text-align: center;background-color: #0073b2!important;", :target => "_blank"} LinkedIn
+ / /column 1
+ / column 2
+ %table.column{:align => "left", :style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;width: 280px;float: left;min-width: 279px;"}
+ %tr{:style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;"}
+ %td{:style => "margin: 0;padding: 15px;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;"}
+ %h5{:style => "margin: 0;padding: 0;font-family: \"HelveticaNeue-Light\", \"Helvetica Neue Light\", \"Helvetica Neue\", Helvetica, Arial, \"Lucida Grande\", sans-serif;line-height: 1.1;margin-bottom: 15px;color: #000;font-weight: 900;font-size: 17px;"} Email us:
+ %p{:style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;margin-bottom: 10px;font-weight: normal;font-size: 14px;line-height: 1.6;"}
+ %strong{:style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;"}
+ %a{:href => "hello@openfoodnetwork.org", :style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;color: #0096ad;"} hello@openfoodnetwork.org
+ / /column 2
+ %span.clear{:style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;display: block;clear: both;"}
+ / /social & contact
+ / /content
+ %td{:style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;"}
+ / /BODY
+ / FOOTER
+ %table.footer-wrap{:style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;width: 100%;clear: both!important;"}
+ %tr{:style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;"}
+ %td{:style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;"}
+ %td.container{:style => "margin: 0 auto!important;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;display: block!important;max-width: 600px!important;clear: both!important;"}
+ / content
+ .content{:style => "margin: 0 auto;padding: 15px;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;max-width: 600px;display: block;"}
+ %table{:style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;width: 100%;"}
+ %tr{:style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;"}
+ %td{:align => "center", :style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;"}
+ %p{:style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;margin-bottom: 10px;font-weight: normal;font-size: 14px;line-height: 1.6;"}
+ %a{:href => "https://openfoodnetwork.org.au/Terms-of-service.pdf", :style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;color: #0096ad;", :target => "_blank"} Terms of service
+ |
+ %a{:href => "http://www.openfoodnetwork.org.au", :style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;color: #0096ad;", :target => "_blank"} Open Food Network
+ / | Unsubscribe
+ / /content
+ %td{:style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;"}
+ / /FOOTER
diff --git a/app/views/enterprise_mailer/creation_confirmation.html.haml b/app/views/enterprise_mailer/creation_confirmation.html.haml
deleted file mode 100644
index 0df3bf06a0..0000000000
--- a/app/views/enterprise_mailer/creation_confirmation.html.haml
+++ /dev/null
@@ -1,9 +0,0 @@
-%h1
- = @enterprise.name + " has been created"
-
-%h3
- Why not check it out on
- %a{ href: "#{map_url}" }
- = Spree::Config[:site_name] + "?"
-
-If you have any questions, please get in touch with us at: hello@openfoodnetwork.org
diff --git a/app/views/groups/index.html.haml b/app/views/groups/index.html.haml
index b033c93d12..1aa5b02629 100644
--- a/app/views/groups/index.html.haml
+++ b/app/views/groups/index.html.haml
@@ -40,8 +40,9 @@
%h5 Our hubs & producers
%ul.small-block-grid-2
%li{"ng-repeat" => "enterprise in group.enterprises", "scroll-after-load" => true}
- %hub-modal{"ng-if" => "enterprise.is_distributor"}
- %producer-modal{"ng-if" => "!enterprise.is_distributor", "show-hub-actions" => 'true'}
+ %enterprise-modal{"ng-if" => "enterprise.is_distributor"}
+ {{ enterprise.name }}
+ %enterprise-modal{"ng-if" => "!enterprise.is_distributor", "show-hub-actions" => 'true'}
{{ enterprise.name }}
diff --git a/app/views/home/_fat.html.haml b/app/views/home/_fat.html.haml
index 406431b9b7..b3741e5aec 100644
--- a/app/views/home/_fat.html.haml
+++ b/app/views/home/_fat.html.haml
@@ -23,7 +23,7 @@
%label Our producers
%ul.small-block-grid-2.medium-block-grid-1.large-block-grid-2
%li{"ng-repeat" => "enterprise in hub.producers"}
- %producer-modal
+ %enterprise-modal
%i.ofn-i_036-producers
%span
{{ enterprise.name }}
diff --git a/app/views/home/_filters.html.haml b/app/views/home/_filters.html.haml
index ff13a0c33c..52fceb6688 100644
--- a/app/views/home/_filters.html.haml
+++ b/app/views/home/_filters.html.haml
@@ -10,7 +10,7 @@
.light Filter by
Type
%ul.small-block-grid-2.medium-block-grid-4.large-block-grid-5
- %taxon-selector{objects: "hubs | hubs:query",
+ %taxon-selector{objects: "Enterprises.hubs | searchEnterprises:query",
results: "activeTaxons"}
.small-12.large-3.columns
%h5.tdhead
diff --git a/app/views/home/_hubs.html.haml b/app/views/home/_hubs.html.haml
index 67cb6abb40..1e5151469e 100644
--- a/app/views/home/_hubs.html.haml
+++ b/app/views/home/_hubs.html.haml
@@ -1,24 +1,17 @@
-= inject_enterprises
-#hubs.hubs{"ng-controller" => "HubsCtrl"}
+= inject_enterprises
+#hubs.hubs{"ng-controller" => "EnterprisesCtrl"}
.row
.small-12.columns
%h1 Shop in your local area
- #active-table-search.row.pad-top
- .small-12.columns
- %input{type: :text,
- "ng-model" => "query",
- placeholder: "Search by name or suburb...",
- "ng-debounce" => "150",
- "ofn-disable-enter" => true}
-
+ = render partial: "shared/components/enterprise_search"
= render partial: "home/filters"
.row{bindonce: true}
.small-12.columns
.active_table
- %hub.active_table_node.row.animate-repeat{"ng-repeat" => "hub in filteredHubs = (hubs | hubs:query | taxons:activeTaxons | shipping:shippingTypes | showProfiles:show_profiles )",
- "ng-class" => "{'is_profile' : !hub.has_shopfront, 'closed' : !open(), 'open' : open(), 'inactive' : !hub.active, 'current' : current()}",
+ %hub.active_table_node.row.animate-repeat{"ng-repeat" => "hub in filteredEnterprises = (Enterprises.hubs | visible | searchEnterprises:query | taxons:activeTaxons | shipping:shippingTypes | showHubProfiles:show_profiles | orderBy:['-active', '+orders_close_at'])",
+ "ng-class" => "{'is_profile' : hub.category == 'hub_profile', 'closed' : !open(), 'open' : open(), 'inactive' : !hub.active, 'current' : current()}",
"scroll-after-load" => true,
"ng-controller" => "HubNodeCtrl",
id: "{{hub.hash}}"}
@@ -26,9 +19,4 @@
= render partial: 'home/skinny'
= render partial: 'home/fat'
- .row{"ng-show" => "filteredHubs.length == 0"}
- .columns.small-12
- %p.no-results
- Sorry, no results found for
- %strong {{query}}.
- Try another search?
+ = render partial: 'shared/components/enterprise_no_results'
diff --git a/app/views/home/_skinny.html.haml b/app/views/home/_skinny.html.haml
index 2010bffe1e..7100a06974 100644
--- a/app/views/home/_skinny.html.haml
+++ b/app/views/home/_skinny.html.haml
@@ -1,4 +1,4 @@
-.row.active_table_row{"ng-if" => "hub.has_shopfront", "ng-click" => "toggle()", "ng-class" => "{'closed' : !open(), 'has_shopfront' : producer.has_shopfront}", bindonce: true}
+.row.active_table_row{"ng-if" => "hub.is_distributor", "ng-click" => "toggle()", "ng-class" => "{'closed' : !open(), 'is_distributor' : producer.is_distributor}", bindonce: true}
.columns.small-12.medium-6.large-5.skinny-head
%a.hub{"bo-href" => "hub.path", "ng-class" => "{primary: hub.active, secondary: !hub.active}", "ofn-empties-cart" => "hub"}
@@ -24,7 +24,7 @@
%em Shopping here
%span.margin-top{ bo: { if: "!current()" } } Orders closed
-.row.active_table_row{"ng-if" => "!hub.has_shopfront", "ng-class" => "closed"}
+.row.active_table_row{"ng-if" => "!hub.is_distributor", "ng-class" => "closed"}
.columns.small-12.medium-6.large-5.skinny-head
%a.hub{"ng-click" => "openModal(hub)", "ng-class" => "{primary: hub.active, secondary: !hub.active}", "ofn-empties-cart" => "hub"}
%i{ng: {class: "hub.icon_font"}}
diff --git a/app/views/json/partials/_enterprise.rabl b/app/views/json/partials/_enterprise.rabl
index 5b52898482..b8800e22ae 100644
--- a/app/views/json/partials/_enterprise.rabl
+++ b/app/views/json/partials/_enterprise.rabl
@@ -21,9 +21,9 @@ node :promo_image do |enterprise|
end
node :icon do |e|
- if e.is_primary_producer? and e.is_distributor?
+ if e.is_primary_producer and e.is_distributor
image_path "map_003-producer-shop.svg"
- elsif e.is_primary_producer?
+ elsif e.is_primary_producer
image_path "map_001-producer-only.svg"
else
image_path "map_005-hub.svg"
diff --git a/app/views/modals/_producer.html.haml b/app/views/modals/_producer.html.haml
deleted file mode 100644
index 51a45cfe5f..0000000000
--- a/app/views/modals/_producer.html.haml
+++ /dev/null
@@ -1,56 +0,0 @@
-%ofn-modal{title: "{{enterprise.name}}"}
- .highlight
- .highlight-top
- %p.right
- {{ [enterprise.address.city, enterprise.address.state_name] | printArray}}
- %h3
- %i.ofn-i_036-producers
- {{ enterprise.name }}
- %img.hero-img{"ng-src" => "{{enterprise.promo_image}}"}
-
- .row{bindonce: true}
- .small-12.large-8.columns
- %div{"ng-show" => "enterprise.long_description.length > 0 || enterprise.logo"}
- %p.modal-header About
- .about-container
- %img.enterprise-logo{"bo-src" => "enterprise.logo", "bo-if" => "enterprise.logo"}
- %p.text-small{"ng-bind-html" => "enterprise.long_description"}
-
- .small-12.large-4.columns
- %div.modal-centered{"bo-if" => "enterprise.email || enterprise.website || enterprise.phone"}
- %p.modal-header Contact
- %p{"bo-if" => "enterprise.phone"}
- {{ enterprise.phone }}
-
- %p{"bo-if" => "enterprise.email"}
- %a{"ng-href" => "{{enterprise.email | stripUrl}}", target: "_blank", mailto: true }
- %span.email
- {{ enterprise.email | stripUrl }}
-
- %p{"bo-show" => "enterprise.website"}
- %a{"ng-href" => "http://{{enterprise.website}}", target: "_blank" }
- {{ enterprise.website | stripUrl }}
-
- %div.modal-centered{"bo-if" => "enterprise.twitter || enterprise.facebook || enterprise.linkedin || enterprise.instagram"}
- %p.modal-header Follow
- .follow-icons{bindonce: true}
- %span{"bo-show" => "enterprise.twitter"}
- %a{"ng-href" => "http://twitter.com/{{enterprise.twitter}}", target: "_blank"}
- %i.ofn-i_041-twitter
-
- %span{"bo-show" => "enterprise.facebook"}
- %a{"ng-href" => "http://{{enterprise.facebook | stripUrl}}", target: "_blank"}
- %i.ofn-i_044-facebook
-
- %span{"bo-show" => "enterprise.linkedin"}
- %a{"ng-href" => "http://{{enterprise.linkedin | stripUrl}}", target: "_blank"}
- %i.ofn-i_042-linkedin
-
- %span{"bo-show" => "enterprise.instagram"}
- %a{"ng-href" => "http://instagram.com/{{enterprise.instagram}}", target: "_blank"}
- %i.ofn-i_043-instagram
-
- %a.close-reveal-modal{"ng-click" => "$close()"}
- %i.ofn-i_009-close
-
-
diff --git a/app/views/producers/_filters.html.haml b/app/views/producers/_filters.html.haml
index 92f0870e7e..00472dc91c 100644
--- a/app/views/producers/_filters.html.haml
+++ b/app/views/producers/_filters.html.haml
@@ -11,5 +11,5 @@
.light Filter by
Type
%ul.small-block-grid-2.medium-block-grid-4.large-block-grid-6
- %taxon-selector{objects: "Producers.visible | filterProducers:query ",
+ %taxon-selector{objects: "Enterprises.producers | searchEnterprises:query ",
results: "activeTaxons"}
diff --git a/app/views/producers/_skinny.html.haml b/app/views/producers/_skinny.html.haml
index 37767b3789..aaa59b20e8 100644
--- a/app/views/producers/_skinny.html.haml
+++ b/app/views/producers/_skinny.html.haml
@@ -1,11 +1,11 @@
-.row.active_table_row{"ng-click" => "toggle()", "ng-class" => "{'closed' : !open(), 'has_shopfront' : producer.has_shopfront}"}
+.row.active_table_row{"ng-click" => "toggle()", "ng-class" => "{'closed' : !open(), 'is_distributor' : producer.is_distributor}"}
.columns.small-12.medium-4.large-4.skinny-head
- %span{"bo-if" => "producer.has_shopfront" }
- %a.has_shopfront{"bo-href" => "producer.path" }
+ %span{"bo-if" => "producer.is_distributor" }
+ %a.is_distributor{"bo-href" => "producer.path" }
%i{ng: {class: "producer.producer_icon_font"}}
%span.margin-top
%strong {{ producer.name }}
- %span.producer-name{"bo-if" => "!producer.has_shopfront" }
+ %span.producer-name{"bo-if" => "!producer.is_distributor" }
%i{ng: {class: "producer.producer_icon_font"}}
%span.margin-top
%strong {{ producer.name }}
diff --git a/app/views/producers/index.html.haml b/app/views/producers/index.html.haml
index fe487585e6..0e46795701 100644
--- a/app/views/producers/index.html.haml
+++ b/app/views/producers/index.html.haml
@@ -1,22 +1,10 @@
-= inject_enterprises
-.producers.pad-top{"ng-controller" => "ProducersCtrl"}
+= inject_enterprises
+.producers.pad-top{"ng-controller" => "EnterprisesCtrl"}
.row
.small-12.columns.pad-top
%h1 Find local producers
- / %div
- / Find a
- / %ofn-modal{title: "producer"}
- / = render partial: "modals/producers"
- / from the list below:
-
- #active-table-search.row
- .small-12.columns
- %input.animate-show{type: :text,
- "ng-model" => "query",
- placeholder: "Search by producer or suburb...",
- "ng-debounce" => "150",
- "ofn-disable-enter" => true}
+ = render partial: "shared/components/enterprise_search"
= render partial: "producers/filters"
.row{bindonce: true}
@@ -24,7 +12,7 @@
.active_table
%producer.active_table_node.row.animate-repeat{id: "{{producer.path}}",
"scroll-after-load" => true,
- "ng-repeat" => "producer in producers = (Producers.visible | filterProducers:query | taxons:activeTaxons)",
+ "ng-repeat" => "producer in filteredEnterprises = (Enterprises.producers | visible | searchEnterprises:query | taxons:activeTaxons)",
"ng-controller" => "ProducerNodeCtrl",
"ng-class" => "{'closed' : !open(), 'open' : open(), 'inactive' : !producer.active}",
id: "{{producer.hash}}"}
@@ -33,10 +21,6 @@
= render partial: 'producers/skinny'
= render partial: 'producers/fat'
- %producer.row{"ng-show" => "producers.length == 0"}
- %p.no-results
- Sorry, no results found for
- %strong {{query}}.
- Try another search?
+ = render partial: 'shared/components/enterprise_no_results'
= render partial: "shared/footer"
diff --git a/app/views/shared/components/_enterprise_no_results.html.haml b/app/views/shared/components/_enterprise_no_results.html.haml
new file mode 100644
index 0000000000..2e6edd0875
--- /dev/null
+++ b/app/views/shared/components/_enterprise_no_results.html.haml
@@ -0,0 +1,5 @@
+%producer.row{"ng-show" => "filteredEnterprises.length == 0"}
+ %p.no-results
+ Sorry, no results found for
+ %strong {{query}}.
+ Try another search?
diff --git a/app/views/shared/components/_enterprise_search.html.haml b/app/views/shared/components/_enterprise_search.html.haml
new file mode 100644
index 0000000000..0ccb23220c
--- /dev/null
+++ b/app/views/shared/components/_enterprise_search.html.haml
@@ -0,0 +1,7 @@
+#active-table-search.row
+ .small-12.columns
+ %input{type: :text,
+ "ng-model" => "query",
+ placeholder: "Search by name or suburb...",
+ "ng-debounce" => "150",
+ "ofn-disable-enter" => true}
diff --git a/app/views/shared/components/_show_profiles.html.haml b/app/views/shared/components/_show_profiles.html.haml
index c2232c3555..638cc47c27 100644
--- a/app/views/shared/components/_show_profiles.html.haml
+++ b/app/views/shared/components/_show_profiles.html.haml
@@ -1,6 +1,7 @@
.small-12.medium-6.columns.text-right
.profile-checkbox
- %input{"ng-model" => "show_profiles", type: "checkbox", name: "profile"}><
- %label Show profiles
%button.button.secondary.tiny.help-btn.ng-scope{:popover => "Profiles do not have a shopfront on the Open Food Network, but may have their own physical or online shop elsewhere", "popover-placement" => "left"}><
%i.ofn-i_013-help
+ %label
+ %input{"ng-model" => "show_profiles", type: "checkbox", name: "profile"}
+ Show profiles
diff --git a/app/views/shop/products/_summary.html.haml b/app/views/shop/products/_summary.html.haml
index 25c71f276a..82d5f7c297 100644
--- a/app/views/shop/products/_summary.html.haml
+++ b/app/views/shop/products/_summary.html.haml
@@ -10,7 +10,7 @@
%em from
%span
- %producer-modal
+ %enterprise-modal
%i.ofn-i_036-producers
{{ enterprise.name }}
diff --git a/app/views/shopping_shared/_producers.html.haml b/app/views/shopping_shared/_producers.html.haml
index d6ff09be4c..25c0c0599d 100644
--- a/app/views/shopping_shared/_producers.html.haml
+++ b/app/views/shopping_shared/_producers.html.haml
@@ -4,5 +4,6 @@
%h5 {{CurrentHub.hub.name}}'s producers:
%ul.small-block-grid-2.large-block-grid-4
%li{"ng-repeat" => "enterprise in CurrentHub.hub.producers"}
- %i.ofn-i_036-producers
- = render partial: "modals/producer"
+ %enterprise-modal
+ %i.ofn-i_036-producers
+ {{ enterprise.name }}
diff --git a/app/views/shopping_shared/_tabs.html.haml b/app/views/shopping_shared/_tabs.html.haml
index 7a78a191b6..c19ec56755 100644
--- a/app/views/shopping_shared/_tabs.html.haml
+++ b/app/views/shopping_shared/_tabs.html.haml
@@ -1,14 +1,14 @@
#tabs{"ng-controller" => "TabsCtrl"}
.row
%tabset.small-12.columns
- // WILL can we add some logic here to make the distributor name not appear at small sizes? e.g. add a class?)
+ -# Build all tabs.
- for name, heading in { about: "About #{current_distributor.name}",
producers: "Producers",
groups: "Groups",
contact: "Contact"}
-
+ -# tabs take tab path in 'active' and 'select' functions defined in TabsCtrl.
%tab{heading: heading,
id: "tab_#{name}",
- active: "active(#{name}.path)",
- select: "select(#{name})"}
+ active: "active(\'#{name}\')",
+ select: "select(\'#{name}\')"}
= render "shopping_shared/#{name}"
diff --git a/app/views/spree/admin/overview/_unconfirmed.html.haml b/app/views/spree/admin/overview/_unconfirmed.html.haml
new file mode 100644
index 0000000000..05c4df2a0d
--- /dev/null
+++ b/app/views/spree/admin/overview/_unconfirmed.html.haml
@@ -0,0 +1,4 @@
+- @enterprises.unconfirmed.each do |enterprise|
+ .alert
+ %h6= "Action Required: Please confirm the email address for #{enterprise.name}."
+ %span.message= "We've sent a confirmation email to #{enterprise.email}, so please check there for further instructions. Thanks!"
\ No newline at end of file
diff --git a/app/views/spree/admin/overview/index.html.haml b/app/views/spree/admin/overview/index.html.haml
index a46a31b404..d83a71bc40 100644
--- a/app/views/spree/admin/overview/index.html.haml
+++ b/app/views/spree/admin/overview/index.html.haml
@@ -1,10 +1,17 @@
%h1{ :style => 'margin-bottom: 30px'} Dashboard
+- if @enterprises.unconfirmed.any?
+
+ = render partial: "spree/admin/overview/unconfirmed"
+
+ %hr
+
- if @enterprises.empty?
= render partial: "spree/admin/overview/enterprises"
- else
+
- if can? :admin, Spree::Product
= render partial: "spree/admin/overview/products"
diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb
new file mode 100644
index 0000000000..9fef52fc8c
--- /dev/null
+++ b/config/initializers/devise.rb
@@ -0,0 +1,5 @@
+Devise.setup do |config|
+ # Add a default scope to devise, to prevent it from checking
+ # whether other devise enabled models are signed into a session or not
+ config.default_scope = :spree_user
+end
\ No newline at end of file
diff --git a/config/ng-test.conf.js b/config/ng-test.conf.js
index eadaf984ae..f87aa3d48a 100644
--- a/config/ng-test.conf.js
+++ b/config/ng-test.conf.js
@@ -27,9 +27,16 @@ module.exports = function(config) {
'app/assets/javascripts/admin/util.js.erb'
],
+ preprocessors: {
+ '**/*.coffee': ['coffee']
+ },
+
coffeePreprocessor: {
options: {
sourceMap: true
+ },
+ transformPath: function(path) {
+ return path.replace(/\.coffee$/, '.js');
}
},
diff --git a/config/routes.rb b/config/routes.rb
index 3e063641dd..ca4a6b59ff 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -6,7 +6,6 @@ Openfoodnetwork::Application.routes.draw do
get "/map", to: "map#index", as: :map
get "/register", to: "registration#index", as: :registration
- get "/register/store", to: "registration#store", as: :store_registration
get "/register/auth", to: "registration#authenticate", as: :registration_auth
resource :shop, controller: "shop" do
@@ -35,6 +34,8 @@ Openfoodnetwork::Application.routes.draw do
end
end
+ devise_for :enterprise
+
namespace :admin do
resources :order_cycles do
post :bulk_update, on: :collection, as: :bulk_update
diff --git a/db/migrate/20140927005000_add_dummy_for_missing_emails.rb b/db/migrate/20140927005000_add_dummy_for_missing_emails.rb
new file mode 100644
index 0000000000..08f638e2a3
--- /dev/null
+++ b/db/migrate/20140927005000_add_dummy_for_missing_emails.rb
@@ -0,0 +1,7 @@
+class AddDummyForMissingEmails < ActiveRecord::Migration
+ def up
+ Enterprise.all.each do |enterprise|
+ enterprise.update_column(:email, "missing@example.com") if enterprise.read_attribute(:email).blank?
+ end
+ end
+end
diff --git a/db/migrate/20140927005043_enterprise_config_refactor.rb b/db/migrate/20140927005043_enterprise_config_refactor.rb
new file mode 100644
index 0000000000..6b51ac6e50
--- /dev/null
+++ b/db/migrate/20140927005043_enterprise_config_refactor.rb
@@ -0,0 +1,57 @@
+class EnterpriseConfigRefactor < ActiveRecord::Migration
+ class Enterprise < ActiveRecord::Base
+ self.inheritance_column = nil
+ end
+
+ def up
+ add_column :enterprises, :sells, :string, null: false, default: 'none'
+ add_index :enterprises, :sells
+ add_index :enterprises, [:is_primary_producer, :sells]
+
+ Enterprise.reset_column_information
+
+ Enterprise.all.each do |enterprise|
+ enterprise.update_attributes!({:sells => sells_what?(enterprise)})
+ end
+
+ remove_column :enterprises, :type
+ remove_column :enterprises, :is_distributor
+ end
+
+ def down
+ # This process is lossy. Producer profiles wont exist.
+ add_column :enterprises, :type, :string, null: false, default: 'profile'
+ add_column :enterprises, :is_distributor, :boolean
+
+ Enterprise.reset_column_information
+
+ Enterprise.all.each do |enterprise|
+ enterprise.update_attributes!({
+ :type => type?(enterprise),
+ :is_distributor => distributes?(enterprise)
+ })
+ end
+
+ remove_column :enterprises, :sells
+ end
+
+ def sells_what?(enterprise)
+ is_distributor = enterprise.read_attribute(:is_distributor)
+ is_primary_producer = enterprise.read_attribute(:is_primary_producer)
+ type = enterprise.read_attribute(:type)
+ return "own" if type == "single" && (is_distributor || is_primary_producer)
+ return "none" if !is_distributor || type == "profile"
+ return "any"
+ end
+
+ def distributes?(enterprise)
+ enterprise.read_attribute(:sells) != "none"
+ end
+
+ def type?(enterprise)
+ sells = enterprise.read_attribute(:sells)
+ return "profile" if sells == "none"
+ return "single" if sells == "own"
+ return "full"
+ end
+end
diff --git a/db/migrate/20141010043405_add_confirmable_to_enterprise.rb b/db/migrate/20141010043405_add_confirmable_to_enterprise.rb
new file mode 100644
index 0000000000..22203fe419
--- /dev/null
+++ b/db/migrate/20141010043405_add_confirmable_to_enterprise.rb
@@ -0,0 +1,16 @@
+class AddConfirmableToEnterprise < ActiveRecord::Migration
+ def up
+ add_column :enterprises, :confirmation_token, :string
+ add_column :enterprises, :confirmed_at, :datetime
+ add_column :enterprises, :confirmation_sent_at, :datetime
+ add_column :enterprises, :unconfirmed_email, :string
+ add_index :enterprises, :confirmation_token, :unique => true
+
+ # Existing enterprises are assumed to be confirmed
+ Enterprise.update_all(:confirmed_at => Time.now)
+ end
+
+ def down
+ remove_columns :enterprises, :confirmation_token, :confirmed_at, :confirmation_sent_at, :unconfirmed_email
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 73f10210a7..974dc8ac9b 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -11,7 +11,7 @@
#
# It's strongly recommended to check this file into your version control system.
-ActiveRecord::Schema.define(:version => 20140904003026) do
+ActiveRecord::Schema.define(:version => 20141010043405) do
create_table "adjustment_metadata", :force => true do |t|
t.integer "adjustment_id"
@@ -238,7 +238,6 @@ ActiveRecord::Schema.define(:version => 20140904003026) do
t.string "description"
t.text "long_description"
t.boolean "is_primary_producer"
- t.boolean "is_distributor"
t.string "contact"
t.string "phone"
t.string "email"
@@ -249,8 +248,8 @@ ActiveRecord::Schema.define(:version => 20140904003026) do
t.integer "address_id"
t.string "pickup_times"
t.string "next_collection_at"
- t.datetime "created_at", :null => false
- t.datetime "updated_at", :null => false
+ t.datetime "created_at", :null => false
+ t.datetime "updated_at", :null => false
t.text "distributor_info"
t.string "logo_file_name"
t.string "logo_content_type"
@@ -264,12 +263,19 @@ ActiveRecord::Schema.define(:version => 20140904003026) do
t.string "facebook"
t.string "instagram"
t.string "linkedin"
- t.string "type", :default => "profile", :null => false
- t.integer "owner_id", :null => false
+ t.integer "owner_id", :null => false
+ t.string "confirmation_token"
+ t.datetime "confirmed_at"
+ t.datetime "confirmation_sent_at"
+ t.string "unconfirmed_email"
+ t.string "sells", :default => "none", :null => false
end
add_index "enterprises", ["address_id"], :name => "index_enterprises_on_address_id"
+ add_index "enterprises", ["confirmation_token"], :name => "index_enterprises_on_confirmation_token", :unique => true
+ add_index "enterprises", ["is_primary_producer", "sells"], :name => "index_enterprises_on_is_primary_producer_and_sells"
add_index "enterprises", ["owner_id"], :name => "index_enterprises_on_owner_id"
+ add_index "enterprises", ["sells"], :name => "index_enterprises_on_sells"
create_table "exchange_fees", :force => true do |t|
t.integer "exchange_id"
diff --git a/script/backup.sh b/script/backup.sh
index 462aef6abe..114a8352c6 100755
--- a/script/backup.sh
+++ b/script/backup.sh
@@ -4,4 +4,5 @@
set -e
+mkdir -p db/backup
ssh $1 "pg_dump -h localhost -U openfoodweb openfoodweb_production |gzip" > db/backup/$1-`date +%Y%m%d`.sql.gz
diff --git a/spec/controllers/admin/enterprises_controller_spec.rb b/spec/controllers/admin/enterprises_controller_spec.rb
index eafdd33c92..4120f163e2 100644
--- a/spec/controllers/admin/enterprises_controller_spec.rb
+++ b/spec/controllers/admin/enterprises_controller_spec.rb
@@ -84,28 +84,28 @@ module Admin
end
describe "updating an enterprise" do
- let(:profile_enterprise) { create(:enterprise, type: 'profile') }
+ let(:profile_enterprise) { create(:enterprise, sells: 'none') }
context "as manager" do
- it "does not allow 'type' to be changed" do
+ it "does not allow 'sells' to be changed" do
profile_enterprise.enterprise_roles.build(user: user).save
controller.stub spree_current_user: user
- enterprise_params = { id: profile_enterprise.id, enterprise: { type: 'full' } }
+ enterprise_params = { id: profile_enterprise.id, enterprise: { sells: 'any' } }
spree_put :update, enterprise_params
profile_enterprise.reload
- expect(profile_enterprise.type).to eq 'profile'
+ expect(profile_enterprise.sells).to eq 'none'
end
end
context "as super admin" do
- it "allows 'type' to be changed" do
+ it "allows 'sells' to be changed" do
controller.stub spree_current_user: admin_user
- enterprise_params = { id: profile_enterprise.id, enterprise: { type: 'full' } }
+ enterprise_params = { id: profile_enterprise.id, enterprise: { sells: 'any' } }
spree_put :update, enterprise_params
profile_enterprise.reload
- expect(profile_enterprise.type).to eq 'full'
+ expect(profile_enterprise.sells).to eq 'any'
end
end
end
@@ -123,38 +123,38 @@ module Admin
user.save!
user
end
- let!(:profile_enterprise1) { create(:enterprise, type: 'profile', owner: original_owner ) }
- let!(:profile_enterprise2) { create(:enterprise, type: 'profile', owner: original_owner ) }
+ let!(:profile_enterprise1) { create(:enterprise, sells: 'none', owner: original_owner ) }
+ let!(:profile_enterprise2) { create(:enterprise, sells: 'none', owner: original_owner ) }
context "as manager" do
- it "does not allow 'type' or 'owner' to be changed" do
+ it "does not allow 'sells' or 'owner' to be changed" do
profile_enterprise1.enterprise_roles.build(user: new_owner).save
profile_enterprise2.enterprise_roles.build(user: new_owner).save
controller.stub spree_current_user: new_owner
- bulk_enterprise_params = { enterprise_set: { collection_attributes: { '0' => { id: profile_enterprise1.id, type: 'full', owner_id: new_owner.id }, '1' => { id: profile_enterprise2.id, type: 'full', owner_id: new_owner.id } } } }
+ bulk_enterprise_params = { enterprise_set: { collection_attributes: { '0' => { id: profile_enterprise1.id, sells: 'any', owner_id: new_owner.id }, '1' => { id: profile_enterprise2.id, sells: 'any', owner_id: new_owner.id } } } }
spree_put :bulk_update, bulk_enterprise_params
profile_enterprise1.reload
profile_enterprise2.reload
- expect(profile_enterprise1.type).to eq 'profile'
- expect(profile_enterprise2.type).to eq 'profile'
+ expect(profile_enterprise1.sells).to eq 'none'
+ expect(profile_enterprise2.sells).to eq 'none'
expect(profile_enterprise1.owner).to eq original_owner
expect(profile_enterprise2.owner).to eq original_owner
end
end
context "as super admin" do
- it "allows 'type' and 'owner' to be changed" do
+ it "allows 'sells' and 'owner' to be changed" do
profile_enterprise1.enterprise_roles.build(user: new_owner).save
profile_enterprise2.enterprise_roles.build(user: new_owner).save
controller.stub spree_current_user: admin_user
- bulk_enterprise_params = { enterprise_set: { collection_attributes: { '0' => { id: profile_enterprise1.id, type: 'full', owner_id: new_owner.id }, '1' => { id: profile_enterprise2.id, type: 'full', owner_id: new_owner.id } } } }
+ bulk_enterprise_params = { enterprise_set: { collection_attributes: { '0' => { id: profile_enterprise1.id, sells: 'any', owner_id: new_owner.id }, '1' => { id: profile_enterprise2.id, sells: 'any', owner_id: new_owner.id } } } }
spree_put :bulk_update, bulk_enterprise_params
profile_enterprise1.reload
profile_enterprise2.reload
- expect(profile_enterprise1.type).to eq 'full'
- expect(profile_enterprise2.type).to eq 'full'
+ expect(profile_enterprise1.sells).to eq 'any'
+ expect(profile_enterprise2.sells).to eq 'any'
expect(profile_enterprise1.owner).to eq new_owner
expect(profile_enterprise2.owner).to eq new_owner
end
diff --git a/spec/controllers/devise/confirmation_controller_spec.rb b/spec/controllers/devise/confirmation_controller_spec.rb
new file mode 100644
index 0000000000..b8719bbd8f
--- /dev/null
+++ b/spec/controllers/devise/confirmation_controller_spec.rb
@@ -0,0 +1,15 @@
+require 'spec_helper'
+
+describe Devise::ConfirmationsController do
+ context "after confirmation" do
+ before do
+ e = create(:enterprise, confirmed_at: nil)
+ @request.env["devise.mapping"] = Devise.mappings[:enterprise]
+ spree_get :show, confirmation_token: e.confirmation_token
+ end
+
+ it "should redirect to admin root" do
+ expect(response).to redirect_to spree.admin_path
+ end
+ end
+end
\ No newline at end of file
diff --git a/spec/controllers/registration_controller_spec.rb b/spec/controllers/registration_controller_spec.rb
index e51a28f73a..8ef292dc68 100644
--- a/spec/controllers/registration_controller_spec.rb
+++ b/spec/controllers/registration_controller_spec.rb
@@ -7,11 +7,6 @@ describe RegistrationController do
get :index
response.should redirect_to registration_auth_path(anchor: "signup?after_login=/register")
end
-
- it "store" do
- get :store
- response.should redirect_to registration_auth_path(anchor: "signup?after_login=/register/store")
- end
end
describe "redirecting when user has reached enterprise ownership limit" do
@@ -41,12 +36,5 @@ describe RegistrationController do
expect(assigns(:spree_api_key)).to eq user.spree_api_key
end
end
-
- describe "store" do
- it "loads the spree api key" do
- get :store
- expect(assigns(:spree_api_key)).to eq user.spree_api_key
- end
- end
end
end
diff --git a/spec/controllers/spree/admin/payment_methods_controller_spec.rb b/spec/controllers/spree/admin/payment_methods_controller_spec.rb
index f3266f69c2..c27fe16f19 100644
--- a/spec/controllers/spree/admin/payment_methods_controller_spec.rb
+++ b/spec/controllers/spree/admin/payment_methods_controller_spec.rb
@@ -73,4 +73,4 @@ describe Spree::Admin::PaymentMethodsController do
end
end
end
-end
\ No newline at end of file
+end
diff --git a/spec/factories.rb b/spec/factories.rb
index db035ba16a..60b94b08c0 100644
--- a/spec/factories.rb
+++ b/spec/factories.rb
@@ -92,21 +92,22 @@ FactoryGirl.define do
factory :enterprise, :class => Enterprise do
owner { FactoryGirl.create :user }
sequence(:name) { |n| "Enterprise #{n}" }
- type 'full'
+ sells 'any'
description 'enterprise'
long_description 'Hello, world!
This is a paragraph.
'
email 'enterprise@example.com'
address { FactoryGirl.create(:address) }
+ confirmed_at { Time.now }
end
factory :supplier_enterprise, :parent => :enterprise do
is_primary_producer true
- is_distributor false
+ sells "none"
end
factory :distributor_enterprise, :parent => :enterprise do
is_primary_producer false
- is_distributor true
+ sells "any"
end
factory :enterprise_relationship do
diff --git a/spec/features/admin/enterprise_user_spec.rb b/spec/features/admin/enterprise_user_spec.rb
index 70e6a9b265..232ffb68ae 100644
--- a/spec/features/admin/enterprise_user_spec.rb
+++ b/spec/features/admin/enterprise_user_spec.rb
@@ -11,10 +11,10 @@ feature %q{
let!(:user) { create_enterprise_user }
let!(:supplier1) { create(:supplier_enterprise, name: 'Supplier 1') }
let!(:supplier2) { create(:supplier_enterprise, name: 'Supplier 2') }
- let(:supplier_profile) { create(:supplier_enterprise, name: 'Supplier profile', type: 'profile') }
+ let(:supplier_profile) { create(:supplier_enterprise, name: 'Supplier profile', sells: 'none') }
let!(:distributor1) { create(:distributor_enterprise, name: 'Distributor 3') }
let!(:distributor2) { create(:distributor_enterprise, name: 'Distributor 4') }
- let(:distributor_profile) { create(:distributor_enterprise, name: 'Distributor profile', type: 'profile') }
+ let(:distributor_profile) { create(:distributor_enterprise, name: 'Distributor profile', sells: 'none') }
describe "creating an enterprise user" do
context "with a limitted number of owned enterprises" do
@@ -53,7 +53,10 @@ feature %q{
end
end
- describe "with only a profile-level enterprise" do
+ # This case no longer exists as anyone with an enterprise can supply into the system.
+ # Or can they?? There is no producer profile anyway.
+ # TODO discuss what parts of this are still necessary in which cases.
+ pending "with only a profile-level enterprise" do
before do
user.enterprise_roles.create! enterprise: supplier_profile
user.enterprise_roles.create! enterprise: distributor_profile
diff --git a/spec/features/admin/enterprises_spec.rb b/spec/features/admin/enterprises_spec.rb
index d3d23aabcb..06b1fd31a6 100644
--- a/spec/features/admin/enterprises_spec.rb
+++ b/spec/features/admin/enterprises_spec.rb
@@ -16,7 +16,7 @@ feature %q{
within("tr.enterprise-#{s.id}") do
expect(page).to have_content s.name
- expect(page).to have_select "enterprise_set_collection_attributes_1_type"
+ expect(page).to have_select "enterprise_set_collection_attributes_1_sells"
expect(page).to have_content "Edit Profile"
expect(page).to have_content "Delete"
expect(page).to_not have_content "Payment Methods"
@@ -26,7 +26,7 @@ feature %q{
within("tr.enterprise-#{d.id}") do
expect(page).to have_content d.name
- expect(page).to have_select "enterprise_set_collection_attributes_0_type"
+ expect(page).to have_select "enterprise_set_collection_attributes_0_sells"
expect(page).to have_content "Edit Profile"
expect(page).to have_content "Delete"
expect(page).to have_content "Payment Methods"
@@ -37,7 +37,7 @@ feature %q{
scenario "editing enterprises in bulk" do
s = create(:supplier_enterprise)
- d = create(:distributor_enterprise, type: 'profile')
+ d = create(:distributor_enterprise, sells: 'none')
d_manager = create_enterprise_user
d_manager.enterprise_roles.build(enterprise: d).save
expect(d.owner).to_not eq d_manager
@@ -48,14 +48,14 @@ feature %q{
within("tr.enterprise-#{d.id}") do
expect(page).to have_checked_field "enterprise_set_collection_attributes_0_visible"
uncheck "enterprise_set_collection_attributes_0_visible"
- select 'full', from: "enterprise_set_collection_attributes_0_type"
+ select 'any', from: "enterprise_set_collection_attributes_0_sells"
select d_manager.email, from: 'enterprise_set_collection_attributes_0_owner_id'
end
click_button "Update"
flash_message.should == 'Enterprises updated successfully'
distributor = Enterprise.find(d.id)
expect(distributor.visible).to eq false
- expect(distributor.type).to eq 'full'
+ expect(distributor.sells).to eq 'any'
expect(distributor.owner).to eq d_manager
end
@@ -82,15 +82,16 @@ feature %q{
click_link 'New Enterprise'
# Checking shipping and payment method sidebars work
+ choose "Any"
uncheck 'enterprise_is_primary_producer'
- check 'enterprise_is_distributor'
+
page.should_not have_checked_field "enterprise_payment_method_ids_#{payment_method.id}"
page.should_not have_checked_field "enterprise_shipping_method_ids_#{shipping_method.id}"
# Filling in details
fill_in 'enterprise_name', :with => 'Eaterprises'
select2_search admin.email, from: 'Owner'
- choose 'Full'
+ choose 'Any'
check "enterprise_payment_method_ids_#{payment_method.id}"
check "enterprise_shipping_method_ids_#{shipping_method.id}"
select2_search eg1.name, from: 'Groups'
@@ -134,7 +135,7 @@ feature %q{
end
fill_in 'enterprise_name', :with => 'Eaterprises'
- choose 'Single'
+ choose 'Own'
select2_search user.email, from: 'Owner'
fill_in 'enterprise_description', :with => 'Connecting farmers and eaters'
long_description = find :css, "text-angular div.ta-scroll-window div.ta-bind"
@@ -142,14 +143,23 @@ feature %q{
# Check Angularjs switching of sidebar elements
uncheck 'enterprise_is_primary_producer'
- uncheck 'enterprise_is_distributor'
+ choose 'None'
+ page.should have_selector "#enterprise_fees", visible: false
page.should have_selector "#payment_methods", visible: false
page.should have_selector "#shipping_methods", visible: false
- page.should have_selector "#enterprise_fees", visible: false
- check 'enterprise_is_distributor'
+ check 'enterprise_is_primary_producer'
+ page.should have_selector "#enterprise_fees"
+ page.should have_selector "#payment_methods", visible: false
+ page.should have_selector "#shipping_methods", visible: false
+ uncheck 'enterprise_is_primary_producer'
+ choose 'Own'
+ page.should have_selector "#enterprise_fees"
page.should have_selector "#payment_methods"
page.should have_selector "#shipping_methods"
+ choose 'Any'
page.should have_selector "#enterprise_fees"
+ page.should have_selector "#payment_methods"
+ page.should have_selector "#shipping_methods"
select2_search eg1.name, from: 'Groups'
@@ -277,16 +287,14 @@ feature %q{
within("tr.enterprise-#{distributor1.id}") do
expect(page).to have_content distributor1.name
- expect(page).to have_checked_field "enterprise_set_collection_attributes_0_is_distributor"
expect(page).to have_unchecked_field "enterprise_set_collection_attributes_0_is_primary_producer"
- expect(page).to_not have_select "enterprise_set_collection_attributes_0_type"
+ expect(page).to_not have_select "enterprise_set_collection_attributes_0_sells"
end
within("tr.enterprise-#{supplier1.id}") do
expect(page).to have_content supplier1.name
- expect(page).to have_unchecked_field "enterprise_set_collection_attributes_1_is_distributor"
expect(page).to have_checked_field "enterprise_set_collection_attributes_1_is_primary_producer"
- expect(page).to_not have_select "enterprise_set_collection_attributes_1_type"
+ expect(page).to_not have_select "enterprise_set_collection_attributes_1_sells"
end
expect(page).to_not have_content "supplier2.name"
diff --git a/spec/features/admin/image_settings_spec.rb b/spec/features/admin/image_settings_spec.rb
new file mode 100644
index 0000000000..a83a072235
--- /dev/null
+++ b/spec/features/admin/image_settings_spec.rb
@@ -0,0 +1,43 @@
+require 'spec_helper'
+
+feature %q{
+ As an admin
+ I want to manage image formats
+} do
+ include AuthenticationWorkflow
+ include WebHelper
+
+ before(:all) do
+ styles = {"mini" => "48x48>",
+ "small" => "100x100>",
+ "product" => "240x240>",
+ "large" => "600x600>"}
+
+ Spree::Config[:attachment_styles] = ActiveSupport::JSON.encode(styles)
+ Spree::Image.attachment_definitions[:attachment][:styles] = ActiveSupport::JSON.decode(Spree::Config[:attachment_styles])
+ Spree::Image.reformat_styles
+ end
+
+ scenario "setting the image format for a paperclip style" do
+ # When I go to the image settings page
+ login_to_admin_section
+ visit spree.edit_admin_image_settings_path
+
+ # All the styles should default to "Unchanged"
+ page.should have_select 'attachment_styles_format_mini', selected: 'Unchanged'
+ page.should have_select 'attachment_styles_format_small', selected: 'Unchanged'
+ page.should have_select 'attachment_styles_format_product', selected: 'Unchanged'
+ page.should have_select 'attachment_styles_format_large', selected: 'Unchanged'
+
+ # When I change a style to "PNG" and save
+ select 'PNG', from: 'attachment_styles_format_mini'
+ click_button 'Update'
+
+ # Then the change should be saved to the image formats
+ page.should have_content "Image Settings successfully updated."
+ page.should have_select 'attachment_styles_format_mini', selected: 'PNG'
+
+ styles = Spree::Image.attachment_definitions[:attachment][:styles]
+ styles[:mini].should == ['48x48>', :png]
+ end
+end
diff --git a/spec/features/admin/order_cycles_spec.rb b/spec/features/admin/order_cycles_spec.rb
index febd966109..be91d442e1 100644
--- a/spec/features/admin/order_cycles_spec.rb
+++ b/spec/features/admin/order_cycles_spec.rb
@@ -471,6 +471,10 @@ feature %q{
# I should see only the order cycle I am coordinating
page.should have_content oc_user_coordinating.name
page.should_not have_content oc_for_other_user.name
+
+ # The order cycle should show enterprises that I manage
+ page.should have_selector 'td.suppliers', text: supplier_managed.name
+ page.should have_selector 'td.distributors', text: distributor_managed.name
# The order cycle should not show enterprises that I don't manage
page.should_not have_selector 'td.suppliers', text: supplier_unmanaged.name
diff --git a/spec/features/admin/variants_spec.rb b/spec/features/admin/variants_spec.rb
index 1904f3d5af..19767d8ea2 100644
--- a/spec/features/admin/variants_spec.rb
+++ b/spec/features/admin/variants_spec.rb
@@ -1,4 +1,4 @@
-require "spec_helper"
+require 'spec_helper'
feature %q{
As an admin
diff --git a/spec/features/consumer/producers_spec.rb b/spec/features/consumer/producers_spec.rb
index 98bef7f084..6e09365195 100644
--- a/spec/features/consumer/producers_spec.rb
+++ b/spec/features/consumer/producers_spec.rb
@@ -3,14 +3,14 @@ require 'spec_helper'
feature %q{
As a consumer
I want to see a list of producers
- So that I can shop at hubs distributing their products
+ So that I can shop at hubs distributing their products
}, js: true do
include UIComponentHelper
let!(:producer) { create(:supplier_enterprise) }
let!(:invisible_producer) { create(:supplier_enterprise, visible: false) }
let(:taxon) { create(:taxon) }
let!(:product) { create(:simple_product, supplier: producer, taxons: [taxon]) }
-
+
before do
visit producers_path
end
@@ -20,7 +20,7 @@ feature %q{
expand_active_table_node producer.name
page.should have_content producer.supplied_taxons.first.name.split.map(&:capitalize).join(' ')
end
-
+
it "doesn't show invisible producers" do
page.should_not have_content invisible_producer.name
end
diff --git a/spec/features/consumer/registration_spec.rb b/spec/features/consumer/registration_spec.rb
index 7ac46a8970..ea09450467 100644
--- a/spec/features/consumer/registration_spec.rb
+++ b/spec/features/consumer/registration_spec.rb
@@ -17,25 +17,22 @@ feature "Registration", js: true do
# Enter Login details
fill_in "Email", with: user.email
fill_in "Password", with: user.password
- click_login_and_ensure_content "This wizard will step you through creating a profile"
+ click_login_and_ensure_content "Hi there!"
expect(URI.parse(current_url).path).to eq registration_path
# Done reading introduction
- click_button_and_ensure_content "Let's get started!", "Woot! First we need to know what sort of enterprise you are:"
+ click_button_and_ensure_content "Let's get started!", "Woot! First we need to know a little bit about your enterprise:"
# Filling in details
fill_in 'enterprise_name', with: "My Awesome Enterprise"
- click_link 'both-panel'
-
- click_button_and_ensure_content "Continue", "Greetings My Awesome Enterprise"
# Filling in address
fill_in 'enterprise_address', with: '123 Abc Street'
fill_in 'enterprise_city', with: 'Northcote'
fill_in 'enterprise_zipcode', with: '3070'
select 'Australia', from: 'enterprise_country'
- select 'Vic', from: 'enterprise_state'
+ select 'VIC', from: 'enterprise_state'
click_button 'Continue'
# Filling in Contact Details
@@ -45,11 +42,16 @@ feature "Registration", js: true do
fill_in 'enterprise_phone', with: '12 3456 7890'
click_button 'Continue'
+ # Choosing a type
+ expect(page).to have_content 'Last step to add My Awesome Enterprise!'
+ click_link 'producer-panel'
+ click_button 'Continue'
+
# Enterprise should be created
expect(page).to have_content 'Nice one!'
e = Enterprise.find_by_name('My Awesome Enterprise')
expect(e.address.address1).to eq "123 Abc Street"
- expect(e.is_distributor).to eq true
+ expect(e.sells).to eq "none"
expect(e.is_primary_producer).to eq true
expect(e.contact).to eq "Saskia Munroe"
@@ -75,7 +77,7 @@ feature "Registration", js: true do
click_button 'Continue'
# Filling in social
- expect(page).to have_content 'Last step!'
+ expect(page).to have_content 'How can people find My Awesome Enterprise online?'
fill_in 'enterprise_website', with: 'www.shop.com'
fill_in 'enterprise_facebook', with: 'FaCeBoOk'
fill_in 'enterprise_linkedin', with: 'LiNkEdIn'
@@ -84,7 +86,7 @@ feature "Registration", js: true do
click_button 'Continue'
# Done
- expect(page).to have_content "You have successfully completed the profile for My Awesome Enterprise"
+ expect(page).to have_content "Finished!"
e.reload
expect(e.website).to eq "www.shop.com"
expect(e.facebook).to eq "FaCeBoOk"
@@ -92,31 +94,6 @@ feature "Registration", js: true do
expect(e.twitter).to eq "@TwItTeR"
expect(e.instagram).to eq "@InStAgRaM"
end
-
- it "Allows a logged in user to register a store" do
- visit store_registration_path
-
- expect(URI.parse(current_url).path).to eq registration_auth_path
-
- page.has_selector? "dd", text: "Log in"
- switch_to_login_tab
-
- # Enter Login details
- fill_in "Email", with: user.email
- fill_in "Password", with: user.password
- click_login_and_ensure_content "This wizard will step you through creating a profile"
-
- expect(URI.parse(current_url).path).to eq store_registration_path
-
- # Done reading introduction
- click_button_and_ensure_content "Let's get started!", "Woot! First we need to know the name of your farm:"
-
- # Details Page
- expect(page).to have_content "Woot! First we need to know the name of your farm:"
- expect(page).to_not have_selector '#enterprise-types'
-
- # Everything from here should be covered in 'profile' spec
- end
end
def switch_to_login_tab
diff --git a/spec/features/consumer/shopping/shopping_spec.rb b/spec/features/consumer/shopping/shopping_spec.rb
index 56c578f91b..d4db6bff29 100644
--- a/spec/features/consumer/shopping/shopping_spec.rb
+++ b/spec/features/consumer/shopping/shopping_spec.rb
@@ -167,7 +167,7 @@ feature "As a consumer I want to shop with a distributor", js: true do
visit shop_path
end
- it "should save group buy data to ze cart" do
+ it "should save group buy data to the cart" do
fill_in "variants[#{variant.id}]", with: 6
fill_in "variant_attributes[#{variant.id}][max_quantity]", with: 7
page.should have_in_cart product.name
diff --git a/spec/javascripts/unit/darkswarm/filters/filter_hubs_spec.js.coffee b/spec/javascripts/unit/darkswarm/filters/filter_hubs_spec.js.coffee
deleted file mode 100644
index fc2702a72b..0000000000
--- a/spec/javascripts/unit/darkswarm/filters/filter_hubs_spec.js.coffee
+++ /dev/null
@@ -1,45 +0,0 @@
-describe 'filtering Hubs', ->
- filter = null
- filterHubs = null
- hubs = [{
- name: "frogs"
- other: "roger"
- address:
- zipcode: "cats"
- city: "cambridge"
- state: "kansas"
- }, {
- name: "donkeys"
- other: "roger"
- address:
- zipcode: ""
- city: "Wellington"
- state: "uzbekistan"
- }]
-
- beforeEach ->
- module 'Darkswarm'
- inject ($filter) ->
- filter = $filter
- filterHubs = $filter('hubs')
-
- it 'has a hub filter', ->
- expect(filter('hubs')).not.toBeNull()
-
- it "filters by name", ->
- expect(filterHubs(hubs, 'donkeys').length).toEqual 1
-
- it "is case insensitive", ->
- expect(filterHubs(hubs, 'DONKEYS').length).toEqual 1
-
- it "filters by state", ->
- expect(filterHubs(hubs, 'kansas').length).toEqual 1
-
- it "filters by zipcode", ->
- expect(filterHubs(hubs, 'cats').length).toEqual 1
-
- it "gives all hubs when no argument is specified", ->
- expect(filterHubs(hubs, '').length).toEqual 2
-
- it "does not filter by anything else", ->
- expect(filterHubs(hubs, 'roger').length).toEqual 0
diff --git a/spec/javascripts/unit/darkswarm/filters/filter_producers_spec.js.coffee b/spec/javascripts/unit/darkswarm/filters/filter_producers_spec.js.coffee
deleted file mode 100644
index 29d8986b56..0000000000
--- a/spec/javascripts/unit/darkswarm/filters/filter_producers_spec.js.coffee
+++ /dev/null
@@ -1,28 +0,0 @@
-describe 'filtering producers', ->
- filter = null
- filterProducers = null
- producers = [{
- name: "frogs"
- other: "roger"
- address:
- zipcode: "cats"
- city: "cambridge"
- state: "kansas"
- }, {
- name: "donkeys"
- other: "roger"
- address:
- zipcode: ""
- city: "Wellington"
- state: "uzbekistan"
- }]
-
- beforeEach ->
- module 'Darkswarm'
- inject ($filter) ->
- filter = $filter
- filterProducers = $filter('filterProducers')
-
-
- it 'has a producer filter', ->
- expect(filter('filterProducers')).not.toBeNull()
diff --git a/spec/javascripts/unit/darkswarm/filters/search_enterprises_spec.js.coffee b/spec/javascripts/unit/darkswarm/filters/search_enterprises_spec.js.coffee
new file mode 100644
index 0000000000..2717e50cfb
--- /dev/null
+++ b/spec/javascripts/unit/darkswarm/filters/search_enterprises_spec.js.coffee
@@ -0,0 +1,40 @@
+describe 'filtering Enterprises', ->
+ filter = null
+ enterprises = [{
+ name: "frogs"
+ other: "roger"
+ address:
+ zipcode: "cats"
+ city: "cambridge"
+ state: "kansas"
+ }, {
+ name: "donkeys"
+ other: "roger"
+ address:
+ zipcode: ""
+ city: "Wellington"
+ state: "uzbekistan"
+ }]
+
+ beforeEach ->
+ module 'Darkswarm'
+ inject ($filter) ->
+ filter = $filter('searchEnterprises')
+
+ it "filters by name", ->
+ expect(filter(enterprises, 'donkeys').length).toEqual 1
+
+ it "is case insensitive", ->
+ expect(filter(enterprises, 'DONKEYS').length).toEqual 1
+
+ it "filters by state", ->
+ expect(filter(enterprises, 'kansas').length).toEqual 1
+
+ it "filters by zipcode", ->
+ expect(filter(enterprises, 'cats').length).toEqual 1
+
+ it "gives all enterprises when no argument is specified", ->
+ expect(filter(enterprises, '').length).toEqual 2
+
+ it "does not filter by anything else", ->
+ expect(filter(enterprises, 'roger').length).toEqual 0
diff --git a/spec/javascripts/unit/darkswarm/services/enterprise_spec.js.coffee b/spec/javascripts/unit/darkswarm/services/enterprise_spec.js.coffee
index 59d4ae9826..94dd7d39d2 100644
--- a/spec/javascripts/unit/darkswarm/services/enterprise_spec.js.coffee
+++ b/spec/javascripts/unit/darkswarm/services/enterprise_spec.js.coffee
@@ -1,24 +1,30 @@
describe "Enterprises service", ->
Enterprises = null
- CurrentHubMock = {}
+ CurrentHubMock = {}
taxons = [
{id: 1, name: "test"}
]
enterprises = [
- {id: 1, type: "hub", producers: [{id: 2}], taxons: [{id: 1}]},
- {id: 2, type: "producer", hubs: [{id: 1}]},
- {id: 3, type: "producer", hubs: [{id: 1}]}
+ {id: 1, visible: true, category: "hub", producers: [{id: 5}], taxons: [{id: 1}]},
+ {id: 2, visible: true, category: "hub", producers: [{id: 6}]}
+ {id: 3, visible: true, category: "hub_profile"}
+ {id: 4, visible: false, category: "hub", producers: [{id: 7}]}
+ {id: 5, visible: true, category: "producer_hub", hubs: [{id: 1}]},
+ {id: 6, visible: true, category: "producer_shop", hubs: [{id: 2}]},
+ {id: 7, visible: true, category: "producer", hubs: [{id: 2}]}
+ {id: 8, visible: false, category: "producer", hubs: [{id: 2}]}
]
+ H1: 0
beforeEach ->
module 'Darkswarm'
module ($provide)->
- $provide.value "CurrentHub", CurrentHubMock
+ $provide.value "CurrentHub", CurrentHubMock
null
- angular.module('Darkswarm').value('enterprises', enterprises)
- angular.module('Darkswarm').value('taxons', taxons)
+ angular.module('Darkswarm').value('enterprises', enterprises)
+ angular.module('Darkswarm').value('taxons', taxons)
inject ($injector)->
- Enterprises = $injector.get("Enterprises")
+ Enterprises = $injector.get("Enterprises")
it "stores enterprises as id/object pairs", ->
expect(Enterprises.enterprises_by_id["1"]).toBe enterprises[0]
@@ -31,8 +37,39 @@ describe "Enterprises service", ->
expect(Enterprises.enterprises[0]).toBe Enterprises.enterprises_by_id["1"]
it "dereferences references to other enterprises", ->
- expect(Enterprises.enterprises_by_id["1"].producers[0]).toBe enterprises[1]
- expect(Enterprises.enterprises_by_id["3"].hubs[0]).toBe enterprises[0]
+ expect(Enterprises.enterprises_by_id["1"].producers[0]).toBe enterprises[4]
+ expect(Enterprises.enterprises_by_id["5"].hubs[0]).toBe enterprises[0]
it "dereferences taxons", ->
expect(Enterprises.enterprises[0].taxons[0]).toBe taxons[0]
+
+ it "filters Enterprise.hubs into a new array", ->
+ expect(Enterprises.hubs[0]).toBe Enterprises.enterprises[0]
+ # Because the $filter is a new sorted array
+ # We check to see the objects in both arrays are still the same
+ Enterprises.enterprises[0].active = false
+ expect(Enterprises.hubs[0].active).toBe false
+
+ it "filters Enterprises.producers into a new array", ->
+ expect(Enterprises.producers[0]).toBe Enterprises.enterprises[4]
+ Enterprises.enterprises[4].active = false
+ expect(Enterprises.producers[0].active).toBe false
+
+ it "only includes visible enterprises in hubs array", ->
+ expect(Enterprises.hubs).toContain Enterprises.enterprises[0]
+ expect(Enterprises.hubs).not.toContain Enterprises.enterprises[3]
+
+ it "only includes visible enterprises in producers array", ->
+ expect(Enterprises.producers).toContain Enterprises.enterprises[4]
+ expect(Enterprises.producers).not.toContain Enterprises.enterprises[7]
+
+ it "includes hub, hub_profile, producer_hub and, producer_shop enterprises in hubs array", ->
+ expect(Enterprises.hubs).toContain Enterprises.enterprises[0]
+ expect(Enterprises.hubs).toContain Enterprises.enterprises[2]
+ expect(Enterprises.hubs).toContain Enterprises.enterprises[4]
+ expect(Enterprises.hubs).toContain Enterprises.enterprises[5]
+
+ it "includes producer_hub, producer_shop and producer enterprises in producers array", ->
+ expect(Enterprises.producers).toContain Enterprises.enterprises[4]
+ expect(Enterprises.producers).toContain Enterprises.enterprises[5]
+ expect(Enterprises.producers).toContain Enterprises.enterprises[6]
diff --git a/spec/javascripts/unit/darkswarm/services/hubs_spec.js.coffee b/spec/javascripts/unit/darkswarm/services/hubs_spec.js.coffee
deleted file mode 100644
index f2620da65b..0000000000
--- a/spec/javascripts/unit/darkswarm/services/hubs_spec.js.coffee
+++ /dev/null
@@ -1,45 +0,0 @@
-describe "Hubs service", ->
- Hubs = null
- Enterprises = null
- CurrentHubMock = {}
- hubs = [
- {
- id: 2
- active: false
- orders_close_at: new Date()
- is_distributor: true
- has_hub_listing: true
- }
- {
- id: 3
- active: false
- orders_close_at: new Date()
- is_distributor: true
- has_hub_listing: true
- }
- {
- id: 1
- active: true
- orders_close_at: new Date()
- is_distributor: true
- has_hub_listing: true
- }
- ]
-
-
- beforeEach ->
- module 'Darkswarm'
- angular.module('Darkswarm').value('enterprises', hubs)
- module ($provide)->
- $provide.value "CurrentHub", CurrentHubMock
- null
- inject ($injector)->
- Enterprises = $injector.get("Enterprises")
- Hubs = $injector.get("Hubs")
-
- it "filters Enterprise.hubs into a new array", ->
- expect(Hubs.hubs[0]).toBe Enterprises.enterprises[2]
- # Because the $filter is a new sorted array
- # We check to see the objects in both arrays are still the same
- Enterprises.enterprises[2].active = false
- expect(Hubs.hubs[0].active).toBe false
diff --git a/spec/javascripts/unit/darkswarm/services/producers_spec.js.coffee b/spec/javascripts/unit/darkswarm/services/producers_spec.js.coffee
deleted file mode 100644
index dc9ac0fc8f..0000000000
--- a/spec/javascripts/unit/darkswarm/services/producers_spec.js.coffee
+++ /dev/null
@@ -1,21 +0,0 @@
-describe "Producers service", ->
- Producers = null
- Enterprises = null
- CurrentHubMock =
- hub:
- id: 1
- enterprises = [
- {is_primary_producer: true}
- ]
-
- beforeEach ->
- module 'Darkswarm'
- module ($provide)->
- $provide.value "CurrentHub", CurrentHubMock
- null
- angular.module('Darkswarm').value('enterprises', enterprises)
- inject ($injector)->
- Producers = $injector.get("Producers")
-
- it "delegates producers array to Enterprises", ->
- expect(Producers.producers[0]).toBe enterprises[0]
diff --git a/spec/mailers/enterprise_mailer_spec.rb b/spec/mailers/enterprise_mailer_spec.rb
index 412870bad7..dd1e150eb7 100644
--- a/spec/mailers/enterprise_mailer_spec.rb
+++ b/spec/mailers/enterprise_mailer_spec.rb
@@ -1,13 +1,16 @@
require 'spec_helper'
describe EnterpriseMailer do
+ let!(:enterprise) { create(:enterprise) }
+
before do
- @enterprise = create(:enterprise)
ActionMailer::Base.deliveries = []
end
- it "should send an email when given an enterprise" do
- EnterpriseMailer.creation_confirmation(@enterprise).deliver
+ it "should send an email confirmation when given an enterprise" do
+ EnterpriseMailer.confirmation_instructions(enterprise, 'token').deliver
ActionMailer::Base.deliveries.count.should == 1
+ mail = ActionMailer::Base.deliveries.first
+ expect(mail.subject).to eq "Please confirm your email for #{enterprise.name}"
end
end
\ No newline at end of file
diff --git a/spec/models/enterprise_spec.rb b/spec/models/enterprise_spec.rb
index 241d1fafc7..206be1e131 100644
--- a/spec/models/enterprise_spec.rb
+++ b/spec/models/enterprise_spec.rb
@@ -3,6 +3,25 @@ require 'spec_helper'
describe Enterprise do
include AuthenticationWorkflow
+ describe "sending emails" do
+ describe "on creation" do
+ let!(:user) { create_enterprise_user( enterprise_limit: 2 ) }
+ let!(:enterprise) { create(:enterprise, owner: user) }
+
+ it "when the email address has not already been confirmed" do
+ mail_message = double "Mail::Message"
+ EnterpriseMailer.should_receive(:confirmation_instructions).and_return mail_message
+ mail_message.should_receive :deliver
+ create(:enterprise, owner: user, email: "unknown@email.com", confirmed_at: nil )
+ end
+
+ it "when the email address has already been confirmed" do
+ EnterpriseMailer.should_not_receive(:confirmation_instructions)
+ e = create(:enterprise, owner: user, email: enterprise.email, confirmed_at: nil)
+ end
+ end
+ end
+
describe "associations" do
it { should belong_to(:owner) }
it { should have_many(:supplied_products) }
@@ -86,6 +105,7 @@ describe Enterprise do
subject { FactoryGirl.create(:distributor_enterprise, :address => FactoryGirl.create(:address)) }
it { should validate_presence_of(:name) }
it { should validate_presence_of(:email) }
+ it { should ensure_length_of(:description).is_at_most(255) }
it "requires an owner" do
expect{
@@ -102,6 +122,7 @@ describe Enterprise do
it { should delegate(:city).to(:address) }
it { should delegate(:state_name).to(:address) }
end
+
describe "scopes" do
describe 'active' do
it 'find active enterprises' do
@@ -111,6 +132,28 @@ describe Enterprise do
end
end
+ describe "confirmed" do
+ it "find enterprises with a confirmed date" do
+ s1 = create(:supplier_enterprise)
+ d1 = create(:distributor_enterprise)
+ s2 = create(:supplier_enterprise, confirmed_at: nil)
+ d2 = create(:distributor_enterprise, confirmed_at: nil)
+ expect(Enterprise.confirmed).to include s1, d1
+ expect(Enterprise.confirmed).to_not include s2, d2
+ end
+ end
+
+ describe "unconfirmed" do
+ it "find enterprises without a confirmed date" do
+ s1 = create(:supplier_enterprise)
+ d1 = create(:distributor_enterprise)
+ s2 = create(:supplier_enterprise, confirmed_at: nil)
+ d2 = create(:distributor_enterprise, confirmed_at: nil)
+ expect(Enterprise.unconfirmed).to_not include s1, d1
+ expect(Enterprise.unconfirmed).to include s2, d2
+ end
+ end
+
describe "distributors_with_active_order_cycles" do
it "finds active distributors by order cycles" do
s = create(:supplier_enterprise)
@@ -503,64 +546,24 @@ describe Enterprise do
end
end
- pending "provide enterprise category" do
-
- # Swap type values full > sell_all, single > sell_own profile > sell_none
- # swap is_distributor for new can_supply flag.
- let(:producer_sell_all_can_supply) {
- create(:enterprise, is_primary_producer: true, type: "full", is_distributor: true)
- }
- let(:producer_sell_all_cant_supply) {
- create(:enterprise, is_primary_producer: true, type: "full", is_distributor: false)
- }
- let(:producer_sell_own_can_supply) {
- create(:enterprise, is_primary_producer: true, type: "single", is_distributor: true)
- }
- let(:producer_sell_own_cant_supply) {
- create(:enterprise, is_primary_producer: true, type: "single", is_distributor: false)
- }
- let(:producer_sell_none_can_supply) {
- create(:enterprise, is_primary_producer: true, type: "profile", is_distributor: true)
- }
- let(:producer_sell_none_cant_supply) {
- create(:enterprise, is_primary_producer: true, type: "profile", is_distributor: false)
- }
- let(:non_producer_sell_all_can_supply) {
- create(:enterprise, is_primary_producer: true, type: "full", is_distributor: true)
- }
- let(:non_producer_sell_all_cant_supply) {
- create(:enterprise, is_primary_producer: true, type: "full", is_distributor: false)
- }
- let(:non_producer_sell_own_can_supply) {
- create(:enterprise, is_primary_producer: true, type: "single", is_distributor: true)
- }
- let(:non_producer_sell_own_cant_supply) {
- create(:enterprise, is_primary_producer: true, type: "single", is_distributor: false)
- }
- let(:non_producer_sell_none_can_supply) {
- create(:enterprise, is_primary_producer: false, type: "profile", is_distributor: true)
- }
- let(:non_producer_sell_none_cant_supply) {
- create(:enterprise, is_primary_producer: false, type: "profile", is_distributor: false)
- }
+ describe "provide enterprise category" do
+ let(:producer_sell_all) { build(:enterprise, is_primary_producer: true, sells: "any") }
+ let(:producer_sell_own) { build(:enterprise, is_primary_producer: true, sells: "own") }
+ let(:producer_sell_none) { build(:enterprise, is_primary_producer: true, sells: "none") }
+ let(:non_producer_sell_all) { build(:enterprise, is_primary_producer: false, sells: "any") }
+ let(:non_producer_sell_own) { build(:enterprise, is_primary_producer: false, sells: "own") }
+ let(:non_producer_sell_none) { build(:enterprise, is_primary_producer: false, sells: "none") }
it "should output enterprise categories" do
- producer_sell_all_can_supply.is_primary_producer.should == true
- producer_sell_all_can_supply.supplies.should == true
- producer_sell_all_can_supply.type.should == "full"
+ producer_sell_all.is_primary_producer.should == true
+ producer_sell_all.sells.should == "any"
- producer_sell_all_can_supply.enterprise_category.should == "producer_hub"
- producer_sell_all_cant_supply.enterprise_category.should == "producer_hub"
- producer_sell_own_can_supply.enterprise_category.should == "producer_shop"
- producer_sell_own_cant_supply.enterprise_category.should == "producer_shop"
- producer_sell_none_can_supply.enterprise_category.should == "producer"
- producer_sell_none_cant_supply.enterprise_category.should == "producer_profile"
- non_producer_sell_all_can_supply.enterprise_category.should == "hub"
- non_producer_sell_all_cant_supply.enterprise_category.should == "hub"
- non_producer_sell_own_can_supply.enterprise_category.should == "hub"
- non_producer_sell_own_cant_supply.enterprise_category.should == "hub"
- non_producer_sell_none_can_supply.enterprise_category.should == "hub_profile"
- non_producer_sell_none_cant_supply.enterprise_category.should == "hub_profile"
+ producer_sell_all.category.should == :producer_hub
+ producer_sell_own.category.should == :producer_shop
+ producer_sell_none.category.should == :producer
+ non_producer_sell_all.category.should == :hub
+ non_producer_sell_own.category.should == :hub
+ non_producer_sell_none.category.should == :hub_profile
end
end
end
diff --git a/spec/models/order_cycle_spec.rb b/spec/models/order_cycle_spec.rb
index 9785d5ed2d..56aa51a0d0 100644
--- a/spec/models/order_cycle_spec.rb
+++ b/spec/models/order_cycle_spec.rb
@@ -44,8 +44,8 @@ describe OrderCycle do
end
it "finds order cycles accessible by a user" do
- e1 = create(:enterprise, is_primary_producer: true, is_distributor: true)
- e2 = create(:enterprise, is_primary_producer: true, is_distributor: true)
+ e1 = create(:enterprise, is_primary_producer: true, sells: "any")
+ e2 = create(:enterprise, is_primary_producer: true, sells: "any")
user = create(:user, enterprises: [e2], spree_roles: [])
user.spree_roles = []
diff --git a/spec/models/spree/ability_spec.rb b/spec/models/spree/ability_spec.rb
index 2d2d1cfb01..e523cce755 100644
--- a/spec/models/spree/ability_spec.rb
+++ b/spec/models/spree/ability_spec.rb
@@ -9,13 +9,46 @@ module Spree
describe "broad permissions" do
subject { AbilityDecorator.new(user) }
let(:user) { create(:user) }
- let(:enterprise_full) { create(:enterprise, type: 'full') }
- let(:enterprise_single) { create(:enterprise, type: 'single') }
- let(:enterprise_profile) { create(:enterprise, type: 'profile') }
+ let(:enterprise_any) { create(:enterprise, sells: 'any') }
+ let(:enterprise_own) { create(:enterprise, sells: 'own') }
+ let(:enterprise_none) { create(:enterprise, sells: 'none') }
+ let(:enterprise_any_producer) { create(:enterprise, sells: 'any', is_primary_producer: true) }
+ let(:enterprise_own_producer) { create(:enterprise, sells: 'own', is_primary_producer: true) }
+ let(:enterprise_none_producer) { create(:enterprise, sells: 'none', is_primary_producer: true) }
- context "as manager of a 'full' type enterprise" do
+ context "as manager of an enterprise who sells 'any'" do
before do
- user.enterprise_roles.create! enterprise: enterprise_full
+ user.enterprise_roles.create! enterprise: enterprise_any
+ end
+
+ it { subject.can_manage_products?(user).should be_false }
+ it { subject.can_manage_enterprises?(user).should be_true }
+ it { subject.can_manage_orders?(user).should be_true }
+ end
+
+ context "as manager of an enterprise who sell 'own'" do
+ before do
+ user.enterprise_roles.create! enterprise: enterprise_own
+ end
+
+ it { subject.can_manage_products?(user).should be_false }
+ it { subject.can_manage_enterprises?(user).should be_true }
+ it { subject.can_manage_orders?(user).should be_true }
+ end
+
+ context "as manager of an enterprise who sells 'none'" do
+ before do
+ user.enterprise_roles.create! enterprise: enterprise_none
+ end
+
+ it { subject.can_manage_products?(user).should be_false }
+ it { subject.can_manage_enterprises?(user).should be_true }
+ it { subject.can_manage_orders?(user).should be_false }
+ end
+
+ context "as manager of a producer enterprise who sells 'any'" do
+ before do
+ user.enterprise_roles.create! enterprise: enterprise_any_producer
end
it { subject.can_manage_products?(user).should be_true }
@@ -23,9 +56,9 @@ module Spree
it { subject.can_manage_orders?(user).should be_true }
end
- context "as manager of a 'single' type enterprise" do
+ context "as manager of a producer enterprise who sell 'own'" do
before do
- user.enterprise_roles.create! enterprise: enterprise_single
+ user.enterprise_roles.create! enterprise: enterprise_own_producer
end
it { subject.can_manage_products?(user).should be_true }
@@ -33,9 +66,9 @@ module Spree
it { subject.can_manage_orders?(user).should be_true }
end
- context "as manager of a 'profile' type enterprise" do
+ context "as manager of a producer enterprise who sells 'none'" do
before do
- user.enterprise_roles.create! enterprise: enterprise_profile
+ user.enterprise_roles.create! enterprise: enterprise_none_producer
end
it { subject.can_manage_products?(user).should be_true }
@@ -151,6 +184,14 @@ module Spree
should_not have_ability(:destroy, for: er2)
end
+ it "should be able to read some reports" do
+ should have_ability([:admin, :index, :customers, :bulk_coop, :orders_and_fulfillment, :products_and_inventory], for: :report)
+ end
+
+ it "should not be able to read other reports" do
+ should_not have_ability([:sales_total, :group_buys, :payments, :orders_and_distributors], for: :report)
+ end
+
end
context "when is a distributor enterprise user" do
@@ -237,17 +278,26 @@ module Spree
it "should not be able to destroy enterprise relationships for other enterprises" do
should_not have_ability(:destroy, for: er1)
end
+
+ it "should be able to read some reports" do
+ should have_ability([:admin, :index, :customers, :group_buys, :bulk_coop, :payments, :orders_and_distributors, :orders_and_fulfillment, :products_and_inventory], for: :report)
+ end
+
+ it "should not be able to read other reports" do
+ should_not have_ability([:sales_total], for: :report)
+ end
+
end
- context 'Order Cycle co-ordinator' do
-
+ context 'Order Cycle co-ordinator, distributor enterprise manager' do
let (:user) do
user = create(:user)
user.spree_roles = []
- s1.enterprise_roles.build(user: user).save
+ d1.enterprise_roles.build(user: user).save
user
end
- let(:oc1) { create(:simple_order_cycle, {coordinator: s1}) }
+
+ let(:oc1) { create(:simple_order_cycle, {coordinator: d1}) }
let(:oc2) { create(:simple_order_cycle) }
it "should be able to read/write OrderCycles they are the co-ordinator of" do
@@ -265,6 +315,10 @@ module Spree
it "should be able to read/write EnterpriseFees" do
should have_ability([:admin, :index, :read, :create, :edit, :bulk_update, :destroy], for: EnterpriseFee)
end
+
+ it "should be able to add enterprises to order cycles" do
+ should have_ability([:admin, :index, :for_order_cycle, :create], for: Enterprise)
+ end
end
context 'enterprise manager' do
@@ -284,7 +338,7 @@ module Spree
end
it 'should have the ability administrate and create enterpises' do
- should have_ability([:admin, :index, :for_order_cycle, :create], for: Enterprise)
+ should have_ability([:admin, :index, :create], for: Enterprise)
end
end
end
diff --git a/spec/models/spree/image_spec.rb b/spec/models/spree/image_spec.rb
new file mode 100644
index 0000000000..56665fa641
--- /dev/null
+++ b/spec/models/spree/image_spec.rb
@@ -0,0 +1,18 @@
+require 'spec_helper'
+
+module Spree
+ describe Image do
+ describe "attachment definitions" do
+ let(:name_str) { {"mini" => "48x48>"} }
+ let(:formatted) { {mini: ["48x48>", "png"]} }
+
+ it "converts style names to symbols" do
+ Image.format_styles(name_str).should == {:mini => "48x48>"}
+ end
+
+ it "converts formats to symbols" do
+ Image.format_styles(formatted).should == {:mini => ["48x48>", :png]}
+ end
+ end
+ end
+end
diff --git a/spec/serializers/enterprise_serializer_spec.rb b/spec/serializers/enterprise_serializer_spec.rb
index 5fe57a99e2..f3409f2d57 100644
--- a/spec/serializers/enterprise_serializer_spec.rb
+++ b/spec/serializers/enterprise_serializer_spec.rb
@@ -13,9 +13,27 @@ describe Api::EnterpriseSerializer do
serializer = Api::EnterpriseSerializer.new enterprise
serializer.to_json.should match taxon.id.to_s
end
-
+
it "will render urls" do
serializer = Api::EnterpriseSerializer.new enterprise
serializer.to_json.should match "map_005-hub.svg"
end
+
+ describe "visibility" do
+ before do
+ enterprise.stub(:visible).and_return true
+ end
+
+ it "is visible when confirmed" do
+ enterprise.stub(:confirmed?).and_return true
+ serializer = Api::EnterpriseSerializer.new enterprise
+ expect(serializer.to_json).to match "\"visible\":true"
+ end
+
+ it "is not visible when unconfirmed" do
+ enterprise.stub(:confirmed?).and_return false
+ serializer = Api::EnterpriseSerializer.new enterprise
+ expect(serializer.to_json).to match "\"visible\":false"
+ end
+ end
end