/* * File: PatientsScreen.tsx * Description: Main patients screen with search, filtering, and patient list * Design & Developed by Tech4Biz Solutions * Copyright (c) Spurrin Innovations. All rights reserved. */ import React, { useEffect, useCallback } from 'react'; import { View, Text, TouchableOpacity, FlatList, RefreshControl, SafeAreaView, StyleSheet, Alert, } from 'react-native'; import { useNavigation } from '@react-navigation/native'; import { useAppDispatch, useAppSelector } from '../../../store/hooks'; import { theme } from '../../../theme/theme'; // Components import PatientCard from '../components/PatientCard'; import SearchBar from '../components/SearchBar'; import FilterTabs from '../components/FilterTabs'; import LoadingState from '../components/LoadingState'; import EmptyState from '../components/EmptyState'; // Redux import { fetchPatients, setSearchQuery, setFilter, } from '../redux/patientCareSlice'; import { selectPatients, selectFilteredPatients, selectPatientsLoading, selectIsRefreshing, selectPatientsError, selectSearchQuery, selectSelectedFilter, selectPatientCounts, } from '../redux/patientCareSelectors'; // Types import { PatientData } from '../redux/patientCareSlice'; import { selectUser } from '../../Auth/redux/authSelectors'; // ============================================================================ // INTERFACES // ============================================================================ // ============================================================================ // PATIENTS SCREEN COMPONENT // ============================================================================ /** * PatientsScreen Component * * Purpose: Main screen for displaying and managing patient list * * Features: * - Real-time patient data fetching * - Search functionality with real-time filtering * - Filter tabs (All, Processed, Pending) * - Sort options (Date, Name, Processed) * - Pull-to-refresh functionality * - Patient cards with vital information * - Navigation to patient details * - Loading and error states * - Empty state handling * - Modern ER-focused UI design */ const PatientsScreen: React.FC = () => { // ============================================================================ // STATE MANAGEMENT // ============================================================================ const dispatch = useAppDispatch(); const navigation = useNavigation(); // Redux state const patients = useAppSelector(selectPatients); const filteredPatients = useAppSelector(selectFilteredPatients); const isLoading = useAppSelector(selectPatientsLoading); const isRefreshing = useAppSelector(selectIsRefreshing); const error = useAppSelector(selectPatientsError); const searchQuery = useAppSelector(selectSearchQuery); const selectedFilter = useAppSelector(selectSelectedFilter); const patientCounts = useAppSelector(selectPatientCounts); // Auth state const user = useAppSelector(selectUser); // ============================================================================ // EFFECTS // ============================================================================ /** * Fetch Patients on Mount * * Purpose: Load patients when component mounts */ useEffect(() => { if (user?.access_token) { dispatch(fetchPatients(user.access_token)); } }, [dispatch, user?.access_token]); /** * Clear Error on Unmount * * Purpose: Clean up error state when component unmounts */ useEffect(() => { return () => { // No clearError action in this file, so this effect is removed. }; }, [dispatch]); // ============================================================================ // EVENT HANDLERS // ============================================================================ /** * Handle Refresh * * Purpose: Handle pull-to-refresh functionality */ const handleRefresh = useCallback(() => { if (user?.access_token) { dispatch(fetchPatients(user.access_token)); } }, [dispatch, user?.access_token]); /** * Handle Search * * Purpose: Handle search query changes * * @param query - Search query string */ const handleSearch = useCallback((query: string) => { dispatch(setSearchQuery(query)); }, [dispatch]); /** * Handle Filter Change * * Purpose: Update the selected filter and refresh the list */ const handleFilterChange = useCallback((filter: 'all' | 'processed' | 'pending') => { dispatch(setFilter(filter)); }, [dispatch]); /** * Handle Patient Press * * Purpose: Navigate to patient details when a patient card is pressed */ const handlePatientPress = useCallback((patient: PatientData) => { (navigation as any).navigate('PatientDetails', { patientId: patient.patid, patientName: patient.patient_info.name, }); }, [navigation]); /** * Handle Emergency Alert * * Purpose: Show emergency alert for critical patients */ const handleEmergencyAlert = useCallback((patient: PatientData) => { Alert.alert( 'Emergency Alert', `Patient ${patient.patient_info.name} (ID: ${patient.patid}) requires immediate attention!\n\nStatus: ${patient.patient_info.report_status}\nPriority: ${patient.patient_info.status}`, [ { text: 'Cancel', style: 'cancel' }, { text: 'View Details', onPress: () => handlePatientPress(patient) }, ] ); }, [handlePatientPress]); // ============================================================================ // RENDER HELPERS // ============================================================================ /** * Render Patient Card * * Purpose: Render individual patient card component */ const renderPatientCard = useCallback(({ item }: { item: PatientData }) => ( handlePatientPress(item)} onEmergencyPress={() => handleEmergencyAlert(item)} /> ), [handlePatientPress, handleEmergencyAlert]); /** * Render Header * * Purpose: Render the screen header with title and action buttons */ const renderHeader = () => ( Patients {filteredPatients.length} of {patients?.length || 0} patients {/* { // TODO: Implement sort modal }} > Sort { // TODO: Implement filter modal }} > Filter */} ); /** * Render Empty State * * Purpose: Render empty state when no patients found */ const renderEmptyState = () => ( ); // ============================================================================ // MAIN RENDER // ============================================================================ if (error && !isLoading) { return ( Error Loading Patients {error} Retry ); } return ( {/* Header */} {renderHeader()} {/* Search and Filters */} {/* Loading State */} {isLoading && patients.length === 0 && ( )} {/* Error State */} {error && patients.length === 0 && ( )} {/* Empty State */} {!isLoading && !error && patients.length === 0 && ( )} {/* No Results State */} {!isLoading && !error && patients.length > 0 && filteredPatients.length === 0 && ( { handleSearch(''); handleFilterChange('all'); }} /> )} {/* Patient List */} {!isLoading && !error && filteredPatients.length > 0 && ( item.patid} contentContainerStyle={styles.listContainer} showsVerticalScrollIndicator={false} refreshControl={ } /> )} {/* TODO: Implement sort and filter modals for enhanced functionality */} {/* Note: Patient data will be loaded from API when fetchPatients is called */} {/* Currently using mock data from Redux slice for development */} ); }; // ============================================================================ // STYLES // ============================================================================ const styles = StyleSheet.create({ // Container Styles container: { flex: 1, backgroundColor: theme.colors.background, }, // Header Styles header: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', paddingHorizontal: theme.spacing.md, paddingVertical: theme.spacing.md, backgroundColor: theme.colors.background, borderBottomWidth: 1, borderBottomColor: theme.colors.border, marginBottom: theme.spacing.md, }, headerLeft: { flex: 1, }, headerRight: { flexDirection: 'row', gap: theme.spacing.sm, }, headerTitle: { fontSize: 24, color: theme.colors.textPrimary, fontFamily: theme.typography.fontFamily.bold, }, headerSubtitle: { fontSize: 14, color: theme.colors.textSecondary, fontFamily: theme.typography.fontFamily.regular, }, actionButton: { backgroundColor: theme.colors.backgroundAlt, paddingHorizontal: theme.spacing.md, paddingVertical: theme.spacing.sm, borderRadius: 8, borderWidth: 1, borderColor: theme.colors.border, }, actionButtonText: { color: theme.colors.textSecondary, fontSize: 14, fontFamily: theme.typography.fontFamily.medium, }, // Search and Filters searchAndFilters: { paddingHorizontal: theme.spacing.md, paddingBottom: theme.spacing.sm, backgroundColor: theme.colors.background, borderBottomWidth: 1, borderBottomColor: theme.colors.border, }, // Center Container for States centerContainer: { flex: 1, justifyContent: 'center', alignItems: 'center', padding: theme.spacing.md, }, // List Styles listContainer: { paddingBottom: theme.spacing.lg, }, listFooter: { paddingVertical: theme.spacing.md, alignItems: 'center', }, footerText: { fontSize: 14, color: theme.colors.textMuted, fontFamily: theme.typography.fontFamily.regular, }, // Error State Styles errorContainer: { flex: 1, justifyContent: 'center', alignItems: 'center', padding: theme.spacing.xl, }, errorTitle: { fontSize: 20, color: theme.colors.error, marginBottom: theme.spacing.sm, fontFamily: theme.typography.fontFamily.bold, textAlign: 'center', }, errorMessage: { fontSize: 16, color: theme.colors.textSecondary, marginBottom: theme.spacing.lg, fontFamily: theme.typography.fontFamily.regular, textAlign: 'center', }, retryButton: { backgroundColor: theme.colors.primary, paddingHorizontal: theme.spacing.lg, paddingVertical: theme.spacing.md, borderRadius: 8, minWidth: 120, alignItems: 'center', }, retryButtonText: { color: theme.colors.background, fontSize: 16, fontFamily: theme.typography.fontFamily.medium, }, }); export default PatientsScreen; /* * End of File: PatientsScreen.tsx * Design & Developed by Tech4Biz Solutions * Copyright (c) Spurrin Innovations. All rights reserved. */