Rework member overview #553

Open
simon wants to merge 27 commits from issue/mitgliederverwaltung-547 into main
3 changed files with 14 additions and 12 deletions
Showing only changes of commit f2312c24a1 - Show all commits

View file

@ -1024,10 +1024,10 @@ defmodule MvWeb.CoreComponents do
doc: doc:
"when true, first header/body column gets sticky left positioning to keep selection controls visible" "when true, first header/body column gets sticky left positioning to keep selection controls visible"
attr :viewport_bottom, :any, attr :infinite_scroll, :boolean,
default: nil, default: false,
doc: doc:
"optional phx-viewport-bottom event (string) rendered on the streamed tbody so the built-in InfiniteScroll hook appends the next page without shifting the scroll position; nil omits the binding" "when true, renders the :footer slot as a full-width infinite-scroll sentinel row (typically only while more pages remain). The caller wires the actual load trigger via a hook in the slot (e.g. an IntersectionObserver sentinel). This component deliberately adds NO phx-viewport-bottom binding: LiveView's built-in InfiniteScroll scrolls the last child of that element into view after each load, which — on a sentinel/loading row — keeps it in view and cascades into loading every page. An IntersectionObserver sentinel has no such side effect."
slot :col, required: true do slot :col, required: true do
attr :label, :string attr :label, :string
@ -1265,13 +1265,15 @@ defmodule MvWeb.CoreComponents do
</tr> </tr>
</tbody> </tbody>
<%!-- After-rows footer in its own, non-streamed tbody so it stays put <%!-- After-rows footer in its own, non-streamed tbody so it stays put
outside the phx-update="stream" container. When viewport_bottom is set it outside the phx-update="stream" container. When infinite_scroll is set it
doubles as the infinite-scroll sentinel: rendered only while more pages holds the load sentinel (a hook lives in the :footer slot): rendered only
exist, so once the last page loads it disappears and stops firing. --%> while more pages remain, so once the last page loads it disappears and the
sentinel stops firing. No phx-viewport-bottom here on purpose LiveView's
built-in InfiniteScroll would scroll this row into view after each load and
cascade into loading everything. --%>
<tbody <tbody
:if={@footer != [] && @viewport_bottom} :if={@footer != [] && @infinite_scroll}
id={"#{@id}-footer"} id={"#{@id}-footer"}
phx-viewport-bottom={@viewport_bottom}
> >
<tr> <tr>
<td colspan={@col_count}> <td colspan={@col_count}>

View file

@ -125,7 +125,7 @@
wrapper_overflow_class="overflow-visible" wrapper_overflow_class="overflow-visible"
sticky_header={true} sticky_header={true}
sticky_first_col={true} sticky_first_col={true}
viewport_bottom={@more? && "load_more"} infinite_scroll={@more?}
row_click={ row_click={
fn {_dom_id, member} -> fn {_dom_id, member} ->
JS.push("select_row_and_navigate", value: %{id: member.id}) JS.push("select_row_and_navigate", value: %{id: member.id})

View file

@ -41,10 +41,10 @@ defmodule MvWeb.MemberLive.IndexPaginationTest do
assert row_count(html) == @page_limit assert row_count(html) == @page_limit
# More rows remain, so the infinite-scroll sentinel is armed. # More rows remain, so the infinite-scroll sentinel is armed.
assert html =~ ~s(phx-viewport-bottom="load_more") assert html =~ ~s(id="members-load-more-sentinel")
end end
test "viewport-bottom appends the next page and stops at the last page", %{conn: conn} do test "the sentinel appends the next page and stops at the last page", %{conn: conn} do
seed_members(@page_limit + 10) seed_members(@page_limit + 10)
conn = conn_with_oidc_user(conn) conn = conn_with_oidc_user(conn)
{:ok, view, html} = live(conn, ~p"/members") {:ok, view, html} = live(conn, ~p"/members")
@ -56,7 +56,7 @@ defmodule MvWeb.MemberLive.IndexPaginationTest do
assert row_count(html_after) == @page_limit + 10 assert row_count(html_after) == @page_limit + 10
# Last page reached: the sentinel is disarmed and a further fetch is a no-op. # Last page reached: the sentinel is disarmed and a further fetch is a no-op.
refute html_after =~ ~s(phx-viewport-bottom="load_more") refute html_after =~ ~s(id="members-load-more-sentinel")
html_again = render_hook(view, "load_more", %{}) html_again = render_hook(view, "load_more", %{})
assert row_count(html_again) == @page_limit + 10 assert row_count(html_again) == @page_limit + 10
end end