Skip to content

Commit

Permalink
Merge pull request #10812 from spree/fix/clear-turbolinks-cache-on-cu…
Browse files Browse the repository at this point in the history
…rrency-change

Fix turbolinks caching issues with currency change
  • Loading branch information
damianlegawiec committed Mar 2, 2021
2 parents 82b094e + f11670c commit 9034287
Show file tree
Hide file tree
Showing 16 changed files with 141 additions and 48 deletions.
2 changes: 2 additions & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ globals:
AUTH_TOKEN: true
SPREE_LOCALE: true
SPREE_CURRENCY: true
SPREE_DEFAULT_CURRENCY: true
SPREE_DEFAULT_LOCALE: true
update_state: true

env:
Expand Down
20 changes: 12 additions & 8 deletions core/app/assets/javascripts/spree.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,20 @@ Spree.pathFor = function (path) {
}

Spree.localizedPathFor = function(path) {
if (typeof (SPREE_LOCALE) !== 'undefined') {
if (path.match(/api\/v/)) {
if (path.match(/\?/)) {
path = path + '&locale=' + SPREE_LOCALE
} else {
path = path + '?locale=' + SPREE_LOCALE
}
if (typeof (SPREE_LOCALE) !== 'undefined' && typeof (SPREE_CURRENCY) !== 'undefined') {
var fullUrl = new URL(Spree.pathFor(path))
var params = fullUrl.searchParams
var pathName = fullUrl.pathname

params.set('currency', SPREE_CURRENCY)

if (pathName.match(/api\/v/)) {
params.set('locale', SPREE_LOCALE)
} else {
path = SPREE_LOCALE + '/' + path
pathName = SPREE_LOCALE + '/' + pathName
}

path = pathName + '?' + params.toString()
}
return Spree.pathFor(path)
}
Expand Down
7 changes: 7 additions & 0 deletions core/lib/spree/core/controller_helpers/currency.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ module Currency
helper_method :supported_currencies_for_all_stores
helper_method :current_currency
helper_method :supported_currency?
helper_method :currency_param
end

def current_currency
Expand Down Expand Up @@ -41,6 +42,12 @@ def supported_currency?(currency_iso_code)

supported_currencies.map(&:iso_code).include?(currency_iso_code.upcase)
end

def currency_param
return if current_currency == current_store.default_currency

current_currency
end
end
end
end
Expand Down
7 changes: 7 additions & 0 deletions core/lib/spree/testing_support/locale_helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,18 @@ def add_french_locales

def open_i18n_menu
find('#header #internationalization-button-desktop').click
expect(page).to have_selector('#internationalization-options-desktop')
end

def close_i18n_menu
find('#header #internationalization-button-desktop').click
expect(page).not_to have_selector('#internationalization-options-desktop')
end

def switch_to_currency(currency)
open_i18n_menu
select currency, from: 'switch_to_currency'
expect(page).to have_no_css '.turbolinks-progress-bar'
end

def switch_to_locale(locale)
Expand Down
16 changes: 16 additions & 0 deletions core/spec/lib/spree/core/controller_helpers/currency_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,20 @@ class FakesController < ApplicationController
expect(controller.supported_currencies).to include(::Money::Currency.find(currency))
end
end

describe '#currency_param' do
let!(:store) { create :store, default: true, default_currency: 'EUR', supported_currencies: 'EUR,GBP' }

context 'same as store default locale' do
before { controller.params = { currency: 'EUR' } }

it { expect(controller.currency_param).to eq(nil) }
end

context 'different than store locale' do
before { controller.params = { currency: 'GBP' } }

it { expect(controller.currency_param).to eq('GBP') }
end
end
end
29 changes: 26 additions & 3 deletions frontend/app/assets/javascripts/spree/frontend.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,9 @@ Spree.routes.api_tokens = Spree.pathFor('api_tokens')
Spree.routes.ensure_cart = Spree.pathFor('ensure_cart')
Spree.routes.api_v2_storefront_cart_apply_coupon_code = Spree.pathFor('api/v2/storefront/cart/apply_coupon_code')
Spree.routes.api_v2_storefront_cart_remove_coupon_code = Spree.pathFor('api/v2/storefront/cart/remove_coupon_code')
Spree.routes.product = function(id) { return Spree.pathFor('products/' + id) }
Spree.routes.product_related = function(id) { return Spree.pathFor('products/' + id + '/related') }
Spree.routes.product_carousel = function (taxonId) { return Spree.pathFor('product_carousel/' + taxonId) }
Spree.routes.product = function(id) { return Spree.localizedPathFor('products/' + id) }
Spree.routes.product_related = function(id) { return Spree.localizedPathFor('products/' + id + '/related') }
Spree.routes.product_carousel = function (taxonId) { return Spree.localizedPathFor('product_carousel/' + taxonId) }
Spree.routes.set_locale = function(locale) { return Spree.pathFor('locale/set?switch_to_locale=' + locale) }
Spree.routes.set_currency = function(currency) { return Spree.pathFor('currency/set?switch_to_currency=' + currency) }

Expand All @@ -57,3 +57,26 @@ Spree.showProgressBar = function () {
Turbolinks.controller.adapter.progressBar.setValue(0)
Turbolinks.controller.adapter.progressBar.show()
}

Spree.clearCache = function () {
if (!Turbolinks.supported) { return }

Turbolinks.clearCache()
}

Spree.setCurrency = function (currency) {
Spree.clearCache()

var params = (new URL(window.location)).searchParams
if (currency === SPREE_DEFAULT_CURRENCY) {
params.delete('currency')
} else {
params.set('currency', currency)
}
var queryString = params.toString()
if (queryString !== '') { queryString = '?' + queryString }

SPREE_CURRENCY = currency

Turbolinks.visit(window.location.pathname + queryString, { action: 'replace' })
}
48 changes: 40 additions & 8 deletions frontend/app/assets/javascripts/spree/frontend/currency.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,43 @@
Spree.ready(function ($) {
var currencySelect = $('#currency-select select')
document.addEventListener('turbolinks:load', function(event) {
// this condition checks if this is the first initial load of turbolinks application
if (!event.data.timing.visitStart) {
var currencySelect = document.querySelectorAll('select[name=switch_to_currency]')

if (currencySelect.length) {
currencySelect.on('change', function () {
currencySelect.attr('disabled')
Spree.showProgressBar()
window.location = Spree.routes.set_currency(this.value)
})
if (currencySelect.length) {
currencySelect.forEach(function (element) {
element.addEventListener('change', function () {
Spree.showProgressBar()
var newCurrency = this.value

// we need to make AJAX call here to the backend to set currency in session
fetch(Spree.routes.set_currency(newCurrency), {
method: 'GET'
}).then(function (response) {
switch (response.status) {
case 200:
Spree.setCurrency(newCurrency)
document.getElementById('internationalization-options-desktop').classList.remove('show')
break
}
})
})
})
}
}
})

// fix back button issue with different currency set
// invalidate page if cached page has different currency then the current one
document.addEventListener('turbolinks:load', function(event) {
if (SPREE_CURRENCY === SPREE_DEFAULT_CURRENCY) {
var regexAnyCurrency = new RegExp('currency=')
if (event.data.url.match(regexAnyCurrency) && !event.data.url.match(SPREE_CURRENCY)) {
Spree.setCurrency(SPREE_CURRENCY)
}
} else {
var regex = new RegExp('currency=' + SPREE_CURRENCY)
if (!event.data.url.match(regex)) {
Spree.setCurrency(SPREE_CURRENCY)
}
}
})
14 changes: 8 additions & 6 deletions frontend/app/assets/javascripts/spree/frontend/locale.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
Spree.ready(function ($) {
var localeSelect = $('#locale-select select')
document.addEventListener('turbolinks:load', function () {
var localeSelect = document.querySelectorAll('select[name=switch_to_locale]')

if (localeSelect.length) {
localeSelect.on('change', function () {
localeSelect.attr('disabled')
Spree.showProgressBar()
window.location = Spree.routes.set_locale(this.value)
localeSelect.forEach(function (element) {
element.addEventListener('change', function () {
Spree.clearCache()
Spree.showProgressBar()
this.form.submit()
})
})
}
})
13 changes: 0 additions & 13 deletions frontend/app/assets/javascripts/spree/frontend/multi_currency.js

This file was deleted.

4 changes: 1 addition & 3 deletions frontend/app/controllers/concerns/spree/locale_urls.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@ module LocaleUrls
private

def default_url_options
return super if locale_param.nil?

super.merge(locale: locale_param)
super.merge(locale: locale_param, currency: currency_param)
end

def redirect_to_default_locale
Expand Down
6 changes: 5 additions & 1 deletion frontend/app/controllers/spree/currency_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@ def set
current_order&.update(currency: new_currency)
session[:currency] = new_currency
end
redirect_back_or_default(root_path(currency: new_currency))

respond_to do |format|
format.html { redirect_back fallback_location: spree.root_path(currency: new_currency) }
format.json { head :ok }
end
end
end
end
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<% if defined?(should_render_currency_dropdown?) && should_render_currency_dropdown? %>
<%= form_tag spree.set_currency_path, method: :get, class: 'px-4 py-3 w-100', id: 'currency-select' do %>
<%= form_tag spree.set_currency_path, method: :get, class: 'px-4 py-3 w-100 currency-select' do %>
<div class="form-group">
<label for="switch_to_currency" class="dropdown-header text-center">
<%= Spree.t(:choose_currency) %>
Expand Down
5 changes: 1 addition & 4 deletions frontend/app/views/spree/shared/_head.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,6 @@
<%= stylesheet_link_tag 'spree/frontend/all', media: 'screen', 'data-turbolinks-track': 'reload' %>
<%= csrf_meta_tags %>
<%= render 'spree/shared/paths' %>
<script>
var SPREE_LOCALE = '<%= I18n.locale %>'
var SPREE_CURRENCY = '<%= current_currency %>'
</script>
<%= render 'spree/shared/locale_and_currency' %>
<%= javascript_include_tag 'spree/frontend/all', defer: true, 'data-turbolinks-track': 'reload' %>
<%= yield :head %>
6 changes: 6 additions & 0 deletions frontend/app/views/spree/shared/_locale_and_currency.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<script>
var SPREE_LOCALE = '<%= I18n.locale %>'
var SPREE_CURRENCY = '<%= current_currency %>'
var SPREE_DEFAULT_CURRENCY = '<%= current_store.default_currency %>'
var SPREE_DEFAULT_LOCALE = '<%= current_store.default_locale %>'
</script>
2 changes: 1 addition & 1 deletion frontend/app/views/spree/shared/_locale_dropdown.html.erb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<% if should_render_locale_dropdown? %>
<%= form_tag spree.set_locale_path, method: :get, class: 'px-4 py-3 w-100', id: 'locale-select' do %>
<%= form_tag spree.set_locale_path, method: :get, class: 'px-4 py-3 w-100 locale-select' do %>
<div class="form-group">
<label for="switch_to_locale" class="dropdown-header text-center">
<%= Spree.t('i18n.language') %>
Expand Down
8 changes: 8 additions & 0 deletions frontend/spec/features/product_prices_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,20 @@
expect(page).to have_text '$19.99'
switch_to_currency('EUR')
expect(page).to have_text '€16.00'
expect(page).to have_current_path(spree.product_path(product, currency: 'EUR'))
switch_to_currency('GBP')
expect(page).to have_text '£23.00'
expect(page).to have_current_path(spree.product_path(product, currency: 'GBP'))
visit spree.products_path
expect(page).to have_text '£23.00'
expect(page).to have_link product.name, href: "/products/#{product.slug}?currency=GBP"
open_i18n_menu
expect(page).to have_select('switch_to_currency', selected: 'GBP')
close_i18n_menu
switch_to_currency('USD')
expect(page).to have_text '$19.99'
expect(page).to have_current_path(spree.products_path)
expect(page).to have_link product.name, href: "/products/#{product.slug}"
end
end
end
Expand Down

0 comments on commit 9034287

Please sign in to comment.