feat(accounts): add Home QTH section to user settings page

This commit is contained in:
Graham McIntire 2026-04-25 16:51:54 -05:00
parent 784caa7699
commit 771299c951
No known key found for this signature in database
GPG key ID: F4ABF488E6029E59
4 changed files with 95 additions and 0 deletions

View file

@ -235,6 +235,23 @@ defmodule Microwaveprop.Accounts do
|> update_user_and_delete_all_tokens()
end
@doc """
Builds a home-QTH changeset from the given attrs (no DB write).
Useful for rendering the form in templates and LiveViews.
"""
@spec change_user_home_qth(User.t(), map()) :: Ecto.Changeset.t()
def change_user_home_qth(%User{} = user, attrs \\ %{}) do
User.change_home_qth(user, attrs)
end
@doc """
Updates the user's home QTH (grid + lat/lon + optional elevation).
"""
@spec update_user_home_qth(User.t(), map()) :: {:ok, User.t()} | {:error, Ecto.Changeset.t()}
def update_user_home_qth(%User{} = user, attrs) do
user |> User.change_home_qth(attrs) |> Repo.update()
end
## Session
@doc """

View file

@ -9,6 +9,7 @@ defmodule MicrowavepropWeb.UserSettingsController do
plug :require_sudo_mode
plug :assign_email_and_password_changesets
plug :assign_home_qth_changeset
plug :assign_beacon_monitors
def edit(conn, _params) do
@ -40,6 +41,21 @@ defmodule MicrowavepropWeb.UserSettingsController do
end
end
def update(conn, %{"action" => "update_home_qth"} = params) do
%{"user" => user_params} = params
user = conn.assigns.current_scope.user
case Accounts.update_user_home_qth(user, user_params) do
{:ok, _user} ->
conn
|> put_flash(:info, "Home QTH updated.")
|> redirect(to: ~p"/users/settings")
{:error, changeset} ->
render(conn, :edit, home_qth_changeset: changeset)
end
end
def update(conn, %{"action" => "update_password"} = params) do
%{"user" => user_params} = params
user = conn.assigns.current_scope.user
@ -78,6 +94,11 @@ defmodule MicrowavepropWeb.UserSettingsController do
|> assign(:password_changeset, Accounts.change_user_password(user))
end
defp assign_home_qth_changeset(conn, _opts) do
user = conn.assigns.current_scope.user
assign(conn, :home_qth_changeset, Accounts.change_user_home_qth(user))
end
defp assign_beacon_monitors(conn, _opts) do
user = conn.assigns.current_scope.user

View file

@ -23,6 +23,35 @@
<div class="divider" />
<.form :let={f} for={@home_qth_changeset} action={~p"/users/settings"} id="update_home_qth">
<input type="hidden" name="action" value="update_home_qth" />
<div class="text-left mb-2">
<h3 class="font-semibold">Home QTH</h3>
<p class="text-xs opacity-70">
Used to anchor the rover map (drive radius, distance/bearing labels).
Enter a Maidenhead grid (e.g. <code>EM13qc</code>) or explicit lat/lon.
</p>
</div>
<.input
field={f[:home_grid]}
type="text"
label="Home grid"
placeholder="EM13qc"
autocomplete="off"
/>
<div class="grid grid-cols-2 gap-3">
<.input field={f[:home_lat]} type="number" step="any" label="Latitude" />
<.input field={f[:home_lon]} type="number" step="any" label="Longitude" />
</div>
<.button variant="primary" phx-disable-with="Saving...">Save Home QTH</.button>
</.form>
<div class="divider" />
<.form :let={f} for={@password_changeset} action={~p"/users/settings"} id="update_password">
<input type="hidden" name="action" value="update_password" />

View file

@ -70,6 +70,34 @@ defmodule MicrowavepropWeb.UserSettingsControllerTest do
end
end
describe "PUT /users/settings (home QTH form)" do
test "updates the user home QTH from a grid", %{conn: conn, user: user} do
conn =
put(conn, ~p"/users/settings", %{
"action" => "update_home_qth",
"user" => %{"home_grid" => "EM13qc"}
})
assert redirected_to(conn) == ~p"/users/settings"
reloaded = Microwaveprop.Repo.reload(user)
assert reloaded.home_grid == "EM13qc"
assert is_float(reloaded.home_lat)
assert is_float(reloaded.home_lon)
end
test "rejects an invalid grid", %{conn: conn} do
conn =
put(conn, ~p"/users/settings", %{
"action" => "update_home_qth",
"user" => %{"home_grid" => "ZZ99zz"}
})
response = html_response(conn, 200)
assert response =~ "Home QTH"
assert response =~ "must be a 4 or 6 character"
end
end
describe "PUT /users/settings (change email form)" do
@tag :capture_log
test "updates the user email", %{conn: conn, user: user} do