Files
triqura-ecd/components/swift/command-center/command-center.tsx
colinislit 3814189934 feat(swift): implementeer artifact opening from chat (E3.S6) 🎉
Epic 3 Story 6 compleet: Artifacts openen automatisch vanuit chat!
🎉 EPIC 3 COMPLEET - Medical Scribe Chat werkt end-to-end!

E3.S6 - Artifact Opening from Chat (2 SP)
- PendingAction state triggers artifact opening
- useEffect in CommandCenter luistert naar pendingAction
- Automatische block opening met prefill data
- Visual flow: Chat → AI → Action → Artifact verschijnt rechts

Components Updated:
- components/swift/artifacts/artifact-area.tsx (86 regels)
  - Renders DagnotatieBlock, ZoekenBlock, OverdrachtBlock
  - Placeholder state wanneer geen block actief
  - Conditional rendering based on activeBlock state

- components/swift/command-center/command-center.tsx
  - useEffect voor pendingAction handling
  - openBlock(type, prefill) aanroep
  - setPendingAction(null) cleanup
  - Console logging voor debugging

Artifact Opening Flow:
1. User: "Notitie voor Jan: medicatie gegeven"
2. AI response met JSON action (confidence 0.95)
3. ChatPanel: parseActionFromResponse()
4. ChatPanel: setPendingAction(action) if confidence ≥ 0.7
5. CommandCenter: useEffect triggers op pendingAction
6. CommandCenter: openBlock('dagnotitie', { patientName: 'Jan', ... })
7. ArtifactArea: Renders DagnotatieBlock met prefill
8. setPendingAction(null) cleanup

Features:
- Automatische artifact opening bij high confidence (≥0.7)
- Prefill data van AI naar block (patientName, category, content, etc.)
- Console logging voor debugging:
  - "[CommandCenter] Processing pending action: {...}"
  - "[CommandCenter] Opening artifact: dagnotitie with prefill: {...}"
- Placeholder state met voorbeelden wanneer geen artifact actief
- Overflow-y-auto voor scrollable artifacts

Blocks Supported:
- dagnotitie → DagnotatieBlock
- zoeken → ZoekenBlock
- overdracht → OverdrachtBlock
- fallback → FallbackPicker

Build Status:
-  pnpm build succesvol (geen type errors)
- Alleen bekende warnings (Supabase realtime, useCallback)

Epic 3 Summary (Chat API & Medical Scribe):
-  E3.S1 — Chat API endpoint skeleton (3 SP)
-  E3.S2 — Streaming response logic (5 SP)
-  E3.S3 — Medical scribe system prompt (3 SP)
-  E3.S4 — Intent detection in response (5 SP)
-  E3.S5 — Frontend streaming (GESKIPT - 3 SP)
-  E3.S6 — Artifact opening from chat (2 SP)

Epic 3 Stats: 5/6 stories (18 SP), 1 geskipt (3 SP)

Voortgang: 48 SP / 85 SP (56%) - 16/31 stories compleet, 2 geskipt

Next Epic: E4 (Artifact Area & Tabs) - Meerdere artifacts, tabs, animaties

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-27 16:23:00 +01:00

99 lines
3.0 KiB
TypeScript

'use client';
/**
* Command Center (v3.0)
*
* Main container for the Swift interface.
* Split-screen layout: Chat Panel (40%) | Artifact Area (60%)
*
* Layout specs:
* - Context Bar: 48px (h-12) - UNCHANGED
* - Split container: flex-1 (fills remaining space)
* - Chat Panel: 40% width (desktop), 100% (mobile)
* - Artifact Area: 60% width (desktop), 100% (mobile)
*
* Epic: E1 (Foundation)
* Stories: E1.S2 (Split-screen layout), E1.S3 (Placeholders), E1.S4 (Responsive)
*/
import { useEffect, useCallback, useRef } from 'react';
import { useSwiftStore } from '@/stores/swift-store';
import { ContextBar } from './context-bar';
import { OfflineBanner } from './offline-banner';
import { ChatPanel } from '../chat/chat-panel';
import { ArtifactArea } from '../artifacts/artifact-area';
export function CommandCenter() {
const { closeBlock, activeBlock, openBlock, pendingAction, setPendingAction } = useSwiftStore();
const inputRef = useRef<HTMLInputElement>(null);
// Global keyboard shortcuts
const handleKeyDown = useCallback(
(e: KeyboardEvent) => {
// Escape: close active block
if (e.key === 'Escape' && activeBlock) {
e.preventDefault();
closeBlock();
}
// Cmd/Ctrl + K: focus input (chat input in v3.0)
if ((e.metaKey || e.ctrlKey) && e.key === 'k') {
e.preventDefault();
inputRef.current?.focus();
}
},
[activeBlock, closeBlock]
);
useEffect(() => {
window.addEventListener('keydown', handleKeyDown);
return () => window.removeEventListener('keydown', handleKeyDown);
}, [handleKeyDown]);
// E3.S6: Handle pending actions from chat (artifact opening)
useEffect(() => {
if (!pendingAction) return;
console.log('[CommandCenter] Processing pending action:', pendingAction);
// Check if action has artifact data
if (pendingAction.artifact) {
const { type, prefill } = pendingAction.artifact;
console.log('[CommandCenter] Opening artifact:', type, 'with prefill:', prefill);
// Open the block with prefill data
openBlock(type, prefill);
// Clear pending action after processing
setPendingAction(null);
} else {
console.log('[CommandCenter] Action has no artifact, skipping');
setPendingAction(null);
}
}, [pendingAction, openBlock, setPendingAction]);
return (
<div className="flex flex-col h-screen overflow-hidden">
{/* Offline Banner */}
<OfflineBanner />
{/* Context Bar - 48px (unchanged) */}
<ContextBar />
{/* Split-screen container - flex-1 */}
<div className="flex-1 flex overflow-hidden">
{/* Chat Panel - 40% (desktop), 100% (mobile) */}
<div className="w-full lg:w-[40%] border-r border-slate-200 flex flex-col">
<ChatPanel />
</div>
{/* Artifact Area - 60% (desktop), hidden on mobile */}
<div className="hidden lg:flex lg:w-[60%] flex-col">
<ArtifactArea />
</div>
</div>
</div>
);
}