"use client"; import { formatDistanceToNow } from "date-fns"; import { Plus, Settings, Shield } from "lucide-react"; import Link from "next/link"; import { notFound } from "next/navigation"; import { useEffect, useState } from "react"; import { Button } from "~/components/ui/button"; import { EntityView, EntityViewHeader, EntityViewSection, EntityViewSidebar, EmptyState, InfoGrid, QuickActions, StatsGrid, } from "~/components/ui/entity-view"; import { useBreadcrumbsEffect } from "~/components/ui/breadcrumb-provider"; import { useSession } from "next-auth/react"; import { api } from "~/trpc/react"; interface StudyDetailPageProps { params: Promise<{ id: string; }>; } const statusConfig = { draft: { label: "Draft", variant: "secondary" as const, icon: "FileText" as const, }, active: { label: "Active", variant: "default" as const, icon: "CheckCircle" as const, }, completed: { label: "Completed", variant: "outline" as const, icon: "CheckCircle" as const, }, archived: { label: "Archived", variant: "destructive" as const, icon: "XCircle" as const, }, }; type Study = { id: string; name: string; description: string | null; status: string; institution: string | null; irbProtocol: string | null; createdAt: Date; updatedAt: Date; }; type Member = { role: string; user: { name: string | null; email: string; }; }; export default function StudyDetailPage({ params }: StudyDetailPageProps) { const { data: session } = useSession(); const [study, setStudy] = useState(null); const [members, setMembers] = useState([]); const [loading, setLoading] = useState(true); const [resolvedParams, setResolvedParams] = useState<{ id: string } | null>( null, ); useEffect(() => { const resolveParams = async () => { const resolved = await params; setResolvedParams(resolved); }; void resolveParams(); }, [params]); const { data: studyData } = api.studies.get.useQuery( { id: resolvedParams?.id ?? "" }, { enabled: !!resolvedParams?.id }, ); const { data: membersData } = api.studies.getMembers.useQuery( { studyId: resolvedParams?.id ?? "" }, { enabled: !!resolvedParams?.id }, ); const { data: experimentsData } = api.experiments.list.useQuery( { studyId: resolvedParams?.id ?? "" }, { enabled: !!resolvedParams?.id }, ); const { data: participantsData } = api.participants.list.useQuery( { studyId: resolvedParams?.id ?? "" }, { enabled: !!resolvedParams?.id }, ); const { data: trialsData } = api.trials.list.useQuery( { studyId: resolvedParams?.id ?? "" }, { enabled: !!resolvedParams?.id }, ); const { data: activityData } = api.studies.getActivity.useQuery( { studyId: resolvedParams?.id ?? "", limit: 5 }, { enabled: !!resolvedParams?.id }, ); useEffect(() => { if (studyData) { setStudy(studyData); } if (membersData) { setMembers(membersData); } if (studyData !== undefined) { setLoading(false); } }, [studyData, membersData]); // Set breadcrumbs useBreadcrumbsEffect([ { label: "Dashboard", href: "/dashboard" }, { label: "Studies", href: "/studies" }, { label: study?.name ?? "Study" }, ]); if (!session?.user) { return notFound(); } if (loading || !study) { return
Loading...
; } const statusInfo = statusConfig[study.status as keyof typeof statusConfig]; const experiments = experimentsData ?? []; const participants = participantsData?.participants ?? []; const trials = trialsData ?? []; const activities = activityData?.activities ?? []; const completedTrials = trials.filter( (trial: { status: string }) => trial.status === "completed", ).length; const totalTrials = trials.length; const stats = { experiments: experiments.length, totalTrials: totalTrials, participants: participants.length, completionRate: totalTrials > 0 ? `${Math.round((completedTrials / totalTrials) * 100)}%` : "—", }; return ( {/* Header */} } />
{/* Main Content */}
{/* Study Information */} {/* Experiments */} Add Experiment } > {experiments.length === 0 ? ( Create First Experiment } /> ) : (
{experiments.map((experiment) => (

{experiment.name}

{experiment.status}
{experiment.description && (

{experiment.description}

)}
Created{" "} {formatDistanceToNow(experiment.createdAt, { addSuffix: true, })} {experiment.estimatedDuration && ( Est. {experiment.estimatedDuration} min )}
))}
)}
{/* Recent Activity */} {activities.length === 0 ? ( ) : (
{activities.map((activity) => (
{activity.user?.name?.charAt(0) ?? activity.user?.email?.charAt(0) ?? "?"}

{activity.user?.name ?? activity.user?.email ?? "Unknown User"}

{formatDistanceToNow(activity.createdAt, { addSuffix: true, })}

{activity.description}

))} {activityData && activityData.pagination.total > 5 && (
)}
)}
{/* Sidebar */} {/* Team Members */} Invite } >
{members.map((member, index) => (
{(member.user.name ?? member.user.email) .charAt(0) .toUpperCase()}

{member.user.name ?? member.user.email}

{member.role}

{member.role === "owner" && ( )}
))}
{/* Quick Stats */} {/* Quick Actions */}
); }