NeoScan_Radiologist/app/modules/Dashboard/screens/DashboardScreen.tsx

1287 lines
39 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,
Dimensions,
} from 'react-native';
import { theme } from '../../../theme/theme';
import { FeedbackAnalysisPieChart } from '../components/FeedbackAnalysisPieChart';
import { useAIDashboard } from '../hooks/useAIDashboard';
import { 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<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,
}) => {
// ============================================================================
// 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 (
<View style={styles.errorContainer}>
<Text style={styles.errorTitle}>Connection Error</Text>
<Text style={styles.errorMessage}>
Unable to connect to the dashboard service
</Text>
<View style={styles.errorInfo}>
<Text style={styles.errorInfoText}> Check your internet connection</Text>
<Text style={styles.errorInfoText}> Verify server status</Text>
<Text style={styles.errorInfoText}> Try again in a few moments</Text>
</View>
<TouchableOpacity style={styles.retryButton} onPress={handleRefresh}>
<Text style={styles.retryButtonText}>Retry Connection</Text>
</TouchableOpacity>
</View>
);
};
/**
* renderNetworkStatus Function
*
* Purpose: Render network status indicator
*/
const renderNetworkStatus = () => {
if (!error && dashboardData) return null;
return (
<View style={styles.networkStatusContainer}>
<Text style={styles.networkStatusText}>
{error ? '⚠️ Connection Issue' : '🔄 Checking Connection...'}
</Text>
<Text style={styles.networkStatusSubtext}>
{error ? 'Please check your internet connection' : 'Verifying dashboard service'}
</Text>
</View>
);
};
/**
* renderNoDataState Function
*
* Purpose: Render no data state when dashboard loads but has no meaningful data
*/
const renderNoDataState = () => {
return (
<View style={styles.container}>
<View style={styles.noDataContainer}>
<Text style={styles.noDataTitle}>Dashboard is Ready</Text>
<Text style={styles.noDataMessage}>
Your AI Analysis Dashboard is ready, but there's no data to display yet.
</Text>
<View style={styles.noDataInfo}>
<Text style={styles.noDataInfoText}>• AI predictions will appear here once scans are processed</Text>
<Text style={styles.noDataInfoText}>• Check back after medical scans are uploaded</Text>
<Text style={styles.noDataInfoText}>• The system will automatically populate data</Text>
</View>
<TouchableOpacity style={styles.retryButton} onPress={handleRefresh}>
<Text style={styles.retryButtonText}>Check for Updates</Text>
</TouchableOpacity>
</View>
</View>
);
};
/**
* 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 = () => {
// Check if dashboard data exists
if (!dashboardData) {
return (
<View style={styles.section}>
<Text style={styles.sectionTitle}>Confidence Score Distribution</Text>
<View style={styles.emptyStateContainer}>
<Text style={styles.emptyStateText}>Dashboard data not available</Text>
<TouchableOpacity style={styles.retryButton} onPress={handleRefresh}>
<Text style={styles.retryButtonText}>Retry</Text>
</TouchableOpacity>
</View>
</View>
);
}
// Check if confidence scores data exists
if (!dashboardData.data?.confidence_scores) {
return (
<View style={styles.section}>
<Text style={styles.sectionTitle}>Confidence Score Distribution</Text>
<View style={styles.emptyStateContainer}>
<Text style={styles.emptyStateText}>Confidence data not available</Text>
<Text style={styles.emptyStateSubtext}>AI confidence scores are not currently accessible</Text>
<View style={styles.emptyStateInfo}>
<Text style={styles.emptyStateInfoText}>• AI system may be initializing</Text>
<Text style={styles.emptyStateInfoText}>• Check system status</Text>
<Text style={styles.emptyStateInfoText}>• Refresh in a few minutes</Text>
</View>
</View>
</View>
);
}
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 (
<View style={styles.section}>
<Text style={styles.sectionTitle}>Confidence Score Distribution</Text>
<View style={styles.emptyStateContainer}>
<Text style={styles.emptyStateText}>No data found</Text>
</View>
</View>
);
}
// Check if all required fields exist and are numbers
if (typeof high !== 'number' || typeof medium !== 'number' || typeof low !== 'number') {
return (
<View style={styles.section}>
<Text style={styles.sectionTitle}>Confidence Score Distribution</Text>
<View style={styles.emptyStateContainer}>
<Text style={styles.emptyStateText}>No confidence data available</Text>
</View>
</View>
);
}
const total = high + medium + low;
// If no predictions, show empty state
if (total === 0) {
return (
<View style={styles.section}>
<Text style={styles.sectionTitle}>Confidence Score Distribution</Text>
<View style={styles.emptyStateContainer}>
<Text style={styles.emptyStateText}>No predictions available yet</Text>
<Text style={styles.emptyStateSubtext}>AI predictions will appear here once the system processes medical scans</Text>
</View>
</View>
);
}
// 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 (
<View style={styles.section}>
<Text style={styles.sectionTitle}>Confidence Score Distribution</Text>
<View style={styles.confidenceContainer}>
{/* High Confidence */}
<View style={styles.confidenceItem}>
<View style={styles.confidenceHeader}>
<View style={[styles.confidenceIndicator, { backgroundColor: theme.colors.success }]} />
<Text style={styles.confidenceLabel}>High Confidence</Text>
<Text style={styles.confidencePercentage}>{highPercent}%</Text>
</View>
<View style={styles.confidenceBarContainer}>
<View
style={[
styles.confidenceBar,
{
backgroundColor: theme.colors.success,
width: high === 0 ? 4 : `${Math.max(highPercent, 5)}%`,
opacity: getBarOpacity(high)
}
]}
/>
</View>
<Text style={styles.confidenceValue}>{high} predictions</Text>
</View>
{/* Medium Confidence */}
<View style={styles.confidenceItem}>
<View style={styles.confidenceHeader}>
<View style={[styles.confidenceIndicator, { backgroundColor: theme.colors.warning }]} />
<Text style={styles.confidenceLabel}>Medium Confidence</Text>
<Text style={styles.confidencePercentage}>{mediumPercent}%</Text>
</View>
<View style={styles.confidenceBarContainer}>
<View
style={[
styles.confidenceBar,
{
backgroundColor: theme.colors.warning,
width: medium === 0 ? 4 : `${Math.max(mediumPercent, 5)}%`,
opacity: getBarOpacity(medium)
}
]}
/>
</View>
<Text style={styles.confidenceValue}>{medium} predictions</Text>
</View>
{/* Low Confidence */}
<View style={styles.confidenceItem}>
<View style={styles.confidenceHeader}>
<View style={[styles.confidenceIndicator, { backgroundColor: theme.colors.error }]} />
<Text style={styles.confidenceLabel}>Low Confidence</Text>
<Text style={styles.confidencePercentage}>{lowPercent}%</Text>
</View>
<View style={styles.confidenceBarContainer}>
<View
style={[
styles.confidenceBar,
{
backgroundColor: theme.colors.error,
width: low === 0 ? 4 : `${Math.max(lowPercent, 5)}%`,
opacity: getBarOpacity(low)
}
]}
/>
</View>
<Text style={styles.confidenceValue}>{low} predictions</Text>
</View>
</View>
{/* Summary Stats */}
<View style={styles.confidenceSummary}>
<Text style={styles.summaryText}>
Total Predictions: <Text style={styles.summaryValue}>{total}</Text>
</Text>
<Text style={styles.summaryText}>
High Confidence Rate: <Text style={[styles.summaryValue, { color: theme.colors.success }]}>{highPercent}%</Text>
</Text>
</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;
// Check if the object is empty or if all values are undefined/null/zero
if (!critical && !urgent && !routine) {
return (
<View style={styles.section}>
<Text style={styles.sectionTitle}>Case Urgency Distribution</Text>
<View style={styles.emptyStateContainer}>
<Text style={styles.emptyStateText}>No data found</Text>
</View>
</View>
);
}
// Check if all values are zero (no cases)
if (critical === 0 && urgent === 0 && routine === 0) {
return (
<View style={styles.section}>
<Text style={styles.sectionTitle}>Case Urgency Distribution</Text>
<View style={styles.emptyStateContainer}>
<Text style={styles.emptyStateText}>No cases recorded yet</Text>
</View>
</View>
);
}
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 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 (
<View style={styles.section}>
<Text style={styles.sectionTitle}>Feedback Analysis</Text>
<View style={styles.emptyStateContainer}>
<Text style={styles.emptyStateText}>No data found</Text>
</View>
</View>
);
}
// Check if all values are zero (no feedback)
if (positive === 0 && negative === 0 && total === 0) {
return (
<View style={styles.section}>
<Text style={styles.sectionTitle}>Feedback Analysis</Text>
<View style={styles.emptyStateContainer}>
<Text style={styles.emptyStateText}>No feedback recorded yet</Text>
<Text style={styles.emptyStateSubtext}>Feedback analysis will appear once users provide feedback</Text>
<View style={styles.emptyStateInfo}>
<Text style={styles.emptyStateInfoText}>• No user feedback has been submitted yet</Text>
</View>
</View>
</View>
);
}
return (
<View style={styles.section}>
<Text style={styles.sectionTitle}>Feedback Analysis</Text>
{/* Pie Chart */}
<FeedbackAnalysisPieChart
data={{ positive, negative, total }}
title="Feedback Distribution"
width={Dimensions.get('window').width - (theme.spacing.md * 2)}
height={220}
/>
{/* Additional Feedback Metrics */}
<View style={styles.feedbackMetrics}>
<Text style={styles.feedbackMetricsText}>
Feedback Coverage: {dashboardData.data.feedback_rate_percentage}%
</Text>
<Text style={styles.feedbackMetricsText}>
Average Feedback per Prediction: {isNaN(Number(dashboardData?.data?.average_feedback_per_prediction))? "N/A" : Number(dashboardData.data.average_feedback_per_prediction).toFixed(2) }
</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;
// Check if the object is empty or if all values are undefined/null/zero
if (!today && !this_week && !this_month && !this_year) {
return (
<View style={styles.section}>
<Text style={styles.sectionTitle}>Time-based Analysis</Text>
<View style={styles.emptyStateContainer}>
<Text style={styles.emptyStateText}>No data found</Text>
</View>
</View>
);
}
// Check if all values are zero (no activity)
if (today === 0 && this_week === 0 && this_month === 0 && this_year === 0) {
return (
<View style={styles.section}>
<Text style={styles.sectionTitle}>Time-based Analysis</Text>
<View style={styles.emptyStateContainer}>
<Text style={styles.emptyStateText}>No activity recorded yet</Text>
<Text style={styles.emptyStateSubtext}>Time-based statistics will appear once AI predictions are made</Text>
</View>
</View>
);
}
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}>{getPersonalizedGreeting()}</Text>
<Text style={styles.dashboardSubtitle}>
{dashboardMessage}
</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>
);
// ============================================================================
// MAIN RENDER
// ============================================================================
// Show error state if there's a critical error
if (error) {
return (
<View style={styles.container}>
{renderErrorState()}
</View>
);
}
// Show loading state while data is being fetched
if (isLoading) {
return (
<View style={styles.loadingContainer}>
<Text style={styles.loadingText}>Loading AI Analysis Dashboard...</Text>
</View>
);
}
// Show no data state if dashboard loads but has no meaningful data
if (!dashboardData || !dashboardData.data) {
return renderNoDataState();
}
return (
<View style={styles.container}>
{/* Scrollable dashboard content */}
<ScrollView
style={styles.scrollView}
contentContainerStyle={styles.scrollContent}
refreshControl={
<RefreshControl
refreshing={isRefreshing}
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.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.
*/