112 lines
3.6 KiB
Elixir
112 lines
3.6 KiB
Elixir
defmodule MicrowavepropWeb.QsoLive.Index do
|
|
@moduledoc false
|
|
use MicrowavepropWeb, :live_view
|
|
|
|
alias Microwaveprop.Radio
|
|
|
|
@sortable_fields ~w(station1 station2 band mode distance_km qso_timestamp)
|
|
@default_sort_by "qso_timestamp"
|
|
@default_sort_order "desc"
|
|
|
|
@impl true
|
|
def mount(_params, _session, socket) do
|
|
{:ok, socket}
|
|
end
|
|
|
|
@impl true
|
|
def handle_params(params, _uri, socket) do
|
|
page = params |> Map.get("page", "1") |> String.to_integer() |> max(1)
|
|
sort_by = validate_sort_field(Map.get(params, "sort_by", @default_sort_by))
|
|
sort_order = validate_sort_order(Map.get(params, "sort_order", @default_sort_order))
|
|
|
|
result =
|
|
Radio.list_qsos(
|
|
page: page,
|
|
sort_by: String.to_existing_atom(sort_by),
|
|
sort_order: String.to_existing_atom(sort_order)
|
|
)
|
|
|
|
{:noreply,
|
|
assign(socket,
|
|
page_title: "QSOs",
|
|
page: result.page,
|
|
total_pages: result.total_pages,
|
|
total_entries: result.total_entries,
|
|
qsos: result.entries,
|
|
sort_by: sort_by,
|
|
sort_order: sort_order
|
|
)}
|
|
end
|
|
|
|
@impl true
|
|
def handle_event("sort", %{"field" => field}, socket) do
|
|
field = validate_sort_field(field)
|
|
|
|
new_order =
|
|
if socket.assigns.sort_by == field && socket.assigns.sort_order == "asc",
|
|
do: "desc",
|
|
else: "asc"
|
|
|
|
{:noreply, push_patch(socket, to: ~p"/qsos?sort_by=#{field}&sort_order=#{new_order}")}
|
|
end
|
|
|
|
defp validate_sort_field(field) when field in @sortable_fields, do: field
|
|
defp validate_sort_field(_), do: @default_sort_by
|
|
|
|
defp validate_sort_order(order) when order in ~w(asc desc), do: order
|
|
defp validate_sort_order(_), do: @default_sort_order
|
|
|
|
@impl true
|
|
def render(assigns) do
|
|
~H"""
|
|
<Layouts.app flash={@flash}>
|
|
<.header>
|
|
QSOs
|
|
<:subtitle>{@total_entries} contacts</:subtitle>
|
|
</.header>
|
|
|
|
<.table
|
|
id="qsos"
|
|
rows={@qsos}
|
|
row_id={fn qso -> "qso-#{qso.id}" end}
|
|
row_click={fn qso -> JS.navigate(~p"/qsos/#{qso.id}") end}
|
|
sort_by={@sort_by}
|
|
sort_order={@sort_order}
|
|
>
|
|
<:col :let={qso} label="Station 1" sort_field="station1">{qso.station1}</:col>
|
|
<:col :let={qso} label="Grid 1">{qso.grid1 || "—"}</:col>
|
|
<:col :let={qso} label="Station 2" sort_field="station2">{qso.station2}</:col>
|
|
<:col :let={qso} label="Grid 2">{qso.grid2 || "—"}</:col>
|
|
<:col :let={qso} label="Band" sort_field="band">{qso.band}</:col>
|
|
<:col :let={qso} label="Mode" sort_field="mode">{qso.mode}</:col>
|
|
<:col :let={qso} label="Distance (km)" sort_field="distance_km">{qso.distance_km}</:col>
|
|
<:col :let={qso} label="Timestamp" sort_field="qso_timestamp">
|
|
{Calendar.strftime(qso.qso_timestamp, "%Y-%m-%d %H:%M")}
|
|
</:col>
|
|
</.table>
|
|
|
|
<div class="flex items-center justify-between pt-4">
|
|
<.link
|
|
:if={@page > 1}
|
|
patch={~p"/qsos?page=#{@page - 1}&sort_by=#{@sort_by}&sort_order=#{@sort_order}"}
|
|
class="btn btn-sm btn-outline"
|
|
>
|
|
<.icon name="hero-chevron-left" class="w-4 h-4" /> Previous
|
|
</.link>
|
|
<span :if={@page <= 1} />
|
|
|
|
<span class="text-sm text-base-content/70">Page {@page} of {@total_pages}</span>
|
|
|
|
<.link
|
|
:if={@page < @total_pages}
|
|
patch={~p"/qsos?page=#{@page + 1}&sort_by=#{@sort_by}&sort_order=#{@sort_order}"}
|
|
class="btn btn-sm btn-outline"
|
|
>
|
|
Next <.icon name="hero-chevron-right" class="w-4 h-4" />
|
|
</.link>
|
|
<span :if={@page >= @total_pages} />
|
|
</div>
|
|
</Layouts.app>
|
|
"""
|
|
end
|
|
end
|