feat: Enhance trial event display with improved formatting and icons, refine trial wizard panels, and update dashboard page layouts.

This commit is contained in:
2026-02-20 00:37:33 -05:00
parent 72971a4b49
commit 60d4fae72c
20 changed files with 1202 additions and 688 deletions

View File

@@ -1,12 +1,13 @@
"use client";
import { formatDistanceToNow } from "date-fns";
import { Calendar, Clock, Edit, Play, Settings, Users } from "lucide-react";
import { Calendar, Clock, Edit, Play, Settings, Users, TestTube } from "lucide-react";
import Link from "next/link";
import { notFound } from "next/navigation";
import { useEffect, useState } from "react";
import { Badge } from "~/components/ui/badge";
import { Button } from "~/components/ui/button";
import { PageHeader } from "~/components/ui/page-header";
import {
EntityView,
EntityViewHeader,
@@ -183,18 +184,19 @@ export default function ExperimentDetailPage({
return (
<EntityView>
<EntityViewHeader
<PageHeader
title={displayName}
subtitle={description ?? undefined}
icon="TestTube"
status={{
label: statusInfo?.label ?? "Unknown",
variant: statusInfo?.variant ?? "secondary",
icon: statusInfo?.icon ?? "TestTube",
}}
description={description ?? undefined}
icon={TestTube}
badges={[
{
label: statusInfo?.label ?? "Unknown",
variant: statusInfo?.variant ?? "secondary",
}
]}
actions={
canEdit ? (
<>
<div className="flex items-center gap-2">
<Button asChild variant="outline">
<Link href={`/studies/${studyId}/experiments/${experimentId}/designer`}>
<Settings className="mr-2 h-4 w-4" />
@@ -209,7 +211,7 @@ export default function ExperimentDetailPage({
Start Trial
</Link>
</Button>
</>
</div>
) : undefined
}
/>

View File

@@ -1,7 +1,7 @@
"use client";
import { formatDistanceToNow } from "date-fns";
import { Plus, Settings, Shield } from "lucide-react";
import { Plus, Settings, Shield, Building } from "lucide-react";
import Link from "next/link";
import { notFound } from "next/navigation";
import { useEffect, useState } from "react";
@@ -16,6 +16,7 @@ import {
QuickActions,
StatsGrid,
} from "~/components/ui/entity-view";
import { PageHeader } from "~/components/ui/page-header";
import { useBreadcrumbsEffect } from "~/components/ui/breadcrumb-provider";
import { useSession } from "next-auth/react";
import { api } from "~/trpc/react";
@@ -167,17 +168,18 @@ export default function StudyDetailPage({ params }: StudyDetailPageProps) {
return (
<EntityView>
{/* Header */}
<EntityViewHeader
<PageHeader
title={study.name}
subtitle={study.description ?? undefined}
icon="Building"
status={{
label: statusInfo?.label ?? "Unknown",
variant: statusInfo?.variant ?? "secondary",
icon: statusInfo?.icon ?? "FileText",
}}
description={study.description ?? undefined}
icon={Building}
badges={[
{
label: statusInfo?.label ?? "Unknown",
variant: statusInfo?.variant ?? "secondary",
}
]}
actions={
<>
<div className="flex items-center gap-2">
<Button asChild variant="outline">
<Link href={`/studies/${study.id}/edit`}>
<Settings className="mr-2 h-4 w-4" />
@@ -190,7 +192,7 @@ export default function StudyDetailPage({ params }: StudyDetailPageProps) {
New Experiment
</Link>
</Button>
</>
</div>
}
/>
@@ -271,10 +273,10 @@ export default function StudyDetailPage({ params }: StudyDetailPageProps) {
</h4>
<span
className={`inline-flex items-center rounded-full px-2 py-1 text-xs font-medium ${experiment.status === "draft"
? "bg-gray-100 text-gray-800"
: experiment.status === "ready"
? "bg-green-100 text-green-800"
: "bg-blue-100 text-blue-800"
? "bg-gray-100 text-gray-800"
: experiment.status === "ready"
? "bg-green-100 text-green-800"
: "bg-blue-100 text-blue-800"
}`}
>
{experiment.status}

View File

@@ -10,8 +10,9 @@ import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "~/com
import { Badge } from "~/components/ui/badge";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "~/components/ui/tabs";
import { Button } from "~/components/ui/button";
import { Edit } from "lucide-react";
import { Edit, Users } from "lucide-react";
import Link from "next/link";
import { PageHeader } from "~/components/ui/page-header";
import { ParticipantConsentManager } from "~/components/participants/ParticipantConsentManager";
@@ -37,14 +38,16 @@ export default async function ParticipantDetailPage({
return (
<EntityView>
<EntityViewHeader
<PageHeader
title={participant.participantCode}
subtitle={participant.name ?? "Unnamed Participant"}
icon="Users"
status={{
label: participant.consentGiven ? "Consent Given" : "No Consent",
variant: participant.consentGiven ? "default" : "secondary"
}}
description={participant.name ?? "Unnamed Participant"}
icon={Users}
badges={[
{
label: participant.consentGiven ? "Consent Given" : "No Consent",
variant: participant.consentGiven ? "default" : "secondary"
}
]}
actions={
<Button asChild variant="outline" size="sm">
<Link href={`/studies/${studyId}/participants/${participantId}/edit`}>

View File

@@ -86,7 +86,7 @@ function AnalysisPageContent() {
);
}
const trialData = {
const customTrialData = {
...trial,
startedAt: trial.startedAt ? new Date(trial.startedAt) : null,
completedAt: trial.completedAt ? new Date(trial.completedAt) : null,
@@ -96,7 +96,7 @@ function AnalysisPageContent() {
return (
<TrialAnalysisView
trial={trialData}
trial={customTrialData}
backHref={`/studies/${studyId}/trials/${trialId}`}
/>
);

View File

@@ -140,6 +140,12 @@ function TrialDetailContent() {
title={`Trial: ${trial.participant.participantCode}`}
description={`${trial.experiment.name} - Session ${trial.sessionNumber}`}
icon={Play}
badges={[
{
label: trial.status.replace("_", " ").toUpperCase(),
variant: getStatusBadgeVariant(trial.status),
}
]}
actions={
<div className="flex gap-2">
{trial.status === "scheduled" && (