Skip to content

Commit

Permalink
Merge branch 'lebihae/fix-infinitescroll-bookings' into 'main'
Browse files Browse the repository at this point in the history
fix(ticketing): fix borked infinite scroll on event bookings management page

See merge request churros/churros!296
  • Loading branch information
LeGmask committed Nov 19, 2024
2 parents a4f312b + b616da1 commit 13f22da
Show file tree
Hide file tree
Showing 6 changed files with 121 additions and 80 deletions.
5 changes: 5 additions & 0 deletions .changeset/chilled-spoons-guess.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@churros/app': patch
---

fix borked infinite scroll on /events/:id/bookings
47 changes: 47 additions & 0 deletions packages/app/src/lib/components/LoadingScreen.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<script lang="ts">
import { LoadingChurros } from '$lib/loading';
export let title = 'Chargement…';
</script>

<div class="loading">
<LoadingChurros />
<p class="gradiented">{title}</p>
<section class="regular-content">
<slot></slot>
</section>
</div>

<style>
.loading {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: 100%;
font-size: 7em;
}
.regular-content {
font-size: calc(1em / 7);
}
.loading p.gradiented {
margin-top: 1.5em;
font-size: calc(1.5em * 1 / 7);
font-weight: bold;
background: linear-gradient(90deg, var(--fg), var(--primary), var(--fg));
background-clip: text;
-webkit-text-fill-color: transparent;
/* stylelint-disable-next-line */
text-fill-color: transparent;
background-size: 200% auto;
animation: textgradient 1s linear infinite reverse;
}
@keyframes textgradient {
to {
background-position: 200% center;
}
}
</style>
23 changes: 15 additions & 8 deletions packages/app/src/lib/scroll.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { browser } from '$app/environment';
import { afterNavigate, beforeNavigate } from '$app/navigation';
import { page } from '$app/stores';
import { debugging } from '$lib/debugging';
import { onMount } from 'svelte';
import { syncToLocalStorage } from 'svelte-store2storage';
import { get, writable, type Writable } from 'svelte/store';
Expand All @@ -19,11 +20,13 @@ export function onReachingEndSoon(
threshold = 3,
) {
if (!browser) return () => {};
const log = taggedLogger('infinitescroll');

async function restartIntersectionObserver() {
// Get the element that's at threshold elements from the bottom
const elements = [...scrollableArea.querySelectorAll(scrollableElementSelector)];
const lastElement = elements.at(elements.length - threshold);
log(`watching for scroll into view of element`, lastElement);
// If there is no such element, we're at the bottom (or at least over the theshold)
if (!lastElement) {
await callback();
Expand All @@ -35,6 +38,7 @@ export function onReachingEndSoon(
async (entries) => {
// If the last element is in view, we're at the bottom
if (entries.some((entry) => entry.isIntersecting)) {
log(`reached last element, calling callback`);
await callback();
intersectionObserver.disconnect();
}
Expand All @@ -61,9 +65,7 @@ export function onReachingEndSoon(
// Also watch for intersection with the "infinitescroll bottom" element(data-infinitescroll-bottom)
infinitescrollBottomIntersectionObserver = new IntersectionObserver(async (entries) => {
if (entries.some((entry) => entry.isIntersecting)) {
console.warn(
`[infinitescroll] Reached data-infinitescroll-bottom, calling callback ${callback.name}`,
);
log(`reached data-infinitescroll-bottom, calling callback`);
await callback();
}
});
Expand Down Expand Up @@ -97,9 +99,10 @@ export function setupScrollPositionRestorer(
scrollableArea: HTMLElement | null | (() => HTMLElement | null),
onScroll: (scrolled: boolean) => void,
) {
const log = taggedLogger('scrollrestorer');
const scrollableElement = () => {
const element = scrollableArea instanceof Function ? scrollableArea() : scrollableArea;
console.info(`[scrollrestorer] Using scrollable element`, element);
log(`Using scrollable element`, element);
return element ?? document.documentElement;
};
/**
Expand All @@ -112,7 +115,7 @@ export function setupScrollPositionRestorer(
const scrollpos = {
[get(page).url.pathname]: scrollableElement().scrollTop,
};
console.info(`[scrollrestorer] Saving scroll position`, scrollpos);
log(`Saving scroll position`, scrollpos);
scrollPositions.set({
...get(scrollPositions),
...scrollpos,
Expand All @@ -121,9 +124,7 @@ export function setupScrollPositionRestorer(

afterNavigate(async () => {
const scrollpos = get(scrollPositions)[get(page).url.pathname];
console.info(
`[scrollrestorer] Restoring scroll position for ${get(page).url.pathname}: ${scrollpos}`,
);
log(`Restoring scroll position for ${get(page).url.pathname}: ${scrollpos}`);
scrollableElement().scrollTo(0, scrollpos ?? 0);
});

Expand All @@ -143,3 +144,9 @@ export function scrollableContainer(mobile: boolean) {
? (document.querySelector('#scrollable-area') as HTMLElement)
: (document.documentElement as HTMLElement);
}

function taggedLogger(tag: string) {
return (...msg: unknown[]) => {
if (get(debugging)) console.info(`[${tag}]`, ...msg);
};
}
62 changes: 32 additions & 30 deletions packages/app/src/routes/(app)/events/[id]/bookings/+page.gql
Original file line number Diff line number Diff line change
Expand Up @@ -23,36 +23,38 @@ query PageEventAllBookings($id: LocalID!, $filter: BookingState!) @loading {
hasNextPage
endCursor
}
nodes @loading(count: 30) {
id
code
...BookingBeneficiary
...BookingAuthor
ticket {
name
}
verifiedAt
verifiedBy {
...AvatarUser
fullName
}
cancelledAt
cancelledBy {
...AvatarUser
fullName
}
opposedAt
opposedBy {
...AvatarUser
fullName
}
updatedAt
...BookingPaymentMethod
...BookingStatus
authorIsBeneficiary
author {
...AvatarUser
fullName
edges @loading(count: 30) {
node {
id
code
...BookingBeneficiary
...BookingAuthor
ticket {
name
}
verifiedAt
verifiedBy {
...AvatarUser
fullName
}
cancelledAt
cancelledBy {
...AvatarUser
fullName
}
opposedAt
opposedBy {
...AvatarUser
fullName
}
updatedAt
...BookingPaymentMethod
...BookingStatus
authorIsBeneficiary
author {
...AvatarUser
fullName
}
}
}
}
Expand Down
27 changes: 20 additions & 7 deletions packages/app/src/routes/(app)/events/[id]/bookings/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,22 @@
import { graphql, type PageEventAllBookings$result } from '$houdini';
import Alert from '$lib/components/Alert.svelte';
import AvatarUser from '$lib/components/AvatarUser.svelte';
import BookingAuthor from '$lib/components/BookingAuthor.svelte';
import BookingBeneficiary from '$lib/components/BookingBeneficiary.svelte';
import BookingPaymentMethod from '$lib/components/BookingPaymentMethod.svelte';
import BookingStatus from '$lib/components/BookingStatus.svelte';
import BookingAuthor from '$lib/components/BookingAuthor.svelte';
import ButtonCopyToClipboard from '$lib/components/ButtonCopyToClipboard.svelte';
import ButtonSecondary from '$lib/components/ButtonSecondary.svelte';
import LoadingScreen from '$lib/components/LoadingScreen.svelte';
import MaybeError from '$lib/components/MaybeError.svelte';
import NavigationTabs from '$lib/components/NavigationTabs.svelte';
import ModalOrDrawer from '$lib/components/ModalOrDrawer.svelte';
import NavigationTabs from '$lib/components/NavigationTabs.svelte';
import { formatDateTimeSmart } from '$lib/dates';
import { allLoaded, loaded, loading, LoadingText, mapLoading } from '$lib/loading';
import { refroute } from '$lib/navigation';
import { isPWA } from '$lib/pwa';
import { route } from '$lib/ROUTES';
import { infinitescroll } from '$lib/scroll';
import { notNull } from '$lib/typing';
import IconOpenTicketPage from '~icons/msl/open-in-new';
import type { PageData } from './$houdini';
import { tabToFilter } from './filters';
Expand All @@ -31,7 +31,7 @@
$: activeTab = ($page.url.searchParams.get('tab') ?? 'unpaid') as (typeof FILTERS)[number];
let openBookingDetailModal: () => void;
let selectedBooking: PageEventAllBookings$result['event']['bookings']['nodes'][number];
let selectedBooking: PageEventAllBookings$result['event']['bookings']['edges'][number]['node'];
const updates = graphql(`
subscription BookingsListUpdates($id: LocalID!, $filter: BookingState!) {
Expand All @@ -54,8 +54,8 @@
$: newBookingsCount =
$updates.data?.event.bookings.nodes.filter(
(fresh) =>
!$PageEventAllBookings.data?.event.bookings.nodes.some(
(existing) => existing.id === fresh.id,
!$PageEventAllBookings.data?.event.bookings.edges.some(
({ node: existing }) => existing.id === fresh.id,
),
).length ?? 0;
Expand Down Expand Up @@ -203,7 +203,7 @@
</NavigationTabs>
</header>
<ul class="bookings" use:infinitescroll={() => PageEventAllBookings.loadNextPage()}>
{#each event.bookings.nodes.filter(notNull) as booking}
{#each event.bookings.edges as { node: booking }}
<li>
<button
class="booking"
Expand Down Expand Up @@ -251,6 +251,12 @@
<li class="booking empty muted">Aucune résevation pour le moment</li>
{/each}
</ul>
{#if loading(event.bookings.pageInfo.hasNextPage, false)}
<!-- TODO: Move to ./ItemBooking.svelte and add a loading placeholder one here -->
<div class="loading-more">
<LoadingScreen />
</div>
{/if}
</div>
</MaybeError>

Expand Down Expand Up @@ -353,4 +359,11 @@
gap: 0.5ch;
align-items: center;
}
.loading-more {
display: flex;
align-items: center;
justify-content: center;
font-size: 0.7em;
}
</style>
37 changes: 2 additions & 35 deletions packages/app/src/routes/(app)/login/done/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import { goto } from '$app/navigation';
import { page } from '$app/stores';
import { cache } from '$houdini';
import { LoadingChurros } from '$lib/loading';
import LoadingScreen from '$lib/components/LoadingScreen.svelte';
import { route } from '$lib/ROUTES';
import { onMount } from 'svelte';
Expand All @@ -12,37 +12,4 @@
});
</script>

<div class="loading">
<LoadingChurros />
<p>Connexion…</p>
</div>

<style>
.loading {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: 100%;
font-size: 7rem;
}
.loading p {
margin-top: 2rem;
font-size: 1.5rem;
font-weight: bold;
background: linear-gradient(90deg, var(--fg), var(--primary), var(--fg));
background-clip: text;
-webkit-text-fill-color: transparent;
/* stylelint-disable-next-line */
text-fill-color: transparent;
background-size: 200% auto;
animation: textgradient 1s linear infinite reverse;
}
@keyframes textgradient {
to {
background-position: 200% center;
}
}
</style>
<LoadingScreen title="Connexion…" />

0 comments on commit 13f22da

Please sign in to comment.