NeoScan_Radiologist/app/modules/AIPrediction/components/EmptyState.tsx

288 lines
8.0 KiB
TypeScript

/*
* File: EmptyState.tsx
* Description: Empty state component for AI predictions
* Design & Developed by Tech4Biz Solutions
* Copyright (c) Spurrin Innovations. All rights reserved.
*/
import React from 'react';
import {
View,
Text,
StyleSheet,
TouchableOpacity,
Dimensions,
} from 'react-native';
import Icon from 'react-native-vector-icons/Feather';
import { theme } from '../../../theme';
// ============================================================================
// INTERFACES
// ============================================================================
interface EmptyStateProps {
title?: string;
message?: string;
iconName?: string;
actionText?: string;
onAction?: () => void;
style?: any;
showRefreshButton?: boolean;
onRefresh?: () => void;
}
// ============================================================================
// CONSTANTS
// ============================================================================
const { width, height } = Dimensions.get('window');
// ============================================================================
// EMPTY STATE COMPONENT
// ============================================================================
/**
* EmptyState Component
*
* Purpose: Display empty state for AI predictions
*
* Features:
* - Customizable title and message
* - Icon display with customizable icon
* - Optional action button
* - Refresh functionality
* - Responsive design
* - Modern empty state design
* - Accessibility support
*/
const EmptyState: React.FC<EmptyStateProps> = ({
title = 'No AI Predictions Found',
message = 'There are no AI prediction cases available at the moment. Try adjusting your filters or refresh to see new predictions.',
iconName = 'brain',
actionText = 'Refresh',
onAction,
style,
showRefreshButton = true,
onRefresh,
}) => {
// ============================================================================
// EVENT HANDLERS
// ============================================================================
/**
* Handle Action Press
*
* Purpose: Handle action button press
*/
const handleActionPress = () => {
if (onAction) {
onAction();
} else if (onRefresh) {
onRefresh();
}
};
// ============================================================================
// RENDER
// ============================================================================
return (
<View style={[styles.container, style]}>
{/* Empty State Icon */}
<View style={styles.iconContainer}>
<Icon
name={iconName}
size={64}
color={theme.colors.textMuted}
style={styles.icon}
/>
</View>
{/* Empty State Title */}
<Text style={styles.title} accessibilityRole="header">
{title}
</Text>
{/* Empty State Message */}
<Text style={styles.message}>
{message}
</Text>
{/* Action Buttons */}
<View style={styles.buttonsContainer}>
{/* Primary Action Button */}
{(onAction || onRefresh) && (
<TouchableOpacity
style={styles.actionButton}
onPress={handleActionPress}
accessibilityRole="button"
accessibilityLabel={actionText}
>
<Icon
name="refresh-cw"
size={18}
color={theme.colors.background}
style={styles.buttonIcon}
/>
<Text style={styles.actionButtonText}>
{actionText}
</Text>
</TouchableOpacity>
)}
{/* Secondary Refresh Button */}
{showRefreshButton && onRefresh && !onAction && (
<TouchableOpacity
style={styles.secondaryButton}
onPress={onRefresh}
accessibilityRole="button"
accessibilityLabel="Refresh data"
>
<Icon
name="refresh-cw"
size={16}
color={theme.colors.primary}
style={styles.buttonIcon}
/>
<Text style={styles.secondaryButtonText}>
Refresh Data
</Text>
</TouchableOpacity>
)}
</View>
{/* Suggestions */}
<View style={styles.suggestionsContainer}>
<Text style={styles.suggestionsTitle}>Try:</Text>
<View style={styles.suggestionsList}>
<View style={styles.suggestionItem}>
<Icon name="search" size={14} color={theme.colors.textMuted} />
<Text style={styles.suggestionText}>Clearing search filters</Text>
</View>
<View style={styles.suggestionItem}>
<Icon name="filter" size={14} color={theme.colors.textMuted} />
<Text style={styles.suggestionText}>Adjusting filter criteria</Text>
</View>
<View style={styles.suggestionItem}>
<Icon name="refresh-cw" size={14} color={theme.colors.textMuted} />
<Text style={styles.suggestionText}>Refreshing the data</Text>
</View>
</View>
</View>
</View>
);
};
// ============================================================================
// STYLES
// ============================================================================
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
paddingHorizontal: theme.spacing.xl,
paddingVertical: theme.spacing.xxl,
minHeight: height * 0.4,
},
iconContainer: {
width: 120,
height: 120,
borderRadius: 60,
backgroundColor: theme.colors.backgroundAlt,
justifyContent: 'center',
alignItems: 'center',
marginBottom: theme.spacing.xl,
...theme.shadows.small,
},
icon: {
opacity: 0.6,
},
title: {
fontSize: theme.typography.fontSize.displaySmall,
fontWeight: theme.typography.fontWeight.bold,
color: theme.colors.textPrimary,
textAlign: 'center',
marginBottom: theme.spacing.md,
},
message: {
fontSize: theme.typography.fontSize.bodyLarge,
color: theme.colors.textSecondary,
textAlign: 'center',
lineHeight: theme.typography.lineHeight.relaxed * theme.typography.fontSize.bodyLarge,
marginBottom: theme.spacing.xl,
maxWidth: width * 0.8,
},
buttonsContainer: {
flexDirection: 'row',
gap: theme.spacing.md,
marginBottom: theme.spacing.xl,
},
actionButton: {
flexDirection: 'row',
alignItems: 'center',
backgroundColor: theme.colors.primary,
paddingHorizontal: theme.spacing.lg,
paddingVertical: theme.spacing.md,
borderRadius: theme.borderRadius.medium,
gap: theme.spacing.sm,
...theme.shadows.medium,
},
actionButtonText: {
fontSize: theme.typography.fontSize.bodyMedium,
fontWeight: theme.typography.fontWeight.medium,
color: theme.colors.background,
},
secondaryButton: {
flexDirection: 'row',
alignItems: 'center',
backgroundColor: 'transparent',
borderWidth: 1,
borderColor: theme.colors.primary,
paddingHorizontal: theme.spacing.lg,
paddingVertical: theme.spacing.md,
borderRadius: theme.borderRadius.medium,
gap: theme.spacing.sm,
},
secondaryButtonText: {
fontSize: theme.typography.fontSize.bodyMedium,
fontWeight: theme.typography.fontWeight.medium,
color: theme.colors.primary,
},
buttonIcon: {
// No additional styles needed
},
suggestionsContainer: {
alignItems: 'center',
maxWidth: width * 0.8,
},
suggestionsTitle: {
fontSize: theme.typography.fontSize.bodyMedium,
fontWeight: theme.typography.fontWeight.medium,
color: theme.colors.textSecondary,
marginBottom: theme.spacing.sm,
},
suggestionsList: {
gap: theme.spacing.sm,
},
suggestionItem: {
flexDirection: 'row',
alignItems: 'center',
gap: theme.spacing.sm,
paddingVertical: theme.spacing.xs,
},
suggestionText: {
fontSize: theme.typography.fontSize.bodyMedium,
color: theme.colors.textMuted,
},
});
export default EmptyState;
/*
* End of File: EmptyState.tsx
* Design & Developed by Tech4Biz Solutions
* Copyright (c) Spurrin Innovations. All rights reserved.
*/