750 lines
22 KiB
TypeScript
750 lines
22 KiB
TypeScript
/*
|
|
* 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<AIPredictionsScreenProps> = ({ 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 }) => (
|
|
<AIPredictionCard
|
|
predictionCase={item}
|
|
onPress={handleCasePress}
|
|
onReview={handleCaseReview}
|
|
isSelected={selectedCaseIds.includes(item.patid)}
|
|
onToggleSelect={handleCaseSelection}
|
|
showReviewButton={true}
|
|
/>
|
|
), [handleCasePress, handleCaseReview, selectedCaseIds, handleCaseSelection]);
|
|
|
|
/**
|
|
* Render List Header
|
|
*
|
|
* Purpose: Render search, filters, and statistics
|
|
*/
|
|
const renderListHeader = useCallback(() => (
|
|
<View>
|
|
{/* Statistics Overview */}
|
|
{showStats && (
|
|
<StatsOverview
|
|
stats={{
|
|
totalCases: statistics.total,
|
|
criticalCases: statistics.critical,
|
|
urgentCases: 0, // Would need to be calculated from urgency filter
|
|
reviewedCases: statistics.reviewed,
|
|
pendingCases: statistics.pending,
|
|
averageConfidence: statistics.averageConfidence,
|
|
todaysCases: 0, // Would need to be calculated from today's data
|
|
weeklyTrend: 12.5, // Mock data
|
|
}}
|
|
onStatsPress={handleStatsPress}
|
|
/>
|
|
)}
|
|
|
|
{/* Search Bar */}
|
|
<SearchBar
|
|
value={searchQuery}
|
|
onChangeText={handleSearch}
|
|
placeholder="Search by patient ID, finding, location..."
|
|
/>
|
|
|
|
{/* Filter Controls */}
|
|
<View style={styles.filterControls}>
|
|
<TouchableOpacity
|
|
style={[styles.filterToggle, showFilters && styles.filterToggleActive]}
|
|
onPress={handleToggleFilters}
|
|
accessibilityRole="button"
|
|
accessibilityLabel="Toggle filters"
|
|
>
|
|
<Icon name="filter" size={18} color={showFilters ? theme.colors.background : theme.colors.primary} />
|
|
<Text style={[styles.filterToggleText, showFilters && styles.filterToggleActiveText]}>
|
|
Filters
|
|
</Text>
|
|
{activeFiltersCount > 0 && (
|
|
<View style={styles.filterBadge}>
|
|
<Text style={styles.filterBadgeText}>{activeFiltersCount}</Text>
|
|
</View>
|
|
)}
|
|
</TouchableOpacity>
|
|
|
|
{selectedCaseIds.length > 0 && (
|
|
<TouchableOpacity
|
|
style={styles.bulkActionButton}
|
|
onPress={handleBulkReview}
|
|
accessibilityRole="button"
|
|
accessibilityLabel={`Bulk actions for ${selectedCaseIds.length} selected cases`}
|
|
>
|
|
<Icon name="check-circle" size={18} color={theme.colors.background} />
|
|
<Text style={styles.bulkActionText}>
|
|
Review {selectedCaseIds.length}
|
|
</Text>
|
|
</TouchableOpacity>
|
|
)}
|
|
</View>
|
|
|
|
{/* Filter Tabs */}
|
|
{showFilters && (
|
|
<FilterTabs
|
|
selectedUrgencyFilter={urgencyFilter}
|
|
selectedSeverityFilter={severityFilter}
|
|
selectedCategoryFilter={categoryFilter}
|
|
onUrgencyFilterChange={handleUrgencyFilterChange}
|
|
onSeverityFilterChange={handleSeverityFilterChange}
|
|
onCategoryFilterChange={handleCategoryFilterChange}
|
|
onClearFilters={handleClearFilters}
|
|
filterCounts={filterCounts}
|
|
activeFiltersCount={activeFiltersCount}
|
|
/>
|
|
)}
|
|
|
|
{/* Results Summary */}
|
|
<View style={styles.resultsSummary}>
|
|
<Text style={styles.resultsText}>
|
|
{statistics.total} predictions found
|
|
{activeFiltersCount > 0 && ` (${activeFiltersCount} filters applied)`}
|
|
</Text>
|
|
</View>
|
|
</View>
|
|
), [
|
|
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 (
|
|
<View style={styles.paginationContainer}>
|
|
<TouchableOpacity
|
|
style={[styles.paginationButton, !hasPreviousPage && styles.paginationButtonDisabled]}
|
|
onPress={handlePreviousPage}
|
|
disabled={!hasPreviousPage}
|
|
accessibilityRole="button"
|
|
accessibilityLabel="Previous page"
|
|
>
|
|
<Icon name="chevron-left" size={20} color={hasPreviousPage ? theme.colors.primary : theme.colors.textMuted} />
|
|
<Text style={[styles.paginationButtonText, !hasPreviousPage && styles.paginationButtonTextDisabled]}>
|
|
Previous
|
|
</Text>
|
|
</TouchableOpacity>
|
|
|
|
<Text style={styles.paginationInfo}>
|
|
Page {currentPage} of {totalPages}
|
|
</Text>
|
|
|
|
<TouchableOpacity
|
|
style={[styles.paginationButton, !hasNextPage && styles.paginationButtonDisabled]}
|
|
onPress={handleNextPage}
|
|
disabled={!hasNextPage}
|
|
accessibilityRole="button"
|
|
accessibilityLabel="Next page"
|
|
>
|
|
<Text style={[styles.paginationButtonText, !hasNextPage && styles.paginationButtonTextDisabled]}>
|
|
Next
|
|
</Text>
|
|
<Icon name="chevron-right" size={20} color={hasNextPage ? theme.colors.primary : theme.colors.textMuted} />
|
|
</TouchableOpacity>
|
|
</View>
|
|
);
|
|
}, [totalPages, currentPage, hasPreviousPage, hasNextPage, handlePreviousPage, handleNextPage]);
|
|
|
|
// ============================================================================
|
|
// RENDER
|
|
// ============================================================================
|
|
|
|
return (
|
|
<SafeAreaView style={styles.container}>
|
|
<StatusBar barStyle="dark-content" backgroundColor={theme.colors.background} />
|
|
|
|
{/* Header */}
|
|
<View style={styles.header}>
|
|
<Text style={styles.headerTitle}>AI Predictions</Text>
|
|
<TouchableOpacity
|
|
style={styles.headerButton}
|
|
onPress={() => setShowStats(!showStats)}
|
|
accessibilityRole="button"
|
|
accessibilityLabel="Toggle statistics"
|
|
>
|
|
<Icon name={showStats ? 'eye-off' : 'eye'} size={20} color={theme.colors.primary} />
|
|
</TouchableOpacity>
|
|
</View>
|
|
|
|
{/* Content */}
|
|
{error ? (
|
|
<EmptyState
|
|
title="Error Loading Predictions"
|
|
message={error}
|
|
iconName="alert-circle"
|
|
actionText="Retry"
|
|
onAction={handleRetry}
|
|
/>
|
|
) : isLoading && cases.length === 0 ? (
|
|
<LoadingState message="Loading AI predictions..." />
|
|
) : cases.length === 0 ? (
|
|
<EmptyState
|
|
title="No AI Predictions Found"
|
|
message="There are no AI prediction cases matching your current filters."
|
|
iconName="brain"
|
|
actionText="Clear Filters"
|
|
onAction={activeFiltersCount > 0 ? handleClearFilters : handleRefresh}
|
|
/>
|
|
) : (
|
|
<FlatList
|
|
data={cases}
|
|
renderItem={renderPredictionCase}
|
|
keyExtractor={(item) => item.patid}
|
|
ListHeaderComponent={renderListHeader}
|
|
ListFooterComponent={renderListFooter}
|
|
refreshControl={
|
|
<RefreshControl
|
|
refreshing={refreshing}
|
|
onRefresh={handleRefresh}
|
|
colors={[theme.colors.primary]}
|
|
tintColor={theme.colors.primary}
|
|
/>
|
|
}
|
|
showsVerticalScrollIndicator={false}
|
|
contentContainerStyle={styles.listContent}
|
|
accessibilityRole="list"
|
|
/>
|
|
)}
|
|
</SafeAreaView>
|
|
);
|
|
};
|
|
|
|
// ============================================================================
|
|
// 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.
|
|
*/
|