From 44818889765e604b4d486fb392c5219ab51c7794 Mon Sep 17 00:00:00 2001 From: Graham McIntire Date: Fri, 20 Feb 2026 17:09:12 -0600 Subject: [PATCH] Fix settings page showing validation errors on initial load The email and callsign changesets add "did not change" errors when created with empty attrs (on mount). Guard all field error displays on changeset.action being set so errors only appear after user interaction. --- lib/aprsme_web/live/user_settings_live.ex | 28 +++++++++---------- .../live/user_settings_live_test.exs | 8 ++++++ 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/lib/aprsme_web/live/user_settings_live.ex b/lib/aprsme_web/live/user_settings_live.ex index 1c5d372..b7b4c2c 100644 --- a/lib/aprsme_web/live/user_settings_live.ex +++ b/lib/aprsme_web/live/user_settings_live.ex @@ -42,7 +42,7 @@ defmodule AprsmeWeb.UserSettingsLive do value={Phoenix.HTML.Form.input_value(f, :email) || ""} class={[ "block w-full rounded-md bg-white px-3 py-1.5 text-base text-gray-900 outline-1 -outline-offset-1 placeholder:text-gray-400 focus:outline-2 focus:-outline-offset-2 focus:outline-indigo-600 sm:text-sm/6 dark:bg-white/5 dark:text-white dark:placeholder:text-gray-500 dark:focus:outline-indigo-500", - if(Keyword.has_key?(@email_changeset.errors, :email), + if(@email_changeset.action && Keyword.has_key?(@email_changeset.errors, :email), do: "outline-red-500 dark:outline-red-400", else: "outline-gray-300 dark:outline-white/10" ) @@ -52,7 +52,7 @@ defmodule AprsmeWeb.UserSettingsLive do />

{translate_error(Keyword.get(@email_changeset.errors, :email))} @@ -69,7 +69,7 @@ defmodule AprsmeWeb.UserSettingsLive do value={@email_form_current_password || ""} class={[ "block w-full rounded-md bg-white px-3 py-1.5 text-base text-gray-900 outline-1 -outline-offset-1 placeholder:text-gray-400 focus:outline-2 focus:-outline-offset-2 focus:outline-indigo-600 sm:text-sm/6 dark:bg-white/5 dark:text-white dark:placeholder:text-gray-500 dark:focus:outline-indigo-500", - if(Keyword.has_key?(@email_changeset.errors, :current_password), + if(@email_changeset.action && Keyword.has_key?(@email_changeset.errors, :current_password), do: "outline-red-500 dark:outline-red-400", else: "outline-gray-300 dark:outline-white/10" ) @@ -79,7 +79,7 @@ defmodule AprsmeWeb.UserSettingsLive do />

{translate_error(Keyword.get(@email_changeset.errors, :current_password))} @@ -124,7 +124,7 @@ defmodule AprsmeWeb.UserSettingsLive do value={Phoenix.HTML.Form.input_value(f, :callsign) || ""} class={[ "block w-full rounded-md bg-white px-3 py-1.5 text-base text-gray-900 outline-1 -outline-offset-1 placeholder:text-gray-400 focus:outline-2 focus:-outline-offset-2 focus:outline-indigo-600 sm:text-sm/6 dark:bg-white/5 dark:text-white dark:placeholder:text-gray-500 dark:focus:outline-indigo-500", - if(Keyword.has_key?(@callsign_changeset.errors, :callsign), + if(@callsign_changeset.action && Keyword.has_key?(@callsign_changeset.errors, :callsign), do: "outline-red-500 dark:outline-red-400", else: "outline-gray-300 dark:outline-white/10" ) @@ -134,7 +134,7 @@ defmodule AprsmeWeb.UserSettingsLive do />

{translate_error(Keyword.get(@callsign_changeset.errors, :callsign))} @@ -151,7 +151,7 @@ defmodule AprsmeWeb.UserSettingsLive do value={@callsign_form_current_password || ""} class={[ "block w-full rounded-md bg-white px-3 py-1.5 text-base text-gray-900 outline-1 -outline-offset-1 placeholder:text-gray-400 focus:outline-2 focus:-outline-offset-2 focus:outline-indigo-600 sm:text-sm/6 dark:bg-white/5 dark:text-white dark:placeholder:text-gray-500 dark:focus:outline-indigo-500", - if(Keyword.has_key?(@callsign_changeset.errors, :current_password), + if(@callsign_changeset.action && Keyword.has_key?(@callsign_changeset.errors, :current_password), do: "outline-red-500 dark:outline-red-400", else: "outline-gray-300 dark:outline-white/10" ) @@ -161,7 +161,7 @@ defmodule AprsmeWeb.UserSettingsLive do />

{translate_error(Keyword.get(@callsign_changeset.errors, :current_password))} @@ -211,7 +211,7 @@ defmodule AprsmeWeb.UserSettingsLive do value={Phoenix.HTML.Form.input_value(f, :password) || ""} class={[ "block w-full rounded-md bg-white px-3 py-1.5 text-base text-gray-900 outline-1 -outline-offset-1 placeholder:text-gray-400 focus:outline-2 focus:-outline-offset-2 focus:outline-indigo-600 sm:text-sm/6 dark:bg-white/5 dark:text-white dark:placeholder:text-gray-500 dark:focus:outline-indigo-500", - if(Keyword.has_key?(@password_changeset.errors, :password), + if(@password_changeset.action && Keyword.has_key?(@password_changeset.errors, :password), do: "outline-red-500 dark:outline-red-400", else: "outline-gray-300 dark:outline-white/10" ) @@ -221,7 +221,7 @@ defmodule AprsmeWeb.UserSettingsLive do />

{translate_error(Keyword.get(@password_changeset.errors, :password))} @@ -237,7 +237,7 @@ defmodule AprsmeWeb.UserSettingsLive do value={Phoenix.HTML.Form.input_value(f, :password_confirmation) || ""} class={[ "block w-full rounded-md bg-white px-3 py-1.5 text-base text-gray-900 outline-1 -outline-offset-1 placeholder:text-gray-400 focus:outline-2 focus:-outline-offset-2 focus:outline-indigo-600 sm:text-sm/6 dark:bg-white/5 dark:text-white dark:placeholder:text-gray-500 dark:focus:outline-indigo-500", - if(Keyword.has_key?(@password_changeset.errors, :password_confirmation), + if(@password_changeset.action && Keyword.has_key?(@password_changeset.errors, :password_confirmation), do: "outline-red-500 dark:outline-red-400", else: "outline-gray-300 dark:outline-white/10" ) @@ -247,7 +247,7 @@ defmodule AprsmeWeb.UserSettingsLive do />

{translate_error(Keyword.get(@password_changeset.errors, :password_confirmation))} @@ -264,7 +264,7 @@ defmodule AprsmeWeb.UserSettingsLive do value={@current_password || ""} class={[ "block w-full rounded-md bg-white px-3 py-1.5 text-base text-gray-900 outline-1 -outline-offset-1 placeholder:text-gray-400 focus:outline-2 focus:-outline-offset-2 focus:outline-indigo-600 sm:text-sm/6 dark:bg-white/5 dark:text-white dark:placeholder:text-gray-500 dark:focus:outline-indigo-500", - if(Keyword.has_key?(@password_changeset.errors, :current_password), + if(@password_changeset.action && Keyword.has_key?(@password_changeset.errors, :current_password), do: "outline-red-500 dark:outline-red-400", else: "outline-gray-300 dark:outline-white/10" ) @@ -274,7 +274,7 @@ defmodule AprsmeWeb.UserSettingsLive do />

{translate_error(Keyword.get(@password_changeset.errors, :current_password))} diff --git a/test/aprsme_web/live/user_settings_live_test.exs b/test/aprsme_web/live/user_settings_live_test.exs index 1702d7b..c987888 100644 --- a/test/aprsme_web/live/user_settings_live_test.exs +++ b/test/aprsme_web/live/user_settings_live_test.exs @@ -21,6 +21,14 @@ defmodule AprsmeWeb.UserSettingsLiveTest do assert html =~ "Change Password" end + test "does not show validation errors on initial load", %{conn: conn} do + {:ok, _lv, html} = live(conn, ~p"/users/settings", on_error: :warn) + + refute html =~ "did not change" + refute html =~ "can't be blank" + refute html =~ "can't be blank" + end + test "redirects if user is not logged in" do conn = build_conn()