288 lines
8.0 KiB
TypeScript
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.
|
|
*/
|