import React, { ReactNode, useState, useEffect } from 'react'; import { View, Modal, Pressable, Platform, ScrollView, Dimensions } from 'react-native'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; import { useTheme } from '~/features/theme/ThemeProvider'; import Text from '~/components/atoms/Text'; import Icon from '~/components/atoms/Icon'; import Button from '~/components/atoms/Button'; import colors from 'tailwindcss/colors'; interface BaseModalProps { isVisible: boolean; onClose: () => void; title: string; children: ReactNode; footerContent?: ReactNode; animationType?: 'slide' | 'fade' | 'none'; closeOnOverlayPress?: boolean; showCloseButton?: boolean; hideFooter?: boolean; overlayOpacity?: number; position?: 'center' | 'top'; scrollable?: boolean; noPadding?: boolean; primaryButtonText?: string; secondaryButtonText?: string; onPrimaryButtonPress?: () => void; onSecondaryButtonPress?: () => void; primaryButtonLoading?: boolean; secondaryButtonLoading?: boolean; primaryButtonDisabled?: boolean; secondaryButtonDisabled?: boolean; size?: 'small' | 'medium' | 'large' | 'full'; maxWidth?: number; } // Responsive breakpoints const BREAKPOINTS = { mobile: 768, tablet: 1024, desktop: 1440, } as const; // Max widths for different modal sizes const MODAL_MAX_WIDTHS = { small: { mobile: 400, tablet: 400, desktop: 400, }, medium: { mobile: 500, tablet: 600, desktop: 700, }, large: { mobile: 600, tablet: 700, desktop: 800, }, full: { mobile: '90%', tablet: '85%', desktop: '80%', }, } as const; /** * Base Modal component that provides a consistent layout and behavior for all modals in the app. * * Features: * - Standardized header with title and close button * - Flexible content area * - Optional footer with configurable buttons * - Theme-aware styling * - Customizable animation and behavior */ const BaseModal: React.FC = ({ isVisible, onClose, title, children, footerContent, animationType = 'none', closeOnOverlayPress = true, showCloseButton = true, hideFooter = false, overlayOpacity = 0.5, position = 'center', scrollable = true, primaryButtonText, secondaryButtonText, onPrimaryButtonPress, onSecondaryButtonPress, primaryButtonLoading = false, secondaryButtonLoading = false, primaryButtonDisabled = false, noPadding = false, secondaryButtonDisabled = false, size = 'medium', maxWidth, }) => { const { isDark, themeVariant } = useTheme(); const insets = useSafeAreaInsets(); const [windowWidth, setWindowWidth] = useState(() => Platform.OS === 'web' ? Dimensions.get('window').width : 0 ); // Update window width on resize useEffect(() => { if (Platform.OS !== 'web') return; const updateWindowWidth = () => { setWindowWidth(Dimensions.get('window').width); }; const subscription = Dimensions.addEventListener('change', updateWindowWidth); return () => subscription?.remove(); }, []); // Debug borders (set to true to enable) const DEBUG_BORDERS = false; // Holen der Theme-Farben basierend auf der aktuellen Variante const themeColors = (colors as any).theme?.extend?.colors as Record; // Hintergrundfarbe für das Modal basierend auf dem Theme (wie Header) const modalBgColor = isDark ? themeColors?.dark?.[themeVariant]?.menuBackground || '#252525' : themeColors?.[themeVariant]?.menuBackground || '#DDDDDD'; // Textfarbe basierend auf dem Theme const textColor = isDark ? themeColors?.dark?.[themeVariant]?.text || '#FFFFFF' : themeColors?.[themeVariant]?.text || '#000000'; // Primärfarbe für Akzente const primaryColor = isDark ? themeColors?.dark?.[themeVariant]?.primary || '#f8d62b' : themeColors?.[themeVariant]?.primary || '#f8d62b'; // Rahmenfarbe basierend auf dem Theme const borderColor = isDark ? themeColors?.dark?.[themeVariant]?.border || '#424242' : themeColors?.[themeVariant]?.border || '#e6e6e6'; // Standardmäßige Footer-Buttons, wenn keine benutzerdefinierten bereitgestellt werden const renderDefaultFooter = () => { if (!primaryButtonText && !secondaryButtonText) return null; return ( {secondaryButtonText && (