Packages

phoenix_kit

1.3.0
1.7.208 1.7.207 1.7.206 1.7.205 1.7.204 1.7.203 1.7.202 1.7.201 1.7.200 1.7.199 1.7.198 1.7.197 1.7.196 1.7.194 1.7.193 1.7.192 1.7.191 1.7.190 1.7.189 1.7.187 1.7.186 1.7.185 1.7.184 1.7.183 1.7.182 1.7.181 1.7.180 1.7.179 1.7.178 1.7.177 1.7.176 1.7.175 1.7.174 1.7.173 1.7.172 1.7.171 1.7.170 1.7.169 1.7.168 1.7.167 1.7.166 1.7.165 1.7.164 1.7.162 1.7.161 1.7.160 1.7.159 1.7.157 1.7.156 1.7.155 1.7.154 1.7.153 1.7.152 1.7.151 1.7.150 1.7.149 1.7.146 1.7.145 1.7.144 1.7.143 1.7.138 1.7.133 1.7.132 1.7.131 1.7.130 1.7.128 1.7.126 1.7.125 1.7.121 1.7.120 1.7.119 1.7.118 1.7.117 1.7.116 1.7.115 1.7.114 1.7.113 1.7.112 1.7.111 1.7.110 1.7.109 1.7.108 1.7.107 1.7.106 1.7.105 1.7.104 1.7.103 1.7.102 1.7.101 1.7.100 1.7.99 1.7.98 1.7.97 1.7.96 1.7.95 1.7.94 1.7.93 1.7.92 1.7.91 1.7.90 1.7.89 1.7.88 1.7.87 1.7.86 1.7.85 1.7.84 1.7.83 1.7.82 1.7.81 1.7.80 1.7.79 1.7.78 1.7.77 1.7.76 1.7.75 1.7.74 1.7.71 1.7.70 1.7.69 1.7.66 1.7.65 1.7.64 1.7.63 1.7.62 1.7.61 1.7.59 1.7.58 1.7.57 1.7.56 1.7.55 1.7.54 1.7.53 1.7.52 1.7.51 1.7.49 1.7.44 1.7.43 1.7.42 1.7.41 1.7.39 1.7.38 1.7.37 1.7.36 1.7.34 1.7.33 1.7.31 1.7.30 1.7.29 1.7.28 1.7.27 1.7.26 1.7.25 1.7.24 1.7.23 1.7.22 1.7.21 1.7.20 1.7.19 1.7.18 1.7.17 1.7.16 1.7.15 1.7.14 1.7.13 1.7.12 1.7.11 1.7.10 1.7.9 1.7.8 1.7.7 1.7.6 1.7.5 1.7.4 1.7.3 1.7.2 1.7.1 1.7.0 1.6.20 1.6.19 1.6.18 1.6.17 1.6.16 1.6.15 1.6.14 1.6.13 1.6.12 1.6.11 1.6.10 1.6.9 1.6.8 1.6.7 1.6.6 1.6.5 1.6.4 1.6.3 1.5.2 1.5.1 1.5.0 1.4.9 1.4.8 1.4.7 1.4.6 1.4.5 1.4.4 1.4.3 1.4.2 1.4.1 1.4.0 1.3.2 1.3.1 1.3.0 1.2.10 1.2.9 1.2.8 1.2.7 1.2.5 1.2.4 1.2.2 1.2.1 1.2.0 1.1.0 1.0.0

A foundation for building Elixir Phoenix apps — SaaS, social networks, ERP systems, marketplaces, and more

Current section

Files

Jump to
phoenix_kit lib phoenix_kit_web users settings.ex
Raw

lib/phoenix_kit_web/users/settings.ex

defmodule PhoenixKitWeb.Users.Settings do
@moduledoc """
LiveView for user account settings management.
Allows authenticated users to update their email, password, profile information,
and personal preferences such as timezone, date format, and time format.
"""
use PhoenixKitWeb, :live_view
alias PhoenixKit.Settings
alias PhoenixKit.Users.Auth
alias PhoenixKit.Utils.Routes
def mount(%{"token" => token}, _session, socket) do
socket =
case Auth.update_user_email(socket.assigns.phoenix_kit_current_user, token) do
:ok ->
put_flash(socket, :info, "Email changed successfully.")
:error ->
put_flash(socket, :error, "Email change link is invalid or it has expired.")
end
{:ok, push_navigate(socket, to: Routes.path("/users/settings"))}
end
def mount(_params, _session, socket) do
user = socket.assigns.phoenix_kit_current_user
email_changeset = Auth.change_user_email(user)
password_changeset = Auth.change_user_password(user)
profile_changeset = Auth.change_user_profile(user)
# Get timezone options from Settings module
setting_options = Settings.get_setting_options()
timezone_options = [{"Use System Default", nil} | setting_options["time_zone"]]
socket =
socket
|> assign(:current_password, nil)
|> assign(:email_form_current_password, nil)
|> assign(:current_email, user.email)
|> assign(:email_form, to_form(email_changeset))
|> assign(:password_form, to_form(password_changeset))
|> assign(:profile_form, to_form(profile_changeset))
|> assign(:timezone_options, timezone_options)
|> assign(:browser_timezone_name, nil)
|> assign(:browser_timezone_offset, nil)
|> assign(:timezone_mismatch_warning, nil)
|> assign(:trigger_submit, false)
{:ok, socket}
end
def handle_event("validate_email", params, socket) do
%{"current_password" => password, "user" => user_params} = params
email_form =
socket.assigns.phoenix_kit_current_user
|> Auth.change_user_email(user_params)
|> Map.put(:action, :validate)
|> to_form()
{:noreply, assign(socket, email_form: email_form, email_form_current_password: password)}
end
def handle_event("update_email", params, socket) do
%{"current_password" => password, "user" => user_params} = params
user = socket.assigns.phoenix_kit_current_user
case Auth.apply_user_email(user, password, user_params) do
{:ok, applied_user} ->
Auth.deliver_user_update_email_instructions(
applied_user,
user.email,
&Routes.url("/users/settings/confirm-email/#{&1}")
)
info = "A link to confirm your email change has been sent to the new address."
{:noreply, socket |> put_flash(:info, info) |> assign(email_form_current_password: nil)}
{:error, changeset} ->
{:noreply, assign(socket, :email_form, to_form(Map.put(changeset, :action, :insert)))}
end
end
def handle_event("validate_password", params, socket) do
%{"current_password" => password, "user" => user_params} = params
password_form =
socket.assigns.phoenix_kit_current_user
|> Auth.change_user_password(user_params)
|> Map.put(:action, :validate)
|> to_form()
{:noreply, assign(socket, password_form: password_form, current_password: password)}
end
def handle_event("update_password", params, socket) do
%{"current_password" => password, "user" => user_params} = params
user = socket.assigns.phoenix_kit_current_user
case Auth.update_user_password(user, password, user_params) do
{:ok, user} ->
password_form =
user
|> Auth.change_user_password(user_params)
|> to_form()
{:noreply, assign(socket, trigger_submit: true, password_form: password_form)}
{:error, changeset} ->
{:noreply, assign(socket, password_form: to_form(changeset))}
end
end
def handle_event("validate_profile", params, socket) do
%{"user" => user_params} = params
# Check if browser timezone data is included in the form submission
socket =
case {params["browser_timezone_name"], params["browser_timezone_offset"]} do
{name, offset} when is_binary(name) and is_binary(offset) ->
socket
|> assign(:browser_timezone_name, name)
|> assign(:browser_timezone_offset, offset)
_ ->
socket
end
profile_form =
socket.assigns.phoenix_kit_current_user
|> Auth.change_user_profile(user_params)
|> Map.put(:action, :validate)
|> to_form()
# Check for timezone mismatch when user changes timezone
socket =
socket
|> assign(profile_form: profile_form)
|> check_timezone_mismatch(user_params["user_timezone"])
{:noreply, socket}
end
def handle_event("update_profile", params, socket) do
%{"user" => user_params} = params
user = socket.assigns.phoenix_kit_current_user
case Auth.update_user_profile(user, user_params) do
{:ok, _user} ->
{:noreply, socket |> put_flash(:info, "Profile updated successfully")}
{:error, changeset} ->
{:noreply, assign(socket, :profile_form, to_form(Map.put(changeset, :action, :insert)))}
end
end
def handle_event("use_browser_timezone", _params, socket) do
browser_offset = socket.assigns.browser_timezone_offset
if browser_offset do
# Update the profile form with browser timezone
user = socket.assigns.phoenix_kit_current_user
updated_attrs = %{"user_timezone" => browser_offset}
profile_form =
user
|> Auth.change_user_profile(updated_attrs)
|> to_form()
socket =
socket
|> assign(:profile_form, profile_form)
|> assign(:timezone_mismatch_warning, nil)
{:noreply, socket}
else
{:noreply, socket}
end
end
# Check for timezone mismatch based on current form values
defp check_timezone_mismatch(socket, selected_timezone) do
browser_offset = socket.assigns[:browser_timezone_offset]
browser_name = socket.assigns[:browser_timezone_name]
# Get selected timezone from parameters or current form value
user_timezone =
selected_timezone ||
get_in(socket.assigns.profile_form.params, ["user_timezone"]) ||
socket.assigns.phoenix_kit_current_user.user_timezone
case {browser_offset, user_timezone} do
{nil, _} ->
# No browser timezone detected, no warning
assign(socket, :timezone_mismatch_warning, nil)
{browser_tz, nil} when browser_tz != "0" ->
# User selected "Use System Default" but browser is not UTC
system_tz = Settings.get_setting("time_zone", "0")
if browser_tz != system_tz do
warning_msg =
"Your browser timezone appears to be #{browser_name} (#{format_timezone_offset(browser_tz)}) " <>
"but you selected 'Use System Default' which is #{format_timezone_offset(system_tz)}."
assign(socket, :timezone_mismatch_warning, warning_msg)
else
assign(socket, :timezone_mismatch_warning, nil)
end
{browser_tz, user_tz} when browser_tz != user_tz ->
# Normalize user timezone for comparison (remove + if present, browser_tz has +)
normalized_user_tz = String.replace(user_tz, "+", "")
normalized_browser_tz = String.replace(browser_tz, "+", "")
# Only show warning if they're actually different (not just formatting)
if normalized_browser_tz != normalized_user_tz do
# User selected specific timezone that doesn't match browser
warning_msg =
"Your browser timezone appears to be #{browser_name} (#{format_timezone_offset(browser_tz)}) " <>
"but you selected #{format_timezone_offset(user_tz)}. Please verify this is correct."
assign(socket, :timezone_mismatch_warning, warning_msg)
else
assign(socket, :timezone_mismatch_warning, nil)
end
_ ->
# Timezones match or no significant difference
assign(socket, :timezone_mismatch_warning, nil)
end
end
# Format timezone offset for display
defp format_timezone_offset(offset) do
case offset do
"0" ->
"UTC+0"
"+" <> _ ->
"UTC" <> offset
"-" <> _ ->
"UTC" <> offset
_ when is_binary(offset) ->
# If it's a positive number without +, add the +
case Integer.parse(offset) do
{num, ""} when num > 0 -> "UTC+" <> offset
{num, ""} when num < 0 -> "UTC" <> offset
{0, ""} -> "UTC+0"
_ -> "UTC" <> offset
end
_ ->
"Unknown"
end
end
defp show_dev_notice? do
case Application.get_env(:phoenix_kit, PhoenixKit.Mailer)[:adapter] do
Swoosh.Adapters.Local -> true
_ -> false
end
end
end