NeoScan_Radiologist/app/shared/components/CustomModal.tsx
2025-08-05 18:01:36 +05:30

348 lines
9.0 KiB
TypeScript

/*
* File: CustomModal.tsx
* Description: Custom modal component with matching UI design
* Design & Developed by Tech4Biz Solutions
* Copyright (c) Spurrin Innovations. All rights reserved.
*/
import React from 'react';
import {
View,
Text,
StyleSheet,
TouchableOpacity,
Modal,
TouchableWithoutFeedback,
Dimensions,
} from 'react-native';
import { theme } from '../../theme/theme';
import Icon from 'react-native-vector-icons/Feather';
// ============================================================================
// INTERFACES
// ============================================================================
/**
* CustomModalProps Interface
*
* Purpose: Defines the props required by the CustomModal component
*
* Props:
* - visible: Whether the modal is visible
* - title: Modal title
* - message: Modal message/content
* - type: Modal type (success, error, warning, info, confirm)
* - onConfirm: Callback for confirm action
* - onCancel: Callback for cancel action
* - confirmText: Text for confirm button
* - cancelText: Text for cancel button
* - onClose: Callback for closing modal
* - showCancel: Whether to show cancel button
* - icon: Custom icon name
*/
interface CustomModalProps {
visible: boolean;
title: string;
message: string;
type?: 'success' | 'error' | 'warning' | 'info' | 'confirm';
onConfirm?: () => void;
onCancel?: () => void;
confirmText?: string;
cancelText?: string;
onClose?: () => void;
showCancel?: boolean;
icon?: string;
}
// ============================================================================
// CUSTOM MODAL COMPONENT
// ============================================================================
/**
* CustomModal Component
*
* Purpose: Displays a custom modal with consistent UI design
*
* Features:
* - Multiple modal types (success, error, warning, info, confirm)
* - Customizable buttons and text
* - Consistent theme styling
* - Backdrop tap to close
* - Icon support
* - Responsive design
*/
export const CustomModal: React.FC<CustomModalProps> = ({
visible,
title,
message,
type = 'info',
onConfirm,
onCancel,
confirmText = 'OK',
cancelText = 'Cancel',
onClose,
showCancel = false,
icon,
}) => {
// ============================================================================
// MODAL CONFIGURATION
// ============================================================================
/**
* Get modal configuration based on type
*/
const getModalConfig = () => {
switch (type) {
case 'success':
return {
icon: icon || 'check-circle',
iconColor: theme.colors.success,
backgroundColor: theme.colors.background,
borderColor: theme.colors.success,
};
case 'error':
return {
icon: icon || 'alert-circle',
iconColor: theme.colors.error,
backgroundColor: theme.colors.background,
borderColor: theme.colors.error,
};
case 'warning':
return {
icon: icon || 'alert-triangle',
iconColor: theme.colors.warning,
backgroundColor: theme.colors.background,
borderColor: theme.colors.warning,
};
case 'confirm':
return {
icon: icon || 'help-circle',
iconColor: theme.colors.primary,
backgroundColor: theme.colors.background,
borderColor: theme.colors.primary,
};
default:
return {
icon: icon || 'info',
iconColor: theme.colors.info,
backgroundColor: theme.colors.background,
borderColor: theme.colors.info,
};
}
};
const config = getModalConfig();
// ============================================================================
// EVENT HANDLERS
// ============================================================================
/**
* Handle confirm action
*/
const handleConfirm = () => {
if (onConfirm) {
onConfirm();
}
if (onClose) {
onClose();
}
};
/**
* Handle cancel action
*/
const handleCancel = () => {
if (onCancel) {
onCancel();
}
if (onClose) {
onClose();
}
};
/**
* Handle backdrop press
*/
const handleBackdropPress = () => {
if (onClose) {
onClose();
}
};
// ============================================================================
// RENDER
// ============================================================================
return (
<Modal
visible={visible}
transparent
animationType="fade"
onRequestClose={onClose}
>
<TouchableWithoutFeedback onPress={handleBackdropPress}>
<View style={styles.backdrop}>
<TouchableWithoutFeedback>
<View style={[
styles.modalContainer,
{
backgroundColor: config.backgroundColor,
borderColor: config.borderColor,
}
]}>
{/* Icon */}
<View style={[styles.iconContainer, { backgroundColor: config.iconColor + '20' }]}>
<Icon name={config.icon} size={32} color={config.iconColor} />
</View>
{/* Title */}
<Text style={styles.title}>{title}</Text>
{/* Message */}
<Text style={styles.message}>{message}</Text>
{/* Buttons */}
<View style={styles.buttonContainer}>
{showCancel && (
<TouchableOpacity
style={[styles.button, styles.cancelButton]}
onPress={handleCancel}
activeOpacity={0.7}
>
<Text style={styles.cancelButtonText}>{cancelText}</Text>
</TouchableOpacity>
)}
<TouchableOpacity
style={[
styles.button,
styles.confirmButton,
{ backgroundColor: config.iconColor },
showCancel && styles.confirmButtonWithCancel,
]}
onPress={handleConfirm}
activeOpacity={0.7}
>
<Text style={styles.confirmButtonText}>{confirmText}</Text>
</TouchableOpacity>
</View>
</View>
</TouchableWithoutFeedback>
</View>
</TouchableWithoutFeedback>
</Modal>
);
};
// ============================================================================
// STYLES
// ============================================================================
const { width: screenWidth } = Dimensions.get('window');
const styles = StyleSheet.create({
// Backdrop
backdrop: {
flex: 1,
backgroundColor: 'rgba(0, 0, 0, 0.5)',
justifyContent: 'center',
alignItems: 'center',
paddingHorizontal: theme.spacing.lg,
},
// Modal container
modalContainer: {
width: screenWidth - theme.spacing.lg * 2,
backgroundColor: theme.colors.background,
borderRadius: theme.borderRadius.large,
padding: theme.spacing.xl,
alignItems: 'center',
borderWidth: 2,
...theme.shadows.large,
},
// Icon container
iconContainer: {
width: 80,
height: 80,
borderRadius: 40,
justifyContent: 'center',
alignItems: 'center',
marginBottom: theme.spacing.lg,
},
// Title
title: {
fontSize: theme.typography.fontSize.displaySmall,
fontFamily: theme.typography.fontFamily.bold,
color: theme.colors.textPrimary,
textAlign: 'center',
marginBottom: theme.spacing.md,
},
// Message
message: {
fontSize: theme.typography.fontSize.bodyLarge,
fontFamily: theme.typography.fontFamily.regular,
color: theme.colors.textSecondary,
textAlign: 'center',
lineHeight: theme.typography.fontSize.bodyLarge * 1.4,
marginBottom: theme.spacing.xl,
},
// Button container
buttonContainer: {
flexDirection: 'row',
width: '100%',
gap: theme.spacing.md,
},
// Button base
button: {
flex: 1,
paddingVertical: theme.spacing.md,
paddingHorizontal: theme.spacing.lg,
borderRadius: theme.borderRadius.medium,
alignItems: 'center',
justifyContent: 'center',
...theme.shadows.primary,
},
// Cancel button
cancelButton: {
backgroundColor: theme.colors.backgroundAlt,
borderWidth: 1,
borderColor: theme.colors.border,
},
// Cancel button text
cancelButtonText: {
fontSize: theme.typography.fontSize.bodyLarge,
fontFamily: theme.typography.fontFamily.medium,
color: theme.colors.textSecondary,
},
// Confirm button
confirmButton: {
backgroundColor: theme.colors.primary,
},
// Confirm button with cancel
confirmButtonWithCancel: {
flex: 1,
},
// Confirm button text
confirmButtonText: {
fontSize: theme.typography.fontSize.bodyLarge,
fontFamily: theme.typography.fontFamily.bold,
color: theme.colors.background,
},
});
/*
* End of File: CustomModal.tsx
* Design & Developed by Tech4Biz Solutions
* Copyright (c) Spurrin Innovations. All rights reserved.
*/