Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { Button } from '@/components/ui/button';
import { Badge, type BadgeTone } from '@/components/ui/badge';
import { Callout } from '@/components/ui/callout';
import {
Play, CheckCircle2, AlertTriangle, FileText,
Play, CheckCircle2, AlertTriangle,
ArrowRight, Clock, Loader2, Network, Upload, Download,
ChevronDown, ChevronRight, Timer, Shield, Zap,
TrendingUp, RotateCcw,
Expand All @@ -25,38 +25,13 @@ import { trackToolRunStarted, trackToolRunCompleted } from '@/lib/conversion-eve
type Phase = 'scenario' | 'upload' | 'analyzing' | 'results' | 'report';

interface DrillState {
selectedScenario: string | null;
uploadedFile: File | null;
validationResult: ValidationResult | null;
phase: Phase;
drillStartTime: number | null;
uploadTime: number | null;
}

const scenarios = [
{
id: 'produce',
title: 'Fresh Produce Supplier',
description: 'Multi-state leafy greens distributor with 500+ retail customers',
complexity: 'High',
recordCount: '2,000+',
},
{
id: 'dairy',
title: 'Dairy Processing Facility',
description: 'Fluid milk processor with complex ingredients and co-packers',
complexity: 'Medium',
recordCount: '800+',
},
{
id: 'supplements',
title: 'Supplement Manufacturer',
description: 'Multi-ingredient dietary supplements with international suppliers',
complexity: 'Very High',
recordCount: '5,000+',
},
];

const analysisStages = [
{ name: 'Parsing records...', duration: 500 },
{ name: 'Mapping CTEs and KDEs...', duration: 800 },
Expand All @@ -67,7 +42,6 @@ const analysisStages = [

export function DrillSimulatorClient() {
const [state, setState] = useState<DrillState>({
selectedScenario: null,
uploadedFile: null,
validationResult: null,
phase: 'scenario',
Expand Down Expand Up @@ -104,10 +78,9 @@ export function DrillSimulatorClient() {
return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
};

const handleScenarioSelect = (scenarioId: string, drillStartTime: number) => {
const handleStartDrill = (drillStartTime: number) => {
setState({
...state,
selectedScenario: scenarioId,
phase: 'upload',
drillStartTime,
uploadTime: null,
Expand Down Expand Up @@ -231,14 +204,10 @@ export function DrillSimulatorClient() {
if (!state.validationResult) return;

const result = state.validationResult;
const scenarioName =
scenarios.find((s) => s.id === state.selectedScenario)?.title ||
'Drill';

const report = `FDA RECALL DRILL SIMULATOR: FULL REPORT
Generated: ${new Date().toISOString()}

SCENARIO: ${scenarioName}
RECORDS ANALYZED: ${result.totalRecords}
OVERALL SCORE: ${result.scores.overallScore.toFixed(1)}/100 (${result.scores.grade})

Expand Down Expand Up @@ -297,7 +266,6 @@ STATUS: ${

const handleReset = () => {
setState({
selectedScenario: null,
uploadedFile: null,
validationResult: null,
phase: 'scenario',
Expand Down Expand Up @@ -341,33 +309,12 @@ STATUS: ${
</p>
</div>

<div className="mb-8 grid grid-cols-1 gap-4 md:grid-cols-3">
{scenarios.map((scenario) => (
<button
key={scenario.id}
type="button"
onClick={() => handleScenarioSelect(scenario.id, Date.now())}
className="rounded-lg border border-re-border bg-re-surface-card p-5 text-left transition-colors duration-120 hover:border-re-border-strong hover:bg-re-surface-inset focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-re-focus-ring focus-visible:ring-offset-2 focus-visible:ring-offset-re-surface-base motion-reduce:transition-none"
>
<div className="mb-3 flex items-start justify-between gap-3">
<h3 className="text-subheading text-re-text-primary">
{scenario.title}
</h3>
<Badge tone="neutral" size="sm">{scenario.complexity}</Badge>
</div>
<p className="mb-4 text-ui text-re-text-secondary">
{scenario.description}
</p>
<div className="flex items-center gap-2 text-small text-re-text-muted">
<FileText size={14} strokeWidth={1.75} aria-hidden="true" />
{scenario.recordCount} records
</div>
</button>
))}
</div>

<div className="mb-8 flex flex-col justify-center gap-4 sm:flex-row">
<Button size="lg" leadingIcon={<Play size={18} strokeWidth={1.75} aria-hidden="true" />}>
<Button
size="lg"
onClick={() => handleStartDrill(Date.now())}
leadingIcon={<Play size={18} strokeWidth={1.75} aria-hidden="true" />}
>
Start Drill: Upload Your Records
</Button>
<Button
Expand Down Expand Up @@ -404,15 +351,6 @@ STATUS: ${
</div>
</div>

<Card className="mb-6" padding="compact">
<h3 className="text-subheading text-re-text-primary">
Scenario: {scenarios.find((s) => s.id === state.selectedScenario)?.title}
</h3>
<p className="mt-1 text-ui text-re-text-secondary">
{scenarios.find((s) => s.id === state.selectedScenario)?.description}
</p>
</Card>

<div
className={cn(
'cursor-pointer rounded-lg border-2 border-dashed p-8 text-center transition-colors duration-120 motion-reduce:transition-none sm:p-12',
Expand Down Expand Up @@ -585,7 +523,7 @@ STATUS: ${
</div>
<Badge tone="info">{gapSummary}</Badge>
<p className="mt-2 text-small text-re-text-tertiary">
Self-check on synthetic drill data. Not a compliance verdict.
Self-check on the records analyzed. Not a compliance verdict.
</p>
</div>
</Card>
Expand Down Expand Up @@ -663,7 +601,7 @@ STATUS: ${
<ScoreCircle score={result.scores.overallScore} />
<Badge tone="info" className="mt-3">{gapSummary}</Badge>
<p className="mt-2 text-center text-small text-re-text-tertiary">
Self-check on synthetic drill data. Not a compliance verdict.
Self-check on the records analyzed. Not a compliance verdict.
</p>
</div>
<div className="space-y-4">
Expand Down Expand Up @@ -892,7 +830,7 @@ STATUS: ${
headline="Get Your Drill Findings"
subheadline="Unlock detailed findings, gap analysis, and a downloadable self-check report."
ctaText="Unlock Findings"
toolContext={{ toolInputs: { score: result.scores.overallScore, grade: result.scores.grade, scenario: state.selectedScenario } }}
toolContext={{ toolInputs: { score: result.scores.overallScore, grade: result.scores.grade } }}
teaser={teaser}
onUnlock={() => {}}
>
Expand Down
Loading
Loading