NORY-15: implement infinite scroll for identities

This commit is contained in:
Markus Thielker 2024-12-08 08:36:04 +01:00
parent 2eb4b80607
commit 6db1b441f0
No known key found for this signature in database
3 changed files with 64 additions and 6 deletions

View file

@ -5,8 +5,9 @@ import { Identity } from '@ory/client';
import { DataTable } from '@/components/ui/data-table';
import { CircleCheck, CircleX } from 'lucide-react';
import { HoverCard, HoverCardContent, HoverCardTrigger } from '@/components/ui/hover-card';
import { useState } from 'react';
import { useEffect, useRef, useState } from 'react';
import { FetchIdentityPageProps } from '@/app/user/page';
import { Spinner } from '@/components/ui/spinner';
interface IdentityDataTableProps {
data: Identity[];
@ -89,8 +90,12 @@ export function IdentityDataTable({ data, pageSize, pageToken, query, fetchIdent
const [items, setItems] = useState<Identity[]>(data);
const [nextToken, setNextToken] = useState<string | undefined>(pageToken);
const fetchMore = async () => {
useEffect(() => {
setItems(data);
setNextToken(pageToken);
}, [data, pageSize, pageToken, query]);
const fetchMore = async () => {
if (!nextToken) return;
const response = await fetchIdentityPage({
@ -103,6 +108,39 @@ export function IdentityDataTable({ data, pageSize, pageToken, query, fetchIdent
setNextToken(response.tokens.get('next') ?? undefined);
};
// TODO: fetch more when scrolling to the end of list
return <DataTable columns={columns} data={items}/>;
const infiniteScrollSensor = useRef(null);
useEffect(() => {
const observer = new IntersectionObserver(
(entries) => {
if (entries[0].isIntersecting) {
fetchMore();
}
},
{ threshold: 0.5 }, // Adjust threshold as needed
);
if (infiniteScrollSensor.current) {
observer.observe(infiniteScrollSensor.current);
}
return () => {
if (infiniteScrollSensor.current) {
observer.unobserve(infiniteScrollSensor.current);
}
};
}, [items]);
return (
<>
<DataTable columns={columns} data={items}/>
{
nextToken && (
<div className="flex w-full justify-center">
<Spinner ref={infiniteScrollSensor} className="h-10"/>
</div>
)
}
</>
);
}

View file

@ -56,10 +56,10 @@ export default async function UserPage(
const params = await searchParams;
const query = params.query ? params.query as string : '';
let pageSize = 200;
let pageSize = 250;
let pageToken: string = '00000000-0000-0000-0000-000000000000';
const initialFetch = await fetchIdentityPage({ pageSize, pageToken, query: '' });
const initialFetch = await fetchIdentityPage({ pageSize, pageToken, query: query });
return (
<div className="space-y-4">

View file

@ -0,0 +1,20 @@
import { cn } from '@/lib/utils';
import { RefObject } from 'react';
export const Spinner = (
{ className, ref }: { className?: string, ref: RefObject<any> },
) => <svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
className={cn('animate-spin', className)}
ref={ref}
>
<path d="M21 12a9 9 0 1 1-6.219-8.56"/>
</svg>;