NeoScan_Radiologist/app/modules/Dashboard/screens/DashboardScreen.tsx
2025-08-14 20:16:03 +05:30

811 lines
23 KiB
TypeScript

/*
* File: DashboardScreen.tsx
* Description: AI Analysis Dashboard - Main dashboard for AI predictions and analysis statistics
* Design & Developed by Tech4Biz Solutions
* Copyright (c) Spurrin Innovations. All rights reserved.
*/
import React, { useState, useEffect } from 'react';
import {
View,
Text,
StyleSheet,
ScrollView,
TouchableOpacity,
RefreshControl,
FlatList,
} from 'react-native';
import { theme } from '../../../theme/theme';
import { DashboardHeader } from '../components/DashboardHeader';
import { BrainPredictionsOverview } from '../components/BrainPredictionsOverview';
/**
* DashboardScreenProps Interface
*
* Purpose: Defines the props required by the DashboardScreen component
*
* Props:
* - navigation: React Navigation object for screen navigation
*/
interface DashboardScreenProps {
navigation: any;
}
/**
* Dashboard Stats Data Interface
*
* Purpose: Defines the structure of the dashboard statistics data
*/
interface DashboardStats {
total_predictions: number;
total_patients: number;
total_feedbacks: number;
prediction_breakdown: Record<string, number>;
critical_findings: Record<string, number>;
midline_shift_stats: Record<string, number>;
hemorrhage_stats: Record<string, number>;
mass_lesion_stats: Record<string, number>;
edema_stats: Record<string, number>;
fracture_stats: Record<string, number>;
feedback_analysis: {
positive: number;
negative: number;
total: number;
};
hospital_distribution: Record<string, number>;
time_analysis: {
today: number;
this_week: number;
this_month: number;
this_year: number;
};
urgency_levels: {
critical: number;
urgent: number;
routine: number;
};
confidence_scores: {
high: number;
medium: number;
low: number;
};
feedback_rate_percentage: number;
predictions_with_feedback: number;
predictions_without_feedback: number;
average_feedback_per_prediction: string;
critical_case_percentage: number;
average_confidence_score: number;
}
/**
* Dashboard Summary Interface
*
* Purpose: Defines the structure of the dashboard summary data
*/
interface DashboardSummary {
total_cases: number;
critical_cases: number;
routine_cases: number;
feedback_coverage: string;
critical_case_rate: string;
average_confidence: string;
}
/**
* Complete Dashboard Data Interface
*
* Purpose: Defines the complete structure of the dashboard API response
*/
interface DashboardData {
success: boolean;
data: DashboardStats;
summary: DashboardSummary;
message: string;
}
/**
* DashboardScreen Component
*
* Purpose: AI Analysis Dashboard for physicians showing prediction statistics
*
* Dashboard Features:
* 1. AI prediction statistics and breakdown
* 2. Feedback analysis and coverage metrics
* 3. Confidence score distribution
* 4. Time-based analysis trends
* 5. Urgency level distribution
* 6. Pull-to-refresh functionality for live updates
*/
export const DashboardScreen: React.FC<DashboardScreenProps> = ({
navigation,
}) => {
// ============================================================================
// STATE MANAGEMENT
// ============================================================================
// Refresh state for pull-to-refresh functionality
const [refreshing, setRefreshing] = useState(false);
// Dashboard data state
const [dashboardData, setDashboardData] = useState<DashboardData | null>(null);
const [isLoading, setIsLoading] = useState(true);
// ============================================================================
// MOCK DATA GENERATION
// ============================================================================
/**
* generateMockDashboardData Function
*
* Purpose: Generate mock dashboard data based on the provided JSON structure
*
* Returns: DashboardData object with AI analysis statistics
*/
const generateMockDashboardData = (): DashboardData => ({
success: true,
data: {
total_predictions: 24,
total_patients: 9,
total_feedbacks: 6,
prediction_breakdown: {
"Other": 24
},
critical_findings: {},
midline_shift_stats: {},
hemorrhage_stats: {},
mass_lesion_stats: {},
edema_stats: {},
fracture_stats: {},
feedback_analysis: {
positive: 6,
negative: 0,
total: 6
},
hospital_distribution: {
"b491dfc2-521b-4eb1-8d88-02b0940ea1ff": 24
},
time_analysis: {
today: 24,
this_week: 24,
this_month: 24,
this_year: 24
},
urgency_levels: {
critical: 0,
urgent: 0,
routine: 24
},
confidence_scores: {
high: 23,
medium: 1,
low: 0
},
feedback_rate_percentage: 25,
predictions_with_feedback: 2,
predictions_without_feedback: 22,
average_feedback_per_prediction: "0.25",
critical_case_percentage: 0,
average_confidence_score: 0.89
},
summary: {
total_cases: 24,
critical_cases: 0,
routine_cases: 24,
feedback_coverage: "25.00%",
critical_case_rate: "0.00%",
average_confidence: "0.89"
},
message: "Statistics generated for 24 predictions"
});
// ============================================================================
// EFFECTS
// ============================================================================
/**
* useEffect for initial data loading
*
* Purpose: Load initial mock data when component mounts
*/
useEffect(() => {
const loadInitialData = async () => {
setIsLoading(true);
// Simulate API call delay
setTimeout(() => {}, 1000);
// Generate and set mock data
setDashboardData(generateMockDashboardData());
setIsLoading(false);
};
loadInitialData();
}, []);
// ============================================================================
// EVENT HANDLERS
// ============================================================================
/**
* handleRefresh Function
*
* Purpose: Handle pull-to-refresh functionality to update dashboard data
*/
const handleRefresh = async () => {
setRefreshing(true);
// Simulate API call with 1-second delay
setTimeout(() => {}, 1000);
// Update data with fresh mock data
setDashboardData(generateMockDashboardData());
setRefreshing(false);
};
// ============================================================================
// RENDER FUNCTIONS
// ============================================================================
/**
* renderStatsCard Function
*
* Purpose: Render individual statistics card component
*
* @param title - Card title
* @param value - Main value to display
* @param subtitle - Optional subtitle
* @param color - Optional color theme
* @returns Statistics card component
*/
const renderStatsCard = (title: string, value: string | number, subtitle?: string, color?: string) => (
<View style={[styles.statsCard, color && { borderLeftColor: color, borderLeftWidth: 4 }]}>
<Text style={styles.statsCardTitle}>{title}</Text>
<Text style={[styles.statsCardValue, color && { color }]}>{value}</Text>
{subtitle && <Text style={styles.statsCardSubtitle}>{subtitle}</Text>}
</View>
);
/**
* renderConfidenceBreakdown Function
*
* Purpose: Render confidence score breakdown section
*/
const renderConfidenceBreakdown = () => {
if (!dashboardData?.data.confidence_scores) return null;
const { high, medium, low } = dashboardData.data.confidence_scores;
const total = high + medium + low;
return (
<View style={styles.section}>
<Text style={styles.sectionTitle}>Confidence Score Distribution</Text>
<View style={styles.confidenceContainer}>
<View style={styles.confidenceItem}>
<View style={[styles.confidenceBar, { backgroundColor: theme.colors.success, height: (high / total) * 100 }]} />
<Text style={styles.confidenceLabel}>High</Text>
<Text style={styles.confidenceValue}>{high}</Text>
</View>
<View style={styles.confidenceItem}>
<View style={[styles.confidenceBar, { backgroundColor: theme.colors.warning, height: (medium / total) * 100 }]} />
<Text style={styles.confidenceLabel}>Medium</Text>
<Text style={styles.confidenceValue}>{medium}</Text>
</View>
<View style={styles.confidenceItem}>
<View style={[styles.confidenceBar, { backgroundColor: theme.colors.error, height: (low / total) * 100 }]} />
<Text style={styles.confidenceLabel}>Low</Text>
<Text style={styles.confidenceValue}>{low}</Text>
</View>
</View>
</View>
);
};
/**
* renderUrgencyBreakdown Function
*
* Purpose: Render urgency level breakdown section
*/
const renderUrgencyBreakdown = () => {
if (!dashboardData?.data.urgency_levels) return null;
const { critical, urgent, routine } = dashboardData.data.urgency_levels;
return (
<View style={styles.section}>
<Text style={styles.sectionTitle}>Case Urgency Distribution</Text>
<View style={styles.urgencyContainer}>
<View style={styles.urgencyItem}>
<View style={[styles.urgencyIndicator, { backgroundColor: theme.colors.error }]} />
<Text style={styles.urgencyLabel}>Critical</Text>
<Text style={styles.urgencyValue}>{critical}</Text>
</View>
<View style={styles.urgencyItem}>
<View style={[styles.urgencyIndicator, { backgroundColor: theme.colors.warning }]} />
<Text style={styles.urgencyLabel}>Urgent</Text>
<Text style={styles.urgencyValue}>{urgent}</Text>
</View>
<View style={styles.urgencyItem}>
<View style={[styles.urgencyIndicator, { backgroundColor: theme.colors.success }]} />
<Text style={styles.urgencyLabel}>Routine</Text>
<Text style={styles.urgencyValue}>{routine}</Text>
</View>
</View>
</View>
);
};
/**
* renderFeedbackAnalysis Function
*
* Purpose: Render feedback analysis section
*/
const renderFeedbackAnalysis = () => {
if (!dashboardData?.data.feedback_analysis) return null;
const { positive, negative, total } = dashboardData.data.feedback_analysis;
const positivePercentage = total > 0 ? ((positive / total) * 100).toFixed(1) : '0';
const negativePercentage = total > 0 ? ((negative / total) * 100).toFixed(1) : '0';
return (
<View style={styles.section}>
<Text style={styles.sectionTitle}>Feedback Analysis</Text>
<View style={styles.feedbackContainer}>
<View style={styles.feedbackItem}>
<View style={[styles.feedbackIndicator, { backgroundColor: theme.colors.success }]} />
<Text style={styles.feedbackLabel}>Positive</Text>
<Text style={styles.feedbackValue}>{positive}</Text>
<Text style={styles.feedbackPercentage}>({positivePercentage}%)</Text>
</View>
<View style={styles.feedbackItem}>
<View style={[styles.feedbackIndicator, { backgroundColor: theme.colors.error }]} />
<Text style={styles.feedbackLabel}>Negative</Text>
<Text style={styles.feedbackValue}>{negative}</Text>
<Text style={styles.feedbackPercentage}>({negativePercentage}%)</Text>
</View>
</View>
<View style={styles.feedbackSummary}>
<Text style={styles.feedbackSummaryText}>
Feedback Coverage: {dashboardData.data.feedback_rate_percentage}%
</Text>
<Text style={styles.feedbackSummaryText}>
Average Feedback per Prediction: {dashboardData.data.average_feedback_per_prediction}
</Text>
</View>
</View>
);
};
/**
* renderTimeAnalysis Function
*
* Purpose: Render time-based analysis section
*/
const renderTimeAnalysis = () => {
if (!dashboardData?.data.time_analysis) return null;
const { today, this_week, this_month, this_year } = dashboardData.data.time_analysis;
return (
<View style={styles.section}>
<Text style={styles.sectionTitle}>Time-based Analysis</Text>
<View style={styles.timeContainer}>
<View style={styles.timeItem}>
<Text style={styles.timeLabel}>Today</Text>
<Text style={styles.timeValue}>{today}</Text>
</View>
<View style={styles.timeItem}>
<Text style={styles.timeLabel}>This Week</Text>
<Text style={styles.timeValue}>{this_week}</Text>
</View>
<View style={styles.timeItem}>
<Text style={styles.timeLabel}>This Month</Text>
<Text style={styles.timeValue}>{this_month}</Text>
</View>
<View style={styles.timeItem}>
<Text style={styles.timeLabel}>This Year</Text>
<Text style={styles.timeValue}>{this_year}</Text>
</View>
</View>
</View>
);
};
/**
* renderHeader Function
*
* Purpose: Render the dashboard header section with key metrics
*/
const renderHeader = () => (
<View style={styles.header}>
{/* Dashboard header with title and refresh button */}
<View style={styles.headerTop}>
<Text style={styles.dashboardTitle}>AI Analysis Dashboard</Text>
<Text style={styles.dashboardSubtitle}>
{dashboardData?.message || 'Loading statistics...'}
</Text>
</View>
{/* Key statistics cards */}
<View style={styles.statsGrid}>
{renderStatsCard(
'Total Predictions',
dashboardData?.data.total_predictions || 0,
'AI analyses performed',
theme.colors.primary
)}
{renderStatsCard(
'Total Patients',
dashboardData?.data.total_patients || 0,
'Unique patients',
theme.colors.info
)}
{renderStatsCard(
'Feedback Rate',
`${dashboardData?.data.feedback_rate_percentage || 0}%`,
'User feedback coverage',
theme.colors.success
)}
{renderStatsCard(
'Avg Confidence',
(dashboardData?.data.average_confidence_score || 0).toFixed(2),
'AI prediction confidence',
theme.colors.warning
)}
</View>
</View>
);
// ============================================================================
// LOADING STATE
// ============================================================================
/**
* Loading state render
*
* Purpose: Show loading indicator while data is being generated
*/
if (isLoading) {
return (
<View style={styles.loadingContainer}>
<Text style={styles.loadingText}>Loading AI Analysis Dashboard...</Text>
</View>
);
}
// ============================================================================
// MAIN RENDER
// ============================================================================
return (
<View style={styles.container}>
{/* Scrollable dashboard content */}
<ScrollView
style={styles.scrollView}
contentContainerStyle={styles.scrollContent}
refreshControl={
<RefreshControl
refreshing={refreshing}
onRefresh={handleRefresh}
colors={[theme.colors.primary]}
tintColor={theme.colors.primary}
/>
}
showsVerticalScrollIndicator={false}
>
{/* Dashboard header with key metrics */}
{renderHeader()}
{/* Confidence score breakdown */}
{renderConfidenceBreakdown()}
{/* Urgency level breakdown */}
{renderUrgencyBreakdown()}
{/* Feedback analysis */}
{renderFeedbackAnalysis()}
{/* Time-based analysis */}
{renderTimeAnalysis()}
{/* Bottom spacing for tab bar */}
<View style={styles.bottomSpacing} />
</ScrollView>
</View>
);
};
// ============================================================================
// STYLES SECTION
// ============================================================================
const styles = StyleSheet.create({
// Main container for the dashboard screen
container: {
flex: 1,
backgroundColor: theme.colors.background,
},
// Loading container for initial data loading
loadingContainer: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: theme.colors.background,
},
// Loading text styling
loadingText: {
fontSize: theme.typography.fontSize.bodyLarge,
color: theme.colors.textSecondary,
fontFamily: theme.typography.fontFamily.medium,
},
// Scroll view styling
scrollView: {
flex: 1,
},
// Scroll content styling
scrollContent: {
paddingBottom: theme.spacing.lg,
},
// Header section containing dashboard components
header: {
paddingHorizontal: theme.spacing.md,
paddingTop: theme.spacing.md,
},
// Header top section with title
headerTop: {
marginBottom: theme.spacing.lg,
},
// Dashboard title styling
dashboardTitle: {
fontSize: theme.typography.fontSize.displayLarge,
fontFamily: theme.typography.fontFamily.bold,
color: theme.colors.textPrimary,
marginBottom: theme.spacing.xs,
},
// Dashboard subtitle styling
dashboardSubtitle: {
fontSize: theme.typography.fontSize.bodyMedium,
fontFamily: theme.typography.fontFamily.regular,
color: theme.colors.textSecondary,
},
// Stats grid container
statsGrid: {
flexDirection: 'row',
flexWrap: 'wrap',
gap: theme.spacing.sm,
marginBottom: theme.spacing.lg,
},
// Individual stats card styling
statsCard: {
flex: 1,
minWidth: '45%',
backgroundColor: theme.colors.background,
borderRadius: theme.borderRadius.medium,
padding: theme.spacing.md,
borderLeftWidth: 0,
borderLeftColor: 'transparent',
...theme.shadows.primary,
},
// Stats card title styling
statsCardTitle: {
fontSize: theme.typography.fontSize.bodySmall,
fontFamily: theme.typography.fontFamily.medium,
color: theme.colors.textSecondary,
marginBottom: theme.spacing.xs,
},
// Stats card value styling
statsCardValue: {
fontSize: theme.typography.fontSize.displayMedium,
fontFamily: theme.typography.fontFamily.bold,
color: theme.colors.textPrimary,
marginBottom: theme.spacing.xs,
},
// Stats card subtitle styling
statsCardSubtitle: {
fontSize: theme.typography.fontSize.bodySmall,
fontFamily: theme.typography.fontFamily.regular,
color: theme.colors.textMuted,
},
// Section container styling
section: {
backgroundColor: theme.colors.background,
borderRadius: theme.borderRadius.medium,
padding: theme.spacing.md,
marginHorizontal: theme.spacing.md,
marginBottom: theme.spacing.md,
...theme.shadows.primary,
},
// Section title styling
sectionTitle: {
fontSize: theme.typography.fontSize.displaySmall,
fontFamily: theme.typography.fontFamily.bold,
color: theme.colors.textPrimary,
marginBottom: theme.spacing.lg,
},
// Confidence breakdown container
confidenceContainer: {
flexDirection: 'row',
justifyContent: 'space-around',
alignItems: 'flex-end',
height: 120,
},
// Confidence item styling
confidenceItem: {
alignItems: 'center',
flex: 1,
},
// Confidence bar styling
confidenceBar: {
width: 40,
borderRadius: theme.borderRadius.small,
marginBottom: theme.spacing.sm,
minHeight: 4,
},
// Confidence label styling
confidenceLabel: {
fontSize: theme.typography.fontSize.bodySmall,
fontFamily: theme.typography.fontFamily.medium,
color: theme.colors.textSecondary,
marginBottom: theme.spacing.xs,
},
// Confidence value styling
confidenceValue: {
fontSize: theme.typography.fontSize.bodyMedium,
fontFamily: theme.typography.fontFamily.bold,
color: theme.colors.textPrimary,
},
// Urgency container styling
urgencyContainer: {
flexDirection: 'row',
justifyContent: 'space-around',
},
// Urgency item styling
urgencyItem: {
alignItems: 'center',
flex: 1,
},
// Urgency indicator styling
urgencyIndicator: {
width: 16,
height: 16,
borderRadius: 8,
marginBottom: theme.spacing.xs,
},
// Urgency label styling
urgencyLabel: {
fontSize: theme.typography.fontSize.bodySmall,
fontFamily: theme.typography.fontFamily.medium,
color: theme.colors.textSecondary,
marginBottom: theme.spacing.xs,
},
// Urgency value styling
urgencyValue: {
fontSize: theme.typography.fontSize.bodyMedium,
fontFamily: theme.typography.fontFamily.bold,
color: theme.colors.textPrimary,
},
// Feedback container styling
feedbackContainer: {
flexDirection: 'row',
justifyContent: 'space-around',
marginBottom: theme.spacing.md,
},
// Feedback item styling
feedbackItem: {
alignItems: 'center',
flex: 1,
},
// Feedback indicator styling
feedbackIndicator: {
width: 16,
height: 16,
borderRadius: 8,
marginBottom: theme.spacing.xs,
},
// Feedback label styling
feedbackLabel: {
fontSize: theme.typography.fontSize.bodySmall,
fontFamily: theme.typography.fontFamily.medium,
color: theme.colors.textSecondary,
marginBottom: theme.spacing.xs,
},
// Feedback value styling
feedbackValue: {
fontSize: theme.typography.fontSize.bodyMedium,
fontFamily: theme.typography.fontFamily.bold,
color: theme.colors.textPrimary,
marginBottom: theme.spacing.xs,
},
// Feedback percentage styling
feedbackPercentage: {
fontSize: theme.typography.fontSize.bodySmall,
fontFamily: theme.typography.fontFamily.regular,
color: theme.colors.textMuted,
},
// Feedback summary styling
feedbackSummary: {
borderTopWidth: 1,
borderTopColor: theme.colors.border,
paddingTop: theme.spacing.md,
},
// Feedback summary text styling
feedbackSummaryText: {
fontSize: theme.typography.fontSize.bodySmall,
fontFamily: theme.typography.fontFamily.regular,
color: theme.colors.textSecondary,
textAlign: 'center',
marginBottom: theme.spacing.xs,
},
// Time container styling
timeContainer: {
flexDirection: 'row',
justifyContent: 'space-around',
},
// Time item styling
timeItem: {
alignItems: 'center',
flex: 1,
},
// Time label styling
timeLabel: {
fontSize: theme.typography.fontSize.bodySmall,
fontFamily: theme.typography.fontFamily.medium,
color: theme.colors.textSecondary,
marginBottom: theme.spacing.xs,
},
// Time value styling
timeValue: {
fontSize: theme.typography.fontSize.bodyMedium,
fontFamily: theme.typography.fontFamily.bold,
color: theme.colors.textPrimary,
},
// Bottom spacing for tab bar
bottomSpacing: {
height: theme.spacing.xl,
},
});
/*
* End of File: DashboardScreen.tsx
* Design & Developed by Tech4Biz Solutions
* Copyright (c) Spurrin Innovations. All rights reserved.
*/