Skip to content

Commit

Permalink
🏹 Implement sort functionality within "View Shuttle Stops" page (#997)
Browse files Browse the repository at this point in the history
* add sorting functionality to stops page table

* format and add sort test

* adjust icon size

* credo
  • Loading branch information
bfauble authored Aug 8, 2024
1 parent e6eb53c commit 0ebc068
Show file tree
Hide file tree
Showing 6 changed files with 88 additions and 21 deletions.
40 changes: 38 additions & 2 deletions lib/arrow/stops.ex
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,12 @@ defmodule Arrow.Stops do
[%Stop{}, ...]
"""
def list_stops do
Repo.all(Stop)
def list_stops(params \\ %{}) do
from(
s in Stop,
order_by: ^order_by(params["order_by"])
)
|> Repo.all()
end

@doc """
Expand Down Expand Up @@ -101,4 +105,36 @@ defmodule Arrow.Stops do
def change_stop(%Stop{} = stop, attrs \\ %{}) do
Stop.changeset(stop, attrs)
end

defp order_by("stop_id_desc"), do: [desc: :stop_id]
defp order_by("stop_id_asc"), do: [asc: :stop_id]
defp order_by("stop_name_desc"), do: [desc: :stop_name]
defp order_by("stop_name_asc"), do: [asc: :stop_name]
defp order_by("stop_desc_desc"), do: [desc: :stop_desc]
defp order_by("stop_desc_asc"), do: [asc: :stop_desc]
defp order_by("platform_code_desc"), do: [desc: :platform_code]
defp order_by("platform_code_asc"), do: [asc: :platform_code]
defp order_by("platform_name_desc"), do: [desc: :platform_name]
defp order_by("platform_name_asc"), do: [asc: :platform_name]
defp order_by("stop_lat_desc"), do: [desc: :stop_lat]
defp order_by("stop_lat_asc"), do: [asc: :stop_lat]
defp order_by("stop_lon_desc"), do: [desc: :stop_lon]
defp order_by("stop_lon_asc"), do: [asc: :stop_lon]
defp order_by("stop_address_desc"), do: [desc: :stop_address]
defp order_by("stop_address_asc"), do: [asc: :stop_address]
defp order_by("zone_id_desc"), do: [desc: :zone_id]
defp order_by("zone_id_asc"), do: [asc: :zone_id]
defp order_by("level_id_desc"), do: [desc: :level_id]
defp order_by("level_id_asc"), do: [asc: :level_id]
defp order_by("parent_station_desc"), do: [desc: :parent_station]
defp order_by("parent_station_asc"), do: [asc: :parent_station]
defp order_by("municipality_desc"), do: [desc: :municipality]
defp order_by("municipality_asc"), do: [asc: :municipality]
defp order_by("on_street_desc"), do: [desc: :on_street]
defp order_by("on_street_asc"), do: [asc: :on_street]
defp order_by("at_street_desc"), do: [desc: :at_street]
defp order_by("at_street_asc"), do: [asc: :at_street]
defp order_by("updated_at_desc"), do: [desc: :updated_at]
defp order_by("updated_at_asc"), do: [asc: :updated_at]
defp order_by(_), do: []
end
16 changes: 15 additions & 1 deletion lib/arrow_web/components/core_components.ex
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,7 @@ defmodule ArrowWeb.CoreComponents do

slot :col, required: true do
attr :label, :string
attr :link, :string
end

slot :action, doc: "the slot for showing user actions in the last table column"
Expand All @@ -488,7 +489,20 @@ defmodule ArrowWeb.CoreComponents do
<table class="w-[40rem] mt-11 sm:w-full">
<thead class="text-sm text-left leading-6 text-zinc-500">
<tr>
<th :for={col <- @col} class="p-0 pb-4 pr-6 font-normal"><%= col[:label] %></th>
<th :for={col <- @col} class="p-0 pb-4 pr-6 font-normal">
<%= if col[:link] do %>
<.link href={col[:link]}>
<%= if String.ends_with?(col[:link], "desc") do %>
<.icon name="hero-bars-arrow-down" class="h-4 w-4" />
<% else %>
<.icon name="hero-bars-arrow-up" class="h-4 w-4" />
<% end %>
<%= col[:label] %>
</.link>
<% else %>
<%= col[:label] %>
<% end %>
</th>
<th :if={@action != []} class="relative p-0 pb-4">
<span class="sr-only"><%= gettext("Actions") %></span>
</th>
Expand Down
6 changes: 3 additions & 3 deletions lib/arrow_web/controllers/stop_controller.ex
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ defmodule ArrowWeb.StopController do
alias Plug.Conn

@spec index(Conn.t(), Conn.params()) :: Conn.t()
def index(conn, _params) do
stops = Stops.list_stops()
render(conn, :index, stops: stops)
def index(conn, params) do
stops = Stops.list_stops(params)
render(conn, :index, stops: stops, order_by: Map.get(params, "order_by"))
end

@spec new(Conn.t(), Conn.params()) :: Conn.t()
Expand Down
10 changes: 10 additions & 0 deletions lib/arrow_web/controllers/stop_html.ex
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,14 @@ defmodule ArrowWeb.StopView do
|> DateTime.shift_zone!("America/New_York")
|> Calendar.strftime("%Y-%m-%d %I:%M %p")
end

def sort_link(nil, field), do: ~p"/stops?#{%{order_by: "#{field}_desc"}}"

def sort_link(sort_by, field) do
if sort_by == "#{field}_desc" do
~p"/stops?#{%{order_by: "#{field}_asc"}}"
else
~p"/stops?#{%{order_by: "#{field}_desc"}}"
end
end
end
30 changes: 15 additions & 15 deletions lib/arrow_web/controllers/stop_html/index.html.heex
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,21 @@
</.header>

<.table id="stops" rows={@stops} row_click={&JS.navigate(~p"/stops/#{&1}")}>
<:col :let={stop} label="Stop"><%= stop.stop_id %></:col>
<:col :let={stop} label="Stop name"><%= stop.stop_name %></:col>
<:col :let={stop} label="Stop desc"><%= stop.stop_desc %></:col>
<:col :let={stop} label="Platform code"><%= stop.platform_code %></:col>
<:col :let={stop} label="Platform name"><%= stop.platform_name %></:col>
<:col :let={stop} label="Stop lat"><%= stop.stop_lat %></:col>
<:col :let={stop} label="Stop long"><%= stop.stop_lon %></:col>
<:col :let={stop} label="Stop address"><%= stop.stop_address %></:col>
<:col :let={stop} label="Zone"><%= stop.zone_id %></:col>
<:col :let={stop} label="Level"><%= stop.level_id %></:col>
<:col :let={stop} label="Parent station"><%= stop.parent_station %></:col>
<:col :let={stop} label="Municipality"><%= stop.municipality %></:col>
<:col :let={stop} label="On street"><%= stop.on_street %></:col>
<:col :let={stop} label="At street"><%= stop.at_street %></:col>
<:col :let={stop} label="Last updated"><%= format_timestamp(stop.updated_at) %></:col>
<:col :let={stop} label="Stop" link={sort_link(@order_by, "stop_id")}><%= stop.stop_id %></:col>
<:col :let={stop} label="Stop name" link={sort_link(@order_by, "stop_name")}><%= stop.stop_name %></:col>
<:col :let={stop} label="Stop desc" link={sort_link(@order_by, "stop_desc")}><%= stop.stop_desc %></:col>
<:col :let={stop} label="Platform code" link={sort_link(@order_by, "platform_code")}><%= stop.platform_code %></:col>
<:col :let={stop} label="Platform name" link={sort_link(@order_by, "platform_name")}><%= stop.platform_name %></:col>
<:col :let={stop} label="Stop lat" link={sort_link(@order_by, "stop_lat")}><%= stop.stop_lat %></:col>
<:col :let={stop} label="Stop long" link={sort_link(@order_by, "stop_lon")}><%= stop.stop_lon %></:col>
<:col :let={stop} label="Stop address" link={sort_link(@order_by, "stop_address")}><%= stop.stop_address %></:col>
<:col :let={stop} label="Zone" link={sort_link(@order_by, "zone_id")}><%= stop.zone_id %></:col>
<:col :let={stop} label="Level" link={sort_link(@order_by, "level_id")}><%= stop.level_id %></:col>
<:col :let={stop} label="Parent station" link={sort_link(@order_by, "parent_station")}><%= stop.parent_station %></:col>
<:col :let={stop} label="Municipality" link={sort_link(@order_by, "municipality")}><%= stop.municipality %></:col>
<:col :let={stop} label="On street" link={sort_link(@order_by, "on_street")}><%= stop.on_street %></:col>
<:col :let={stop} label="At street" link={sort_link(@order_by, "at_street")}><%= stop.at_street %></:col>
<:col :let={stop} label="Last updated" link={sort_link(@order_by, "updated_at")}><%= format_timestamp(stop.updated_at) %></:col>
<:action :let={stop}>
<div class="sr-only">
<.link navigate={~p"/stops/#{stop}"}>Show</.link>
Expand Down
7 changes: 7 additions & 0 deletions test/arrow/stops_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,13 @@ defmodule Arrow.StopsTest do
assert Stops.list_stops() == [stop]
end

test "list_stops/1 returns all stops sorted by order_by param" do
stop_a = stop_fixture(%{stop_name: "Stop A"})
stop_z = stop_fixture(%{stop_name: "Stop Z"})
assert Stops.list_stops(%{"order_by" => "stop_name_desc"}) == [stop_z, stop_a]
assert Stops.list_stops(%{"order_by" => "stop_name_asc"}) == [stop_a, stop_z]
end

test "get_stop!/1 returns the stop with given id" do
stop = stop_fixture()
assert Stops.get_stop!(stop.id) == stop
Expand Down

0 comments on commit 0ebc068

Please sign in to comment.