Epic 5 deels compleet: Error handling en keyboard shortcuts geïmplementeerd. Voortgang: 62 SP / 72 SP (86%) - Nog 1 story voor MVP compleet! E5.S2 - Error Handling (2 SP) - Gecentraliseerde error handler utility (lib/swift/error-handler.ts) - isOffline(), isNetworkError(), getErrorInfo() functies - safeFetch() wrapper met 30s timeout en retry logic - retryFetch() met exponential backoff (max 3 retries) - User-friendly Nederlandse error messages voor alle HTTP status codes - OfflineBanner component met online/offline detection - Alle blocks en CommandInput gebruiken nieuwe error handler - Context bar margin adjustment voor offline banner - parseErrorResponse() voor HTML error detection E5.S3 - Keyboard Shortcuts (2 SP) - ⌘Enter / Ctrl+Enter quick submit in CommandInput - ⌘Enter / Ctrl+Enter quick save in DagnotatieBlock - Visual hints (⌘↵) op submit button in DagnotatieBlock - Geverifieerd: ⌘K focus, Escape close, 1-3 FallbackPicker - Cross-platform support (macOS + Windows/Linux) - preventDefault() voor browser conflict preventie Components Updated: - DagnotatieBlock: safeFetch, getErrorInfo, retryFetch, ⌘Enter save - OverdrachtBlock: safeFetch, retryFetch voor AI generation - ZoekenBlock: safeFetch, getErrorInfo voor patient search - CommandInput: safeFetch, getErrorInfo, ⌘Enter submit - CommandCenter: OfflineBanner integration - ContextBar: useOffline hook voor margin adjustment Nieuwe Files: - lib/swift/error-handler.ts (301 regels) - Error handling utilities - components/swift/command-center/offline-banner.tsx (72 regels) - docs/swift/keyboard-shortcuts-reference.md (200+ regels) - docs/swift/test-plan-e5-s2-error-handling.md (350+ regels) - docs/swift/test-plan-e5-s3-keyboard-shortcuts.md (350+ regels) - docs/swift/PROJECT-STATUS-2024-12-27.md (500+ regels) - Status report Documentatie: - Bouwplan bijgewerkt naar v2.5 - Epic completion details toegevoegd met progress bars - Manual test checklist bijgewerkt (17/20 scenarios) - Risico's sectie bijgewerkt (alle major risks gemitigeerd) - Sprint planning status: E5 75% compleet (6/8 SP) Technische verbeteringen: - Offline detection met visual feedback - Network error retry met exponential backoff - HTTP 401/404/500/503 error messages in Nederlands - Timeout protection (30s) op alle API calls - Keyboard shortcuts met visual hints - Cross-platform shortcut support Testing: - Error handling test plan met 8 categorieën - Keyboard shortcuts test plan met 6 categorieën - 40+ test scenarios gedocumenteerd - Quick smoke test checklists Voortgang: 62 SP / 72 SP (86%) - E5.S2 en E5.S3 compleet 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
86 lines
3.1 KiB
TypeScript
86 lines
3.1 KiB
TypeScript
'use client';
|
|
|
|
/**
|
|
* Context Bar
|
|
*
|
|
* Top bar showing current context: shift, selected patient, user info.
|
|
* Height: 48px (h-12)
|
|
*/
|
|
|
|
import { useSwiftStore, type ShiftType } from '@/stores/swift-store';
|
|
import { Sun, Moon, Sunrise, Sunset, X, User, ArrowLeft } from 'lucide-react';
|
|
import Link from 'next/link';
|
|
import { useOffline } from './offline-banner';
|
|
|
|
const SHIFT_CONFIG: Record<ShiftType, { icon: typeof Sun; label: string; color: string }> = {
|
|
nacht: { icon: Moon, label: 'Nachtdienst', color: 'text-indigo-600' },
|
|
ochtend: { icon: Sunrise, label: 'Ochtenddienst', color: 'text-amber-600' },
|
|
middag: { icon: Sun, label: 'Middagdienst', color: 'text-yellow-600' },
|
|
avond: { icon: Sunset, label: 'Avonddienst', color: 'text-orange-600' },
|
|
};
|
|
|
|
export function ContextBar() {
|
|
const { shift, activePatient, setActivePatient } = useSwiftStore();
|
|
const isOffline = useOffline();
|
|
const shiftConfig = SHIFT_CONFIG[shift];
|
|
const ShiftIcon = shiftConfig.icon;
|
|
|
|
return (
|
|
<header
|
|
className="h-12 border-b border-slate-200 flex items-center px-4 justify-between shrink-0 bg-white"
|
|
style={isOffline ? { marginTop: '40px' } : undefined}
|
|
>
|
|
{/* Left: Logo + Shift */}
|
|
<div className="flex items-center gap-4">
|
|
<Link
|
|
href="/epd"
|
|
className="flex items-center gap-2 text-slate-600 hover:text-slate-900 transition-colors"
|
|
title="Terug naar EPD"
|
|
>
|
|
<ArrowLeft size={16} />
|
|
<span className="text-sm font-semibold tracking-tight">Swift</span>
|
|
</Link>
|
|
|
|
<div className="h-4 w-px bg-slate-200" />
|
|
|
|
<div className={`flex items-center gap-1.5 ${shiftConfig.color}`}>
|
|
<ShiftIcon size={14} />
|
|
<span className="text-xs font-medium">{shiftConfig.label}</span>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Center: Active Patient */}
|
|
<div className="flex items-center">
|
|
{activePatient ? (
|
|
<div className="flex items-center gap-2 px-3 py-1 rounded-full bg-slate-100 border border-slate-300">
|
|
<div className="w-5 h-5 rounded-full bg-blue-600 flex items-center justify-center text-[10px] font-medium text-white">
|
|
{activePatient.name_given[0]?.[0]}
|
|
{activePatient.name_family[0]}
|
|
</div>
|
|
<span className="text-sm text-slate-900">
|
|
{activePatient.name_given.join(' ')} {activePatient.name_family}
|
|
</span>
|
|
<button
|
|
onClick={() => setActivePatient(null)}
|
|
className="p-0.5 rounded hover:bg-slate-200 text-slate-400 hover:text-slate-700 transition-colors"
|
|
title="Patiënt deselecteren"
|
|
>
|
|
<X size={14} />
|
|
</button>
|
|
</div>
|
|
) : (
|
|
<span className="text-sm text-slate-500">Geen patiënt geselecteerd</span>
|
|
)}
|
|
</div>
|
|
|
|
{/* Right: User */}
|
|
<div className="flex items-center gap-3">
|
|
<div className="flex items-center gap-2 text-slate-600">
|
|
<User size={16} />
|
|
<span className="text-xs hidden sm:block">Verpleegkundige</span>
|
|
</div>
|
|
</div>
|
|
</header>
|
|
);
|
|
}
|