NeoScan_Radiologist/app/modules/AIPrediction/hooks/useAIPredictions.ts

384 lines
9.8 KiB
TypeScript

/*
* 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<typeof selectPaginatedCases>;
statistics: ReturnType<typeof selectCasesStatistics>;
// 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<void>;
refreshPredictions: () => Promise<void>;
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<void>;
// 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.
*/