From 675fbb7245067ffac08012d572d98c13eee535f8 Mon Sep 17 00:00:00 2001 From: Kilian von Pflugk Date: Wed, 29 Apr 2026 15:53:52 +0200 Subject: [PATCH 1/2] fix: persist form state across mobile app switches - auto-save settings/availability on blur so unsaved changes survive LiveView reconnects - use localStorage (not sessionStorage) for LocalStateStore hooks so state survives tab kills on mobile - forward phx-debounce through simple_form component --- lib/algora_web/components/core_components.ex | 2 +- lib/algora_web/live/onboarding/dev.ex | 2 +- lib/algora_web/live/org/dashboard_live.ex | 2 +- lib/algora_web/live/sign_in_live.ex | 2 +- lib/algora_web/live/user/dashboard_live.ex | 18 ++++++++++++++++-- lib/algora_web/live/user/settings_live.ex | 15 ++++++++++++--- 6 files changed, 32 insertions(+), 9 deletions(-) diff --git a/lib/algora_web/components/core_components.ex b/lib/algora_web/components/core_components.ex index 5fcdc71f2..e68a2c71c 100644 --- a/lib/algora_web/components/core_components.ex +++ b/lib/algora_web/components/core_components.ex @@ -671,7 +671,7 @@ defmodule AlgoraWeb.CoreComponents do attr :class, :string, default: nil, doc: "the class to apply to the form" attr :rest, :global, - include: ~w(autocomplete name rel action enctype method novalidate target), + include: ~w(autocomplete name rel action enctype method novalidate target phx-debounce), doc: "the arbitrary HTML attributes to apply to the form tag" slot :inner_block, required: true diff --git a/lib/algora_web/live/onboarding/dev.ex b/lib/algora_web/live/onboarding/dev.ex index 10d217c01..d9aef1334 100644 --- a/lib/algora_web/live/onboarding/dev.ex +++ b/lib/algora_web/live/onboarding/dev.ex @@ -122,7 +122,7 @@ defmodule AlgoraWeb.Onboarding.DevLive do @impl true def render(assigns) do ~H""" -
+
diff --git a/lib/algora_web/live/org/dashboard_live.ex b/lib/algora_web/live/org/dashboard_live.ex index e295deae5..6f9808f0b 100644 --- a/lib/algora_web/live/org/dashboard_live.ex +++ b/lib/algora_web/live/org/dashboard_live.ex @@ -205,7 +205,7 @@ defmodule AlgoraWeb.Org.DashboardLive do @impl true def render(assigns) do ~H""" -
+
<.section :if={@payable_bounties != %{}}> <.card> diff --git a/lib/algora_web/live/sign_in_live.ex b/lib/algora_web/live/sign_in_live.ex index 9fb76ccef..069ab374f 100644 --- a/lib/algora_web/live/sign_in_live.ex +++ b/lib/algora_web/live/sign_in_live.ex @@ -14,7 +14,7 @@ defmodule AlgoraWeb.SignInLive do @impl true def render(assigns) do ~H""" -
+
<.wordmark class="h-10 w-auto absolute top-4 left-4 sm:top-8 sm:left-8" />
diff --git a/lib/algora_web/live/user/dashboard_live.ex b/lib/algora_web/live/user/dashboard_live.ex index 7ec4659fa..15a2a867c 100644 --- a/lib/algora_web/live/user/dashboard_live.ex +++ b/lib/algora_web/live/user/dashboard_live.ex @@ -206,6 +206,7 @@ defmodule AlgoraWeb.User.DashboardLive do id="availability-form" phx-change="validate_availability" phx-submit="save_availability" + phx-debounce="blur" class="grid grid-cols-1 lg:grid-cols-2 gap-4" > <.input @@ -405,8 +406,21 @@ defmodule AlgoraWeb.User.DashboardLive do @impl true def handle_event("validate_availability", %{"availability_form" => params}, socket) do - changeset = AvailabilityForm.changeset(socket.assigns.availability_form.source, params) - {:noreply, assign(socket, availability_form: to_form(changeset))} + changeset = + socket.assigns.availability_form.source + |> AvailabilityForm.changeset(params) + |> Map.put(:action, :validate) + + socket = assign(socket, availability_form: to_form(changeset)) + + if changeset.valid? do + case Accounts.update_settings(socket.assigns.current_user, params) do + {:ok, user} -> {:noreply, assign(socket, :current_user, user)} + {:error, save_changeset} -> {:noreply, assign(socket, availability_form: to_form(save_changeset))} + end + else + {:noreply, socket} + end end @impl true diff --git a/lib/algora_web/live/user/settings_live.ex b/lib/algora_web/live/user/settings_live.ex index 3e509e580..77c04ccfc 100644 --- a/lib/algora_web/live/user/settings_live.ex +++ b/lib/algora_web/live/user/settings_live.ex @@ -18,7 +18,7 @@ defmodule AlgoraWeb.User.SettingsLive do <.card_title>Account <.card_content> - <.simple_form for={@form} phx-change="validate" phx-submit="save"> + <.simple_form for={@form} phx-change="validate" phx-submit="save" phx-debounce="blur">
<.input field={@form[:handle]} label="Handle" /> @@ -45,7 +45,7 @@ defmodule AlgoraWeb.User.SettingsLive do <.card_title>Public Profile <.card_content> - <.simple_form for={@form} phx-change="validate" phx-submit="save"> + <.simple_form for={@form} phx-change="validate" phx-submit="save" phx-debounce="blur">
<.input field={@form[:display_name]} label="Name" /> <.input field={@form[:bio]} type="textarea" label="Bio" /> @@ -83,7 +83,16 @@ defmodule AlgoraWeb.User.SettingsLive do |> User.settings_changeset(params) |> Map.put(:action, :validate) - {:noreply, assign_form(socket, changeset)} + socket = assign_form(socket, changeset) + + if changeset.valid? do + case Accounts.update_settings(socket.assigns.current_user, params) do + {:ok, user} -> {:noreply, assign(socket, current_user: user)} + {:error, save_changeset} -> {:noreply, assign_form(socket, save_changeset)} + end + else + {:noreply, socket} + end end def handle_event("save", %{"user" => params}, socket) do From 568c1df811c40bebc0b93e71f6d3885a911979a4 Mon Sep 17 00:00:00 2001 From: Kilian von Pflugk Date: Wed, 29 Apr 2026 16:03:27 +0200 Subject: [PATCH 2/2] fix: add data-storage=localStorage to second LocalStateStore in dev.ex --- lib/algora_web/live/onboarding/dev.ex | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/algora_web/live/onboarding/dev.ex b/lib/algora_web/live/onboarding/dev.ex index d9aef1334..54b296742 100644 --- a/lib/algora_web/live/onboarding/dev.ex +++ b/lib/algora_web/live/onboarding/dev.ex @@ -97,6 +97,7 @@ defmodule AlgoraWeb.Onboarding.DevLive do class="w-screen h-screen fixed inset-0 bg-background z-[100]" phx-hook="LocalStateStore" id="onboarding-dev-page" + data-storage="localStorage" >