mirror of
https://github.com/soconnor0919/hristudio.git
synced 2026-02-05 07:56:30 -05:00
Pre-conf work 2025
This commit is contained in:
@@ -1,43 +1,41 @@
|
||||
"use client";
|
||||
|
||||
import {
|
||||
Briefcase, Clock, GraduationCap, Info, Mail, Shield, User
|
||||
} from "lucide-react";
|
||||
import { Briefcase, Clock, GraduationCap, Info, Shield } from "lucide-react";
|
||||
import { Avatar, AvatarFallback } from "~/components/ui/avatar";
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "~/components/ui/card";
|
||||
|
||||
interface ParticipantInfoProps {
|
||||
participant: {
|
||||
id: string;
|
||||
participantCode: string;
|
||||
email: string | null;
|
||||
name: string | null;
|
||||
demographics: any;
|
||||
demographics: Record<string, unknown> | null;
|
||||
};
|
||||
trialStatus: "scheduled" | "in_progress" | "completed" | "aborted" | "failed";
|
||||
}
|
||||
|
||||
export function ParticipantInfo({ participant }: ParticipantInfoProps) {
|
||||
const demographics = participant.demographics || {};
|
||||
export function ParticipantInfo({
|
||||
participant,
|
||||
trialStatus: _trialStatus,
|
||||
}: ParticipantInfoProps) {
|
||||
const demographics = participant.demographics ?? {};
|
||||
|
||||
// Extract common demographic fields
|
||||
const age = demographics.age;
|
||||
const gender = demographics.gender;
|
||||
const occupation = demographics.occupation;
|
||||
const education = demographics.education;
|
||||
const language = demographics.primaryLanguage || demographics.language;
|
||||
const location = demographics.location || demographics.city;
|
||||
const experience = demographics.robotExperience || demographics.experience;
|
||||
const age = demographics.age as string | number | undefined;
|
||||
const gender = demographics.gender as string | undefined;
|
||||
const occupation = demographics.occupation as string | undefined;
|
||||
const education = demographics.education as string | undefined;
|
||||
const language =
|
||||
(demographics.primaryLanguage as string | undefined) ??
|
||||
(demographics.language as string | undefined);
|
||||
const experience =
|
||||
(demographics.robotExperience as string | undefined) ??
|
||||
(demographics.experience as string | undefined);
|
||||
|
||||
// Get participant initials for avatar
|
||||
const getInitials = () => {
|
||||
if (participant.name) {
|
||||
const nameParts = participant.name.split(" ");
|
||||
return nameParts.map((part) => part.charAt(0).toUpperCase()).join("");
|
||||
}
|
||||
return participant.participantCode.substring(0, 2).toUpperCase();
|
||||
};
|
||||
|
||||
const formatDemographicValue = (key: string, value: any) => {
|
||||
const formatDemographicValue = (key: string, value: unknown) => {
|
||||
if (value === null || value === undefined || value === "") return null;
|
||||
|
||||
// Handle different data types
|
||||
@@ -53,81 +51,64 @@ export function ParticipantInfo({ participant }: ParticipantInfoProps) {
|
||||
return JSON.stringify(value);
|
||||
}
|
||||
|
||||
return String(value);
|
||||
return typeof value === "string" ? value : JSON.stringify(value);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center space-x-2">
|
||||
<User className="h-4 w-4 text-slate-600" />
|
||||
<h3 className="font-medium text-slate-900">Participant</h3>
|
||||
</div>
|
||||
|
||||
{/* Basic Info Card */}
|
||||
<Card className="shadow-sm">
|
||||
<CardContent className="p-4">
|
||||
<div className="flex items-start space-x-3">
|
||||
<Avatar className="h-10 w-10">
|
||||
<AvatarFallback className="bg-blue-100 font-medium text-blue-600">
|
||||
{getInitials()}
|
||||
</AvatarFallback>
|
||||
</Avatar>
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="truncate font-medium text-slate-900">
|
||||
{participant.name || "Anonymous"}
|
||||
</div>
|
||||
<div className="text-sm text-slate-600">
|
||||
ID: {participant.participantCode}
|
||||
</div>
|
||||
{participant.email && (
|
||||
<div className="mt-1 flex items-center space-x-1 text-xs text-slate-500">
|
||||
<Mail className="h-3 w-3" />
|
||||
<span className="truncate">{participant.email}</span>
|
||||
</div>
|
||||
)}
|
||||
{/* Basic Info */}
|
||||
<div className="rounded-lg border p-4">
|
||||
<div className="flex items-start space-x-3">
|
||||
<Avatar className="h-10 w-10">
|
||||
<AvatarFallback className="font-medium">
|
||||
{getInitials()}
|
||||
</AvatarFallback>
|
||||
</Avatar>
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="truncate font-medium text-slate-900">
|
||||
Participant {participant.participantCode}
|
||||
</div>
|
||||
<div className="text-sm text-slate-600">
|
||||
ID: {participant.participantCode}
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Quick Demographics */}
|
||||
{(age || gender || language) && (
|
||||
<Card className="shadow-sm">
|
||||
<CardContent className="p-4">
|
||||
<div className="grid grid-cols-1 gap-2 text-sm">
|
||||
{age && (
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-slate-600">Age:</span>
|
||||
<span className="font-medium">{age}</span>
|
||||
</div>
|
||||
)}
|
||||
{gender && (
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-slate-600">Gender:</span>
|
||||
<span className="font-medium capitalize">{gender}</span>
|
||||
</div>
|
||||
)}
|
||||
{language && (
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-slate-600">Language:</span>
|
||||
<span className="font-medium">{language}</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
{(age ?? gender ?? language) && (
|
||||
<div className="rounded-lg border p-4">
|
||||
<div className="grid grid-cols-1 gap-2 text-sm">
|
||||
{age && (
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-slate-600">Age:</span>
|
||||
<span className="font-medium">{age}</span>
|
||||
</div>
|
||||
)}
|
||||
{gender && (
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-slate-600">Gender:</span>
|
||||
<span className="font-medium capitalize">{gender}</span>
|
||||
</div>
|
||||
)}
|
||||
{language && (
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-slate-600">Language:</span>
|
||||
<span className="font-medium">{language}</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Background Info */}
|
||||
{(occupation || education || experience) && (
|
||||
<Card className="shadow-sm">
|
||||
<CardHeader className="pb-2">
|
||||
<CardTitle className="flex items-center space-x-1 text-sm font-medium text-slate-700">
|
||||
<Info className="h-3 w-3" />
|
||||
<span>Background</span>
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-2 pt-0">
|
||||
{(occupation ?? education ?? experience) && (
|
||||
<div className="rounded-lg border p-4">
|
||||
<div className="mb-3 flex items-center space-x-1 text-sm font-medium text-slate-700">
|
||||
<Info className="h-3 w-3" />
|
||||
<span>Background</span>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
{occupation && (
|
||||
<div className="flex items-start space-x-2 text-sm">
|
||||
<Briefcase className="mt-0.5 h-3 w-3 flex-shrink-0 text-slate-400" />
|
||||
@@ -155,19 +136,17 @@ export function ParticipantInfo({ participant }: ParticipantInfoProps) {
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Additional Demographics */}
|
||||
{Object.keys(demographics).length > 0 && (
|
||||
<Card className="shadow-sm">
|
||||
<CardHeader className="pb-2">
|
||||
<CardTitle className="text-sm font-medium text-slate-700">
|
||||
Additional Info
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="pt-0">
|
||||
<div className="rounded-lg border p-4">
|
||||
<div className="mb-3 text-sm font-medium text-slate-700">
|
||||
Additional Info
|
||||
</div>
|
||||
<div>
|
||||
<div className="space-y-1">
|
||||
{Object.entries(demographics)
|
||||
.filter(
|
||||
@@ -211,30 +190,26 @@ export function ParticipantInfo({ participant }: ParticipantInfoProps) {
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Consent Status */}
|
||||
<Card className="border-green-200 bg-green-50 shadow-sm">
|
||||
<CardContent className="p-3">
|
||||
<div className="flex items-center space-x-2">
|
||||
<div className="h-2 w-2 rounded-full bg-green-500"></div>
|
||||
<span className="text-sm font-medium text-green-800">
|
||||
Consent Verified
|
||||
</span>
|
||||
</div>
|
||||
<div className="mt-1 text-xs text-green-600">
|
||||
Participant has provided informed consent
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<div className="rounded-lg border p-3">
|
||||
<div className="flex items-center space-x-2">
|
||||
<div className="h-2 w-2 rounded-full bg-green-500"></div>
|
||||
<span className="text-sm font-medium">Consent Verified</span>
|
||||
</div>
|
||||
<div className="text-muted-foreground mt-1 text-xs">
|
||||
Participant has provided informed consent
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Session Info */}
|
||||
<div className="space-y-1 text-xs text-slate-500">
|
||||
<div className="flex items-center space-x-1">
|
||||
<Clock className="h-3 w-3" />
|
||||
<span>Session started: {new Date().toLocaleTimeString()}</span>
|
||||
<span>Session active</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user