Packages
phoenix_kit
1.3.2
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
Current section
Files
lib/phoenix_kit_web/users/user_form.ex
defmodule PhoenixKitWeb.Users.UserForm do
@moduledoc """
LiveView for creating and editing users in the admin interface.
Provides a form for managing user data including email, password, roles,
and profile information. Supports both creation of new users and editing
existing users.
"""
use PhoenixKitWeb, :live_view
alias PhoenixKit.Users.Auth
alias PhoenixKit.Utils.Routes
def mount(params, _session, socket) do
# Handle locale
locale = params["locale"] || socket.assigns[:current_locale] || "en"
Gettext.put_locale(PhoenixKitWeb.Gettext, locale)
Process.put(:phoenix_kit_current_locale, locale)
user_id = params["id"]
mode = if user_id, do: :edit, else: :new
socket =
socket
|> assign(:current_locale, locale)
|> assign(:mode, mode)
|> assign(:user_id, user_id)
|> assign(:page_title, page_title(mode))
|> assign(:show_reset_password_modal, false)
|> assign(:show_password_field, false)
|> load_user_data(mode, user_id)
|> load_form_data()
{:ok, socket}
end
def handle_event("validate_user", %{"user" => user_params}, socket) do
# Filter password from params if password field is not shown
filtered_params =
if socket.assigns.mode == :edit and not socket.assigns.show_password_field do
Map.delete(user_params, "password")
else
user_params
end
changeset =
case socket.assigns.mode do
:new -> Auth.change_user_registration(%Auth.User{}, filtered_params)
:edit -> Auth.change_user_registration(socket.assigns.user, filtered_params)
end
|> Map.put(:action, :validate)
socket =
socket
|> assign(:changeset, changeset)
|> assign(:form_data, user_params)
{:noreply, socket}
end
def handle_event("save_user", %{"user" => user_params}, socket) do
case socket.assigns.mode do
:new -> create_user(socket, user_params)
:edit -> update_user(socket, user_params)
end
end
def handle_event("cancel", _params, socket) do
{:noreply, push_navigate(socket, to: Routes.path("/admin/users"))}
end
def handle_event("show_reset_password_modal", _params, socket) do
socket = assign(socket, :show_reset_password_modal, true)
{:noreply, socket}
end
def handle_event("hide_reset_password_modal", _params, socket) do
socket = assign(socket, :show_reset_password_modal, false)
{:noreply, socket}
end
def handle_event("admin_reset_password", _params, socket) do
user = socket.assigns.user
case Auth.deliver_user_reset_password_instructions(
user,
&Routes.url("/users/reset-password/#{&1}")
) do
{:ok, _} ->
socket =
socket
|> put_flash(
:info,
"Password reset email sent to #{user.email}. The user will receive instructions to reset their password."
)
|> assign(:show_reset_password_modal, false)
{:noreply, socket}
{:error, _reason} ->
socket =
put_flash(socket, :error, "Failed to send password reset email. Please try again.")
{:noreply, socket}
end
end
def handle_event("toggle_password_field", _params, socket) do
new_show_password_field = !socket.assigns.show_password_field
socket =
socket
|> assign(:show_password_field, new_show_password_field)
|> reload_changeset_with_password(new_show_password_field)
{:noreply, socket}
end
defp create_user(socket, user_params) do
case Auth.register_user(user_params) do
{:ok, user} ->
# Optionally send confirmation email
case Auth.deliver_user_confirmation_instructions(
user,
&Routes.url("/users/confirm/#{&1}")
) do
{:ok, _} -> :ok
# Continue even if email fails
{:error, _} -> :ok
end
socket =
socket
|> put_flash(:info, "User created successfully. Confirmation email sent.")
|> push_navigate(to: Routes.path("/admin/users"))
{:noreply, socket}
{:error, %Ecto.Changeset{} = changeset} ->
socket =
socket
|> assign(:changeset, changeset)
|> assign(:form_data, user_params)
{:noreply, socket}
end
end
defp update_user(socket, user_params) do
user = socket.assigns.user
show_password_field = socket.assigns.show_password_field
# Check if password update is needed
password_provided =
show_password_field and Map.has_key?(user_params, "password") and
user_params["password"] != nil and String.trim(user_params["password"]) != ""
if password_provided do
# Update both profile and password
case update_profile_and_password(user, user_params) do
{:ok, _updated_user} ->
socket =
socket
|> put_flash(:info, "User profile and password updated successfully.")
|> push_navigate(to: Routes.path("/admin/users"))
{:noreply, socket}
{:error, changeset} ->
socket =
socket
|> assign(:changeset, changeset)
|> assign(:form_data, user_params)
{:noreply, socket}
end
else
# Update profile only (exclude password)
profile_params = Map.delete(user_params, "password")
case Auth.update_user_profile(user, profile_params) do
{:ok, _user} ->
socket =
socket
|> put_flash(:info, "User updated successfully.")
|> push_navigate(to: Routes.path("/admin/users"))
{:noreply, socket}
{:error, %Ecto.Changeset{} = changeset} ->
socket =
socket
|> assign(:changeset, changeset)
|> assign(:form_data, user_params)
{:noreply, socket}
end
end
end
defp load_user_data(socket, :new, _user_id) do
assign(socket, :user, %Auth.User{})
end
defp load_user_data(socket, :edit, user_id) do
user = Auth.get_user!(user_id)
assign(socket, :user, user)
end
defp load_form_data(%{assigns: %{mode: :new}} = socket) do
changeset = Auth.change_user_registration(%Auth.User{}, %{})
socket
|> assign(:changeset, changeset)
|> assign(:form_data, %{
"email" => "",
"password" => "",
"first_name" => "",
"last_name" => ""
})
end
defp load_form_data(%{assigns: %{mode: :edit, user: user}} = socket) do
changeset = Auth.change_user_registration(user, %{})
socket
|> assign(:changeset, changeset)
|> assign(:form_data, %{
"email" => user.email || "",
"first_name" => user.first_name || "",
"last_name" => user.last_name || ""
})
end
defp page_title(:new), do: "Create User"
defp page_title(:edit), do: "Edit User"
defp reload_changeset_with_password(socket, show_password_field) do
case socket.assigns.mode do
:new ->
# For new users, password is always required
socket
:edit ->
# For edit mode, reload changeset to include/exclude password field
user = socket.assigns.user
form_data = socket.assigns.form_data || %{}
# Create changeset with or without password validation
changeset =
if show_password_field do
# Include password in changeset when field is shown
Auth.change_user_registration(user, form_data)
else
# Standard profile changeset when password field is hidden
Auth.change_user_registration(user, Map.delete(form_data, "password"))
end
assign(socket, :changeset, changeset)
end
end
defp update_profile_and_password(user, user_params) do
# First validate profile update
profile_params = Map.delete(user_params, "password")
case Auth.update_user_profile(user, profile_params) do
{:ok, updated_user} ->
# If profile update succeeded, update password
password_params = Map.take(user_params, ["password"])
case Auth.admin_update_user_password(updated_user, password_params) do
{:ok, final_user} ->
{:ok, final_user}
{:error, password_changeset} ->
# If password update failed, return a combined changeset
profile_changeset = Auth.change_user_registration(user, user_params)
combined_changeset = merge_password_errors(profile_changeset, password_changeset)
{:error, combined_changeset}
end
{:error, profile_changeset} ->
# Profile update failed, return the profile changeset with password field
{:error, profile_changeset}
end
end
defp merge_password_errors(profile_changeset, password_changeset) do
# Merge password errors into the profile changeset
password_errors = password_changeset.errors
Enum.reduce(password_errors, profile_changeset, fn {field, error}, acc ->
Ecto.Changeset.add_error(acc, field, elem(error, 0), elem(error, 1))
end)
end
end