- Create MaidenheadChangesetHelpers: consolidate grid validation, callsign normalization, lat/lon validation, grid/latlon derivation across 6 schemas - Create ContextHelpers: shared fetch_owned with admin bypass, safe_enqueue for Oban workers, UUID casting to replace CastError rescues - Extend LiveHelpers: add current_user/1 (removes 7 duplicate definitions), subscribe/2 (replaces 13 inline PubSub sites), assign_url_params/2 - Extract Propagation.ScoreStore (528 lines): separate file I/O and cache management from scoring logic, 13 defdelegate passthroughs - Split SubmitLive (942->475 lines): extract CSV/ADIF upload rendering into 3 function component modules (csv_upload, adif_upload, preview) - Update 16 LiveViews to use shared helpers
83 lines
3 KiB
Elixir
83 lines
3 KiB
Elixir
defmodule MicrowavepropWeb.LiveHelpers do
|
|
@moduledoc """
|
|
Small helpers shared across LiveView modules. Use sparingly — most
|
|
view-specific logic belongs in its own LiveView.
|
|
"""
|
|
|
|
# ── Parse helpers ────────────────────────────────────────────────────
|
|
|
|
alias Phoenix.LiveView.Socket
|
|
|
|
@doc """
|
|
Parses a value into a float, returning `default` for nil, empty, or
|
|
unparseable input. Accepts strings, numbers, or any value with a
|
|
`String.Chars` impl.
|
|
"""
|
|
@spec parse_float(term(), float()) :: float()
|
|
def parse_float(nil, default), do: default
|
|
def parse_float("", default), do: default
|
|
|
|
def parse_float(value, default) do
|
|
case value |> to_string() |> Float.parse() do
|
|
{n, _} -> n
|
|
:error -> default
|
|
end
|
|
end
|
|
|
|
@doc """
|
|
Parses a value into an integer, returning `default` for nil, empty,
|
|
or unparseable input.
|
|
"""
|
|
@spec parse_int(term(), integer()) :: integer()
|
|
def parse_int(nil, default), do: default
|
|
def parse_int("", default), do: default
|
|
|
|
def parse_int(value, default) do
|
|
case value |> to_string() |> Integer.parse() do
|
|
{n, _} -> n
|
|
:error -> default
|
|
end
|
|
end
|
|
|
|
# ── User helpers ─────────────────────────────────────────────────────
|
|
|
|
@doc """
|
|
Extracts the current user from a LiveView socket or assigns map.
|
|
Returns the `%User{}` struct or `nil` if not authenticated.
|
|
"""
|
|
@spec current_user(Socket.t() | map()) :: Ecto.Schema.t() | nil
|
|
def current_user(%Socket{assigns: assigns}) do
|
|
current_user(assigns)
|
|
end
|
|
|
|
@spec current_user(map()) :: Ecto.Schema.t() | nil
|
|
def current_user(%{current_scope: %{user: %_{} = user}}), do: user
|
|
def current_user(%{user: %_{} = user}), do: user
|
|
def current_user(_), do: nil
|
|
|
|
# ── PubSub helpers ───────────────────────────────────────────────────
|
|
|
|
@doc """
|
|
Subscribes the socket to a Phoenix.PubSub topic, but only when the
|
|
socket is connected (WebSocket). Safe to call unconditionally in mount/3.
|
|
"""
|
|
@spec subscribe(Socket.t(), String.t()) :: :ok
|
|
def subscribe(%Socket{} = socket, topic) when is_binary(topic) do
|
|
if Phoenix.LiveView.connected?(socket) do
|
|
Phoenix.PubSub.subscribe(Microwaveprop.PubSub, topic)
|
|
end
|
|
|
|
:ok
|
|
end
|
|
|
|
# ── URL helpers ──────────────────────────────────────────────────────
|
|
|
|
@doc """
|
|
Merges URL params with defaults for handle_params/3. Returns a map of
|
|
merged values suitable for assigning to the socket.
|
|
"""
|
|
@spec assign_url_params(map(), map()) :: map()
|
|
def assign_url_params(params, defaults) when is_map(params) and is_map(defaults) do
|
|
Map.merge(defaults, Map.take(params, Map.keys(defaults)))
|
|
end
|
|
end
|