Files
triqura-ecd/components/swift/blocks/block-container.tsx
ikbenlit 2a67a0a2d9 git commit -m "feat(swift): implement Epic 3 - P1 Blocks (E3.S0-S6)" -m "Epic 3 compleet: Alle P1 blocks geïmplementeerd met volledige functionaliteit." -m "E3.S0 - CanvasArea block rendering" -m "- Switch/case voor block types met prefill data" -m "- AnimatePresence voor smooth transitions" -m "- PatientContextCard auto-display wanneer activePatient is gezet" -m "" -m "E3.S1 - Block Container animaties" -m "- Framer Motion animaties voor container, content en close button" -m "- Stagger effecten voor content children" -m "- Hover/tap animaties voor close button" -m "" -m "E3.S2 - DagnotatieBlock" -m "- Patient search met debounced FHIR API integratie" -m "- Category selector (medicatie, adl, gedrag, incident, observatie)" -m "- Textarea met character counter (max 500)" -m "- Opslaan naar /api/reports met validatie en error handling" -m "" -m "E3.S3 - Patient search API" -m "- GET /api/patients/search?q= met fuzzy search" -m "- Match score berekening voor resultaten" -m "- Auth check en error handling" -m "" -m "E3.S4 - ZoekenBlock" -m "- Debounced patient search met dropdown" -m "- Patient selectie → setActivePatient in store" -m "- Auto-close na selectie + recent action" -m "" -m "E3.S5 - PatientContextCard" -m "- Auto-open na patient selectie" -m "- Notities, vitals, diagnoses en risico's secties" -m "- API integratie met /api/overdracht/[patientId]" -m "" -m "E3.S6 - OverdrachtBlock" -m "- Lijst van patiënten met activiteit" -m "- Period selector (1d, 3d, 7d, 14d)" -m "- AI samenvatting generatie per patiënt" -m "- Aandachtspunten en actiepunten weergave" -m "" -m "Technische verbeteringen:" -m "- Technische debt opgelost: BlockContainer animaties, CanvasArea rendering" -m "- PatientContextCard toegevoegd aan blocks" -m "- Alle blocks gebruiken BlockContainer voor consistente styling" -m "" -m "Voortgang: 56 SP / 72 SP (78%) - Epic 3 compleet"
2025-12-24 09:06:39 +01:00

108 lines
2.6 KiB
TypeScript

'use client';
/**
* Block Container
*
* Wrapper for ephemeral blocks with animation, close button, and sizing.
*/
import { ReactNode } from 'react';
import { motion, type Variants } from 'framer-motion';
import { X } from 'lucide-react';
import { useSwiftStore } from '@/stores/swift-store';
import type { BlockSize } from '@/lib/swift/types';
interface BlockContainerProps {
title: string;
size?: BlockSize;
children: ReactNode;
}
const SIZE_CLASSES: Record<BlockSize, string> = {
sm: 'max-w-sm',
md: 'max-w-md',
lg: 'max-w-2xl',
full: 'max-w-4xl',
};
// Container animations
const containerVariants: Variants = {
initial: { scale: 0.98, opacity: 0 },
animate: {
scale: 1,
opacity: 1,
transition: {
duration: 0.2,
ease: [0.4, 0, 0.2, 1] as [number, number, number, number],
},
},
};
// Content stagger animation
const contentVariants: Variants = {
initial: { opacity: 0, y: 10 },
animate: {
opacity: 1,
y: 0,
transition: {
delay: 0.1,
duration: 0.2,
ease: [0.4, 0, 0.2, 1] as [number, number, number, number],
},
},
};
// Close button hover animation
const closeButtonVariants = {
rest: { scale: 1, rotate: 0 },
hover: { scale: 1.1, rotate: 90 },
tap: { scale: 0.95 },
};
export function BlockContainer({ title, size = 'md', children }: BlockContainerProps) {
const { closeBlock } = useSwiftStore();
return (
<motion.div
variants={containerVariants}
initial="initial"
animate="animate"
className={`w-full ${SIZE_CLASSES[size]} bg-slate-800 rounded-xl border border-slate-700 shadow-2xl`}
>
{/* Header */}
<div className="flex items-center justify-between px-4 py-3 border-b border-slate-700">
<motion.h2
initial={{ opacity: 0, x: -10 }}
animate={{ opacity: 1, x: 0 }}
transition={{ delay: 0.05, duration: 0.2 }}
className="text-lg font-medium text-white"
>
{title}
</motion.h2>
<motion.button
onClick={closeBlock}
variants={closeButtonVariants}
initial="rest"
whileHover="hover"
whileTap="tap"
className="p-1 rounded hover:bg-slate-700 text-slate-400 hover:text-white transition-colors"
title="Sluiten (Esc)"
aria-label="Block sluiten"
>
<X size={20} />
</motion.button>
</div>
{/* Content */}
<motion.div
variants={contentVariants}
initial="initial"
animate="animate"
className="p-4"
>
{children}
</motion.div>
</motion.div>
);
}