NeoScan_Radiologist/app/modules/Dashboard/screens/ERDashboardScreen.tsx
2025-08-05 18:01:36 +05:30

752 lines
25 KiB
TypeScript

/*
* File: ERDashboardScreen.tsx
* Description: Main ER dashboard screen displaying patient list, critical alerts, and department 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,
Alert,
} from 'react-native';
import { theme } from '../../../theme/theme';
import { ERDashboard, Patient, Alert as AlertType } from '../../../shared/types';
import { PatientCard } from '../components/PatientCard';
import { CriticalAlerts } from '../components/CriticalAlerts';
import { DashboardHeader } from '../components/DashboardHeader';
import { QuickActions } from '../components/QuickActions';
import { DepartmentStats } from '../components/DepartmentStats';
/**
* ERDashboardScreenProps Interface
*
* Purpose: Defines the props required by the ERDashboardScreen component
*
* Props:
* - navigation: React Navigation object for screen navigation
*/
interface ERDashboardScreenProps {
navigation: any;
}
/**
* ERDashboardScreen Component
*
* Purpose: Main dashboard screen for Emergency Department physicians
*
* Dashboard Features:
* 1. Real-time patient overview with filtering capabilities
* 2. Critical alerts display for immediate attention
* 3. Quick action buttons for common tasks
* 4. Department statistics and bed occupancy
* 5. Pull-to-refresh functionality for live updates
* 6. Internal data generation for demonstration
*
* Patient Filtering:
* - All: Shows all patients in the system
* - Critical: Shows only patients with critical priority
* - Active: Shows only patients with active status
*
* Data Flow:
* 1. Generate mock data internally for demonstration
* 2. Filter patients based on selected filter
* 3. Display critical alerts at the top
* 4. Show patient cards in scrollable list
* 5. Handle refresh and navigation interactions
*/
export const ERDashboardScreen: React.FC<ERDashboardScreenProps> = ({
navigation,
}) => {
// ============================================================================
// STATE MANAGEMENT
// ============================================================================
// Refresh state for pull-to-refresh functionality
const [refreshing, setRefreshing] = useState(false);
// Patient filter state to control which patients are displayed
const [selectedFilter, setSelectedFilter] = useState<'all' | 'critical' | 'active'>('all');
// Dashboard data state
const [dashboard, setDashboard] = useState<ERDashboard | null>(null);
const [patients, setPatients] = useState<Patient[]>([]);
const [alerts, setAlerts] = useState<AlertType[]>([]);
const [isLoading, setIsLoading] = useState(true);
// ============================================================================
// MOCK DATA GENERATION
// ============================================================================
/**
* generateMockDashboard Function
*
* Purpose: Generate mock dashboard data for demonstration
*
* Returns: ERDashboard object with realistic ER statistics
*/
const generateMockDashboard = (): ERDashboard => ({
totalPatients: 24, // Total number of patients in ER
criticalPatients: 3, // Number of patients requiring immediate attention
pendingScans: 8, // Number of scans waiting for review
recentReports: 12, // Number of reports generated recently
bedOccupancy: 85, // Percentage of beds currently occupied
departmentStats: {
emergency: 8, // Patients in emergency department
trauma: 4, // Patients in trauma department
cardiac: 3, // Patients in cardiac department
neurology: 2, // Patients in neurology department
pediatrics: 5, // Patients in pediatrics department
icu: 2, // Patients in ICU
},
shiftInfo: {
currentShift: 'DAY' as const, // Current shift (DAY/NIGHT)
startTime: new Date(), // Shift start time
endTime: new Date(), // Shift end time
attendingPhysician: 'Dr. Smith', // Lead physician on duty
residents: ['Dr. Johnson', 'Dr. Williams'], // Resident physicians
nurses: ['Nurse Brown', 'Nurse Davis'], // Nursing staff
},
lastUpdated: new Date(), // Last time dashboard was updated
});
/**
* generateMockPatients Function
*
* Purpose: Generate mock patient data for demonstration
*
* Returns: Array of Patient objects with realistic medical data
*/
const generateMockPatients = (): Patient[] => [
{
id: '1', // Unique patient identifier
mrn: 'MRN001', // Medical Record Number
firstName: 'John',
lastName: 'Doe',
dateOfBirth: new Date('1985-03-15'),
gender: 'MALE' as const,
age: 38,
bedNumber: 'A1', // Assigned bed number
roomNumber: '101', // Room number
admissionDate: new Date('2024-01-15'),
status: 'ACTIVE' as const, // Current patient status
priority: 'CRITICAL' as const, // Priority level for treatment
department: 'Emergency',
attendingPhysician: 'Dr. Smith',
allergies: [
{
id: '1',
name: 'Penicillin',
severity: 'SEVERE' as const,
reaction: 'Anaphylaxis'
},
],
medications: [
{
id: '1',
name: 'Morphine',
dosage: '2mg',
frequency: 'Every 4 hours',
route: 'IV', // Administration route
startDate: new Date(),
status: 'ACTIVE' as const,
prescribedBy: 'Dr. Smith',
},
],
vitalSigns: {
bloodPressure: { systolic: 140, diastolic: 90, timestamp: new Date() },
heartRate: { value: 95, timestamp: new Date() },
temperature: { value: 37.2, timestamp: new Date() },
respiratoryRate: { value: 18, timestamp: new Date() },
oxygenSaturation: { value: 98, timestamp: new Date() },
},
medicalHistory: [],
currentDiagnosis: 'Chest pain, rule out MI', // Current medical diagnosis
lastUpdated: new Date(),
},
{
id: '2',
mrn: 'MRN002',
firstName: 'Jane',
lastName: 'Smith',
dateOfBirth: new Date('1990-07-22'),
gender: 'FEMALE' as const,
age: 33,
bedNumber: 'B2',
roomNumber: '102',
admissionDate: new Date('2024-01-15'),
status: 'ACTIVE' as const,
priority: 'HIGH' as const,
department: 'Trauma',
attendingPhysician: 'Dr. Johnson',
allergies: [],
medications: [],
vitalSigns: {
bloodPressure: { systolic: 120, diastolic: 80, timestamp: new Date() },
heartRate: { value: 88, timestamp: new Date() },
temperature: { value: 36.8, timestamp: new Date() },
respiratoryRate: { value: 16, timestamp: new Date() },
oxygenSaturation: { value: 99, timestamp: new Date() },
},
medicalHistory: [],
currentDiagnosis: 'Multiple trauma from MVA', // MVA = Motor Vehicle Accident
lastUpdated: new Date(),
},
{
id: '3',
mrn: 'MRN003',
firstName: 'Michael',
lastName: 'Brown',
dateOfBirth: new Date('1978-11-08'),
gender: 'MALE' as const,
age: 45,
bedNumber: 'C3',
roomNumber: '103',
admissionDate: new Date('2024-01-15'),
status: 'PENDING' as const,
priority: 'MEDIUM' as const,
department: 'Cardiac',
attendingPhysician: 'Dr. Williams',
allergies: [
{
id: '2',
name: 'Aspirin',
severity: 'MODERATE' as const,
reaction: 'Stomach upset'
},
],
medications: [
{
id: '2',
name: 'Nitroglycerin',
dosage: '0.4mg',
frequency: 'As needed',
route: 'Sublingual',
startDate: new Date(),
status: 'ACTIVE' as const,
prescribedBy: 'Dr. Williams',
},
],
vitalSigns: {
bloodPressure: { systolic: 160, diastolic: 100, timestamp: new Date() },
heartRate: { value: 110, timestamp: new Date() },
temperature: { value: 36.9, timestamp: new Date() },
respiratoryRate: { value: 20, timestamp: new Date() },
oxygenSaturation: { value: 95, timestamp: new Date() },
},
medicalHistory: [],
currentDiagnosis: 'Hypertension, chest pain',
lastUpdated: new Date(),
},
{
id: '4',
mrn: 'MRN004',
firstName: 'Sarah',
lastName: 'Wilson',
dateOfBirth: new Date('1995-04-12'),
gender: 'FEMALE' as const,
age: 28,
bedNumber: 'D4',
roomNumber: '104',
admissionDate: new Date('2024-01-15'),
status: 'ACTIVE' as const,
priority: 'CRITICAL' as const,
department: 'Neurology',
attendingPhysician: 'Dr. Davis',
allergies: [],
medications: [
{
id: '3',
name: 'Mannitol',
dosage: '100ml',
frequency: 'Every 6 hours',
route: 'IV',
startDate: new Date(),
status: 'ACTIVE' as const,
prescribedBy: 'Dr. Davis',
},
],
vitalSigns: {
bloodPressure: { systolic: 180, diastolic: 110, timestamp: new Date() },
heartRate: { value: 60, timestamp: new Date() },
temperature: { value: 38.5, timestamp: new Date() },
respiratoryRate: { value: 12, timestamp: new Date() },
oxygenSaturation: { value: 92, timestamp: new Date() },
},
medicalHistory: [],
currentDiagnosis: 'Suspected intracranial hemorrhage',
lastUpdated: new Date(),
},
{
id: '5',
mrn: 'MRN005',
firstName: 'David',
lastName: 'Miller',
dateOfBirth: new Date('1982-09-30'),
gender: 'MALE' as const,
age: 41,
bedNumber: 'E5',
roomNumber: '105',
admissionDate: new Date('2024-01-15'),
status: 'ACTIVE' as const,
priority: 'HIGH' as const,
department: 'Pediatrics',
attendingPhysician: 'Dr. Brown',
allergies: [
{
id: '3',
name: 'Latex',
severity: 'SEVERE' as const,
reaction: 'Contact dermatitis'
},
],
medications: [],
vitalSigns: {
bloodPressure: { systolic: 110, diastolic: 70, timestamp: new Date() },
heartRate: { value: 85, timestamp: new Date() },
temperature: { value: 37.8, timestamp: new Date() },
respiratoryRate: { value: 22, timestamp: new Date() },
oxygenSaturation: { value: 97, timestamp: new Date() },
},
medicalHistory: [],
currentDiagnosis: 'Fever of unknown origin',
lastUpdated: new Date(),
},
];
/**
* generateMockAlerts Function
*
* Purpose: Generate mock alert data for demonstration
*
* Returns: Array of Alert objects with realistic medical alerts
*/
const generateMockAlerts = (): AlertType[] => [
{
id: '1',
type: 'CRITICAL_FINDING' as const, // Type of alert
priority: 'CRITICAL' as const, // Priority level
title: 'Critical Finding Detected',
message: 'AI has detected a potential brain bleed in CT scan. Immediate review required.',
patientId: '4', // Associated patient
patientName: 'Sarah Wilson',
bedNumber: 'D4',
timestamp: new Date(), // When alert was generated
isRead: false, // Whether alert has been read
isAcknowledged: false, // Whether alert has been acknowledged
actionRequired: true, // Whether action is required
},
{
id: '2',
type: 'VITAL_SIGNS_ALERT' as const,
priority: 'HIGH' as const,
title: 'Vital Sign Alert',
message: 'Blood pressure elevated: 180/110. Patient requires immediate attention.',
patientId: '4',
patientName: 'Sarah Wilson',
bedNumber: 'D4',
timestamp: new Date(Date.now() - 300000), // 5 minutes ago
isRead: false,
isAcknowledged: false,
actionRequired: true,
},
{
id: '3',
type: 'MEDICATION_ALERT' as const,
priority: 'MEDIUM' as const,
title: 'Medication Due',
message: 'Morphine due for patient John Doe in 15 minutes.',
patientId: '1',
patientName: 'John Doe',
bedNumber: 'A1',
timestamp: new Date(Date.now() - 600000), // 10 minutes ago
isRead: true,
isAcknowledged: true,
actionRequired: false,
},
];
// ============================================================================
// EFFECTS
// ============================================================================
/**
* useEffect for initial data loading
*
* Purpose: Load initial mock data when component mounts
*
* Flow:
* 1. Set loading state to true
* 2. Generate mock data
* 3. Set data in state
* 4. Set loading state to false
*/
useEffect(() => {
const loadInitialData = async () => {
setIsLoading(true);
// Simulate API call delay
await new Promise(resolve => setTimeout(resolve, 1000));
// Generate and set mock data
setDashboard(generateMockDashboard());
setPatients(generateMockPatients());
setAlerts(generateMockAlerts());
setIsLoading(false);
};
loadInitialData();
}, []);
// ============================================================================
// EVENT HANDLERS
// ============================================================================
/**
* handleRefresh Function
*
* Purpose: Handle pull-to-refresh functionality to update dashboard data
*
* Flow:
* 1. Set refreshing state to true (show loading indicator)
* 2. Simulate API call with delay
* 3. Update data with fresh mock data
* 4. Set refreshing state to false (hide loading indicator)
*/
const handleRefresh = async () => {
setRefreshing(true); // Show refresh indicator
// Simulate API call with 1-second delay
await new Promise(resolve => setTimeout(resolve, 1000));
// Update data with fresh mock data
setDashboard(generateMockDashboard());
setPatients(generateMockPatients());
setAlerts(generateMockAlerts());
setRefreshing(false); // Hide refresh indicator
};
/**
* handlePatientPress Function
*
* Purpose: Handle patient card press navigation
*
* @param patient - Patient object that was pressed
*/
const handlePatientPress = (patient: Patient) => {
// TODO: Navigate to patient details screen
console.log('Patient pressed:', patient.firstName, patient.lastName);
Alert.alert('Patient Details', `Navigate to ${patient.firstName} ${patient.lastName}'s details`);
};
/**
* handleAlertPress Function
*
* Purpose: Handle alert press interaction
*
* @param alert - Alert object that was pressed
*/
const handleAlertPress = (alert: AlertType) => {
// TODO: Navigate to alert details or patient details
console.log('Alert pressed:', alert.title);
Alert.alert('Alert Details', alert.message);
};
// ============================================================================
// DATA PROCESSING
// ============================================================================
/**
* filteredPatients - Computed property
*
* Purpose: Filter patients based on selected filter criteria
*
* Filter Options:
* - 'all': Show all patients regardless of status or priority
* - 'critical': Show only patients with CRITICAL priority
* - 'active': Show only patients with ACTIVE status
*/
const filteredPatients = patients.filter(patient => {
switch (selectedFilter) {
case 'critical':
return patient.priority === 'CRITICAL'; // Only critical priority patients
case 'active':
return patient.status === 'ACTIVE'; // Only active status patients
default:
return true; // All patients
}
});
/**
* criticalAlerts - Computed property
*
* Purpose: Extract critical alerts from all alerts for immediate display
*
* Filter: Only alerts with CRITICAL priority that require immediate attention
*/
const criticalAlerts = alerts.filter(alert => alert.priority === 'CRITICAL');
/**
* pendingScans - Computed property
*
* Purpose: Identify patients with pending scans or high priority needs
*
* Filter: Patients with PENDING status or HIGH priority
*/
const pendingScans = patients.filter(patient =>
patient.status === 'PENDING' || patient.priority === 'HIGH'
);
// ============================================================================
// RENDER FUNCTIONS
// ============================================================================
/**
* renderPatientCard Function
*
* Purpose: Render individual patient card component
*
* @param item - Patient data object
* @returns PatientCard component with patient data and press handler
*/
const renderPatientCard = ({ item }: { item: Patient }) => (
<PatientCard
patient={item}
onPress={() => handlePatientPress(item)} // Navigate to patient details
/>
);
/**
* renderHeader Function
*
* Purpose: Render the dashboard header section with all dashboard components
*
* Components included:
* - DashboardHeader: Shows shift info and key statistics
* - CriticalAlerts: Displays urgent alerts requiring attention
* - QuickActions: Provides quick access to common functions
* - DepartmentStats: Shows department-wise patient distribution
* - Filter buttons: Allow filtering of patient list
*/
const renderHeader = () => (
<View style={styles.header}>
{/* Dashboard header with shift information and key metrics */}
{dashboard && <DashboardHeader dashboard={dashboard} />}
{/* Critical alerts section - only show if there are critical alerts */}
{criticalAlerts.length > 0 && (
<CriticalAlerts
alerts={criticalAlerts}
onAlertPress={handleAlertPress} // Handle alert interaction
/>
)}
{/* Quick action buttons for common tasks */}
<QuickActions
onQuickAction={(action) => {
// TODO: Implement quick action handlers
console.log('Quick action:', action);
}}
/>
{/* Department statistics showing patient distribution */}
{dashboard && <DepartmentStats stats={dashboard.departmentStats} />}
{/* Patient filter section with filter buttons */}
<View style={styles.filterContainer}>
<Text style={styles.sectionTitle}>Patients</Text>
<View style={styles.filterButtons}>
{/* All patients filter button */}
<TouchableOpacity
style={[
styles.filterButton,
selectedFilter === 'all' && styles.filterButtonActive
]}
onPress={() => setSelectedFilter('all')}
>
<Text style={[
styles.filterButtonText,
selectedFilter === 'all' && styles.filterButtonTextActive
]}>
All ({patients.length})
</Text>
</TouchableOpacity>
{/* Critical patients filter button */}
<TouchableOpacity
style={[
styles.filterButton,
selectedFilter === 'critical' && styles.filterButtonActive
]}
onPress={() => setSelectedFilter('critical')}
>
<Text style={[
styles.filterButtonText,
selectedFilter === 'critical' && styles.filterButtonTextActive
]}>
Critical ({patients.filter(p => p.priority === 'CRITICAL').length})
</Text>
</TouchableOpacity>
{/* Active patients filter button */}
<TouchableOpacity
style={[
styles.filterButton,
selectedFilter === 'active' && styles.filterButtonActive
]}
onPress={() => setSelectedFilter('active')}
>
<Text style={[
styles.filterButtonText,
selectedFilter === 'active' && styles.filterButtonTextActive
]}>
Active ({patients.filter(p => p.status === 'ACTIVE').length})
</Text>
</TouchableOpacity>
</View>
</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 Dashboard...</Text>
</View>
);
}
// ============================================================================
// MAIN RENDER
// ============================================================================
return (
<View style={styles.container}>
{/* FlatList for efficient rendering of patient cards */}
<FlatList
data={filteredPatients} // Filtered patient data
renderItem={renderPatientCard} // Render function for each patient
keyExtractor={(item) => item.id} // Unique key for each patient
ListHeaderComponent={renderHeader} // Header with dashboard components
contentContainerStyle={styles.listContainer} // Container styling
refreshControl={
<RefreshControl
refreshing={refreshing} // Show refresh indicator
onRefresh={handleRefresh} // Handle refresh action
colors={[theme.colors.primary]} // Refresh indicator color
tintColor={theme.colors.primary} // iOS refresh indicator color
/>
}
showsVerticalScrollIndicator={false} // Hide scroll indicator for cleaner look
/>
</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,
},
// Container for the FlatList content
listContainer: {
paddingBottom: theme.spacing.lg, // Add bottom padding for tab bar
},
// Header section containing dashboard components
header: {
paddingHorizontal: theme.spacing.md, // Horizontal padding for content
},
// Container for patient filter section
filterContainer: {
marginTop: theme.spacing.lg, // Top margin for separation
marginBottom: theme.spacing.md, // Bottom margin for list spacing
},
// Section title styling
sectionTitle: {
fontSize: theme.typography.fontSize.displaySmall,
fontFamily: theme.typography.fontFamily.bold,
color: theme.colors.textPrimary,
marginBottom: theme.spacing.md,
},
// Container for filter buttons
filterButtons: {
flexDirection: 'row', // Horizontal layout
gap: theme.spacing.sm, // Space between buttons
},
// Individual filter button styling
filterButton: {
paddingHorizontal: theme.spacing.md,
paddingVertical: theme.spacing.sm,
borderRadius: theme.borderRadius.medium,
borderWidth: 1,
borderColor: theme.colors.border,
backgroundColor: theme.colors.background,
},
// Active filter button styling
filterButtonActive: {
backgroundColor: theme.colors.primary, // Primary color background
borderColor: theme.colors.primary, // Primary color border
},
// Filter button text styling
filterButtonText: {
fontSize: theme.typography.fontSize.bodyMedium,
color: theme.colors.textSecondary,
fontFamily: theme.typography.fontFamily.medium,
},
// Active filter button text styling
filterButtonTextActive: {
color: theme.colors.background, // White text on primary background
},
});
/*
* End of File: ERDashboardScreen.tsx
* Design & Developed by Tech4Biz Solutions
* Copyright (c) Spurrin Innovations. All rights reserved.
*/