Skip to content

Commit

Permalink
feat: simple sorting on column headings for hills index
Browse files Browse the repository at this point in the history
.
  • Loading branch information
colindensem committed Jul 1, 2022
1 parent 4faa4f2 commit 4d74c25
Show file tree
Hide file tree
Showing 11 changed files with 154 additions and 67 deletions.
5 changes: 5 additions & 0 deletions lib/ascend/ecto_helper.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
defmodule Ascend.EctoHelper do
def enum(values) do
{:parameterized, Ecto.Enum, Ecto.Enum.init(values: values)}
end
end
16 changes: 14 additions & 2 deletions lib/ascend/hills.ex
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,20 @@ defmodule Ascend.Hills do
[%Hill{}, ...]
"""
def list_hills do
Repo.all(Hill)
def list_hills(opts) do
from(h in Hill)
|> sort(opts)
|> Repo.all()
end

defp sort(query, %{sort_by: sort_by, sort_dir: sort_dir})
when sort_by in [:dobih_id, :name, :metres, :feet] and
sort_dir in [:asc, :desc] do
order_by(query, {^sort_dir, ^sort_by})
end

defp sort(query, %{}) do
order_by(query, {:asc, :metres})
end

@doc """
Expand Down
24 changes: 24 additions & 0 deletions lib/ascend_web/forms/sorting_form.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
defmodule AscendWeb.Forms.SortingForm do
import Ecto.Changeset
alias Ascend.EctoHelper

@sortable_fields [:dobih_id, :name, :metres, :feet]

@fields %{
sort_by: EctoHelper.enum(@sortable_fields),
sort_dir: EctoHelper.enum([:asc, :desc])
}

@default_values %{
sort_by: :metres,
sort_dir: :desc
}

def parse(params) do
{@default_values, @fields}
|> cast(params, Map.keys(@fields))
|> apply_action(:insert)
end

def default_values(), do: @default_values
end
46 changes: 27 additions & 19 deletions lib/ascend_web/live/hill_live/index.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,37 +2,45 @@ defmodule AscendWeb.HillLive.Index do
use AscendWeb, :live_view

alias Ascend.Hills
alias Ascend.Hills.Hill
alias AscendWeb.Forms.SortingForm

@impl true
def mount(_params, _session, socket) do
{:ok, assign(socket, :hills, list_hills())}
end
def mount(_params, _session, socket), do: {:ok, socket}

@impl true
def handle_params(params, _url, socket) do
{:noreply, apply_action(socket, socket.assigns.live_action, params)}
socket =
socket
|> assign(:page_title, "Listing Hills")
|> parse_params(params)
|> assign_hills()

{:noreply, socket}
end

defp apply_action(socket, :edit, %{"id" => id}) do
socket
|> assign(:page_title, "Edit Hill")
|> assign(:hill, Hills.get_hill!(id))
@impl true
def handle_info({:update, opts}, socket) do
path = Routes.hill_index_path(socket, :index, opts)
{:noreply, push_patch(socket, to: path, replace: true)}
end

defp apply_action(socket, :new, _params) do
socket
|> assign(:page_title, "New Hill")
|> assign(:hill, %Hill{})
defp parse_params(socket, params) do
with {:ok, sorting_opts} <- SortingForm.parse(params) do
assign_sorting(socket, sorting_opts)
else
_error ->
assign_sorting(socket)
end
end

defp apply_action(socket, :index, _params) do
socket
|> assign(:page_title, "Listing Hills")
|> assign(:hill, nil)
defp assign_sorting(socket, overrides \\ %{}) do
opts = Map.merge(SortingForm.default_values(), overrides)
assign(socket, :sorting, opts)
end

defp list_hills do
Hills.list_hills()
defp assign_hills(socket) do
%{sorting: sorting} = socket.assigns

assign(socket, :hills, Hills.list_hills(sorting))
end
end
21 changes: 18 additions & 3 deletions lib/ascend_web/live/hill_live/index.html.heex
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,25 @@
<table>
<thead>
<tr>
<th>Name</th>
<th><.live_component
module={AscendWeb.Live.SortingComponent}
id={"sorting-name"}
key={:name}
sorting={@sorting} />
</th>
<th>Dobih</th>
<th>Metres</th>
<th>Feet</th>
<th><.live_component
module={AscendWeb.Live.SortingComponent}
id={"sorting-metres"}
key={:metres}
sorting={@sorting} />
</th>
<th><.live_component
module={AscendWeb.Live.SortingComponent}
id={"sorting-feet"}
key={:feet}
sorting={@sorting} />
</th>
<th>Grid ref</th>
<th>Classification</th>
<th>Region</th>
Expand Down
26 changes: 26 additions & 0 deletions lib/ascend_web/live/sorting_component.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
defmodule AscendWeb.Live.SortingComponent do
use AscendWeb, :live_component

def render(assigns) do
~H"""
<div phx-click="sort" phx-target={@myself}>
<%= @key %> <%= chevron(@sorting, @key) %>
</div>
"""
end

def handle_event("sort", _params, socket) do
%{sorting: %{sort_dir: sort_dir}, key: key} = socket.assigns
sort_dir = if sort_dir == :asc, do: :desc, else: :asc
opts = %{sort_by: key, sort_dir: sort_dir}

send(self(), {:update, opts})
{:noreply, assign(socket, :sorting, opts)}
end

def chevron(%{sort_by: sort_by, sort_dir: sort_dir}, key) when sort_by == key do
if sort_dir == :asc, do: "▼", else: "▲"
end

def chevron(_opts, _key), do: ""
end
2 changes: 0 additions & 2 deletions lib/ascend_web/router.ex
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,7 @@ defmodule AscendWeb.Router do
scope "/", AscendWeb do
pipe_through :browser

# get "/", PageController, :index
live "/", HillLive.Index, :index
live "/hills", HillLive.Index, :index

live "/hills/:id", HillLive.Show, :show
end
Expand Down
27 changes: 18 additions & 9 deletions test/ascend/hills_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ defmodule Ascend.HillsTest do
describe "hills" do
alias Ascend.Hills.Hill

import Ascend.HillsFixtures
import Ascend.Factory

@invalid_attrs %{
area: nil,
Expand All @@ -22,13 +22,22 @@ defmodule Ascend.HillsTest do
wainwright_outlying_fell: nil
}

test "list_hills/0 returns all hills" do
hill = hill_fixture()
assert Hills.list_hills() == [hill]
test "list_hills/1 returns all hills" do
hill1 = insert(:hill, metres: 1000, feet: 3280.84)
hill2 = insert(:hill, metres: 500, feet: 1640.42)
assert Hills.list_hills(%{}) == [hill2, hill1]
end

test "list hills/1 with name sort" do
hill1 = insert(:hill, name: "Z Hill")
hill2 = insert(:hill, name: "A Hill")

sort = %{sort_by: :name, sort_dir: :asc}
assert Hills.list_hills(sort) == [hill2, hill1]
end

test "get_hill!/1 returns the hill with given id" do
hill = hill_fixture()
hill = insert(:hill)
assert Hills.get_hill!(hill.id) == hill
end

Expand Down Expand Up @@ -66,7 +75,7 @@ defmodule Ascend.HillsTest do
end

test "update_hill/2 with valid data updates the hill" do
hill = hill_fixture()
hill = insert(:hill)

update_attrs = %{
area: "some updated area",
Expand Down Expand Up @@ -97,19 +106,19 @@ defmodule Ascend.HillsTest do
end

test "update_hill/2 with invalid data returns error changeset" do
hill = hill_fixture()
hill = insert(:hill)
assert {:error, %Ecto.Changeset{}} = Hills.update_hill(hill, @invalid_attrs)
assert hill == Hills.get_hill!(hill.id)
end

test "delete_hill/1 deletes the hill" do
hill = hill_fixture()
hill = insert(:hill)
assert {:ok, %Hill{}} = Hills.delete_hill(hill)
assert_raise Ecto.NoResultsError, fn -> Hills.get_hill!(hill.id) end
end

test "change_hill/1 returns a hill changeset" do
hill = hill_fixture()
hill = insert(:hill)
assert %Ecto.Changeset{} = Hills.change_hill(hill)
end
end
Expand Down
4 changes: 2 additions & 2 deletions test/ascend_web/live/hill_live_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ defmodule AscendWeb.HillLiveTest do
use AscendWeb.ConnCase

import Phoenix.LiveViewTest
import Ascend.HillsFixtures
import Ascend.Factory

defp create_hill(_) do
hill = hill_fixture()
hill = insert(:hill)
%{hill: hill}
end

Expand Down
20 changes: 20 additions & 0 deletions test/support/factory.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
defmodule Ascend.Factory do
use ExMachina.Ecto, repo: Ascend.Repo
alias Ascend.Hills.Hill

def hill_factory do
%Hill{
area: "some area",
classification: "some classification",
dobih_id: sequence(:dobih_id, & &1),
feet: 1640.42,
grid_ref: "GR 123 456",
metres: 500,
munro: true,
name: "some name",
region: "some region",
wainwright: false,
wainwright_outlying_fell: false
}
end
end
30 changes: 0 additions & 30 deletions test/support/fixtures/hills_fixtures.ex

This file was deleted.

0 comments on commit 4d74c25

Please sign in to comment.