NORY-15: implement infinite scroll for identities
This commit is contained in:
parent
2eb4b80607
commit
6db1b441f0
3 changed files with 64 additions and 6 deletions
|
@ -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>
|
||||
)
|
||||
}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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">
|
||||
|
|
20
dashboard/src/components/ui/spinner.tsx
Normal file
20
dashboard/src/components/ui/spinner.tsx
Normal 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>;
|
Loading…
Add table
Reference in a new issue