Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,15 @@
shadow-base
">

<% available_timezones_for_select = ActiveSupport::TimeZone.all.map(&:name) %>
<li class="h-8 flex items-center hover:bg-gray-25 rounded">
<%= autosubmit_select_tag(
"solidus_timezone",
options_for_select(available_timezones_for_select, selected: Time.zone.name),
icon: 'time-zone-line',
) %>
</li>

<% if (available_locales = Spree.i18n_available_locales).any? %>
<li class="h-8 flex items-center hover:bg-gray-25 rounded">
<%= autosubmit_select_tag(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@
<div class="py-1.5">
<%= f.text_field(:password_confirmation) %>
</div>
<% if @user.respond_to?(:timezone) %>
<div class="py-1.5">
<%= f.select :timezone, ActiveSupport::TimeZone.all.map { |t| [t.name, t.to_s] }, include_blank: t("spree.none") %>
</div>
<% end %>
<div class="py-1.5">
<%= f.checkbox_row(:spree_role_ids, options: role_options, row_title: "Roles", layout: :subsection) %>
</div>
Expand Down
1 change: 1 addition & 0 deletions admin/app/controllers/solidus_admin/base_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ class BaseController < ApplicationController
include SolidusAdmin::ControllerHelpers::Theme
include SolidusAdmin::ComponentsHelper
include SolidusAdmin::AuthenticationAdapters::Backend if defined?(Spree::Backend)
include Spree::Core::ControllerHelpers::Timezone

layout :set_layout

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def index
end
end

context "successful request" do
context "authorized request" do

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.

before do
user = create(:admin_user, email: "admin@example.com")
allow_any_instance_of(SolidusAdmin::BaseController).to receive(:spree_current_user).and_return(user)
Expand All @@ -43,6 +43,12 @@ def index
get :index
expect(response.code).to eq "200"
end

it "sets timezone by param" do

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.

get :index, params: {solidus_timezone: "Hawaii"}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Layout/SpaceInsideHashLiteralBraces: Space inside { missing.
Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.
Layout/SpaceInsideHashLiteralBraces: Space inside } missing.

expect(session).to have_key(:solidus_timezone)
expect(session[:solidus_timezone]).to eq("Hawaii")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.

end
end

describe "layout rendering" do
Expand Down
1 change: 1 addition & 0 deletions admin/spec/features/users_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
let(:sign_in_date) { DateTime.now }

before do
allow_any_instance_of(Spree.user_class).to receive(:try).with(:timezone) { nil }

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Metrics/LineLength: Line is too long. [86/80]

allow_any_instance_of(Spree.user_class).to receive(:try).with(:email).and_call_original
allow_any_instance_of(Spree.user_class).to receive(:try).with(:last_sign_in_at).and_return(sign_in_date)
end
Expand Down
2 changes: 2 additions & 0 deletions backend/app/controllers/spree/admin/base_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
module Spree
module Admin
class BaseController < Spree::BaseController
include Spree::Core::ControllerHelpers::Timezone

helper "spree/admin/navigation"
layout "spree/layouts/admin"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
<%= button_tag class: 'btn fa fa-chevron-circle-left', id: 'admin-nav-toggle', type: :button do %>
<span class="text"><%= t('spree.minimize_menu') %></span>
<% end %>
<%= render partial: 'spree/admin/shared/timezone_selection' %>
<%= render partial: 'spree/admin/shared/locale_selection' %>
<%= render partial: 'spree/admin/shared/theme_selection' %>
<% if lookup_context.exists?('spree/admin/shared/_navigation_footer') %>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
data-legacy-label="<%= 'spree.navigation.switch_to_legacy'.then { t(_1, default: t(_1, locale: :en)) } %>"
data-admin-label="<%= 'spree.navigation.switch_to_solidus_admin'.then { t(_1, default: t(_1, locale: :en)) } %>"
></span>
<span><input type="checkbox" id="solidus-admin-switch" class="solidus-admin--nav--switch"/></span>
<span><input type="checkbox" id="solidus-admin-switch" class="solidus-admin--nav--switch"></span>
</label>
</li>
</ul>
Expand All @@ -49,6 +49,7 @@
</summary>

<ul>
<%= render 'spree/admin/shared/timezone_selection_solidus_admin' %>
<%= render 'spree/admin/shared/locale_selection_solidus_admin' %>
<%= render 'spree/admin/shared/theme_selection_solidus_admin' %>

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<% available_timezones_for_select = ActiveSupport::TimeZone.all.map(&:name) %>

<%= form_tag(url_for, method: :get, style: "width: 100%;") do %>
<label class="admin-navbar-selection admin-timezone-selection">
<i class="fa fa-globe fa-fw" title="<%= I18n.t('spree.choose_dashboard_locale') %>"></i>
<select name="solidus_timezone" class="custom-select fullwidth" onchange="this.form.requestSubmit()">
<%= options_for_select(available_timezones_for_select, selected: Time.zone.name) %>
</select>
</label>
<% end %>
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<% available_timezones_for_select = ActiveSupport::TimeZone.all.map(&:name) %>

<li>
<%= form_tag(url_for, method: :get, style: "width: 100%;") do %>
<label>
<svg aria-hidden="true"><use xlink:href="<%= image_path('spree/backend/themes/solidus_admin/remixicon.symbol.svg') %>#ri-time-zone-line"></use></svg>
<select name="solidus_timezone" onchange="this.form.requestSubmit()">
<%= options_for_select(available_timezones_for_select, selected: Time.zone.name) %>
</select>
<svg aria-hidden="true"><use xlink:href="<%= image_path('spree/backend/themes/solidus_admin/remixicon.symbol.svg') %>#ri-expand-up-down-line"></use></svg>
</label>
<% end %>
</li>
9 changes: 9 additions & 0 deletions backend/app/views/spree/admin/users/_form.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -76,5 +76,14 @@
<% end %>
<% end %>
<% end %>

<% if can?(:update, @user) && @user.respond_to?(:timezone) %>
<%= f.field_container :timezone do %>
<%= f.label :timezone %>
<%= f.collection_select :timezone, ActiveSupport::TimeZone.all, :name, :to_s,
{include_blank: t("spree.none")},
class: "select2 fullwidth" %>
<% end %>
<% end %>
</div>
</div>
15 changes: 15 additions & 0 deletions backend/spec/controllers/spree/admin/base_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,19 @@ def index
end
end
end

context "authorized request" do

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.

stub_authorization!

it "allows access" do

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.

get :index
expect(response.body).to eq("test")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.

end

it "sets timezone by param" do

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.

get :index, params: {solidus_timezone: "Hawaii"}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Layout/SpaceInsideHashLiteralBraces: Space inside { missing.
Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.
Layout/SpaceInsideHashLiteralBraces: Space inside } missing.

expect(session).to have_key(:solidus_timezone)
expect(session[:solidus_timezone]).to eq("Hawaii")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.

end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ module Admin
let(:stock_item) { variant.stock_items.first }
let!(:user) { create :user }

before { expect(controller).to receive(:spree_current_user).and_return(user) }
before { expect(controller).to receive(:spree_current_user).twice.and_return(user) }

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Metrics/LineLength: Line is too long. [92/80]

before { request.env["HTTP_REFERER"] = "product_admin_page" }

subject do
Expand Down
55 changes: 55 additions & 0 deletions core/app/helpers/spree/core/controller_helpers/timezone.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# frozen_string_literal: true

module Spree
module Core
module ControllerHelpers
module Timezone
extend ActiveSupport::Concern

included do
around_action :set_timezone
end

private

# Sets the timezone for the current request.
#
# Uses the most preferred timezone or falls back to the server default.
#
# It respects the server's configured timezone from +config/application.rb+.
#
def set_timezone(&action)
timezone = if timezone_change_needed?
resolved_timezone || Time.zone.name

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Layout/IndentationWidth: Use 2 (not -9) spaces for indentation.

else

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Layout/ElseAlignment: Align else with if.

session[:solidus_timezone]
end

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Layout/EndAlignment: end at 26, 10 is not aligned with if at 22, 21.

session[:solidus_timezone] = timezone
Time.use_zone(timezone, &action)
end

# Checks if we need to change the timezone or not.
def timezone_change_needed?
params[:solidus_timezone].present? || session[:solidus_timezone].blank?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Metrics/LineLength: Line is too long. [81/80]

end

# Returns the first valid timezone from the priority chain, or nil.
#
# The priority order is:
#
# * the passed parameter: +params[:solidus_timezone]+
# * the user's timezone preference
#
def resolved_timezone
candidates = [params[:solidus_timezone], timezone_from_user].compact
candidates.detect { |tz| ActiveSupport::TimeZone[tz].present? }
end

# Try to get the timezone from user settings.
def timezone_from_user
spree_current_user.try(:timezone).presence
end
end
end
end
end
2 changes: 1 addition & 1 deletion core/lib/spree/permitted_attributes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ module PermittedAttributes
# by changing a user with higher priveleges' email to one a lower-priveleged
# admin owns. Creating a user with an email is handled separate at the
# controller level.
@@user_attributes = [:password, :password_confirmation, customer_metadata: {}]
@@user_attributes = [:password, :password_confirmation, :timezone, customer_metadata: {}]

@@variant_attributes = [
:name, :presentation, :cost_price, :lock_version,
Expand Down
101 changes: 101 additions & 0 deletions core/spec/helpers/controller_helpers/timezone_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# frozen_string_literal: true

require "rails_helper"

RSpec.describe Spree::Core::ControllerHelpers::Timezone, type: :controller do
controller(ActionController::Base) do
include Spree::Core::ControllerHelpers::Timezone

def index
render plain: Time.zone.name
end

private

attr_reader :spree_current_user
end

let(:original_timezone) { Time.zone.name }

describe "#set_timezone" do
context "with params[:solidus_timezone]" do
it "sets the timezone from the param" do
get :index, params: {solidus_timezone: "Hawaii"}
expect(response.body).to eq("Hawaii")
end

it "stores the timezone in the session" do
get :index, params: {solidus_timezone: "Hawaii"}
expect(session[:solidus_timezone]).to eq("Hawaii")
end

it "takes priority over session" do
get :index, params: {solidus_timezone: "Hawaii"}, session: {solidus_timezone: "Tokyo"}
expect(response.body).to eq("Hawaii")
end
end

context "with session[:solidus_timezone]" do
it "uses the timezone from the session" do
get :index, session: {solidus_timezone: "Tokyo"}
expect(response.body).to eq("Tokyo")
end
end

context "with spree_current_user timezone" do
let(:user) { double("User", timezone: "Berlin") }

before do
controller.instance_variable_set(:@spree_current_user, user)
end

it "uses the user's timezone" do
get :index
expect(response.body).to eq("Berlin")
end

context "when user does not respond to timezone" do
let(:user) { double("User") }

it "falls back to the server default" do
get :index
expect(response.body).to eq(original_timezone)
end
end

context "when user's timezone is blank" do
let(:user) { double("User", timezone: "") }

it "falls back to the server default" do
get :index
expect(response.body).to eq(original_timezone)
end
end
end

context "with an invalid timezone" do
it "falls back to the server default" do
get :index, params: {solidus_timezone: "Nonexistent/Zone"}
expect(response.body).to eq(original_timezone)
end
end

context "with no timezone set anywhere" do
it "uses the server default timezone" do
get :index
expect(response.body).to eq(original_timezone)
end

it "stores the server default in session" do
get :index
expect(session[:solidus_timezone]).to eq(original_timezone)
end
end

it "restores the original timezone after the request" do
original = Time.zone.name
get :index, params: {solidus_timezone: "Hawaii"}
expect(Time.zone.name).to eq(original)
end
end
end
Loading