diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index 7b394140d5..ec1a08947e 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -13,21 +13,11 @@ Provide context for others to understand it. -->
#### Release notes
-
+
-
-
-
-
-Changelog Category: Added | Changed | Deprecated | Removed | Fixed | Security
-
-
-
-#### Discourse thread
-
+
+Changelog Category: User facing changes | Technical changes
diff --git a/.rubocop_manual_todo.yml b/.rubocop_manual_todo.yml
index a919e0dedc..dba500e10f 100644
--- a/.rubocop_manual_todo.yml
+++ b/.rubocop_manual_todo.yml
@@ -167,7 +167,6 @@ Layout/LineLength:
- spec/features/admin/enterprises/index_spec.rb
- spec/features/admin/enterprises_spec.rb
- spec/features/admin/enterprise_user_spec.rb
- - spec/features/admin/image_settings_spec.rb
- spec/features/admin/multilingual_spec.rb
- spec/features/admin/order_cycles/complex_creating_specific_time_spec.rb
- spec/features/admin/order_cycles/complex_editing_multiple_product_pages_spec.rb
@@ -345,7 +344,6 @@ Metrics/AbcSize:
- app/controllers/cart_controller.rb
- app/controllers/discourse_sso_controller.rb
- app/controllers/enterprises_controller.rb
- - app/controllers/spree/admin/image_settings_controller.rb
- app/controllers/spree/admin/orders_controller.rb
- app/controllers/spree/admin/orders/customer_details_controller.rb
- app/controllers/spree/admin/overview_controller.rb
@@ -665,7 +663,6 @@ Metrics/MethodLength:
- app/controllers/api/variants_controller.rb
- app/controllers/cart_controller.rb
- app/controllers/shop_controller.rb
- - app/controllers/spree/admin/image_settings_controller.rb
- app/controllers/spree/admin/orders_controller.rb
- app/controllers/spree/admin/orders/customer_details_controller.rb
- app/controllers/spree/admin/payment_methods_controller.rb
@@ -814,42 +811,17 @@ Metrics/ModuleLength:
- app/helpers/spree/admin/navigation_helper.rb
- app/models/spree/order/checkout.rb
- app/models/spree/payment/processing.rb
- - engines/catalog/spec/services/catalog/product_import/products_reset_strategy_spec.rb
- - engines/order_management/spec/services/order_management/order/updater_spec.rb
- - engines/order_management/spec/services/order_management/stock/package_spec.rb
- - engines/order_management/spec/services/order_management/subscriptions/estimator_spec.rb
- - engines/order_management/spec/services/order_management/subscriptions/form_spec.rb
- engines/order_management/spec/services/order_management/subscriptions/proxy_order_syncer_spec.rb
- - engines/order_management/spec/services/order_management/subscriptions/summarizer_spec.rb
- engines/order_management/spec/services/order_management/subscriptions/validator_spec.rb
- - engines/order_management/spec/services/order_management/subscriptions/variants_list_spec.rb
- lib/open_food_network/column_preference_defaults.rb
- spec/controllers/admin/order_cycles_controller_spec.rb
- - spec/controllers/api/order_cycles_controller_spec.rb
- spec/controllers/api/orders_controller_spec.rb
- - spec/controllers/spree/admin/payment_methods_controller_spec.rb
- - spec/lib/open_food_network/address_finder_spec.rb
- - spec/lib/open_food_network/customers_report_spec.rb
- - spec/lib/open_food_network/enterprise_fee_calculator_spec.rb
- - spec/lib/open_food_network/order_cycle_form_applicator_spec.rb
- spec/lib/open_food_network/order_cycle_permissions_spec.rb
- - spec/lib/open_food_network/order_grouper_spec.rb
- - spec/lib/open_food_network/packing_report_spec.rb
- - spec/lib/open_food_network/permissions_spec.rb
- - spec/lib/open_food_network/products_and_inventory_report_spec.rb
- - spec/lib/open_food_network/scope_variant_to_hub_spec.rb
- - spec/lib/open_food_network/tag_rule_applicator_spec.rb
- - spec/lib/open_food_network/user_balance_calculator_spec.rb
- - spec/lib/open_food_network/users_and_enterprises_report_spec.rb
- spec/models/spree/adjustment_spec.rb
- spec/models/spree/credit_card_spec.rb
- spec/models/spree/line_item_spec.rb
- spec/models/spree/product_spec.rb
- - spec/models/spree/shipping_method_spec.rb
- spec/models/spree/variant_spec.rb
- - spec/services/permissions/order_spec.rb
- - spec/services/variant_units/option_value_namer_spec.rb
- - spec/support/request/stripe_helper.rb
Metrics/ParameterLists:
Max: 5
diff --git a/.rubocop_specs.yml b/.rubocop_specs.yml
new file mode 100644
index 0000000000..8ea54cd55c
--- /dev/null
+++ b/.rubocop_specs.yml
@@ -0,0 +1,7 @@
+inherit_from:
+ - .rubocop.yml
+
+# This rubocop config file is only used for specs
+# Here we allow specs to be 300 lines long
+Metrics/ModuleLength:
+ Max: 300
diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml
index 2c867c2ec1..93648258a3 100644
--- a/.rubocop_todo.yml
+++ b/.rubocop_todo.yml
@@ -691,7 +691,6 @@ Style/FrozenStringLiteralComment:
- 'app/controllers/spree/admin/base_controller.rb'
- 'app/controllers/spree/admin/countries_controller.rb'
- 'app/controllers/spree/admin/general_settings_controller.rb'
- - 'app/controllers/spree/admin/image_settings_controller.rb'
- 'app/controllers/spree/admin/images_controller.rb'
- 'app/controllers/spree/admin/invoices_controller.rb'
- 'app/controllers/spree/admin/mail_methods_controller.rb'
@@ -726,7 +725,6 @@ Style/FrozenStringLiteralComment:
- 'app/controllers/user_passwords_controller.rb'
- 'app/controllers/user_registrations_controller.rb'
- 'app/helpers/admin/enterprises_helper.rb'
- - 'app/helpers/admin/image_settings_helper.rb'
- 'app/helpers/admin/injection_helper.rb'
- 'app/helpers/admin/orders_helper.rb'
- 'app/helpers/admin/subscriptions_helper.rb'
@@ -1123,7 +1121,6 @@ Style/FrozenStringLiteralComment:
- 'spec/controllers/shops_controller_spec.rb'
- 'spec/controllers/spree/admin/adjustments_controller_spec.rb'
- 'spec/controllers/spree/admin/base_controller_spec.rb'
- - 'spec/controllers/spree/admin/image_settings_controller_spec.rb'
- 'spec/controllers/spree/admin/invoices_controller_spec.rb'
- 'spec/controllers/spree/admin/mail_methods_controller_spec.rb'
- 'spec/controllers/spree/admin/orders/customer_details_controller_spec.rb'
@@ -1168,7 +1165,6 @@ Style/FrozenStringLiteralComment:
- 'spec/features/admin/bulk_product_update_spec.rb'
- 'spec/features/admin/configuration/content_spec.rb'
- 'spec/features/admin/configuration/general_settings_spec.rb'
- - 'spec/features/admin/configuration/image_settings_spec.rb'
- 'spec/features/admin/configuration/mail_methods_spec.rb'
- 'spec/features/admin/configuration/states_spec.rb'
- 'spec/features/admin/configuration/tax_categories_spec.rb'
@@ -1184,7 +1180,6 @@ Style/FrozenStringLiteralComment:
- 'spec/features/admin/enterprises/index_spec.rb'
- 'spec/features/admin/enterprises_spec.rb'
- 'spec/features/admin/external_services_spec.rb'
- - 'spec/features/admin/image_settings_spec.rb'
- 'spec/features/admin/multilingual_spec.rb'
- 'spec/features/admin/overview_spec.rb'
- 'spec/features/admin/payment_method_spec.rb'
diff --git a/DOCKER.md b/DOCKER.md
deleted file mode 100644
index 15fa75df5a..0000000000
--- a/DOCKER.md
+++ /dev/null
@@ -1,65 +0,0 @@
-### Docker
-
-It is possible to setup the Open Food Network app easily with Docker and Docker Compose.
-The objective is to spare configuration time, in order to help people testing the app and contribute to it.
-It can also be used as documentation. It is not perfect but it is used in many other projects and many devs are used to it nowadays.
-
-### Install Docker
-
-Please check the documentation here, https://docs.docker.com/install/ to install Docker.
-
-For Docker Compose, information are here: https://docs.docker.com/compose/install/.
-
-Better to have at least 2GB free on your computer in order to download images and create containers for Open Food Network app.
-
-
-### Use Docker with Open Food Network
-
-Open a terminal with a shell.
-
-Clone the repository. If you're planning on contributing code to the project (which we [LOVE](CONTRIBUTING.md)), it is a good idea to begin by forking this repo using the Fork button in the top-right corner of this screen. You should then be able to use git clone to copy your fork onto your local machine.
-
-```sh
-$ git clone https://github.com/YOUR_GITHUB_USERNAME_HERE/openfoodnetwork
-```
-
-Otherwise, if you just want to get things running, clone from the OFN main repo:
-
-```sh
-$ git clone git@github.com:openfoodfoundation/openfoodnetwork.git
-```
-
-Go at the root of the app:
-
-```sh
-$ cd openfoodnetwork
-```
-
-Download the Docker images and build the containers:
-
-```sh
-$ docker-compose build
-```
-
-Setup the database and seed it with sample data:
-```sh
-$ docker-compose run web bundle exec rake db:reset
-$ docker-compose run web bundle exec rake db:test:prepare
-$ docker-compose run web bundle exec rake ofn:sample_data
-```
-
-Finally, run the app with all the required containers:
-
-```sh
-$ docker-compose up
-```
-
-The default admin user is 'ofn@example.com' with 'ofn123' password.
-Check the app in the browser at `http://localhost:3000`.
-
-You will then get the trace of the containers in the terminal. You can stop the containers using Ctrl-C in the terminal.
-
-You can find some useful tips and commands [here](https://github.com/openfoodfoundation/openfoodnetwork/wiki/Docker:-useful-tips-and-commands).
-
-### Troubleshooting
-If you are using Windows and having issues related to the ruby-build not finding a definition for the ruby version, you may need to follow these commands [here](https://stackoverflow.com/questions/2517190/how-do-i-force-git-to-use-lf-instead-of-crlf-under-windows/33424884#33424884) to fix your local git config related to line breaks.
diff --git a/Dockerfile b/Dockerfile
index d45df4780a..d5fe7270ac 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -27,8 +27,11 @@ RUN sh -c "echo 'deb https://apt.postgresql.org/pub/repos/apt/ bionic-pgdg main'
apt-get update && \
apt-get install -yqq --no-install-recommends postgresql-client-9.5 libpq-dev
-# Install node
-RUN apt-get install -y nodejs
+# Install node & yarn
+RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - && \
+ echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list && \
+ apt-get update && \
+ apt-get install -y nodejs yarn
# Install Chrome
RUN wget --quiet -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - && \
@@ -43,5 +46,9 @@ RUN wget https://chromedriver.storage.googleapis.com/2.41/chromedriver_linux64.z
# Copy code and install app dependencies
COPY . /usr/src/app/
+
+# Install front-end dependencies
+RUN yarn install
+
# Run bundler install in parallel with the amount of available CPUs
RUN bundle install --jobs="$(nproc)"
diff --git a/Gemfile b/Gemfile
index 95db8c699a..38e15fb73e 100644
--- a/Gemfile
+++ b/Gemfile
@@ -3,7 +3,7 @@ ruby "2.3.7"
git_source(:github) { |repo_name| "https://github.com/#{repo_name}.git" }
gem 'i18n', '~> 0.6.11'
-gem 'i18n-js', '~> 3.7.1'
+gem 'i18n-js', '~> 3.8.0'
gem 'rails', '~> 4.0.13'
gem 'rails-i18n', '~> 4.0'
gem 'rails_safe_tasks', '~> 1.0'
diff --git a/Gemfile.lock b/Gemfile.lock
index adda24eddd..83e30d89dc 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -109,7 +109,7 @@ GEM
activesupport (= 4.0.13)
arel (~> 4.0.0)
activerecord-deprecated_finders (1.0.4)
- activerecord-import (1.0.6)
+ activerecord-import (1.0.7)
activerecord (>= 3.2)
activerecord-postgresql-adapter (0.0.1)
pg
@@ -204,7 +204,7 @@ GEM
activerecord (>= 3.2.0, < 5.0)
fog (~> 1.0)
rails (>= 3.2.0, < 5.0)
- ddtrace (0.41.0)
+ ddtrace (0.42.0)
msgpack
debugger-linecache (1.2.0)
delayed_job (4.1.8)
@@ -421,7 +421,7 @@ GEM
mime-types (~> 3.0)
multi_xml (>= 0.5.2)
i18n (0.6.11)
- i18n-js (3.7.1)
+ i18n-js (3.8.0)
i18n (>= 0.6.6)
immigrant (0.3.6)
activerecord (>= 3.0)
@@ -685,7 +685,7 @@ GEM
nokogiri (~> 1.6)
rubyzip (>= 1.3.0)
selenium-webdriver (>= 3.0, < 4.0)
- webmock (3.9.2)
+ webmock (3.9.3)
addressable (>= 2.3.6)
crack (>= 0.3.2)
hashdiff (>= 0.4.0, < 2.0.0)
@@ -754,7 +754,7 @@ DEPENDENCIES
highline (= 1.6.18)
httparty (~> 0.18)
i18n (~> 0.6.11)
- i18n-js (~> 3.7.1)
+ i18n-js (~> 3.8.0)
immigrant
jquery-migrate-rails
jquery-rails (= 3.1.5)
diff --git a/app/assets/images/flag.svg b/app/assets/images/flag.svg
deleted file mode 100644
index bac244c981..0000000000
--- a/app/assets/images/flag.svg
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
diff --git a/app/assets/images/ofn-logo.png b/app/assets/images/ofn-logo.png
new file mode 100644
index 0000000000..6058b26a75
Binary files /dev/null and b/app/assets/images/ofn-logo.png differ
diff --git a/app/assets/javascripts/admin/all.js b/app/assets/javascripts/admin/all.js
index 212518b010..564c099ccd 100644
--- a/app/assets/javascripts/admin/all.js
+++ b/app/assets/javascripts/admin/all.js
@@ -27,14 +27,14 @@
//= require lodash.underscore.js
// spree
-//= require spree
+//= require admin/spree/spree
//= require admin/spree/spree-select2
//= require modernizr
//= require equalize
//= require css_browser_selector_dev
//= require responsive-tables
//= require admin/spree_paypal_express
-//= require admin/handlebar_extensions
+//= require handlebars
// OFN specific
//= require_tree ../templates/admin
diff --git a/app/assets/javascripts/admin/spree/base.js.erb b/app/assets/javascripts/admin/spree/base.js.erb
index 1ddd4a8dd3..79a8dfb6f8 100644
--- a/app/assets/javascripts/admin/spree/base.js.erb
+++ b/app/assets/javascripts/admin/spree/base.js.erb
@@ -116,7 +116,8 @@ $.fn.radioControlsVisibilityOfElement = function(dependentElementSelector){
}
$(document).ready(function() {
- if (typeof Spree !== 'undefined') {
+ if (typeof Spree !== 'undefined' &&
+ typeof Spree.translations !== 'undefined') {
handle_date_picker_fields = function(){
$('.datepicker').datepicker({
dateFormat: Spree.translations.date_picker,
diff --git a/app/assets/javascripts/admin/spree/image_settings.js.erb b/app/assets/javascripts/admin/spree/image_settings.js.erb
deleted file mode 100644
index d8c0b2a635..0000000000
--- a/app/assets/javascripts/admin/spree/image_settings.js.erb
+++ /dev/null
@@ -1,59 +0,0 @@
-$(document).ready(function() {
-
- if ($('input#preferences_use_s3[type="checkbox"]:checked').length > 0) {
- $('#s3_settings, #s3_headers').show();
- }
-
- // Toggle display of S3 settings based on value of use_s3 checkbox
- $('input#preferences_use_s3[type="checkbox"]').click(function() {
- $('#s3_settings, #s3_headers').toggle();
- });
-
- $(document).on('click', '.destroy_style', function(e) {
- e.preventDefault();
- $(this).parent().remove();
- });
-
- $(document).on('click', '.destroy_new_attachment_styles', function(e) {
- e.preventDefault();
- $(this).closest('.new_attachment_styles').remove();
- });
-
- $(document).on('click', '.destroy_new_s3_headers', function(e) {
- e.preventDefault();
- $(this).closest('.new_s3_headers').remove();
- });
-
- // Handle adding new styles
- var styles_hash_index = 1;
- $(document).on('click', '.add_new_style', function(e) {
- e.preventDefault();
- $('#new-styles').append(generate_html_for_hash("new_attachment_styles", styles_hash_index));
- });
-
- // Handle adding new headers
- var headers_hash_index = 1;
- $(document).on('click', '.add_header', function(e) {
- e.preventDefault();
- $('#headers_list').append(generate_html_for_hash("new_s3_headers", headers_hash_index));
- });
-
- // Generates html for new paperclip styles form fields
- generate_html_for_hash = function(hash_name, index) {
- var html = '
';
-
- index += 1;
- return html;
- };
-});
diff --git a/app/assets/javascripts/admin/spree/spree.js.coffee b/app/assets/javascripts/admin/spree/spree.js.coffee
new file mode 100644
index 0000000000..c905ff48e7
--- /dev/null
+++ b/app/assets/javascripts/admin/spree/spree.js.coffee
@@ -0,0 +1,13 @@
+#= require jsuri
+
+class window.Spree
+ # Helper function to take a URL and add query parameters to it
+ @url: (uri, query) ->
+ if uri.path == undefined
+ uri = new Uri(uri)
+ if query
+ $.each query, (key, value) ->
+ uri.addQueryParam(key, value)
+ if Spree.api_key
+ uri.addQueryParam('token', Spree.api_key)
+ return uri
diff --git a/app/assets/javascripts/darkswarm/controllers/products/product_node_controller.js.coffee b/app/assets/javascripts/darkswarm/controllers/products/product_node_controller.js.coffee
index fb8ac8d288..5a723fb8b1 100644
--- a/app/assets/javascripts/darkswarm/controllers/products/product_node_controller.js.coffee
+++ b/app/assets/javascripts/darkswarm/controllers/products/product_node_controller.js.coffee
@@ -1,6 +1,6 @@
Darkswarm.controller "ProductNodeCtrl", ($scope, $modal, FilterSelectorsService) ->
$scope.enterprise = $scope.product.supplier # For the modal, so it's consistent
+ $scope.productPropertySelectors = FilterSelectorsService.createSelectors()
$scope.triggerProductModal = ->
- $scope.productPropertySelectors = FilterSelectorsService.createSelectors()
$modal.open(templateUrl: "product_modal.html", scope: $scope)
diff --git a/app/assets/javascripts/darkswarm/controllers/shop_variant_controller.js.coffee b/app/assets/javascripts/darkswarm/controllers/shop_variant_controller.js.coffee
new file mode 100644
index 0000000000..adc25f4ad7
--- /dev/null
+++ b/app/assets/javascripts/darkswarm/controllers/shop_variant_controller.js.coffee
@@ -0,0 +1,39 @@
+Darkswarm.controller "ShopVariantCtrl", ($scope, $modal, Cart) ->
+ $scope.$watchGroup [
+ 'variant.line_item.quantity',
+ 'variant.line_item.max_quantity'
+ ], (new_value, old_value) ->
+ return if old_value[0] == null && new_value[0] == null
+ Cart.adjust($scope.variant.line_item)
+
+ $scope.add = (quantity) ->
+ item = $scope.variant.line_item
+ item.quantity += quantity
+ if $scope.variant.product.group_buy
+ if item.quantity < 1 || item.max_quantity < item.quantity
+ item.max_quantity = item.quantity
+
+ $scope.addMax = (quantity) ->
+ item = $scope.variant.line_item
+ item.max_quantity += quantity
+ if item.max_quantity < item.quantity
+ item.quantity = item.max_quantity
+
+ $scope.canAdd = (quantity) ->
+ wantedQuantity = $scope.variant.line_item.quantity + quantity
+ $scope.quantityValid(wantedQuantity)
+
+ $scope.canAddMax = (quantity) ->
+ variant = $scope.variant
+ wantedQuantity = variant.line_item.max_quantity + quantity
+ $scope.quantityValid(wantedQuantity) && variant.line_item.quantity > 0
+
+ $scope.quantityValid = (quantity) ->
+ variant = $scope.variant
+ minimum = 0
+ maximum = variant.on_demand && Infinity || variant.on_hand
+ quantity >= minimum && quantity <= maximum
+
+ $scope.addBulk = (quantity) ->
+ $scope.add(quantity)
+ $modal.open(templateUrl: "bulk_buy_modal.html", scope: $scope, windowClass: "product-bulk-modal")
diff --git a/app/assets/javascripts/darkswarm/directives/price_breakdown.js.coffee b/app/assets/javascripts/darkswarm/directives/price_breakdown.js.coffee
index 8b0beb17a5..1b4609ff4d 100644
--- a/app/assets/javascripts/darkswarm/directives/price_breakdown.js.coffee
+++ b/app/assets/javascripts/darkswarm/directives/price_breakdown.js.coffee
@@ -2,7 +2,7 @@ Darkswarm.directive "priceBreakdown", ($tooltip)->
# We use the $tooltip service from Angular foundation to give us boilerplate
# Subsequently we patch the scope, template and restrictions
tooltip = $tooltip 'priceBreakdown', 'priceBreakdown', 'click'
- tooltip.scope =
+ tooltip.scope =
variant: "="
tooltip.templateUrl = "price_breakdown_button.html"
tooltip.replace = true
@@ -15,6 +15,3 @@ Darkswarm.directive 'priceBreakdownPopup', ->
replace: true
templateUrl: 'price_breakdown.html'
scope: false
-
- link: (scope, elem, attrs) ->
- scope.expanded = false unless scope.expanded?
diff --git a/app/assets/javascripts/darkswarm/directives/price_percentage.js.coffee b/app/assets/javascripts/darkswarm/directives/price_percentage.js.coffee
deleted file mode 100644
index 35140598c4..0000000000
--- a/app/assets/javascripts/darkswarm/directives/price_percentage.js.coffee
+++ /dev/null
@@ -1,10 +0,0 @@
-Darkswarm.directive "pricePercentage", ->
- restrict: 'E'
- replace: true
- templateUrl: 'price_percentage.html'
- scope:
- percentage: '='
-
- link: (scope, elem, attrs) ->
- elem.find(".meter").css
- width: "#{scope.percentage}%"
diff --git a/app/assets/javascripts/darkswarm/directives/shop_variant.js.coffee b/app/assets/javascripts/darkswarm/directives/shop_variant.js.coffee
index 84615e3125..1872b55dfd 100644
--- a/app/assets/javascripts/darkswarm/directives/shop_variant.js.coffee
+++ b/app/assets/javascripts/darkswarm/directives/shop_variant.js.coffee
@@ -4,10 +4,4 @@ Darkswarm.directive "shopVariant", ->
templateUrl: 'shop_variant.html'
scope:
variant: '='
- controller: ($scope, Cart) ->
- $scope.$watchGroup [
- 'variant.line_item.quantity',
- 'variant.line_item.max_quantity'
- ], (new_value, old_value) ->
- return if old_value[0] == null && new_value[0] == null
- Cart.adjust($scope.variant.line_item)
+ controller: 'ShopVariantCtrl'
diff --git a/app/assets/javascripts/darkswarm/services/variants.js.coffee b/app/assets/javascripts/darkswarm/services/variants.js.coffee
index a650db5cd7..f5ba1af757 100644
--- a/app/assets/javascripts/darkswarm/services/variants.js.coffee
+++ b/app/assets/javascripts/darkswarm/services/variants.js.coffee
@@ -10,7 +10,6 @@ Darkswarm.factory 'Variants', ->
extend: (variant)->
variant.extended_name = @extendedVariantName(variant)
- variant.base_price_percentage = Math.round(variant.price / variant.price_with_fees * 100)
variant.line_item ||= @lineItemFor(variant) # line_item may have been initialised in Cart#constructor
variant.line_item.total_price = variant.price_with_fees * variant.line_item.quantity
variant
diff --git a/app/assets/javascripts/templates/bulk_buy_modal.html.haml b/app/assets/javascripts/templates/bulk_buy_modal.html.haml
new file mode 100644
index 0000000000..9625c1bd8f
--- /dev/null
+++ b/app/assets/javascripts/templates/bulk_buy_modal.html.haml
@@ -0,0 +1,37 @@
+.row
+ .columns.small-12
+ %h3{"ng-bind" => "::variant.extended_name"}
+
+.row.variant-bulk-buy-price-summary
+ .columns.small-6
+ .variant-unit {{ ::variant.unit_to_display }}
+ .columns.small-6
+ {{ variant.line_item.total_price | localizeCurrency }}
+
+.row
+ .columns.small-6
+ .variant-bulk-buy-quantity-label
+ {{ "js.shopfront.bulk_buy_modal.min_quantity" | t }}
+ %div
+ %button.bulk-buy-add.variant-quantity{type: "button", ng: {click: "add(-1)", disabled: "!canAdd(-1)"}}>
+ -# U+FF0D Fullwidth Hyphen-Minus
+ -
+ %span.bulk-buy.variant-quantity>
+ {{ variant.line_item.quantity }}
+ %button.bulk-buy-add.variant-quantity{type: "button", ng: {click: "add(1)", disabled: "!canAdd(1)"}}
+ -# U+FF0B Fullwidth Plus Sign
+ +
+ .columns.small-6
+ .variant-bulk-buy-quantity-label
+ {{ "js.shopfront.bulk_buy_modal.max_quantity" | t }}
+ %div
+ %button.bulk-buy-add.variant-quantity{type: "button", ng: {click: "addMax(-1)", disabled: "!canAddMax(-1)"}}>
+ -# U+FF0D Fullwidth Hyphen-Minus
+ -
+ %span.bulk-buy.variant-quantity>
+ {{ variant.line_item.max_quantity }}
+ %button.bulk-buy-add.variant-quantity{type: "button", ng: {click: "addMax(1)", disabled: "!canAddMax(1)"}}
+ -# U+FF0B Fullwidth Plus Sign
+ +
+
+%ng-include{src: "'partials/close.html'"}
diff --git a/app/assets/javascripts/templates/partials/shop_variant_no_group_buy.html.haml b/app/assets/javascripts/templates/partials/shop_variant_no_group_buy.html.haml
index 8ba787f20b..0d6563bc2a 100644
--- a/app/assets/javascripts/templates/partials/shop_variant_no_group_buy.html.haml
+++ b/app/assets/javascripts/templates/partials/shop_variant_no_group_buy.html.haml
@@ -1,14 +1,16 @@
.small-5.medium-3.large-3.columns.text-right{"ng-if" => "::!variant.product.group_buy"}
- %input{type: :number,
- integer: true,
- value: nil,
- min: 0,
- placeholder: "0",
- "ofn-disable-scroll" => true,
- "ng-debounce" => "500",
- onwheel: "this.blur()",
- "ng-model" => "variant.line_item.quantity",
- "ofn-on-hand" => "{{variant.on_demand && 9999 || variant.on_hand }}",
- "ng-disabled" => "!variant.on_demand && variant.on_hand == 0",
- name: "variants[{{::variant.id}}]", id: "variants_{{::variant.id}}"}
+ %button.add-variant{type: "button", ng: {if: "!variant.line_item.quantity", click: "add(1)", disabled: "!canAdd(1)"}}
+ {{ "js.shopfront.variant.add_to_cart" | t }}
+ %button.variant-quantity{type: "button", ng: {if: "variant.line_item.quantity", click: "add(-1)"}}>
+ -# U+FF0D Fullwidth Hyphen-Minus
+ -
+ %button.variant-quantity{type: "button", ng: {if: "variant.line_item.quantity", click: "add(1)", disabled: "!canAdd(1)"}}
+ -# U+FF0B Fullwidth Plus Sign
+ +
+ %br
+ .variant-quantity-display{ng: {class: "{visible: variant.line_item.quantity}"}}
+ {{ "js.shopfront.variant.quantity_in_cart" | t:{quantity: variant.line_item.quantity || 0} }}
+ %input{type: :hidden,
+ name: "variants[{{::variant.id}}]",
+ ng: {model: "variant.line_item.quantity"}}
diff --git a/app/assets/javascripts/templates/partials/shop_variant_with_group_buy.html.haml b/app/assets/javascripts/templates/partials/shop_variant_with_group_buy.html.haml
index c0cc46ac13..18f46e5490 100644
--- a/app/assets/javascripts/templates/partials/shop_variant_with_group_buy.html.haml
+++ b/app/assets/javascripts/templates/partials/shop_variant_with_group_buy.html.haml
@@ -1,28 +1,17 @@
.small-5.medium-3.large-3.columns.text-right{"ng-if" => "::variant.product.group_buy"}
- %span.bulk-input-container
- %span.bulk-input
- %input.bulk.first{type: :number,
- value: nil,
- integer: true,
- min: 0,
- "ng-model" => "variant.line_item.quantity",
- placeholder: "{{::'shop_variant_quantity_min' | t}}",
- "ofn-disable-scroll" => true,
- "ng-debounce" => "500",
- onwheel: "this.blur()",
- "ofn-on-hand" => "{{variant.on_demand && 9999 || variant.on_hand }}",
- name: "variants[{{::variant.id}}]", id: "variants_{{::variant.id}}"}
- %span.bulk-input
- %input.bulk.second{type: :number,
- "ng-disabled" => "!variant.line_item.quantity",
- integer: true,
- min: 0,
- "ng-model" => "variant.line_item.max_quantity",
- placeholder: "{{::'shop_variant_quantity_max' | t}}",
- "ofn-disable-scroll" => true,
- "ng-debounce" => "500",
- onwheel: "this.blur()",
- min: "{{variant.line_item.quantity}}",
- name: "variant_attributes[{{::variant.id}}][max_quantity]",
- id: "variants_{{::variant.id}}_max"}
+ %button.add-variant{type: "button", ng: {if: "!variant.line_item.quantity", click: "addBulk(1)", disabled: "!canAdd(1)"}}
+ {{ "js.shopfront.variant.add_to_cart" | t }}
+ %button.bulk-buy.variant-quantity{type: "button", ng: {if: "variant.line_item.quantity", click: "addBulk(0)"}}>
+ {{ variant.line_item.quantity }}
+ %button.bulk-buy.variant-quantity{type: "button", ng: {if: "variant.line_item.quantity", click: "addBulk(0)"}}
+ {{ variant.line_item.max_quantity || "-" }}
+ %br
+ .variant-quantity-display{ng: {class: "{visible: variant.line_item.quantity}"}}
+ {{ "js.shopfront.variant.in_cart" | t }}
+ %input{type: :hidden,
+ name: "variants[{{::variant.id}}]",
+ ng: {model: "variant.line_item.quantity"}}
+ %input{type: :hidden,
+ name: "variants[{{::variant.id}}]",
+ ng: {model: "variant.line_item.max_quantity"}}
diff --git a/app/assets/javascripts/templates/price_breakdown.html.haml b/app/assets/javascripts/templates/price_breakdown.html.haml
index 48e0a8d5e0..bd4c3bf88f 100644
--- a/app/assets/javascripts/templates/price_breakdown.html.haml
+++ b/app/assets/javascripts/templates/price_breakdown.html.haml
@@ -1,37 +1,28 @@
-.joyride-tip-guide.price_breakdown{"ng-class" => "{ in: tt_isOpen, fade: tt_animation }"}
- %span.joyride-nub.right
+.joyride-tip-guide.price_breakdown{ng: {class: "{ in: tt_isOpen, fade: tt_animation }", show: "tt_isOpen"}}
+ %span.joyride-nub.top
+ .background{ng: {click: "tt_isOpen = false"}}
.joyride-content-wrapper
- .collapsed{"ng-show" => "!expanded"}
- %price-percentage{percentage: 'variant.base_price_percentage'}
- %a{"ng-click" => "expanded = !expanded"}
- %span{"ng-bind" => "::'price_breakdown' | t"}
- %i.ofn-i_005-caret-down
-
- .expanded{"ng-show" => "expanded"}
- %ul
- %li.cost
- .right {{ ::variant.price | localizeCurrency }}
- %span{"ng-bind" => "::'item_cost' | t"}
- %li.admin-fee{"ng-if" => "::variant.fees.admin"}
- .right {{ ::variant.fees.admin | localizeCurrency }}
- %span{"ng-bind" => "::'admin_fee' | t"}
- %li.sales-fee{"ng-if" => "::variant.fees.sales"}
- .right {{ ::variant.fees.sales | localizeCurrency }}
- %span{"ng-bind" => "::'sales_fee' | t"}
- %li.packing-fee{"ng-if" => "::variant.fees.packing"}
- .right {{ ::variant.fees.packing | localizeCurrency }}
- %span{"ng-bind" => "::'packing_fee' | t"}
- %li.transport-fee{"ng-if" => "::variant.fees.transport"}
- .right {{ ::variant.fees.transport | localizeCurrency }}
- %span{"ng-bind" => "::'transport_fee' | t"}
- %li.fundraising-fee{"ng-if" => "::variant.fees.fundraising"}
- .right {{ ::variant.fees.fundraising | localizeCurrency }}
- %span{"ng-bind" => "::'fundraising_fee' | t"}
- %li.total
- %strong
- .right = {{ ::variant.price_with_fees | localizeCurrency }}
-
-
- %a{"ng-click" => "expanded = !expanded"}
- %span{"ng-bind" => "::'price_graph' | t"}
- %i.ofn-i_006-caret-up
+ %h6 {{ "js.shopfront.price_breakdown" | t }}
+ %ul
+ %li
+ .right {{ ::variant.price | localizeCurrency }}
+ %span{"ng-bind" => "::'item_cost' | t"}
+ %li{"ng-if" => "::variant.fees.admin"}
+ .right {{ ::variant.fees.admin | localizeCurrency }}
+ %span{"ng-bind" => "::'admin_fee' | t"}
+ %li{"ng-if" => "::variant.fees.sales"}
+ .right {{ ::variant.fees.sales | localizeCurrency }}
+ %span{"ng-bind" => "::'sales_fee' | t"}
+ %li{"ng-if" => "::variant.fees.packing"}
+ .right {{ ::variant.fees.packing | localizeCurrency }}
+ %span{"ng-bind" => "::'packing_fee' | t"}
+ %li{"ng-if" => "::variant.fees.transport"}
+ .right {{ ::variant.fees.transport | localizeCurrency }}
+ %span{"ng-bind" => "::'transport_fee' | t"}
+ %li{"ng-if" => "::variant.fees.fundraising"}
+ .right {{ ::variant.fees.fundraising | localizeCurrency }}
+ %span{"ng-bind" => "::'fundraising_fee' | t"}
+ %li
+ %strong
+ .right = {{ ::variant.price_with_fees | localizeCurrency }}
+
diff --git a/app/assets/javascripts/templates/price_percentage.html.haml b/app/assets/javascripts/templates/price_percentage.html.haml
deleted file mode 100644
index f524103643..0000000000
--- a/app/assets/javascripts/templates/price_percentage.html.haml
+++ /dev/null
@@ -1,4 +0,0 @@
-.progress
- .right {{::'fees' | t}}
- .meter
- {{::'item_cost' | t}}
diff --git a/app/assets/javascripts/templates/shop_variant.html.haml b/app/assets/javascripts/templates/shop_variant.html.haml
index 71ca3c33ec..1435f33399 100644
--- a/app/assets/javascripts/templates/shop_variant.html.haml
+++ b/app/assets/javascripts/templates/shop_variant.html.haml
@@ -1,31 +1,16 @@
.variants.row
- .small-12.medium-4.large-4.columns.variant-name
- .table-cell
- .inline {{ ::variant.name_to_display }}
- .bulk-buy.inline{"ng-if" => "::variant.product.group_buy"}
- %i.ofn-i_056-bulk><
- %em><
- \ {{::'bulk' | t}}
+ .small-4.medium-4.large-6.columns.variant-name
+ .inline{"ng-if" => "::variant.display_name"} {{ ::variant.display_name }}
+ .variant-unit {{ ::variant.unit_to_display }}
+ .small-3.medium-3.large-2.columns.variant-price
+ %price-breakdown{"price-breakdown" => "_", variant: "variant",
+ "price-breakdown-append-to-body" => "true",
+ "price-breakdown-placement" => "bottom",
+ "price-breakdown-animation" => true}
+ {{ variant.price_with_fees | localizeCurrency }}
+ .medium-2.large-1.columns.total-price
+ %span{"ng-class" => "{filled: variant.line_item.total_price}"}
+ {{ variant.line_item.total_price | localizeCurrency }}
%ng-include{src: "'partials/shop_variant_no_group_buy.html'"}
%ng-include{src: "'partials/shop_variant_with_group_buy.html'"}
-
- .small-3.medium-1.large-1.columns.variant-unit
- .table-cell
- %em {{ ::variant.unit_to_display }}
-
- .small-4.medium-2.large-2.columns.variant-price
- .table-cell.price
- %i.ofn-i_009-close
- {{ variant.price_with_fees | localizeCurrency }}
-
- -# Now in a template in app/assets/javascripts/templates !
- %price-breakdown{"price-breakdown" => "_", variant: "variant",
- "price-breakdown-append-to-body" => "true",
- "price-breakdown-placement" => "left",
- "price-breakdown-animation" => true}
-
- .small-12.medium-2.large-2.columns.total-price.text-right
- .table-cell
- %strong{"ng-class" => "{filled: variant.line_item.total_price}"}
- {{ variant.line_item.total_price | localizeCurrency }}
diff --git a/app/assets/stylesheets/admin/all.scss b/app/assets/stylesheets/admin/all.scss
index 6d5992f8d4..65d555e561 100644
--- a/app/assets/stylesheets/admin/all.scss
+++ b/app/assets/stylesheets/admin/all.scss
@@ -35,7 +35,6 @@
@import 'plugins/font-awesome';
@import 'plugins/select2';
-@import 'sections/image_settings';
@import 'sections/orders';
@import 'sections/products';
diff --git a/app/assets/stylesheets/admin/hacks/ie.scss b/app/assets/stylesheets/admin/hacks/ie.scss
index ba5cd61501..4eff79ed84 100644
--- a/app/assets/stylesheets/admin/hacks/ie.scss
+++ b/app/assets/stylesheets/admin/hacks/ie.scss
@@ -29,11 +29,6 @@ html.ie {
z-index: 0;
}
}
-
- // Fix margin-top for destroy paperclip styles background
- .destroy_new_attachment_styles {
- margin-top: 17px !important;
- }
}
// IE8 Hacks
diff --git a/app/assets/stylesheets/admin/sections/image_settings.scss b/app/assets/stylesheets/admin/sections/image_settings.scss
deleted file mode 100644
index dc7a29b1b2..0000000000
--- a/app/assets/stylesheets/admin/sections/image_settings.scss
+++ /dev/null
@@ -1,3 +0,0 @@
-.destroy_style, .destroy_header {
- float: right;
-}
diff --git a/app/assets/stylesheets/admin/shared/layout.scss b/app/assets/stylesheets/admin/shared/layout.scss
index 4288e88266..17af56a59b 100644
--- a/app/assets/stylesheets/admin/shared/layout.scss
+++ b/app/assets/stylesheets/admin/shared/layout.scss
@@ -71,12 +71,6 @@
display: none;
}
-// For block grids
-.frameless {
- margin-left: -10px;
- margin-right: -10px;
-}
-
// Header
//---------------------------------------------------
#header {
diff --git a/app/assets/stylesheets/darkswarm/_shop-inputs.scss b/app/assets/stylesheets/darkswarm/_shop-inputs.scss
index 59a3bd0c67..7de6a9355a 100644
--- a/app/assets/stylesheets/darkswarm/_shop-inputs.scss
+++ b/app/assets/stylesheets/darkswarm/_shop-inputs.scss
@@ -6,93 +6,110 @@
.darkswarm {
// #search
@include placeholder(rgba(0, 0, 0, 0.4), #777);
+}
- // ordering
- product {
- input {
- @include border-radius(0);
+.reveal-modal.product-bulk-modal {
+ width: 26em;
+}
- @include csstrans;
+// Components to add variants to cart and change quantities
+//
+// They are not nested so that they can be used in modals.
+button.add-variant, button.variant-quantity {
+ height: 2.5rem;
+ border-radius: 0;
+ background-color: $orange-500;
+ color: white;
+ // Override foundation button styles:
+ font-size: 1rem;
+ margin: 0;
+ padding: 0;
+ transition: none;
- margin: 0;
- width: 10rem;
- display: inline;
-
- @include box-shadow(none);
-
- border-color: #b3b3b3;
- text-align: right;
-
- @include breakpoint(desktop) {
- width: 8rem;
- }
-
- @include breakpoint(tablet) {
- width: 7rem;
- }
-
- @include breakpoint(phablet) {
- float: left !important;
- font-size: 0.75rem;
- padding-left: 0.25rem;
- padding-right: 0.25rem;
- }
-
- @include breakpoint(mobile) {
- width: 5.8rem;
- }
-
- &:hover {
- @include box-shadow(none);
-
- border-color: #888;
- background-color: #fafafa;
- }
-
- &:active, &:focus, &.active {
- @include box-shadow(none);
-
- background-color: #f9f4b9;
- border-color: #666;
- }
+ &:hover {
+ background-color: $orange-600;
+ }
+ &[disabled] {
+ &:hover, &:focus {
+ background-color: $orange-500;
}
+ }
+ &:nth-of-type(1) {
+ border-bottom-left-radius: 0.25em;
+ border-top-left-radius: 0.25em;
+ }
+ &:nth-last-of-type(1) {
+ border-top-right-radius: 0.25em;
+ border-bottom-right-radius: 0.25em;
+ }
+}
- // BULK
+button.add-variant {
+ min-width: 6rem;
+ padding: 0 1em;
- input.bulk {
- width: 5rem;
-
- @include breakpoint(desktop) {
- width: 4rem;
- }
-
- @include breakpoint(tablet) {
- width: 3.5rem;
- }
-
- @include breakpoint(mobile) {
- width: 2.8rem;
- }
- }
-
- input.bulk.first {
- border-right: 0;
- }
-
- input.bulk.second {
- border-left: 0;
- }
-
- .bulk-input-container {
- float: right;
-
- @include breakpoint(phablet) {
- float: left !important;
- }
-
- .bulk-input {
- float: left;
- }
+ &[disabled] {
+ &:hover, &:focus {
+ background-color: $orange-500;
}
}
}
+
+button.variant-quantity {
+ width: 3rem;
+
+ &:nth-of-type(1):not(.bulk-buy):not(.bulk-buy-add) {
+ border-right: .1em solid $orange-400;
+ }
+}
+
+.variant-quantity-display {
+ display: inline-block;
+ font-size: 0.875em;
+ margin-top: 0.25em;
+ text-align: center;
+ width: 6rem;
+ visibility: hidden;
+
+ &.visible {
+ visibility: visible;
+ }
+}
+
+button.bulk-buy.variant-quantity {
+ background-color: transparent;
+ border: .1em solid $grey-200;
+ color: inherit;
+}
+
+button.bulk-buy-add.variant-quantity {
+ width: 2.5rem;
+
+ &[disabled] {
+ background-color: $grey-400;
+
+ &:hover, &:focus {
+ background-color: $grey-400;
+ }
+ }
+}
+
+span.bulk-buy.variant-quantity {
+ border: .1em solid $grey-200;
+ height: 2.5rem;
+ display: inline-block;
+ min-width: 3em;
+ padding: .5em;
+ text-align: center;
+ vertical-align: top;
+}
+
+.variant-bulk-buy-price-summary {
+ color: $disabled-med;
+ margin-bottom: 1em;
+}
+
+.variant-bulk-buy-quantity-label {
+ font-size: 0.875rem;
+ margin-bottom: .5em;
+}
diff --git a/app/assets/stylesheets/darkswarm/_shop-navigation.scss b/app/assets/stylesheets/darkswarm/_shop-navigation.scss
index d3febdb28f..8ed5400ed9 100644
--- a/app/assets/stylesheets/darkswarm/_shop-navigation.scss
+++ b/app/assets/stylesheets/darkswarm/_shop-navigation.scss
@@ -178,7 +178,7 @@ shop ordercycle {
}
shop navigation ordercycle {
- margin-top: 3em;
+ margin-top: 3.4em;
padding: 1em;
height: 7.6em;
position: absolute;
diff --git a/app/assets/stylesheets/darkswarm/_shop-popovers.scss b/app/assets/stylesheets/darkswarm/_shop-popovers.scss
index dd5aa5a177..d91f870330 100644
--- a/app/assets/stylesheets/darkswarm/_shop-popovers.scss
+++ b/app/assets/stylesheets/darkswarm/_shop-popovers.scss
@@ -4,86 +4,69 @@
// Pop over
// Foundation overrides
.joyride-tip-guide.price_breakdown {
+ width: 16rem;
+ max-width: 65%;
// JS needs to be tweaked to adjust for left alignment - this is dynamic can't rewrite in CSS
- background-color: #999;
- color: #1f1f1f;
- margin-left: -8px;
+ margin-left: -7.4rem;
+ margin-top: 0.1rem;
- @include box-shadow(0 1px 2px 0 rgba(0, 0, 0, 0.7));
+ @include box-shadow(0 2px 8px 0 rgba(0, 0, 0, 0.35));
.joyride-content-wrapper {
- padding: 1.125rem 1.25rem 1.5rem;
- padding: 1rem;
- margin: 1%;
+ padding: .625rem;
width: 98%;
- background-color: white;
- }
-
- h1, h2, h3, h4, h5, h6 {
- color: #1f1f1f;
- }
-
- .joyride-nub.right {
- top: 38px;
- border-color: #999 !important;
- border-top-color: transparent !important;
- border-right-color: transparent !important;
- border-bottom-color: transparent !important;
- }
-
- .progress {
- background-color: #13bf85;
- padding: 0;
- border: none;
+ background-color: $grey-800;
color: white;
- font-size: 0.75rem;
- font-style: oblique;
- line-height: 1;
- height: auto;
-
- .right {
- padding: 0.5rem 0.25rem 0 0;
- }
-
- .meter {
- background-color: #0b8c61;
- padding: 0.5rem 0.25rem;
- border-right: 1px solid #539f92;
- }
}
- .expanded {
- ul, li {
- list-style: none;
- margin: 0;
- font-size: 0.875rem;
- }
+ h6 {
+ font-size: 0.937rem;
+ line-height: 1;
+ border-bottom: .1em solid $grey-700;
+ padding: 0 0 .625em 0;
+ margin-bottom: 2px;
+ }
- li {
- background-color: #13bf85;
- padding: 0 0.25rem;
- margin-bottom: 2px;
- color: white;
- }
+ .joyride-nub.top {
+ left: 7.4rem;
+ z-index: -1;
+ }
- li.cost {
- background-color: #0b8c61;
- }
+ .background {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ z-index: -1;
+ cursor: pointer;
+ }
- li:last-child {
- margin-bottom: 0.75rem;
- }
+ ul, li {
+ list-style: none;
+ margin: 0;
+ font-size: 0.875rem;
+ }
+
+ li {
+ line-height: 1;
+ border-bottom: .1em solid $grey-700;
+ padding: 0.625rem 0;
+ margin-bottom: 2px;
+ }
+
+ li:last-child {
+ border-bottom: 0;
+ padding-bottom: 0;
}
}
button.graph-button {
// z-index: 9999999
- border: 1px solid transparent;
padding: 0;
margin: 0;
- display: inline;
+ display: inline-block;
background-color: rgba(255, 255, 255, 0.5);
- padding: 4px;
@include box-shadow(none);
@@ -97,7 +80,6 @@ button.graph-button {
}
&:focus {
- border: 1px solid #e0e0e0;
background-color: rgba(255, 255, 255, 1);
&:before {
@@ -107,22 +89,15 @@ button.graph-button {
&:hover, &:active {
background-color: rgba(255, 255, 255, 1);
- border: 1px solid transparent;
&:before {
- color: $clr-brick-bright;
+ color: $teal-500;
}
}
-
- @include breakpoint(tablet) {
- // Hide for small
- display: none;
- }
}
button.graph-button.open {
- border: 1px solid transparent;
- background-color: $clr-brick-bright;
+ background-color: $teal-500;
&:before {
content: "";
diff --git a/app/assets/stylesheets/darkswarm/_shop-product-rows.scss b/app/assets/stylesheets/darkswarm/_shop-product-rows.scss
index b0ea1faf39..feb9f54e5d 100644
--- a/app/assets/stylesheets/darkswarm/_shop-product-rows.scss
+++ b/app/assets/stylesheets/darkswarm/_shop-product-rows.scss
@@ -10,91 +10,57 @@
.columns {
padding-top: 0em;
padding-bottom: 0em;
- display: table;
line-height: 1.1;
-
- // outline: 1px solid red
-
- @include breakpoint(tablet) {
- font-size: 0.875rem;
- }
-
- @include breakpoint(phablet) {
- font-size: 0.75rem;
- }
}
+ }
- .table-cell {
- display: table-cell;
- vertical-align: middle;
- height: 37px;
+ .shop-variants {
+ // product-thumb width + 1rem
+ padding-left: calc(22.222% + 1rem);
+
+ @include breakpoint(phablet) {
+ padding-left: 0;
+ clear: left;
}
}
// ROW VARIANTS
.row.variants {
- margin-left: 0;
- margin-right: 0;
- background-color: #ECECEC;
-
- &:hover, &:focus, &:active {
- background-color: $clr-brick-light;
- }
-
- &:nth-of-type(even) {
- background-color: #f9f9f9;
-
- &:hover, &:focus, &:active {
- background-color: $clr-brick-ultra-light;
- }
- }
+ margin: 0 0 1em 0;
&.out-of-stock {
opacity: 0.2;
}
+ .variant-name,
+ .total-price {
+ padding-top: .74em;
+ }
+ .variant-price {
+ padding-top: .65em;
+ }
+
// Variant name
.variant-name {
- padding-left: 7.9375rem;
+ padding-left: 0;
+ padding-right: 0;
- @include breakpoint(tablet) {
- padding-left: 4.9375rem;
- }
- }
-
- .variant-name {
@include breakpoint(phablet) {
- background: #333;
- color: white;
- padding-left: 0.9375rem;
- font-weight: bold;
-
- .table-cell {
- height: 27px;
- }
+ padding-left: 0.5rem;
}
- }
- // Variant unit
- .variant-unit {
- padding-left: 0rem;
- padding-right: 0rem;
- color: #888;
- font-size: 0.875rem;
- overflow: hidden;
-
- @include breakpoint(tablet) {
- font-size: 0.75rem;
+ & > *:nth-child(n + 2) {
+ color: $grey-550;
+ font-size: 0.875rem;
+ font-style: italic;
+ line-height: normal;
}
}
// Variant price
.variant-price {
- padding-left: 0.25rem;
- padding-right: 0.25rem;
-
@include breakpoint(phablet) {
- text-align: right;
+ padding-left: 1rem;
}
}
@@ -108,24 +74,16 @@
}
@include breakpoint(phablet) {
- background: #777;
- color: $disabled-med;
-
- .filled {
- color: white;
- }
-
- .table-cell {
- height: 27px;
- }
+ display: none;
}
}
}
// ROW SUMMARY
- .row.summary {
+ .summary {
margin-left: 0;
margin-right: 0;
+ margin-bottom: 1.25em;
background: #fff;
.columns {
@@ -140,39 +98,77 @@
}
.summary-header {
- padding-left: 7.9375rem;
-
- @include breakpoint(tablet) {
- padding-left: 4.9375rem;
- }
+ // product-thumb width + 1rem
+ padding-left: calc(22.222% + 1rem);
+ padding-right: 1rem;
@include breakpoint(phablet) {
- padding-left: 0.9375rem;
+ padding-left: calc(33.333% + 1rem);
}
- small {
- font-size: 80%;
+ .product-producer {
+ color: $grey-550;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ font-style: italic;
+
+ a {
+ color: $teal-500;
+
+ &:hover, &:focus, &:active {
+ color: $teal-600;
+ text-decoration: underline;
+ }
+ }
}
h3 {
- font-size: 1.5rem;
- margin: 0;
+ font-size: 1.3rem;
+ margin-top: 0.75rem;
+ margin-bottom: 0.6rem;
}
h3 a {
- color: #222;
-
- i {
- @include csstrans;
-
- font-size: 0.6em;
- }
+ color: $orange-500;
&:hover, &:focus, &:active {
- color: $clr-brick;
+ color: $orange-600;
+ text-decoration: underline;
+ }
+ }
- i {
- font-size: 0.8em;
+ .product-description {
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ margin-bottom: 0.75rem;
+ }
+
+ .product-properties {
+ margin: .5em 0;
+
+ li {
+ margin: 0 0.25rem 0.25rem 0;
+
+ a {
+ padding: 0.1em 0.625em;
+
+ cursor: auto;
+
+ &.has-tip {
+ cursor: pointer;
+ font-weight: normal;
+ }
+ &:hover, &:focus {
+ border-color: #ccc;
+ }
+ }
+
+ // Foundation doesn't show the nub on mobile.
+ // Repeating the style to show it here.
+ .nub {
+ border-color: transparent transparent #333333 transparent;
}
}
}
diff --git a/app/assets/stylesheets/darkswarm/_shop-product-thumb.scss b/app/assets/stylesheets/darkswarm/_shop-product-thumb.scss
index c9f8794295..9b51d7f881 100644
--- a/app/assets/stylesheets/darkswarm/_shop-product-thumb.scss
+++ b/app/assets/stylesheets/darkswarm/_shop-product-thumb.scss
@@ -1,80 +1,32 @@
-@import "mixins";
-@import "branding";
-@import "animations";
-
.darkswarm {
products {
product {
.product-thumb {
- @include csstrans;
-
- position: absolute;
- top: 2px;
- left: 0px;
- width: 7rem;
- height: 7rem;
+ // Desktop: the product summary is nine columns wide. Use two
+ // for the image. 100% / 9 * 2 = 22.222% <= 192px
+ width: calc(22.222%);
float: left;
- display: block;
- z-index: 1;
- background-color: white;
- overflow: hidden;
-
- i {
- @include csstrans;
-
- transition-delay: 150ms;
- position: absolute;
- left: 45%;
- top: 45%;
- z-index: 99999;
- color: white;
- font-size: 1rem;
- opacity: 0;
- }
-
- img {
- @include csstrans;
-
- opacity: 1;
-
- @include transform-scale(scale(1));
- }
-
- &:hover, &:focus, &:active {
- background-color: $clr-brick;
-
- i {
- left: 32%;
- top: 30%;
- font-size: 3rem;
- opacity: 1;
- }
-
- img {
- opacity: 0.5;
-
- @include transform-scale(scale(1.1));
- }
- }
-
- @include breakpoint(tablet) {
- top: 2px;
- width: 4rem;
- height: 4rem;
-
- &:hover, &:focus, &:active {
- i {
- left: 30%;
- top: 30%;
- font-size: 2rem;
- }
- }
- }
+ // Mobile: the summary has full twelve columns and the image
+ // should take four of them. 100% / 12 * 4 = 33.333% <= 227px
@include breakpoint(phablet) {
- display: none;
- width: 0rem;
- height: 0rem;
+ width: calc(33.333%);
+ }
+
+ // Make this an anchor for the bulk label.
+ position: relative;
+
+ .product-thumb__bulk-label {
+ background-color: $grey-700;
+ color: white;
+ position: absolute;
+ right: 0;
+ top: .8em;
+ padding: .25em .5em;
+ }
+
+ &:hover {
+ filter: brightness(96%);
}
}
}
diff --git a/app/assets/stylesheets/darkswarm/_shop-taxon-flag.scss b/app/assets/stylesheets/darkswarm/_shop-taxon-flag.scss
deleted file mode 100644
index b6b237215e..0000000000
--- a/app/assets/stylesheets/darkswarm/_shop-taxon-flag.scss
+++ /dev/null
@@ -1,47 +0,0 @@
-@import "mixins";
-
-.darkswarm {
- products {
- product {
- .taxon-flag {
- background: transparent image-url("flag.svg") top center no-repeat;
- background-size: 34px 39px;
- min-height: 40px;
- width: 34px;
- margin-top: -1.1rem;
- padding-top: 0.25rem;
- z-index: 999999;
-
- @include breakpoint(mobile) {
- background-size: 28px 32px;
- min-height: 32px;
- width: 28px;
- }
-
- render-svg {
- svg {
- width: 24px;
- height: 24px;
-
- path {
- fill: #999;
- }
- }
- }
-
- @include breakpoint(tablet) {
- margin-top: -0.85rem;
- }
-
- @include breakpoint(mobile) {
- render-svg {
- svg {
- width: 18px;
- height: 18px;
- }
- }
- }
- }
- }
- }
-}
diff --git a/app/assets/stylesheets/darkswarm/branding.scss b/app/assets/stylesheets/darkswarm/branding.scss
index de705bbfa3..b29e81acf9 100644
--- a/app/assets/stylesheets/darkswarm/branding.scss
+++ b/app/assets/stylesheets/darkswarm/branding.scss
@@ -11,7 +11,6 @@ $ofn-grey: #808184;
$clr-brick: #c1122b;
$clr-brick-light: #f5e6e7;
$clr-brick-light-trans: rgba(245, 230, 231, 0.9);
-$clr-brick-ultra-light: #faf5f6;
$clr-brick-bright: #eb4c46;
$clr-brick-med-bright: #e5a2a0;
$clr-brick-light-bright: #f5c4c9;
@@ -48,6 +47,7 @@ $grey-200: #ddd;
$grey-300: #ccc;
$grey-400: #bbb;
$grey-500: #999;
+$grey-550: #888;
$grey-600: #777;
$grey-650: #666;
$grey-700: #555;
@@ -56,6 +56,7 @@ $grey-800: #333;
$teal-300: #80d3df;
$teal-400: #4cb5c5;
$teal-500: #0096ad;
+$teal-600: #007a9a;
$orange-400: #ff9466;
$orange-450: #f4704c;
diff --git a/app/assets/stylesheets/darkswarm/embedded_shopfront.scss b/app/assets/stylesheets/darkswarm/embedded_shopfront.scss
index 210825a008..2db5181cdd 100644
--- a/app/assets/stylesheets/darkswarm/embedded_shopfront.scss
+++ b/app/assets/stylesheets/darkswarm/embedded_shopfront.scss
@@ -59,13 +59,6 @@ body.embedded {
line-height: $large-menu-height;
height: $large-menu-height;
vertical-align: top;
-
- &.cart {
- div.joyride-tip-guide { // Cart Dropdown
- top: 75px;
- overflow: visible;
- }
- }
}
}
diff --git a/app/assets/stylesheets/darkswarm/mixins.scss b/app/assets/stylesheets/darkswarm/mixins.scss
index 43d291e14e..90febd6009 100644
--- a/app/assets/stylesheets/darkswarm/mixins.scss
+++ b/app/assets/stylesheets/darkswarm/mixins.scss
@@ -142,57 +142,6 @@
// Background options \\
-@mixin darkbg {
- background-color: $clr-brick;
-
- &, & * {
- color: white;
- }
-
- a {
- color: $clr-brick-ultra-light;
-
- &:hover {
- text-decoration: none;
- color: $clr-brick-light;
- }
- }
-}
-
-@mixin lightbg {
- background-color: $clr-brick-light;
-
- &, & * {
- color: black;
- }
-
- a {
- color: $clr-brick;
-
- &:hover {
- text-decoration: none;
- color: $clr-brick-bright;
- }
- }
-}
-
-@mixin turqbg {
- background-color: $clr-turquoise-light;
-
- &, & * {
- color: $clr-turquoise;
- }
-
- a {
- color: $clr-turquoise;
-
- &:hover {
- text-decoration: none;
- color: $clr-turquoise-bright;
- }
- }
-}
-
@mixin fullbg {
background-position: center center;
background-repeat: no-repeat;
@@ -202,12 +151,6 @@
background-size: cover;
}
-@mixin fullwidthbg {
- background-position: center top;
- background-repeat: no-repeat;
- background-size: 100% auto;
-}
-
@mixin gradient($gradient-clr1, $gradient-clr2) {
background: $gradient-clr1;
diff --git a/app/assets/stylesheets/darkswarm/shop.scss b/app/assets/stylesheets/darkswarm/shop.scss
index 6f411db6e9..8312f6c360 100644
--- a/app/assets/stylesheets/darkswarm/shop.scss
+++ b/app/assets/stylesheets/darkswarm/shop.scss
@@ -8,10 +8,30 @@
@import "shop-inputs";
@import "shop-navigation";
@import "shop-product-rows";
-@import "shop-taxon-flag";
@import "shop-popovers";
.darkswarm {
+ .product-listing {
+ @include breakpoint(desktop) {
+ padding-right: 0;
+ padding-left: 0;
+ }
+
+ .row.full {
+ width: 100%;
+ margin: 0;
+
+ .columns.full {
+ padding-right: 0;
+ padding-left: 0;
+ }
+ }
+ }
+
+ .filter-header {
+ margin-top: 1.1em;
+ }
+
products {
display: block;
@@ -51,32 +71,18 @@
product {
@include csstrans;
- border-bottom: 1px solid #e5e5e5;
- border-top: 1px solid #e5e5e5;
+ // Avoid margin collapsing which breaks the flush alignment of the first
+ // image.
+ overflow: auto;
+
+ &:nth-child(n + 2) {
+ border-top: 1px solid $grey-100;
+ }
padding-bottom: 1px;
- margin-bottom: 20px !important;
position: relative;
display: block;
color: $med-drk-grey;
- &:hover, &:focus, &:active {
- border-bottom: 1px solid $clr-brick-med-bright;
- border-top: 1px solid $clr-brick-med-bright;
- }
-
- // BULK
- .bulk-buy {
- font-size: 0.875rem;
-
- @include breakpoint(tablet) {
- font-size: 0.75rem;
- }
- }
-
- .bulk-buy, .bulk-buy i {
- color: #888;
- }
-
.inline {
display: inline;
}
@@ -85,27 +91,6 @@
width: 100px;
margin-bottom: 20px;
}
-
- // ICONS
- i {
- font-size: 0.75em;
- padding-right: 0.9375rem;
-
- @include breakpoint(phablet) {
- padding-right: 0.25rem;
- }
- }
-
- i.ofn-i_056-bulk {
- font-size: 1rem;
- padding-right: 0rem;
- }
-
- i.ofn-i_036-producers {
- padding-left: 0.2rem;
- padding-right: 0rem;
- font-size: 0.8rem;
- }
}
}
diff --git a/app/assets/stylesheets/darkswarm/shop_search.scss b/app/assets/stylesheets/darkswarm/shop_search.scss
index 4b141cd021..28e4269b4c 100644
--- a/app/assets/stylesheets/darkswarm/shop_search.scss
+++ b/app/assets/stylesheets/darkswarm/shop_search.scss
@@ -6,7 +6,6 @@
background-color: $grey-100;
height: 5em;
padding: 1em 0;
- margin-bottom: 1em;
position: relative;
z-index: 5;
@@ -50,7 +49,7 @@
button {
background-color: $grey-600;
- margin-left: 1em;
+ margin: 0 0 0 1em;
height: 3em;
width: 7em;
padding: 0;
diff --git a/app/assets/stylesheets/darkswarm/ui.scss b/app/assets/stylesheets/darkswarm/ui.scss
index d6b0988ad6..a9a43b0b5f 100644
--- a/app/assets/stylesheets/darkswarm/ui.scss
+++ b/app/assets/stylesheets/darkswarm/ui.scss
@@ -159,11 +159,6 @@ a.button.large {
display: flex;
}
-.no-gutter {
- padding-right: 0;
- padding-left: 0;
-}
-
.disable-scroll {
overflow: hidden;
}
diff --git a/app/controllers/admin/enterprises_controller.rb b/app/controllers/admin/enterprises_controller.rb
index 4277dc2ff4..f1b4887f6a 100644
--- a/app/controllers/admin/enterprises_controller.rb
+++ b/app/controllers/admin/enterprises_controller.rb
@@ -73,7 +73,7 @@ module Admin
if @enterprise.update(attributes)
flash[:success] = I18n.t(:enterprise_register_success_notice, enterprise: @enterprise.name)
- redirect_to admin_dashboard_path
+ redirect_to spree.admin_dashboard_path
else
flash[:error] = I18n.t(:enterprise_register_error, enterprise: @enterprise.name)
render :welcome, layout: "spree/layouts/bare_admin"
diff --git a/app/controllers/checkout_controller.rb b/app/controllers/checkout_controller.rb
index c47b112359..b25dd490f2 100644
--- a/app/controllers/checkout_controller.rb
+++ b/app/controllers/checkout_controller.rb
@@ -1,6 +1,7 @@
# frozen_string_literal: true
require 'open_food_network/address_finder'
+require 'spree/core/gateway_error'
class CheckoutController < Spree::StoreController
layout 'darkswarm'
@@ -47,8 +48,6 @@ class CheckoutController < Spree::StoreController
params_adapter = Checkout::FormDataAdapter.new(permitted_params, @order, spree_current_user)
return action_failed unless @order.update(params_adapter.params[:order])
- fire_event('spree.checkout.update')
-
checkout_workflow(params_adapter.shipping_method_id)
rescue Spree::Core::GatewayError => e
rescue_from_spree_gateway_error(e)
@@ -150,7 +149,7 @@ class CheckoutController < Spree::StoreController
def handle_redirect_from_stripe
if OrderWorkflow.new(@order).next && order_complete?
checkout_succeeded
- redirect_to(order_path(@order)) && return
+ redirect_to(spree.order_path(@order)) && return
else
checkout_failed
end
@@ -210,10 +209,10 @@ class CheckoutController < Spree::StoreController
def update_succeeded_response
respond_to do |format|
format.html do
- respond_with(@order, location: order_path(@order))
+ respond_with(@order, location: spree.order_path(@order))
end
format.json do
- render json: { path: order_path(@order) }, status: :ok
+ render json: { path: spree.order_path(@order) }, status: :ok
end
end
end
diff --git a/app/controllers/spree/admin/general_settings_controller.rb b/app/controllers/spree/admin/general_settings_controller.rb
index dcb360bcc9..73fbe619d3 100644
--- a/app/controllers/spree/admin/general_settings_controller.rb
+++ b/app/controllers/spree/admin/general_settings_controller.rb
@@ -17,7 +17,7 @@ module Spree
end
flash[:success] = Spree.t(:successfully_updated, resource: Spree.t(:general_settings))
- redirect_to edit_admin_general_settings_path
+ redirect_to spree.edit_admin_general_settings_path
end
end
end
diff --git a/app/controllers/spree/admin/image_settings_controller.rb b/app/controllers/spree/admin/image_settings_controller.rb
deleted file mode 100644
index 476dd401a8..0000000000
--- a/app/controllers/spree/admin/image_settings_controller.rb
+++ /dev/null
@@ -1,79 +0,0 @@
-module Spree
- module Admin
- class ImageSettingsController < Spree::Admin::BaseController
- def edit
- @styles = ActiveSupport::JSON.decode(Spree::Config[:attachment_styles])
- @headers = ActiveSupport::JSON.decode(Spree::Config[:s3_headers])
- end
-
- def update
- update_styles(params)
- update_headers(params) if Spree::Config[:use_s3]
-
- Spree::Config.set(params[:preferences])
- update_paperclip_settings
-
- respond_to do |format|
- format.html {
- flash[:success] = Spree.t(:image_settings_updated)
- redirect_to spree.edit_admin_image_settings_path
- }
- end
- end
-
- private
-
- def update_styles(params)
- if params[:new_attachment_styles].present?
- params[:new_attachment_styles].each do |_index, style|
- params[:attachment_styles][style[:name]] = style[:value] if style[:value].present?
- end
- end
-
- styles = params[:attachment_styles]
-
- Spree::Config[:attachment_styles] = ActiveSupport::JSON.encode(styles) unless styles.nil?
- end
-
- def update_headers(params)
- if params[:new_s3_headers].present?
- params[:new_s3_headers].each do |_index, header|
- params[:s3_headers][header[:name]] = header[:value] if header[:value].present?
- end
- end
-
- headers = params[:s3_headers]
-
- Spree::Config[:s3_headers] = ActiveSupport::JSON.encode(headers) unless headers.nil?
- end
-
- def update_paperclip_settings
- if Spree::Config[:use_s3]
- s3_creds = { access_key_id: Spree::Config[:s3_access_key],
- secret_access_key: Spree::Config[:s3_secret],
- bucket: Spree::Config[:s3_bucket] }
- Spree::Image.attachment_definitions[:attachment][:storage] = :s3
- Spree::Image.attachment_definitions[:attachment][:s3_credentials] = s3_creds
- Spree::Image.attachment_definitions[:attachment][:s3_headers] =
- ActiveSupport::JSON.decode(Spree::Config[:s3_headers])
- Spree::Image.attachment_definitions[:attachment][:bucket] = Spree::Config[:s3_bucket]
- else
- Spree::Image.attachment_definitions[:attachment].delete :storage
- end
-
- Spree::Image.attachment_definitions[:attachment][:styles] =
- ActiveSupport::JSON.decode(Spree::Config[:attachment_styles]).symbolize_keys!
- Spree::Image.attachment_definitions[:attachment][:path] = Spree::Config[:attachment_path]
- Spree::Image.attachment_definitions[:attachment][:default_url] =
- Spree::Config[:attachment_default_url]
- Spree::Image.attachment_definitions[:attachment][:default_style] =
- Spree::Config[:attachment_default_style]
-
- # 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.
- Spree::Image.reformat_styles
- end
- end
- end
-end
diff --git a/app/controllers/spree/admin/images_controller.rb b/app/controllers/spree/admin/images_controller.rb
index c73e4e6826..b16e643508 100644
--- a/app/controllers/spree/admin/images_controller.rb
+++ b/app/controllers/spree/admin/images_controller.rb
@@ -61,7 +61,7 @@ module Spree
private
def location_after_save
- admin_product_images_url(@product)
+ spree.admin_product_images_url(@product)
end
def load_data
diff --git a/app/controllers/spree/admin/mail_methods_controller.rb b/app/controllers/spree/admin/mail_methods_controller.rb
index 70d573f319..d3618488ed 100644
--- a/app/controllers/spree/admin/mail_methods_controller.rb
+++ b/app/controllers/spree/admin/mail_methods_controller.rb
@@ -23,7 +23,7 @@ module Spree
rescue StandardError => e
flash[:error] = Spree.t('admin.mail_methods.testmail.error') % { e: e }
ensure
- redirect_to edit_admin_mail_methods_url
+ redirect_to spree.edit_admin_mail_methods_url
end
private
diff --git a/app/controllers/spree/admin/orders/customer_details_controller.rb b/app/controllers/spree/admin/orders/customer_details_controller.rb
index 8ad0c7ea28..56502d54a0 100644
--- a/app/controllers/spree/admin/orders/customer_details_controller.rb
+++ b/app/controllers/spree/admin/orders/customer_details_controller.rb
@@ -27,7 +27,7 @@ module Spree
@order.shipments.map(&:refresh_rates)
flash[:success] = Spree.t('customer_details_updated')
- redirect_to admin_order_customer_path(@order)
+ redirect_to spree.admin_order_customer_path(@order)
else
render action: :edit
end
diff --git a/app/controllers/spree/admin/orders_controller.rb b/app/controllers/spree/admin/orders_controller.rb
index 0e3b28d630..56dc8b0ed7 100644
--- a/app/controllers/spree/admin/orders_controller.rb
+++ b/app/controllers/spree/admin/orders_controller.rb
@@ -29,7 +29,7 @@ module Spree
@order = Order.create
@order.created_by = spree_current_user
@order.save
- redirect_to edit_admin_order_url(@order)
+ redirect_to spree.edit_admin_order_url(@order)
end
def edit
@@ -48,16 +48,16 @@ module Spree
if @order.line_items.empty?
@order.errors.add(:line_items, Spree.t('errors.messages.blank'))
end
- return redirect_to(edit_admin_order_path(@order),
+ return redirect_to(spree.edit_admin_order_path(@order),
flash: { error: @order.errors.full_messages.join(', ') })
end
@order.update!
if @order.complete?
- redirect_to edit_admin_order_path(@order)
+ redirect_to spree.edit_admin_order_path(@order)
else
# Jump to next step if order is not complete
- redirect_to admin_order_customer_path(@order)
+ redirect_to spree.admin_order_customer_path(@order)
end
end
@@ -91,7 +91,9 @@ module Spree
Spree::OrderMailer.invoice_email(@order.id, pdf).deliver
flash[:success] = t('admin.orders.invoice_email_sent')
- respond_with(@order) { |format| format.html { redirect_to edit_admin_order_path(@order) } }
+ respond_with(@order) { |format|
+ format.html { redirect_to spree.edit_admin_order_path(@order) }
+ }
end
def print
@@ -131,7 +133,9 @@ module Spree
flash[:error] = t(:must_have_valid_business_number,
enterprise_name: @order.distributor.name)
- respond_with(@order) { |format| format.html { redirect_to edit_admin_order_path(@order) } }
+ respond_with(@order) { |format|
+ format.html { redirect_to spree.edit_admin_order_path(@order) }
+ }
end
def load_distribution_choices
diff --git a/app/controllers/spree/admin/payment_methods_controller.rb b/app/controllers/spree/admin/payment_methods_controller.rb
index 950b97340b..72408fef26 100644
--- a/app/controllers/spree/admin/payment_methods_controller.rb
+++ b/app/controllers/spree/admin/payment_methods_controller.rb
@@ -22,7 +22,7 @@ module Spree
if @payment_method.save
invoke_callbacks(:create, :after)
flash[:success] = Spree.t(:successfully_created, resource: Spree.t(:payment_method))
- redirect_to edit_admin_payment_method_path(@payment_method)
+ redirect_to spree.edit_admin_payment_method_path(@payment_method)
else
invoke_callbacks(:create, :fails)
respond_with(@payment_method)
@@ -43,7 +43,7 @@ module Spree
if @payment_method.update(params_for_update)
invoke_callbacks(:update, :after)
flash[:success] = Spree.t(:successfully_updated, resource: Spree.t(:payment_method))
- redirect_to edit_admin_payment_method_path(@payment_method)
+ redirect_to spree.edit_admin_payment_method_path(@payment_method)
else
invoke_callbacks(:update, :fails)
respond_with(@payment_method)
@@ -122,7 +122,7 @@ module Spree
return if valid_payment_methods.include?(params[:payment_method][:type])
flash[:error] = Spree.t(:invalid_payment_provider)
- redirect_to new_admin_payment_method_path
+ redirect_to spree.new_admin_payment_method_path
end
def load_hubs
diff --git a/app/controllers/spree/admin/payments_controller.rb b/app/controllers/spree/admin/payments_controller.rb
index bfdb4fd2ff..0b5732caa1 100644
--- a/app/controllers/spree/admin/payments_controller.rb
+++ b/app/controllers/spree/admin/payments_controller.rb
@@ -12,7 +12,7 @@ module Spree
def index
@payments = @order.payments
- redirect_to new_admin_order_payment_url(@order) if @payments.empty?
+ redirect_to spree.new_admin_order_payment_url(@order) if @payments.empty?
end
def new
@@ -25,7 +25,7 @@ module Spree
begin
unless @payment.save
- redirect_to admin_order_payments_path(@order)
+ redirect_to spree.admin_order_payments_path(@order)
return
end
@@ -35,16 +35,16 @@ module Spree
@payment.process!
flash[:success] = flash_message_for(@payment, :successfully_created)
- redirect_to admin_order_payments_path(@order)
+ redirect_to spree.admin_order_payments_path(@order)
else
OrderWorkflow.new(@order).complete!
flash[:success] = Spree.t(:new_order_completed)
- redirect_to edit_admin_order_url(@order)
+ redirect_to spree.edit_admin_order_url(@order)
end
rescue Spree::Core::GatewayError => e
flash[:error] = e.message.to_s
- redirect_to new_admin_order_payment_path(@order)
+ redirect_to spree.new_admin_order_payment_path(@order)
end
end
@@ -118,7 +118,7 @@ module Spree
return if @order.payment? || @order.complete?
flash[:notice] = Spree.t(:fill_in_customer_info)
- redirect_to edit_admin_order_customer_url(@order)
+ redirect_to spree.edit_admin_order_customer_url(@order)
end
def load_order
diff --git a/app/controllers/spree/admin/products_controller.rb b/app/controllers/spree/admin/products_controller.rb
index 0556c25a1a..42d4006680 100644
--- a/app/controllers/spree/admin/products_controller.rb
+++ b/app/controllers/spree/admin/products_controller.rb
@@ -29,9 +29,9 @@ module Spree
if @object.save
flash[:success] = flash_message_for(@object, :successfully_created)
if params[:button] == "add_another"
- redirect_to new_admin_product_path
+ redirect_to spree.new_admin_product_path
else
- redirect_to admin_products_path
+ redirect_to spree.admin_products_path
end
else
render :new
@@ -70,7 +70,7 @@ module Spree
flash[:success] = flash_message_for(@object, :successfully_updated)
end
- redirect_to edit_admin_product_url(@object, @url_filters)
+ redirect_to spree.edit_admin_product_url(@object, @url_filters)
end
end
@@ -97,7 +97,7 @@ module Spree
Spree.t('notice_messages.product_not_cloned')
end
- redirect_to edit_admin_product_url(@new)
+ redirect_to spree.edit_admin_product_url(@new)
end
def group_buy_options
diff --git a/app/controllers/spree/admin/shipping_methods_controller.rb b/app/controllers/spree/admin/shipping_methods_controller.rb
index b91f8432a9..14f7654177 100644
--- a/app/controllers/spree/admin/shipping_methods_controller.rb
+++ b/app/controllers/spree/admin/shipping_methods_controller.rb
@@ -74,7 +74,7 @@ module Spree
end
def location_after_save
- edit_admin_shipping_method_path(@shipping_method)
+ spree.edit_admin_shipping_method_path(@shipping_method)
end
def load_data
diff --git a/app/controllers/spree/admin/states_controller.rb b/app/controllers/spree/admin/states_controller.rb
index 09d7244439..56f077b0ea 100644
--- a/app/controllers/spree/admin/states_controller.rb
+++ b/app/controllers/spree/admin/states_controller.rb
@@ -14,7 +14,7 @@ module Spree
protected
def location_after_save
- admin_country_states_url(@country)
+ spree.admin_country_states_url(@country)
end
def collection
diff --git a/app/controllers/spree/admin/tax_settings_controller.rb b/app/controllers/spree/admin/tax_settings_controller.rb
index a66ad219ff..8be30677e0 100644
--- a/app/controllers/spree/admin/tax_settings_controller.rb
+++ b/app/controllers/spree/admin/tax_settings_controller.rb
@@ -6,7 +6,7 @@ module Spree
respond_to do |format|
format.html {
- redirect_to edit_admin_tax_settings_path
+ redirect_to spree.edit_admin_tax_settings_path
}
end
end
diff --git a/app/controllers/spree/admin/taxonomies_controller.rb b/app/controllers/spree/admin/taxonomies_controller.rb
index fb735ec4fa..66497eda2a 100644
--- a/app/controllers/spree/admin/taxonomies_controller.rb
+++ b/app/controllers/spree/admin/taxonomies_controller.rb
@@ -11,9 +11,9 @@ module Spree
def location_after_save
if @taxonomy.created_at == @taxonomy.updated_at
- edit_admin_taxonomy_url(@taxonomy)
+ spree.edit_admin_taxonomy_url(@taxonomy)
else
- admin_taxonomies_url
+ spree.admin_taxonomies_url
end
end
diff --git a/app/controllers/spree/admin/taxons_controller.rb b/app/controllers/spree/admin/taxons_controller.rb
index 0b171567d2..1b9b980da2 100644
--- a/app/controllers/spree/admin/taxons_controller.rb
+++ b/app/controllers/spree/admin/taxons_controller.rb
@@ -15,9 +15,9 @@ module Spree
respond_with(@taxon) do |format|
format.html do
if redirect_to @taxonomy
- edit_admin_taxonomy_url(@taxonomy)
+ spree.edit_admin_taxonomy_url(@taxonomy)
else
- admin_taxonomies_url
+ spree.admin_taxonomies_url
end
end
end
@@ -95,7 +95,7 @@ module Spree
end
respond_with(@taxon) do |format|
- format.html { redirect_to edit_admin_taxonomy_url(@taxonomy) }
+ format.html { redirect_to spree.edit_admin_taxonomy_url(@taxonomy) }
format.json { render json: @taxon.to_json }
end
end
diff --git a/app/controllers/spree/admin/users_controller.rb b/app/controllers/spree/admin/users_controller.rb
index e6ffeaa6cd..3241a889f1 100644
--- a/app/controllers/spree/admin/users_controller.rb
+++ b/app/controllers/spree/admin/users_controller.rb
@@ -60,14 +60,14 @@ module Spree
if @user.generate_spree_api_key!
flash[:success] = t('spree.api.key_generated')
end
- redirect_to edit_admin_user_path(@user)
+ redirect_to spree.edit_admin_user_path(@user)
end
def clear_api_key
if @user.clear_spree_api_key!
flash[:success] = t('spree.api.key_cleared')
end
- redirect_to edit_admin_user_path(@user)
+ redirect_to spree.edit_admin_user_path(@user)
end
protected
diff --git a/app/controllers/spree/admin/variants_controller.rb b/app/controllers/spree/admin/variants_controller.rb
index 302b3e62a5..bb1f8284ac 100644
--- a/app/controllers/spree/admin/variants_controller.rb
+++ b/app/controllers/spree/admin/variants_controller.rb
@@ -61,17 +61,21 @@ module Spree
@url_filters = ::ProductFilters.new.extract(request.query_parameters)
@variant = Spree::Variant.find(params[:id])
- flash[:success] = if VariantDeleter.new.delete(@variant)
- Spree.t('notice_messages.variant_deleted')
- else
- Spree.t('notice_messages.variant_not_deleted')
- end
+ flash[:success] = delete_variant
- redirect_to admin_product_variants_url(params[:product_id], @url_filters)
+ redirect_to spree.admin_product_variants_url(params[:product_id], @url_filters)
end
protected
+ def delete_variant
+ if VariantDeleter.new.delete(@variant)
+ Spree.t('notice_messages.variant_deleted')
+ else
+ Spree.t('notice_messages.variant_not_deleted')
+ end
+ end
+
def create_before
option_values = params[:new_variant]
option_values.andand.each_value { |id| @object.option_values << OptionValue.find(id) }
diff --git a/app/controllers/spree/base_controller.rb b/app/controllers/spree/base_controller.rb
index 21a3d6fe5d..b2e4628bc3 100644
--- a/app/controllers/spree/base_controller.rb
+++ b/app/controllers/spree/base_controller.rb
@@ -3,8 +3,8 @@
require 'cancan'
require 'spree/core/controller_helpers/auth'
require 'spree/core/controller_helpers/respond_with'
-require 'spree/core/controller_helpers/common'
require 'spree/core/controller_helpers/ssl'
+require 'spree/core/controller_helpers/common'
module Spree
class BaseController < ApplicationController
diff --git a/app/controllers/spree/credit_cards_controller.rb b/app/controllers/spree/credit_cards_controller.rb
index a1c2e60ea5..9b4c2d971d 100644
--- a/app/controllers/spree/credit_cards_controller.rb
+++ b/app/controllers/spree/credit_cards_controller.rb
@@ -48,10 +48,10 @@ module Spree
else
flash[:error] = I18n.t(:card_could_not_be_removed)
end
- redirect_to account_path(anchor: 'cards')
+ redirect_to spree.account_path(anchor: 'cards')
rescue Stripe::CardError
flash[:error] = I18n.t(:card_could_not_be_removed)
- redirect_to account_path(anchor: 'cards')
+ redirect_to spree.account_path(anchor: 'cards')
end
private
diff --git a/app/controllers/spree/orders_controller.rb b/app/controllers/spree/orders_controller.rb
index 898ec93f99..9703c8def8 100644
--- a/app/controllers/spree/orders_controller.rb
+++ b/app/controllers/spree/orders_controller.rb
@@ -78,11 +78,7 @@ module Spree
discard_empty_line_items
with_open_adjustments { update_totals_and_taxes }
- if @order == current_order
- fire_event('spree.order.contents_changed')
- else
- @order.update_distribution_charge!
- end
+ @order.update_distribution_charge!
respond_with(@order) do |format|
format.html do
@@ -90,7 +86,7 @@ module Spree
@order.next_transition.run_callbacks if @order.cart?
redirect_to checkout_state_path(@order.checkout_steps.first)
elsif @order.complete?
- redirect_to order_path(@order)
+ redirect_to spree.order_path(@order)
else
redirect_to main_app.cart_path
end
@@ -157,7 +153,7 @@ module Spree
else
flash[:error] = I18n.t(:orders_could_not_cancel)
end
- redirect_to request.referer || order_path(@order)
+ redirect_to request.referer || spree.order_path(@order)
end
private
@@ -221,7 +217,7 @@ module Spree
if items.empty?
flash[:error] = I18n.t(:orders_cannot_remove_the_final_item)
- redirect_to order_path(order_to_update)
+ redirect_to spree.order_path(order_to_update)
end
end
diff --git a/app/controllers/spree/user_passwords_controller.rb b/app/controllers/spree/user_passwords_controller.rb
index 4e7fc6e824..6358d16f0b 100644
--- a/app/controllers/spree/user_passwords_controller.rb
+++ b/app/controllers/spree/user_passwords_controller.rb
@@ -7,7 +7,7 @@ require "spree/core/controller_helpers/ssl"
module Spree
class UserPasswordsController < Devise::PasswordsController
- helper 'spree/base', 'spree/store'
+ helper 'spree/base'
include Spree::Core::ControllerHelpers::Auth
include Spree::Core::ControllerHelpers::Common
diff --git a/app/controllers/spree/user_registrations_controller.rb b/app/controllers/spree/user_registrations_controller.rb
index 1a2d740da7..64c3681d81 100644
--- a/app/controllers/spree/user_registrations_controller.rb
+++ b/app/controllers/spree/user_registrations_controller.rb
@@ -7,7 +7,7 @@ require "spree/core/controller_helpers/ssl"
module Spree
class UserRegistrationsController < Devise::RegistrationsController
- helper 'spree/base', 'spree/store'
+ helper 'spree/base'
include Spree::Core::ControllerHelpers::Auth
include Spree::Core::ControllerHelpers::Common
diff --git a/app/controllers/spree/user_sessions_controller.rb b/app/controllers/spree/user_sessions_controller.rb
index c17eafb892..f090a281ca 100644
--- a/app/controllers/spree/user_sessions_controller.rb
+++ b/app/controllers/spree/user_sessions_controller.rb
@@ -7,7 +7,7 @@ require "spree/core/controller_helpers/ssl"
module Spree
class UserSessionsController < Devise::SessionsController
- helper 'spree/base', 'spree/store'
+ helper 'spree/base'
include Spree::Core::ControllerHelpers::Auth
include Spree::Core::ControllerHelpers::Common
diff --git a/app/helpers/admin/image_settings_helper.rb b/app/helpers/admin/image_settings_helper.rb
deleted file mode 100644
index e337161298..0000000000
--- a/app/helpers/admin/image_settings_helper.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-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/spree/user_mailer.rb b/app/mailers/spree/user_mailer.rb
index a93aff05a5..a53db460a0 100644
--- a/app/mailers/spree/user_mailer.rb
+++ b/app/mailers/spree/user_mailer.rb
@@ -8,10 +8,12 @@ module Spree
def reset_password_instructions(user, token, _opts = {})
@edit_password_reset_url = spree.
edit_spree_user_password_url(reset_password_token: token)
+ subject = "#{Spree::Config[:site_name]} " \
+ "#{I18n.t('spree.user_mailer.reset_password_instructions.subject')}"
- mail(to: user.email, from: from_address,
- subject: Spree::Config[:site_name] + ' ' +
- I18n.t(:subject, scope: [:devise, :mailer, :reset_password_instructions]))
+ I18n.with_locale valid_locale(user) do
+ mail(to: user.email, from: from_address, subject: subject)
+ end
end
# This is a OFN specific email, not from Devise::Mailer
diff --git a/app/models/enterprise_group.rb b/app/models/enterprise_group.rb
index 0bf0319bde..5bb20d3821 100644
--- a/app/models/enterprise_group.rb
+++ b/app/models/enterprise_group.rb
@@ -1,5 +1,6 @@
require 'open_food_network/locking'
require 'open_food_network/permalink_generator'
+require 'spree/core/s3_support'
class EnterpriseGroup < ActiveRecord::Base
include PermalinkGenerator
diff --git a/app/models/spree/app_configuration.rb b/app/models/spree/app_configuration.rb
new file mode 100644
index 0000000000..d56ca5a6ac
--- /dev/null
+++ b/app/models/spree/app_configuration.rb
@@ -0,0 +1,148 @@
+# frozen_string_literal: true
+
+# This is the primary location for defining spree preferences
+#
+# This file allows us to add global configuration variables, which
+# we can allow to be modified in the UI by adding appropriate form
+# elements to existing or new configuration pages.
+#
+# The expectation is that this is created once and stored in
+# the spree environment
+#
+# setters:
+# a.color = :blue
+# a[:color] = :blue
+# a.set :color = :blue
+# a.preferred_color = :blue
+#
+# getters:
+# a.color
+# a[:color]
+# a.get :color
+# a.preferred_color
+#
+module Spree
+ class AppConfiguration < Preferences::Configuration
+ # Should state/state_name be required
+ preference :address_requires_state, :boolean, default: true
+ preference :admin_interface_logo, :string, default: 'ofn-logo.png'
+ preference :admin_products_per_page, :integer, default: 10
+ # Should only be true if you don't need to track inventory
+ preference :allow_backorder_shipping, :boolean, default: false
+ preference :allow_checkout_on_gateway_error, :boolean, default: false
+ preference :allow_guest_checkout, :boolean, default: true
+ preference :allow_ssl_in_development_and_test, :boolean, default: false
+ preference :allow_ssl_in_production, :boolean, default: true
+ preference :allow_ssl_in_staging, :boolean, default: true
+ # Automatically capture the credit card (as opposed to just authorize and capture later)
+ preference :auto_capture, :boolean, default: false
+ # Replace with the name of a zone if you would like to limit the countries
+ preference :checkout_zone, :string, default: nil
+ preference :currency, :string, default: "USD"
+ preference :currency_decimal_mark, :string, default: "."
+ preference :currency_symbol_position, :string, default: "before"
+ preference :currency_thousands_separator, :string, default: ","
+ preference :display_currency, :boolean, default: false
+ preference :default_country_id, :integer
+ preference :default_meta_description, :string, default: 'OFN demo site'
+ preference :default_meta_keywords, :string, default: 'ofn, demo'
+ preference :default_seo_title, :string, default: ''
+ preference :hide_cents, :boolean, default: false
+ preference :layout, :string, default: 'darkswarm'
+ preference :logo, :string, default: 'ofn-logo.png'
+
+ # Maximum nesting level in taxons menu
+ preference :max_level_in_taxons_menu, :integer, default: 1
+ preference :orders_per_page, :integer, default: 15
+ preference :prices_inc_tax, :boolean, default: false
+ preference :products_per_page, :integer, default: 12
+ preference :redirect_https_to_http, :boolean, default: false
+ preference :require_master_price, :boolean, default: true
+ preference :shipment_inc_vat, :boolean, default: false
+ # Request instructions/info for shipping
+ preference :shipping_instructions, :boolean, default: false
+ # Displays variant full price or difference with product price.
+ preference :show_variant_full_price, :boolean, default: false
+ preference :show_products_without_price, :boolean, default: false
+ preference :show_raw_product_description, :boolean, default: false
+ preference :site_name, :string, default: 'OFN Demo Site'
+ preference :site_url, :string, default: 'demo.openfoodnetwork.org'
+ preference :tax_using_ship_address, :boolean, default: true
+ # Determines whether to track on_hand values for variants / products.
+ preference :track_inventory_levels, :boolean, default: true
+
+ # Preferences related to image settings
+ preference :attachment_default_url, :string,
+ default: '/spree/products/:id/:style/:basename.:extension'
+ preference :attachment_path, :string,
+ default: ':rails_root/public/spree/products/:id/:style/:basename.:extension'
+ preference :attachment_url, :string,
+ default: '/spree/products/:id/:style/:basename.:extension'
+ preference :attachment_styles, :string,
+ default: "{\"mini\":\"48x48>\",\"small\":\"100x100>\",\"product\":\"240x240>\",\"large\":\"600x600>\"}"
+ preference :attachment_default_style, :string, default: 'product'
+ preference :s3_access_key, :string
+ preference :s3_bucket, :string
+ preference :s3_secret, :string
+ preference :s3_headers, :string, default: "{\"Cache-Control\":\"max-age=31557600\"}"
+ preference :use_s3, :boolean, default: false # Use S3 for images rather than the file system
+ preference :s3_protocol, :string
+ preference :s3_host_alias, :string
+
+ # Default mail headers settings
+ preference :enable_mail_delivery, :boolean, default: false
+ preference :mails_from, :string, default: 'ofn@example.com'
+ preference :mail_bcc, :string, default: 'ofn@example.com'
+ preference :intercept_email, :string, default: nil
+
+ # Default smtp settings
+ preference :override_actionmailer_config, :boolean, default: true
+ preference :mail_host, :string, default: 'localhost'
+ preference :mail_domain, :string, default: 'localhost'
+ preference :mail_port, :integer, default: 25
+ preference :secure_connection_type, :string,
+ default: Core::MailSettings::SECURE_CONNECTION_TYPES[0]
+ preference :mail_auth_type, :string, default: Core::MailSettings::MAIL_AUTH[0]
+ preference :smtp_username, :string
+ preference :smtp_password, :string
+
+ # Embedded Shopfronts
+ preference :enable_embedded_shopfronts, :boolean, default: false
+ preference :embedded_shopfronts_whitelist, :text, default: nil
+
+ # Legal Preferences
+ preference :footer_tos_url, :string, default: "/Terms-of-service.pdf"
+ preference :enterprises_require_tos, :boolean, default: false
+ preference :privacy_policy_url, :string, default: nil
+ preference :cookies_consent_banner_toggle, :boolean, default: false
+ preference :cookies_policy_matomo_section, :boolean, default: false
+
+ # Tax Preferences
+ preference :products_require_tax_category, :boolean, default: false
+ preference :shipping_tax_rate, :decimal, default: 0
+
+ # Monitoring
+ preference :last_job_queue_heartbeat_at, :string, default: nil
+
+ # External services
+ preference :bugherd_api_key, :string, default: nil
+ preference :matomo_url, :string, default: nil
+ preference :matomo_site_id, :string, default: nil
+ preference :matomo_tag_manager_url, :string, default: nil
+
+ # Invoices & Receipts
+ preference :enable_invoices?, :boolean, default: true
+ preference :invoice_style2?, :boolean, default: false
+ preference :enable_receipt_printing?, :boolean, default: false
+
+ # Stripe Connect
+ preference :stripe_connect_enabled, :boolean, default: false
+
+ # Number localization
+ preference :enable_localized_number?, :boolean, default: false
+
+ # Enable cache
+ preference :enable_products_cache?, :boolean,
+ default: (Rails.env.production? || Rails.env.staging?)
+ end
+end
diff --git a/app/models/spree/app_configuration_decorator.rb b/app/models/spree/app_configuration_decorator.rb
deleted file mode 100644
index a039ddbd45..0000000000
--- a/app/models/spree/app_configuration_decorator.rb
+++ /dev/null
@@ -1,44 +0,0 @@
-Spree::AppConfiguration.class_eval do
- # This file decorates the existing preferences file defined by Spree.
- # It allows us to add our own global configuration variables, which
- # we can allow to be modified in the UI by adding appropriate form
- # elements to existing or new configuration pages.
-
- # Embedded Shopfronts
- preference :enable_embedded_shopfronts, :boolean, default: false
- preference :embedded_shopfronts_whitelist, :text, default: nil
-
- # Legal Preferences
- preference :footer_tos_url, :string, default: "/Terms-of-service.pdf"
- preference :enterprises_require_tos, :boolean, default: false
- preference :privacy_policy_url, :string, default: nil
- preference :cookies_consent_banner_toggle, :boolean, default: false
- preference :cookies_policy_matomo_section, :boolean, default: false
-
- # Tax Preferences
- preference :products_require_tax_category, :boolean, default: false
- preference :shipping_tax_rate, :decimal, default: 0
-
- # Monitoring
- preference :last_job_queue_heartbeat_at, :string, default: nil
-
- # External services
- preference :bugherd_api_key, :string, default: nil
- preference :matomo_url, :string, default: nil
- preference :matomo_site_id, :string, default: nil
- preference :matomo_tag_manager_url, :string, default: nil
-
- # Invoices & Receipts
- preference :enable_invoices?, :boolean, default: true
- preference :invoice_style2?, :boolean, default: false
- preference :enable_receipt_printing?, :boolean, default: false
-
- # Stripe Connect
- preference :stripe_connect_enabled, :boolean, default: false
-
- # Number localization
- preference :enable_localized_number?, :boolean, default: false
-
- # Enable cache
- preference :enable_products_cache?, :boolean, default: (Rails.env.production? || Rails.env.staging?)
-end
diff --git a/app/models/spree/gateway.rb b/app/models/spree/gateway.rb
index 99d57826fb..4b7533c2d8 100644
--- a/app/models/spree/gateway.rb
+++ b/app/models/spree/gateway.rb
@@ -1,5 +1,8 @@
# frozen_string_literal: true
+require 'concerns/payment_method_distributors'
+require 'spree/core/delegate_belongs_to'
+
module Spree
class Gateway < PaymentMethod
include PaymentMethodDistributors
diff --git a/app/models/spree/image.rb b/app/models/spree/image.rb
index 3ece2769aa..c42d147ca0 100644
--- a/app/models/spree/image.rb
+++ b/app/models/spree/image.rb
@@ -5,13 +5,19 @@ module Spree
validates_attachment_presence :attachment
validate :no_attachment_errors
+ # This is where the styles are used in the app:
+ # - mini: used in the BackOffice: Bulk Product Edit page and Order Cycle edit page
+ # - small: used in the FrontOffice: Product List page
+ # - product: used in the BackOffice: Product Image upload modal in the Bulk Product Edit page
+ # and Product image edit page
+ # - large: used in the FrontOffice: product modal
has_attached_file :attachment,
- styles: { mini: '48x48>', small: '100x100>',
- product: '240x240>', large: '600x600>' },
+ styles: { mini: "48x48#", small: "227x227#",
+ product: "240x240>", large: "600x600>" },
default_style: :product,
url: '/spree/products/:id/:style/:basename.:extension',
path: ':rails_root/public/spree/products/:id/:style/:basename.:extension',
- convert_options: { all: '-strip -auto-orient -colorspace RGB' }
+ convert_options: { all: '-strip -auto-orient -colorspace sRGB' }
# save the w,h of the original image (from which others can be calculated)
# we need to look at the write-queue for images which have not been saved yet
@@ -20,15 +26,6 @@ module Spree
include Spree::Core::S3Support
supports_s3 :attachment
- Spree::Image.attachment_definitions[:attachment][:styles] =
- ActiveSupport::JSON.decode(Spree::Config[:attachment_styles]).symbolize_keys!
- Spree::Image.attachment_definitions[:attachment][:path] = Spree::Config[:attachment_path]
- Spree::Image.attachment_definitions[:attachment][:url] = Spree::Config[:attachment_url]
- Spree::Image.attachment_definitions[:attachment][:default_url] =
- Spree::Config[:attachment_default_url]
- Spree::Image.attachment_definitions[:attachment][:default_style] =
- Spree::Config[:attachment_default_style]
-
# used by admin products autocomplete
def mini_url
attachment.url(:mini, false)
@@ -51,26 +48,26 @@ module Spree
false
end
- # 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]
+ def self.set_attachment_attributes(attribute_name, attribute_value)
+ attachment_definitions[:attachment][attribute_name] = attribute_value
+ end
+
+ def self.set_s3_attachment_definitions
+ if Spree::Config[:use_s3]
+ set_attachment_attributes(:storage, :s3)
+ set_attachment_attributes(:s3_credentials, s3_credentials)
+ set_attachment_attributes(:s3_headers,
+ ActiveSupport::JSON.decode(Spree::Config[:s3_headers]))
+ set_attachment_attributes(:bucket, Spree::Config[:s3_bucket])
+ else
+ attachment_definitions[:attachment].delete :storage
end
-
- Hash[styles_a]
end
- def self.reformat_styles
- Spree::Image.attachment_definitions[:attachment][:styles] =
- format_styles(Spree::Image.attachment_definitions[:attachment][:styles])
+ def self.s3_credentials
+ { access_key_id: Spree::Config[:s3_access_key],
+ secret_access_key: Spree::Config[:s3_secret],
+ bucket: Spree::Config[:s3_bucket] }
end
-
- reformat_styles
end
end
diff --git a/app/models/spree/order.rb b/app/models/spree/order.rb
index 00dfb64d4f..c2a0a98582 100644
--- a/app/models/spree/order.rb
+++ b/app/models/spree/order.rb
@@ -6,11 +6,6 @@ require 'open_food_network/feature_toggle'
require 'open_food_network/tag_rule_applicator'
require 'concerns/order_shipment'
-ActiveSupport::Notifications
- .subscribe('spree.order.contents_changed') do |_name, _start, _finish, _id, payload|
- payload[:order].reload.update_distribution_charge!
-end
-
module Spree
class Order < ActiveRecord::Base
prepend OrderShipment
diff --git a/app/models/spree/payment_method.rb b/app/models/spree/payment_method.rb
index 9c41fbefa2..a521122d67 100644
--- a/app/models/spree/payment_method.rb
+++ b/app/models/spree/payment_method.rb
@@ -1,5 +1,8 @@
# frozen_string_literal: true
+require 'concerns/payment_method_distributors'
+require 'spree/core/calculated_adjustments'
+
module Spree
class PaymentMethod < ActiveRecord::Base
include Spree::Core::CalculatedAdjustments
@@ -99,7 +102,7 @@ module Spree
self.class.include Spree::Core::CalculatedAdjustments
end
- self.calculator ||= Calculator::FlatRate.new(preferred_amount: 0)
+ self.calculator ||= ::Calculator::FlatRate.new(preferred_amount: 0)
end
def has_distributor?(distributor)
diff --git a/app/models/spree/preference.rb b/app/models/spree/preference.rb
new file mode 100644
index 0000000000..b877f460ce
--- /dev/null
+++ b/app/models/spree/preference.rb
@@ -0,0 +1,42 @@
+# frozen_string_literal: true
+
+module Spree
+ class Preference < ActiveRecord::Base
+ serialize :value
+
+ validates :key, presence: true
+ validates :value_type, presence: true
+
+ scope :valid, -> {
+ where(Spree::Preference.arel_table[:key].not_eq(nil)).
+ where(Spree::Preference.arel_table[:value_type].not_eq(nil))
+ }
+
+ # The type conversions here should match
+ # the ones in spree::preferences::preferrable#convert_preference_value
+ def value
+ if self[:value_type].present?
+ case self[:value_type].to_sym
+ when :string, :text
+ self[:value].to_s
+ when :password
+ self[:value].to_s
+ when :decimal
+ BigDecimal(self[:value].to_s).round(2, BigDecimal::ROUND_HALF_UP)
+ when :integer
+ self[:value].to_i
+ when :boolean
+ !(self[:value].to_s =~ /^[t|1]/i).nil?
+ else
+ self[:value].is_a?(String) ? YAML.safe_load(self[:value]) : self[:value]
+ end
+ else
+ self[:value]
+ end
+ end
+
+ def raw_value
+ self[:value]
+ end
+ end
+end
diff --git a/app/models/spree/preferences/configuration.rb b/app/models/spree/preferences/configuration.rb
new file mode 100644
index 0000000000..d1a514484d
--- /dev/null
+++ b/app/models/spree/preferences/configuration.rb
@@ -0,0 +1,74 @@
+# frozen_string_literal: true
+
+# This takes the preferrable methods and adds some
+# syntatic sugar to access the preferences
+#
+# class App < Configuration
+# preference :color, :string
+# end
+#
+# a = App.new
+#
+# setters:
+# a.color = :blue
+# a[:color] = :blue
+# a.set :color = :blue
+# a.preferred_color = :blue
+#
+# getters:
+# a.color
+# a[:color]
+# a.get :color
+# a.preferred_color
+#
+#
+module Spree
+ module Preferences
+ class Configuration
+ include Spree::Preferences::Preferable
+
+ def configure
+ yield(self) if block_given?
+ end
+
+ def preference_cache_key(name)
+ [ENV['RAILS_CACHE_ID'], self.class.name, name].flatten.join('::').underscore
+ end
+
+ def reset
+ preferences.each do |name, _value|
+ set_preference name, preference_default(name)
+ end
+ end
+
+ alias :[] :get_preference
+ alias :[]= :set_preference
+
+ alias :get :get_preference
+
+ def set(*args)
+ options = args.extract_options!
+ options.each do |name, value|
+ set_preference name, value
+ end
+
+ return unless args.size == 2
+
+ set_preference args[0], args[1]
+ end
+
+ def method_missing(method, *args)
+ name = method.to_s.gsub('=', '')
+ if has_preference? name
+ if method.to_s =~ /=$/
+ set_preference(name, args.first)
+ else
+ get_preference name
+ end
+ else
+ super
+ end
+ end
+ end
+ end
+end
diff --git a/app/models/spree/preferences/preferable.rb b/app/models/spree/preferences/preferable.rb
new file mode 100644
index 0000000000..76f4e6aad7
--- /dev/null
+++ b/app/models/spree/preferences/preferable.rb
@@ -0,0 +1,138 @@
+# frozen_string_literal: true
+
+# The preference_cache_key is used to determine if the preference
+# can be set. The default behavior is to return nil if there is no
+# id value. On ActiveRecords, new objects will have their preferences
+# saved to a pending hash until it is persisted.
+#
+# class_attributes are inheritied unless you reassign them in
+# the subclass, so when you inherit a Preferable class, the
+# inherited hook will assign a new hash for the subclass definitions
+# and copy all the definitions allowing the subclass to add
+# additional defintions without affecting the base
+module Spree
+ module Preferences
+ module Preferable
+ def self.included(base)
+ base.class_eval do
+ extend Spree::Preferences::PreferableClassMethods
+
+ if respond_to?(:after_create)
+ after_create do |obj|
+ obj.save_pending_preferences
+ end
+ end
+
+ if respond_to?(:after_destroy)
+ after_destroy do |obj|
+ obj.clear_preferences
+ end
+ end
+ end
+ end
+
+ def get_preference(name)
+ has_preference! name
+ __send__ self.class.preference_getter_method(name)
+ end
+ alias :preferred :get_preference
+ alias :prefers? :get_preference
+
+ def set_preference(name, value)
+ has_preference! name
+ __send__ self.class.preference_setter_method(name), value
+ end
+
+ def preference_type(name)
+ has_preference! name
+ __send__ self.class.preference_type_getter_method(name)
+ end
+
+ def preference_default(name)
+ has_preference! name
+ __send__ self.class.preference_default_getter_method(name)
+ end
+
+ def preference_description(name)
+ has_preference! name
+ __send__ self.class.preference_description_getter_method(name)
+ end
+
+ def has_preference!(name)
+ raise NoMethodError, "#{name} preference not defined" unless has_preference? name
+ end
+
+ def has_preference?(name)
+ respond_to? self.class.preference_getter_method(name)
+ end
+
+ def preferences
+ prefs = {}
+ methods.grep(/^prefers_.*\?$/).each do |pref_method|
+ prefs[pref_method.to_s.gsub(/prefers_|\?/, '').to_sym] = __send__(pref_method)
+ end
+ prefs
+ end
+
+ def preference_cache_key(name)
+ return unless id
+
+ [ENV["RAILS_CACHE_ID"], self.class.name, name, id].join('::').underscore
+ end
+
+ def save_pending_preferences
+ return unless @pending_preferences
+
+ @pending_preferences.each do |name, value|
+ set_preference(name, value)
+ end
+ end
+
+ def clear_preferences
+ preferences.keys.each { |pref| preference_store.delete preference_cache_key(pref) }
+ end
+
+ private
+
+ def add_pending_preference(name, value)
+ @pending_preferences ||= {}
+ @pending_preferences[name] = value
+ end
+
+ def get_pending_preference(name)
+ return unless @pending_preferences
+
+ @pending_preferences[name]
+ end
+
+ def convert_preference_value(value, type)
+ case type
+ when :string, :text
+ value.to_s
+ when :password
+ value.to_s
+ when :decimal
+ BigDecimal(value.to_s).round(2, BigDecimal::ROUND_HALF_UP)
+ when :integer
+ value.to_i
+ when :boolean
+ if value.is_a?(FalseClass) ||
+ value.nil? ||
+ value == 0 ||
+ value =~ /^(f|false|0)$/i ||
+ (value.respond_to?(:empty?) && value.empty?)
+ false
+ else
+ true
+ end
+ else
+ value
+ end
+ end
+
+ def preference_store
+ Spree::Preferences::Store.instance
+ end
+ end
+ end
+end
diff --git a/app/models/spree/preferences/preferable_class_methods.rb b/app/models/spree/preferences/preferable_class_methods.rb
new file mode 100644
index 0000000000..dd9369d3a0
--- /dev/null
+++ b/app/models/spree/preferences/preferable_class_methods.rb
@@ -0,0 +1,101 @@
+# frozen_string_literal: true
+
+module Spree
+ module Preferences
+ module PreferableClassMethods
+ def preference(name, type, *args)
+ options = args.extract_options!
+ options.assert_valid_keys(:default, :description)
+ default = options[:default]
+ description = options[:description] || name
+
+ # cache_key will be nil for new objects, then if we check if there
+ # is a pending preference before going to default
+ define_method preference_getter_method(name) do
+ # perference_cache_key will only be nil/false for new records
+ #
+ if preference_cache_key(name)
+ preference_store.get(preference_cache_key(name), default)
+ else
+ get_pending_preference(name) || default
+ end
+ end
+ alias_method prefers_getter_method(name), preference_getter_method(name)
+
+ define_method preference_setter_method(name) do |value|
+ value = convert_preference_value(value, type)
+ if preference_cache_key(name)
+ preference_store.set preference_cache_key(name), value, type
+ else
+ add_pending_preference(name, value)
+ end
+ end
+ alias_method prefers_setter_method(name), preference_setter_method(name)
+
+ define_method preference_default_getter_method(name) do
+ default
+ end
+
+ define_method preference_type_getter_method(name) do
+ type
+ end
+
+ define_method preference_description_getter_method(name) do
+ description
+ end
+ end
+
+ def remove_preference(name)
+ if method_defined? preference_getter_method(name)
+ remove_method preference_getter_method(name)
+ end
+ if method_defined? preference_setter_method(name)
+ remove_method preference_setter_method(name)
+ end
+ if method_defined? prefers_getter_method(name)
+ remove_method prefers_getter_method(name)
+ end
+ if method_defined? prefers_setter_method(name)
+ remove_method prefers_setter_method(name)
+ end
+ if method_defined? preference_default_getter_method(name)
+ remove_method preference_default_getter_method(name)
+ end
+ if method_defined? preference_type_getter_method(name)
+ remove_method preference_type_getter_method(name)
+ end
+ if method_defined? preference_description_getter_method(name)
+ remove_method preference_description_getter_method(name)
+ end
+ end
+
+ def preference_getter_method(name)
+ "preferred_#{name}".to_sym
+ end
+
+ def preference_setter_method(name)
+ "preferred_#{name}=".to_sym
+ end
+
+ def prefers_getter_method(name)
+ "prefers_#{name}?".to_sym
+ end
+
+ def prefers_setter_method(name)
+ "prefers_#{name}=".to_sym
+ end
+
+ def preference_default_getter_method(name)
+ "preferred_#{name}_default".to_sym
+ end
+
+ def preference_type_getter_method(name)
+ "preferred_#{name}_type".to_sym
+ end
+
+ def preference_description_getter_method(name)
+ "preferred_#{name}_description".to_sym
+ end
+ end
+ end
+end
diff --git a/app/models/spree/preferences/store.rb b/app/models/spree/preferences/store.rb
new file mode 100644
index 0000000000..cb30d31eaa
--- /dev/null
+++ b/app/models/spree/preferences/store.rb
@@ -0,0 +1,99 @@
+# frozen_string_literal: true
+
+# Use singleton class Spree::Preferences::Store.instance to access
+#
+# StoreInstance has a persistence flag that is on by default,
+# but we disable database persistence in testing to speed up tests
+#
+
+require 'singleton'
+
+module Spree
+ module Preferences
+ class StoreInstance
+ attr_accessor :persistence
+
+ def initialize
+ @cache = Rails.cache
+ @persistence = true
+ end
+
+ def set(key, value, type)
+ @cache.write(key, value)
+ persist(key, value, type)
+ end
+
+ def exist?(key)
+ @cache.exist?(key) ||
+ should_persist? && Spree::Preference.where(key: key).exists?
+ end
+
+ def get(key, fallback = nil)
+ # return the retrieved value, if it's in the cache
+ # use unless nil? incase the value is actually boolean false
+ #
+ unless (val = @cache.read(key)).nil?
+ return val
+ end
+
+ if should_persist?
+ # If it's not in the cache, maybe it's in the database, but
+ # has been cleared from the cache
+
+ # does it exist in the database?
+ if Spree::Preference.table_exists? && preference = Spree::Preference.find_by(key: key)
+ # it does exist, so let's put it back into the cache
+ @cache.write(preference.key, preference.value)
+
+ # and return the value
+ return preference.value
+ end
+ end
+
+ unless fallback.nil?
+ # cache fallback so we won't hit the db above on
+ # subsequent queries for the same key
+ #
+ @cache.write(key, fallback)
+ end
+
+ fallback
+ end
+
+ def delete(key)
+ @cache.delete(key)
+ destroy(key)
+ end
+
+ def clear_cache
+ @cache.clear
+ end
+
+ private
+
+ def persist(cache_key, value, type)
+ return unless should_persist?
+
+ preference = Spree::Preference.where(key: cache_key).first_or_initialize
+ preference.value = value
+ preference.value_type = type
+ preference.save
+ end
+
+ def destroy(cache_key)
+ return unless should_persist?
+
+ preference = Spree::Preference.find_by(key: cache_key)
+ preference&.destroy
+ end
+
+ def should_persist?
+ @persistence && Spree::Preference.connected? && Spree::Preference.table_exists?
+ end
+ end
+
+ class Store < StoreInstance
+ include Singleton
+ end
+ end
+end
diff --git a/app/serializers/api/product_serializer.rb b/app/serializers/api/product_serializer.rb
index 733904c5b6..9223a797d8 100644
--- a/app/serializers/api/product_serializer.rb
+++ b/app/serializers/api/product_serializer.rb
@@ -18,7 +18,7 @@ class Api::ProductSerializer < ActiveModel::Serializer
# return an unformatted descripton
def description
- strip_tags object.description
+ strip_tags object.description&.strip
end
# return a sanitized html description
diff --git a/app/views/shop/products/_form.html.haml b/app/views/shop/products/_form.html.haml
index ffbc7bdf25..9506cd4bcd 100644
--- a/app/views/shop/products/_form.html.haml
+++ b/app/views/shop/products/_form.html.haml
@@ -4,26 +4,39 @@
= render partial: "shop/products/searchbar"
.row
- .small-12.columns
- .footer-pad.small-12.columns.no-gutter
- .row
- .medium-12.large-10.columns
- = render partial: "shop/products/search_feedback"
+ .footer-pad.small-12.columns.product-listing
+ .row.full
+ .medium-12.large-9.columns.full
+ = render partial: "shop/products/search_feedback"
- %div.pad-top{ "infinite-scroll" => "loadMore()", "infinite-scroll-distance" => "1", "infinite-scroll-disabled" => 'Products.loading' }
- %product.animate-repeat{"ng-controller" => "ProductNodeCtrl", "ng-repeat" => "product in Products.products track by product.id", "id" => "product-{{ product.id }}"}
- = render "shop/products/summary"
+ %div.pad-top{ "infinite-scroll" => "loadMore()", "infinite-scroll-distance" => "1", "infinite-scroll-disabled" => 'Products.loading' }
+ %product.animate-repeat{"ng-controller" => "ProductNodeCtrl", "ng-repeat" => "product in Products.products track by product.id", "id" => "product-{{ product.id }}"}
+ = render "shop/products/summary"
+ .shop-variants
%shop-variant{variant: 'variant', "ng-repeat" => "variant in product.variants | orderBy: ['name_to_display','unit_value'] track by variant.id", "id" => "variant-{{ variant.id }}", "ng-class" => "{'out-of-stock': !variant.on_demand && variant.on_hand == 0}"}
- %product{"ng-show" => "Products.loading"}
- .row.summary
- .small-12.columns.text-center
- = t :products_loading
- .row
- .small-12.columns.text-center
- %img.spinner{ src: image_path("spinning-circles.svg") }
+ %product{"ng-show" => "Products.loading"}
+ .summary
+ .small-12.columns.text-center
+ = t :products_loading
+ .row.full
+ .small-12.columns.text-center
+ %img.spinner{ src: image_path("spinning-circles.svg") }
- .hide-for-medium-down.large-2.columns
+ .hide-for-medium-down.large-1.columns
+ -# Space between products and filters
+
+ .hide-for-medium-down.large-2.columns
+ %h5.filter-header
+ = t(:products_filter_by)
+ %span{ng: {show: 'filtersCount()' }}
+ = "({{ filtersCount() }} #{t(:products_filter_selected)})"
+
+ = render partial: "shop/products/filters"
+
+ .expanding-sidebar.shop-filters-sidebar.hide-for-large-up{ng: {show: 'showFilterSidebar', class: "{'shown': showFilterSidebar}"}}
+ .background{ng: {click: 'toggleFilterSidebar()'}}
+ .sidebar
%h5
= t(:products_filter_by)
%span{ng: {show: 'filtersCount()' }}
@@ -31,18 +44,8 @@
= render partial: "shop/products/filters"
- .expanding-sidebar.shop-filters-sidebar.hide-for-large-up{ng: {show: 'showFilterSidebar', class: "{'shown': showFilterSidebar}"}}
- .background{ng: {click: 'toggleFilterSidebar()'}}
- .sidebar
- %h5
- = t(:products_filter_by)
- %span{ng: {show: 'filtersCount()' }}
- = "({{ filtersCount() }} #{t(:products_filter_selected)})"
-
- = render partial: "shop/products/filters"
-
- .sidebar-footer
- %button.large.dark.left{type: 'button', ng: {click: 'clearFilters()'}}
- = t(:products_filter_clear)
- %button.large.bright.right{type: 'button', ng: {click: 'toggleFilterSidebar()'}}
- = t(:products_filter_done)
+ .sidebar-footer
+ %button.large.dark.left{type: 'button', ng: {click: 'clearFilters()'}}
+ = t(:products_filter_clear)
+ %button.large.bright.right{type: 'button', ng: {click: 'toggleFilterSidebar()'}}
+ = t(:products_filter_done)
diff --git a/app/views/shop/products/_summary.html.haml b/app/views/shop/products/_summary.html.haml
index 3c12a68db8..c87d26ff46 100644
--- a/app/views/shop/products/_summary.html.haml
+++ b/app/views/shop/products/_summary.html.haml
@@ -1,20 +1,20 @@
.product-thumb
%a{"ng-click" => "triggerProductModal()"}
- %i.ofn-i_057-expand
- %img{"ng-src" => "{{::product.primaryImageOrMissing}}", "ng-click" => "triggerProductModal()"}
+ %span.product-thumb__bulk-label{"ng-if" => "::product.group_buy"}
+ = t(".bulk")
+ %img{"ng-src" => "{{::product.primaryImageOrMissing}}"}
-.row.summary
- .small-10.medium-10.large-11.columns.summary-header
+.summary
+ .summary-header
%h3
%a{"ng-click" => "triggerProductModal()", href: 'javascript:void(0)'}
%span{"ng-bind" => "::product.name"}
- %i.ofn-i_057-expand
- %small
- %em
- = t :products_from
+ %p.product-description{ng: {bind: "::product.description", click: "triggerProductModal()", show: "product.description.length"}}
+ .product-producer
+ = t :products_from
%span
%enterprise-modal
- %i.ofn-i_036-producers
%span{"ng-bind" => "::enterprise.name"}
- .small-2.medium-2.large-1.columns.text-center
- .taxon-flag
+
+ .product-properties.filter-shopfront.property-selectors
+ %filter-selector{ 'selector-set' => "productPropertySelectors", objects: "[product] | propertiesWithValuesOf" }
diff --git a/app/views/spree/admin/image_settings/edit.html.haml b/app/views/spree/admin/image_settings/edit.html.haml
deleted file mode 100644
index 4345755792..0000000000
--- a/app/views/spree/admin/image_settings/edit.html.haml
+++ /dev/null
@@ -1,81 +0,0 @@
-= render :partial => 'spree/admin/shared/configuration_menu'
-
-- content_for :page_title do
- = Spree.t(:image_settings)
-
-= form_tag admin_image_settings_path, :method => :put do
- - destroy = Spree.t(:destroy)
-
- %fieldset.no-border-top
- %fieldset.no-border-bottom
- %legend{:align => "center"}= Spree.t(:general_settings)
- .field
- .warning.note= Spree.t(:image_settings_warning)
-
- .field{"data-hook" => "attachment_path"}
- = label_tag 'preferences[attachment_path]', Spree.t(:attachment_path)
- = preference_field_tag 'preferences[attachment_path]', Spree::Config[:attachment_path], :type => :string
- .alpha.eight.columns
- .field{"data-hook" => "attachment_default_url"}
- = label_tag 'preferences[attachment_default_url]', Spree.t(:attachment_default_url)
- = preference_field_tag 'preferences[attachment_default_url]', Spree::Config[:attachment_default_url], :type => :string
- .alpha.eight.columns
- .field{"data-hook" => "attachment_url"}
- = label_tag 'preferences[attachment_url]', Spree.t(:attachment_url)
- = preference_field_tag 'preferences[attachment_url]', Spree::Config[:attachment_url], :type => :string
- .omega.four.columns
- .field{"data-hook" => "attachment_default_style"}
- = label_tag 'preferences[attachment_default_style]', Spree.t(:attachment_default_style)
- = collection_select 'preferences', 'attachment_default_style', @styles, :first, :first, {:selected => Spree::Config[:attachment_default_style] }, :class => 'select2 fullwidth'
- .clear
- .field{"data-hook" => "use_s3"}
- = preference_field_tag 'preferences[use_s3]', Spree::Config[:use_s3], :type => :boolean
- = label_tag 'preferences[use_s3]', Spree.t(:use_s3)
-
- %fieldset#attachment_styles.no-border-bottom{"data-hook" => "attachment_styles"}
- %legend{:align => "center"}= Spree.t(:attachment_styles)
- #styles_list.row.frameless
- - @styles.each_with_index do |(style_name, style_value), index|
- .field.three.columns
- = label_tag "attachment_styles[#{style_name}]", style_name
- %a.destroy_style{: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}"
- #new-styles.row.frameless
- .field
- = link_to_with_icon 'icon-plus', Spree.t(:add_new_style), '#', :class => 'add_new_style button'
-
- .row
- #s3_settings.alpha.six.columns{"data-hook" => "s3_settings", :style => "display: none"}
- %fieldset.no-border-bottom
- %legend{:align => "center"}= Spree.t(:configure_s3)
- .field{"data-hook" => "s3_access_key"}
- = label_tag 'preferences[s3_access_key]', Spree.t(:s3_access_key)
- = preference_field_tag 'preferences[s3_access_key]', Spree::Config[:s3_access_key], :type => :string
- .field{"data-hook" => "s3_secret"}
- = label_tag 'preferences[s3_secret]', Spree.t(:s3_secret)
- = preference_field_tag 'preferences[s3_secret]', Spree::Config[:s3_secret], :type => :string
- .field{"data-hook" => "s3_bucket"}
- = label_tag 'preferences[s3_bucket]', Spree.t(:s3_bucket)
- = preference_field_tag 'preferences[s3_bucket]', Spree::Config[:s3_bucket], :type => :string
- .field{"data-hook" => "s3_protocol"}
- = label_tag 'preferences[s3_protocol]', Spree.t(:s3_protocol)
- = preference_field_tag 'preferences[s3_protocol]', Spree::Config[:s3_protocol], :type => :string
-
- #s3_headers.omega.six.columns{"data-hook" => "s3_headers", :style => "display: none"}
- %fieldset.no-border-bottom
- %legend{:align => "center"}= Spree.t(:s3_headers)
- #headers_list
- - @headers.each do |header_name, header_value|
- .field
- = label_tag "s3_headers[#{header_name}]", header_name
- %a.destroy_header.with-tip{:alt => destroy, :href => "#", :title => destroy}
- %i.icon-trash
- = text_field_tag "s3_headers[#{header_name}]", header_value, :class => 'fullwidth'
- = link_to_with_icon 'icon-plus', Spree.t(:add_new_header), '#', :class => 'add_header button'
-
- .form-buttons.filter-actions.actions{"data-hook" => "buttons"}
- = button Spree.t('actions.update'), 'icon-refresh'
diff --git a/app/views/spree/admin/orders/customer_details/_address_form.html.haml b/app/views/spree/admin/orders/customer_details/_address_form.html.haml
index 18bd0970b6..da8d943c18 100644
--- a/app/views/spree/admin/orders/customer_details/_address_form.html.haml
+++ b/app/views/spree/admin/orders/customer_details/_address_form.html.haml
@@ -16,10 +16,6 @@
%div{class: "field"}
= f.label :lastname, Spree.t(:last_name) + ':'
= f.text_field :lastname, class: 'fullwidth'
- - if Spree::Config[:company]
- %div{class: "field"}
- = f.label :company, Spree.t(:company) + ':'
- = f.text_field :company, class: 'fullwidth'
%div{class: "field"}
= f.label :address1, Spree.t(:street_address) + ':'
= f.text_field :address1, class: 'fullwidth'
diff --git a/app/views/spree/admin/shared/_configuration_menu.html.haml b/app/views/spree/admin/shared/_configuration_menu.html.haml
index c5f302f0db..3e5790beb5 100644
--- a/app/views/spree/admin/shared/_configuration_menu.html.haml
+++ b/app/views/spree/admin/shared/_configuration_menu.html.haml
@@ -7,7 +7,6 @@
= configurations_sidebar_menu_item Spree.t(:general_settings), edit_admin_general_settings_path
- if Spree::Config[:override_actionmailer_config]
= configurations_sidebar_menu_item Spree.t(:mail_method_settings), edit_admin_mail_methods_path
- = configurations_sidebar_menu_item Spree.t(:image_settings), edit_admin_image_settings_path
= configurations_sidebar_menu_item Spree.t(:tax_categories), admin_tax_categories_path
= configurations_sidebar_menu_item Spree.t(:tax_rates), admin_tax_rates_path
= configurations_sidebar_menu_item Spree.t(:tax_settings), edit_admin_tax_settings_path
diff --git a/app/views/spree/admin/shared/_routes.html.erb b/app/views/spree/admin/shared/_routes.html.erb
index 15d562e4ef..438d257af9 100644
--- a/app/views/spree/admin/shared/_routes.html.erb
+++ b/app/views/spree/admin/shared/_routes.html.erb
@@ -1,4 +1,10 @@