diff --git a/lib/phoenix_kit/users/auth/user.ex b/lib/phoenix_kit/users/auth/user.ex index 2349ff848..b8b1e2646 100644 --- a/lib/phoenix_kit/users/auth/user.ex +++ b/lib/phoenix_kit/users/auth/user.ex @@ -519,7 +519,19 @@ 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 @@ -527,6 +539,7 @@ defmodule PhoenixKit.Users.Auth.User do end _ -> + # User has manually entered a username, don't override it changeset end end diff --git a/lib/phoenix_kit_web/live/components/media_selector_modal.ex b/lib/phoenix_kit_web/live/components/media_selector_modal.ex index a26d9b42c..ca29333c4 100644 --- a/lib/phoenix_kit_web/live/components/media_selector_modal.ex +++ b/lib/phoenix_kit_web/live/components/media_selector_modal.ex @@ -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 diff --git a/lib/phoenix_kit_web/users/user_form.ex b/lib/phoenix_kit_web/users/user_form.ex index 188b4452a..7a123ae0e 100644 --- a/lib/phoenix_kit_web/users/user_form.ex +++ b/lib/phoenix_kit_web/users/user_form.ex @@ -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() @@ -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} -> @@ -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) diff --git a/lib/phoenix_kit_web/users/user_form.html.heex b/lib/phoenix_kit_web/users/user_form.html.heex index 9df5ad977..ee06f3b32 100644 --- a/lib/phoenix_kit_web/users/user_form.html.heex +++ b/lib/phoenix_kit_web/users/user_form.html.heex @@ -38,9 +38,11 @@
<%!-- Avatar Preview (Left) --%>
- <% 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" %> -
+
<%= if avatar_file_id do %> <% avatar_url = PhoenixKit.Storage.URLSigner.signed_url(avatar_file_id, variant) %> @@ -59,6 +61,12 @@

Avatar

+ <%!-- Pending Badge --%> + <%= if @pending_avatar_file_id do %> +
+ Pending +
+ <% end %> <% else %> <% initials = (@user.first_name || @user.email) @@ -95,10 +103,17 @@ <%!-- Current Avatar Info --%> <%= if avatar_file_id do %> -
- <.icon name="hero-check-circle" class="w-4 h-4 inline text-success" /> - Avatar selected -
+ <%= if @pending_avatar_file_id do %> +
+ <.icon name="hero-clock" class="w-4 h-4 inline" /> + New avatar pending - click "Update User" to save +
+ <% else %> +
+ <.icon name="hero-check-circle" class="w-4 h-4 inline text-success" /> + Avatar selected +
+ <% end %> <% end %>
@@ -693,6 +708,7 @@ show={@show_media_selector} mode={:single} selected_ids={[current_avatar_id]} + phoenix_kit_current_user={@phoenix_kit_current_user} /> <% else %> <.live_component @@ -700,6 +716,7 @@ id="media-selector-modal" show={@show_media_selector} mode={:single} + phoenix_kit_current_user={@phoenix_kit_current_user} /> <% end %> <% end %>