'use client'; import { ColumnDef } from '@tanstack/react-table'; import { Identity } from '@ory/client'; import { DataTable } from '@/components/ui/data-table'; import { CircleCheck, CircleX, Copy, MoreHorizontal, Trash, UserCheck, UserMinus, UserPen, UserX } from 'lucide-react'; import React, { useEffect, useRef, useState } from 'react'; import { FetchIdentityPageProps } from '@/app/(inside)/user/page'; import { Spinner } from '@/components/ui/spinner'; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, } from '@/components/ui/dropdown-menu'; import { Button, buttonVariants } from '@/components/ui/button'; import Link from 'next/link'; import { toast } from 'sonner'; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, } from '@/components/ui/alert-dialog'; import { blockIdentity, deleteIdentity, deleteIdentitySessions, unblockIdentity } from '@/app/(inside)/user/action'; import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'; interface IdentityDataTableProps { data: Identity[]; pageSize: number; pageToken: string | undefined; query: string; fetchIdentityPage: (props: FetchIdentityPageProps) => Promise<{ data: Identity[], tokens: Map }>; } export function IdentityDataTable({ data, pageSize, pageToken, query, fetchIdentityPage }: IdentityDataTableProps) { const columns: ColumnDef[] = [ { id: 'id', accessorKey: 'id', header: 'ID', }, { id: 'active', header: 'Active', cell: ({ row }) => { const identity = row.original; if (identity.state === 'active') { return ; } else { return ; } }, }, { id: 'name', accessorKey: 'traits.name', header: 'Name', }, { id: 'email', header: 'Email', cell: ({ row }) => { const identity = row.original; const email = identity.verifiable_addresses ? identity.verifiable_addresses[0] : undefined; if (!email) { return

Something went wrong

; } else { return (
{email.value} { email.verified ? This email was confirmed at {new Date(email.verified_at!!).toLocaleString()} : This email is not confirmed yet }
); } }, }, { id: 'actions', cell: ({ row }) => { const identity = row.original; return ( Actions { navigator.clipboard.writeText(identity.id); toast.success('Copied to clipboard'); }} > Copy identity ID View identity { setCurrentIdentity(identity); setIdentitySessionVisible(true); }} className="flex items-center space-x-2 text-red-500"> Delete sessions { identity.state === 'active' && { setCurrentIdentity(identity); setBlockIdentityVisible(true); }} className="flex items-center space-x-2 text-red-500"> Block identity } { identity.state === 'inactive' && { setCurrentIdentity(identity); setUnblockIdentityVisible(true); }} className="flex items-center space-x-2 text-red-500"> Unblock identity } { setCurrentIdentity(identity); setDeleteIdentityVisible(true); }} className="flex items-center space-x-2 text-red-500"> Delete identity ); }, }, ]; const [items, setItems] = useState(data); const [nextToken, setNextToken] = useState(pageToken); // react on changes from ssr (query params) useEffect(() => { setItems(data); setNextToken(pageToken); }, [data, pageSize, pageToken, query]); // infinite scroll handling 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]); const fetchMore = async () => { if (!nextToken) return; const response = await fetchIdentityPage({ pageSize: pageSize, pageToken: nextToken, query: query, }); setItems([...items, ...response.data]); setNextToken(response.tokens.get('next') ?? undefined); }; // quick actions const [currentIdentity, setCurrentIdentity] = useState(undefined); const [identitySessionVisible, setIdentitySessionVisible] = useState(false); const [blockIdentityVisible, setBlockIdentityVisible] = useState(false); const [unblockIdentityVisible, setUnblockIdentityVisible] = useState(false); const [deleteIdentityVisible, setDeleteIdentityVisible] = useState(false); return ( <> { currentIdentity && ( <> {/* delete sessions dialog */} setIdentitySessionVisible(open)}> Delete sessions Are you sure you want to delete this identity's sessions? {JSON.stringify(currentIdentity.traits, null, 4)} Cancel deleteIdentitySessions(currentIdentity.id)}> Invalidate sessions {/* block identity dialog */} setBlockIdentityVisible(open)}> Block identity Are you sure you want to block this identity? {JSON.stringify(currentIdentity.traits, null, 4)} Cancel blockIdentity(currentIdentity.id)}> Block identity {/* unblock identity dialog */} setUnblockIdentityVisible(open)}> Unblock identity Are you sure you want to unblock this identity? {JSON.stringify(currentIdentity.traits, null, 4)} Cancel unblockIdentity(currentIdentity.id)}> Unblock identity {/* delete identity dialog */} setDeleteIdentityVisible(open)}> Delete identity Are you sure you want to delete this identity? This action can not be undone! {JSON.stringify(currentIdentity.traits, null, 4)} Cancel deleteIdentity(currentIdentity.id)}> Delete identity ) } { nextToken && (
) } ); }