[WIP] added first attempt at pagination component

This commit is contained in:
Kieran Eglin 2024-04-17 09:31:17 -07:00
parent a4d5f45edc
commit 9f491d4774
No known key found for this signature in database
GPG key ID: 193984967FCF432D
4 changed files with 139 additions and 20 deletions

View file

@ -0,0 +1,12 @@
defmodule Pinchflat.Utils.NumberUtils do
@moduledoc """
Utility methods for working with numbers
"""
# TODO: test
def clamp(num, minimum, maximum) do
num
|> max(minimum)
|> min(maximum)
end
end

View file

@ -2,6 +2,8 @@ defmodule PinchflatWeb.CustomComponents.TableComponents do
@moduledoc false @moduledoc false
use Phoenix.Component use Phoenix.Component
alias PinchflatWeb.CoreComponents
@doc """ @doc """
Renders a table component with the given rows and columns. Renders a table component with the given rows and columns.
@ -50,4 +52,45 @@ defmodule PinchflatWeb.CustomComponents.TableComponents do
</table> </table>
""" """
end end
attr :page_number, :integer, default: 1
attr :total_pages, :integer, default: 1
def pagination_controls(assigns) do
~H"""
<nav>
<ul class="flex flex-wrap items-center">
<li>
<span
class={[
"flex h-8 w-8 items-center justify-center rounded",
@page_number != 1 && "cursor-pointer hover:bg-primary hover:text-white",
@page_number == 1 && "cursor-not-allowed"
]}
phx-click={@page_number != 1 && "page_change"}
phx-value-direction="dec"
>
<CoreComponents.icon name="hero-chevron-left" />
</span>
</li>
<li>
<span class="mx-2">Page <%= @page_number %> of <%= @total_pages %></span>
</li>
<li>
<span
class={[
"flex h-8 w-8 items-center justify-center rounded",
@page_number != @total_pages && "cursor-pointer hover:bg-primary hover:text-white",
@page_number == @total_pages && "cursor-not-allowed"
]}
phx-click={@page_number != @total_pages && "page_change"}
phx-value-direction="inc"
>
<CoreComponents.icon name="hero-chevron-right" />
</span>
</li>
</ul>
</nav>
"""
end
end end

View file

@ -0,0 +1,83 @@
defmodule Pinchflat.PendingTableLive do
use PinchflatWeb, :live_view
import Ecto.Query, warn: false
alias Pinchflat.Repo
alias Pinchflat.Sources
alias Pinchflat.Media.MediaQuery
alias Pinchflat.Utils.NumberUtils
@limit 10
def render(%{records: []} = assigns) do
~H"""
<p class="text-black dark:text-white">Nothing Here!</p>
"""
end
def render(assigns) do
~H"""
<div>
<span class="mb-4 inline-block">
Showing <%= length(@records) %> of <%= @total_record_count %>
</span>
<.table rows={@records} table_class="text-black dark:text-white">
<:col :let={media_item} label="Title">
<.subtle_link href={~p"/sources/#{@source.id}/media/#{media_item.id}"}>
<%= StringUtils.truncate(media_item.title, 50) %>
</.subtle_link>
</:col>
<:col :let={media_item} label="" class="flex place-content-evenly">
<.icon_link href={~p"/sources/#{@source.id}/media/#{media_item.id}"} icon="hero-eye" class="mx-1" />
<.icon_link href={~p"/sources/#{@source.id}/media/#{media_item.id}/edit"} icon="hero-pencil-square" class="mx-1" />
</:col>
</.table>
<section class="flex justify-center mt-5">
<.pagination_controls page_number={@page} total_pages={@total_pages} />
</section>
</div>
"""
end
def mount(_params, session, socket) do
page = 1
source = Sources.get_source!(session["source_id"])
base_query = generate_base_query(source)
pagination_attrs = fetch_pagination_attributes(base_query, page)
{:ok, assign(socket, Map.merge(pagination_attrs, %{base_query: base_query, source: source}))}
end
def handle_event("page_change", %{"direction" => direction}, %{assigns: assigns} = socket) do
direction = if direction == "inc", do: 1, else: -1
new_page = assigns.page + direction
new_assigns = fetch_pagination_attributes(assigns.base_query, new_page)
{:noreply, assign(socket, new_assigns)}
end
defp fetch_pagination_attributes(base_query, page) do
total_record_count = Repo.aggregate(base_query, :count, :id)
total_pages = ceil(total_record_count / @limit)
page = NumberUtils.clamp(page, 1, total_pages)
records = fetch_records(base_query, page)
%{page: page, total_pages: total_pages, records: records, total_record_count: total_record_count}
end
defp generate_base_query(source) do
MediaQuery.new()
|> MediaQuery.for_source(source)
|> MediaQuery.where_pending_download()
|> order_by(desc: :id)
end
defp fetch_records(base_query, page) do
offset = (page - 1) * @limit
base_query
|> limit(^@limit)
|> offset(^offset)
|> Repo.all()
end
end

View file

@ -37,26 +37,7 @@
</div> </div>
</:tab> </:tab>
<:tab title="Pending Media"> <:tab title="Pending Media">
<%= if match?([_|_], @pending_media) do %> <%= live_render(@conn, Pinchflat.PendingTableLive, session: %{"source_id" => @source.id}) %>
<h4 class="text-white text-lg mb-6">Shows a maximum of 100 media items</h4>
<.table rows={@pending_media} table_class="text-black dark:text-white">
<:col :let={media_item} label="Title">
<.subtle_link href={~p"/sources/#{@source.id}/media/#{media_item.id}"}>
<%= StringUtils.truncate(media_item.title, 50) %>
</.subtle_link>
</:col>
<:col :let={media_item} label="" class="flex place-content-evenly">
<.icon_link href={~p"/sources/#{@source.id}/media/#{media_item.id}"} icon="hero-eye" class="mx-1" />
<.icon_link
href={~p"/sources/#{@source.id}/media/#{media_item.id}/edit"}
icon="hero-pencil-square"
class="mx-1"
/>
</:col>
</.table>
<% else %>
<p class="text-black dark:text-white">Nothing Here!</p>
<% end %>
</:tab> </:tab>
<:tab title="Downloaded Media"> <:tab title="Downloaded Media">
<%= if match?([_|_], @downloaded_media) do %> <%= if match?([_|_], @downloaded_media) do %>