/* * File: AIPredictionsScreen.tsx * Description: Main AI Predictions screen with data rendering and management * Design & Developed by Tech4Biz Solutions * Copyright (c) Spurrin Innovations. All rights reserved. */ import React, { useEffect, useCallback, useState } from 'react'; import { View, Text, StyleSheet, FlatList, RefreshControl, TouchableOpacity, Alert, StatusBar, SafeAreaView, } from 'react-native'; import Icon from 'react-native-vector-icons/Feather'; import { theme } from '../../../theme'; import { useAppDispatch, useAppSelector } from '../../../store/hooks'; // Import Redux actions and selectors import { fetchAIPredictions, setSearchQuery, setUrgencyFilter, setSeverityFilter, setCategoryFilter, setCurrentPage, clearAllFilters, toggleShowFilters, toggleCaseSelection, clearSelectedCases, updateCaseReview, } from '../redux'; import { selectPaginatedCases, selectIsLoading, selectError, selectSearchQuery, selectUrgencyFilter, selectSeverityFilter, selectCategoryFilter, selectShowFilters, selectSelectedCaseIds, selectCasesStatistics, selectFilterCounts, selectActiveFiltersCount, selectCurrentPage, selectTotalPages, selectHasNextPage, selectHasPreviousPage, } from '../redux'; // Import components import { AIPredictionCard, SearchBar, FilterTabs, LoadingState, EmptyState, StatsOverview, } from '../components'; // Import types import type { AIPredictionCase } from '../types'; // Import auth selector import { selectUser } from '../../Auth/redux/authSelectors'; // ============================================================================ // INTERFACES // ============================================================================ interface AIPredictionsScreenProps { navigation: any; route?: any; } // ============================================================================ // AI PREDICTIONS SCREEN COMPONENT // ============================================================================ /** * AIPredictionsScreen Component * * Purpose: Main screen for displaying and managing AI prediction cases * * Features: * - Comprehensive AI predictions list * - Real-time search and filtering * - Statistics overview dashboard * - Bulk case selection and actions * - Pull-to-refresh functionality * - Pagination support * - Review status management * - Modern card-based design * - Error handling and retry * - Loading states and empty states * - Accessibility support */ const AIPredictionsScreen: React.FC = ({ navigation }) => { // ============================================================================ // REDUX STATE // ============================================================================ const dispatch = useAppDispatch(); // Auth state const user :any = useAppSelector(selectUser); // AI Prediction state const cases = useAppSelector(selectPaginatedCases); const isLoading = useAppSelector(selectIsLoading); const error = useAppSelector(selectError); const searchQuery = useAppSelector(selectSearchQuery); const urgencyFilter = useAppSelector(selectUrgencyFilter); const severityFilter = useAppSelector(selectSeverityFilter); const categoryFilter = useAppSelector(selectCategoryFilter); const showFilters = useAppSelector(selectShowFilters); const selectedCaseIds = useAppSelector(selectSelectedCaseIds); const statistics = useAppSelector(selectCasesStatistics); const filterCounts = useAppSelector(selectFilterCounts); const activeFiltersCount = useAppSelector(selectActiveFiltersCount); const currentPage = useAppSelector(selectCurrentPage); const totalPages = useAppSelector(selectTotalPages); const hasNextPage = useAppSelector(selectHasNextPage); const hasPreviousPage = useAppSelector(selectHasPreviousPage); // ============================================================================ // LOCAL STATE // ============================================================================ const [refreshing, setRefreshing] = useState(false); const [showStats, setShowStats] = useState(true); // ============================================================================ // EFFECTS // ============================================================================ /** * Load AI Predictions on Mount * * Purpose: Fetch AI predictions when component mounts */ console.log('user ===>', user); useEffect(() => { if (user?.access_token) { loadAIPredictions(); } }, [user?.access_token]); /** * Load AI Predictions on Filter Change * * Purpose: Reload data when filters change */ useEffect(() => { if (user?.access_token) { loadAIPredictions(); } }, [urgencyFilter, severityFilter, categoryFilter, searchQuery, currentPage]); // ============================================================================ // EVENT HANDLERS // ============================================================================ /** * Load AI Predictions * * Purpose: Fetch AI predictions from API */ const loadAIPredictions = useCallback(async () => { if (!user?.access_token) return; try { const params = { page: currentPage, limit: 20, ...(urgencyFilter !== 'all' && { urgency: urgencyFilter }), ...(severityFilter !== 'all' && { severity: severityFilter }), ...(categoryFilter !== 'all' && { category: categoryFilter }), ...(searchQuery.trim() && { search: searchQuery.trim() }), }; await dispatch(fetchAIPredictions({ token: user.access_token, params, })).unwrap(); } catch (error) { console.error('Failed to load AI predictions:', error); // Error is handled by Redux state } }, [dispatch, user?.access_token, currentPage, urgencyFilter, severityFilter, categoryFilter, searchQuery]); /** * Handle Refresh * * Purpose: Handle pull-to-refresh */ const handleRefresh = useCallback(async () => { setRefreshing(true); await loadAIPredictions(); setRefreshing(false); }, [loadAIPredictions]); /** * Handle Search * * Purpose: Handle search query change */ const handleSearch = useCallback((query: string) => { dispatch(setSearchQuery(query)); }, [dispatch]); /** * Handle Filter Changes * * Purpose: Handle filter option changes */ const handleUrgencyFilterChange = useCallback((filter: typeof urgencyFilter) => { dispatch(setUrgencyFilter(filter)); }, [dispatch]); const handleSeverityFilterChange = useCallback((filter: typeof severityFilter) => { dispatch(setSeverityFilter(filter)); }, [dispatch]); const handleCategoryFilterChange = useCallback((filter: typeof categoryFilter) => { dispatch(setCategoryFilter(filter)); }, [dispatch]); /** * Handle Clear Filters * * Purpose: Clear all active filters */ const handleClearFilters = useCallback(() => { dispatch(clearAllFilters()); }, [dispatch]); /** * Handle Toggle Filters * * Purpose: Toggle filter visibility */ const handleToggleFilters = useCallback(() => { dispatch(toggleShowFilters()); }, [dispatch]); /** * Handle Case Press * * Purpose: Navigate to case details */ const handleCasePress = useCallback((predictionCase: AIPredictionCase) => { navigation.navigate('AIPredictionDetails', { caseId: predictionCase.patid }); }, [navigation]); /** * Handle Case Review * * Purpose: Handle case review action */ const handleCaseReview = useCallback(async (caseId: string) => { if (!user?.access_token) return; try { await dispatch(updateCaseReview({ caseId, reviewData: { review_status: 'reviewed', reviewed_by: user.name || user.email || 'Current User', }, token: user.access_token, })).unwrap(); Alert.alert( 'Review Updated', 'Case has been marked as reviewed.', [{ text: 'OK' }] ); } catch (error) { Alert.alert( 'Error', 'Failed to update case review. Please try again.', [{ text: 'OK' }] ); } }, [dispatch, user]); /** * Handle Case Selection * * Purpose: Handle case selection for bulk operations */ const handleCaseSelection = useCallback((caseId: string) => { dispatch(toggleCaseSelection(caseId)); }, [dispatch]); /** * Handle Bulk Actions * * Purpose: Handle bulk actions on selected cases */ const handleBulkReview = useCallback(() => { if (selectedCaseIds.length === 0) return; Alert.alert( 'Bulk Review', `Mark ${selectedCaseIds.length} cases as reviewed?`, [ { text: 'Cancel', style: 'cancel' }, { text: 'Confirm', onPress: async () => { // Implement bulk review logic here // For now, just clear selections dispatch(clearSelectedCases()); }, }, ] ); }, [selectedCaseIds, dispatch]); /** * Handle Page Change * * Purpose: Handle pagination */ const handlePreviousPage = useCallback(() => { if (hasPreviousPage) { dispatch(setCurrentPage(currentPage - 1)); } }, [dispatch, currentPage, hasPreviousPage]); const handleNextPage = useCallback(() => { if (hasNextPage) { dispatch(setCurrentPage(currentPage + 1)); } }, [dispatch, currentPage, hasNextPage]); /** * Handle Stats Press * * Purpose: Handle statistics card press */ const handleStatsPress = useCallback((statType: string) => { // Navigate to detailed statistics or apply relevant filters switch (statType) { case 'critical': dispatch(setUrgencyFilter('emergency')); break; case 'urgent': dispatch(setUrgencyFilter('urgent')); break; case 'pending': // Filter for pending reviews break; default: break; } }, [dispatch]); /** * Handle Retry * * Purpose: Handle retry after error */ const handleRetry = useCallback(() => { loadAIPredictions(); }, [loadAIPredictions]); // ============================================================================ // RENDER FUNCTIONS // ============================================================================ /** * Render AI Prediction Case * * Purpose: Render individual AI prediction case card */ const renderPredictionCase = useCallback(({ item }: { item: AIPredictionCase }) => ( ), [handleCasePress, handleCaseReview, selectedCaseIds, handleCaseSelection]); /** * Render List Header * * Purpose: Render search, filters, and statistics */ const renderListHeader = useCallback(() => ( {/* Statistics Overview */} {showStats && ( )} {/* Search Bar */} {/* Filter Controls */} Filters {activeFiltersCount > 0 && ( {activeFiltersCount} )} {selectedCaseIds.length > 0 && ( Review {selectedCaseIds.length} )} {/* Filter Tabs */} {showFilters && ( )} {/* Results Summary */} {statistics.total} predictions found {activeFiltersCount > 0 && ` (${activeFiltersCount} filters applied)`} ), [ showStats, statistics, handleStatsPress, searchQuery, handleSearch, showFilters, handleToggleFilters, activeFiltersCount, selectedCaseIds, handleBulkReview, urgencyFilter, severityFilter, categoryFilter, handleUrgencyFilterChange, handleSeverityFilterChange, handleCategoryFilterChange, handleClearFilters, filterCounts, ]); /** * Render List Footer * * Purpose: Render pagination controls */ const renderListFooter = useCallback(() => { if (totalPages <= 1) return null; return ( Previous Page {currentPage} of {totalPages} Next ); }, [totalPages, currentPage, hasPreviousPage, hasNextPage, handlePreviousPage, handleNextPage]); // ============================================================================ // RENDER // ============================================================================ return ( {/* Header */} AI Predictions setShowStats(!showStats)} accessibilityRole="button" accessibilityLabel="Toggle statistics" > {/* Content */} {error ? ( ) : isLoading && cases.length === 0 ? ( ) : cases.length === 0 ? ( 0 ? handleClearFilters : handleRefresh} /> ) : ( item.patid} ListHeaderComponent={renderListHeader} ListFooterComponent={renderListFooter} refreshControl={ } showsVerticalScrollIndicator={false} contentContainerStyle={styles.listContent} accessibilityRole="list" /> )} ); }; // ============================================================================ // STYLES // ============================================================================ const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: theme.colors.background, }, header: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', paddingHorizontal: theme.spacing.md, paddingVertical: theme.spacing.md, borderBottomWidth: 1, borderBottomColor: theme.colors.border, backgroundColor: theme.colors.background, }, headerTitle: { fontSize: theme.typography.fontSize.displaySmall, fontWeight: theme.typography.fontWeight.bold, color: theme.colors.textPrimary, }, headerButton: { padding: theme.spacing.sm, }, filterControls: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', paddingHorizontal: theme.spacing.md, paddingVertical: theme.spacing.sm, }, filterToggle: { flexDirection: 'row', alignItems: 'center', paddingHorizontal: theme.spacing.md, paddingVertical: theme.spacing.sm, borderRadius: theme.borderRadius.medium, borderWidth: 1, borderColor: theme.colors.primary, gap: theme.spacing.sm, }, filterToggleActive: { backgroundColor: theme.colors.primary, }, filterToggleText: { fontSize: theme.typography.fontSize.bodyMedium, color: theme.colors.primary, fontWeight: theme.typography.fontWeight.medium, }, filterToggleActiveText: { color: theme.colors.background, }, filterBadge: { backgroundColor: theme.colors.error, borderRadius: 10, minWidth: 20, height: 20, justifyContent: 'center', alignItems: 'center', }, filterBadgeText: { fontSize: theme.typography.fontSize.caption, color: theme.colors.background, fontWeight: theme.typography.fontWeight.bold, }, bulkActionButton: { flexDirection: 'row', alignItems: 'center', backgroundColor: theme.colors.primary, paddingHorizontal: theme.spacing.md, paddingVertical: theme.spacing.sm, borderRadius: theme.borderRadius.medium, gap: theme.spacing.sm, }, bulkActionText: { fontSize: theme.typography.fontSize.bodyMedium, color: theme.colors.background, fontWeight: theme.typography.fontWeight.medium, }, resultsSummary: { paddingHorizontal: theme.spacing.md, paddingVertical: theme.spacing.sm, }, resultsText: { fontSize: theme.typography.fontSize.bodyMedium, color: theme.colors.textSecondary, }, listContent: { paddingBottom: theme.spacing.xl, }, paginationContainer: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', paddingHorizontal: theme.spacing.md, paddingVertical: theme.spacing.lg, marginTop: theme.spacing.lg, }, paginationButton: { flexDirection: 'row', alignItems: 'center', paddingHorizontal: theme.spacing.md, paddingVertical: theme.spacing.sm, borderRadius: theme.borderRadius.medium, borderWidth: 1, borderColor: theme.colors.primary, gap: theme.spacing.xs, }, paginationButtonDisabled: { borderColor: theme.colors.textMuted, opacity: 0.5, }, paginationButtonText: { fontSize: theme.typography.fontSize.bodyMedium, color: theme.colors.primary, fontWeight: theme.typography.fontWeight.medium, }, paginationButtonTextDisabled: { color: theme.colors.textMuted, }, paginationInfo: { fontSize: theme.typography.fontSize.bodyMedium, color: theme.colors.textSecondary, fontWeight: theme.typography.fontWeight.medium, }, }); export default AIPredictionsScreen; /* * End of File: AIPredictionsScreen.tsx * Design & Developed by Tech4Biz Solutions * Copyright (c) Spurrin Innovations. All rights reserved. */