"use client"; import { type ColumnDef } from "@tanstack/react-table"; import { formatDistanceToNow } from "date-fns"; import { MoreHorizontal, Eye, Edit, Trash2, Copy, User, Mail, TestTube, } from "lucide-react"; import Link from "next/link"; import { Badge } from "~/components/ui/badge"; import { Button } from "~/components/ui/button"; import { Checkbox } from "~/components/ui/checkbox"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, } from "~/components/ui/dropdown-menu"; import { DataTableColumnHeader } from "~/components/ui/data-table-column-header"; import { toast } from "sonner"; export type Participant = { id: string; participantCode: string; email: string | null; name: string | null; consentGiven: boolean; consentDate: Date | null; createdAt: Date; trialCount: number; userRole?: "owner" | "researcher" | "wizard" | "observer"; canEdit?: boolean; canDelete?: boolean; }; function ParticipantActionsCell({ participant }: { participant: Participant }) { const handleDelete = async () => { if ( window.confirm( `Are you sure you want to delete participant "${participant.name ?? participant.participantCode}"?`, ) ) { try { // TODO: Implement delete participant mutation toast.success("Participant deleted successfully"); } catch { toast.error("Failed to delete participant"); } } }; const handleCopyId = () => { void navigator.clipboard.writeText(participant.id); toast.success("Participant ID copied to clipboard"); }; const handleCopyCode = () => { void navigator.clipboard.writeText(participant.participantCode); toast.success("Participant code copied to clipboard"); }; return ( Actions View Details {participant.canEdit && ( Edit Participant )} Copy Participant ID Copy Participant Code {!participant.consentGiven && ( Send Consent Form )} {participant.canDelete && ( <> Delete Participant )} ); } export const participantsColumns: ColumnDef[] = [ { id: "select", header: ({ table }) => ( table.toggleAllPageRowsSelected(!!value)} aria-label="Select all" /> ), cell: ({ row }) => ( row.toggleSelected(!!value)} aria-label="Select row" /> ), enableSorting: false, enableHiding: false, }, { accessorKey: "participantCode", header: ({ column }) => ( ), cell: ({ row }) => (
{row.getValue("participantCode")}
), }, { accessorKey: "name", header: ({ column }) => ( ), cell: ({ row }) => { const name = row.getValue("name") as string | null; const email = row.original.email; return (
{name ?? "No name provided"}
{email && (
{email}
)}
); }, }, { accessorKey: "consentGiven", header: ({ column }) => ( ), cell: ({ row }) => { const consentGiven = row.getValue("consentGiven"); const consentDate = row.original.consentDate; if (consentGiven) { return ( Consented ); } return ( Pending ); }, filterFn: (row, id, value) => { const consentGiven = row.getValue(id) as boolean; if (value === "consented") return !!consentGiven; if (value === "pending") return !consentGiven; return true; }, }, { accessorKey: "trialCount", header: ({ column }) => ( ), cell: ({ row }) => { const trialCount = row.getValue("trialCount") as number; return (
{trialCount as number}
); }, }, { accessorKey: "createdAt", header: ({ column }) => ( ), cell: ({ row }) => { const date = row.getValue("createdAt") as Date; return (
{formatDistanceToNow(date, { addSuffix: true })}
); }, }, { id: "actions", header: "Actions", cell: ({ row }) => , enableSorting: false, enableHiding: false, }, ];