add pagination across all admin and shop views
All checks were successful
deploy / deploy (push) Successful in 1m38s
All checks were successful
deploy / deploy (push) Successful in 1m38s
URL-based offset pagination with ?page=N for bookmarkable pages. Admin views use push_patch, shop collection uses navigate links. Responsive on mobile with horizontal-scroll tables and stacking pagination controls. Includes dev seed script for testing. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -6,8 +6,8 @@ defmodule BerrypodWeb.Admin.Newsletter do
|
||||
@impl true
|
||||
def mount(_params, _session, socket) do
|
||||
counts = Newsletter.count_subscribers_by_status()
|
||||
subscribers = Newsletter.list_subscribers()
|
||||
campaigns = Newsletter.list_campaigns()
|
||||
sub_page = Newsletter.list_subscribers_paginated(page: 1)
|
||||
camp_page = Newsletter.list_campaigns_paginated(page: 1)
|
||||
|
||||
{:ok,
|
||||
socket
|
||||
@@ -15,38 +15,47 @@ defmodule BerrypodWeb.Admin.Newsletter do
|
||||
|> assign(:tab, "overview")
|
||||
|> assign(:newsletter_enabled, Newsletter.newsletter_enabled?())
|
||||
|> assign(:status_counts, counts)
|
||||
|> assign(:subscriber_count, length(subscribers))
|
||||
|> assign(:campaign_count, length(campaigns))
|
||||
|> assign(:subscriber_pagination, sub_page)
|
||||
|> assign(:subscriber_count, sub_page.total_count)
|
||||
|> assign(:campaign_pagination, camp_page)
|
||||
|> assign(:campaign_count, camp_page.total_count)
|
||||
|> assign(:status_filter, "all")
|
||||
|> assign(:search, "")
|
||||
|> stream(:subscribers, subscribers)
|
||||
|> stream(:campaigns, campaigns)}
|
||||
|> stream(:subscribers, sub_page.items)
|
||||
|> stream(:campaigns, camp_page.items)}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_params(%{"tab" => tab}, _uri, socket)
|
||||
when tab in ~w(overview subscribers campaigns) do
|
||||
def handle_params(params, _uri, socket) do
|
||||
tab =
|
||||
if params["tab"] in ~w(overview subscribers campaigns), do: params["tab"], else: "overview"
|
||||
|
||||
page_num = Berrypod.Pagination.parse_page(params)
|
||||
|
||||
socket = assign(socket, :tab, tab)
|
||||
|
||||
socket =
|
||||
case tab do
|
||||
"subscribers" ->
|
||||
subscribers =
|
||||
Newsletter.list_subscribers(
|
||||
page =
|
||||
Newsletter.list_subscribers_paginated(
|
||||
status: socket.assigns.status_filter,
|
||||
search: socket.assigns.search
|
||||
search: socket.assigns.search,
|
||||
page: page_num
|
||||
)
|
||||
|
||||
socket
|
||||
|> assign(:subscriber_count, length(subscribers))
|
||||
|> stream(:subscribers, subscribers, reset: true)
|
||||
|> assign(:subscriber_pagination, page)
|
||||
|> assign(:subscriber_count, page.total_count)
|
||||
|> stream(:subscribers, page.items, reset: true)
|
||||
|
||||
"campaigns" ->
|
||||
campaigns = Newsletter.list_campaigns()
|
||||
page = Newsletter.list_campaigns_paginated(page: page_num)
|
||||
|
||||
socket
|
||||
|> assign(:campaign_count, length(campaigns))
|
||||
|> stream(:campaigns, campaigns, reset: true)
|
||||
|> assign(:campaign_pagination, page)
|
||||
|> assign(:campaign_count, page.total_count)
|
||||
|> stream(:campaigns, page.items, reset: true)
|
||||
|
||||
_ ->
|
||||
socket
|
||||
@@ -55,8 +64,6 @@ defmodule BerrypodWeb.Admin.Newsletter do
|
||||
{:noreply, socket}
|
||||
end
|
||||
|
||||
def handle_params(_params, _uri, socket), do: {:noreply, socket}
|
||||
|
||||
@impl true
|
||||
def handle_event("toggle_enabled", _params, socket) do
|
||||
new_value = !socket.assigns.newsletter_enabled
|
||||
@@ -71,23 +78,17 @@ defmodule BerrypodWeb.Admin.Newsletter do
|
||||
end
|
||||
|
||||
def handle_event("filter_subscribers", %{"status" => status}, socket) do
|
||||
subscribers = Newsletter.list_subscribers(status: status, search: socket.assigns.search)
|
||||
|
||||
{:noreply,
|
||||
socket
|
||||
|> assign(:status_filter, status)
|
||||
|> assign(:subscriber_count, length(subscribers))
|
||||
|> stream(:subscribers, subscribers, reset: true)}
|
||||
|> push_patch(to: ~p"/admin/newsletter?tab=subscribers")}
|
||||
end
|
||||
|
||||
def handle_event("search_subscribers", %{"search" => term}, socket) do
|
||||
subscribers = Newsletter.list_subscribers(status: socket.assigns.status_filter, search: term)
|
||||
|
||||
{:noreply,
|
||||
socket
|
||||
|> assign(:search, term)
|
||||
|> assign(:subscriber_count, length(subscribers))
|
||||
|> stream(:subscribers, subscribers, reset: true)}
|
||||
|> push_patch(to: ~p"/admin/newsletter?tab=subscribers")}
|
||||
end
|
||||
|
||||
def handle_event("delete_subscriber", %{"id" => id}, socket) do
|
||||
@@ -152,12 +153,17 @@ defmodule BerrypodWeb.Admin.Newsletter do
|
||||
status_filter={@status_filter}
|
||||
status_counts={@status_counts}
|
||||
subscriber_count={@subscriber_count}
|
||||
subscriber_pagination={@subscriber_pagination}
|
||||
search={@search}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div :if={@tab == "campaigns"}>
|
||||
<.campaigns_tab streams={@streams} campaign_count={@campaign_count} />
|
||||
<.campaigns_tab
|
||||
streams={@streams}
|
||||
campaign_count={@campaign_count}
|
||||
campaign_pagination={@campaign_pagination}
|
||||
/>
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
@@ -254,6 +260,7 @@ defmodule BerrypodWeb.Admin.Newsletter do
|
||||
attr :status_filter, :string, required: true
|
||||
attr :status_counts, :map, required: true
|
||||
attr :subscriber_count, :integer, required: true
|
||||
attr :subscriber_pagination, Berrypod.Pagination, required: true
|
||||
attr :search, :string, required: true
|
||||
|
||||
defp subscribers_tab(assigns) do
|
||||
@@ -323,6 +330,13 @@ defmodule BerrypodWeb.Admin.Newsletter do
|
||||
</:action>
|
||||
</.table>
|
||||
|
||||
<.admin_pagination
|
||||
:if={@subscriber_count > 0}
|
||||
page={@subscriber_pagination}
|
||||
patch={~p"/admin/newsletter"}
|
||||
params={%{"tab" => "subscribers"}}
|
||||
/>
|
||||
|
||||
<div :if={@subscriber_count == 0} class="text-center py-12 text-base-content/60">
|
||||
<.icon name="hero-envelope" class="size-12 mx-auto mb-4" />
|
||||
<p class="text-lg font-medium">No subscribers yet</p>
|
||||
@@ -336,6 +350,7 @@ defmodule BerrypodWeb.Admin.Newsletter do
|
||||
|
||||
attr :streams, :any, required: true
|
||||
attr :campaign_count, :integer, required: true
|
||||
attr :campaign_pagination, Berrypod.Pagination, required: true
|
||||
|
||||
defp campaigns_tab(assigns) do
|
||||
~H"""
|
||||
@@ -370,6 +385,13 @@ defmodule BerrypodWeb.Admin.Newsletter do
|
||||
</:action>
|
||||
</.table>
|
||||
|
||||
<.admin_pagination
|
||||
:if={@campaign_count > 0}
|
||||
page={@campaign_pagination}
|
||||
patch={~p"/admin/newsletter"}
|
||||
params={%{"tab" => "campaigns"}}
|
||||
/>
|
||||
|
||||
<div :if={@campaign_count == 0} class="text-center py-12 text-base-content/60">
|
||||
<.icon name="hero-megaphone" class="size-12 mx-auto mb-4" />
|
||||
<p class="text-lg font-medium">No campaigns yet</p>
|
||||
|
||||
Reference in New Issue
Block a user