Skip to content

Commit

Permalink
feat: settings page for user preferences - fixes #8
Browse files Browse the repository at this point in the history
  • Loading branch information
kjellberg committed Apr 8, 2024
1 parent 165507a commit c27aaab
Show file tree
Hide file tree
Showing 14 changed files with 139 additions and 1 deletion.
9 changes: 9 additions & 0 deletions app/controllers/application_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ class ApplicationController < ActionController::Base

before_action :authenticate_user!
before_action :ensure_onboarded, unless: :devise_controller?
before_action :setup_locale

# Strong parameters for account.
# Used for account creation and update.
Expand Down Expand Up @@ -32,4 +33,12 @@ def after_sign_out_path_for(resource_or_scope)
uri.query = nil # Remove any query parameters
uri.to_s
end

# The locale is set to the user's locale if present, otherwise it is set to the default locale
# Get available locales and default_locale from Kiqr::Config
def setup_locale
I18n.default_locale = Kiqr::Config.default_locale
I18n.available_locales = Kiqr::Config.available_locales
I18n.locale = current_user&.locale&.to_sym || I18n.default_locale
end
end
27 changes: 27 additions & 0 deletions app/controllers/users/preferences_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
class Users::PreferencesController < ApplicationController
def edit
@user = current_user
end

def update
@user = current_user
if @user.update(preferences_params)
redirect_to edit_user_preferences_path, notice: t(".updated")
else
render :edit, status: :unprocessable_entity
end
end

private

def options_for_locale
I18n.available_locales.map do |locale|
[I18n.t("languages.#{locale}"), locale]
end
end
helper_method :options_for_locale

def preferences_params
params.require(:user).permit(:time_zone, :locale)
end
end
6 changes: 6 additions & 0 deletions app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ class User < ApplicationRecord
has_many :account_users, dependent: :destroy
has_many :accounts, through: :account_users

# Validate time zone format.
validates :time_zone, inclusion: {in: ActiveSupport::TimeZone.all.map(&:name)}

# Validate locale is a valid locale.
validates :locale, inclusion: {in: Kiqr::Config.available_locales.map(&:to_s)}

# Get the user's full name from their personal account.
delegate :name, to: :personal_account

Expand Down
8 changes: 8 additions & 0 deletions app/views/partials/navigations/_settings.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,14 @@
<i class="fa fa-arrow-turn-down w-3 h-3"></i>
</div>

<%= render(PageLayouts::Settings::NavigationItem::Component.new(
label: t('.items.preferences.label'),
description: t('.items.preferences.description'),
icon: "fa fa-sliders",
path: edit_user_preferences_path,
active: current_base_path?(edit_user_preferences_path)
)) %>

<%= render(PageLayouts::Settings::NavigationItem::Component.new(
label: t('.items.two_factor.label'),
description: t('.items.two_factor.description'),
Expand Down
7 changes: 7 additions & 0 deletions app/views/users/preferences/_form.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<%= simple_form_for(user, url: user_preferences_path, method: :patch) do |f| %>
<%= f.input :locale, placeholder: t(".locale.placeholder"), required: true, autofocus: true, prompt: t(".locale.prompt"), as: :select, collection: options_for_locale %>
<%= f.input :time_zone, placeholder: t(".timezone.placeholder"), required: true, autofocus: true %>
<div class="mt-4 flex justify-between items-center">
<%= f.button :submit, t(".submit_button") %>
</div>
<% end %>
7 changes: 7 additions & 0 deletions app/views/users/preferences/edit.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<% title t(".title") %>
<%= render(PageLayouts::Settings::Component.new(
title: t(".title"),
description: t(".description")
)) do %>
<%= render "form", user: @user %>
<% end %>
9 changes: 9 additions & 0 deletions config/initializers/kiqr.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,13 @@
# note that it will be overwritten if you use your own mailer class
# with default "from" parameter.
config.default_from_email = "[email protected]"

# ==> Locales
# Configure the available locales in the application.
# This is used to validate the locale of the user.
config.available_locales = [:en, :sv]

# Default locale
# This is used to set the default locale for the application.
config.default_locale = :en
end
5 changes: 5 additions & 0 deletions config/initializers/locale.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Permitted locales available for the application
I18n.available_locales = Kiqr::Config.available_locales

# Set default locale to something other than :en
I18n.default_locale = Kiqr::Config.default_locale
21 changes: 21 additions & 0 deletions config/locales/kiqr.en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,18 @@ en:
user:
label: "Login credentials"
description: "Change user email or password"
preferences:
label: "Preferences"
description: "Change your personal settings"
two_factor:
label: "Two-factor authentication"
description: "One-time passwords"
delete_user:
label: "Delete user account"
description: "Remove all user related data"
languages:
en: "English"
sv: "Swedish"
accounts:
new:
heading:
Expand Down Expand Up @@ -222,6 +228,21 @@ en:
label: "One-time password"
placeholder: "Enter the 6-digit code"
verify_button: "Verify configuration"
preferences:
edit:
title: "User preferences"
description: "Update your user preferences."
form:
email:
label: "Email address"
placeholder: "Enter a valid email address"
locale:
label: "Language"
prompt: "Select a language"
placeholder: "Select your preferred language"
submit_button: "Save changes"
update:
updated: "User preferences have been updated."
account_mailer:
invitation_email:
welcome: "Welcome to %{app_name}"
Expand Down
2 changes: 2 additions & 0 deletions config/routes/authentication.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
delete "two-factor/destroy" => "two_factor#destroy", :as => :destroy_two_factor

get "delete" => "cancellations#show", :as => :delete_user_registration

resource :preferences, only: %i[edit update], as: :user_preferences
end

scope module: :users, path: nil do
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
class AddLocaleAndTimeZoneToUsers < ActiveRecord::Migration[7.1]
def change
add_column :users, :locale, :string, default: "en"
add_column :users, :time_zone, :string, default: "UTC"
end
end
4 changes: 3 additions & 1 deletion db/schema.rb

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions lib/kiqr/config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,14 @@ class Config
# note that it will be overwritten if you use your own mailer class
# with default "from" parameter.
config_accessor :default_from_email, default: "[email protected]"

# ==> Locales
# Configure the available locales in the application.
# This is used to validate the locale of the user.
config_accessor :available_locales, default: [:en]

# Default locale
# This is used to set the default locale for the application.
config_accessor :default_locale, default: :en
end
end
20 changes: 20 additions & 0 deletions test/controllers/users/preferences_controller_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
require "test_helper"

class Users::PreferencesControllerTest < ActionDispatch::IntegrationTest
test "should get edit page" do
user = create(:user)
sign_in(user)
get edit_user_preferences_path
assert_response :success
end

test "can update user preferences" do
user = create(:user, time_zone: "UTC", locale: "en")
sign_in(user)

patch user_preferences_path, params: {user: {time_zone: "Stockholm", locale: "sv"}}
assert_redirected_to edit_user_preferences_path
assert_equal "Stockholm", user.reload.time_zone
assert_equal "sv", user.reload.locale
end
end

0 comments on commit c27aaab

Please sign in to comment.