import React, { useState, useEffect } from 'react'; import { Transition } from '@headlessui/react'; import { FaTimes } from 'react-icons/fa'; // Define types export interface TooltipProps { children: React.ReactNode; text: string; position?: 'top' | 'bottom' | 'left' | 'right'; delay?: number; } export interface ModalProps { isOpen: boolean; onClose: () => void; title: string; children: React.ReactNode; size?: 'sm' | 'md' | 'lg' | 'xl'; } export interface ConfirmDialogProps { isOpen: boolean; onClose: () => void; onConfirm: () => void; title: string; message: string; confirmText?: string; cancelText?: string; variant?: 'danger' | 'warning' | 'info'; } export interface ToastProps { message: string; type: 'success' | 'error' | 'warning' | 'info'; onClose: () => void; autoClose?: boolean; duration?: number; } export interface ToastItem extends ToastProps { id: number; } export interface NetworkStatsProps { people: any[]; relationships: any[]; } // Enhanced Tooltip with animation and positioning export const Tooltip: React.FC = ({ children, text, position = 'top', delay = 300, }) => { const [show, setShow] = useState(false); const [timeoutId, setTimeoutId] = useState(null); const handleMouseEnter = () => { if (timeoutId) clearTimeout(timeoutId); const id = setTimeout(() => setShow(true), delay); setTimeoutId(id); }; const handleMouseLeave = () => { if (timeoutId) clearTimeout(timeoutId); const id = setTimeout(() => setShow(false), 100); setTimeoutId(id); }; useEffect(() => { return () => { if (timeoutId) clearTimeout(timeoutId); }; }, [timeoutId]); const positionClasses = { top: '-top-8 left-1/2 transform -translate-x-1/2', bottom: 'top-full mt-2 left-1/2 transform -translate-x-1/2', left: 'right-full mr-2 top-1/2 transform -translate-y-1/2', right: 'left-full ml-2 top-1/2 transform -translate-y-1/2', }; const arrowClasses = { top: 'absolute w-2 h-2 bg-gray-900 transform rotate-45 -bottom-1 left-1/2 -translate-x-1/2', bottom: 'absolute w-2 h-2 bg-gray-900 transform rotate-45 -top-1 left-1/2 -translate-x-1/2', left: 'absolute w-2 h-2 bg-gray-900 transform rotate-45 right-0 top-1/2 -translate-y-1/2 -mr-1', right: 'absolute w-2 h-2 bg-gray-900 transform rotate-45 left-0 top-1/2 -translate-y-1/2 -ml-1', }; return (
{children}
{text}
); }; // Enhanced Modal with animations and responsive design export const Modal: React.FC = ({ isOpen, onClose, title, children, size = 'md' }) => { const sizeClasses = { sm: 'max-w-md', md: 'max-w-lg', lg: 'max-w-2xl', xl: 'max-w-4xl', }; // Close on escape key useEffect(() => { const handleEsc = (event: KeyboardEvent) => { if (event.key === 'Escape') { onClose(); } }; if (isOpen) { document.addEventListener('keydown', handleEsc); } return () => { document.removeEventListener('keydown', handleEsc); }; }, [isOpen, onClose]); if (!isOpen) return null; return (
e.stopPropagation()} >
{children}
); }; // Enhanced Confirmation dialog export const ConfirmDialog: React.FC = ({ isOpen, onClose, onConfirm, title, message, confirmText = 'Confirm', cancelText = 'Cancel', variant = 'danger', }) => { const variantClasses = { danger: 'bg-red-600 hover:bg-red-700 focus:ring-red-500', warning: 'bg-amber-600 hover:bg-amber-700 focus:ring-amber-500', info: 'bg-blue-600 hover:bg-blue-700 focus:ring-blue-500', }; return (

{message}

); }; // Enhanced Network statistics card export const NetworkStats: React.FC = ({ people, relationships }) => { const [showDetails, setShowDetails] = useState(false); // Calculate statistics const avgConnections = people.length > 0 ? (relationships.length / people.length).toFixed(1) : '0.0'; const isolatedPeople = people.filter( person => !relationships.some(r => r.source === person._id || r.target === person._id) ).length; // Find most connected person const personConnectionCounts = people.map(person => ({ person, count: relationships.filter(r => r.source === person._id || r.target === person._id).length, })); const mostConnected = personConnectionCounts.length > 0 ? personConnectionCounts.reduce((prev, current) => prev.count > current.count ? prev : current ) : null; return (

Network Statistics

{people.length}
People
{relationships.length}
Relationships
{avgConnections}
Avg. Connections
{isolatedPeople}
Isolated People
{mostConnected && mostConnected.count > 0 && (
Most Connected
{mostConnected.person.firstName} {mostConnected.person.lastName}
{mostConnected.count} connections
)}
); }; // Enhanced Toast notification component export const Toast: React.FC = ({ message, type, onClose, autoClose = true, duration = 3000, }) => { useEffect(() => { if (autoClose) { const timer = setTimeout(() => { onClose(); }, duration); return () => clearTimeout(timer); } }, [onClose, autoClose, duration]); const typeStyles = { success: 'bg-green-600', error: 'bg-red-600', warning: 'bg-amber-600', info: 'bg-blue-600', }; const icon = { success: '✓', error: '✕', warning: '⚠', info: 'ℹ', }; return (
{icon[type]} {message}
); }; // Reusable Button component with variants export interface ButtonProps { children: React.ReactNode; onClick?: () => void; type?: 'button' | 'submit' | 'reset'; variant?: 'primary' | 'secondary' | 'danger' | 'success' | 'outline'; size?: 'sm' | 'md' | 'lg'; icon?: React.ReactNode; className?: string; disabled?: boolean; fullWidth?: boolean; } export const Button: React.FC = ({ children, onClick, type = 'button', variant = 'primary', size = 'md', icon, className = '', disabled = false, fullWidth = false, }) => { const variantClasses = { primary: 'bg-indigo-600 hover:bg-indigo-700 text-white focus:ring-indigo-500', secondary: 'bg-slate-700 hover:bg-slate-600 text-white focus:ring-slate-500', danger: 'bg-red-600 hover:bg-red-700 text-white focus:ring-red-500', success: 'bg-green-600 hover:bg-green-700 text-white focus:ring-green-500', outline: 'bg-transparent border border-slate-600 text-slate-300 hover:bg-slate-800 focus:ring-slate-400', }; const sizeClasses = { sm: 'px-2 py-1 text-xs', md: 'px-4 py-2 text-sm', lg: 'px-5 py-2.5 text-base', }; return ( ); }; // FormField component for consistent form styling export interface FormFieldProps { label: string; id: string; error?: string; required?: boolean; className?: string; children: React.ReactNode; labelClassName?: string; } export const FormField: React.FC = ({ label, id, error, required = false, className = '', children, labelClassName = '', }) => { return (
{children} {error &&

{error}

}
); }; // Badge component for tags, status indicators, etc. export interface BadgeProps { children: React.ReactNode; color?: 'blue' | 'green' | 'red' | 'yellow' | 'purple' | 'gray'; className?: string; } export const Badge: React.FC = ({ children, color = 'blue', className = '' }) => { const colorClasses = { blue: 'bg-blue-100 text-blue-800', green: 'bg-green-100 text-green-800', red: 'bg-red-100 text-red-800', yellow: 'bg-yellow-100 text-yellow-800', purple: 'bg-purple-100 text-purple-800', gray: 'bg-gray-100 text-gray-800', }; return ( {children} ); }; // Empty state component export interface EmptyStateProps { title: string; description: string; icon?: React.ReactNode; action?: React.ReactNode; } export const EmptyState: React.FC = ({ title, description, icon, action }) => { return (
{icon && (
{icon}
)}

{title}

{description}

{action}
); }; // Card component export interface CardProps { children: React.ReactNode; className?: string; } export const Card: React.FC = ({ children, className = '' }) => { return (
{children}
); }; export const CardHeader: React.FC = ({ children, className = '' }) => { return
{children}
; }; export const CardBody: React.FC = ({ children, className = '' }) => { return
{children}
; }; export const CardFooter: React.FC = ({ children, className = '' }) => { return
{children}
; };