add locale to user settings
This commit is contained in:
		| @@ -269,6 +269,35 @@ defmodule Lokal.Accounts do | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   @doc """ | ||||
|   Returns an `%Changeset{}` for changing the user locale. | ||||
|  | ||||
|   ## Examples | ||||
|  | ||||
|       iex> change_user_locale(user) | ||||
|       %Changeset{data: %User{}} | ||||
|  | ||||
|   """ | ||||
|   @spec change_user_locale(User.t()) :: Changeset.t(User.t()) | ||||
|   def change_user_locale(%{locale: locale} = user), do: User.locale_changeset(user, locale) | ||||
|  | ||||
|   @doc """ | ||||
|   Updates the user locale. | ||||
|  | ||||
|   ## Examples | ||||
|  | ||||
|       iex> update_user_locale(user, "valid locale") | ||||
|       {:ok, %User{}} | ||||
|  | ||||
|       iex> update_user_password(user, "invalid locale") | ||||
|       {:error, %Changeset{}} | ||||
|  | ||||
|   """ | ||||
|   @spec update_user_locale(User.t(), locale :: String.t()) :: | ||||
|           {:ok, User.t()} | {:error, Changeset.t(User.t())} | ||||
|   def update_user_locale(user, locale), | ||||
|     do: user |> User.locale_changeset(locale) |> Repo.update() | ||||
|  | ||||
|   @doc """ | ||||
|   Deletes a user. must be performed by an admin or the same user! | ||||
|  | ||||
|   | ||||
| @@ -18,6 +18,7 @@ defmodule Lokal.Accounts.User do | ||||
|     field :hashed_password, :string | ||||
|     field :confirmed_at, :naive_datetime | ||||
|     field :role, Ecto.Enum, values: [:admin, :user], default: :user | ||||
|     field :locale, :string | ||||
|  | ||||
|     has_many :invites, Invite, on_delete: :delete_all | ||||
|  | ||||
| @@ -32,6 +33,7 @@ defmodule Lokal.Accounts.User do | ||||
|           confirmed_at: NaiveDateTime.t(), | ||||
|           role: atom(), | ||||
|           invites: [Invite.t()], | ||||
|           locale: String.t() | nil, | ||||
|           inserted_at: NaiveDateTime.t(), | ||||
|           updated_at: NaiveDateTime.t() | ||||
|         } | ||||
| @@ -60,7 +62,7 @@ defmodule Lokal.Accounts.User do | ||||
|           Changeset.t(t() | new_user()) | ||||
|   def registration_changeset(user, attrs, opts \\ []) do | ||||
|     user | ||||
|     |> cast(attrs, [:email, :password, :role]) | ||||
|     |> cast(attrs, [:email, :password, :role, :locale]) | ||||
|     |> validate_email() | ||||
|     |> validate_password(opts) | ||||
|   end | ||||
| @@ -185,4 +187,14 @@ defmodule Lokal.Accounts.User do | ||||
|       do: changeset, | ||||
|       else: changeset |> add_error(:current_password, dgettext("errors", "is not valid")) | ||||
|   end | ||||
|  | ||||
|   @doc """ | ||||
|   A changeset for changing the user's locale | ||||
|   """ | ||||
|   @spec locale_changeset(t() | Changeset.t(t()), locale :: String.t() | nil) :: Changeset.t(t()) | ||||
|   def locale_changeset(user_or_changeset, locale) do | ||||
|     user_or_changeset | ||||
|     |> cast(%{"locale" => locale}, [:locale]) | ||||
|     |> validate_required(:locale) | ||||
|   end | ||||
| end | ||||
|   | ||||
| @@ -47,6 +47,7 @@ defmodule LokalWeb do | ||||
|       use Phoenix.LiveView, | ||||
|         layout: {LokalWeb.LayoutView, "live.html"} | ||||
|  | ||||
|       on_mount LokalWeb.InitAssigns | ||||
|       unquote(view_helpers()) | ||||
|     end | ||||
|   end | ||||
|   | ||||
| @@ -10,10 +10,11 @@ defmodule LokalWeb.UserSettingsController do | ||||
|     render(conn, "edit.html", page_title: gettext("Settings")) | ||||
|   end | ||||
|  | ||||
|   def update(conn, %{"action" => "update_email"} = params) do | ||||
|     %{"current_password" => password, "user" => user_params} = params | ||||
|     user = conn.assigns.current_user | ||||
|  | ||||
|   def update(%{assigns: %{current_user: user}} = conn, %{ | ||||
|         "action" => "update_email", | ||||
|         "current_password" => password, | ||||
|         "user" => user_params | ||||
|       }) do | ||||
|     case Accounts.apply_user_email(user, password, user_params) do | ||||
|       {:ok, applied_user} -> | ||||
|         Accounts.deliver_update_email_instructions( | ||||
| @@ -33,14 +34,15 @@ defmodule LokalWeb.UserSettingsController do | ||||
|         |> redirect(to: Routes.user_settings_path(conn, :edit)) | ||||
|  | ||||
|       {:error, changeset} -> | ||||
|         render(conn, "edit.html", email_changeset: changeset) | ||||
|         conn |> render("edit.html", email_changeset: changeset) | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   def update(conn, %{"action" => "update_password"} = params) do | ||||
|     %{"current_password" => password, "user" => user_params} = params | ||||
|     user = conn.assigns.current_user | ||||
|  | ||||
|   def update(%{assigns: %{current_user: user}} = conn, %{ | ||||
|         "action" => "update_password", | ||||
|         "current_password" => password, | ||||
|         "user" => user_params | ||||
|       }) do | ||||
|     case Accounts.update_user_password(user, password, user_params) do | ||||
|       {:ok, user} -> | ||||
|         conn | ||||
| @@ -49,12 +51,27 @@ defmodule LokalWeb.UserSettingsController do | ||||
|         |> UserAuth.log_in_user(user) | ||||
|  | ||||
|       {:error, changeset} -> | ||||
|         render(conn, "edit.html", password_changeset: changeset) | ||||
|         conn |> render("edit.html", password_changeset: changeset) | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   def confirm_email(conn, %{"token" => token}) do | ||||
|     case Accounts.update_user_email(conn.assigns.current_user, token) do | ||||
|   def update( | ||||
|         %{assigns: %{current_user: user}} = conn, | ||||
|         %{"action" => "update_locale", "user" => %{"locale" => locale}} | ||||
|       ) do | ||||
|     case Accounts.update_user_locale(user, locale) do | ||||
|       {:ok, _user} -> | ||||
|         conn | ||||
|         |> put_flash(:info, dgettext("prompts", "Language updated successfully.")) | ||||
|         |> redirect(to: Routes.user_settings_path(conn, :edit)) | ||||
|  | ||||
|       {:error, changeset} -> | ||||
|         conn |> render("edit.html", locale_changeset: changeset) | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   def confirm_email(%{assigns: %{current_user: user}} = conn, %{"token" => token}) do | ||||
|     case Accounts.update_user_email(user, token) do | ||||
|       :ok -> | ||||
|         conn | ||||
|         |> put_flash(:info, dgettext("prompts", "Email changed successfully.")) | ||||
| @@ -84,11 +101,10 @@ defmodule LokalWeb.UserSettingsController do | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   defp assign_email_and_password_changesets(conn, _opts) do | ||||
|     user = conn.assigns.current_user | ||||
|  | ||||
|   defp assign_email_and_password_changesets(%{assigns: %{current_user: user}} = conn, _opts) do | ||||
|     conn | ||||
|     |> assign(:email_changeset, Accounts.change_user_email(user)) | ||||
|     |> assign(:password_changeset, Accounts.change_user_password(user)) | ||||
|     |> assign(:locale_changeset, Accounts.change_user_locale(user)) | ||||
|   end | ||||
| end | ||||
|   | ||||
							
								
								
									
										19
									
								
								lib/lokal_web/live/init_assigns.ex
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								lib/lokal_web/live/init_assigns.ex
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | ||||
| defmodule LokalWeb.InitAssigns do | ||||
|   @moduledoc """ | ||||
|   Ensures common `assigns` are applied to all LiveViews attaching this hook. | ||||
|   """ | ||||
|   import Phoenix.LiveView | ||||
|   alias Lokal.Accounts | ||||
|  | ||||
|   def on_mount(:default, _params, %{"locale" => locale, "user_token" => user_token}, socket) do | ||||
|     Gettext.put_locale(locale) | ||||
|  | ||||
|     socket = | ||||
|       socket | ||||
|       |> assign_new(:current_user, fn -> Accounts.get_user_by_session_token(user_token) end) | ||||
|  | ||||
|     {:cont, socket} | ||||
|   end | ||||
|  | ||||
|   def on_mount(:default, _params, _session, socket), do: {:cont, socket} | ||||
| end | ||||
| @@ -10,9 +10,7 @@ defmodule LokalWeb.InviteLive.Index do | ||||
|   alias Phoenix.LiveView.JS | ||||
|  | ||||
|   @impl true | ||||
|   def mount(_params, session, socket) do | ||||
|     %{assigns: %{current_user: current_user}} = socket = socket |> assign_defaults(session) | ||||
|  | ||||
|   def mount(_params, _session, %{assigns: %{current_user: current_user}} = socket) do | ||||
|     socket = | ||||
|       if current_user |> Map.get(:role) == :admin do | ||||
|         socket |> display_invites() | ||||
|   | ||||
| @@ -4,21 +4,8 @@ defmodule LokalWeb.LiveHelpers do | ||||
|   """ | ||||
|  | ||||
|   import Phoenix.LiveView.Helpers | ||||
|   import Phoenix.LiveView | ||||
|   alias Lokal.Accounts | ||||
|   alias Phoenix.LiveView.JS | ||||
|  | ||||
|   def assign_defaults(socket, %{"user_token" => user_token} = _session) do | ||||
|     socket | ||||
|     |> assign_new(:current_user, fn -> | ||||
|       Accounts.get_user_by_session_token(user_token) | ||||
|     end) | ||||
|   end | ||||
|  | ||||
|   def assign_defaults(socket, _session) do | ||||
|     socket | ||||
|   end | ||||
|  | ||||
|   @doc """ | ||||
|   Renders a live component inside a modal. | ||||
|  | ||||
|   | ||||
| @@ -6,13 +6,8 @@ defmodule LokalWeb.PageLive do | ||||
|   use LokalWeb, :live_view | ||||
|  | ||||
|   @impl true | ||||
|   def mount(_params, session, socket) do | ||||
|     socket = | ||||
|       socket | ||||
|       |> assign_defaults(session) | ||||
|       |> assign(page_title: gettext("Home"), query: "", results: %{}) | ||||
|  | ||||
|     {:ok, socket} | ||||
|   def mount(_params, _session, socket) do | ||||
|     {:ok, socket |> assign(page_title: gettext("Home"), query: "", results: %{})} | ||||
|   end | ||||
|  | ||||
|   @impl true | ||||
|   | ||||
| @@ -11,6 +11,17 @@ defmodule LokalWeb.Router do | ||||
|     plug :protect_from_forgery | ||||
|     plug :put_secure_browser_headers | ||||
|     plug :fetch_current_user | ||||
|     plug :put_user_locale, default: Application.get_env(:gettext, :default_locale, "en_US") | ||||
|   end | ||||
|  | ||||
|   defp put_user_locale(%{assigns: %{current_user: %{locale: locale}}} = conn, default: default) do | ||||
|     Gettext.put_locale(locale || default) | ||||
|     conn |> put_session(:locale, locale || default) | ||||
|   end | ||||
|  | ||||
|   defp put_user_locale(conn, default: default) do | ||||
|     Gettext.put_locale(default) | ||||
|     conn |> put_session(:locale, default) | ||||
|   end | ||||
|  | ||||
|   pipeline :require_admin do | ||||
|   | ||||
| @@ -30,6 +30,15 @@ | ||||
|     <%= password_input(f, :password, required: true, class: "input input-primary col-span-2") %> | ||||
|     <%= error_tag(f, :password, "col-span-3") %> | ||||
|  | ||||
|     <%= label(f, :locale, gettext("Language"), class: "title text-lg text-primary-600") %> | ||||
|     <%= select( | ||||
|       f, | ||||
|       :locale, | ||||
|       [{gettext("English"), "en_US"}], | ||||
|       class: "input input-primary col-span-2" | ||||
|     ) %> | ||||
|     <%= error_tag(f, :locale) %> | ||||
|  | ||||
|     <%= submit(dgettext("actions", "Register"), class: "mx-auto btn btn-primary col-span-3") %> | ||||
|   <% end %> | ||||
|  | ||||
|   | ||||
| @@ -1,17 +1,18 @@ | ||||
| <div class="mx-auto mb-8 max-w-2xl flex flex-col justify-center items-center space-y-4"> | ||||
| <div | ||||
|   class="mx-auto mb-8 max-w-2xl flex flex-col justify-center items-center text-center space-y-4" | ||||
| > | ||||
|   <h1 class="pb-4 title text-primary-600 text-xl"> | ||||
|     <%= gettext("Settings") %> | ||||
|   </h1> | ||||
|  | ||||
|   <hr class="hr" /> | ||||
|  | ||||
|   <%= form_for @email_changeset, | ||||
|            Routes.user_settings_path(@conn, :update), | ||||
|            [ | ||||
|              class: | ||||
|                "flex flex-col space-y-4 sm:space-y-0 sm:grid sm:grid-cols-3 sm:gap-4 justify-center items-center" | ||||
|            ], | ||||
|            fn f -> %> | ||||
|   <.form | ||||
|     let={f} | ||||
|     for={@email_changeset} | ||||
|     action={Routes.user_settings_path(@conn, :update)} | ||||
|     class="flex flex-col space-y-4 sm:space-y-0 sm:grid sm:grid-cols-3 sm:gap-4 justify-center items-center" | ||||
|   > | ||||
|     <h3 class="title text-primary-600 text-lg col-span-3"> | ||||
|       <%= dgettext("actions", "Change email") %> | ||||
|     </h3> | ||||
| @@ -45,17 +46,16 @@ | ||||
|     <%= submit(dgettext("actions", "Change email"), | ||||
|       class: "mx-auto btn btn-primary col-span-3" | ||||
|     ) %> | ||||
|   <% end %> | ||||
|   </.form> | ||||
|  | ||||
|   <hr class="hr" /> | ||||
|  | ||||
|   <%= form_for @password_changeset, | ||||
|            Routes.user_settings_path(@conn, :update), | ||||
|            [ | ||||
|              class: | ||||
|                "flex flex-col space-y-4 sm:space-y-0 sm:grid sm:grid-cols-3 sm:gap-4 justify-center items-center" | ||||
|            ], | ||||
|            fn f -> %> | ||||
|   <.form | ||||
|     let={f} | ||||
|     for={@password_changeset} | ||||
|     action={Routes.user_settings_path(@conn, :update)} | ||||
|     class="flex flex-col space-y-4 sm:space-y-0 sm:grid sm:grid-cols-3 sm:gap-4 justify-center items-center" | ||||
|   > | ||||
|     <h3 class="title text-primary-600 text-lg col-span-3"> | ||||
|       <%= dgettext("actions", "Change password") %> | ||||
|     </h3> | ||||
| @@ -101,7 +101,40 @@ | ||||
|     <%= submit(dgettext("actions", "Change password"), | ||||
|       class: "mx-auto btn btn-primary col-span-3" | ||||
|     ) %> | ||||
|   <% end %> | ||||
|   </.form> | ||||
|  | ||||
|   <hr class="hr" /> | ||||
|  | ||||
|   <.form | ||||
|     let={f} | ||||
|     for={@locale_changeset} | ||||
|     action={Routes.user_settings_path(@conn, :update)} | ||||
|     class="flex flex-col space-y-4 justify-center items-center" | ||||
|   > | ||||
|     <h3 class="title text-primary-600 text-lg"> | ||||
|       <%= dgettext("actions", "Change Language") %> | ||||
|     </h3> | ||||
|  | ||||
|     <%= if @locale_changeset.action && not @locale_changeset.valid? do %> | ||||
|       <div class="alert alert-danger"> | ||||
|         <p> | ||||
|           <%= dgettext("errors", "Oops, something went wrong! Please check the errors below.") %> | ||||
|         </p> | ||||
|       </div> | ||||
|     <% end %> | ||||
|  | ||||
|     <%= hidden_input(f, :action, name: "action", value: "update_locale") %> | ||||
|  | ||||
|     <%= select(f, :locale, [{gettext("English"), "en_US"}, {"Spanish", "es"}], | ||||
|       class: "mx-2 my-1 min-w-md input input-primary" | ||||
|     ) %> | ||||
|     <%= error_tag(f, :locale) %> | ||||
|  | ||||
|     <%= submit(dgettext("actions", "Change language"), | ||||
|       class: "whitespace-nowrap mx-auto btn btn-primary", | ||||
|       data: [qa: dgettext("prompts", "Are you sure you want to change your language?")] | ||||
|     ) %> | ||||
|   </.form> | ||||
|  | ||||
|   <hr class="hr" /> | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user