diff --git a/app/modules/Dashboard/components/FeedbackAnalysisPieChart.tsx b/app/modules/Dashboard/components/FeedbackAnalysisPieChart.tsx new file mode 100644 index 0000000..c20536a --- /dev/null +++ b/app/modules/Dashboard/components/FeedbackAnalysisPieChart.tsx @@ -0,0 +1,337 @@ +/* + * File: FeedbackAnalysisPieChart.tsx + * Description: Pie chart component for feedback analysis using react-native-chart-kit + * Design & Developed by Tech4Biz Solutions + * Copyright (c) Spurrin Innovations. All rights reserved. + */ + +import React from 'react'; +import { View, Text, StyleSheet, Dimensions } from 'react-native'; +import { PieChart } from 'react-native-chart-kit'; +import { theme } from '../../../theme/theme'; + +// ============================================================================ +// TYPES +// ============================================================================ + +/** + * Feedback Analysis Data Interface + * + * Purpose: Defines the structure of feedback analysis data for pie chart + */ +interface FeedbackAnalysisData { + positive: number; + negative: number; + total: number; +} + +/** + * FeedbackAnalysisPieChart Props Interface + * + * Purpose: Defines the props required by the FeedbackAnalysisPieChart component + * + * Props: + * - data: Feedback analysis data containing positive, negative, and total counts + * - title: Optional title for the chart + * - width: Chart width (defaults to screen width - 32) + * - height: Chart height (defaults to 220) + */ +interface FeedbackAnalysisPieChartProps { + data: FeedbackAnalysisData; + title?: string; + width?: number; + height?: number; +} + +// ============================================================================ +// COMPONENT +// ============================================================================ + +/** + * FeedbackAnalysisPieChart Component + * + * Purpose: Renders a pie chart showing feedback analysis distribution + * + * Features: + * - Pie chart visualization of positive vs negative feedback + * - Custom colors for different feedback types + * - Responsive sizing + * - Legend with percentages + * - Empty state handling + */ +export const FeedbackAnalysisPieChart: React.FC = ({ + data, + title = 'Feedback Analysis Overview', + width = Dimensions.get('window').width - 32, + height = 220, +}) => { + // ============================================================================ + // DATA PROCESSING + // ============================================================================ + + /** + * Process data for pie chart + * + * Purpose: Convert feedback data into chart-kit format + */ + const chartData = React.useMemo(() => { + const { positive, negative } = data; + + // Only show data if there are actual feedbacks + if (positive === 0 && negative === 0) { + return []; + } + + const chartDataArray = []; + + // Add positive feedback data + if (positive > 0) { + chartDataArray.push({ + name: 'Positive', + population: positive, + color: theme.colors.success, + legendFontColor: theme.colors.textPrimary, + legendFontSize: 12, + }); + } + + // Add negative feedback data + if (negative > 0) { + chartDataArray.push({ + name: 'Negative', + population: negative, + color: theme.colors.error, + legendFontColor: theme.colors.textPrimary, + legendFontSize: 12, + }); + } + + return chartDataArray; + }, [data]); + + // ============================================================================ + // CHART CONFIGURATION + // ============================================================================ + + /** + * Chart configuration object + * + * Purpose: Configure pie chart appearance and behavior + */ + const chartConfig = { + backgroundColor: theme.colors.background, + backgroundGradientFrom: theme.colors.background, + backgroundGradientTo: theme.colors.background, + decimalPlaces: 0, + color: (opacity = 1) => theme.colors.primary, + labelColor: (opacity = 1) => theme.colors.textPrimary, + style: { + borderRadius: theme.borderRadius.medium, + }, + propsForDots: { + r: '6', + strokeWidth: '2', + stroke: theme.colors.primary, + }, + }; + + // ============================================================================ + // RENDER FUNCTIONS + // ============================================================================ + + /** + * Render empty state + * + * Purpose: Show message when no feedback data is available + */ + const renderEmptyState = () => ( + + No feedback data available + + Feedback will appear here once received + + + ); + + /** + * Render chart legend + * + * Purpose: Display custom legend with percentages + */ + const renderLegend = () => { + const { positive, negative, total } = data; + + if (total === 0) return null; + + const positivePercentage = ((positive / total) * 100).toFixed(1); + const negativePercentage = ((negative / total) * 100).toFixed(1); + + return ( + + + + + Positive: {positive} ({positivePercentage}%) + + + + + + Negative: {negative} ({negativePercentage}%) + + + + + Total Feedback: {total} + + + + ); + }; + + // ============================================================================ + // MAIN RENDER + // ============================================================================ + + return ( + + {/* Chart Title */} + {/* {title && ( + {title} + )} */} + + {/* Chart Container */} + + {chartData.length > 0 ? ( + <> + {/* Pie Chart */} + + + {/* Custom Legend */} + {renderLegend()} + + ) : ( + renderEmptyState() + )} + + + ); +}; + +// ============================================================================ +// STYLES +// ============================================================================ + +const styles = StyleSheet.create({ + // Main container + container: { + backgroundColor: theme.colors.background, + borderRadius: theme.borderRadius.medium, + paddingHorizontal: theme.spacing.md, + alignItems: 'center', + justifyContent: 'center', + minHeight: 250, + }, + + // Chart title styling + title: { + fontSize: theme.typography.fontSize.displaySmall, + fontFamily: theme.typography.fontFamily.bold, + color: theme.colors.textPrimary, + marginBottom: theme.spacing.md, + textAlign: 'center', + }, + + // Chart container + chartContainer: { + alignItems: 'center', + justifyContent: 'center', + width: '100%', + flex: 1, + }, + + // Empty state styling + emptyState: { + alignItems: 'center', + justifyContent: 'center', + paddingVertical: theme.spacing.xl, + minHeight: 150, + }, + + // Empty state text styling + emptyStateText: { + fontSize: theme.typography.fontSize.bodyMedium, + fontFamily: theme.typography.fontFamily.medium, + color: theme.colors.textSecondary, + marginBottom: theme.spacing.xs, + }, + + // Empty state subtext styling + emptyStateSubtext: { + fontSize: theme.typography.fontSize.bodySmall, + fontFamily: theme.typography.fontFamily.regular, + color: theme.colors.textMuted, + textAlign: 'center', + }, + + // Legend container styling + legendContainer: { + marginTop: theme.spacing.md, + alignItems: 'center', + }, + + // Legend item styling + legendItem: { + flexDirection: 'row', + alignItems: 'center', + marginBottom: theme.spacing.sm, + }, + + // Legend color indicator styling + legendColor: { + width: 16, + height: 16, + borderRadius: 8, + marginRight: theme.spacing.sm, + }, + + // Legend text styling + legendText: { + fontSize: theme.typography.fontSize.bodyMedium, + fontFamily: theme.typography.fontFamily.medium, + color: theme.colors.textPrimary, + }, + + // Total container styling + totalContainer: { + marginTop: theme.spacing.sm, + paddingTop: theme.spacing.sm, + borderTopWidth: 1, + borderTopColor: theme.colors.border, + alignItems: 'center', + }, + + // Total text styling + totalText: { + fontSize: theme.typography.fontSize.bodyMedium, + fontFamily: theme.typography.fontFamily.bold, + color: theme.colors.textPrimary, + }, +}); + +/* + * End of File: FeedbackAnalysisPieChart.tsx + * Design & Developed by Tech4Biz Solutions + * Copyright (c) Spurrin Innovations. All rights reserved. + */ diff --git a/app/modules/Dashboard/components/index.ts b/app/modules/Dashboard/components/index.ts index b000aea..f893da3 100644 --- a/app/modules/Dashboard/components/index.ts +++ b/app/modules/Dashboard/components/index.ts @@ -3,4 +3,5 @@ export { CriticalAlerts } from './CriticalAlerts'; export { DashboardHeader } from './DashboardHeader'; export { QuickActions } from './QuickActions'; export { DepartmentStats } from './DepartmentStats'; -export { BrainPredictionsOverview } from './BrainPredictionsOverview'; \ No newline at end of file +export { BrainPredictionsOverview } from './BrainPredictionsOverview'; +export { FeedbackAnalysisPieChart } from './FeedbackAnalysisPieChart'; \ No newline at end of file diff --git a/app/modules/Dashboard/hooks/index.ts b/app/modules/Dashboard/hooks/index.ts new file mode 100644 index 0000000..e5736d3 --- /dev/null +++ b/app/modules/Dashboard/hooks/index.ts @@ -0,0 +1,14 @@ +/* + * File: index.ts + * Description: Dashboard hooks exports + * Design & Developed by Tech4Biz Solutions + * Copyright (c) Spurrin Innovations. All rights reserved. + */ + +export * from './useAIDashboard'; + +/* + * End of File: index.ts + * Design & Developed by Tech4Biz Solutions + * Copyright (c) Spurrin Innovations. All rights reserved. + */ diff --git a/app/modules/Dashboard/hooks/useAIDashboard.ts b/app/modules/Dashboard/hooks/useAIDashboard.ts new file mode 100644 index 0000000..4b1e70c --- /dev/null +++ b/app/modules/Dashboard/hooks/useAIDashboard.ts @@ -0,0 +1,101 @@ +/* + * File: useAIDashboard.ts + * Description: Custom hook for AI dashboard functionality + * Design & Developed by Tech4Biz Solutions + * Copyright (c) Spurrin Innovations. All rights reserved. + */ + +import { useEffect } from 'react'; +import { useDispatch, useSelector } from 'react-redux'; +import { AppDispatch } from '../../../store'; +import { selectAIDashboardData, selectAIDashboardError, selectAIDashboardLoading, selectAIDashboardRefreshing, selectDashboardMessage } from '../redux/aiDashboardSelectors'; +import { fetchAIDashboardStatistics, refreshAIDashboardStatistics } from '../redux/aiDashboardSlice'; +import { selectUser } from '../../Auth/redux'; + +// import { +// fetchAIDashboardStatistics, +// refreshAIDashboardStatistics, +// selectAIDashboardData, +// selectAIDashboardLoading, +// selectAIDashboardRefreshing, +// selectAIDashboardError, +// selectDashboardMessage +// } from '../redux'; + +/** + * useAIDashboard Custom Hook + * + * Purpose: Custom hook for AI dashboard functionality + * + * Features: + * - Fetch dashboard statistics from API + * - Refresh dashboard data + * - Access dashboard state from Redux + * - Handle authentication token + * + * @returns Object containing dashboard state and actions + */ +export const useAIDashboard = () => { + const dispatch = useDispatch(); + + // Select dashboard data from Redux store + const dashboardData = useSelector(selectAIDashboardData); + const isLoading = useSelector(selectAIDashboardLoading); + const isRefreshing = useSelector(selectAIDashboardRefreshing); + const error = useSelector(selectAIDashboardError); + const dashboardMessage = useSelector(selectDashboardMessage); + + // TODO: Get actual authentication token from auth store + // For now, using a placeholder token + const authToken = useSelector(selectUser)?.access_token; + + /** + * Fetch Dashboard Statistics + * + * Purpose: Fetch dashboard statistics from API + */ + const fetchDashboardStatistics = () => { + dispatch(fetchAIDashboardStatistics(authToken)); + }; + + /** + * Refresh Dashboard Statistics + * + * Purpose: Refresh dashboard statistics from API + */ + const refreshDashboardStatistics = () => { + dispatch(refreshAIDashboardStatistics(authToken)); + }; + + /** + * useEffect for initial data loading + * + * Purpose: Load initial dashboard data from API when hook is used + */ + useEffect(() => { + // Fetch dashboard statistics from API + fetchDashboardStatistics(); + }, []); + + return { + // State + dashboardData, + isLoading, + isRefreshing, + error, + dashboardMessage, + + // Actions + fetchDashboardStatistics, + refreshDashboardStatistics, + + // Constants + authToken + }; +}; + +/* + * End of File: useAIDashboard.ts + * Design & Developed by Tech4Biz Solutions + * Copyright (c) Spurrin Innovations. All rights reserved. + */ diff --git a/app/modules/Dashboard/index.ts b/app/modules/Dashboard/index.ts index a326b4d..0d0feb1 100644 --- a/app/modules/Dashboard/index.ts +++ b/app/modules/Dashboard/index.ts @@ -39,6 +39,9 @@ export { default as DashboardHeader } from './components/DashboardHeader'; export { default as QuickActions } from './components/QuickActions'; export { default as DepartmentStats } from './components/DepartmentStats'; +// Export hooks +export * from './hooks'; + // Export Redux export { fetchDashboardData, @@ -51,6 +54,36 @@ export { updateDashboardData, } from './redux/dashboardSlice'; +// Export AI Dashboard Redux +export { + fetchAIDashboardStatistics, + refreshAIDashboardStatistics, + clearError as clearAIDashboardError, + setTimeRange, + setHospital, + setDepartment, + updateDashboardData as updateAIDashboardData, +} from './redux/aiDashboardSlice'; + +// Export AI Dashboard Selectors +export { + selectAIDashboardData, + selectAIDashboardLoading, + selectAIDashboardRefreshing, + selectAIDashboardError, + selectDashboardMessage, + selectTotalPredictions, + selectTotalPatients, + selectTotalFeedbacks, + selectFeedbackRatePercentage, + selectAverageConfidenceScore, + selectCriticalCasePercentage, + selectConfidenceScores, + selectUrgencyLevels, + selectFeedbackAnalysis, + selectTimeAnalysis, +} from './redux/aiDashboardSelectors'; + export { fetchAlerts, acknowledgeAlert, diff --git a/app/modules/Dashboard/redux/aiDashboardSelectors.ts b/app/modules/Dashboard/redux/aiDashboardSelectors.ts new file mode 100644 index 0000000..4db5899 --- /dev/null +++ b/app/modules/Dashboard/redux/aiDashboardSelectors.ts @@ -0,0 +1,426 @@ +/* + * File: aiDashboardSelectors.ts + * Description: Selectors for AI dashboard state management + * Design & Developed by Tech4Biz Solutions + * Copyright (c) Spurrin Innovations. All rights reserved. + */ + +import { createSelector } from '@reduxjs/toolkit'; +import { RootState } from '../../../store'; + +// ============================================================================ +// BASE SELECTORS +// ============================================================================ + +/** + * Select AI Dashboard State + * + * Purpose: Get the entire AI dashboard state from root state + */ +const selectAIDashboardState = (state: RootState) => state.aiDashboard; + +/** + * Select AI Dashboard Data + * + * Purpose: Get the AI dashboard data from state + */ +export const selectAIDashboardData = createSelector( + [selectAIDashboardState], + (aiDashboard) => aiDashboard.dashboardData +); + +/** + * Select AI Dashboard Statistics + * + * Purpose: Get the AI dashboard statistics data + */ +export const selectAIDashboardStats = createSelector( + [selectAIDashboardData], + (dashboardData) => dashboardData?.data +); + +/** + * Select AI Dashboard Summary + * + * Purpose: Get the AI dashboard summary data + */ +export const selectAIDashboardSummary = createSelector( + [selectAIDashboardData], + (dashboardData) => dashboardData?.summary +); + +// ============================================================================ +// LOADING STATE SELECTORS +// ============================================================================ + +/** + * Select AI Dashboard Loading State + * + * Purpose: Get the loading state for AI dashboard + */ +export const selectAIDashboardLoading = createSelector( + [selectAIDashboardState], + (aiDashboard) => aiDashboard.isLoading +); + +/** + * Select AI Dashboard Refreshing State + * + * Purpose: Get the refreshing state for AI dashboard + */ +export const selectAIDashboardRefreshing = createSelector( + [selectAIDashboardState], + (aiDashboard) => aiDashboard.isRefreshing +); + +// ============================================================================ +// ERROR STATE SELECTORS +// ============================================================================ + +/** + * Select AI Dashboard Error + * + * Purpose: Get the error state for AI dashboard + */ +export const selectAIDashboardError = createSelector( + [selectAIDashboardState], + (aiDashboard) => aiDashboard.error +); + +// ============================================================================ +// FILTER STATE SELECTORS +// ============================================================================ + +/** + * Select Selected Time Range + * + * Purpose: Get the currently selected time range filter + */ +export const selectSelectedTimeRange = createSelector( + [selectAIDashboardState], + (aiDashboard) => aiDashboard.selectedTimeRange +); + +/** + * Select Selected Hospital + * + * Purpose: Get the currently selected hospital filter + */ +export const selectSelectedHospital = createSelector( + [selectAIDashboardState], + (aiDashboard) => aiDashboard.selectedHospital +); + +/** + * Select Selected Department + * + * Purpose: Get the currently selected department filter + */ +export const selectSelectedDepartment = createSelector( + [selectAIDashboardState], + (aiDashboard) => aiDashboard.selectedDepartment +); + +// ============================================================================ +// DERIVED DATA SELECTORS +// ============================================================================ + +/** + * Select Total Predictions Count + * + * Purpose: Get the total number of AI predictions + */ +export const selectTotalPredictions = createSelector( + [selectAIDashboardStats], + (stats) => stats?.total_predictions || 0 +); + +/** + * Select Total Patients Count + * + * Purpose: Get the total number of unique patients + */ +export const selectTotalPatients = createSelector( + [selectAIDashboardStats], + (stats) => stats?.total_patients || 0 +); + +/** + * Select Total Feedbacks Count + * + * Purpose: Get the total number of feedbacks received + */ +export const selectTotalFeedbacks = createSelector( + [selectAIDashboardStats], + (stats) => stats?.total_feedbacks || 0 +); + +/** + * Select Feedback Rate Percentage + * + * Purpose: Get the feedback rate as a percentage + */ +export const selectFeedbackRatePercentage = createSelector( + [selectAIDashboardStats], + (stats) => stats?.feedback_rate_percentage || 0 +); + +/** + * Select Average Confidence Score + * + * Purpose: Get the average confidence score for AI predictions + */ +export const selectAverageConfidenceScore = createSelector( + [selectAIDashboardStats], + (stats) => stats?.average_confidence_score || 0 +); + +/** + * Select Critical Case Percentage + * + * Purpose: Get the percentage of critical cases + */ +export const selectCriticalCasePercentage = createSelector( + [selectAIDashboardStats], + (stats) => stats?.critical_case_percentage || 0 +); + +// ============================================================================ +// CONFIDENCE SCORE SELECTORS +// ============================================================================ + +/** + * Select Confidence Score Distribution + * + * Purpose: Get the distribution of confidence scores + */ +export const selectConfidenceScores = createSelector( + [selectAIDashboardStats], + (stats) => stats?.confidence_scores || { high: 0, medium: 0, low: 0 } +); + +/** + * Select High Confidence Count + * + * Purpose: Get the count of high confidence predictions + */ +export const selectHighConfidenceCount = createSelector( + [selectConfidenceScores], + (confidenceScores) => confidenceScores.high +); + +/** + * Select Medium Confidence Count + * + * Purpose: Get the count of medium confidence predictions + */ +export const selectMediumConfidenceCount = createSelector( + [selectConfidenceScores], + (confidenceScores) => confidenceScores.medium +); + +/** + * Select Low Confidence Count + * + * Purpose: Get the count of low confidence predictions + */ +export const selectLowConfidenceCount = createSelector( + [selectConfidenceScores], + (confidenceScores) => confidenceScores.low +); + +// ============================================================================ +// URGENCY LEVEL SELECTORS +// ============================================================================ + +/** + * Select Urgency Level Distribution + * + * Purpose: Get the distribution of urgency levels + */ +export const selectUrgencyLevels = createSelector( + [selectAIDashboardStats], + (stats) => stats?.urgency_levels || { critical: 0, urgent: 0, routine: 0 } +); + +/** + * Select Critical Urgency Count + * + * Purpose: Get the count of critical urgency cases + */ +export const selectCriticalUrgencyCount = createSelector( + [selectUrgencyLevels], + (urgencyLevels) => urgencyLevels.critical +); + +/** + * Select Urgent Urgency Count + * + * Purpose: Get the count of urgent cases + */ +export const selectUrgentUrgencyCount = createSelector( + [selectUrgencyLevels], + (urgencyLevels) => urgencyLevels.urgent +); + +/** + * Select Routine Urgency Count + * + * Purpose: Get the count of routine cases + */ +export const selectRoutineUrgencyCount = createSelector( + [selectUrgencyLevels], + (urgencyLevels) => urgencyLevels.routine +); + +// ============================================================================ +// FEEDBACK ANALYSIS SELECTORS +// ============================================================================ + +/** + * Select Feedback Analysis Data + * + * Purpose: Get the feedback analysis data + */ +export const selectFeedbackAnalysis = createSelector( + [selectAIDashboardStats], + (stats) => stats?.feedback_analysis || { positive: 0, negative: 0, total: 0 } +); + +/** + * Select Positive Feedback Count + * + * Purpose: Get the count of positive feedbacks + */ +export const selectPositiveFeedbackCount = createSelector( + [selectFeedbackAnalysis], + (feedbackAnalysis) => feedbackAnalysis.positive +); + +/** + * Select Negative Feedback Count + * + * Purpose: Get the count of negative feedbacks + */ +export const selectNegativeFeedbackCount = createSelector( + [selectFeedbackAnalysis], + (feedbackAnalysis) => feedbackAnalysis.negative +); + +/** + * Select Total Feedback Count + * + * Purpose: Get the total count of feedbacks + */ +export const selectTotalFeedbackCount = createSelector( + [selectFeedbackAnalysis], + (feedbackAnalysis) => feedbackAnalysis.total +); + +// ============================================================================ +// TIME ANALYSIS SELECTORS +// ============================================================================ + +/** + * Select Time Analysis Data + * + * Purpose: Get the time-based analysis data + */ +export const selectTimeAnalysis = createSelector( + [selectAIDashboardStats], + (stats) => stats?.time_analysis || { today: 0, this_week: 0, this_month: 0, this_year: 0 } +); + +/** + * Select Today's Count + * + * Purpose: Get the count for today + */ +export const selectTodayCount = createSelector( + [selectTimeAnalysis], + (timeAnalysis) => timeAnalysis.today +); + +/** + * Select This Week's Count + * + * Purpose: Get the count for this week + */ +export const selectThisWeekCount = createSelector( + [selectTimeAnalysis], + (timeAnalysis) => timeAnalysis.this_week +); + +/** + * Select This Month's Count + * + * Purpose: Get the count for this month + */ +export const selectThisMonthCount = createSelector( + [selectTimeAnalysis], + (timeAnalysis) => timeAnalysis.this_month +); + +/** + * Select This Year's Count + * + * Purpose: Get the count for this year + */ +export const selectThisYearCount = createSelector( + [selectTimeAnalysis], + (timeAnalysis) => timeAnalysis.this_year +); + +// ============================================================================ +// LAST UPDATED SELECTORS +// ============================================================================ + +/** + * Select Last Updated Timestamp + * + * Purpose: Get the last updated timestamp + */ +export const selectLastUpdated = createSelector( + [selectAIDashboardState], + (aiDashboard) => aiDashboard.lastUpdated +); + +// ============================================================================ +// COMPUTED SELECTORS +// ============================================================================ + +/** + * Select Dashboard Message + * + * Purpose: Get the dashboard message or default message + */ +export const selectDashboardMessage = createSelector( + [selectAIDashboardData], + (dashboardData) => dashboardData?.message || 'Loading statistics...' +); + +/** + * Select Is Dashboard Empty + * + * Purpose: Check if dashboard has no data + */ +export const selectIsDashboardEmpty = createSelector( + [selectAIDashboardData], + (dashboardData) => !dashboardData || !dashboardData.data +); + +/** + * Select Has Dashboard Data + * + * Purpose: Check if dashboard has data + */ +export const selectHasDashboardData = createSelector( + [selectIsDashboardEmpty], + (isEmpty) => !isEmpty +); + +/* + * End of File: aiDashboardSelectors.ts + * Design & Developed by Tech4Biz Solutions + * Copyright (c) Spurrin Innovations. All rights reserved. + */ diff --git a/app/modules/Dashboard/redux/aiDashboardSlice.ts b/app/modules/Dashboard/redux/aiDashboardSlice.ts new file mode 100644 index 0000000..9309a3d --- /dev/null +++ b/app/modules/Dashboard/redux/aiDashboardSlice.ts @@ -0,0 +1,368 @@ +/* + * File: aiDashboardSlice.ts + * Description: AI Analysis Dashboard state management slice + * Design & Developed by Tech4Biz Solutions + * Copyright (c) Spurrin Innovations. All rights reserved. + */ + +import { createSlice, createAsyncThunk, PayloadAction } from '@reduxjs/toolkit'; +import { dashboardAPI } from '../services/dashboardAPI'; + +// ============================================================================ +// TYPES +// ============================================================================ + +/** + * AI Dashboard Statistics Interface + * + * Purpose: Defines the structure of AI dashboard statistics data + */ +export interface AIDashboardStats { + total_predictions: number; + total_patients: number; + total_feedbacks: number; + prediction_breakdown: Record; + critical_findings: Record; + midline_shift_stats: Record; + hemorrhage_stats: Record; + mass_lesion_stats: Record; + edema_stats: Record; + fracture_stats: Record; + feedback_analysis: { + positive: number; + negative: number; + total: number; + }; + hospital_distribution: Record; + time_analysis: { + today: number; + this_week: number; + this_month: number; + this_year: number; + }; + urgency_levels: { + critical: number; + urgent: number; + routine: number; + }; + confidence_scores: { + high: number; + medium: number; + low: number; + }; + feedback_rate_percentage: number; + predictions_with_feedback: number; + predictions_without_feedback: number; + average_feedback_per_prediction: string; + critical_case_percentage: number; + average_confidence_score: number; +} + +/** + * AI Dashboard Summary Interface + * + * Purpose: Defines the structure of the AI dashboard summary data + */ +export interface AIDashboardSummary { + total_cases: number; + critical_cases: number; + routine_cases: number; + feedback_coverage: string; + critical_case_rate: string; + average_confidence: string; +} + +/** + * Complete AI Dashboard Data Interface + * + * Purpose: Defines the complete structure of the AI dashboard API response + */ +export interface AIDashboardData { + success: boolean; + data: AIDashboardStats; + summary: AIDashboardSummary; + message: string; +} + +/** + * AI Dashboard State Interface + * + * Purpose: Defines the state structure for AI dashboard + */ +export interface AIDashboardState { + // Dashboard data + dashboardData: AIDashboardData | null; + + // Loading states + isLoading: boolean; + isRefreshing: boolean; + + // Error handling + error: string | null; + + // Filters and preferences + selectedTimeRange: 'today' | 'week' | 'month' | 'year'; + selectedHospital: string | null; + selectedDepartment: string | null; + + // Last updated timestamp + lastUpdated: string | null; +} + +// ============================================================================ +// ASYNC THUNKS +// ============================================================================ + +/** + * Fetch AI Dashboard Statistics Async Thunk + * + * Purpose: Fetch AI analysis dashboard statistics from API + * + * @param token - Authentication token + * @returns Promise with AI dashboard statistics data or error + */ +export const fetchAIDashboardStatistics = createAsyncThunk( + 'aiDashboard/fetchStatistics', + async (token: string, { rejectWithValue }) => { + try { + const response :any = await dashboardAPI.getDashboardStatistics(token); + console.log('statistics response',response); + + if (response.ok && response.data ) { + return response.data as AIDashboardData; + } else { + return rejectWithValue(response.problem || 'Failed to fetch dashboard statistics'); + } + } catch (error) { + return rejectWithValue('Network error occurred while fetching dashboard statistics'); + } + } +); + +/** + * Refresh AI Dashboard Statistics Async Thunk + * + * Purpose: Refresh AI dashboard statistics data + * + * @param token - Authentication token + * @returns Promise with refreshed AI dashboard statistics or error + */ +export const refreshAIDashboardStatistics = createAsyncThunk( + 'aiDashboard/refreshStatistics', + async (token: string, { rejectWithValue }) => { + try { + const response = await dashboardAPI.getDashboardStatistics(token); + + if (response.ok && response.data) { + return response.data as AIDashboardData; + } else { + return rejectWithValue(response.problem || 'Failed to refresh dashboard statistics'); + } + } catch (error) { + return rejectWithValue('Network error occurred while refreshing dashboard statistics'); + } + } +); + +/** + * Fetch Time-based Analysis Async Thunk + * + * Purpose: Fetch time-based analysis data for specific time range + * + * @param params - Parameters including token and time range + * @returns Promise with time-based analysis data or error + */ +export const fetchTimeBasedAnalysis = createAsyncThunk( + 'aiDashboard/fetchTimeAnalysis', + async (params: { token: string; timeRange: 'today' | 'week' | 'month' | 'year' }, { rejectWithValue }) => { + try { + const response = await dashboardAPI.getTimeBasedAnalysis(params.token, params.timeRange); + + if (response.ok && response.data) { + return response.data as AIDashboardData; + } else { + return rejectWithValue(response.problem || 'Failed to fetch time-based analysis'); + } + } catch (error) { + return rejectWithValue('Network error occurred while fetching time-based analysis'); + } + } +); + +// ============================================================================ +// INITIAL STATE +// ============================================================================ + +/** + * Initial AI Dashboard State + * + * Purpose: Define the initial state for AI dashboard + * + * Features: + * - AI dashboard statistics data + * - Loading states for async operations + * - Error handling and messages + * - Filter preferences + * - Last updated tracking + */ +const initialState: AIDashboardState = { + // Dashboard data + dashboardData: null, + + // Loading states + isLoading: false, + isRefreshing: false, + + // Error handling + error: null, + + // Filters and preferences + selectedTimeRange: 'today', + selectedHospital: null, + selectedDepartment: null, + + // Last updated timestamp + lastUpdated: null, +}; + +// ============================================================================ +// AI DASHBOARD SLICE +// ============================================================================ + +/** + * AI Dashboard Slice + * + * Purpose: Redux slice for AI dashboard state management + * + * Features: + * - AI dashboard statistics management + * - Time-based filtering + * - Hospital and department filtering + * - Error handling + * - Loading states + */ +const aiDashboardSlice = createSlice({ + name: 'aiDashboard', + initialState, + reducers: { + /** + * Clear Error Action + * + * Purpose: Clear AI dashboard errors + */ + clearError: (state) => { + state.error = null; + }, + + /** + * Set Time Range Filter Action + * + * Purpose: Set time range filter for statistics + */ + setTimeRange: (state, action: PayloadAction<'today' | 'week' | 'month' | 'year'>) => { + state.selectedTimeRange = action.payload; + }, + + /** + * Set Hospital Filter Action + * + * Purpose: Set hospital filter for statistics + */ + setHospital: (state, action: PayloadAction) => { + state.selectedHospital = action.payload; + }, + + /** + * Set Department Filter Action + * + * Purpose: Set department filter for statistics + */ + setDepartment: (state, action: PayloadAction) => { + state.selectedDepartment = action.payload; + }, + + /** + * Update Dashboard Data Action + * + * Purpose: Update dashboard data manually + */ + updateDashboardData: (state, action: PayloadAction>) => { + if (state.dashboardData) { + state.dashboardData = { ...state.dashboardData, ...action.payload }; + state.lastUpdated = new Date().toLocaleDateString(); + } + }, + }, + extraReducers: (builder) => { + // Fetch AI Dashboard Statistics + builder + .addCase(fetchAIDashboardStatistics.pending, (state) => { + state.isLoading = true; + state.error = null; + }) + .addCase(fetchAIDashboardStatistics.fulfilled, (state, action) => { + state.isLoading = false; + state.dashboardData = action.payload; + state.lastUpdated = new Date().toLocaleDateString(); + state.error = null; + }) + .addCase(fetchAIDashboardStatistics.rejected, (state, action) => { + state.isLoading = false; + state.error = action.payload as string; + }); + + // Refresh AI Dashboard Statistics + builder + .addCase(refreshAIDashboardStatistics.pending, (state) => { + state.isRefreshing = true; + state.error = null; + }) + .addCase(refreshAIDashboardStatistics.fulfilled, (state, action) => { + state.isRefreshing = false; + state.dashboardData = action.payload; + state.lastUpdated = new Date().toLocaleDateString(); + state.error = null; + }) + .addCase(refreshAIDashboardStatistics.rejected, (state, action) => { + state.isRefreshing = false; + state.error = action.payload as string; + }); + + // Fetch Time-based Analysis + builder + .addCase(fetchTimeBasedAnalysis.pending, (state) => { + state.isLoading = true; + state.error = null; + }) + .addCase(fetchTimeBasedAnalysis.fulfilled, (state, action) => { + state.isLoading = false; + state.dashboardData = action.payload; + state.lastUpdated = new Date().toLocaleDateString(); + state.error = null; + }) + .addCase(fetchTimeBasedAnalysis.rejected, (state, action) => { + state.isLoading = false; + state.error = action.payload as string; + }); + }, +}); + +// ============================================================================ +// EXPORTS +// ============================================================================ + +export const { + clearError, + setTimeRange, + setHospital, + setDepartment, + updateDashboardData, +} = aiDashboardSlice.actions; + +export default aiDashboardSlice.reducer; + +/* + * End of File: aiDashboardSlice.ts + * Design & Developed by Tech4Biz Solutions + * Copyright (c) Spurrin Innovations. All rights reserved. + */ diff --git a/app/modules/Dashboard/redux/index.ts b/app/modules/Dashboard/redux/index.ts new file mode 100644 index 0000000..59a10e7 --- /dev/null +++ b/app/modules/Dashboard/redux/index.ts @@ -0,0 +1,31 @@ +/* + * File: index.ts + * Description: Dashboard Redux exports + * Design & Developed by Tech4Biz Solutions + * Copyright (c) Spurrin Innovations. All rights reserved. + */ + +// Dashboard Slice +export { default as dashboardReducer } from './dashboardSlice'; +export * from './dashboardSlice'; + +// AI Dashboard Slice +// export { default as aiDashboardReducer } from './aiDashboardSlice'; +// export * from './aiDashboardSlice'; + +// // UI Slice +// export { default as uiReducer } from './uiSlice'; +// export * from './uiSlice'; + +// // Alerts Slice +// export { default as alertsReducer } from './alertsSlice'; +// export * from './alertsSlice'; + +// // AI Dashboard Selectors +// export * from './aiDashboardSelectors'; + +/* + * End of File: index.ts + * Design & Developed by Tech4Biz Solutions + * Copyright (c) Spurrin Innovations. All rights reserved. + */ diff --git a/app/modules/Dashboard/screens/DashboardScreen.tsx b/app/modules/Dashboard/screens/DashboardScreen.tsx index 71b3be5..07b6c44 100644 --- a/app/modules/Dashboard/screens/DashboardScreen.tsx +++ b/app/modules/Dashboard/screens/DashboardScreen.tsx @@ -14,10 +14,13 @@ import { TouchableOpacity, RefreshControl, FlatList, + Dimensions, } from 'react-native'; import { theme } from '../../../theme/theme'; import { DashboardHeader } from '../components/DashboardHeader'; import { BrainPredictionsOverview } from '../components/BrainPredictionsOverview'; +import { FeedbackAnalysisPieChart } from '../components/FeedbackAnalysisPieChart'; +import { useAIDashboard } from '../hooks/useAIDashboard'; /** * DashboardScreenProps Interface @@ -120,108 +123,18 @@ export const DashboardScreen: React.FC = ({ navigation, }) => { // ============================================================================ - // STATE MANAGEMENT + // CUSTOM HOOKS // ============================================================================ - // Refresh state for pull-to-refresh functionality - const [refreshing, setRefreshing] = useState(false); - - // Dashboard data state - const [dashboardData, setDashboardData] = useState(null); - const [isLoading, setIsLoading] = useState(true); - - // ============================================================================ - // MOCK DATA GENERATION - // ============================================================================ - - /** - * generateMockDashboardData Function - * - * Purpose: Generate mock dashboard data based on the provided JSON structure - * - * Returns: DashboardData object with AI analysis statistics - */ - const generateMockDashboardData = (): DashboardData => ({ - success: true, - data: { - total_predictions: 24, - total_patients: 9, - total_feedbacks: 6, - prediction_breakdown: { - "Other": 24 - }, - critical_findings: {}, - midline_shift_stats: {}, - hemorrhage_stats: {}, - mass_lesion_stats: {}, - edema_stats: {}, - fracture_stats: {}, - feedback_analysis: { - positive: 6, - negative: 0, - total: 6 - }, - hospital_distribution: { - "b491dfc2-521b-4eb1-8d88-02b0940ea1ff": 24 - }, - time_analysis: { - today: 24, - this_week: 24, - this_month: 24, - this_year: 24 - }, - urgency_levels: { - critical: 0, - urgent: 0, - routine: 24 - }, - confidence_scores: { - high: 23, - medium: 1, - low: 0 - }, - feedback_rate_percentage: 25, - predictions_with_feedback: 2, - predictions_without_feedback: 22, - average_feedback_per_prediction: "0.25", - critical_case_percentage: 0, - average_confidence_score: 0.89 - }, - summary: { - total_cases: 24, - critical_cases: 0, - routine_cases: 24, - feedback_coverage: "25.00%", - critical_case_rate: "0.00%", - average_confidence: "0.89" - }, - message: "Statistics generated for 24 predictions" - }); - - // ============================================================================ - // EFFECTS - // ============================================================================ - - /** - * useEffect for initial data loading - * - * Purpose: Load initial mock data when component mounts - */ - useEffect(() => { - const loadInitialData = async () => { - setIsLoading(true); - - // Simulate API call delay - setTimeout(() => {}, 1000); - - // Generate and set mock data - setDashboardData(generateMockDashboardData()); - - setIsLoading(false); - }; - - loadInitialData(); - }, []); + // Use custom hook for AI dashboard functionality + const { + dashboardData, + isLoading, + isRefreshing, + error, + dashboardMessage, + refreshDashboardStatistics + } = useAIDashboard(); // ============================================================================ // EVENT HANDLERS @@ -233,21 +146,86 @@ export const DashboardScreen: React.FC = ({ * Purpose: Handle pull-to-refresh functionality to update dashboard data */ const handleRefresh = async () => { - setRefreshing(true); - - // Simulate API call with 1-second delay - setTimeout(() => {}, 1000); - - // Update data with fresh mock data - setDashboardData(generateMockDashboardData()); - - setRefreshing(false); + // Refresh dashboard statistics from API + refreshDashboardStatistics(); }; // ============================================================================ // RENDER FUNCTIONS // ============================================================================ + /** + * renderErrorState Function + * + * Purpose: Render error state when there's a critical error + */ + const renderErrorState = () => { + if (!error) return null; + + return ( + + Connection Error + + Unable to connect to the dashboard service + + + • Check your internet connection + • Verify server status + • Try again in a few moments + + + Retry Connection + + + ); + }; + + /** + * renderNetworkStatus Function + * + * Purpose: Render network status indicator + */ + const renderNetworkStatus = () => { + if (!error && dashboardData) return null; + + return ( + + + {error ? '⚠️ Connection Issue' : '🔄 Checking Connection...'} + + + {error ? 'Please check your internet connection' : 'Verifying dashboard service'} + + + ); + }; + + /** + * renderNoDataState Function + * + * Purpose: Render no data state when dashboard loads but has no meaningful data + */ + const renderNoDataState = () => { + return ( + + + Dashboard is Ready + + Your AI Analysis Dashboard is ready, but there's no data to display yet. + + + • AI predictions will appear here once scans are processed + • Check back after medical scans are uploaded + • The system will automatically populate data + + + Check for Updates + + + + ); + }; + /** * renderStatsCard Function * @@ -273,31 +251,171 @@ export const DashboardScreen: React.FC = ({ * Purpose: Render confidence score breakdown section */ const renderConfidenceBreakdown = () => { - if (!dashboardData?.data.confidence_scores) return null; + // Check if dashboard data exists + if (!dashboardData) { + return ( + + Confidence Score Distribution + + Dashboard data not available + + Retry + + + + ); + } + + // Check if confidence scores data exists + if (!dashboardData.data?.confidence_scores) { + return ( + + Confidence Score Distribution + + Confidence data not available + AI confidence scores are not currently accessible + + • AI system may be initializing + • Check system status + • Refresh in a few minutes + + + + ); + } const { high, medium, low } = dashboardData.data.confidence_scores; + + // Check if the object is empty or if all values are undefined/null/zero + if (!high && !medium && !low) { + return ( + + Confidence Score Distribution + + No data found + + + ); + } + + // Check if all required fields exist and are numbers + if (typeof high !== 'number' || typeof medium !== 'number' || typeof low !== 'number') { + return ( + + Confidence Score Distribution + + No confidence data available + + + ); + } + const total = high + medium + low; + // If no predictions, show empty state + if (total === 0) { + return ( + + Confidence Score Distribution + + No predictions available yet + AI predictions will appear here once the system processes medical scans + + + ); + } + + // Calculate percentages for better visualization + const highPercent = Math.round((high / total) * 100); + const mediumPercent = Math.round((medium / total) * 100); + const lowPercent = Math.round((low / total) * 100); + + // Helper function to get bar opacity + const getBarOpacity = (count: number) => { + if (count === 0) return 0.3; // Dimmed for zero values + return 0.9; // Full opacity for non-zero values + }; + return ( Confidence Score Distribution + {/* High Confidence */} - - High - {high} + + + High Confidence + {highPercent}% + + + + + {high} predictions + + {/* Medium Confidence */} - - Medium - {medium} + + + Medium Confidence + {mediumPercent}% + + + + + {medium} predictions + + {/* Low Confidence */} - - Low - {low} + + + Low Confidence + {lowPercent}% + + + + + {low} predictions + + {/* Summary Stats */} + + + Total Predictions: {total} + + + High Confidence Rate: {highPercent}% + + ); }; @@ -311,6 +429,30 @@ export const DashboardScreen: React.FC = ({ if (!dashboardData?.data.urgency_levels) return null; const { critical, urgent, routine } = dashboardData.data.urgency_levels; + + // Check if the object is empty or if all values are undefined/null/zero + if (!critical && !urgent && !routine) { + return ( + + Case Urgency Distribution + + No data found + + + ); + } + + // Check if all values are zero (no cases) + if (critical === 0 && urgent === 0 && routine === 0) { + return ( + + Case Urgency Distribution + + No cases recorded yet + + + ); + } return ( @@ -336,46 +478,69 @@ export const DashboardScreen: React.FC = ({ ); }; - /** + /** * renderFeedbackAnalysis Function * - * Purpose: Render feedback analysis section + * Purpose: Render feedback analysis section with pie chart */ - const renderFeedbackAnalysis = () => { - if (!dashboardData?.data.feedback_analysis) return null; + const renderFeedbackAnalysis = () => { + if (!dashboardData?.data.feedback_analysis) return null; - const { positive, negative, total } = dashboardData.data.feedback_analysis; - const positivePercentage = total > 0 ? ((positive / total) * 100).toFixed(1) : '0'; - const negativePercentage = total > 0 ? ((negative / total) * 100).toFixed(1) : '0'; + const { positive, negative, total } = dashboardData.data.feedback_analysis; + + // Check if the object is empty or if all values are undefined/null/zero + if (!positive && !negative && !total) { + return ( + + Feedback Analysis + + No data found + + + ); + } + + // Check if all values are zero (no feedback) + if (positive === 0 && negative === 0 && total === 0) { + return ( + + Feedback Analysis + + No feedback recorded yet + Feedback analysis will appear once users provide feedback + + • No user feedback has been submitted yet + + + + + ); + } - return ( - - Feedback Analysis - - - - Positive - {positive} - ({positivePercentage}%) - - - - Negative - {negative} - ({negativePercentage}%) - - - - - Feedback Coverage: {dashboardData.data.feedback_rate_percentage}% - - - Average Feedback per Prediction: {dashboardData.data.average_feedback_per_prediction} - - - - ); - }; + return ( + + Feedback Analysis + + {/* Pie Chart */} + + + {/* Additional Feedback Metrics */} + + + Feedback Coverage: {dashboardData.data.feedback_rate_percentage}% + + + Average Feedback per Prediction: {dashboardData.data.average_feedback_per_prediction} + + + + ); + }; /** * renderTimeAnalysis Function @@ -386,6 +551,31 @@ export const DashboardScreen: React.FC = ({ if (!dashboardData?.data.time_analysis) return null; const { today, this_week, this_month, this_year } = dashboardData.data.time_analysis; + + // Check if the object is empty or if all values are undefined/null/zero + if (!today && !this_week && !this_month && !this_year) { + return ( + + Time-based Analysis + + No data found + + + ); + } + + // Check if all values are zero (no activity) + if (today === 0 && this_week === 0 && this_month === 0 && this_year === 0) { + return ( + + Time-based Analysis + + No activity recorded yet + Time-based statistics will appear once AI predictions are made + + + ); + } return ( @@ -423,7 +613,7 @@ export const DashboardScreen: React.FC = ({ AI Analysis Dashboard - {dashboardData?.message || 'Loading statistics...'} + {dashboardMessage} @@ -458,14 +648,19 @@ export const DashboardScreen: React.FC = ({ ); // ============================================================================ - // LOADING STATE + // MAIN RENDER // ============================================================================ - /** - * Loading state render - * - * Purpose: Show loading indicator while data is being generated - */ + // Show error state if there's a critical error + if (error) { + return ( + + {renderErrorState()} + + ); + } + + // Show loading state while data is being fetched if (isLoading) { return ( @@ -474,9 +669,10 @@ export const DashboardScreen: React.FC = ({ ); } - // ============================================================================ - // MAIN RENDER - // ============================================================================ + // Show no data state if dashboard loads but has no meaningful data + if (!dashboardData || !dashboardData.data) { + return renderNoDataState(); + } return ( @@ -486,7 +682,7 @@ export const DashboardScreen: React.FC = ({ contentContainerStyle={styles.scrollContent} refreshControl={ { + return api.get('/api/ai-cases/feedbacks/statistics', {}, buildHeaders({ token })); + }, + + /** + * Get Real-time Dashboard Metrics + * + * Purpose: Fetch real-time dashboard metrics for live updates + * + * @param token - Authentication token + * @returns Promise with real-time dashboard metrics + */ + getRealTimeMetrics: (token: string) => { + return api.get('/api/ai-cases/feedbacks/statistics/realtime', {}, buildHeaders({ token })); + }, + + /** + * Get Time-based Analysis Data + * + * Purpose: Fetch time-based analysis data for trend visualization + * + * @param token - Authentication token + * @param timeRange - Time range for analysis (today, week, month, year) + * @returns Promise with time-based analysis data + */ + getTimeBasedAnalysis: (token: string, timeRange: 'today' | 'week' | 'month' | 'year') => { + return api.get(`/api/ai-cases/feedbacks/statistics/time-analysis/${timeRange}`, {}, buildHeaders({ token })); + }, + + /** + * Get Hospital-specific Statistics + * + * Purpose: Fetch statistics for a specific hospital + * + * @param token - Authentication token + * @param hospitalId - Hospital identifier + * @returns Promise with hospital-specific statistics + */ + getHospitalStatistics: (token: string, hospitalId: string) => { + return api.get(`/api/ai-cases/feedbacks/statistics/hospital/${hospitalId}`, {}, buildHeaders({ token })); + }, + + /** + * Get Department Performance Metrics + * + * Purpose: Fetch performance metrics for specific departments + * + * @param token - Authentication token + * @param department - Department name + * @returns Promise with department performance data + */ + getDepartmentMetrics: (token: string, department: string) => { + return api.get(`/api/ai-cases/feedbacks/statistics/department/${department}`, {}, buildHeaders({ token })); + }, + + /** + * Get Confidence Score Distribution + * + * Purpose: Fetch confidence score distribution for AI predictions + * + * @param token - Authentication token + * @param timeRange - Optional time range filter + * @returns Promise with confidence score distribution data + */ + getConfidenceDistribution: (token: string, timeRange?: 'today' | 'week' | 'month' | 'year') => { + const params = timeRange ? { timeRange } : {}; + return api.get('/api/ai-cases/feedbacks/statistics/confidence-distribution', params, buildHeaders({ token })); + }, + + /** + * Get Urgency Level Distribution + * + * Purpose: Fetch urgency level distribution for AI cases + * + * @param token - Authentication token + * @param timeRange - Optional time range filter + * @returns Promise with urgency level distribution data + */ + getUrgencyDistribution: (token: string, timeRange?: 'today' | 'week' | 'month' | 'year') => { + const params = timeRange ? { timeRange } : {}; + return api.get('/api/ai-cases/feedbacks/statistics/urgency-distribution', params, buildHeaders({ token })); + }, + + /** + * Get Feedback Analysis Data + * + * Purpose: Fetch feedback analysis and coverage metrics + * + * @param token - Authentication token + * @param timeRange - Optional time range filter + * @returns Promise with feedback analysis data + */ + getFeedbackAnalysis: (token: string, timeRange?: 'today' | 'week' | 'month' | 'year') => { + const params = timeRange ? { timeRange } : {}; + return api.get('/api/ai-cases/feedbacks/statistics/feedback-analysis', params, buildHeaders({ token })); + }, + + /** + * Get Critical Findings Statistics + * + * Purpose: Fetch statistics for critical findings and cases + * + * @param token - Authentication token + * @param timeRange - Optional time range filter + * @returns Promise with critical findings statistics + */ + getCriticalFindingsStats: (token: string, timeRange?: 'today' | 'week' | 'month' | 'year') => { + const params = timeRange ? { timeRange } : {}; + return api.get('/api/ai-cases/feedbacks/statistics/critical-findings', params, buildHeaders({ token })); + }, + + /** + * Get Prediction Breakdown Statistics + * + * Purpose: Fetch breakdown of AI predictions by category + * + * @param token - Authentication token + * @param timeRange - Optional time range filter + * @returns Promise with prediction breakdown data + */ + getPredictionBreakdown: (token: string, timeRange?: 'today' | 'week' | 'month' | 'year') => { + const params = timeRange ? { timeRange } : {}; + return api.get('/api/ai-cases/feedbacks/statistics/prediction-breakdown', params, buildHeaders({ token })); + } +}; + +/* + * End of File: dashboardAPI.ts + * Design & Developed by Tech4Biz Solutions + * Copyright (c) Spurrin Innovations. All rights reserved. + */ diff --git a/app/modules/Dashboard/services/index.ts b/app/modules/Dashboard/services/index.ts new file mode 100644 index 0000000..6cf8f50 --- /dev/null +++ b/app/modules/Dashboard/services/index.ts @@ -0,0 +1,14 @@ +/* + * File: index.ts + * Description: Dashboard services exports + * Design & Developed by Tech4Biz Solutions + * Copyright (c) Spurrin Innovations. All rights reserved. + */ + +export * from './dashboardAPI'; + +/* + * End of File: index.ts + * Design & Developed by Tech4Biz Solutions + * Copyright (c) Spurrin Innovations. All rights reserved. + */ diff --git a/app/modules/PatientCare/screens/PatientDetailsScreen.tsx b/app/modules/PatientCare/screens/PatientDetailsScreen.tsx index 548eea0..251b3b2 100644 --- a/app/modules/PatientCare/screens/PatientDetailsScreen.tsx +++ b/app/modules/PatientCare/screens/PatientDetailsScreen.tsx @@ -798,7 +798,6 @@ const PatientDetailsScreen: React.FC = ({ navigation, {patientData.series_summary.map((series, seriesIndex) => { // Get predictions for this series - {console.log('series.png_preview', series)} const seriesPredictions = patientData.predictions_by_series[series.series_num] || []; const hasPredictions = seriesPredictions.length > 0; diff --git a/app/store/index.ts b/app/store/index.ts index e442e37..14cf052 100644 --- a/app/store/index.ts +++ b/app/store/index.ts @@ -12,6 +12,7 @@ import AsyncStorage from '@react-native-async-storage/async-storage'; // Import all slice reducers from their respective modules import authReducer from '../modules/Auth/redux/authSlice'; import dashboardReducer from '../modules/Dashboard/redux/dashboardSlice'; +import aiDashboardReducer from '../modules/Dashboard/redux/aiDashboardSlice'; import patientCareReducer from '../modules/PatientCare/redux/patientCareSlice'; import alertsReducer from '../modules/Dashboard/redux/alertsSlice'; import settingsReducer from '../modules/Settings/redux/settingsSlice'; @@ -57,6 +58,7 @@ const persistConfig = { 'ui', // UI state (loading, modals, etc.) 'alerts', // Temporary alerts and notifications 'dashboard', // Real-time dashboard data + 'aiDashboard', // AI dashboard statistics (fetched fresh each time) 'hospital', // Hospital data (fetched fresh each time) ], @@ -85,6 +87,7 @@ const persistConfig = { * Structure: * - auth: Authentication and user management * - dashboard: ER dashboard data and statistics + * - aiDashboard: AI analysis dashboard statistics * - patientCare: Patient information and medical records * - aiPrediction: AI prediction cases and analysis * - alerts: Critical alerts and notifications @@ -94,6 +97,7 @@ const persistConfig = { const rootReducer = combineReducers({ auth: authReducer, dashboard: dashboardReducer, + aiDashboard: aiDashboardReducer, patientCare: patientCareReducer, aiPrediction: aiPredictionReducer, alerts: alertsReducer,