mirror of
https://github.com/ClaperCo/Claper.git
synced 2026-08-29 01:58:48 +02:00
Adjust interaction list paging on resize
This commit is contained in:
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
- Fix datetime being reset at every changes
|
- Fix datetime being reset at every changes
|
||||||
- Fix account creation with a soft-deleted email
|
- Fix account creation with a soft-deleted email
|
||||||
|
- Fix interaction list paging on resize
|
||||||
|
|
||||||
## v.3.0.0
|
## v.3.0.0
|
||||||
|
|
||||||
|
|||||||
@@ -515,6 +515,18 @@ Hooks.SlideSortable = {
|
|||||||
};
|
};
|
||||||
Hooks.InteractionDrag = {
|
Hooks.InteractionDrag = {
|
||||||
mounted() {
|
mounted() {
|
||||||
|
this.lastInteractionListHeight = null;
|
||||||
|
this.interactionListResizeObserver = new ResizeObserver(([entry]) => {
|
||||||
|
const height = window.matchMedia("(min-width: 1024px)").matches
|
||||||
|
? Math.round(entry.contentRect.height)
|
||||||
|
: 0;
|
||||||
|
|
||||||
|
if (height === this.lastInteractionListHeight) return;
|
||||||
|
this.lastInteractionListHeight = height;
|
||||||
|
this.pushEventTo(this.el, "interaction-list-resized", { height });
|
||||||
|
});
|
||||||
|
this.interactionListResizeObserver.observe(this.el);
|
||||||
|
|
||||||
this.el.addEventListener("dragstart", (e) => {
|
this.el.addEventListener("dragstart", (e) => {
|
||||||
const item = e.target.closest("[data-interaction-id]");
|
const item = e.target.closest("[data-interaction-id]");
|
||||||
if (!item) return;
|
if (!item) return;
|
||||||
@@ -546,6 +558,9 @@ Hooks.InteractionDrag = {
|
|||||||
.forEach((n) => n.classList.remove("opacity-40"));
|
.forEach((n) => n.classList.remove("opacity-40"));
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
destroyed() {
|
||||||
|
this.interactionListResizeObserver.disconnect();
|
||||||
|
},
|
||||||
};
|
};
|
||||||
Hooks.OpenPresenter = {
|
Hooks.OpenPresenter = {
|
||||||
open(e) {
|
open(e) {
|
||||||
|
|||||||
@@ -540,7 +540,10 @@
|
|||||||
<!-- Bottom Section - Interactions & Options -->
|
<!-- Bottom Section - Interactions & Options -->
|
||||||
<div class="flex-1 flex flex-col lg:flex-row overflow-y-auto lg:overflow-hidden">
|
<div class="flex-1 flex flex-col lg:flex-row overflow-y-auto lg:overflow-hidden">
|
||||||
<!-- Interactions Panel -->
|
<!-- Interactions Panel -->
|
||||||
<div class="lg:w-1/3 flex-shrink-0 p-4">
|
<div
|
||||||
|
id="interactions-pane"
|
||||||
|
class="lg:w-1/3 flex-shrink-0 p-4 lg:min-h-0 lg:flex lg:flex-col lg:overflow-hidden"
|
||||||
|
>
|
||||||
<.live_component
|
<.live_component
|
||||||
id="interaction-list"
|
id="interaction-list"
|
||||||
module={ClaperWeb.EventLive.ManageInteractionListComponent}
|
module={ClaperWeb.EventLive.ManageInteractionListComponent}
|
||||||
|
|||||||
@@ -2,17 +2,21 @@ defmodule ClaperWeb.EventLive.ManageInteractionListComponent do
|
|||||||
use ClaperWeb, :live_component
|
use ClaperWeb, :live_component
|
||||||
|
|
||||||
@per_page 6
|
@per_page 6
|
||||||
|
@max_per_page 20
|
||||||
|
@fixed_content_height 200
|
||||||
|
@interaction_row_height 64
|
||||||
|
|
||||||
def update(assigns, socket) do
|
def update(assigns, socket) do
|
||||||
page = Map.get(socket.assigns, :page, 0)
|
page = Map.get(socket.assigns, :page, 0)
|
||||||
|
per_page = Map.get(socket.assigns, :per_page, @per_page)
|
||||||
total = length(assigns.interactions)
|
total = length(assigns.interactions)
|
||||||
max_page = max(0, ceil(total / @per_page) - 1)
|
max_page = max_page(total, per_page)
|
||||||
page = min(page, max_page)
|
page = min(page, max_page)
|
||||||
|
|
||||||
{:ok,
|
{:ok,
|
||||||
socket
|
socket
|
||||||
|> assign(assigns)
|
|> assign(assigns)
|
||||||
|> assign(page: page, per_page: @per_page)}
|
|> assign(page: page, per_page: per_page)}
|
||||||
end
|
end
|
||||||
|
|
||||||
def handle_event("prev-page", _, socket) do
|
def handle_event("prev-page", _, socket) do
|
||||||
@@ -20,16 +24,38 @@ defmodule ClaperWeb.EventLive.ManageInteractionListComponent do
|
|||||||
end
|
end
|
||||||
|
|
||||||
def handle_event("next-page", _, socket) do
|
def handle_event("next-page", _, socket) do
|
||||||
max_page = max(0, ceil(length(socket.assigns.interactions) / @per_page) - 1)
|
max_page = max_page(length(socket.assigns.interactions), socket.assigns.per_page)
|
||||||
{:noreply, assign(socket, page: min(max_page, socket.assigns.page + 1))}
|
{:noreply, assign(socket, page: min(max_page, socket.assigns.page + 1))}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def handle_event("interaction-list-resized", %{"height" => height}, socket)
|
||||||
|
when is_integer(height) do
|
||||||
|
per_page =
|
||||||
|
height
|
||||||
|
|> Kernel.-(@fixed_content_height)
|
||||||
|
|> div(@interaction_row_height)
|
||||||
|
|> max(@per_page)
|
||||||
|
|> min(@max_per_page)
|
||||||
|
|
||||||
|
first_interaction = socket.assigns.page * socket.assigns.per_page
|
||||||
|
|
||||||
|
page =
|
||||||
|
min(
|
||||||
|
div(first_interaction, per_page),
|
||||||
|
max_page(length(socket.assigns.interactions), per_page)
|
||||||
|
)
|
||||||
|
|
||||||
|
{:noreply, assign(socket, page: page, per_page: per_page)}
|
||||||
|
end
|
||||||
|
|
||||||
defp paginated_interactions(interactions, page, per_page) do
|
defp paginated_interactions(interactions, page, per_page) do
|
||||||
interactions
|
interactions
|
||||||
|> Enum.drop(page * per_page)
|
|> Enum.drop(page * per_page)
|
||||||
|> Enum.take(per_page)
|
|> Enum.take(per_page)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp max_page(total, per_page), do: max(0, ceil(total / per_page) - 1)
|
||||||
|
|
||||||
def render(assigns) do
|
def render(assigns) do
|
||||||
assigns =
|
assigns =
|
||||||
assign(assigns,
|
assign(assigns,
|
||||||
@@ -41,7 +67,8 @@ defmodule ClaperWeb.EventLive.ManageInteractionListComponent do
|
|||||||
<div
|
<div
|
||||||
id="interaction-drag-list"
|
id="interaction-drag-list"
|
||||||
phx-hook="InteractionDrag"
|
phx-hook="InteractionDrag"
|
||||||
class="relative flex flex-col gap-2 border border-gray-200 rounded-2xl p-2"
|
phx-target={@myself}
|
||||||
|
class="relative flex flex-col gap-2 border border-gray-200 rounded-2xl p-2 lg:flex-1 lg:min-h-0 lg:overflow-y-auto"
|
||||||
>
|
>
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
<svg
|
<svg
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ defmodule ClaperWeb.EventLiveTest do
|
|||||||
use ClaperWeb.ConnCase
|
use ClaperWeb.ConnCase
|
||||||
|
|
||||||
import Phoenix.LiveViewTest
|
import Phoenix.LiveViewTest
|
||||||
import Claper.{FormsFixtures, PresentationsFixtures}
|
import Claper.{FormsFixtures, PollsFixtures, PresentationsFixtures}
|
||||||
|
|
||||||
@update_attrs %{name: "some updated name"}
|
@update_attrs %{name: "some updated name"}
|
||||||
|
|
||||||
@@ -194,6 +194,79 @@ defmodule ClaperWeb.EventLiveTest do
|
|||||||
describe "Manage" do
|
describe "Manage" do
|
||||||
setup [:register_and_log_in_user, :create_event]
|
setup [:register_and_log_in_user, :create_event]
|
||||||
|
|
||||||
|
test "keeps interaction pagination reachable on short screens", %{
|
||||||
|
conn: conn,
|
||||||
|
presentation_file: presentation_file
|
||||||
|
} do
|
||||||
|
for index <- 1..7 do
|
||||||
|
poll_fixture(%{
|
||||||
|
presentation_file_id: presentation_file.id,
|
||||||
|
title: "Poll #{index}"
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
{:ok, manage_live, html} = live(conn, ~p"/e/#{presentation_file.event.code}/manage")
|
||||||
|
document = Floki.parse_document!(html)
|
||||||
|
|
||||||
|
interaction_pane_classes =
|
||||||
|
document
|
||||||
|
|> Floki.attribute("#interactions-pane", "class")
|
||||||
|
|> List.first()
|
||||||
|
|> String.split()
|
||||||
|
|
||||||
|
interaction_list_classes =
|
||||||
|
document
|
||||||
|
|> Floki.attribute("#interaction-drag-list", "class")
|
||||||
|
|> List.first()
|
||||||
|
|> String.split()
|
||||||
|
|
||||||
|
assert "lg:flex" in interaction_pane_classes
|
||||||
|
assert "lg:min-h-0" in interaction_pane_classes
|
||||||
|
assert "lg:overflow-hidden" in interaction_pane_classes
|
||||||
|
assert "lg:flex-1" in interaction_list_classes
|
||||||
|
assert "lg:overflow-y-auto" in interaction_list_classes
|
||||||
|
assert has_element?(manage_live, ~s(#interaction-drag-list button[phx-click="next-page"]))
|
||||||
|
|
||||||
|
manage_live
|
||||||
|
|> element(~s(#interaction-drag-list button[phx-click="next-page"]))
|
||||||
|
|> render_click()
|
||||||
|
|
||||||
|
assert render(manage_live) =~ "2 / 2"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "shows more interactions when the panel is taller", %{
|
||||||
|
conn: conn,
|
||||||
|
presentation_file: presentation_file
|
||||||
|
} do
|
||||||
|
for index <- 1..13 do
|
||||||
|
poll_fixture(%{
|
||||||
|
presentation_file_id: presentation_file.id,
|
||||||
|
title: "Poll #{index}"
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
{:ok, manage_live, _html} = live(conn, ~p"/e/#{presentation_file.event.code}/manage")
|
||||||
|
|
||||||
|
assert manage_live
|
||||||
|
|> render()
|
||||||
|
|> Floki.parse_document!()
|
||||||
|
|> Floki.find("[data-interaction-id]")
|
||||||
|
|> length() == 6
|
||||||
|
|
||||||
|
manage_live
|
||||||
|
|> element("#interaction-drag-list")
|
||||||
|
|> render_hook("interaction-list-resized", %{"height" => 900})
|
||||||
|
|
||||||
|
html = render(manage_live)
|
||||||
|
|
||||||
|
assert html
|
||||||
|
|> Floki.parse_document!()
|
||||||
|
|> Floki.find("[data-interaction-id]")
|
||||||
|
|> length() == 10
|
||||||
|
|
||||||
|
assert html =~ "1 / 2"
|
||||||
|
end
|
||||||
|
|
||||||
test "prompts to regenerate missing thumbnails and starts regeneration", %{
|
test "prompts to regenerate missing thumbnails and starts regeneration", %{
|
||||||
conn: conn,
|
conn: conn,
|
||||||
presentation_file: presentation_file
|
presentation_file: presentation_file
|
||||||
|
|||||||
Reference in New Issue
Block a user