diff --git a/lib/app/item.ex b/lib/app/item.ex index 2dbb245a..ab40827f 100644 --- a/lib/app/item.ex +++ b/lib/app/item.ex @@ -10,11 +10,11 @@ defmodule App.Item do @derive {Jason.Encoder, except: [:__meta__, :__struct__, :timer, :inserted_at, :updated_at]} schema "items" do - field :person_id, :integer - field :status, :integer - field :text, :string + field(:person_id, :integer) + field(:status, :integer) + field(:text, :string) - has_many :timer, Timer + has_many(:timer, Timer) many_to_many(:tags, Tag, join_through: ItemTag, on_replace: :delete) timestamps() @@ -236,12 +236,18 @@ defmodule App.Item do %{name: username, num_items: 1, num_timers: 3, person_id: 1} ] """ - def person_with_item_and_timer_count(sort_column \\ :person_id) do + def person_with_item_and_timer_count( + sort_column \\ :person_id, + sort_order \\ :asc + ) do sort_column = to_string(sort_column) + sort_order = to_string(sort_order) sort_column = if validate_sort_column(sort_column), do: sort_column, else: "person_id" + sort_order = if validate_order(sort_order), do: sort_order, else: "asc" + sql = """ SELECT i.person_id, COUNT(distinct i.id) AS "num_items", @@ -252,7 +258,7 @@ defmodule App.Item do FROM items i LEFT JOIN timers t ON t.item_id = i.id GROUP BY i.person_id - ORDER BY #{sort_column} ASC + ORDER BY #{sort_column} #{sort_order} """ Ecto.Adapters.SQL.query!(Repo, sql) @@ -389,4 +395,11 @@ defmodule App.Item do column ) end + + defp validate_order(order) do + Enum.member?( + ~w(asc desc), + order + ) + end end diff --git a/lib/app_web/live/stats_live.ex b/lib/app_web/live/stats_live.ex index b1c45684..c2b6f8d9 100644 --- a/lib/app_web/live/stats_live.ex +++ b/lib/app_web/live/stats_live.ex @@ -22,7 +22,9 @@ defmodule AppWeb.StatsLive do {:ok, assign(socket, person_id: person_id, - metrics: metrics + metrics: metrics, + sort_column: :person_id, + sort_order: :asc )} end @@ -66,14 +68,24 @@ defmodule AppWeb.StatsLive do @impl true def handle_event("sort", %{"key" => key}, socket) do - metrics = + sort_column = key |> String.to_atom() - |> Item.person_with_item_and_timer_count() + + sort_order = + if socket.assigns.sort_column == sort_column do + toggle_sort_order(socket.assigns.sort_order) + else + :asc + end + + metrics = Item.person_with_item_and_timer_count(sort_column, sort_order) {:noreply, assign(socket, - metrics: metrics + metrics: metrics, + sort_column: sort_column, + sort_order: sort_order )} end @@ -102,4 +114,7 @@ defmodule AppWeb.StatsLive do def is_highlighted_person?(metric, person_id), do: metric.person_id == person_id + + defp toggle_sort_order(:asc), do: :desc + defp toggle_sort_order(:desc), do: :asc end diff --git a/lib/app_web/live/stats_live.html.heex b/lib/app_web/live/stats_live.html.heex index ad46b7e6..49360636 100644 --- a/lib/app_web/live/stats_live.html.heex +++ b/lib/app_web/live/stats_live.html.heex @@ -8,6 +8,8 @@ module={AppWeb.TableComponent} id="table_component" rows={@metrics} + sort_column={@sort_column} + sort_order={@sort_order} highlight={&is_highlighted_person?(&1, @person_id)} > <:column :let={metric} label="Id" key="person_id"> diff --git a/lib/app_web/templates/table_component/arrow_down.html.heex b/lib/app_web/templates/table_component/arrow_down.html.heex new file mode 100644 index 00000000..2d4d4faa --- /dev/null +++ b/lib/app_web/templates/table_component/arrow_down.html.heex @@ -0,0 +1,14 @@ + + + diff --git a/lib/app_web/templates/table_component/arrow_up.html.heex b/lib/app_web/templates/table_component/arrow_up.html.heex new file mode 100644 index 00000000..9d500c75 --- /dev/null +++ b/lib/app_web/templates/table_component/arrow_up.html.heex @@ -0,0 +1,31 @@ +<%= if @invisible do %> + +<% else %> + + + +<% end %> diff --git a/lib/app_web/templates/table_component/table_component.html.heex b/lib/app_web/templates/table_component/table_component.html.heex index 9c6c265e..92c2a7b7 100644 --- a/lib/app_web/templates/table_component/table_component.html.heex +++ b/lib/app_web/templates/table_component/table_component.html.heex @@ -7,7 +7,19 @@ phx-click="sort" phx-value-key={column.key} > - <%= column.label %> + + <%= column.label %> + + <%= if @sort_column == String.to_atom(column.key) do %> + <%= if @sort_order == :asc do %> + <%= render_arrow_up() %> + <% else %> + <%= render_arrow_down() %> + <% end %> + <% else %> + <%= render_arrow_up(:invisible) %> + <% end %> + <% end %> diff --git a/lib/app_web/views/table_component_view.ex b/lib/app_web/views/table_component_view.ex index 60b10630..d8b3c67e 100644 --- a/lib/app_web/views/table_component_view.ex +++ b/lib/app_web/views/table_component_view.ex @@ -1,3 +1,19 @@ defmodule AppWeb.TableComponentView do use AppWeb, :view + + def render_arrow_down() do + Phoenix.View.render(AppWeb.TableComponentView, "arrow_down.html", %{}) + end + + def render_arrow_up() do + Phoenix.View.render(AppWeb.TableComponentView, "arrow_up.html", %{ + invisible: false + }) + end + + def render_arrow_up(:invisible) do + Phoenix.View.render(AppWeb.TableComponentView, "arrow_up.html", %{ + invisible: true + }) + end end