/* * File: BrainPredictionsOverview.tsx * Description: Component to display patient overview statistics based on different AI prediction scenarios for brain conditions * Design & Developed by Tech4Biz Solutions * Copyright (c) Spurrin Innovations. All rights reserved. */ import React from 'react'; import { View, Text, StyleSheet, Dimensions, ScrollView, } from 'react-native'; import { PieChart } from 'react-native-chart-kit'; import { theme } from '../../../theme/theme'; import { ERDashboard } from '../../../shared/types'; /** * BrainPredictionsOverviewProps Interface * * Purpose: Defines the props required by the BrainPredictionsOverview component * * Props: * - dashboard: ERDashboard object containing brain prediction statistics */ interface BrainPredictionsOverviewProps { dashboard: ERDashboard; } /** * BrainPredictionsOverview Component * * Purpose: Display patient overview statistics based on different AI prediction scenarios * * Features: * 1. Shows distribution of patients by brain condition predictions * 2. Displays AI confidence levels for each prediction type * 3. Shows critical vs non-critical brain conditions * 4. Provides summary statistics for quick overview * 5. Visualizes data using react-native-chart-kit pie chart * * Prediction Categories: * - Hemorrhagic Conditions (IPH, IVH, SAH, SDH, EDH) * - Ischemic Conditions (Stroke) * - Structural Changes (Mass effect, Midline shift) * - Normal Findings */ export const BrainPredictionsOverview: React.FC = ({ dashboard, }) => { // ============================================================================ // MOCK PREDICTION DATA // ============================================================================ /** * Mock prediction statistics based on brain conditions * In a real app, this would come from the AI analysis API */ const predictionStats = { // Hemorrhagic Conditions intraparenchymal: { count: 2, confidence: 94, critical: true }, intraventricular: { count: 1, confidence: 87, critical: true }, subarachnoid: { count: 1, confidence: 87, critical: true }, subdural: { count: 1, confidence: 89, critical: true }, epidural: { count: 1, confidence: 96, critical: true }, // Ischemic Conditions ischemic_stroke: { count: 1, confidence: 92, critical: true }, // Structural Changes mass_effect: { count: 2, confidence: 91, critical: true }, midline_shift: { count: 1, confidence: 96, critical: true }, // Normal Findings normal_brain: { count: 3, confidence: 98, critical: false }, // Pending Analysis pending_analysis: { count: 6, confidence: 0, critical: false }, }; // ============================================================================ // HELPER FUNCTIONS // ============================================================================ /** * getPredictionLabel Function * * Purpose: Get human-readable label for prediction type * * @param predictionType - Type of brain prediction * @returns Human-readable label */ const getPredictionLabel = (predictionType: string) => { if (!predictionType) { return 'Unknown'; // Default label for undefined types } const labels: { [key: string]: string } = { intraparenchymal: 'IPH', intraventricular: 'IVH', subarachnoid: 'SAH', subdural: 'SDH', epidural: 'EDH', ischemic_stroke: 'Stroke', mass_effect: 'Mass Effect', midline_shift: 'Midline Shift', normal_brain: 'Normal', pending_analysis: 'Pending', }; return labels[predictionType] || predictionType; }; /** * getPredictionColor Function * * Purpose: Get color based on prediction type and criticality * * @param predictionType - Type of brain prediction * @param isCritical - Whether the condition is critical * @returns Color string for styling */ const getPredictionColor = (predictionType: string, isCritical: boolean) => { if (!predictionType) { return theme.colors.textSecondary; // Default color for undefined types } // Define distinct colors for each prediction class const predictionColors: { [key: string]: string } = { intraparenchymal: '#E53E3E', // Red for IPH intraventricular: '#C53030', // Dark Red for IVH subarachnoid: '#F56565', // Light Red for SAH subdural: '#FC8181', // Pink Red for SDH epidural: '#E53E3E', // Red for EDH ischemic_stroke: '#3182CE', // Blue for Stroke mass_effect: '#805AD5', // Purple for Mass Effect midline_shift: '#553C9A', // Dark Purple for Midline Shift normal_brain: '#38A169', // Green for Normal pending_analysis: '#D69E2E', // Yellow for Pending }; return predictionColors[predictionType] || theme.colors.textSecondary; }; // ============================================================================ // COMPUTED VALUES // ============================================================================ /** * Calculate total patients */ const totalPatients = Object.values(predictionStats).reduce((sum, stats) => sum + stats.count, 0); /** * Calculate total critical conditions */ const totalCritical = Object.values(predictionStats) .filter(stats => stats.critical) .reduce((sum, stats) => sum + stats.count, 0); /** * Calculate total normal findings */ const totalNormal = predictionStats.normal_brain.count; /** * Calculate total pending analysis */ const totalPending = predictionStats.pending_analysis.count; /** * Calculate average confidence for critical conditions */ const criticalConditions = Object.values(predictionStats).filter(stats => stats.critical && stats.confidence > 0); const averageConfidence = criticalConditions.length > 0 ? Math.round(criticalConditions.reduce((sum, stats) => sum + stats.confidence, 0) / criticalConditions.length) : 0; /** * Get all prediction classes by count */ const allPredictions = Object.entries(predictionStats) .filter(([_, stats]) => stats.count > 0) .sort((a, b) => b[1].count - a[1].count); // ============================================================================ // CHART DATA PREPARATION // ============================================================================ /** * Prepare chart data for react-native-chart-kit PieChart */ const chartData = Object.entries(predictionStats) .filter(([_, stats]) => stats && stats.count > 0) // Filter out undefined or zero count entries .map(([predictionType, stats]) => ({ name: getPredictionLabel(predictionType), population: stats.count, // react-native-chart-kit uses 'population' property color: getPredictionColor(predictionType, stats.critical), legendFontColor: theme.colors.textPrimary, legendFontSize: 12, confidence: stats.confidence, isCritical: stats.critical, })) .filter(item => item.population > 0) // Additional filter to ensure no zero count items .sort((a, b) => b.population - a.population); // Sort by count descending - removed limit to show all classes /** * Chart configuration for react-native-chart-kit */ const chartConfig = { backgroundColor: theme.colors.background, backgroundGradientFrom: theme.colors.background, backgroundGradientTo: theme.colors.background, decimalPlaces: 0, color: (opacity = 1) => `rgba(33, 150, 243, ${opacity})`, labelColor: (opacity = 1) => `rgba(33, 33, 33, ${opacity})`, style: { borderRadius: 16, }, propsForDots: { r: '6', strokeWidth: '2', stroke: theme.colors.primary, }, useShadowColorFromDataset: false, }; // ============================================================================ // RENDER FUNCTIONS // ============================================================================ /** * renderLegend Function * * Purpose: Render chart legend with confidence levels in grid layout * * @returns Legend component */ const renderLegend = () => ( Prediction Classes Breakdown {chartData.map((item, index) => ( {item.name} {item.population} patients {item.confidence > 0 && ( {item.confidence}% )} ))} ); // ============================================================================ // MAIN RENDER // ============================================================================ return ( {/* Section Header */} Brain AI Predictions Overview Patient distribution by AI-detected conditions {/* Pie Chart Section */} {chartData.length > 0 ? ( {(() => { try { return ( ); } catch (error) { console.warn('PieChart error:', error); return ( Chart temporarily unavailable ); } })()} {renderLegend()} ) : ( No data available for chart )} {/* Summary Statistics */} Total Patients {totalPatients} Critical Cases {totalCritical} Pending Analysis {totalPending} Avg Confidence {averageConfidence}% ); }; // ============================================================================ // STYLES SECTION // ============================================================================ const styles = StyleSheet.create({ // Main container container: { backgroundColor: theme.colors.background, borderRadius: theme.borderRadius.large, padding: theme.spacing.md, marginVertical: theme.spacing.sm, borderWidth: 1, borderColor: theme.colors.border, }, // Header section header: { marginBottom: theme.spacing.lg, }, // Main title title: { fontSize: theme.typography.fontSize.displaySmall, fontFamily: theme.typography.fontFamily.bold, color: theme.colors.textPrimary, marginBottom: theme.spacing.xs, }, // Subtitle subtitle: { fontSize: theme.typography.fontSize.bodyMedium, fontFamily: theme.typography.fontFamily.regular, color: theme.colors.textSecondary, }, // Statistics grid statsGrid: { flexDirection: 'row', flexWrap: 'wrap', gap: theme.spacing.xs, marginBottom: theme.spacing.lg, }, // Individual stat card statCard: { flex: 1, minWidth: '30%', maxWidth: '32%', backgroundColor: theme.colors.background, borderRadius: theme.borderRadius.medium, padding: theme.spacing.sm, borderWidth: 1, borderColor: theme.colors.border, borderLeftWidth: 3, alignItems: 'center', }, // Stat value statValue: { fontSize: theme.typography.fontSize.displaySmall, fontFamily: theme.typography.fontFamily.bold, color: theme.colors.textPrimary, marginBottom: theme.spacing.xs, }, // Stat title statTitle: { fontSize: theme.typography.fontSize.bodySmall, fontFamily: theme.typography.fontFamily.semibold, color: theme.colors.textPrimary, textAlign: 'center', marginBottom: theme.spacing.xs, }, // Stat subtitle statSubtitle: { fontSize: theme.typography.fontSize.caption, fontFamily: theme.typography.fontFamily.regular, color: theme.colors.textSecondary, textAlign: 'center', }, // Chart section chartSection: { marginBottom: theme.spacing.lg, }, // Chart title chartTitle: { fontSize: theme.typography.fontSize.bodyLarge, fontFamily: theme.typography.fontFamily.semibold, color: theme.colors.textPrimary, marginBottom: theme.spacing.xs, }, // Chart subtitle chartSubtitle: { fontSize: theme.typography.fontSize.bodySmall, fontFamily: theme.typography.fontFamily.regular, color: theme.colors.textSecondary, marginBottom: theme.spacing.md, }, // Chart scroll view chartScrollView: { // Removed maxHeight to allow full content to be visible }, // Chart content chartContent: { alignItems: 'center', paddingHorizontal: theme.spacing.sm, }, // Pie chart container pieChartContainer: { alignItems: 'center', marginBottom: theme.spacing.lg, backgroundColor: theme.colors.background, borderRadius: theme.borderRadius.medium, padding: theme.spacing.md, }, // Legend container legendContainer: { width: '100%', paddingHorizontal: theme.spacing.sm, backgroundColor: theme.colors.backgroundAlt, borderRadius: theme.borderRadius.medium, padding: theme.spacing.md, marginTop: theme.spacing.md, }, // Legend title legendTitle: { fontSize: theme.typography.fontSize.bodyLarge, fontFamily: theme.typography.fontFamily.semibold, color: theme.colors.textPrimary, marginBottom: theme.spacing.md, textAlign: 'center', }, // Legend grid container legendGrid: { flexDirection: 'row', flexWrap: 'wrap', gap: theme.spacing.sm, }, // Legend grid item legendGridItem: { width: '48%', backgroundColor: theme.colors.background, borderRadius: theme.borderRadius.small, padding: theme.spacing.sm, borderWidth: 1, borderColor: theme.colors.border, marginBottom: theme.spacing.xs, }, // Legend item header legendItemHeader: { flexDirection: 'row', alignItems: 'center', marginBottom: theme.spacing.xs, }, // Legend color legendColor: { width: 12, height: 12, borderRadius: 6, marginRight: theme.spacing.xs, }, // Legend label legendLabel: { fontSize: theme.typography.fontSize.bodySmall, fontFamily: theme.typography.fontFamily.semibold, color: theme.colors.textPrimary, flex: 1, }, // Legend count legendCount: { fontSize: theme.typography.fontSize.caption, fontFamily: theme.typography.fontFamily.medium, color: theme.colors.textPrimary, marginBottom: theme.spacing.xs, }, // Legend confidence legendConfidence: { fontSize: theme.typography.fontSize.caption, fontFamily: theme.typography.fontFamily.regular, color: theme.colors.textSecondary, }, // No data container noDataContainer: { flex: 1, justifyContent: 'center', alignItems: 'center', padding: theme.spacing.md, }, // No data text noDataText: { fontSize: theme.typography.fontSize.bodyMedium, fontFamily: theme.typography.fontFamily.regular, color: theme.colors.textSecondary, }, // Summary container summaryContainer: { flexDirection: 'row', justifyContent: 'space-around', paddingTop: theme.spacing.md, borderTopWidth: 1, borderTopColor: theme.colors.border, }, // Summary item summaryItem: { alignItems: 'center', }, // Summary label summaryLabel: { fontSize: theme.typography.fontSize.bodySmall, fontFamily: theme.typography.fontFamily.regular, color: theme.colors.textSecondary, marginBottom: theme.spacing.xs, }, // Summary value summaryValue: { fontSize: theme.typography.fontSize.displaySmall, fontFamily: theme.typography.fontFamily.bold, color: theme.colors.textPrimary, }, // Error container errorContainer: { flex: 1, justifyContent: 'center', alignItems: 'center', padding: theme.spacing.md, backgroundColor: theme.colors.backgroundAlt, borderRadius: theme.borderRadius.medium, }, // Error text errorText: { fontSize: theme.typography.fontSize.bodyMedium, fontFamily: theme.typography.fontFamily.regular, color: theme.colors.textSecondary, textAlign: 'center', }, }); /* * End of File: BrainPredictionsOverview.tsx * Design & Developed by Tech4Biz Solutions * Copyright (c) Spurrin Innovations. All rights reserved. */