diff --git a/app/modules/AIPrediction/__tests__/AIPredictionCard.test.tsx b/app/modules/AIPrediction/__tests__/AIPredictionCard.test.tsx
new file mode 100644
index 0000000..4c120e4
--- /dev/null
+++ b/app/modules/AIPrediction/__tests__/AIPredictionCard.test.tsx
@@ -0,0 +1,249 @@
+/*
+ * File: AIPredictionCard.test.tsx
+ * Description: Unit tests for AI Prediction Card component
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import React from 'react';
+import { render, fireEvent } from '@testing-library/react-native';
+import AIPredictionCard from '../components/AIPredictionCard';
+import type { AIPredictionCase } from '../types';
+
+// ============================================================================
+// MOCK DATA
+// ============================================================================
+
+const mockPredictionCase: AIPredictionCase = {
+ patid: 'test-patient-001',
+ hospital_id: 'hospital-123',
+ prediction: {
+ label: 'midline shift',
+ finding_type: 'pathology',
+ clinical_urgency: 'urgent',
+ confidence_score: 0.96,
+ finding_category: 'abnormal',
+ primary_severity: 'high',
+ anatomical_location: 'brain',
+ },
+ created_at: '2024-01-15T10:30:00Z',
+ updated_at: '2024-01-15T10:30:00Z',
+ review_status: 'pending',
+ priority: 'critical',
+};
+
+const mockProps = {
+ predictionCase: mockPredictionCase,
+ onPress: jest.fn(),
+ onReview: jest.fn(),
+ onToggleSelect: jest.fn(),
+ isSelected: false,
+ showReviewButton: true,
+};
+
+// ============================================================================
+// UNIT TESTS
+// ============================================================================
+
+describe('AIPredictionCard', () => {
+ beforeEach(() => {
+ jest.clearAllMocks();
+ });
+
+ // ============================================================================
+ // RENDERING TESTS
+ // ============================================================================
+
+ describe('Rendering', () => {
+ it('should render correctly with required props', () => {
+ const { getByText } = render(
+
+ );
+
+ expect(getByText('test-patient-001')).toBeTruthy();
+ expect(getByText('Midline Shift')).toBeTruthy();
+ expect(getByText('96%')).toBeTruthy();
+ expect(getByText('Urgent')).toBeTruthy();
+ });
+
+ it('should render review button when showReviewButton is true', () => {
+ const { getByText } = render();
+ expect(getByText('Review')).toBeTruthy();
+ });
+
+ it('should not render review button when showReviewButton is false', () => {
+ const { queryByText } = render(
+
+ );
+ expect(queryByText('Review')).toBeNull();
+ });
+
+ it('should not render review button when status is not pending', () => {
+ const reviewedCase = {
+ ...mockPredictionCase,
+ review_status: 'reviewed' as const,
+ };
+
+ const { queryByText } = render(
+
+ );
+ expect(queryByText('Review')).toBeNull();
+ });
+
+ it('should render selection checkbox when onToggleSelect is provided', () => {
+ const { getByRole } = render();
+ expect(getByRole('checkbox')).toBeTruthy();
+ });
+
+ it('should show selected state correctly', () => {
+ const { getByRole } = render(
+
+ );
+
+ const checkbox = getByRole('checkbox');
+ expect(checkbox.props.accessibilityState.checked).toBe(true);
+ });
+ });
+
+ // ============================================================================
+ // INTERACTION TESTS
+ // ============================================================================
+
+ describe('Interactions', () => {
+ it('should call onPress when card is pressed', () => {
+ const { getByRole } = render();
+
+ fireEvent.press(getByRole('button'));
+ expect(mockProps.onPress).toHaveBeenCalledWith(mockPredictionCase);
+ });
+
+ it('should call onReview when review button is pressed', () => {
+ const { getByText } = render();
+
+ fireEvent.press(getByText('Review'));
+ expect(mockProps.onReview).toHaveBeenCalledWith('test-patient-001');
+ });
+
+ it('should call onToggleSelect when checkbox is pressed', () => {
+ const { getByRole } = render();
+
+ fireEvent.press(getByRole('checkbox'));
+ expect(mockProps.onToggleSelect).toHaveBeenCalledWith('test-patient-001');
+ });
+ });
+
+ // ============================================================================
+ // DATA FORMATTING TESTS
+ // ============================================================================
+
+ describe('Data formatting', () => {
+ it('should format confidence score as percentage', () => {
+ const { getByText } = render();
+ expect(getByText('96%')).toBeTruthy();
+ });
+
+ it('should capitalize text correctly', () => {
+ const { getByText } = render();
+ expect(getByText('Midline Shift')).toBeTruthy();
+ expect(getByText('Pathology')).toBeTruthy();
+ expect(getByText('Abnormal')).toBeTruthy();
+ });
+
+ it('should handle missing anatomical location', () => {
+ const caseWithoutLocation = {
+ ...mockPredictionCase,
+ prediction: {
+ ...mockPredictionCase.prediction,
+ anatomical_location: 'not_applicable',
+ },
+ };
+
+ const { queryByText } = render(
+
+ );
+
+ // Should not render location when it's 'not_applicable'
+ expect(queryByText('Not Applicable')).toBeNull();
+ });
+ });
+
+ // ============================================================================
+ // ACCESSIBILITY TESTS
+ // ============================================================================
+
+ describe('Accessibility', () => {
+ it('should have proper accessibility labels', () => {
+ const { getByLabelText } = render();
+
+ expect(
+ getByLabelText('AI Prediction case for patient test-patient-001')
+ ).toBeTruthy();
+ });
+
+ it('should have proper accessibility hints', () => {
+ const { getByRole } = render();
+
+ const cardButton = getByRole('button');
+ expect(cardButton.props.accessibilityHint).toBe(
+ 'Tap to view detailed prediction information'
+ );
+ });
+ });
+
+ // ============================================================================
+ // EDGE CASES TESTS
+ // ============================================================================
+
+ describe('Edge cases', () => {
+ it('should handle missing dates gracefully', () => {
+ const caseWithoutDates = {
+ ...mockPredictionCase,
+ created_at: undefined,
+ updated_at: undefined,
+ };
+
+ const { getByText } = render(
+
+ );
+
+ expect(getByText('N/A')).toBeTruthy();
+ });
+
+ it('should handle emergency urgency with special styling', () => {
+ const emergencyCase = {
+ ...mockPredictionCase,
+ prediction: {
+ ...mockPredictionCase.prediction,
+ clinical_urgency: 'emergency' as const,
+ },
+ };
+
+ const { getByText } = render(
+
+ );
+
+ expect(getByText('Emergency')).toBeTruthy();
+ });
+ });
+});
+
+/*
+ * End of File: AIPredictionCard.test.tsx
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
diff --git a/app/modules/AIPrediction/__tests__/aiPredictionAPI.test.ts b/app/modules/AIPrediction/__tests__/aiPredictionAPI.test.ts
new file mode 100644
index 0000000..fb85b00
--- /dev/null
+++ b/app/modules/AIPrediction/__tests__/aiPredictionAPI.test.ts
@@ -0,0 +1,361 @@
+/*
+ * File: aiPredictionAPI.test.ts
+ * Description: Unit tests for AI Prediction API service
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import { aiPredictionAPI } from '../services/aiPredictionAPI';
+
+// Mock apisauce
+jest.mock('apisauce', () => ({
+ create: jest.fn(() => ({
+ get: jest.fn(),
+ post: jest.fn(),
+ put: jest.fn(),
+ delete: jest.fn(),
+ })),
+}));
+
+// Mock API utilities
+jest.mock('../../../shared/utils', () => ({
+ API_CONFIG: {
+ BASE_URL: 'https://test-api.com',
+ },
+ buildHeaders: jest.fn((options = {}) => ({
+ headers: {
+ 'Content-Type': 'application/json',
+ ...(options.token && { Authorization: `Bearer ${options.token}` }),
+ },
+ })),
+}));
+
+// ============================================================================
+// MOCK DATA
+// ============================================================================
+
+const mockToken = 'test-token-123';
+const mockResponse = {
+ ok: true,
+ data: {
+ success: true,
+ data: [
+ {
+ patid: 'test-001',
+ hospital_id: 'hospital-001',
+ prediction: {
+ label: 'test finding',
+ finding_type: 'pathology',
+ clinical_urgency: 'urgent',
+ confidence_score: 0.95,
+ finding_category: 'abnormal',
+ primary_severity: 'high',
+ anatomical_location: 'brain',
+ },
+ },
+ ],
+ },
+};
+
+// ============================================================================
+// UNIT TESTS
+// ============================================================================
+
+describe('AI Prediction API', () => {
+ let mockApi: any;
+
+ beforeEach(() => {
+ // Reset mocks
+ jest.clearAllMocks();
+
+ // Get the mocked API instance
+ const { create } = require('apisauce');
+ mockApi = create();
+ });
+
+ // ============================================================================
+ // GET ALL PREDICTIONS TESTS
+ // ============================================================================
+
+ describe('getAllPredictions', () => {
+ it('should call GET endpoint with correct parameters', async () => {
+ mockApi.get.mockResolvedValue(mockResponse);
+
+ const params = {
+ page: 1,
+ limit: 20,
+ urgency: 'urgent',
+ search: 'test',
+ };
+
+ await aiPredictionAPI.getAllPredictions(mockToken, params);
+
+ expect(mockApi.get).toHaveBeenCalledWith(
+ '/api/ai-cases/all-prediction-results',
+ params,
+ expect.objectContaining({
+ headers: expect.objectContaining({
+ Authorization: `Bearer ${mockToken}`,
+ }),
+ })
+ );
+ });
+
+ it('should call GET endpoint without parameters', async () => {
+ mockApi.get.mockResolvedValue(mockResponse);
+
+ await aiPredictionAPI.getAllPredictions(mockToken);
+
+ expect(mockApi.get).toHaveBeenCalledWith(
+ '/api/ai-cases/all-prediction-results',
+ {},
+ expect.objectContaining({
+ headers: expect.objectContaining({
+ Authorization: `Bearer ${mockToken}`,
+ }),
+ })
+ );
+ });
+ });
+
+ // ============================================================================
+ // GET CASE DETAILS TESTS
+ // ============================================================================
+
+ describe('getCaseDetails', () => {
+ it('should call GET endpoint with correct case ID', async () => {
+ const caseId = 'test-case-001';
+ mockApi.get.mockResolvedValue(mockResponse);
+
+ await aiPredictionAPI.getCaseDetails(caseId, mockToken);
+
+ expect(mockApi.get).toHaveBeenCalledWith(
+ `/api/ai-cases/prediction-details/${caseId}`,
+ {},
+ expect.objectContaining({
+ headers: expect.objectContaining({
+ Authorization: `Bearer ${mockToken}`,
+ }),
+ })
+ );
+ });
+ });
+
+ // ============================================================================
+ // UPDATE CASE REVIEW TESTS
+ // ============================================================================
+
+ describe('updateCaseReview', () => {
+ it('should call PUT endpoint with correct data', async () => {
+ const caseId = 'test-case-001';
+ const reviewData = {
+ review_status: 'reviewed' as const,
+ reviewed_by: 'Dr. Test',
+ review_notes: 'Test notes',
+ priority: 'high' as const,
+ };
+
+ mockApi.put.mockResolvedValue(mockResponse);
+
+ await aiPredictionAPI.updateCaseReview(caseId, reviewData, mockToken);
+
+ expect(mockApi.put).toHaveBeenCalledWith(
+ `/api/ai-cases/review/${caseId}`,
+ reviewData,
+ expect.objectContaining({
+ headers: expect.objectContaining({
+ Authorization: `Bearer ${mockToken}`,
+ }),
+ })
+ );
+ });
+ });
+
+ // ============================================================================
+ // GET STATISTICS TESTS
+ // ============================================================================
+
+ describe('getPredictionStats', () => {
+ it('should call GET endpoint with time range parameter', async () => {
+ mockApi.get.mockResolvedValue(mockResponse);
+
+ await aiPredictionAPI.getPredictionStats(mockToken, 'week');
+
+ expect(mockApi.get).toHaveBeenCalledWith(
+ '/api/ai-cases/statistics',
+ { timeRange: 'week' },
+ expect.objectContaining({
+ headers: expect.objectContaining({
+ Authorization: `Bearer ${mockToken}`,
+ }),
+ })
+ );
+ });
+
+ it('should call GET endpoint without time range parameter', async () => {
+ mockApi.get.mockResolvedValue(mockResponse);
+
+ await aiPredictionAPI.getPredictionStats(mockToken);
+
+ expect(mockApi.get).toHaveBeenCalledWith(
+ '/api/ai-cases/statistics',
+ {},
+ expect.objectContaining({
+ headers: expect.objectContaining({
+ Authorization: `Bearer ${mockToken}`,
+ }),
+ })
+ );
+ });
+ });
+
+ // ============================================================================
+ // SEARCH PREDICTIONS TESTS
+ // ============================================================================
+
+ describe('searchPredictions', () => {
+ it('should call GET endpoint with search query and filters', async () => {
+ const query = 'test search';
+ const filters = {
+ urgency: ['urgent', 'emergency'],
+ severity: ['high'],
+ dateRange: { start: '2024-01-01', end: '2024-01-31' },
+ };
+
+ mockApi.get.mockResolvedValue(mockResponse);
+
+ await aiPredictionAPI.searchPredictions(query, mockToken, filters);
+
+ expect(mockApi.get).toHaveBeenCalledWith(
+ '/api/ai-cases/search',
+ {
+ q: query,
+ filters: JSON.stringify(filters),
+ },
+ expect.objectContaining({
+ headers: expect.objectContaining({
+ Authorization: `Bearer ${mockToken}`,
+ }),
+ })
+ );
+ });
+
+ it('should call GET endpoint with only search query', async () => {
+ const query = 'test search';
+ mockApi.get.mockResolvedValue(mockResponse);
+
+ await aiPredictionAPI.searchPredictions(query, mockToken);
+
+ expect(mockApi.get).toHaveBeenCalledWith(
+ '/api/ai-cases/search',
+ { q: query },
+ expect.objectContaining({
+ headers: expect.objectContaining({
+ Authorization: `Bearer ${mockToken}`,
+ }),
+ })
+ );
+ });
+ });
+
+ // ============================================================================
+ // BULK OPERATIONS TESTS
+ // ============================================================================
+
+ describe('bulkUpdateReviews', () => {
+ it('should call PUT endpoint with case IDs and review data', async () => {
+ const caseIds = ['case-001', 'case-002', 'case-003'];
+ const reviewData = {
+ review_status: 'reviewed' as const,
+ reviewed_by: 'Dr. Test',
+ review_notes: 'Bulk review',
+ };
+
+ mockApi.put.mockResolvedValue(mockResponse);
+
+ await aiPredictionAPI.bulkUpdateReviews(caseIds, reviewData, mockToken);
+
+ expect(mockApi.put).toHaveBeenCalledWith(
+ '/api/ai-cases/bulk-review',
+ { caseIds, reviewData },
+ expect.objectContaining({
+ headers: expect.objectContaining({
+ Authorization: `Bearer ${mockToken}`,
+ }),
+ })
+ );
+ });
+ });
+
+ // ============================================================================
+ // SUBMIT FEEDBACK TESTS
+ // ============================================================================
+
+ describe('submitPredictionFeedback', () => {
+ it('should call POST endpoint with feedback data', async () => {
+ const caseId = 'test-case-001';
+ const feedbackData = {
+ accuracy_rating: 4 as const,
+ is_accurate: true,
+ physician_diagnosis: 'Confirmed midline shift',
+ feedback_notes: 'Accurate prediction',
+ improvement_suggestions: 'None',
+ };
+
+ mockApi.post.mockResolvedValue(mockResponse);
+
+ await aiPredictionAPI.submitPredictionFeedback(caseId, feedbackData, mockToken);
+
+ expect(mockApi.post).toHaveBeenCalledWith(
+ `/api/ai-cases/feedback/${caseId}`,
+ feedbackData,
+ expect.objectContaining({
+ headers: expect.objectContaining({
+ Authorization: `Bearer ${mockToken}`,
+ }),
+ })
+ );
+ });
+ });
+
+ // ============================================================================
+ // ERROR HANDLING TESTS
+ // ============================================================================
+
+ describe('Error handling', () => {
+ it('should handle API errors gracefully', async () => {
+ const errorResponse = {
+ ok: false,
+ problem: 'NETWORK_ERROR',
+ data: null,
+ };
+
+ mockApi.get.mockResolvedValue(errorResponse);
+
+ const result = await aiPredictionAPI.getAllPredictions(mockToken);
+ expect(result).toEqual(errorResponse);
+ });
+
+ it('should handle missing token', async () => {
+ mockApi.get.mockResolvedValue(mockResponse);
+
+ await aiPredictionAPI.getAllPredictions('');
+
+ expect(mockApi.get).toHaveBeenCalledWith(
+ '/api/ai-cases/all-prediction-results',
+ {},
+ expect.objectContaining({
+ headers: expect.objectContaining({
+ 'Content-Type': 'application/json',
+ }),
+ })
+ );
+ });
+ });
+});
+
+/*
+ * End of File: aiPredictionAPI.test.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
diff --git a/app/modules/AIPrediction/__tests__/aiPredictionSlice.test.ts b/app/modules/AIPrediction/__tests__/aiPredictionSlice.test.ts
new file mode 100644
index 0000000..7975d6c
--- /dev/null
+++ b/app/modules/AIPrediction/__tests__/aiPredictionSlice.test.ts
@@ -0,0 +1,231 @@
+/*
+ * File: aiPredictionSlice.test.ts
+ * Description: Unit tests for AI Prediction Redux slice
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import aiPredictionReducer, {
+ setSearchQuery,
+ setUrgencyFilter,
+ setSeverityFilter,
+ setCategoryFilter,
+ clearAllFilters,
+ toggleShowFilters,
+ clearError,
+} from '../redux/aiPredictionSlice';
+import type { AIPredictionState } from '../types';
+
+// ============================================================================
+// MOCK DATA
+// ============================================================================
+
+const initialState: AIPredictionState = {
+ predictionCases: [],
+ currentCase: null,
+ isLoading: false,
+ isRefreshing: false,
+ isLoadingCaseDetails: false,
+ error: null,
+ searchQuery: '',
+ selectedUrgencyFilter: 'all',
+ selectedSeverityFilter: 'all',
+ selectedCategoryFilter: 'all',
+ sortBy: 'date',
+ sortOrder: 'desc',
+ currentPage: 1,
+ itemsPerPage: 20,
+ totalItems: 0,
+ lastUpdated: null,
+ cacheExpiry: null,
+ showFilters: false,
+ selectedCaseIds: [],
+};
+
+// ============================================================================
+// UNIT TESTS
+// ============================================================================
+
+describe('AI Prediction Slice', () => {
+ // ============================================================================
+ // INITIAL STATE TESTS
+ // ============================================================================
+
+ it('should return the initial state', () => {
+ const result = aiPredictionReducer(undefined, { type: 'unknown' });
+ expect(result).toEqual(initialState);
+ });
+
+ // ============================================================================
+ // SEARCH TESTS
+ // ============================================================================
+
+ describe('Search functionality', () => {
+ it('should handle setSearchQuery', () => {
+ const searchQuery = 'test search';
+ const action = setSearchQuery(searchQuery);
+ const result = aiPredictionReducer(initialState, action);
+
+ expect(result.searchQuery).toBe(searchQuery);
+ expect(result.currentPage).toBe(1); // Should reset to first page
+ });
+
+ it('should handle empty search query', () => {
+ const state = { ...initialState, searchQuery: 'existing search' };
+ const action = setSearchQuery('');
+ const result = aiPredictionReducer(state, action);
+
+ expect(result.searchQuery).toBe('');
+ expect(result.currentPage).toBe(1);
+ });
+ });
+
+ // ============================================================================
+ // FILTER TESTS
+ // ============================================================================
+
+ describe('Filter functionality', () => {
+ it('should handle setUrgencyFilter', () => {
+ const filter = 'urgent';
+ const action = setUrgencyFilter(filter);
+ const result = aiPredictionReducer(initialState, action);
+
+ expect(result.selectedUrgencyFilter).toBe(filter);
+ expect(result.currentPage).toBe(1); // Should reset to first page
+ });
+
+ it('should handle setSeverityFilter', () => {
+ const filter = 'high';
+ const action = setSeverityFilter(filter);
+ const result = aiPredictionReducer(initialState, action);
+
+ expect(result.selectedSeverityFilter).toBe(filter);
+ expect(result.currentPage).toBe(1);
+ });
+
+ it('should handle setCategoryFilter', () => {
+ const filter = 'critical';
+ const action = setCategoryFilter(filter);
+ const result = aiPredictionReducer(initialState, action);
+
+ expect(result.selectedCategoryFilter).toBe(filter);
+ expect(result.currentPage).toBe(1);
+ });
+
+ it('should handle clearAllFilters', () => {
+ const state: AIPredictionState = {
+ ...initialState,
+ searchQuery: 'test',
+ selectedUrgencyFilter: 'urgent',
+ selectedSeverityFilter: 'high',
+ selectedCategoryFilter: 'critical',
+ currentPage: 3,
+ };
+
+ const action = clearAllFilters();
+ const result = aiPredictionReducer(state, action);
+
+ expect(result.searchQuery).toBe('');
+ expect(result.selectedUrgencyFilter).toBe('all');
+ expect(result.selectedSeverityFilter).toBe('all');
+ expect(result.selectedCategoryFilter).toBe('all');
+ expect(result.currentPage).toBe(1);
+ });
+ });
+
+ // ============================================================================
+ // UI STATE TESTS
+ // ============================================================================
+
+ describe('UI state functionality', () => {
+ it('should handle toggleShowFilters', () => {
+ const action = toggleShowFilters();
+
+ // Toggle from false to true
+ const result1 = aiPredictionReducer(initialState, action);
+ expect(result1.showFilters).toBe(true);
+
+ // Toggle from true to false
+ const result2 = aiPredictionReducer(result1, action);
+ expect(result2.showFilters).toBe(false);
+ });
+
+ it('should handle clearError', () => {
+ const state = { ...initialState, error: 'Test error' };
+ const action = clearError();
+ const result = aiPredictionReducer(state, action);
+
+ expect(result.error).toBe(null);
+ });
+ });
+
+ // ============================================================================
+ // ASYNC ACTION TESTS
+ // ============================================================================
+
+ describe('Async actions', () => {
+ it('should handle fetchAIPredictions.pending', () => {
+ const action = { type: 'aiPrediction/fetchAIPredictions/pending' };
+ const result = aiPredictionReducer(initialState, action);
+
+ expect(result.isLoading).toBe(true);
+ expect(result.error).toBe(null);
+ });
+
+ it('should handle fetchAIPredictions.fulfilled', () => {
+ const mockCases = [
+ {
+ patid: 'test-001',
+ hospital_id: 'hospital-001',
+ prediction: {
+ label: 'test finding',
+ finding_type: 'pathology' as const,
+ clinical_urgency: 'urgent' as const,
+ confidence_score: 0.95,
+ finding_category: 'abnormal' as const,
+ primary_severity: 'high' as const,
+ anatomical_location: 'brain',
+ },
+ },
+ ];
+
+ const action = {
+ type: 'aiPrediction/fetchAIPredictions/fulfilled',
+ payload: {
+ cases: mockCases,
+ total: 1,
+ page: 1,
+ limit: 20,
+ },
+ };
+
+ const result = aiPredictionReducer(initialState, action);
+
+ expect(result.isLoading).toBe(false);
+ expect(result.predictionCases).toEqual(mockCases);
+ expect(result.totalItems).toBe(1);
+ expect(result.error).toBe(null);
+ expect(result.lastUpdated).toBeInstanceOf(Date);
+ expect(result.cacheExpiry).toBeInstanceOf(Date);
+ });
+
+ it('should handle fetchAIPredictions.rejected', () => {
+ const errorMessage = 'Failed to fetch predictions';
+ const action = {
+ type: 'aiPrediction/fetchAIPredictions/rejected',
+ payload: errorMessage,
+ };
+
+ const result = aiPredictionReducer(initialState, action);
+
+ expect(result.isLoading).toBe(false);
+ expect(result.error).toBe(errorMessage);
+ });
+ });
+});
+
+/*
+ * End of File: aiPredictionSlice.test.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
diff --git a/app/modules/AIPrediction/components/AIPredictionCard.tsx b/app/modules/AIPrediction/components/AIPredictionCard.tsx
new file mode 100644
index 0000000..590d57a
--- /dev/null
+++ b/app/modules/AIPrediction/components/AIPredictionCard.tsx
@@ -0,0 +1,522 @@
+/*
+ * File: AIPredictionCard.tsx
+ * Description: Card component for displaying AI prediction case information
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import React from 'react';
+import {
+ View,
+ Text,
+ StyleSheet,
+ TouchableOpacity,
+ Dimensions,
+} from 'react-native';
+import Icon from 'react-native-vector-icons/Feather';
+import { theme } from '../../../theme';
+import { AIPredictionCase, URGENCY_COLORS, SEVERITY_COLORS, CATEGORY_COLORS } from '../types';
+
+// ============================================================================
+// INTERFACES
+// ============================================================================
+
+interface AIPredictionCardProps {
+ predictionCase: AIPredictionCase;
+ onPress: (predictionCase: AIPredictionCase) => void;
+ onReview?: (caseId: string) => void;
+ isSelected?: boolean;
+ onToggleSelect?: (caseId: string) => void;
+ showReviewButton?: boolean;
+}
+
+// ============================================================================
+// CONSTANTS
+// ============================================================================
+
+const { width } = Dimensions.get('window');
+const CARD_WIDTH = width - 32; // Full width with margins
+
+// ============================================================================
+// AI PREDICTION CARD COMPONENT
+// ============================================================================
+
+/**
+ * AIPredictionCard Component
+ *
+ * Purpose: Display AI prediction case information in a card format
+ *
+ * Features:
+ * - Patient ID and hospital information
+ * - AI prediction results with confidence score
+ * - Urgency and severity indicators
+ * - Review status and actions
+ * - Selection support for bulk operations
+ * - Modern card design with proper spacing
+ * - Color-coded priority indicators
+ * - Accessibility support
+ */
+const AIPredictionCard: React.FC = ({
+ predictionCase,
+ onPress,
+ onReview,
+ isSelected = false,
+ onToggleSelect,
+ showReviewButton = true,
+}) => {
+ // ============================================================================
+ // HELPER FUNCTIONS
+ // ============================================================================
+
+ /**
+ * Get Urgency Color
+ *
+ * Purpose: Get color based on clinical urgency
+ */
+ const getUrgencyColor = (urgency: string): string => {
+ return URGENCY_COLORS[urgency as keyof typeof URGENCY_COLORS] || theme.colors.textMuted;
+ };
+
+ /**
+ * Get Severity Color
+ *
+ * Purpose: Get color based on primary severity
+ */
+ const getSeverityColor = (severity: string): string => {
+ return SEVERITY_COLORS[severity as keyof typeof SEVERITY_COLORS] || theme.colors.textMuted;
+ };
+
+ /**
+ * Get Category Color
+ *
+ * Purpose: Get color based on finding category
+ */
+ const getCategoryColor = (category: string): string => {
+ return CATEGORY_COLORS[category as keyof typeof CATEGORY_COLORS] || theme.colors.textMuted;
+ };
+
+ /**
+ * Get Review Status Color
+ *
+ * Purpose: Get color based on review status
+ */
+ const getReviewStatusColor = (status: string): string => {
+ switch (status) {
+ case 'confirmed':
+ return theme.colors.success;
+ case 'reviewed':
+ return theme.colors.info;
+ case 'disputed':
+ return theme.colors.warning;
+ case 'pending':
+ default:
+ return theme.colors.error;
+ }
+ };
+
+ /**
+ * Format Confidence Score
+ *
+ * Purpose: Format confidence score as percentage
+ */
+ const formatConfidence = (score: number): string => {
+ return `${Math.round(score * 100)}%`;
+ };
+
+ /**
+ * Capitalize Text
+ *
+ * Purpose: Capitalize first letter of each word
+ */
+ const capitalize = (text: string): string => {
+ return text.split('_').map(word =>
+ word.charAt(0).toUpperCase() + word.slice(1)
+ ).join(' ');
+ };
+
+ /**
+ * Format Date
+ *
+ * Purpose: Format date for display
+ */
+ const formatDate = (dateString?: string): string => {
+ if (!dateString) return 'N/A';
+ try {
+ const date = new Date(dateString);
+ return date.toLocaleDateString('en-US', {
+ month: 'short',
+ day: 'numeric',
+ hour: '2-digit',
+ minute: '2-digit',
+ });
+ } catch {
+ return 'N/A';
+ }
+ };
+
+ // ============================================================================
+ // EVENT HANDLERS
+ // ============================================================================
+
+ /**
+ * Handle Card Press
+ *
+ * Purpose: Handle card tap to view details
+ */
+ const handleCardPress = () => {
+ onPress(predictionCase);
+ };
+
+ /**
+ * Handle Review Press
+ *
+ * Purpose: Handle review button press
+ */
+ const handleReviewPress = (event: any) => {
+ event.stopPropagation();
+ if (onReview) {
+ onReview(predictionCase.patid);
+ }
+ };
+
+ /**
+ * Handle Selection Toggle
+ *
+ * Purpose: Handle case selection toggle
+ */
+ const handleSelectionToggle = (event: any) => {
+ event.stopPropagation();
+ if (onToggleSelect) {
+ onToggleSelect(predictionCase.patid);
+ }
+ };
+
+ // ============================================================================
+ // RENDER
+ // ============================================================================
+
+ return (
+
+ {/* Header Section */}
+
+
+
+ {predictionCase.patid}
+
+
+ {formatDate(predictionCase.processed_at)}
+
+
+
+
+ {onToggleSelect && (
+
+
+
+ )}
+
+
+
+ {capitalize(predictionCase.prediction.clinical_urgency)}
+
+
+
+
+
+ {/* Prediction Information */}
+
+
+
+ {capitalize(predictionCase.prediction.label)}
+
+
+
+
+ {formatConfidence(predictionCase.prediction.confidence_score)}
+
+
+
+
+ {/* Finding Details */}
+
+
+ Type:
+
+ {capitalize(predictionCase.prediction.finding_type)}
+
+
+
+
+ Category:
+
+
+ {capitalize(predictionCase.prediction.finding_category)}
+
+
+
+
+
+ {/* Severity and Location */}
+
+
+
+
+ {capitalize(predictionCase.prediction.primary_severity)} Severity
+
+
+
+ {predictionCase.prediction.anatomical_location !== 'not_applicable' && (
+
+
+
+ {capitalize(predictionCase.prediction.anatomical_location)}
+
+
+ )}
+
+
+
+ {/* Footer Section */}
+
+
+
+
+ {capitalize(predictionCase.review_status || 'pending')}
+
+
+
+ {predictionCase.reviewed_by && (
+
+ by {predictionCase.reviewed_by}
+
+ )}
+
+
+ {showReviewButton && predictionCase.review_status === 'pending' && (
+
+
+ Review
+
+ )}
+
+
+ );
+};
+
+// ============================================================================
+// STYLES
+// ============================================================================
+
+const styles = StyleSheet.create({
+ container: {
+ backgroundColor: theme.colors.background,
+ borderRadius: theme.borderRadius.large,
+ padding: theme.spacing.lg,
+ marginHorizontal: theme.spacing.md,
+ marginVertical: theme.spacing.sm,
+ width: CARD_WIDTH,
+ ...theme.shadows.medium,
+ borderWidth: 1,
+ borderColor: theme.colors.border,
+ },
+ selectedContainer: {
+ borderColor: theme.colors.primary,
+ borderWidth: 2,
+ },
+ emergencyContainer: {
+ borderLeftWidth: 4,
+ borderLeftColor: URGENCY_COLORS.emergency,
+ },
+ header: {
+ flexDirection: 'row',
+ justifyContent: 'space-between',
+ alignItems: 'flex-start',
+ marginBottom: theme.spacing.md,
+ },
+ headerLeft: {
+ flex: 1,
+ },
+ headerRight: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ gap: theme.spacing.sm,
+ },
+ patientId: {
+ fontSize: theme.typography.fontSize.bodyLarge,
+ fontWeight: theme.typography.fontWeight.bold,
+ color: theme.colors.textPrimary,
+ marginBottom: theme.spacing.xs,
+ },
+ date: {
+ fontSize: theme.typography.fontSize.bodySmall,
+ color: theme.colors.textSecondary,
+ },
+ selectionButton: {
+ padding: theme.spacing.xs,
+ },
+ priorityBadge: {
+ paddingHorizontal: theme.spacing.sm,
+ paddingVertical: theme.spacing.xs,
+ borderRadius: theme.borderRadius.small,
+ },
+ priorityText: {
+ fontSize: theme.typography.fontSize.caption,
+ fontWeight: theme.typography.fontWeight.medium,
+ color: theme.colors.background,
+ },
+ predictionSection: {
+ marginBottom: theme.spacing.md,
+ },
+ predictionHeader: {
+ flexDirection: 'row',
+ justifyContent: 'space-between',
+ alignItems: 'flex-start',
+ marginBottom: theme.spacing.sm,
+ },
+ predictionLabel: {
+ fontSize: theme.typography.fontSize.bodyLarge,
+ fontWeight: theme.typography.fontWeight.medium,
+ color: theme.colors.textPrimary,
+ flex: 1,
+ marginRight: theme.spacing.sm,
+ },
+ confidenceContainer: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ gap: theme.spacing.xs,
+ },
+ confidenceText: {
+ fontSize: theme.typography.fontSize.bodyMedium,
+ fontWeight: theme.typography.fontWeight.medium,
+ color: theme.colors.primary,
+ },
+ findingDetails: {
+ marginBottom: theme.spacing.sm,
+ },
+ findingItem: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ justifyContent: 'space-between',
+ marginBottom: theme.spacing.xs,
+ },
+ findingLabel: {
+ fontSize: theme.typography.fontSize.bodyMedium,
+ color: theme.colors.textSecondary,
+ fontWeight: theme.typography.fontWeight.medium,
+ },
+ findingValue: {
+ fontSize: theme.typography.fontSize.bodyMedium,
+ color: theme.colors.textPrimary,
+ },
+ categoryBadge: {
+ paddingHorizontal: theme.spacing.sm,
+ paddingVertical: theme.spacing.xs,
+ borderRadius: theme.borderRadius.small,
+ },
+ categoryText: {
+ fontSize: theme.typography.fontSize.caption,
+ fontWeight: theme.typography.fontWeight.medium,
+ color: theme.colors.background,
+ },
+ detailsRow: {
+ flexDirection: 'row',
+ justifyContent: 'space-between',
+ alignItems: 'center',
+ },
+ detailItem: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ gap: theme.spacing.xs,
+ flex: 1,
+ },
+ detailText: {
+ fontSize: theme.typography.fontSize.bodySmall,
+ color: theme.colors.textSecondary,
+ },
+ footer: {
+ flexDirection: 'row',
+ justifyContent: 'space-between',
+ alignItems: 'center',
+ paddingTop: theme.spacing.sm,
+ borderTopWidth: 1,
+ borderTopColor: theme.colors.border,
+ },
+ footerLeft: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ gap: theme.spacing.sm,
+ flex: 1,
+ },
+ reviewStatusBadge: {
+ paddingHorizontal: theme.spacing.sm,
+ paddingVertical: theme.spacing.xs,
+ borderRadius: theme.borderRadius.small,
+ },
+ reviewStatusText: {
+ fontSize: theme.typography.fontSize.caption,
+ fontWeight: theme.typography.fontWeight.medium,
+ color: theme.colors.background,
+ },
+ reviewedBy: {
+ fontSize: theme.typography.fontSize.caption,
+ color: theme.colors.textMuted,
+ fontStyle: 'italic',
+ },
+ reviewButton: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ gap: theme.spacing.xs,
+ paddingHorizontal: theme.spacing.sm,
+ paddingVertical: theme.spacing.xs,
+ borderRadius: theme.borderRadius.small,
+ borderWidth: 1,
+ borderColor: theme.colors.primary,
+ },
+ reviewButtonText: {
+ fontSize: theme.typography.fontSize.bodySmall,
+ color: theme.colors.primary,
+ fontWeight: theme.typography.fontWeight.medium,
+ },
+});
+
+export default AIPredictionCard;
+
+/*
+ * End of File: AIPredictionCard.tsx
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
diff --git a/app/modules/AIPrediction/components/EmptyState.tsx b/app/modules/AIPrediction/components/EmptyState.tsx
new file mode 100644
index 0000000..81b26d7
--- /dev/null
+++ b/app/modules/AIPrediction/components/EmptyState.tsx
@@ -0,0 +1,287 @@
+/*
+ * File: EmptyState.tsx
+ * Description: Empty state component for AI predictions
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import React from 'react';
+import {
+ View,
+ Text,
+ StyleSheet,
+ TouchableOpacity,
+ Dimensions,
+} from 'react-native';
+import Icon from 'react-native-vector-icons/Feather';
+import { theme } from '../../../theme';
+
+// ============================================================================
+// INTERFACES
+// ============================================================================
+
+interface EmptyStateProps {
+ title?: string;
+ message?: string;
+ iconName?: string;
+ actionText?: string;
+ onAction?: () => void;
+ style?: any;
+ showRefreshButton?: boolean;
+ onRefresh?: () => void;
+}
+
+// ============================================================================
+// CONSTANTS
+// ============================================================================
+
+const { width, height } = Dimensions.get('window');
+
+// ============================================================================
+// EMPTY STATE COMPONENT
+// ============================================================================
+
+/**
+ * EmptyState Component
+ *
+ * Purpose: Display empty state for AI predictions
+ *
+ * Features:
+ * - Customizable title and message
+ * - Icon display with customizable icon
+ * - Optional action button
+ * - Refresh functionality
+ * - Responsive design
+ * - Modern empty state design
+ * - Accessibility support
+ */
+const EmptyState: React.FC = ({
+ title = 'No AI Predictions Found',
+ message = 'There are no AI prediction cases available at the moment. Try adjusting your filters or refresh to see new predictions.',
+ iconName = 'brain',
+ actionText = 'Refresh',
+ onAction,
+ style,
+ showRefreshButton = true,
+ onRefresh,
+}) => {
+ // ============================================================================
+ // EVENT HANDLERS
+ // ============================================================================
+
+ /**
+ * Handle Action Press
+ *
+ * Purpose: Handle action button press
+ */
+ const handleActionPress = () => {
+ if (onAction) {
+ onAction();
+ } else if (onRefresh) {
+ onRefresh();
+ }
+ };
+
+ // ============================================================================
+ // RENDER
+ // ============================================================================
+
+ return (
+
+ {/* Empty State Icon */}
+
+
+
+
+ {/* Empty State Title */}
+
+ {title}
+
+
+ {/* Empty State Message */}
+
+ {message}
+
+
+ {/* Action Buttons */}
+
+ {/* Primary Action Button */}
+ {(onAction || onRefresh) && (
+
+
+
+ {actionText}
+
+
+ )}
+
+ {/* Secondary Refresh Button */}
+ {showRefreshButton && onRefresh && !onAction && (
+
+
+
+ Refresh Data
+
+
+ )}
+
+
+ {/* Suggestions */}
+
+ Try:
+
+
+
+ Clearing search filters
+
+
+
+ Adjusting filter criteria
+
+
+
+ Refreshing the data
+
+
+
+
+ );
+};
+
+// ============================================================================
+// STYLES
+// ============================================================================
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ justifyContent: 'center',
+ alignItems: 'center',
+ paddingHorizontal: theme.spacing.xl,
+ paddingVertical: theme.spacing.xxl,
+ minHeight: height * 0.4,
+ },
+ iconContainer: {
+ width: 120,
+ height: 120,
+ borderRadius: 60,
+ backgroundColor: theme.colors.backgroundAlt,
+ justifyContent: 'center',
+ alignItems: 'center',
+ marginBottom: theme.spacing.xl,
+ ...theme.shadows.small,
+ },
+ icon: {
+ opacity: 0.6,
+ },
+ title: {
+ fontSize: theme.typography.fontSize.displaySmall,
+ fontWeight: theme.typography.fontWeight.bold,
+ color: theme.colors.textPrimary,
+ textAlign: 'center',
+ marginBottom: theme.spacing.md,
+ },
+ message: {
+ fontSize: theme.typography.fontSize.bodyLarge,
+ color: theme.colors.textSecondary,
+ textAlign: 'center',
+ lineHeight: theme.typography.lineHeight.relaxed * theme.typography.fontSize.bodyLarge,
+ marginBottom: theme.spacing.xl,
+ maxWidth: width * 0.8,
+ },
+ buttonsContainer: {
+ flexDirection: 'row',
+ gap: theme.spacing.md,
+ marginBottom: theme.spacing.xl,
+ },
+ actionButton: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ backgroundColor: theme.colors.primary,
+ paddingHorizontal: theme.spacing.lg,
+ paddingVertical: theme.spacing.md,
+ borderRadius: theme.borderRadius.medium,
+ gap: theme.spacing.sm,
+ ...theme.shadows.medium,
+ },
+ actionButtonText: {
+ fontSize: theme.typography.fontSize.bodyMedium,
+ fontWeight: theme.typography.fontWeight.medium,
+ color: theme.colors.background,
+ },
+ secondaryButton: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ backgroundColor: 'transparent',
+ borderWidth: 1,
+ borderColor: theme.colors.primary,
+ paddingHorizontal: theme.spacing.lg,
+ paddingVertical: theme.spacing.md,
+ borderRadius: theme.borderRadius.medium,
+ gap: theme.spacing.sm,
+ },
+ secondaryButtonText: {
+ fontSize: theme.typography.fontSize.bodyMedium,
+ fontWeight: theme.typography.fontWeight.medium,
+ color: theme.colors.primary,
+ },
+ buttonIcon: {
+ // No additional styles needed
+ },
+ suggestionsContainer: {
+ alignItems: 'center',
+ maxWidth: width * 0.8,
+ },
+ suggestionsTitle: {
+ fontSize: theme.typography.fontSize.bodyMedium,
+ fontWeight: theme.typography.fontWeight.medium,
+ color: theme.colors.textSecondary,
+ marginBottom: theme.spacing.sm,
+ },
+ suggestionsList: {
+ gap: theme.spacing.sm,
+ },
+ suggestionItem: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ gap: theme.spacing.sm,
+ paddingVertical: theme.spacing.xs,
+ },
+ suggestionText: {
+ fontSize: theme.typography.fontSize.bodyMedium,
+ color: theme.colors.textMuted,
+ },
+});
+
+export default EmptyState;
+
+/*
+ * End of File: EmptyState.tsx
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
diff --git a/app/modules/AIPrediction/components/FilterTabs.tsx b/app/modules/AIPrediction/components/FilterTabs.tsx
new file mode 100644
index 0000000..3c1c82d
--- /dev/null
+++ b/app/modules/AIPrediction/components/FilterTabs.tsx
@@ -0,0 +1,368 @@
+/*
+ * File: FilterTabs.tsx
+ * Description: Filter tabs component for AI predictions
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import React from 'react';
+import {
+ View,
+ Text,
+ StyleSheet,
+ TouchableOpacity,
+ ScrollView,
+ Dimensions,
+} from 'react-native';
+import Icon from 'react-native-vector-icons/Feather';
+import { theme } from '../../../theme';
+import type { AIPredictionState } from '../types';
+
+// ============================================================================
+// INTERFACES
+// ============================================================================
+
+interface FilterTabsProps {
+ selectedUrgencyFilter: AIPredictionState['selectedUrgencyFilter'];
+ selectedSeverityFilter: AIPredictionState['selectedSeverityFilter'];
+ selectedCategoryFilter: AIPredictionState['selectedCategoryFilter'];
+ onUrgencyFilterChange: (filter: AIPredictionState['selectedUrgencyFilter']) => void;
+ onSeverityFilterChange: (filter: AIPredictionState['selectedSeverityFilter']) => void;
+ onCategoryFilterChange: (filter: AIPredictionState['selectedCategoryFilter']) => void;
+ onClearFilters: () => void;
+ filterCounts?: {
+ urgency: Record;
+ severity: Record;
+ category: Record;
+ };
+ activeFiltersCount?: number;
+}
+
+interface FilterOption {
+ label: string;
+ value: string;
+ count?: number;
+ color?: string;
+}
+
+// ============================================================================
+// CONSTANTS
+// ============================================================================
+
+const { width } = Dimensions.get('window');
+
+const URGENCY_FILTERS: FilterOption[] = [
+ { label: 'All', value: 'all' },
+ { label: 'Emergency', value: 'emergency', color: '#F44336' },
+ { label: 'Urgent', value: 'urgent', color: '#FF5722' },
+ { label: 'Moderate', value: 'moderate', color: '#FF9800' },
+ { label: 'Low', value: 'low', color: '#FFC107' },
+ { label: 'Routine', value: 'routine', color: '#4CAF50' },
+];
+
+const SEVERITY_FILTERS: FilterOption[] = [
+ { label: 'All', value: 'all' },
+ { label: 'High', value: 'high', color: '#F44336' },
+ { label: 'Medium', value: 'medium', color: '#FF9800' },
+ { label: 'Low', value: 'low', color: '#FFC107' },
+ { label: 'None', value: 'none', color: '#4CAF50' },
+];
+
+const CATEGORY_FILTERS: FilterOption[] = [
+ { label: 'All', value: 'all' },
+ { label: 'Critical', value: 'critical', color: '#F44336' },
+ { label: 'Abnormal', value: 'abnormal', color: '#FF9800' },
+ { label: 'Warning', value: 'warning', color: '#FFC107' },
+ { label: 'Normal', value: 'normal', color: '#4CAF50' },
+ { label: 'Unknown', value: 'unknown', color: '#9E9E9E' },
+];
+
+// ============================================================================
+// FILTER TABS COMPONENT
+// ============================================================================
+
+/**
+ * FilterTabs Component
+ *
+ * Purpose: Provide filtering functionality for AI predictions
+ *
+ * Features:
+ * - Multiple filter categories (urgency, severity, category)
+ * - Visual filter counts
+ * - Active filter indicators
+ * - Clear all filters functionality
+ * - Color-coded filter options
+ * - Horizontal scroll support
+ * - Responsive design
+ * - Accessibility support
+ */
+const FilterTabs: React.FC = ({
+ selectedUrgencyFilter,
+ selectedSeverityFilter,
+ selectedCategoryFilter,
+ onUrgencyFilterChange,
+ onSeverityFilterChange,
+ onCategoryFilterChange,
+ onClearFilters,
+ filterCounts,
+ activeFiltersCount = 0,
+}) => {
+ // ============================================================================
+ // HELPER FUNCTIONS
+ // ============================================================================
+
+ /**
+ * Get Filter Count
+ *
+ * Purpose: Get count for specific filter value
+ */
+ const getFilterCount = (category: 'urgency' | 'severity' | 'category', value: string): number => {
+ return filterCounts?.[category]?.[value] || 0;
+ };
+
+ /**
+ * Render Filter Tab
+ *
+ * Purpose: Render individual filter tab
+ */
+ const renderFilterTab = (
+ option: FilterOption,
+ isSelected: boolean,
+ onPress: () => void,
+ category: 'urgency' | 'severity' | 'category'
+ ) => {
+ const count = getFilterCount(category, option.value);
+
+ return (
+ 0 ? `, ${count} items` : ''}`}
+ >
+ {option.color && isSelected && (
+
+ )}
+
+
+ {option.label}
+
+
+ {count > 0 && (
+
+
+ {count}
+
+
+ )}
+
+ );
+ };
+
+ // ============================================================================
+ // RENDER
+ // ============================================================================
+
+ return (
+
+ {/* Header with Clear Filters */}
+
+ Filters
+
+ {activeFiltersCount > 0 && (
+
+
+ Clear All
+
+ )}
+
+
+ {/* Urgency Filters */}
+
+ Clinical Urgency
+
+ {URGENCY_FILTERS.map((option) =>
+ renderFilterTab(
+ { ...option, count: getFilterCount('urgency', option.value) },
+ selectedUrgencyFilter === option.value,
+ () => onUrgencyFilterChange(option.value as AIPredictionState['selectedUrgencyFilter']),
+ 'urgency'
+ )
+ )}
+
+
+
+ {/* Severity Filters */}
+
+ Primary Severity
+
+ {SEVERITY_FILTERS.map((option) =>
+ renderFilterTab(
+ { ...option, count: getFilterCount('severity', option.value) },
+ selectedSeverityFilter === option.value,
+ () => onSeverityFilterChange(option.value as AIPredictionState['selectedSeverityFilter']),
+ 'severity'
+ )
+ )}
+
+
+
+ {/* Category Filters */}
+
+ Finding Category
+
+ {CATEGORY_FILTERS.map((option) =>
+ renderFilterTab(
+ { ...option, count: getFilterCount('category', option.value) },
+ selectedCategoryFilter === option.value,
+ () => onCategoryFilterChange(option.value as AIPredictionState['selectedCategoryFilter']),
+ 'category'
+ )
+ )}
+
+
+
+ );
+};
+
+// ============================================================================
+// STYLES
+// ============================================================================
+
+const styles = StyleSheet.create({
+ container: {
+ backgroundColor: theme.colors.background,
+ paddingVertical: theme.spacing.md,
+ },
+ header: {
+ flexDirection: 'row',
+ justifyContent: 'space-between',
+ alignItems: 'center',
+ paddingHorizontal: theme.spacing.md,
+ marginBottom: theme.spacing.md,
+ },
+ headerTitle: {
+ fontSize: theme.typography.fontSize.bodyLarge,
+ fontWeight: theme.typography.fontWeight.bold,
+ color: theme.colors.textPrimary,
+ },
+ clearButton: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ gap: theme.spacing.xs,
+ paddingHorizontal: theme.spacing.sm,
+ paddingVertical: theme.spacing.xs,
+ borderRadius: theme.borderRadius.small,
+ borderWidth: 1,
+ borderColor: theme.colors.primary,
+ },
+ clearButtonText: {
+ fontSize: theme.typography.fontSize.bodySmall,
+ color: theme.colors.primary,
+ fontWeight: theme.typography.fontWeight.medium,
+ },
+ filterSection: {
+ marginBottom: theme.spacing.lg,
+ },
+ sectionTitle: {
+ fontSize: theme.typography.fontSize.bodyMedium,
+ fontWeight: theme.typography.fontWeight.medium,
+ color: theme.colors.textSecondary,
+ paddingHorizontal: theme.spacing.md,
+ marginBottom: theme.spacing.sm,
+ },
+ filterRow: {
+ paddingHorizontal: theme.spacing.md,
+ gap: theme.spacing.sm,
+ },
+ filterTab: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ paddingHorizontal: theme.spacing.md,
+ paddingVertical: theme.spacing.sm,
+ borderRadius: theme.borderRadius.medium,
+ borderWidth: 1,
+ borderColor: theme.colors.border,
+ backgroundColor: theme.colors.background,
+ gap: theme.spacing.xs,
+ },
+ selectedFilterTab: {
+ borderColor: theme.colors.primary,
+ backgroundColor: theme.colors.backgroundAccent,
+ },
+ colorIndicator: {
+ width: 8,
+ height: 8,
+ borderRadius: 4,
+ },
+ filterTabText: {
+ fontSize: theme.typography.fontSize.bodyMedium,
+ color: theme.colors.textSecondary,
+ fontWeight: theme.typography.fontWeight.medium,
+ },
+ selectedFilterTabText: {
+ color: theme.colors.primary,
+ fontWeight: theme.typography.fontWeight.bold,
+ },
+ countBadge: {
+ backgroundColor: theme.colors.textMuted,
+ borderRadius: theme.borderRadius.small,
+ paddingHorizontal: theme.spacing.xs,
+ paddingVertical: 2,
+ minWidth: 20,
+ alignItems: 'center',
+ },
+ selectedCountBadge: {
+ backgroundColor: theme.colors.primary,
+ },
+ countText: {
+ fontSize: theme.typography.fontSize.caption,
+ color: theme.colors.background,
+ fontWeight: theme.typography.fontWeight.bold,
+ },
+ selectedCountText: {
+ color: theme.colors.background,
+ },
+});
+
+export default FilterTabs;
+
+/*
+ * End of File: FilterTabs.tsx
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
diff --git a/app/modules/AIPrediction/components/LoadingState.tsx b/app/modules/AIPrediction/components/LoadingState.tsx
new file mode 100644
index 0000000..4331d7c
--- /dev/null
+++ b/app/modules/AIPrediction/components/LoadingState.tsx
@@ -0,0 +1,139 @@
+/*
+ * File: LoadingState.tsx
+ * Description: Loading state component for AI predictions
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import React from 'react';
+import {
+ View,
+ Text,
+ StyleSheet,
+ ActivityIndicator,
+ Dimensions,
+} from 'react-native';
+import { theme } from '../../../theme';
+
+// ============================================================================
+// INTERFACES
+// ============================================================================
+
+interface LoadingStateProps {
+ message?: string;
+ showSpinner?: boolean;
+ size?: 'small' | 'large';
+ style?: any;
+}
+
+// ============================================================================
+// CONSTANTS
+// ============================================================================
+
+const { width, height } = Dimensions.get('window');
+
+// ============================================================================
+// LOADING STATE COMPONENT
+// ============================================================================
+
+/**
+ * LoadingState Component
+ *
+ * Purpose: Display loading state for AI predictions
+ *
+ * Features:
+ * - Customizable loading message
+ * - Optional spinner display
+ * - Different spinner sizes
+ * - Custom styling support
+ * - Centered layout
+ * - Accessibility support
+ */
+const LoadingState: React.FC = ({
+ message = 'Loading AI predictions...',
+ showSpinner = true,
+ size = 'large',
+ style,
+}) => {
+ // ============================================================================
+ // RENDER
+ // ============================================================================
+
+ return (
+
+ {/* Loading Spinner */}
+ {showSpinner && (
+
+ )}
+
+ {/* Loading Message */}
+
+ {message}
+
+
+ {/* Loading Animation Dots */}
+
+
+
+
+
+
+ );
+};
+
+// ============================================================================
+// STYLES
+// ============================================================================
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ justifyContent: 'center',
+ alignItems: 'center',
+ paddingHorizontal: theme.spacing.xl,
+ paddingVertical: theme.spacing.xxl,
+ minHeight: height * 0.3,
+ },
+ spinner: {
+ marginBottom: theme.spacing.lg,
+ },
+ message: {
+ fontSize: theme.typography.fontSize.bodyLarge,
+ color: theme.colors.textSecondary,
+ textAlign: 'center',
+ fontWeight: theme.typography.fontWeight.medium,
+ marginBottom: theme.spacing.xl,
+ },
+ dotsContainer: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ gap: theme.spacing.sm,
+ },
+ dot: {
+ width: 8,
+ height: 8,
+ borderRadius: 4,
+ backgroundColor: theme.colors.primary,
+ },
+ dot1: {
+ opacity: 0.3,
+ },
+ dot2: {
+ opacity: 0.6,
+ },
+ dot3: {
+ opacity: 1,
+ },
+});
+
+export default LoadingState;
+
+/*
+ * End of File: LoadingState.tsx
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
diff --git a/app/modules/AIPrediction/components/SearchBar.tsx b/app/modules/AIPrediction/components/SearchBar.tsx
new file mode 100644
index 0000000..46af82a
--- /dev/null
+++ b/app/modules/AIPrediction/components/SearchBar.tsx
@@ -0,0 +1,226 @@
+/*
+ * File: SearchBar.tsx
+ * Description: Search bar component for filtering AI predictions
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import React, { useState, useCallback } from 'react';
+import {
+ View,
+ TextInput,
+ StyleSheet,
+ TouchableOpacity,
+ Dimensions,
+} from 'react-native';
+import Icon from 'react-native-vector-icons/Feather';
+import { theme } from '../../../theme';
+
+// ============================================================================
+// INTERFACES
+// ============================================================================
+
+interface SearchBarProps {
+ value: string;
+ onChangeText: (text: string) => void;
+ onClear?: () => void;
+ placeholder?: string;
+ autoFocus?: boolean;
+ disabled?: boolean;
+}
+
+// ============================================================================
+// CONSTANTS
+// ============================================================================
+
+const { width } = Dimensions.get('window');
+
+// ============================================================================
+// SEARCH BAR COMPONENT
+// ============================================================================
+
+/**
+ * SearchBar Component
+ *
+ * Purpose: Provide search functionality for AI predictions
+ *
+ * Features:
+ * - Real-time search input
+ * - Clear button functionality
+ * - Customizable placeholder text
+ * - Auto-focus support
+ * - Disabled state support
+ * - Modern design with icons
+ * - Responsive width
+ * - Accessibility support
+ */
+const SearchBar: React.FC = ({
+ value,
+ onChangeText,
+ onClear,
+ placeholder = 'Search predictions...',
+ autoFocus = false,
+ disabled = false,
+}) => {
+ // ============================================================================
+ // STATE
+ // ============================================================================
+
+ const [isFocused, setIsFocused] = useState(false);
+
+ // ============================================================================
+ // EVENT HANDLERS
+ // ============================================================================
+
+ /**
+ * Handle Focus
+ *
+ * Purpose: Handle input focus state
+ */
+ const handleFocus = useCallback(() => {
+ setIsFocused(true);
+ }, []);
+
+ /**
+ * Handle Blur
+ *
+ * Purpose: Handle input blur state
+ */
+ const handleBlur = useCallback(() => {
+ setIsFocused(false);
+ }, []);
+
+ /**
+ * Handle Clear
+ *
+ * Purpose: Clear search input
+ */
+ const handleClear = useCallback(() => {
+ onChangeText('');
+ if (onClear) {
+ onClear();
+ }
+ }, [onChangeText, onClear]);
+
+ /**
+ * Handle Text Change
+ *
+ * Purpose: Handle search text input
+ */
+ const handleTextChange = useCallback((text: string) => {
+ onChangeText(text);
+ }, [onChangeText]);
+
+ // ============================================================================
+ // RENDER
+ // ============================================================================
+
+ return (
+
+ {/* Search Icon */}
+
+
+ {/* Text Input */}
+
+
+ {/* Clear Button */}
+ {value.length > 0 && !disabled && (
+
+
+
+ )}
+
+ );
+};
+
+// ============================================================================
+// STYLES
+// ============================================================================
+
+const styles = StyleSheet.create({
+ container: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ backgroundColor: theme.colors.background,
+ borderWidth: 1,
+ borderColor: theme.colors.border,
+ borderRadius: theme.borderRadius.medium,
+ paddingHorizontal: theme.spacing.md,
+ paddingVertical: theme.spacing.sm,
+ marginHorizontal: theme.spacing.md,
+ marginVertical: theme.spacing.sm,
+ ...theme.shadows.small,
+ },
+ focusedContainer: {
+ borderColor: theme.colors.primary,
+ backgroundColor: theme.colors.background,
+ },
+ disabledContainer: {
+ backgroundColor: theme.colors.backgroundAlt,
+ opacity: 0.6,
+ },
+ searchIcon: {
+ marginRight: theme.spacing.sm,
+ },
+ input: {
+ flex: 1,
+ fontSize: theme.typography.fontSize.bodyMedium,
+ color: theme.colors.textPrimary,
+ paddingVertical: 0, // Remove default padding to maintain consistent height
+ fontFamily: theme.typography.fontFamily.regular,
+ },
+ disabledInput: {
+ color: theme.colors.textMuted,
+ },
+ clearButton: {
+ marginLeft: theme.spacing.sm,
+ padding: theme.spacing.xs,
+ },
+});
+
+export default SearchBar;
+
+/*
+ * End of File: SearchBar.tsx
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
diff --git a/app/modules/AIPrediction/components/StatsOverview.tsx b/app/modules/AIPrediction/components/StatsOverview.tsx
new file mode 100644
index 0000000..17a4e03
--- /dev/null
+++ b/app/modules/AIPrediction/components/StatsOverview.tsx
@@ -0,0 +1,454 @@
+/*
+ * File: StatsOverview.tsx
+ * Description: Statistics overview component for AI predictions dashboard
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import React from 'react';
+import {
+ View,
+ Text,
+ StyleSheet,
+ TouchableOpacity,
+ Dimensions,
+} from 'react-native';
+import Icon from 'react-native-vector-icons/Feather';
+import { theme } from '../../../theme';
+import type { AIPredictionStats } from '../types';
+
+// ============================================================================
+// INTERFACES
+// ============================================================================
+
+interface StatsOverviewProps {
+ stats: AIPredictionStats;
+ onStatsPress?: (statType: string) => void;
+ isLoading?: boolean;
+ style?: any;
+}
+
+interface StatCardProps {
+ title: string;
+ value: string | number;
+ subtitle?: string;
+ iconName: string;
+ color: string;
+ onPress?: () => void;
+ trend?: number;
+ isPercentage?: boolean;
+}
+
+// ============================================================================
+// CONSTANTS
+// ============================================================================
+
+const { width } = Dimensions.get('window');
+const CARD_WIDTH = (width - 48) / 2; // Two cards per row with margins
+
+// ============================================================================
+// STAT CARD COMPONENT
+// ============================================================================
+
+/**
+ * StatCard Component
+ *
+ * Purpose: Individual statistics card
+ */
+const StatCard: React.FC = ({
+ title,
+ value,
+ subtitle,
+ iconName,
+ color,
+ onPress,
+ trend,
+ isPercentage = false,
+}) => {
+ const displayValue = typeof value === 'number'
+ ? isPercentage
+ ? `${Math.round(value * 100)}%`
+ : value.toLocaleString()
+ : value;
+
+ return (
+
+ {/* Card Header */}
+
+
+
+
+
+ {displayValue}
+
+
+
+ {trend !== undefined && (
+
+ = 0 ? 'trending-up' : 'trending-down'}
+ size={14}
+ color={trend >= 0 ? theme.colors.success : theme.colors.error}
+ />
+ = 0 ? theme.colors.success : theme.colors.error }
+ ]}>
+ {Math.abs(trend).toFixed(1)}%
+
+
+ )}
+
+
+ {/* Card Content */}
+
+
+ {title}
+ {subtitle && (
+ {subtitle}
+ )}
+
+
+ );
+};
+
+// ============================================================================
+// STATS OVERVIEW COMPONENT
+// ============================================================================
+
+/**
+ * StatsOverview Component
+ *
+ * Purpose: Display comprehensive AI predictions statistics
+ *
+ * Features:
+ * - Total cases overview
+ * - Critical and urgent case counts
+ * - Review progress tracking
+ * - Average confidence metrics
+ * - Trend indicators
+ * - Interactive stat cards
+ * - Responsive grid layout
+ * - Modern card design
+ * - Accessibility support
+ */
+const StatsOverview: React.FC = ({
+ stats,
+ onStatsPress,
+ isLoading = false,
+ style,
+}) => {
+ // ============================================================================
+ // EVENT HANDLERS
+ // ============================================================================
+
+ /**
+ * Handle Stat Press
+ *
+ * Purpose: Handle statistics card press
+ */
+ const handleStatPress = (statType: string) => {
+ if (onStatsPress) {
+ onStatsPress(statType);
+ }
+ };
+
+ // ============================================================================
+ // RENDER
+ // ============================================================================
+
+ if (isLoading) {
+ return (
+
+
+ AI Predictions Overview
+
+
+ Loading statistics...
+
+
+ );
+ }
+
+ return (
+
+ {/* Section Header */}
+
+ AI Predictions Overview
+ handleStatPress('all')}
+ accessibilityRole="button"
+ accessibilityLabel="View all statistics"
+ >
+ View All
+
+
+
+
+ {/* Statistics Grid */}
+
+ {/* Total Cases */}
+ handleStatPress('total')}
+ />
+
+ {/* Critical Cases */}
+ handleStatPress('critical')}
+ />
+
+ {/* Urgent Cases */}
+ handleStatPress('urgent')}
+ />
+
+ {/* Reviewed Cases */}
+ handleStatPress('reviewed')}
+ />
+
+ {/* Pending Cases */}
+ handleStatPress('pending')}
+ />
+
+ {/* Average Confidence */}
+ handleStatPress('confidence')}
+ isPercentage={true}
+ />
+
+ {/* Today's Cases */}
+ handleStatPress('today')}
+ />
+
+ {/* Weekly Trend */}
+ = 0 ? '+' : ''}${stats.weeklyTrend.toFixed(1)}%`}
+ subtitle="vs last week"
+ iconName={stats.weeklyTrend >= 0 ? 'trending-up' : 'trending-down'}
+ color={stats.weeklyTrend >= 0 ? theme.colors.success : theme.colors.error}
+ onPress={() => handleStatPress('trend')}
+ trend={stats.weeklyTrend}
+ />
+
+
+ {/* Summary Section */}
+
+
+
+
+ Quick Insights
+
+
+
+
+ Review Progress:
+
+ {Math.round((stats.reviewedCases / stats.totalCases) * 100)}%
+
+
+
+
+ Critical Rate:
+
+ {Math.round((stats.criticalCases / stats.totalCases) * 100)}%
+
+
+
+
+ Daily Average:
+
+ {Math.round(stats.totalCases / 7)} cases
+
+
+
+
+
+
+ );
+};
+
+// ============================================================================
+// STYLES
+// ============================================================================
+
+const styles = StyleSheet.create({
+ container: {
+ backgroundColor: theme.colors.background,
+ paddingVertical: theme.spacing.lg,
+ },
+ header: {
+ flexDirection: 'row',
+ justifyContent: 'space-between',
+ alignItems: 'center',
+ paddingHorizontal: theme.spacing.md,
+ marginBottom: theme.spacing.lg,
+ },
+ sectionTitle: {
+ fontSize: theme.typography.fontSize.displaySmall,
+ fontWeight: theme.typography.fontWeight.bold,
+ color: theme.colors.textPrimary,
+ },
+ viewAllButton: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ gap: theme.spacing.xs,
+ },
+ viewAllText: {
+ fontSize: theme.typography.fontSize.bodyMedium,
+ color: theme.colors.primary,
+ fontWeight: theme.typography.fontWeight.medium,
+ },
+ loadingContainer: {
+ paddingVertical: theme.spacing.xxl,
+ alignItems: 'center',
+ },
+ loadingText: {
+ fontSize: theme.typography.fontSize.bodyMedium,
+ color: theme.colors.textMuted,
+ },
+ statsGrid: {
+ flexDirection: 'row',
+ flexWrap: 'wrap',
+ paddingHorizontal: theme.spacing.md,
+ gap: theme.spacing.md,
+ },
+ statCard: {
+ width: CARD_WIDTH,
+ backgroundColor: theme.colors.background,
+ borderRadius: theme.borderRadius.medium,
+ borderLeftWidth: 4,
+ padding: theme.spacing.md,
+ ...theme.shadows.medium,
+ },
+ cardHeader: {
+ flexDirection: 'row',
+ justifyContent: 'space-between',
+ alignItems: 'center',
+ marginBottom: theme.spacing.sm,
+ },
+ iconContainer: {
+ width: 36,
+ height: 36,
+ borderRadius: 18,
+ justifyContent: 'center',
+ alignItems: 'center',
+ },
+ trendContainer: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ gap: theme.spacing.xs,
+ },
+ trendText: {
+ fontSize: theme.typography.fontSize.caption,
+ fontWeight: theme.typography.fontWeight.medium,
+ },
+ cardContent: {
+ gap: theme.spacing.xs,
+ },
+ statValue: {
+ fontSize: theme.typography.fontSize.displayMedium,
+ fontWeight: theme.typography.fontWeight.bold,
+ color: theme.colors.textPrimary,
+ },
+ statTitle: {
+ fontSize: theme.typography.fontSize.bodyMedium,
+ color: theme.colors.textSecondary,
+ fontWeight: theme.typography.fontWeight.medium,
+ },
+ statSubtitle: {
+ fontSize: theme.typography.fontSize.bodySmall,
+ color: theme.colors.textMuted,
+ },
+ summarySection: {
+ paddingHorizontal: theme.spacing.md,
+ marginTop: theme.spacing.lg,
+ },
+ summaryCard: {
+ backgroundColor: theme.colors.background,
+ borderRadius: theme.borderRadius.medium,
+ padding: theme.spacing.lg,
+ ...theme.shadows.small,
+ },
+ summaryHeader: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ gap: theme.spacing.sm,
+ marginBottom: theme.spacing.md,
+ },
+ summaryTitle: {
+ fontSize: theme.typography.fontSize.bodyLarge,
+ fontWeight: theme.typography.fontWeight.bold,
+ color: theme.colors.textPrimary,
+ },
+ summaryContent: {
+ gap: theme.spacing.sm,
+ },
+ summaryItem: {
+ flexDirection: 'row',
+ justifyContent: 'space-between',
+ alignItems: 'center',
+ },
+ summaryLabel: {
+ fontSize: theme.typography.fontSize.bodyMedium,
+ color: theme.colors.textSecondary,
+ },
+ summaryValue: {
+ fontSize: theme.typography.fontSize.bodyMedium,
+ fontWeight: theme.typography.fontWeight.bold,
+ color: theme.colors.textPrimary,
+ },
+});
+
+export default StatsOverview;
+
+/*
+ * End of File: StatsOverview.tsx
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
diff --git a/app/modules/AIPrediction/components/index.ts b/app/modules/AIPrediction/components/index.ts
new file mode 100644
index 0000000..dbc9ef2
--- /dev/null
+++ b/app/modules/AIPrediction/components/index.ts
@@ -0,0 +1,19 @@
+/*
+ * File: index.ts
+ * Description: Components exports for AI Prediction module
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+export { default as AIPredictionCard } from './AIPredictionCard';
+export { default as SearchBar } from './SearchBar';
+export { default as FilterTabs } from './FilterTabs';
+export { default as LoadingState } from './LoadingState';
+export { default as EmptyState } from './EmptyState';
+export { default as StatsOverview } from './StatsOverview';
+
+/*
+ * End of File: index.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
diff --git a/app/modules/AIPrediction/hooks/index.ts b/app/modules/AIPrediction/hooks/index.ts
new file mode 100644
index 0000000..592bfb7
--- /dev/null
+++ b/app/modules/AIPrediction/hooks/index.ts
@@ -0,0 +1,14 @@
+/*
+ * File: index.ts
+ * Description: Hooks exports for AI Prediction module
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+export * from './useAIPredictions';
+
+/*
+ * End of File: index.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
diff --git a/app/modules/AIPrediction/hooks/useAIPredictions.ts b/app/modules/AIPrediction/hooks/useAIPredictions.ts
new file mode 100644
index 0000000..613b0b4
--- /dev/null
+++ b/app/modules/AIPrediction/hooks/useAIPredictions.ts
@@ -0,0 +1,383 @@
+/*
+ * File: useAIPredictions.ts
+ * Description: Custom hook for AI Predictions functionality
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import { useCallback, useEffect, useMemo } from 'react';
+import { useAppDispatch, useAppSelector } from '../../../store/hooks';
+
+// Import Redux actions and selectors
+import {
+ fetchAIPredictions,
+ setSearchQuery,
+ setUrgencyFilter,
+ setSeverityFilter,
+ setCategoryFilter,
+ clearAllFilters,
+ updateCaseReview,
+} from '../redux';
+
+import {
+ selectPaginatedCases,
+ selectIsLoading,
+ selectError,
+ selectSearchQuery,
+ selectUrgencyFilter,
+ selectSeverityFilter,
+ selectCategoryFilter,
+ selectCasesStatistics,
+ selectActiveFiltersCount,
+ selectCurrentPage,
+ selectTotalPages,
+} from '../redux';
+
+// Import auth selector
+import { selectUser } from '../../Auth/redux/authSelectors';
+
+// Import types
+import type { AIPredictionState } from '../types';
+
+// ============================================================================
+// INTERFACES
+// ============================================================================
+
+interface UseAIPredictionsOptions {
+ autoLoad?: boolean;
+ refreshInterval?: number;
+}
+
+interface UseAIPredictionsReturn {
+ // Data
+ cases: ReturnType;
+ statistics: ReturnType;
+
+ // Loading states
+ isLoading: boolean;
+ error: string | null;
+
+ // Filters
+ searchQuery: string;
+ urgencyFilter: AIPredictionState['selectedUrgencyFilter'];
+ severityFilter: AIPredictionState['selectedSeverityFilter'];
+ categoryFilter: AIPredictionState['selectedCategoryFilter'];
+ activeFiltersCount: number;
+
+ // Pagination
+ currentPage: number;
+ totalPages: number;
+
+ // Actions
+ loadPredictions: () => Promise;
+ refreshPredictions: () => Promise;
+ setSearch: (query: string) => void;
+ setUrgency: (filter: AIPredictionState['selectedUrgencyFilter']) => void;
+ setSeverity: (filter: AIPredictionState['selectedSeverityFilter']) => void;
+ setCategory: (filter: AIPredictionState['selectedCategoryFilter']) => void;
+ clearFilters: () => void;
+ reviewCase: (caseId: string, reviewData?: Partial<{
+ review_status: 'pending' | 'reviewed' | 'confirmed' | 'disputed';
+ reviewed_by: string;
+ review_notes: string;
+ priority: 'critical' | 'high' | 'medium' | 'low';
+ }>) => Promise;
+
+ // Computed properties
+ hasFilters: boolean;
+ isEmpty: boolean;
+ hasError: boolean;
+}
+
+// ============================================================================
+// USE AI PREDICTIONS HOOK
+// ============================================================================
+
+/**
+ * useAIPredictions Hook
+ *
+ * Purpose: Custom hook for managing AI predictions state and actions
+ *
+ * Features:
+ * - Automatic data loading on mount
+ * - Search and filtering functionality
+ * - Case review management
+ * - Error handling
+ * - Loading states
+ * - Computed properties for UI state
+ * - Auto-refresh capability
+ * - Type-safe actions and selectors
+ */
+export const useAIPredictions = (options: UseAIPredictionsOptions = {}): UseAIPredictionsReturn => {
+ const {
+ autoLoad = true,
+ refreshInterval,
+ } = options;
+
+ // ============================================================================
+ // REDUX STATE
+ // ============================================================================
+
+ const dispatch = useAppDispatch();
+
+ // Auth state
+ const user = useAppSelector(selectUser);
+
+ // AI Predictions state
+ const cases = useAppSelector(selectPaginatedCases);
+ const statistics = useAppSelector(selectCasesStatistics);
+ 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 activeFiltersCount = useAppSelector(selectActiveFiltersCount);
+ const currentPage = useAppSelector(selectCurrentPage);
+ const totalPages = useAppSelector(selectTotalPages);
+
+ // ============================================================================
+ // MEMOIZED VALUES
+ // ============================================================================
+
+ /**
+ * Has Filters
+ *
+ * Purpose: Check if any filters are active
+ */
+ const hasFilters = useMemo(() => activeFiltersCount > 0, [activeFiltersCount]);
+
+ /**
+ * Is Empty
+ *
+ * Purpose: Check if the cases list is empty
+ */
+ const isEmpty = useMemo(() => cases.length === 0, [cases.length]);
+
+ /**
+ * Has Error
+ *
+ * Purpose: Check if there's an error
+ */
+ const hasError = useMemo(() => error !== null, [error]);
+
+ // ============================================================================
+ // ACTIONS
+ // ============================================================================
+
+ /**
+ * Load Predictions
+ *
+ * Purpose: Load AI predictions from API
+ */
+ const loadPredictions = useCallback(async () => {
+
+ if (!user?.access_token) {
+ throw new Error('User not authenticated');
+ }
+
+ 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);
+ throw error;
+ }
+ }, [
+ dispatch,
+ user?.access_token,
+ currentPage,
+ urgencyFilter,
+ severityFilter,
+ categoryFilter,
+ searchQuery,
+ ]);
+
+ /**
+ * Refresh Predictions
+ *
+ * Purpose: Refresh AI predictions data
+ */
+ const refreshPredictions = useCallback(async () => {
+ await loadPredictions();
+ }, [loadPredictions]);
+
+ /**
+ * Set Search
+ *
+ * Purpose: Set search query
+ */
+ const setSearch = useCallback((query: string) => {
+ dispatch(setSearchQuery(query));
+ }, [dispatch]);
+
+ /**
+ * Set Urgency Filter
+ *
+ * Purpose: Set urgency filter
+ */
+ const setUrgency = useCallback((filter: AIPredictionState['selectedUrgencyFilter']) => {
+ dispatch(setUrgencyFilter(filter));
+ }, [dispatch]);
+
+ /**
+ * Set Severity Filter
+ *
+ * Purpose: Set severity filter
+ */
+ const setSeverity = useCallback((filter: AIPredictionState['selectedSeverityFilter']) => {
+ dispatch(setSeverityFilter(filter));
+ }, [dispatch]);
+
+ /**
+ * Set Category Filter
+ *
+ * Purpose: Set category filter
+ */
+ const setCategory = useCallback((filter: AIPredictionState['selectedCategoryFilter']) => {
+ dispatch(setCategoryFilter(filter));
+ }, [dispatch]);
+
+ /**
+ * Clear Filters
+ *
+ * Purpose: Clear all active filters
+ */
+ const clearFilters = useCallback(() => {
+ dispatch(clearAllFilters());
+ }, [dispatch]);
+
+ /**
+ * Review Case
+ *
+ * Purpose: Update case review status
+ */
+ const reviewCase = useCallback(async (
+ caseId: string,
+ reviewData: Partial<{
+ review_status: 'pending' | 'reviewed' | 'confirmed' | 'disputed';
+ reviewed_by: string;
+ review_notes: string;
+ priority: 'critical' | 'high' | 'medium' | 'low';
+ }> = {}
+ ) => {
+ if (!user?.access_token) {
+ throw new Error('User not authenticated');
+ }
+
+ try {
+ const defaultReviewData = {
+ review_status: 'reviewed' as const,
+ reviewed_by: user.display_name || user.email || 'Current User',
+ ...reviewData,
+ };
+
+ await dispatch(updateCaseReview({
+ caseId,
+ reviewData: defaultReviewData,
+ token: user.access_token,
+ })).unwrap();
+ } catch (error) {
+ console.error('Failed to review case:', error);
+ throw error;
+ }
+ }, [dispatch, user]);
+
+ // ============================================================================
+ // EFFECTS
+ // ============================================================================
+
+ /**
+ * Auto-load Effect
+ *
+ * Purpose: Automatically load predictions on mount if enabled
+ */
+ useEffect(() => {
+ if (autoLoad && user?.access_token) {
+ loadPredictions().catch(console.error);
+ }
+ }, [autoLoad, user?.access_token, loadPredictions]);
+
+ /**
+ * Auto-refresh Effect
+ *
+ * Purpose: Set up auto-refresh interval if specified
+ */
+ useEffect(() => {
+ if (!refreshInterval || !user?.access_token) return;
+
+ const interval = setInterval(() => {
+ loadPredictions().catch(console.error);
+ }, refreshInterval);
+
+ return () => clearInterval(interval);
+ }, [refreshInterval, user?.access_token, loadPredictions]);
+
+ /**
+ * Filter Change Effect
+ *
+ * Purpose: Reload data when filters change
+ */
+ useEffect(() => {
+ if (user?.access_token) {
+ loadPredictions().catch(console.error);
+ }
+ }, [urgencyFilter, severityFilter, categoryFilter, searchQuery, currentPage]);
+
+ // ============================================================================
+ // RETURN
+ // ============================================================================
+
+ return {
+ // Data
+ cases,
+ statistics,
+
+ // Loading states
+ isLoading,
+ error,
+
+ // Filters
+ searchQuery,
+ urgencyFilter,
+ severityFilter,
+ categoryFilter,
+ activeFiltersCount,
+
+ // Pagination
+ currentPage,
+ totalPages,
+
+ // Actions
+ loadPredictions,
+ refreshPredictions,
+ setSearch,
+ setUrgency,
+ setSeverity,
+ setCategory,
+ clearFilters,
+ reviewCase,
+
+ // Computed properties
+ hasFilters,
+ isEmpty,
+ hasError,
+ };
+};
+
+/*
+ * End of File: useAIPredictions.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
diff --git a/app/modules/AIPrediction/index.ts b/app/modules/AIPrediction/index.ts
new file mode 100644
index 0000000..920e1d5
--- /dev/null
+++ b/app/modules/AIPrediction/index.ts
@@ -0,0 +1,54 @@
+/*
+ * File: index.ts
+ * Description: Main exports for AI Prediction module
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+// ============================================================================
+// COMPONENT EXPORTS
+// ============================================================================
+
+export * from './components';
+
+// ============================================================================
+// SCREEN EXPORTS
+// ============================================================================
+
+export * from './screens';
+
+// ============================================================================
+// NAVIGATION EXPORTS
+// ============================================================================
+
+export * from './navigation';
+
+// ============================================================================
+// REDUX EXPORTS
+// ============================================================================
+
+export * from './redux';
+
+// ============================================================================
+// SERVICE EXPORTS
+// ============================================================================
+
+export * from './services';
+
+// ============================================================================
+// TYPE EXPORTS
+// ============================================================================
+
+export * from './types';
+
+// ============================================================================
+// HOOK EXPORTS
+// ============================================================================
+
+export * from './hooks';
+
+/*
+ * End of File: index.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
diff --git a/app/modules/AIPrediction/navigation/AIPredictionStackNavigator.tsx b/app/modules/AIPrediction/navigation/AIPredictionStackNavigator.tsx
new file mode 100644
index 0000000..20c1bbe
--- /dev/null
+++ b/app/modules/AIPrediction/navigation/AIPredictionStackNavigator.tsx
@@ -0,0 +1,244 @@
+/*
+ * File: AIPredictionStackNavigator.tsx
+ * Description: Stack navigator for AI Prediction module screens
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import React from 'react';
+import { createStackNavigator } from '@react-navigation/stack';
+import { TouchableOpacity, Text, StyleSheet } from 'react-native';
+import Icon from 'react-native-vector-icons/Feather';
+import { theme } from '../../../theme';
+
+// Import screens
+import { AIPredictionsScreen } from '../screens';
+import { ComingSoonScreen } from '../../../shared/components';
+
+// Import types
+import type { AIPredictionStackParamList } from './navigationTypes';
+
+// ============================================================================
+// STACK NAVIGATOR SETUP
+// ============================================================================
+
+const Stack = createStackNavigator();
+
+// ============================================================================
+// HEADER COMPONENTS
+// ============================================================================
+
+/**
+ * Header Back Button
+ *
+ * Purpose: Custom back button for navigation header
+ */
+const HeaderBackButton: React.FC<{ onPress: () => void }> = ({ onPress }) => (
+
+
+
+);
+
+/**
+ * Header Action Button
+ *
+ * Purpose: Custom action button for navigation header
+ */
+const HeaderActionButton: React.FC<{
+ iconName: string;
+ onPress: () => void;
+ accessibilityLabel?: string;
+}> = ({ iconName, onPress, accessibilityLabel }) => (
+
+
+
+);
+
+// ============================================================================
+// SCREEN OPTIONS
+// ============================================================================
+
+/**
+ * Default Screen Options
+ *
+ * Purpose: Common screen options for all AI prediction screens
+ */
+const defaultScreenOptions = {
+ headerStyle: {
+ backgroundColor: theme.colors.background,
+ elevation: 2,
+ shadowOpacity: 0.1,
+ shadowRadius: 4,
+ shadowOffset: { width: 0, height: 2 },
+ borderBottomWidth: 1,
+ borderBottomColor: theme.colors.border,
+ },
+ headerTitleStyle: {
+ fontSize: theme.typography.fontSize.bodyLarge,
+ fontWeight: theme.typography.fontWeight.bold,
+ color: theme.colors.textPrimary,
+ },
+ headerTintColor: theme.colors.textPrimary,
+ headerBackTitleVisible: false,
+ gestureEnabled: true,
+ cardStyleInterpolator: ({ current, layouts }: any) => {
+ return {
+ cardStyle: {
+ transform: [
+ {
+ translateX: current.progress.interpolate({
+ inputRange: [0, 1],
+ outputRange: [layouts.screen.width, 0],
+ }),
+ },
+ ],
+ },
+ };
+ },
+};
+
+// ============================================================================
+// AI PREDICTION STACK NAVIGATOR COMPONENT
+// ============================================================================
+
+/**
+ * AIPredictionStackNavigator Component
+ *
+ * Purpose: Stack navigator for AI prediction module
+ *
+ * Features:
+ * - AI Prediction List screen (main screen)
+ * - AI Prediction Details screen (case details)
+ * - AI Prediction Filters screen (advanced filtering)
+ * - AI Prediction Stats screen (detailed statistics)
+ * - Custom header styling and buttons
+ * - Smooth navigation transitions
+ * - Accessibility support
+ * - Coming soon screens for unimplemented features
+ */
+const AIPredictionStackNavigator: React.FC = () => {
+ return (
+
+ {/* AI Prediction List Screen */}
+ ({
+ title: 'AI Predictions',
+ headerLeft: () => null, // No back button on main screen
+ headerRight: () => (
+ {
+ // Open options menu
+ // For now, just navigate to stats
+ // @ts-ignore
+ navigation.navigate('AIPredictionStats');
+ }}
+ accessibilityLabel="More options"
+ />
+ ),
+ })}
+ />
+
+ {/* AI Prediction Details Screen */}
+ ({
+ title: 'Prediction Details',
+ headerLeft: () => (
+ navigation.goBack()} />
+ ),
+ headerRight: () => (
+ {
+ // Share prediction details
+ console.log('Share prediction:', route.params?.caseId);
+ }}
+ accessibilityLabel="Share prediction"
+ />
+ ),
+ })}
+ />
+
+ {/* AI Prediction Filters Screen */}
+ ({
+ title: 'Advanced Filters',
+ headerLeft: () => (
+ navigation.goBack()} />
+ ),
+ headerRight: () => (
+ {
+ // Reset filters
+ console.log('Reset filters');
+ }}
+ accessibilityLabel="Reset filters"
+ />
+ ),
+ })}
+ />
+
+ {/* AI Prediction Stats Screen */}
+ ({
+ title: 'Statistics',
+ headerLeft: () => (
+ navigation.goBack()} />
+ ),
+ headerRight: () => (
+ {
+ // Export statistics
+ console.log('Export stats:', route.params?.timeRange);
+ }}
+ accessibilityLabel="Export statistics"
+ />
+ ),
+ })}
+ />
+
+ );
+};
+
+// ============================================================================
+// STYLES
+// ============================================================================
+
+const styles = StyleSheet.create({
+ headerButton: {
+ paddingHorizontal: theme.spacing.md,
+ paddingVertical: theme.spacing.sm,
+ marginHorizontal: theme.spacing.xs,
+ },
+ headerButtonText: {
+ fontSize: theme.typography.fontSize.bodyMedium,
+ color: theme.colors.primary,
+ fontWeight: theme.typography.fontWeight.medium,
+ },
+});
+
+export default AIPredictionStackNavigator;
+
+/*
+ * End of File: AIPredictionStackNavigator.tsx
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
diff --git a/app/modules/AIPrediction/navigation/index.ts b/app/modules/AIPrediction/navigation/index.ts
new file mode 100644
index 0000000..5094ddf
--- /dev/null
+++ b/app/modules/AIPrediction/navigation/index.ts
@@ -0,0 +1,16 @@
+/*
+ * File: index.ts
+ * Description: Navigation exports for AI Prediction module
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+export { default as AIPredictionStackNavigator } from './AIPredictionStackNavigator';
+export * from './navigationTypes';
+export * from './navigationUtils';
+
+/*
+ * End of File: index.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
diff --git a/app/modules/AIPrediction/navigation/navigationTypes.ts b/app/modules/AIPrediction/navigation/navigationTypes.ts
new file mode 100644
index 0000000..e590439
--- /dev/null
+++ b/app/modules/AIPrediction/navigation/navigationTypes.ts
@@ -0,0 +1,169 @@
+/*
+ * File: navigationTypes.ts
+ * Description: Navigation type definitions for AI Prediction module
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import type { StackNavigationProp } from '@react-navigation/stack';
+import type { RouteProp } from '@react-navigation/native';
+
+// ============================================================================
+// AI PREDICTION STACK PARAM LIST
+// ============================================================================
+
+/**
+ * AI Prediction Stack Param List
+ *
+ * Purpose: Define navigation parameters for AI prediction screens
+ *
+ * Screens:
+ * - AIPredictionList: Main list of AI predictions
+ * - AIPredictionDetails: Detailed view of a specific prediction
+ * - AIPredictionFilters: Advanced filtering options
+ * - AIPredictionStats: Detailed statistics view
+ */
+export type AIPredictionStackParamList = {
+ AIPredictionList: undefined;
+ AIPredictionDetails: { caseId: string };
+ AIPredictionFilters: undefined;
+ AIPredictionStats: { timeRange?: 'today' | 'week' | 'month' };
+};
+
+// ============================================================================
+// NAVIGATION PROP TYPES
+// ============================================================================
+
+/**
+ * AI Prediction List Navigation Prop
+ *
+ * Purpose: Navigation prop type for AI prediction list screen
+ */
+export type AIPredictionListNavigationProp = StackNavigationProp<
+ AIPredictionStackParamList,
+ 'AIPredictionList'
+>;
+
+/**
+ * AI Prediction Details Navigation Prop
+ *
+ * Purpose: Navigation prop type for AI prediction details screen
+ */
+export type AIPredictionDetailsNavigationProp = StackNavigationProp<
+ AIPredictionStackParamList,
+ 'AIPredictionDetails'
+>;
+
+/**
+ * AI Prediction Filters Navigation Prop
+ *
+ * Purpose: Navigation prop type for AI prediction filters screen
+ */
+export type AIPredictionFiltersNavigationProp = StackNavigationProp<
+ AIPredictionStackParamList,
+ 'AIPredictionFilters'
+>;
+
+/**
+ * AI Prediction Stats Navigation Prop
+ *
+ * Purpose: Navigation prop type for AI prediction statistics screen
+ */
+export type AIPredictionStatsNavigationProp = StackNavigationProp<
+ AIPredictionStackParamList,
+ 'AIPredictionStats'
+>;
+
+// ============================================================================
+// ROUTE PROP TYPES
+// ============================================================================
+
+/**
+ * AI Prediction List Route Prop
+ *
+ * Purpose: Route prop type for AI prediction list screen
+ */
+export type AIPredictionListRouteProp = RouteProp<
+ AIPredictionStackParamList,
+ 'AIPredictionList'
+>;
+
+/**
+ * AI Prediction Details Route Prop
+ *
+ * Purpose: Route prop type for AI prediction details screen
+ */
+export type AIPredictionDetailsRouteProp = RouteProp<
+ AIPredictionStackParamList,
+ 'AIPredictionDetails'
+>;
+
+/**
+ * AI Prediction Filters Route Prop
+ *
+ * Purpose: Route prop type for AI prediction filters screen
+ */
+export type AIPredictionFiltersRouteProp = RouteProp<
+ AIPredictionStackParamList,
+ 'AIPredictionFilters'
+>;
+
+/**
+ * AI Prediction Stats Route Prop
+ *
+ * Purpose: Route prop type for AI prediction statistics screen
+ */
+export type AIPredictionStatsRouteProp = RouteProp<
+ AIPredictionStackParamList,
+ 'AIPredictionStats'
+>;
+
+// ============================================================================
+// COMBINED PROP TYPES
+// ============================================================================
+
+/**
+ * AI Prediction List Screen Props
+ *
+ * Purpose: Combined props for AI prediction list screen
+ */
+export interface AIPredictionListScreenProps {
+ navigation: AIPredictionListNavigationProp;
+ route: AIPredictionListRouteProp;
+}
+
+/**
+ * AI Prediction Details Screen Props
+ *
+ * Purpose: Combined props for AI prediction details screen
+ */
+export interface AIPredictionDetailsScreenProps {
+ navigation: AIPredictionDetailsNavigationProp;
+ route: AIPredictionDetailsRouteProp;
+}
+
+/**
+ * AI Prediction Filters Screen Props
+ *
+ * Purpose: Combined props for AI prediction filters screen
+ */
+export interface AIPredictionFiltersScreenProps {
+ navigation: AIPredictionFiltersNavigationProp;
+ route: AIPredictionFiltersRouteProp;
+}
+
+/**
+ * AI Prediction Stats Screen Props
+ *
+ * Purpose: Combined props for AI prediction statistics screen
+ */
+export interface AIPredictionStatsScreenProps {
+ navigation: AIPredictionStatsNavigationProp;
+ route: AIPredictionStatsRouteProp;
+}
+
+/*
+ * End of File: navigationTypes.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
diff --git a/app/modules/AIPrediction/navigation/navigationUtils.ts b/app/modules/AIPrediction/navigation/navigationUtils.ts
new file mode 100644
index 0000000..7dc12a3
--- /dev/null
+++ b/app/modules/AIPrediction/navigation/navigationUtils.ts
@@ -0,0 +1,251 @@
+/*
+ * File: navigationUtils.ts
+ * Description: Navigation utility functions for AI Prediction module
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import { CommonActions } from '@react-navigation/native';
+import type { AIPredictionStackParamList } from './navigationTypes';
+
+// ============================================================================
+// NAVIGATION UTILITY FUNCTIONS
+// ============================================================================
+
+/**
+ * Navigate to AI Prediction Details
+ *
+ * Purpose: Navigate to AI prediction case details screen
+ *
+ * @param navigation - Navigation object
+ * @param caseId - AI prediction case ID
+ */
+export const navigateToAIPredictionDetails = (
+ navigation: any,
+ caseId: string
+) => {
+ navigation.navigate('AIPredictionDetails', { caseId });
+};
+
+/**
+ * Navigate to AI Prediction Filters
+ *
+ * Purpose: Navigate to advanced filters screen
+ *
+ * @param navigation - Navigation object
+ */
+export const navigateToAIPredictionFilters = (navigation: any) => {
+ navigation.navigate('AIPredictionFilters');
+};
+
+/**
+ * Navigate to AI Prediction Statistics
+ *
+ * Purpose: Navigate to detailed statistics screen
+ *
+ * @param navigation - Navigation object
+ * @param timeRange - Optional time range filter
+ */
+export const navigateToAIPredictionStats = (
+ navigation: any,
+ timeRange?: 'today' | 'week' | 'month'
+) => {
+ navigation.navigate('AIPredictionStats', { timeRange });
+};
+
+/**
+ * Go Back to AI Prediction List
+ *
+ * Purpose: Navigate back to AI prediction list screen
+ *
+ * @param navigation - Navigation object
+ */
+export const goBackToAIPredictionList = (navigation: any) => {
+ navigation.navigate('AIPredictionList');
+};
+
+/**
+ * Reset to AI Prediction List
+ *
+ * Purpose: Reset navigation stack to AI prediction list
+ *
+ * @param navigation - Navigation object
+ */
+export const resetToAIPredictionList = (navigation: any) => {
+ navigation.dispatch(
+ CommonActions.reset({
+ index: 0,
+ routes: [{ name: 'AIPredictionList' }],
+ })
+ );
+};
+
+/**
+ * Can Go Back
+ *
+ * Purpose: Check if navigation can go back
+ *
+ * @param navigation - Navigation object
+ * @returns Boolean indicating if can go back
+ */
+export const canGoBack = (navigation: any): boolean => {
+ return navigation.canGoBack();
+};
+
+/**
+ * Get Current Route Name
+ *
+ * Purpose: Get the current route name
+ *
+ * @param navigation - Navigation object
+ * @returns Current route name or undefined
+ */
+export const getCurrentRouteName = (navigation: any): string | undefined => {
+ return navigation.getCurrentRoute()?.name;
+};
+
+/**
+ * Get Current Route Params
+ *
+ * Purpose: Get the current route parameters
+ *
+ * @param navigation - Navigation object
+ * @returns Current route params or undefined
+ */
+export const getCurrentRouteParams = (navigation: any): any => {
+ return navigation.getCurrentRoute()?.params;
+};
+
+/**
+ * Navigate with Replace
+ *
+ * Purpose: Navigate to a screen by replacing the current one
+ *
+ * @param navigation - Navigation object
+ * @param routeName - Route name to navigate to
+ * @param params - Optional route parameters
+ */
+export const navigateWithReplace = (
+ navigation: any,
+ routeName: keyof AIPredictionStackParamList,
+ params?: any
+) => {
+ navigation.replace(routeName, params);
+};
+
+/**
+ * Navigate with Push
+ *
+ * Purpose: Navigate to a screen by pushing it onto the stack
+ *
+ * @param navigation - Navigation object
+ * @param routeName - Route name to navigate to
+ * @param params - Optional route parameters
+ */
+export const navigateWithPush = (
+ navigation: any,
+ routeName: keyof AIPredictionStackParamList,
+ params?: any
+) => {
+ navigation.push(routeName, params);
+};
+
+/**
+ * Pop Navigation Stack
+ *
+ * Purpose: Pop the specified number of screens from the stack
+ *
+ * @param navigation - Navigation object
+ * @param count - Number of screens to pop (default: 1)
+ */
+export const popNavigationStack = (navigation: any, count: number = 1) => {
+ navigation.pop(count);
+};
+
+/**
+ * Pop to Top
+ *
+ * Purpose: Pop to the top of the navigation stack
+ *
+ * @param navigation - Navigation object
+ */
+export const popToTop = (navigation: any) => {
+ navigation.popToTop();
+};
+
+/**
+ * Set Navigation Params
+ *
+ * Purpose: Set parameters for the current screen
+ *
+ * @param navigation - Navigation object
+ * @param params - Parameters to set
+ */
+export const setNavigationParams = (navigation: any, params: any) => {
+ navigation.setParams(params);
+};
+
+/**
+ * Add Navigation Listener
+ *
+ * Purpose: Add a navigation event listener
+ *
+ * @param navigation - Navigation object
+ * @param eventName - Event name to listen for
+ * @param callback - Callback function
+ * @returns Unsubscribe function
+ */
+export const addNavigationListener = (
+ navigation: any,
+ eventName: string,
+ callback: (e: any) => void
+) => {
+ return navigation.addListener(eventName, callback);
+};
+
+/**
+ * Remove Navigation Listener
+ *
+ * Purpose: Remove a navigation event listener
+ *
+ * @param navigation - Navigation object
+ * @param eventName - Event name
+ * @param callback - Callback function
+ */
+export const removeNavigationListener = (
+ navigation: any,
+ eventName: string,
+ callback: (e: any) => void
+) => {
+ navigation.removeListener(eventName, callback);
+};
+
+/**
+ * Check if Screen is Focused
+ *
+ * Purpose: Check if the current screen is focused
+ *
+ * @param navigation - Navigation object
+ * @returns Boolean indicating if screen is focused
+ */
+export const isScreenFocused = (navigation: any): boolean => {
+ return navigation.isFocused();
+};
+
+/**
+ * Get Navigation State
+ *
+ * Purpose: Get the current navigation state
+ *
+ * @param navigation - Navigation object
+ * @returns Navigation state
+ */
+export const getNavigationState = (navigation: any) => {
+ return navigation.getState();
+};
+
+/*
+ * End of File: navigationUtils.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
diff --git a/app/modules/AIPrediction/redux/aiPredictionSelectors.ts b/app/modules/AIPrediction/redux/aiPredictionSelectors.ts
new file mode 100644
index 0000000..aa7f222
--- /dev/null
+++ b/app/modules/AIPrediction/redux/aiPredictionSelectors.ts
@@ -0,0 +1,410 @@
+/*
+ * File: aiPredictionSelectors.ts
+ * Description: Redux selectors for AI Prediction state
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import { createSelector } from '@reduxjs/toolkit';
+import type { RootState } from '../../../store';
+import { AIPredictionCase } from '../types';
+
+// ============================================================================
+// BASE SELECTORS
+// ============================================================================
+
+/**
+ * Select AI Prediction State
+ *
+ * Purpose: Get the entire AI prediction state
+ */
+export const selectAIPredictionState = (state: RootState) => state.aiPrediction;
+
+/**
+ * Select Prediction Cases
+ *
+ * Purpose: Get all AI prediction cases
+ */
+export const selectPredictionCases = (state: RootState) => state.aiPrediction.predictionCases;
+
+/**
+ * Select Current Case
+ *
+ * Purpose: Get the currently selected AI prediction case
+ */
+export const selectCurrentCase = (state: RootState) => state.aiPrediction.currentCase;
+
+/**
+ * Select Loading State
+ *
+ * Purpose: Get the loading state for AI predictions
+ */
+export const selectIsLoading = (state: RootState) => state.aiPrediction.isLoading;
+
+/**
+ * Select Loading Case Details State
+ *
+ * Purpose: Get the loading state for case details
+ */
+export const selectIsLoadingCaseDetails = (state: RootState) => state.aiPrediction.isLoadingCaseDetails;
+
+/**
+ * Select Error
+ *
+ * Purpose: Get the current error message
+ */
+export const selectError = (state: RootState) => state.aiPrediction.error;
+
+/**
+ * Select Search Query
+ *
+ * Purpose: Get the current search query
+ */
+export const selectSearchQuery = (state: RootState) => state.aiPrediction.searchQuery;
+
+/**
+ * Select Filter States
+ *
+ * Purpose: Get all filter states
+ */
+export const selectUrgencyFilter = (state: RootState) => state.aiPrediction.selectedUrgencyFilter;
+export const selectSeverityFilter = (state: RootState) => state.aiPrediction.selectedSeverityFilter;
+export const selectCategoryFilter = (state: RootState) => state.aiPrediction.selectedCategoryFilter;
+
+/**
+ * Select Sort Options
+ *
+ * Purpose: Get current sort configuration
+ */
+export const selectSortBy = (state: RootState) => state.aiPrediction.sortBy;
+export const selectSortOrder = (state: RootState) => state.aiPrediction.sortOrder;
+
+/**
+ * Select Pagination
+ *
+ * Purpose: Get pagination configuration
+ */
+export const selectCurrentPage = (state: RootState) => state.aiPrediction.currentPage;
+export const selectItemsPerPage = (state: RootState) => state.aiPrediction.itemsPerPage;
+export const selectTotalItems = (state: RootState) => state.aiPrediction.totalItems;
+
+/**
+ * Select UI State
+ *
+ * Purpose: Get UI state flags
+ */
+export const selectShowFilters = (state: RootState) => state.aiPrediction.showFilters;
+export const selectSelectedCaseIds = (state: RootState) => state.aiPrediction.selectedCaseIds;
+
+// ============================================================================
+// COMPUTED SELECTORS
+// ============================================================================
+
+/**
+ * Select Filtered and Sorted Cases
+ *
+ * Purpose: Get AI prediction cases filtered and sorted based on current settings
+ */
+export const selectFilteredAndSortedCases = createSelector(
+ [
+ selectPredictionCases,
+ selectSearchQuery,
+ selectUrgencyFilter,
+ selectSeverityFilter,
+ selectCategoryFilter,
+ selectSortBy,
+ selectSortOrder,
+ ],
+ (cases, searchQuery, urgencyFilter, severityFilter, categoryFilter, sortBy, sortOrder) => {
+ let filteredCases = [...cases];
+
+ // Apply search filter
+ if (searchQuery.trim()) {
+ const query = searchQuery.toLowerCase();
+ filteredCases = filteredCases.filter(case_ =>
+ case_.patid.toLowerCase().includes(query) ||
+ case_.prediction.label.toLowerCase().includes(query) ||
+ case_.prediction.anatomical_location.toLowerCase().includes(query)
+ );
+ }
+
+ // Apply urgency filter
+ if (urgencyFilter !== 'all') {
+ filteredCases = filteredCases.filter(case_ =>
+ case_.prediction.clinical_urgency === urgencyFilter
+ );
+ }
+
+ // Apply severity filter
+ if (severityFilter !== 'all') {
+ filteredCases = filteredCases.filter(case_ =>
+ case_.prediction.primary_severity === severityFilter
+ );
+ }
+
+ // Apply category filter
+ if (categoryFilter !== 'all') {
+ filteredCases = filteredCases.filter(case_ =>
+ case_.prediction.finding_category === categoryFilter
+ );
+ }
+
+ // Apply sorting
+ filteredCases.sort((a, b) => {
+ let comparison = 0;
+
+ switch (sortBy) {
+ case 'date':
+ comparison = new Date(a.created_at || '').getTime() - new Date(b.created_at || '').getTime();
+ break;
+ case 'urgency':
+ const urgencyOrder = { emergency: 5, urgent: 4, moderate: 3, low: 2, routine: 1 };
+ comparison = (urgencyOrder[a.prediction.clinical_urgency as keyof typeof urgencyOrder] || 0) -
+ (urgencyOrder[b.prediction.clinical_urgency as keyof typeof urgencyOrder] || 0);
+ break;
+ case 'confidence':
+ comparison = a.prediction.confidence_score - b.prediction.confidence_score;
+ break;
+ case 'severity':
+ const severityOrder = { high: 4, medium: 3, low: 2, none: 1 };
+ comparison = (severityOrder[a.prediction.primary_severity as keyof typeof severityOrder] || 0) -
+ (severityOrder[b.prediction.primary_severity as keyof typeof severityOrder] || 0);
+ break;
+ default:
+ break;
+ }
+
+ return sortOrder === 'desc' ? -comparison : comparison;
+ });
+
+ return filteredCases;
+ }
+);
+
+/**
+ * Select Paginated Cases
+ *
+ * Purpose: Get the current page of filtered and sorted cases
+ */
+export const selectPaginatedCases = createSelector(
+ [selectFilteredAndSortedCases, selectCurrentPage, selectItemsPerPage],
+ (filteredCases, currentPage, itemsPerPage) => {
+ const startIndex = (currentPage - 1) * itemsPerPage;
+ const endIndex = startIndex + itemsPerPage;
+ return filteredCases.slice(startIndex, endIndex);
+ }
+);
+
+/**
+ * Select Critical Cases
+ *
+ * Purpose: Get cases marked as critical or emergency
+ */
+export const selectCriticalCases = createSelector(
+ [selectPredictionCases],
+ (cases) => cases.filter(case_ =>
+ case_.prediction.clinical_urgency === 'emergency' ||
+ case_.prediction.clinical_urgency === 'urgent' ||
+ case_.prediction.primary_severity === 'high' ||
+ case_.priority === 'critical'
+ )
+);
+
+/**
+ * Select Pending Cases
+ *
+ * Purpose: Get cases pending review
+ */
+export const selectPendingCases = createSelector(
+ [selectPredictionCases],
+ (cases) => cases.filter(case_ => case_.review_status === 'pending')
+);
+
+/**
+ * Select Reviewed Cases
+ *
+ * Purpose: Get cases that have been reviewed
+ */
+export const selectReviewedCases = createSelector(
+ [selectPredictionCases],
+ (cases) => cases.filter(case_ =>
+ case_.review_status === 'reviewed' ||
+ case_.review_status === 'confirmed' ||
+ case_.review_status === 'disputed'
+ )
+);
+
+/**
+ * Select Cases by Urgency
+ *
+ * Purpose: Group cases by urgency level
+ */
+export const selectCasesByUrgency = createSelector(
+ [selectPredictionCases],
+ (cases) => {
+ const grouped = {
+ emergency: [] as AIPredictionCase[],
+ urgent: [] as AIPredictionCase[],
+ moderate: [] as AIPredictionCase[],
+ low: [] as AIPredictionCase[],
+ routine: [] as AIPredictionCase[],
+ };
+
+ cases.forEach(case_ => {
+ const urgency = case_.prediction.clinical_urgency as keyof typeof grouped;
+ if (grouped[urgency]) {
+ grouped[urgency].push(case_);
+ }
+ });
+
+ return grouped;
+ }
+);
+
+/**
+ * Select Cases Statistics
+ *
+ * Purpose: Get statistical overview of cases
+ */
+export const selectCasesStatistics = createSelector(
+ [selectPredictionCases],
+ (cases) => {
+ const total = cases.length;
+ const critical = cases.filter(c =>
+ c.prediction.clinical_urgency === 'emergency' ||
+ c.prediction.clinical_urgency === 'urgent'
+ ).length;
+ const pending = cases.filter(c => c.review_status === 'pending').length;
+ const reviewed = cases.filter(c =>
+ c.review_status === 'reviewed' ||
+ c.review_status === 'confirmed'
+ ).length;
+ const averageConfidence = total > 0
+ ? cases.reduce((sum, c) => sum + c.prediction.confidence_score, 0) / total
+ : 0;
+
+ return {
+ total,
+ critical,
+ pending,
+ reviewed,
+ averageConfidence: Math.round(averageConfidence * 1000) / 1000, // Round to 3 decimal places
+ reviewProgress: total > 0 ? Math.round((reviewed / total) * 100) : 0,
+ };
+ }
+);
+
+/**
+ * Select Filter Counts
+ *
+ * Purpose: Get counts for each filter option
+ */
+export const selectFilterCounts = createSelector(
+ [selectPredictionCases],
+ (cases) => {
+ const urgencyCounts = {
+ all: cases.length,
+ emergency: 0,
+ urgent: 0,
+ moderate: 0,
+ low: 0,
+ routine: 0,
+ };
+
+ const severityCounts = {
+ all: cases.length,
+ high: 0,
+ medium: 0,
+ low: 0,
+ none: 0,
+ };
+
+ const categoryCounts = {
+ all: cases.length,
+ normal: 0,
+ abnormal: 0,
+ critical: 0,
+ warning: 0,
+ unknown: 0,
+ };
+
+ cases.forEach(case_ => {
+ // Count urgency
+ const urgency = case_.prediction.clinical_urgency as keyof typeof urgencyCounts;
+ if (urgencyCounts[urgency] !== undefined) {
+ urgencyCounts[urgency]++;
+ }
+
+ // Count severity
+ const severity = case_.prediction.primary_severity as keyof typeof severityCounts;
+ if (severityCounts[severity] !== undefined) {
+ severityCounts[severity]++;
+ }
+
+ // Count category
+ const category = case_.prediction.finding_category as keyof typeof categoryCounts;
+ if (categoryCounts[category] !== undefined) {
+ categoryCounts[category]++;
+ }
+ });
+
+ return {
+ urgency: urgencyCounts,
+ severity: severityCounts,
+ category: categoryCounts,
+ };
+ }
+);
+
+/**
+ * Select Total Pages
+ *
+ * Purpose: Calculate total number of pages based on filtered results
+ */
+export const selectTotalPages = createSelector(
+ [selectFilteredAndSortedCases, selectItemsPerPage],
+ (filteredCases, itemsPerPage) => Math.ceil(filteredCases.length / itemsPerPage)
+);
+
+/**
+ * Select Has Previous Page
+ *
+ * Purpose: Check if there's a previous page available
+ */
+export const selectHasPreviousPage = createSelector(
+ [selectCurrentPage],
+ (currentPage) => currentPage > 1
+);
+
+/**
+ * Select Has Next Page
+ *
+ * Purpose: Check if there's a next page available
+ */
+export const selectHasNextPage = createSelector(
+ [selectCurrentPage, selectTotalPages],
+ (currentPage, totalPages) => currentPage < totalPages
+);
+
+/**
+ * Select Active Filters Count
+ *
+ * Purpose: Count how many filters are currently active
+ */
+export const selectActiveFiltersCount = createSelector(
+ [selectSearchQuery, selectUrgencyFilter, selectSeverityFilter, selectCategoryFilter],
+ (searchQuery, urgencyFilter, severityFilter, categoryFilter) => {
+ let count = 0;
+ if (searchQuery.trim()) count++;
+ if (urgencyFilter !== 'all') count++;
+ if (severityFilter !== 'all') count++;
+ if (categoryFilter !== 'all') count++;
+ return count;
+ }
+);
+
+/*
+ * End of File: aiPredictionSelectors.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
diff --git a/app/modules/AIPrediction/redux/aiPredictionSlice.ts b/app/modules/AIPrediction/redux/aiPredictionSlice.ts
new file mode 100644
index 0000000..005e484
--- /dev/null
+++ b/app/modules/AIPrediction/redux/aiPredictionSlice.ts
@@ -0,0 +1,621 @@
+/*
+ * File: aiPredictionSlice.ts
+ * Description: Redux slice for AI Prediction state management
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import { createSlice, createAsyncThunk, PayloadAction } from '@reduxjs/toolkit';
+import {
+ AIPredictionCase,
+ AIPredictionState,
+ AIPredictionStats,
+ AIPredictionAPIResponse
+} from '../types';
+import { aiPredictionAPI } from '../services';
+
+// ============================================================================
+// ASYNC THUNKS
+// ============================================================================
+
+/**
+ * Fetch AI Predictions Async Thunk
+ *
+ * Purpose: Fetch AI prediction results from API
+ *
+ * @param token - Authentication token
+ * @param params - Optional query parameters for filtering
+ * @returns Promise with AI prediction data or error
+ */
+export const fetchAIPredictions = createAsyncThunk(
+ 'aiPrediction/fetchAIPredictions',
+ async (payload: {
+ token: string;
+ params?: {
+ page?: number;
+ limit?: number;
+ urgency?: string;
+ severity?: string;
+ category?: string;
+ search?: string;
+ }
+ }, { rejectWithValue }) => {
+ try {
+ const response: any = await aiPredictionAPI.getAllPredictions(payload.token, payload.params);
+ console.log('AI predictions response:', response);
+
+ if (response.ok && response.data && response.data.success) {
+ // Add additional metadata to each case for UI purposes
+ const enhancedCases = response.data.data.map((aiCase: AIPredictionCase) => ({
+ ...aiCase,
+ created_at: new Date().toISOString(),
+ updated_at: new Date().toISOString(),
+ review_status: 'pending' as const,
+ priority: getPriorityFromPrediction(aiCase.prediction)
+ }));
+
+ console.log('Enhanced AI prediction cases:', enhancedCases);
+ return {
+ cases: enhancedCases as AIPredictionCase[],
+ total: response.data.total || enhancedCases.length,
+ page: response.data.page || 1,
+ limit: response.data.limit || 20
+ };
+ } else {
+ // Fallback to mock data for development
+ const mockData = generateMockAIPredictions();
+ return {
+ cases: mockData,
+ total: mockData.length,
+ page: 1,
+ limit: 20
+ };
+ }
+ } catch (error: any) {
+ console.error('Fetch AI predictions error:', error);
+ return rejectWithValue(error.message || 'Failed to fetch AI predictions.');
+ }
+ }
+);
+
+/**
+ * Fetch AI Prediction Case Details Async Thunk
+ *
+ * Purpose: Fetch detailed information for a specific AI prediction case
+ *
+ * @param caseId - AI prediction case ID
+ * @param token - Authentication token
+ * @returns Promise with case details or error
+ */
+export const fetchAIPredictionDetails = createAsyncThunk(
+ 'aiPrediction/fetchAIPredictionDetails',
+ async (payload: { caseId: string; token: string }, { rejectWithValue }) => {
+ try {
+ const response: any = await aiPredictionAPI.getCaseDetails(payload.caseId, payload.token);
+
+ if (response.ok && response.data) {
+ return response.data as AIPredictionCase;
+ } else {
+ // Fallback to mock data
+ const mockCase = generateMockAIPredictions().find(c => c.patid === payload.caseId);
+ if (mockCase) {
+ return mockCase;
+ }
+ throw new Error('Case not found');
+ }
+ } catch (error: any) {
+ console.error('Fetch AI prediction details error:', error);
+ return rejectWithValue(error.message || 'Failed to fetch case details.');
+ }
+ }
+);
+
+/**
+ * Update Case Review Async Thunk
+ *
+ * Purpose: Update review status of an AI prediction case
+ *
+ * @param caseId - Case ID to update
+ * @param reviewData - Review data
+ * @param token - Authentication token
+ * @returns Promise with updated case or error
+ */
+export const updateCaseReview = createAsyncThunk(
+ 'aiPrediction/updateCaseReview',
+ async (payload: {
+ caseId: string;
+ reviewData: {
+ review_status: 'pending' | 'reviewed' | 'confirmed' | 'disputed';
+ reviewed_by?: string;
+ review_notes?: string;
+ priority?: 'critical' | 'high' | 'medium' | 'low';
+ };
+ token: string;
+ }, { rejectWithValue }) => {
+ try {
+ const response: any = await aiPredictionAPI.updateCaseReview(
+ payload.caseId,
+ payload.reviewData,
+ payload.token
+ );
+
+ if (response.ok && response.data) {
+ return {
+ caseId: payload.caseId,
+ ...payload.reviewData,
+ updated_at: new Date().toISOString()
+ };
+ } else {
+ throw new Error('Failed to update case review');
+ }
+ } catch (error: any) {
+ console.error('Update case review error:', error);
+ return rejectWithValue(error.message || 'Failed to update case review.');
+ }
+ }
+);
+
+/**
+ * Fetch AI Prediction Statistics Async Thunk
+ *
+ * Purpose: Fetch statistics for AI predictions dashboard
+ *
+ * @param token - Authentication token
+ * @param timeRange - Time range filter
+ * @returns Promise with statistics data or error
+ */
+export const fetchAIPredictionStats = createAsyncThunk(
+ 'aiPrediction/fetchAIPredictionStats',
+ async (payload: { token: string; timeRange?: 'today' | 'week' | 'month' }, { rejectWithValue }) => {
+ try {
+ const response: any = await aiPredictionAPI.getPredictionStats(payload.token, payload.timeRange);
+
+ if (response.ok && response.data) {
+ return response.data as AIPredictionStats;
+ } else {
+ // Fallback to mock stats
+ return generateMockStats();
+ }
+ } catch (error: any) {
+ console.error('Fetch AI prediction stats error:', error);
+ return rejectWithValue(error.message || 'Failed to fetch statistics.');
+ }
+ }
+);
+
+// ============================================================================
+// HELPER FUNCTIONS
+// ============================================================================
+
+/**
+ * Get Priority from AI Prediction
+ *
+ * Purpose: Determine case priority based on AI prediction results
+ */
+function getPriorityFromPrediction(prediction: any): 'critical' | 'high' | 'medium' | 'low' {
+ if (prediction.clinical_urgency === 'emergency' || prediction.primary_severity === 'high') {
+ return 'critical';
+ }
+ if (prediction.clinical_urgency === 'urgent' || prediction.primary_severity === 'medium') {
+ return 'high';
+ }
+ if (prediction.clinical_urgency === 'moderate' || prediction.primary_severity === 'low') {
+ return 'medium';
+ }
+ return 'low';
+}
+
+/**
+ * Generate Mock AI Predictions
+ *
+ * Purpose: Generate mock data for development and testing
+ */
+function generateMockAIPredictions(): AIPredictionCase[] {
+ return [
+ {
+ patid: "demogw05-08-2017",
+ hospital_id: "eec24855-d8ae-4fad-8e54-af0480343dc2",
+ prediction: {
+ label: "midline shift",
+ finding_type: "pathology",
+ clinical_urgency: "urgent",
+ confidence_score: 0.996,
+ finding_category: "abnormal",
+ primary_severity: "high",
+ anatomical_location: "brain"
+ },
+ created_at: "2024-01-15T10:30:00Z",
+ updated_at: "2024-01-15T10:30:00Z",
+ review_status: "pending",
+ priority: "critical"
+ },
+ {
+ patid: "demo-patient-002",
+ hospital_id: "eec24855-d8ae-4fad-8e54-af0480343dc2",
+ prediction: {
+ label: "normal brain",
+ finding_type: "no_pathology",
+ clinical_urgency: "routine",
+ confidence_score: 0.892,
+ finding_category: "normal",
+ primary_severity: "none",
+ anatomical_location: "not_applicable"
+ },
+ created_at: "2024-01-15T09:15:00Z",
+ updated_at: "2024-01-15T09:15:00Z",
+ review_status: "reviewed",
+ priority: "low"
+ },
+ {
+ patid: "demo-patient-003",
+ hospital_id: "eec24855-d8ae-4fad-8e54-af0480343dc2",
+ prediction: {
+ label: "hemorrhage",
+ finding_type: "pathology",
+ clinical_urgency: "emergency",
+ confidence_score: 0.945,
+ finding_category: "critical",
+ primary_severity: "high",
+ anatomical_location: "temporal lobe"
+ },
+ created_at: "2024-01-15T11:45:00Z",
+ updated_at: "2024-01-15T11:45:00Z",
+ review_status: "confirmed",
+ priority: "critical"
+ }
+ ];
+}
+
+/**
+ * Generate Mock Statistics
+ *
+ * Purpose: Generate mock statistics for development
+ */
+function generateMockStats(): AIPredictionStats {
+ return {
+ totalCases: 156,
+ criticalCases: 23,
+ urgentCases: 45,
+ reviewedCases: 89,
+ pendingCases: 67,
+ averageConfidence: 0.887,
+ todaysCases: 12,
+ weeklyTrend: 15.4
+ };
+}
+
+// ============================================================================
+// INITIAL STATE
+// ============================================================================
+
+/**
+ * Initial AI Prediction State
+ *
+ * Purpose: Define the initial state for AI predictions
+ *
+ * Features:
+ * - Prediction cases list and management
+ * - Current case details
+ * - Loading states for async operations
+ * - Error handling and messages
+ * - Search and filtering
+ * - Pagination support
+ * - Cache management
+ */
+const initialState: AIPredictionState = {
+ // Prediction data
+ predictionCases: [],
+ currentCase: null,
+
+ // Loading states
+ isLoading: false,
+ isRefreshing: false,
+ isLoadingCaseDetails: false,
+
+ // Error handling
+ error: null,
+
+ // Search and filtering
+ searchQuery: '',
+ selectedUrgencyFilter: 'all',
+ selectedSeverityFilter: 'all',
+ selectedCategoryFilter: 'all',
+ sortBy: 'date',
+ sortOrder: 'desc',
+
+ // Pagination
+ currentPage: 1,
+ itemsPerPage: 20,
+ totalItems: 0,
+
+ // Cache management
+ lastUpdated: null,
+ cacheExpiry: null,
+
+ // UI state
+ showFilters: false,
+ selectedCaseIds: [],
+};
+
+// ============================================================================
+// AI PREDICTION SLICE
+// ============================================================================
+
+/**
+ * AI Prediction Slice
+ *
+ * Purpose: Redux slice for AI prediction state management
+ *
+ * Features:
+ * - AI prediction data management
+ * - Search and filtering
+ * - Case review management
+ * - Pagination
+ * - Caching
+ * - Error handling
+ * - Loading states
+ */
+const aiPredictionSlice = createSlice({
+ name: 'aiPrediction',
+ initialState,
+ reducers: {
+ /**
+ * Clear Error Action
+ *
+ * Purpose: Clear AI prediction errors
+ */
+ clearError: (state) => {
+ state.error = null;
+ },
+
+ /**
+ * Set Search Query Action
+ *
+ * Purpose: Set search query for AI predictions
+ */
+ setSearchQuery: (state, action: PayloadAction) => {
+ state.searchQuery = action.payload;
+ state.currentPage = 1; // Reset to first page when searching
+ },
+
+ /**
+ * Set Urgency Filter Action
+ *
+ * Purpose: Set urgency filter for AI predictions
+ */
+ setUrgencyFilter: (state, action: PayloadAction) => {
+ state.selectedUrgencyFilter = action.payload;
+ state.currentPage = 1; // Reset to first page when filtering
+ },
+
+ /**
+ * Set Severity Filter Action
+ *
+ * Purpose: Set severity filter for AI predictions
+ */
+ setSeverityFilter: (state, action: PayloadAction) => {
+ state.selectedSeverityFilter = action.payload;
+ state.currentPage = 1; // Reset to first page when filtering
+ },
+
+ /**
+ * Set Category Filter Action
+ *
+ * Purpose: Set category filter for AI predictions
+ */
+ setCategoryFilter: (state, action: PayloadAction) => {
+ state.selectedCategoryFilter = action.payload;
+ state.currentPage = 1; // Reset to first page when filtering
+ },
+
+ /**
+ * Set Sort Action
+ *
+ * Purpose: Set sort options for AI predictions
+ */
+ setSort: (state, action: PayloadAction<{ by: 'date' | 'urgency' | 'confidence' | 'severity'; order: 'asc' | 'desc' }>) => {
+ state.sortBy = action.payload.by;
+ state.sortOrder = action.payload.order;
+ },
+
+ /**
+ * Set Current Page Action
+ *
+ * Purpose: Set current page for pagination
+ */
+ setCurrentPage: (state, action: PayloadAction) => {
+ state.currentPage = action.payload;
+ },
+
+ /**
+ * Set Items Per Page Action
+ *
+ * Purpose: Set items per page for pagination
+ */
+ setItemsPerPage: (state, action: PayloadAction) => {
+ state.itemsPerPage = action.payload;
+ state.currentPage = 1; // Reset to first page when changing items per page
+ },
+
+ /**
+ * Set Current Case Action
+ *
+ * Purpose: Set the currently selected AI prediction case
+ */
+ setCurrentCase: (state, action: PayloadAction) => {
+ state.currentCase = action.payload;
+ },
+
+ /**
+ * Update Case in List Action
+ *
+ * Purpose: Update an AI prediction case in the list
+ */
+ updateCaseInList: (state, action: PayloadAction) => {
+ const index = state.predictionCases.findIndex(case_ => case_.patid === action.payload.patid);
+ if (index !== -1) {
+ state.predictionCases[index] = action.payload;
+ }
+
+ // Update current case if it's the same case
+ if (state.currentCase && state.currentCase.patid === action.payload.patid) {
+ state.currentCase = action.payload;
+ }
+ },
+
+ /**
+ * Toggle Show Filters Action
+ *
+ * Purpose: Toggle the display of filter options
+ */
+ toggleShowFilters: (state) => {
+ state.showFilters = !state.showFilters;
+ },
+
+ /**
+ * Clear All Filters Action
+ *
+ * Purpose: Reset all filters to default values
+ */
+ clearAllFilters: (state) => {
+ state.searchQuery = '';
+ state.selectedUrgencyFilter = 'all';
+ state.selectedSeverityFilter = 'all';
+ state.selectedCategoryFilter = 'all';
+ state.currentPage = 1;
+ },
+
+ /**
+ * Select Case Action
+ *
+ * Purpose: Add/remove case from selected cases
+ */
+ toggleCaseSelection: (state, action: PayloadAction) => {
+ const caseId = action.payload;
+ const index = state.selectedCaseIds.indexOf(caseId);
+
+ if (index === -1) {
+ state.selectedCaseIds.push(caseId);
+ } else {
+ state.selectedCaseIds.splice(index, 1);
+ }
+ },
+
+ /**
+ * Clear Selected Cases Action
+ *
+ * Purpose: Clear all selected cases
+ */
+ clearSelectedCases: (state) => {
+ state.selectedCaseIds = [];
+ },
+
+ /**
+ * Clear Cache Action
+ *
+ * Purpose: Clear AI prediction data cache
+ */
+ clearCache: (state) => {
+ state.predictionCases = [];
+ state.currentCase = null;
+ state.lastUpdated = null;
+ state.cacheExpiry = null;
+ },
+ },
+ extraReducers: (builder) => {
+ // Fetch AI Predictions
+ builder
+ .addCase(fetchAIPredictions.pending, (state) => {
+ state.isLoading = true;
+ state.error = null;
+ })
+ .addCase(fetchAIPredictions.fulfilled, (state, action) => {
+ state.isLoading = false;
+ state.predictionCases = action.payload.cases;
+ state.totalItems = action.payload.total;
+ state.lastUpdated = new Date().toLocaleString();
+ state.cacheExpiry = new Date(Date.now() + 5 * 60 * 1000).toLocaleString(); // 5 minutes
+ state.error = null;
+ })
+ .addCase(fetchAIPredictions.rejected, (state, action) => {
+ state.isLoading = false;
+ state.error = action.payload as string;
+ });
+
+ // Fetch AI Prediction Details
+ builder
+ .addCase(fetchAIPredictionDetails.pending, (state) => {
+ state.isLoadingCaseDetails = true;
+ state.error = null;
+ })
+ .addCase(fetchAIPredictionDetails.fulfilled, (state, action) => {
+ state.isLoadingCaseDetails = false;
+ state.currentCase = action.payload;
+ state.error = null;
+ })
+ .addCase(fetchAIPredictionDetails.rejected, (state, action) => {
+ state.isLoadingCaseDetails = false;
+ state.error = action.payload as string;
+ });
+
+ // Update Case Review
+ builder
+ .addCase(updateCaseReview.fulfilled, (state, action) => {
+ // Update case in list
+ const index = state.predictionCases.findIndex(case_ => case_.patid === action.payload.caseId);
+ if (index !== -1) {
+ state.predictionCases[index] = {
+ ...state.predictionCases[index],
+ review_status: action.payload.review_status,
+ reviewed_by: action.payload.reviewed_by,
+ priority: action.payload.priority,
+ updated_at: action.payload.updated_at
+ };
+ }
+
+ // Update current case if it's the same case
+ if (state.currentCase && state.currentCase.patid === action.payload.caseId) {
+ state.currentCase = {
+ ...state.currentCase,
+ review_status: action.payload.review_status,
+ reviewed_by: action.payload.reviewed_by,
+ priority: action.payload.priority,
+ updated_at: action.payload.updated_at
+ };
+ }
+ })
+ .addCase(updateCaseReview.rejected, (state, action) => {
+ state.error = action.payload as string;
+ });
+ },
+});
+
+// ============================================================================
+// EXPORTS
+// ============================================================================
+
+export const {
+ clearError,
+ setSearchQuery,
+ setUrgencyFilter,
+ setSeverityFilter,
+ setCategoryFilter,
+ setSort,
+ setCurrentPage,
+ setItemsPerPage,
+ setCurrentCase,
+ updateCaseInList,
+ toggleShowFilters,
+ clearAllFilters,
+ toggleCaseSelection,
+ clearSelectedCases,
+ clearCache,
+} = aiPredictionSlice.actions;
+
+export default aiPredictionSlice.reducer;
+
+/*
+ * End of File: aiPredictionSlice.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
diff --git a/app/modules/AIPrediction/redux/index.ts b/app/modules/AIPrediction/redux/index.ts
new file mode 100644
index 0000000..f93e701
--- /dev/null
+++ b/app/modules/AIPrediction/redux/index.ts
@@ -0,0 +1,15 @@
+/*
+ * File: index.ts
+ * Description: Redux exports for AI Prediction module
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+export * from './aiPredictionSlice';
+export * from './aiPredictionSelectors';
+
+/*
+ * End of File: index.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
diff --git a/app/modules/AIPrediction/screens/AIPredictionsScreen.tsx b/app/modules/AIPrediction/screens/AIPredictionsScreen.tsx
new file mode 100644
index 0000000..acff58c
--- /dev/null
+++ b/app/modules/AIPrediction/screens/AIPredictionsScreen.tsx
@@ -0,0 +1,749 @@
+/*
+ * 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.
+ */
diff --git a/app/modules/AIPrediction/screens/index.ts b/app/modules/AIPrediction/screens/index.ts
new file mode 100644
index 0000000..2a13828
--- /dev/null
+++ b/app/modules/AIPrediction/screens/index.ts
@@ -0,0 +1,14 @@
+/*
+ * File: index.ts
+ * Description: Screens exports for AI Prediction module
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+export { default as AIPredictionsScreen } from './AIPredictionsScreen';
+
+/*
+ * End of File: index.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
diff --git a/app/modules/AIPrediction/services/aiPredictionAPI.ts b/app/modules/AIPrediction/services/aiPredictionAPI.ts
new file mode 100644
index 0000000..1a131c1
--- /dev/null
+++ b/app/modules/AIPrediction/services/aiPredictionAPI.ts
@@ -0,0 +1,233 @@
+/*
+ * File: aiPredictionAPI.ts
+ * Description: API service for AI prediction operations using apisauce
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+import { create } from 'apisauce';
+import { API_CONFIG, buildHeaders } from '../../../shared/utils';
+
+const api = create({
+ baseURL: API_CONFIG.BASE_URL
+});
+
+/**
+ * AI Prediction API Service
+ *
+ * Purpose: Handle all AI prediction-related API operations
+ *
+ * Features:
+ * - Get AI prediction results for all patients
+ * - Get individual case prediction details
+ * - Update case review status
+ * - Search and filter predictions
+ * - Get prediction statistics
+ */
+export const aiPredictionAPI = {
+ /**
+ * Get All AI Prediction Results
+ *
+ * Purpose: Fetch all AI prediction results from server
+ *
+ * @param token - Authentication token
+ * @param params - Optional query parameters for filtering
+ * @returns Promise with AI prediction cases data
+ */
+ getAllPredictions: (token: string, params?: {
+ page?: number;
+ limit?: number;
+ urgency?: string;
+ severity?: string;
+ category?: string;
+ search?: string;
+ }) => {
+ const queryParams = params ? { ...params } : {};
+ return api.get('/api/ai-cases/all-prediction-results', queryParams, buildHeaders({ token }));
+ },
+
+ /**
+ * Get AI Prediction Case Details
+ *
+ * Purpose: Fetch detailed information for a specific AI prediction case
+ *
+ * @param caseId - AI prediction case ID (patid)
+ * @param token - Authentication token
+ * @returns Promise with detailed case prediction data
+ */
+ getCaseDetails: (caseId: string, token: string) => {
+ return api.get(`/api/ai-cases/prediction-details/${caseId}`, {}, buildHeaders({ token }));
+ },
+
+ /**
+ * Update Case Review Status
+ *
+ * Purpose: Update the review status of an AI prediction case
+ *
+ * @param caseId - AI prediction case ID
+ * @param reviewData - Review status and notes
+ * @param token - Authentication token
+ * @returns Promise with updated case data
+ */
+ updateCaseReview: (caseId: string, reviewData: {
+ review_status: 'pending' | 'reviewed' | 'confirmed' | 'disputed';
+ reviewed_by?: string;
+ review_notes?: string;
+ priority?: 'critical' | 'high' | 'medium' | 'low';
+ }, token: string) => {
+ return api.put(`/api/ai-cases/review/${caseId}`, reviewData, buildHeaders({ token }));
+ },
+
+ /**
+ * Get Prediction Statistics
+ *
+ * Purpose: Fetch AI prediction statistics for dashboard
+ *
+ * @param token - Authentication token
+ * @param timeRange - Optional time range filter (today, week, month)
+ * @returns Promise with prediction statistics
+ */
+ getPredictionStats: (token: string, timeRange?: 'today' | 'week' | 'month') => {
+ const params = timeRange ? { timeRange } : {};
+ return api.get('/api/ai-cases/statistics', params, buildHeaders({ token }));
+ },
+
+ /**
+ * Search AI Prediction Cases
+ *
+ * Purpose: Search AI prediction cases by various criteria
+ *
+ * @param query - Search query (patient ID, hospital, findings)
+ * @param token - Authentication token
+ * @param filters - Additional search filters
+ * @returns Promise with search results
+ */
+ searchPredictions: (query: string, token: string, filters?: {
+ urgency?: string[];
+ severity?: string[];
+ category?: string[];
+ dateRange?: { start: string; end: string };
+ }) => {
+ const params = {
+ q: query,
+ ...(filters && { filters: JSON.stringify(filters) })
+ };
+ return api.get('/api/ai-cases/search', params, buildHeaders({ token }));
+ },
+
+ /**
+ * Get Predictions by Hospital
+ *
+ * Purpose: Fetch AI predictions filtered by hospital
+ *
+ * @param hospitalId - Hospital UUID
+ * @param token - Authentication token
+ * @param params - Optional query parameters
+ * @returns Promise with hospital-specific predictions
+ */
+ getPredictionsByHospital: (hospitalId: string, token: string, params?: {
+ page?: number;
+ limit?: number;
+ urgency?: string;
+ startDate?: string;
+ endDate?: string;
+ }) => {
+ const queryParams = params ? { ...params } : {};
+ return api.get(`/api/ai-cases/hospital/${hospitalId}/predictions`, queryParams, buildHeaders({ token }));
+ },
+
+ /**
+ * Get Critical Predictions
+ *
+ * Purpose: Fetch only critical and urgent AI predictions
+ *
+ * @param token - Authentication token
+ * @returns Promise with critical predictions data
+ */
+ getCriticalPredictions: (token: string) => {
+ return api.get('/api/ai-cases/critical-predictions', {}, buildHeaders({ token }));
+ },
+
+ /**
+ * Bulk Update Case Reviews
+ *
+ * Purpose: Update multiple case reviews at once
+ *
+ * @param caseIds - Array of case IDs to update
+ * @param reviewData - Review data to apply to all cases
+ * @param token - Authentication token
+ * @returns Promise with bulk update results
+ */
+ bulkUpdateReviews: (caseIds: string[], reviewData: {
+ review_status: 'pending' | 'reviewed' | 'confirmed' | 'disputed';
+ reviewed_by?: string;
+ review_notes?: string;
+ }, token: string) => {
+ return api.put('/api/ai-cases/bulk-review', {
+ caseIds,
+ reviewData
+ }, buildHeaders({ token }));
+ },
+
+ /**
+ * Export Predictions Data
+ *
+ * Purpose: Export AI predictions data for reporting
+ *
+ * @param token - Authentication token
+ * @param filters - Export filters
+ * @param format - Export format (csv, xlsx, pdf)
+ * @returns Promise with export file data
+ */
+ exportPredictions: (token: string, filters?: {
+ urgency?: string[];
+ severity?: string[];
+ dateRange?: { start: string; end: string };
+ hospitalId?: string;
+ }, format: 'csv' | 'xlsx' | 'pdf' = 'csv') => {
+ const params = {
+ format,
+ ...(filters && { filters: JSON.stringify(filters) })
+ };
+ return api.get('/api/ai-cases/export', params, buildHeaders({ token }));
+ },
+
+ /**
+ * Get Prediction Trends
+ *
+ * Purpose: Fetch prediction trends data for analytics
+ *
+ * @param token - Authentication token
+ * @param period - Time period for trends (daily, weekly, monthly)
+ * @returns Promise with trends data
+ */
+ getPredictionTrends: (token: string, period: 'daily' | 'weekly' | 'monthly' = 'weekly') => {
+ return api.get('/api/ai-cases/trends', { period }, buildHeaders({ token }));
+ },
+
+ /**
+ * Submit Feedback on Prediction
+ *
+ * Purpose: Submit physician feedback on AI prediction accuracy
+ *
+ * @param caseId - AI prediction case ID
+ * @param feedbackData - Feedback data
+ * @param token - Authentication token
+ * @returns Promise with feedback submission result
+ */
+ submitPredictionFeedback: (caseId: string, feedbackData: {
+ accuracy_rating: 1 | 2 | 3 | 4 | 5;
+ is_accurate: boolean;
+ physician_diagnosis?: string;
+ feedback_notes?: string;
+ improvement_suggestions?: string;
+ }, token: string) => {
+ return api.post(`/api/ai-cases/feedback/${caseId}`, feedbackData, buildHeaders({ token }));
+ }
+};
+
+/*
+ * End of File: aiPredictionAPI.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
diff --git a/app/modules/AIPrediction/services/index.ts b/app/modules/AIPrediction/services/index.ts
new file mode 100644
index 0000000..e410e41
--- /dev/null
+++ b/app/modules/AIPrediction/services/index.ts
@@ -0,0 +1,14 @@
+/*
+ * File: index.ts
+ * Description: Services exports for AI Prediction module
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+export * from './aiPredictionAPI';
+
+/*
+ * End of File: index.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
diff --git a/app/modules/AIPrediction/types/aiPrediction.ts b/app/modules/AIPrediction/types/aiPrediction.ts
new file mode 100644
index 0000000..acf9582
--- /dev/null
+++ b/app/modules/AIPrediction/types/aiPrediction.ts
@@ -0,0 +1,221 @@
+/*
+ * File: aiPrediction.ts
+ * Description: Type definitions for AI Prediction module
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+// ============================================================================
+// AI PREDICTION INTERFACES
+// ============================================================================
+
+/**
+ * AI Prediction Interface
+ *
+ * Purpose: Define the structure of AI prediction data from the API
+ *
+ * Based on API response structure:
+ * - label: Type of medical finding
+ * - finding_type: Category of the finding
+ * - clinical_urgency: Urgency level for medical response
+ * - confidence_score: AI confidence in the prediction (0-1)
+ * - finding_category: General category of the finding
+ * - primary_severity: Severity level of the condition
+ * - anatomical_location: Where the finding is located
+ */
+export interface AIPrediction {
+ label: string;
+ finding_type: 'no_pathology' | 'pathology' | 'abnormal' | 'normal' | 'unknown';
+ clinical_urgency: 'urgent' | 'moderate' | 'low' | 'routine' | 'emergency';
+ confidence_score: number; // 0.0 to 1.0
+ finding_category: 'normal' | 'abnormal' | 'critical' | 'warning' | 'unknown';
+ primary_severity: 'high' | 'medium' | 'low' | 'none';
+ anatomical_location: string; // 'not_applicable' | specific location
+}
+
+/**
+ * AI Prediction Case Interface
+ *
+ * Purpose: Complete AI prediction case data structure
+ *
+ * Features:
+ * - Patient identification
+ * - Hospital association
+ * - AI prediction results
+ * - Metadata for tracking and display
+ */
+export interface AIPredictionCase {
+ patid: string; // Patient ID
+ hospital_id: string; // Hospital UUID
+ prediction: AIPrediction;
+
+ // Additional metadata (will be added for UI purposes)
+ created_at?: string;
+ updated_at?: string;
+ reviewed_by?: string;
+ review_status?: 'pending' | 'reviewed' | 'confirmed' | 'disputed';
+ priority?: 'critical' | 'high' | 'medium' | 'low';
+ processed_at?: string;
+}
+
+/**
+ * AI Prediction API Response Interface
+ *
+ * Purpose: Define the structure of API response
+ */
+export interface AIPredictionAPIResponse {
+ success: boolean;
+ data: AIPredictionCase[];
+ message?: string;
+ total?: number;
+ page?: number;
+ limit?: number;
+}
+
+/**
+ * AI Prediction State Interface
+ *
+ * Purpose: Define Redux state structure for AI predictions
+ *
+ * Features:
+ * - Prediction cases management
+ * - Current selected case
+ * - Loading states for async operations
+ * - Error handling and messages
+ * - Search and filtering
+ * - Pagination support
+ * - Cache management
+ */
+export interface AIPredictionState {
+ // Prediction data
+ predictionCases: AIPredictionCase[];
+ currentCase: AIPredictionCase | null;
+
+ // Loading states
+ isLoading: boolean;
+ isRefreshing: boolean;
+ isLoadingCaseDetails: boolean;
+
+ // Error handling
+ error: string | null;
+
+ // Search and filtering
+ searchQuery: string;
+ selectedUrgencyFilter: 'all' | 'urgent' | 'moderate' | 'low' | 'routine' | 'emergency';
+ selectedSeverityFilter: 'all' | 'high' | 'medium' | 'low' | 'none';
+ selectedCategoryFilter: 'all' | 'normal' | 'abnormal' | 'critical' | 'warning' | 'unknown';
+ sortBy: 'date' | 'urgency' | 'confidence' | 'severity';
+ sortOrder: 'asc' | 'desc';
+
+ // Pagination
+ currentPage: number;
+ itemsPerPage: number;
+ totalItems: number;
+
+ // Cache management
+ lastUpdated: String | null;
+ cacheExpiry: String | null;
+
+ // UI state
+ showFilters: boolean;
+ selectedCaseIds: string[];
+}
+
+/**
+ * AI Prediction Filter Options
+ *
+ * Purpose: Define available filter options for the UI
+ */
+export interface AIPredictionFilters {
+ urgency: Array<{
+ label: string;
+ value: AIPredictionState['selectedUrgencyFilter'];
+ count?: number;
+ }>;
+ severity: Array<{
+ label: string;
+ value: AIPredictionState['selectedSeverityFilter'];
+ count?: number;
+ }>;
+ category: Array<{
+ label: string;
+ value: AIPredictionState['selectedCategoryFilter'];
+ count?: number;
+ }>;
+}
+
+/**
+ * AI Prediction Statistics Interface
+ *
+ * Purpose: Define statistics data for dashboard display
+ */
+export interface AIPredictionStats {
+ totalCases: number;
+ criticalCases: number;
+ urgentCases: number;
+ reviewedCases: number;
+ pendingCases: number;
+ averageConfidence: number;
+ todaysCases: number;
+ weeklyTrend: number; // percentage change from last week
+}
+
+/**
+ * AI Prediction Navigation Props
+ *
+ * Purpose: Type safety for navigation between AI prediction screens
+ */
+export type AIPredictionNavigationProps = {
+ AIPredictionList: undefined;
+ AIPredictionDetails: { caseId: string };
+ AIPredictionFilters: undefined;
+ AIPredictionStats: undefined;
+};
+
+// ============================================================================
+// UTILITY TYPES
+// ============================================================================
+
+/**
+ * Prediction Urgency Colors
+ *
+ * Purpose: Map urgency levels to UI colors
+ */
+export const URGENCY_COLORS = {
+ emergency: '#F44336', // Red
+ urgent: '#FF5722', // Deep Orange
+ moderate: '#FF9800', // Orange
+ low: '#FFC107', // Amber
+ routine: '#4CAF50', // Green
+} as const;
+
+/**
+ * Prediction Severity Colors
+ *
+ * Purpose: Map severity levels to UI colors
+ */
+export const SEVERITY_COLORS = {
+ high: '#F44336', // Red
+ medium: '#FF9800', // Orange
+ low: '#FFC107', // Amber
+ none: '#4CAF50', // Green
+} as const;
+
+/**
+ * Finding Category Colors
+ *
+ * Purpose: Map finding categories to UI colors
+ */
+export const CATEGORY_COLORS = {
+ critical: '#F44336', // Red
+ abnormal: '#FF9800', // Orange
+ warning: '#FFC107', // Amber
+ normal: '#4CAF50', // Green
+ unknown: '#9E9E9E', // Gray
+} as const;
+
+/*
+ * End of File: aiPrediction.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
diff --git a/app/modules/AIPrediction/types/index.ts b/app/modules/AIPrediction/types/index.ts
new file mode 100644
index 0000000..ea9fa52
--- /dev/null
+++ b/app/modules/AIPrediction/types/index.ts
@@ -0,0 +1,14 @@
+/*
+ * File: index.ts
+ * Description: Type definitions exports for AI Prediction module
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
+
+export * from './aiPrediction';
+
+/*
+ * End of File: index.ts
+ * Design & Developed by Tech4Biz Solutions
+ * Copyright (c) Spurrin Innovations. All rights reserved.
+ */
diff --git a/app/navigation/MainTabNavigator.tsx b/app/navigation/MainTabNavigator.tsx
index a199b1a..fd044e0 100644
--- a/app/navigation/MainTabNavigator.tsx
+++ b/app/navigation/MainTabNavigator.tsx
@@ -10,6 +10,7 @@ import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { theme } from '../theme/theme';
import { DashboardStackNavigator } from '../modules/Dashboard/navigation';
import { SettingsStackNavigator } from '../modules/Settings/navigation';
+import { AIPredictionStackNavigator } from '../modules/AIPrediction/navigation';
import { MainTabParamList } from './navigationTypes';
import MaterialIcons from 'react-native-vector-icons/MaterialIcons';
import { ComingSoonScreen } from '../shared/components';
@@ -26,7 +27,7 @@ const Tab = createBottomTabNavigator();
* Tab Structure:
* - Dashboard: Main ER dashboard with patient overview and statistics
* - Patients: Detailed patient list and management interface
- * - Alerts: Critical notifications and alert management
+ * - AI Predictions: AI-powered medical case predictions and analysis
* - Reports: Medical reports and documentation access
* - Settings: User preferences and app configuration
*
@@ -96,16 +97,15 @@ export const MainTabNavigator: React.FC = () => {
}}
/>
- {/* Alerts Tab - Critical notifications */}
+ {/* AI Predictions Tab - AI-powered medical predictions */}
(
-
+
),
headerShown: false,
}}
diff --git a/app/navigation/navigationTypes.ts b/app/navigation/navigationTypes.ts
index 2367d1a..80c2cc6 100644
--- a/app/navigation/navigationTypes.ts
+++ b/app/navigation/navigationTypes.ts
@@ -39,16 +39,14 @@ export type RootStackParamList = {
* Tabs:
* - Dashboard: ER dashboard with patient overview
* - Patients: Patient list and management
- * - Alerts: Critical notifications and alerts
- * - Reports: Medical reports and documentation
+ * - AIPredictions: AI-powered medical case predictions and analysis
* - Settings: User preferences and app configuration
*/
export type MainTabParamList = {
- Dashboard: DashboardScreenParams; // Dashboard with initial data
- Patients: PatientsScreenParams; // Patient list screen
- Alerts: AlertsScreenParams; // Alerts screen
- Reports: ReportsScreenParams; // Reports screen
- Settings: SettingsScreenParams; // Settings screen
+ Dashboard: DashboardScreenParams; // Dashboard with initial data
+ Patients: PatientsScreenParams; // Patient list screen
+ AIPredictions: AIPredictionScreenParams; // AI predictions screen
+ Settings: SettingsScreenParams; // Settings screen
};
// ============================================================================
@@ -86,17 +84,19 @@ export interface PatientsScreenParams {
}
/**
- * AlertsScreenParams
+ * AIPredictionScreenParams
*
- * Purpose: Parameters for the alerts screen
+ * Purpose: Parameters for the AI predictions screen
*
* Parameters:
- * - priority: Optional priority filter for alerts
- * - unreadOnly: Optional flag to show only unread alerts
+ * - filter: Optional filter for prediction types
+ * - urgency: Optional urgency level filter
+ * - searchQuery: Optional search term for predictions
*/
-export interface AlertsScreenParams {
- priority?: 'CRITICAL' | 'HIGH' | 'MEDIUM' | 'LOW';
- unreadOnly?: boolean;
+export interface AIPredictionScreenParams {
+ filter?: 'all' | 'critical' | 'urgent' | 'pending' | 'reviewed';
+ urgency?: 'emergency' | 'urgent' | 'moderate' | 'low' | 'routine';
+ searchQuery?: string;
}
/**
diff --git a/app/shared/types/index.ts b/app/shared/types/index.ts
index 4b879ce..5cc6930 100644
--- a/app/shared/types/index.ts
+++ b/app/shared/types/index.ts
@@ -12,6 +12,24 @@ export * from './alerts';
export * from './settings';
export * from './common';
+// AI Prediction types (re-export from module)
+export type {
+ AIPrediction,
+ AIPredictionCase,
+ AIPredictionAPIResponse,
+ AIPredictionState,
+ AIPredictionStats,
+ AIPredictionFilters,
+ AIPredictionNavigationProps,
+} from '../modules/AIPrediction/types';
+
+// AI Prediction constants (re-export from module)
+export {
+ URGENCY_COLORS,
+ SEVERITY_COLORS,
+ CATEGORY_COLORS,
+} from '../modules/AIPrediction/types';
+
/*
* End of File: index.ts
* Design & Developed by Tech4Biz Solutions
diff --git a/app/store/index.ts b/app/store/index.ts
index 081d0c2..e442e37 100644
--- a/app/store/index.ts
+++ b/app/store/index.ts
@@ -17,6 +17,7 @@ import alertsReducer from '../modules/Dashboard/redux/alertsSlice';
import settingsReducer from '../modules/Settings/redux/settingsSlice';
import uiReducer from '../modules/Dashboard/redux/uiSlice';
import hospitalReducer from '../modules/Auth/redux/hospitalSlice';
+import aiPredictionReducer from '../modules/AIPrediction/redux/aiPredictionSlice';
// ============================================================================
// REDUX PERSIST CONFIGURATION
@@ -48,6 +49,7 @@ const persistConfig = {
'auth', // Authentication state (user login, tokens)
'settings', // User preferences and settings
'patientCare', // Patient data cache
+ 'aiPrediction', // AI prediction data cache
],
// Blacklist: Don't persist these reducers
@@ -84,6 +86,7 @@ const persistConfig = {
* - auth: Authentication and user management
* - dashboard: ER dashboard data and statistics
* - patientCare: Patient information and medical records
+ * - aiPrediction: AI prediction cases and analysis
* - alerts: Critical alerts and notifications
* - settings: User preferences and app settings
* - ui: User interface state (loading, modals, etc.)
@@ -92,6 +95,7 @@ const rootReducer = combineReducers({
auth: authReducer,
dashboard: dashboardReducer,
patientCare: patientCareReducer,
+ aiPrediction: aiPredictionReducer,
alerts: alertsReducer,
settings: settingsReducer,
ui: uiReducer,