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>
This commit is contained in:
136
components/cortex/shared/block-states.tsx
Normal file
136
components/cortex/shared/block-states.tsx
Normal file
@@ -0,0 +1,136 @@
|
||||
'use client';
|
||||
|
||||
/**
|
||||
* Block State Components
|
||||
*
|
||||
* Reusable state components for Cortex blocks:
|
||||
* - BlockLoading: Loading spinner with message
|
||||
* - BlockError: Error state with retry option
|
||||
* - BlockEmpty: Empty state with action option
|
||||
*
|
||||
* Epic: E0 - Block States
|
||||
*/
|
||||
|
||||
import { Loader2, AlertCircle, RefreshCw } from 'lucide-react';
|
||||
import type { LucideIcon } from 'lucide-react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
// ============================================================================
|
||||
// BlockLoading (E0.S1)
|
||||
// ============================================================================
|
||||
|
||||
interface BlockLoadingProps {
|
||||
/** Tekst onder de spinner */
|
||||
message?: string;
|
||||
/** Extra CSS classes */
|
||||
className?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loading state for Cortex blocks.
|
||||
* Shows centered spinner with optional message.
|
||||
*/
|
||||
export function BlockLoading({
|
||||
message = 'Laden...',
|
||||
className,
|
||||
}: BlockLoadingProps) {
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
'flex flex-col items-center justify-center py-12',
|
||||
className
|
||||
)}
|
||||
>
|
||||
<Loader2 className="h-6 w-6 animate-spin text-slate-400 mb-2" />
|
||||
<span className="text-sm text-slate-500">{message}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// BlockError (E0.S2)
|
||||
// ============================================================================
|
||||
|
||||
interface BlockErrorProps {
|
||||
/** Foutmelding tekst */
|
||||
message: string;
|
||||
/** Callback voor retry knop (toont knop indien aanwezig) */
|
||||
onRetry?: () => void;
|
||||
/** Extra CSS classes */
|
||||
className?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Error state for Cortex blocks.
|
||||
* Shows error icon, message, and optional retry button.
|
||||
*/
|
||||
export function BlockError({
|
||||
message,
|
||||
onRetry,
|
||||
className,
|
||||
}: BlockErrorProps) {
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
'flex flex-col items-center justify-center py-8 text-center',
|
||||
className
|
||||
)}
|
||||
>
|
||||
<AlertCircle className="h-8 w-8 text-red-500 mb-2" />
|
||||
<p className="text-sm text-red-700 mb-3 max-w-xs">{message}</p>
|
||||
{onRetry && (
|
||||
<Button variant="outline" size="sm" onClick={onRetry}>
|
||||
<RefreshCw className="h-4 w-4 mr-1.5" />
|
||||
Opnieuw proberen
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// BlockEmpty (E0.S3)
|
||||
// ============================================================================
|
||||
|
||||
interface BlockEmptyProps {
|
||||
/** Icoon component */
|
||||
icon: LucideIcon;
|
||||
/** Hoofdboodschap */
|
||||
message: string;
|
||||
/** Optionele actie knop */
|
||||
action?: {
|
||||
label: string;
|
||||
onClick: () => void;
|
||||
};
|
||||
/** Extra CSS classes */
|
||||
className?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Empty state for Cortex blocks.
|
||||
* Shows icon, message, and optional action button.
|
||||
*/
|
||||
export function BlockEmpty({
|
||||
icon: Icon,
|
||||
message,
|
||||
action,
|
||||
className,
|
||||
}: BlockEmptyProps) {
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
'flex flex-col items-center justify-center py-8 text-center',
|
||||
className
|
||||
)}
|
||||
>
|
||||
<Icon className="h-8 w-8 text-slate-300 mb-2" />
|
||||
<p className="text-sm text-slate-500 mb-3">{message}</p>
|
||||
{action && (
|
||||
<Button variant="outline" size="sm" onClick={action.onClick}>
|
||||
{action.label}
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user