Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion lib/phoenix_kit/users/auth/user.ex
Original file line number Diff line number Diff line change
Expand Up @@ -519,14 +519,27 @@ defmodule PhoenixKit.Users.Auth.User do
nil ->
email = get_change(changeset, :email) || get_field(changeset, :email)

if email do
# Only generate username if email contains "@" to ensure user finishes typing
if email && String.contains?(email, "@") do
generated_username = generate_unique_username_from_email(email)
put_change(changeset, :username, generated_username)
else
changeset
end

"" ->
# Treat empty string same as nil - allow generation if email has "@"
email = get_change(changeset, :email) || get_field(changeset, :email)

if email && String.contains?(email, "@") do
generated_username = generate_unique_username_from_email(email)
put_change(changeset, :username, generated_username)
else
changeset
end

_ ->
# User has manually entered a username, don't override it
changeset
end
end
Expand Down
3 changes: 2 additions & 1 deletion lib/phoenix_kit_web/live/components/media_selector_modal.ex
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,14 @@ defmodule PhoenixKitWeb.Live.Components.MediaSelectorModal do
|> assign(:media_selection_mode, :single)
|> assign(:media_selected_ids, [])

# In template
# In template (IMPORTANT: Must pass phoenix_kit_current_user for uploads to work)
<.live_component
module={PhoenixKitWeb.Live.Components.MediaSelectorModal}
id="media-selector-modal"
show={@show_media_selector}
mode={@media_selection_mode}
selected_ids={@media_selected_ids}
phoenix_kit_current_user={@phoenix_kit_current_user}
/>

# To open the modal
Expand Down
45 changes: 26 additions & 19 deletions lib/phoenix_kit_web/users/user_form.ex
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ defmodule PhoenixKitWeb.Users.UserForm do
|> assign(:default_role, default_role)
|> assign(:timezone_options, timezone_options)
|> assign(:show_media_selector, false)
|> assign(:pending_avatar_file_id, nil)
|> assign(:avatar_changed, false)
|> load_user_data(mode, user_id)
|> load_form_data()

Expand Down Expand Up @@ -336,12 +338,27 @@ defmodule PhoenixKitWeb.Users.UserForm do
defp update_user(socket, user_params) do
user = socket.assigns.user
custom_fields_params = Map.get(user_params, "custom_fields", %{})

# Include pending avatar if it was changed via media selector
custom_fields_params =
if socket.assigns[:avatar_changed] && socket.assigns[:pending_avatar_file_id] do
Map.put(custom_fields_params, "avatar_file_id", socket.assigns.pending_avatar_file_id)
else
custom_fields_params
end

profile_params = Map.delete(user_params, "custom_fields")

with :ok <- validate_custom_fields(user, custom_fields_params),
{:ok, updated_user} <- update_user_profile(socket, user, profile_params),
{:ok, user_with_fields} <- update_custom_fields(updated_user, custom_fields_params),
result <- update_user_roles_if_changed(socket, user_with_fields) do
# Clear avatar change flag after successful update
socket =
socket
|> assign(:avatar_changed, false)
|> assign(:pending_avatar_file_id, nil)

handle_update_result(socket, result)
else
{:error, %Ecto.Changeset{} = changeset} ->
Expand Down Expand Up @@ -680,27 +697,17 @@ defmodule PhoenixKitWeb.Users.UserForm do
# Get the first selected file ID (single selection mode)
avatar_file_id = List.first(file_ids)

# Update user with new avatar
user = socket.assigns.user

# Store avatar selection without saving to database yet
# Avatar will be saved when "Update User" button is clicked
socket =
if avatar_file_id && user do
case Auth.update_user_fields(user, %{"avatar_file_id" => avatar_file_id}) do
{:ok, updated_user} ->
Logger.info("Avatar updated to file_id: #{avatar_file_id}")

socket
|> assign(:user, updated_user)
|> assign(:show_media_selector, false)
|> put_flash(:info, "Avatar updated successfully!")

{:error, changeset} ->
Logger.error("Failed to update avatar: #{inspect(changeset)}")
if avatar_file_id do
Logger.info("Avatar selected (pending save): #{avatar_file_id}")

socket
|> assign(:show_media_selector, false)
|> put_flash(:error, "Failed to update avatar")
end
socket
|> assign(:pending_avatar_file_id, avatar_file_id)
|> assign(:avatar_changed, true)
|> assign(:show_media_selector, false)
|> put_flash(:info, "Avatar selected. Click 'Update User' to save.")
else
socket
|> assign(:show_media_selector, false)
Expand Down
29 changes: 23 additions & 6 deletions lib/phoenix_kit_web/users/user_form.html.heex
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,11 @@
<div class="flex gap-6">
<%!-- Avatar Preview (Left) --%>
<div class="flex-shrink-0">
<% avatar_file_id = @user.custom_fields && @user.custom_fields["avatar_file_id"] %>
<% avatar_file_id =
@pending_avatar_file_id ||
(@user.custom_fields && @user.custom_fields["avatar_file_id"]) %>
<% variant = "medium" %>
<div class="w-32 h-32 bg-primary rounded-lg overflow-hidden flex items-center justify-center">
<div class="w-32 h-32 bg-primary rounded-lg overflow-hidden flex items-center justify-center relative">
<%= if avatar_file_id do %>
<% avatar_url =
PhoenixKit.Storage.URLSigner.signed_url(avatar_file_id, variant) %>
Expand All @@ -59,6 +61,12 @@
<p class="text-xs text-primary-content">Avatar</p>
</div>
</div>
<%!-- Pending Badge --%>
<%= if @pending_avatar_file_id do %>
<div class="absolute top-2 right-2 badge badge-warning badge-sm">
Pending
</div>
<% end %>
<% else %>
<% initials =
(@user.first_name || @user.email)
Expand Down Expand Up @@ -95,10 +103,17 @@

<%!-- Current Avatar Info --%>
<%= if avatar_file_id do %>
<div class="text-sm text-base-content/60">
<.icon name="hero-check-circle" class="w-4 h-4 inline text-success" />
Avatar selected
</div>
<%= if @pending_avatar_file_id do %>
<div class="text-sm text-warning font-semibold">
<.icon name="hero-clock" class="w-4 h-4 inline" />
New avatar pending - click "Update User" to save
</div>
<% else %>
<div class="text-sm text-base-content/60">
<.icon name="hero-check-circle" class="w-4 h-4 inline text-success" />
Avatar selected
</div>
<% end %>
<% end %>
</div>
</div>
Expand Down Expand Up @@ -693,13 +708,15 @@
show={@show_media_selector}
mode={:single}
selected_ids={[current_avatar_id]}
phoenix_kit_current_user={@phoenix_kit_current_user}
/>
<% else %>
<.live_component
module={PhoenixKitWeb.Live.Components.MediaSelectorModal}
id="media-selector-modal"
show={@show_media_selector}
mode={:single}
phoenix_kit_current_user={@phoenix_kit_current_user}
/>
<% end %>
<% end %>
Expand Down
Loading