Skip to content

Commit

Permalink
Add locale field to users table and implement language switcher in us…
Browse files Browse the repository at this point in the history
…er settings
  • Loading branch information
alxlion committed Apr 7, 2024
1 parent 3da4c49 commit 189d012
Show file tree
Hide file tree
Showing 14 changed files with 319 additions and 130 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@
- Add toggle for message reactions in attendees room
- Add toggle for polls results in attendees room
- Add delete account button in user settings
- Add language switcher in user settings
- Add tour guide for new users
- Add headers to exported CSV in reports
- Add the ability to embed attendees room in an iframe
- Add spanish locale (#84) (@eduproinf)
- Change date picker for a more user-friendly one
- Upgrade Ecto, Phoenix and LiveView
- Fix user avatars in reports
Expand Down
10 changes: 7 additions & 3 deletions assets/js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,24 +10,28 @@ import AirDatepicker from 'air-datepicker'
import airdatepickerLocaleEn from 'air-datepicker/locale/en'
import airdatepickerLocaleFr from 'air-datepicker/locale/fr'
import airdatepickerLocaleDe from 'air-datepicker/locale/de'
import airdatepickerLocaleEs from 'air-datepicker/locale/es'
import 'moment/locale/de'
import 'moment/locale/fr'
import 'moment/locale/es'
import QRCodeStyling from "qr-code-styling"
import { Presenter } from "./presenter"
import { Manager } from "./manager"
import Split from "split-grid"
import { TourGuideClient } from "@sjmc11/tourguidejs/src/Tour"
window.moment = moment

const locale = document.querySelector("html").getAttribute("lang") || navigator.language.split('-')[0]
window.moment.locale("en")
window.moment.locale(navigator.language.split('-')[0])
window.moment.locale(locale)
window.Alpine = Alpine
Alpine.start()

let airdatepickerLocale = {
en: airdatepickerLocaleEn,
fr: airdatepickerLocaleFr,
de: airdatepickerLocaleDe
de: airdatepickerLocaleDe,
es: airdatepickerLocaleEs
}
let csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute("content")
let Hooks = {}
Expand Down Expand Up @@ -265,7 +269,7 @@ Hooks.Pickr = {
const utc = moment(date).utc().format("YYYY-MM-DDTHH:mm:ss")
utcTime.value = utc
},
locale: airdatepickerLocale[navigator.language.split('-')[0]]
locale: airdatepickerLocale[locale]
})
},
updated() {
Expand Down
27 changes: 27 additions & 0 deletions lib/claper/accounts.ex
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,19 @@ defmodule Claper.Accounts do
User.email_changeset(user, attrs)
end

@doc """
Returns an `%Ecto.Changeset{}` for changing the user preferences.
## Examples
iex> change_user_preferences(user)
%Ecto.Changeset{data: %User{}}
"""
def change_user_preferences(user, attrs \\ %{}) do
User.preferences_changeset(user, attrs)
end

@doc """
Emulates that the email will change without actually changing
it in the database.
Expand Down Expand Up @@ -177,6 +190,20 @@ defmodule Claper.Accounts do
end
end

@doc """
Updates the user preferences.
## Examples
iex> update_user_preferences(user, %{locale: "en})
{:ok, %User{}}
iex> update_user_preferences(user, %{locale: "invalid})
{:error, %Ecto.Changeset{}}
"""
def update_user_preferences(user, attrs \\ %{}) do
user
|> User.preferences_changeset(attrs)
|> Repo.update()
end

@doc """
Delivers the magic link email to the given user.
Expand Down
6 changes: 6 additions & 0 deletions lib/claper/accounts/user.ex
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ defmodule Claper.Accounts.User do
field :hashed_password, :string, redact: true
field :is_admin, :boolean
field :confirmed_at, :naive_datetime
field :locale, :string

has_many :events, Claper.Events.Event

Expand All @@ -23,6 +24,11 @@ defmodule Claper.Accounts.User do
|> validate_password(opts)
end

def preferences_changeset(user, attrs) do
user
|> cast(attrs, [:locale])
end

defp validate_email(changeset) do
changeset
|> validate_required([:email])
Expand Down
6 changes: 3 additions & 3 deletions lib/claper_web/live/event_live/event_form_component.ex
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ defmodule ClaperWeb.EventLive.EventFormComponent do
{:noreply,
socket
|> put_flash(:info, gettext("Created successfully"))
|> push_navigate(to: socket.assigns.return_to)}
|> redirect(to: socket.assigns.return_to)}

{:error, %Ecto.Changeset{} = changeset} ->
{:noreply, assign(socket, changeset: changeset)}
Expand Down Expand Up @@ -231,7 +231,7 @@ defmodule ClaperWeb.EventLive.EventFormComponent do
{:noreply,
socket
|> put_flash(:info, gettext("Created successfully"))
|> push_navigate(to: socket.assigns.return_to)}
|> redirect(to: socket.assigns.return_to)}

{:error, %Ecto.Changeset{} = changeset} ->
{:noreply, assign(socket, changeset: changeset)}
Expand All @@ -251,7 +251,7 @@ defmodule ClaperWeb.EventLive.EventFormComponent do
{:noreply,
socket
|> put_flash(:info, gettext("Updated successfully"))
|> push_navigate(to: socket.assigns.return_to)}
|> redirect(to: socket.assigns.return_to)}

{:error, %Ecto.Changeset{} = changeset} ->
{:noreply, assign(socket, :changeset, changeset)}
Expand Down
31 changes: 30 additions & 1 deletion lib/claper_web/live/user_settings_live/show.ex
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,23 @@ defmodule ClaperWeb.UserSettingsLive.Show do

email_changeset = Accounts.User.email_changeset(%Accounts.User{}, %{})
password_changeset = Accounts.User.password_changeset(%Accounts.User{}, %{})
preferences_changeset = Accounts.User.preferences_changeset(socket.assigns.current_user, %{})


{:ok,
socket
|> assign(:email_changeset, email_changeset)
|> assign(:password_changeset, password_changeset)}
|> assign(:password_changeset, password_changeset)
|> assign(:preferences_changeset, preferences_changeset)
}
end

@impl true
def handle_params(params, _url, socket) do
{:noreply, apply_action(socket, socket.assigns.live_action, params)}
end


defp apply_action(socket, :edit_email, _params) do
socket
|> assign(:page_title, gettext("Update your email"))
Expand Down Expand Up @@ -97,6 +102,30 @@ defmodule ClaperWeb.UserSettingsLive.Show do
end
end

@impl true
def handle_event("save", %{"action" => "update_preferences"} = params, socket) do
locale = params["user"]["locale"]
available_locales = Gettext.known_locales(ClaperWeb.Gettext)
if Enum.member?(available_locales, locale) do
case Accounts.update_user_preferences(socket.assigns.current_user, params["user"]) do
{:ok, _applied_user} ->
{:noreply,
socket
|> put_flash(
:info,
gettext("Your preferences have been updated.")
)
|> redirect(to: ~p"/users/settings")}

{:error, changeset} ->
{:noreply, assign(socket, :preferences_changeset, changeset)}
end
else
{:noreply, socket}
end

end

@impl true
def handle_event("delete_account", _params, %{assigns: %{current_user: user}} = socket) do
Accounts.delete(user)
Expand Down
31 changes: 31 additions & 0 deletions lib/claper_web/live/user_settings_live/show.html.heex
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,37 @@
</div>
</dl>
</div>
<div>
<div class="py-5">
<h3 class="text-lg leading-6 font-medium text-gray-900">
<%= gettext("Preferences") %>
</h3>
<p class="mt-1 max-w-2xl text-sm text-gray-500">
<%= gettext("Customize your account") %>
</p>
</div>
<div class="border-t border-gray-200 py-5 sm:p-0">
<dl class="sm:divide-y sm:divide-gray-200">
<div class="mt-5">
<.form :let={f} for={@preferences_changeset} phx-change="save">
<%= hidden_input(f, :action, name: "action", value: "update_preferences") %>
<ClaperWeb.Component.Input.select
form={f}
fieldClass="!w-auto"
array={[
{"English", "en"},
{"Español", "es"},
{"Français", "fr"},
{"German", "de"}
]}
key={:locale}
name={gettext("Language")}
/>
</.form>
</div>
</dl>
</div>
</div>
<div>
<div class="py-5">
<h3 class="text-lg leading-6 font-medium text-gray-900">
Expand Down
5 changes: 3 additions & 2 deletions lib/claper_web/plugs/locale.ex
Original file line number Diff line number Diff line change
Expand Up @@ -66,17 +66,18 @@ defmodule ClaperWeb.Plugs.Locale do

def call(conn, _opts) do
known_locales = Gettext.known_locales(ClaperWeb.Gettext)
user_locale = Map.get(conn.assigns.current_user || %{}, :locale)

accepted_languages =
extract_accept_language(conn)
|> Enum.reject(&(String.length(&1) > 2 && not Enum.member?(known_locales, &1)))

case accepted_languages do
[locale | _] ->
Gettext.put_locale(ClaperWeb.Gettext, locale)
Gettext.put_locale(ClaperWeb.Gettext, user_locale || locale)

conn
|> put_session(:locale, locale)
|> put_session(:locale, user_locale || locale)

_ ->
conn
Expand Down
2 changes: 1 addition & 1 deletion lib/claper_web/templates/layout/user.html.heex
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<!DOCTYPE html>
<html lang="en">
<html lang={@current_user.locale}>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
Expand Down
Loading

0 comments on commit 189d012

Please sign in to comment.