/* * 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, Dimensions, } from 'react-native'; import { theme } from '../../../theme/theme'; import { DashboardHeader } from '../components/DashboardHeader'; import { BrainPredictionsOverview } from '../components/BrainPredictionsOverview'; import { FeedbackAnalysisPieChart } from '../components/FeedbackAnalysisPieChart'; import { useAIDashboard } from '../hooks/useAIDashboard'; import { selectUserDisplayName, selectUserFirstName } from '../../Auth/redux/authSelectors'; import { useAppSelector } from '../../../store/hooks'; /** * 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; critical_findings: Record; midline_shift_stats: Record; hemorrhage_stats: Record; mass_lesion_stats: Record; edema_stats: Record; fracture_stats: Record; feedback_analysis: { positive: number; negative: number; total: number; }; hospital_distribution: Record; 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 = ({ navigation, }) => { // ============================================================================ // CUSTOM HOOKS & SELECTORS // ============================================================================ // Use custom hook for AI dashboard functionality const { dashboardData, isLoading, isRefreshing, error, dashboardMessage, refreshDashboardStatistics } = useAIDashboard(); // Get user display name from auth state const userDisplayName = useAppSelector(selectUserFirstName); // ============================================================================ // HELPER FUNCTIONS // ============================================================================ /** * getPersonalizedGreeting Function * * Purpose: Generate a personalized greeting based on time of day and user's display name * * @returns Personalized greeting string */ const getPersonalizedGreeting = (): string => { const currentHour = new Date().getHours(); let timeGreeting = ''; // Determine time-based greeting if (currentHour >= 5 && currentHour < 12) { timeGreeting = 'Good Morning'; } else if (currentHour >= 12 && currentHour < 17) { timeGreeting = 'Good Afternoon'; } else if (currentHour >= 17 && currentHour < 21) { timeGreeting = 'Good Evening'; } else { timeGreeting = 'Good Evening'; } // Create personalized greeting with fallback const displayName = userDisplayName || 'Doctor'; return `${timeGreeting}, Dr. ${displayName}`; }; // ============================================================================ // EVENT HANDLERS // ============================================================================ /** * handleRefresh Function * * Purpose: Handle pull-to-refresh functionality to update dashboard data */ const handleRefresh = async () => { // Refresh dashboard statistics from API refreshDashboardStatistics(); }; // ============================================================================ // RENDER FUNCTIONS // ============================================================================ /** * renderErrorState Function * * Purpose: Render error state when there's a critical error */ const renderErrorState = () => { if (!error) return null; return ( Connection Error Unable to connect to the dashboard service • Check your internet connection • Verify server status • Try again in a few moments Retry Connection ); }; /** * renderNetworkStatus Function * * Purpose: Render network status indicator */ const renderNetworkStatus = () => { if (!error && dashboardData) return null; return ( {error ? '⚠️ Connection Issue' : '🔄 Checking Connection...'} {error ? 'Please check your internet connection' : 'Verifying dashboard service'} ); }; /** * renderNoDataState Function * * Purpose: Render no data state when dashboard loads but has no meaningful data */ const renderNoDataState = () => { return ( Dashboard is Ready Your AI Analysis Dashboard is ready, but there's no data to display yet. • AI predictions will appear here once scans are processed • Check back after medical scans are uploaded • The system will automatically populate data Check for Updates ); }; /** * 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) => ( {title} {value} {subtitle && {subtitle}} ); /** * renderConfidenceBreakdown Function * * Purpose: Render confidence score breakdown section */ const renderConfidenceBreakdown = () => { // Check if dashboard data exists if (!dashboardData) { return ( Confidence Score Distribution Dashboard data not available Retry ); } // Check if confidence scores data exists if (!dashboardData.data?.confidence_scores) { return ( Confidence Score Distribution Confidence data not available AI confidence scores are not currently accessible • AI system may be initializing • Check system status • Refresh in a few minutes ); } const { high, medium, low } = dashboardData.data.confidence_scores; // Check if the object is empty or if all values are undefined/null/zero if (!high && !medium && !low) { return ( Confidence Score Distribution No data found ); } // Check if all required fields exist and are numbers if (typeof high !== 'number' || typeof medium !== 'number' || typeof low !== 'number') { return ( Confidence Score Distribution No confidence data available ); } const total = high + medium + low; // If no predictions, show empty state if (total === 0) { return ( Confidence Score Distribution No predictions available yet AI predictions will appear here once the system processes medical scans ); } // Calculate percentages for better visualization const highPercent = Math.round((high / total) * 100); const mediumPercent = Math.round((medium / total) * 100); const lowPercent = Math.round((low / total) * 100); // Helper function to get bar opacity const getBarOpacity = (count: number) => { if (count === 0) return 0.3; // Dimmed for zero values return 0.9; // Full opacity for non-zero values }; return ( Confidence Score Distribution {/* High Confidence */} High Confidence {highPercent}% {high} predictions {/* Medium Confidence */} Medium Confidence {mediumPercent}% {medium} predictions {/* Low Confidence */} Low Confidence {lowPercent}% {low} predictions {/* Summary Stats */} Total Predictions: {total} High Confidence Rate: {highPercent}% ); }; /** * 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; // Check if the object is empty or if all values are undefined/null/zero if (!critical && !urgent && !routine) { return ( Case Urgency Distribution No data found ); } // Check if all values are zero (no cases) if (critical === 0 && urgent === 0 && routine === 0) { return ( Case Urgency Distribution No cases recorded yet ); } return ( Case Urgency Distribution Critical {critical} Urgent {urgent} Routine {routine} ); }; /** * renderFeedbackAnalysis Function * * Purpose: Render feedback analysis section with pie chart */ const renderFeedbackAnalysis = () => { if (!dashboardData?.data.feedback_analysis) return null; const { positive, negative, total } = dashboardData.data.feedback_analysis; // Check if the object is empty or if all values are undefined/null/zero if (!positive && !negative && !total) { return ( Feedback Analysis No data found ); } // Check if all values are zero (no feedback) if (positive === 0 && negative === 0 && total === 0) { return ( Feedback Analysis No feedback recorded yet Feedback analysis will appear once users provide feedback • No user feedback has been submitted yet ); } return ( Feedback Analysis {/* Pie Chart */} {/* Additional Feedback Metrics */} Feedback Coverage: {dashboardData.data.feedback_rate_percentage}% Average Feedback per Prediction: {dashboardData.data.average_feedback_per_prediction} ); }; /** * 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; // Check if the object is empty or if all values are undefined/null/zero if (!today && !this_week && !this_month && !this_year) { return ( Time-based Analysis No data found ); } // Check if all values are zero (no activity) if (today === 0 && this_week === 0 && this_month === 0 && this_year === 0) { return ( Time-based Analysis No activity recorded yet Time-based statistics will appear once AI predictions are made ); } return ( Time-based Analysis Today {today} This Week {this_week} This Month {this_month} This Year {this_year} ); }; /** * renderHeader Function * * Purpose: Render the dashboard header section with key metrics */ const renderHeader = () => ( {/* Dashboard header with title and refresh button */} {getPersonalizedGreeting()} {dashboardMessage} {/* Key statistics cards */} {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 )} ); // ============================================================================ // MAIN RENDER // ============================================================================ // Show error state if there's a critical error if (error) { return ( {renderErrorState()} ); } // Show loading state while data is being fetched if (isLoading) { return ( Loading AI Analysis Dashboard... ); } // Show no data state if dashboard loads but has no meaningful data if (!dashboardData || !dashboardData.data) { return renderNoDataState(); } return ( {/* Scrollable dashboard content */} } 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 */} ); }; // ============================================================================ // 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.displayMedium, fontFamily: theme.typography.fontFamily.bold, color: theme.colors.textPrimary, marginBottom: theme.spacing.xs, marginTop: theme.spacing.sm, }, // 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: { gap: theme.spacing.md, }, // Confidence item styling confidenceItem: { backgroundColor: theme.colors.backgroundAlt, borderRadius: theme.borderRadius.medium, padding: theme.spacing.md, marginBottom: theme.spacing.sm, ...theme.shadows.small, }, // Confidence bar styling confidenceBar: { height: 12, borderRadius: theme.borderRadius.small, backgroundColor: theme.colors.primary, }, // Confidence label styling confidenceLabel: { fontSize: theme.typography.fontSize.bodyMedium, fontFamily: theme.typography.fontFamily.medium, color: theme.colors.textPrimary, flex: 1, }, // Confidence value styling confidenceValue: { fontSize: theme.typography.fontSize.bodySmall, fontFamily: theme.typography.fontFamily.regular, color: theme.colors.textMuted, marginTop: theme.spacing.xs, textAlign: 'center', }, // Confidence header styling confidenceHeader: { flexDirection: 'row', alignItems: 'center', marginBottom: theme.spacing.sm, }, // Confidence indicator styling confidenceIndicator: { width: 16, height: 16, borderRadius: 8, marginRight: theme.spacing.xs, }, // Confidence percentage styling confidencePercentage: { fontSize: theme.typography.fontSize.bodyMedium, fontFamily: theme.typography.fontFamily.bold, color: theme.colors.textPrimary, marginLeft: 'auto', }, // Confidence bar container styling confidenceBarContainer: { width: '100%', height: 12, backgroundColor: theme.colors.border, borderRadius: theme.borderRadius.small, marginBottom: theme.spacing.sm, overflow: 'hidden', }, // 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, }, // Feedback metrics container styling feedbackMetrics: { marginTop: theme.spacing.md, paddingTop: theme.spacing.md, borderTopWidth: 1, borderTopColor: theme.colors.border, alignItems: 'center', }, // Feedback metrics text styling feedbackMetricsText: { 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, }, // Confidence summary styling confidenceSummary: { marginTop: theme.spacing.lg, paddingTop: theme.spacing.md, borderTopWidth: 1, borderTopColor: theme.colors.border, alignItems: 'center', backgroundColor: theme.colors.backgroundAlt, borderRadius: theme.borderRadius.medium, padding: theme.spacing.md, marginHorizontal: -theme.spacing.md, }, // Summary text styling summaryText: { fontSize: theme.typography.fontSize.bodyMedium, fontFamily: theme.typography.fontFamily.medium, color: theme.colors.textSecondary, marginBottom: theme.spacing.sm, }, // Summary value styling summaryValue: { fontSize: theme.typography.fontSize.bodyLarge, fontFamily: theme.typography.fontFamily.bold, color: theme.colors.textPrimary, }, // Bottom spacing for tab bar bottomSpacing: { height: theme.spacing.xl, }, // Empty state container styling emptyStateContainer: { alignItems: 'center', paddingVertical: theme.spacing.lg, }, // Empty state text styling emptyStateText: { fontSize: theme.typography.fontSize.bodyLarge, fontFamily: theme.typography.fontFamily.bold, color: theme.colors.textSecondary, marginBottom: theme.spacing.xs, }, // Empty state subtext styling emptyStateSubtext: { fontSize: theme.typography.fontSize.bodySmall, fontFamily: theme.typography.fontFamily.regular, color: theme.colors.textMuted, textAlign: 'center', marginBottom: theme.spacing.sm, }, // Empty state info styling emptyStateInfo: { marginTop: theme.spacing.sm, paddingHorizontal: theme.spacing.md, }, // Empty state info text styling emptyStateInfoText: { fontSize: theme.typography.fontSize.bodySmall, fontFamily: theme.typography.fontFamily.regular, color: theme.colors.textMuted, marginBottom: theme.spacing.xs, }, // Retry button styling retryButton: { marginTop: theme.spacing.md, paddingVertical: theme.spacing.sm, paddingHorizontal: theme.spacing.lg, backgroundColor: theme.colors.primary, borderRadius: theme.borderRadius.small, borderWidth: 1, borderColor: theme.colors.primary, }, // Retry button text styling retryButtonText: { fontSize: theme.typography.fontSize.bodySmall, fontFamily: theme.typography.fontFamily.medium, color: theme.colors.background, }, // Error container styling errorContainer: { alignItems: 'center', paddingVertical: theme.spacing.lg, backgroundColor: theme.colors.backgroundAlt, borderRadius: theme.borderRadius.medium, marginHorizontal: theme.spacing.md, marginBottom: theme.spacing.md, ...theme.shadows.primary, }, // Error title styling errorTitle: { fontSize: theme.typography.fontSize.bodyLarge, fontFamily: theme.typography.fontFamily.bold, color: theme.colors.textSecondary, marginBottom: theme.spacing.xs, }, // Error message styling errorMessage: { fontSize: theme.typography.fontSize.bodyMedium, fontFamily: theme.typography.fontFamily.regular, color: theme.colors.textMuted, textAlign: 'center', marginBottom: theme.spacing.sm, }, // Error info styling errorInfo: { marginTop: theme.spacing.sm, paddingHorizontal: theme.spacing.md, }, // Error info text styling errorInfoText: { fontSize: theme.typography.fontSize.bodySmall, fontFamily: theme.typography.fontFamily.regular, color: theme.colors.textMuted, marginBottom: theme.spacing.xs, }, // No data container styling noDataContainer: { alignItems: 'center', paddingVertical: theme.spacing.lg, backgroundColor: theme.colors.backgroundAlt, borderRadius: theme.borderRadius.medium, marginHorizontal: theme.spacing.md, marginBottom: theme.spacing.md, ...theme.shadows.primary, }, // No data title styling noDataTitle: { fontSize: theme.typography.fontSize.bodyLarge, fontFamily: theme.typography.fontFamily.bold, color: theme.colors.textSecondary, marginBottom: theme.spacing.xs, }, // No data message styling noDataMessage: { fontSize: theme.typography.fontSize.bodyMedium, fontFamily: theme.typography.fontFamily.regular, color: theme.colors.textMuted, textAlign: 'center', marginBottom: theme.spacing.sm, }, // No data info styling noDataInfo: { marginTop: theme.spacing.sm, paddingHorizontal: theme.spacing.md, }, // No data info text styling noDataInfoText: { fontSize: theme.typography.fontSize.bodySmall, fontFamily: theme.typography.fontFamily.regular, color: theme.colors.textMuted, marginBottom: theme.spacing.xs, }, // Network status container styling networkStatusContainer: { alignItems: 'center', paddingVertical: theme.spacing.md, backgroundColor: theme.colors.backgroundAlt, borderRadius: theme.borderRadius.small, marginHorizontal: theme.spacing.md, marginBottom: theme.spacing.md, ...theme.shadows.small, }, // Network status text styling networkStatusText: { fontSize: theme.typography.fontSize.bodySmall, fontFamily: theme.typography.fontFamily.medium, color: theme.colors.warning, marginBottom: theme.spacing.xs, }, // Network status subtext styling networkStatusSubtext: { fontSize: theme.typography.fontSize.caption, fontFamily: theme.typography.fontFamily.regular, color: theme.colors.warning, textAlign: 'center', }, }); /* * End of File: DashboardScreen.tsx * Design & Developed by Tech4Biz Solutions * Copyright (c) Spurrin Innovations. All rights reserved. */