Files
triqura-ecd/components/cortex/shared/block-item.tsx
colinislit b095b1e492 feat(cortex): add Intake Blocks MVP for voice/text commands
Adds 4 new intents for intake workflow:
- intake_status: shows completion percentage and section checklist
- intake_navigeer: navigation to specific intake tabs
- risico_query: displays risk assessments with severity indicators
- diagnose_query: shows primary/secondary diagnoses

New components:
- IntakeStatusBlock, RisicoBlock, DiagnoseBlock
- Shared block components (BlockLoading, BlockError, BlockEmpty, BlockSection, BlockItem, BlockFooter)
- useBlockData and useIntakeContext hooks

New API routes:
- GET /api/cortex/intake/status
- GET /api/cortex/intake/risico
- GET /api/cortex/intake/diagnose

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-03 23:21:18 +01:00

129 lines
3.3 KiB
TypeScript

'use client';
/**
* BlockItem Component
*
* List item for use within BlockSection.
* Supports title, subtitle, badge, and click handling.
*
* Epic: E1.S2 - Block Layout
*/
import { cn } from '@/lib/utils';
// ============================================================================
// Types
// ============================================================================
export type BadgeVariant = 'default' | 'success' | 'warning' | 'danger';
interface BlockItemProps {
/** Hoofdtekst */
title: string;
/** Subtekst (datum, auteur, etc.) */
subtitle?: string;
/** Status badge */
badge?: {
label: string;
variant: BadgeVariant;
};
/** Klik handler (maakt item klikbaar) */
onClick?: () => void;
/** Extra CSS classes */
className?: string;
}
// ============================================================================
// Styling
// ============================================================================
const BADGE_STYLES: Record<BadgeVariant, string> = {
default: 'bg-slate-100 text-slate-700 border-slate-200',
success: 'bg-green-50 text-green-700 border-green-200',
warning: 'bg-amber-50 text-amber-700 border-amber-200',
danger: 'bg-red-50 text-red-700 border-red-200',
};
// ============================================================================
// Component
// ============================================================================
/**
* List item for Cortex blocks.
* Renders as button when clickable, div otherwise.
*/
export function BlockItem({
title,
subtitle,
badge,
onClick,
className,
}: BlockItemProps) {
const isClickable = Boolean(onClick);
const Component = isClickable ? 'button' : 'div';
return (
<Component
type={isClickable ? 'button' : undefined}
onClick={onClick}
className={cn(
'flex items-center justify-between p-3 rounded-lg',
'bg-slate-50 border border-slate-200',
'w-full text-left',
isClickable && [
'cursor-pointer',
'hover:bg-slate-100 hover:border-slate-300',
'transition-colors',
],
className
)}
>
{/* Content */}
<div className="min-w-0 flex-1">
<p className="text-sm font-medium text-slate-900 truncate">{title}</p>
{subtitle && (
<p className="text-xs text-slate-500 mt-0.5 truncate">{subtitle}</p>
)}
</div>
{/* Badge */}
{badge && (
<span
className={cn(
'ml-3 flex-shrink-0',
'px-2 py-0.5 rounded-full',
'text-xs font-medium border',
BADGE_STYLES[badge.variant]
)}
>
{badge.label}
</span>
)}
</Component>
);
}
// ============================================================================
// Helper: Get variant from risk level
// ============================================================================
/**
* Maps risk level string to badge variant.
* Used for consistent risk display across blocks.
*/
export function getRiskBadgeVariant(level: string): BadgeVariant {
switch (level.toLowerCase()) {
case 'laag':
return 'success';
case 'gemiddeld':
case 'matig':
return 'warning';
case 'hoog':
case 'zeer_hoog':
case 'zeer hoog':
return 'danger';
default:
return 'default';
}
}