import { useCallback, createContext, useContext, ReactNode } from 'react'; import { OperationOutcome, OperationOutcomeIssue } from 'fhir/r4'; export interface ProcessedOperationOutcomeIssue { severity: 'fatal' | 'error' | 'warning' | 'information'; code: string; diagnostics: string; location?: string[]; description: string; } export interface ProcessedOperationOutcome { hasErrors: boolean; hasWarnings: boolean; errorCount: number; warningCount: number; issues: ProcessedOperationOutcomeIssue[]; summary: string; } export const useErrorHandlerService = () => { const processOperationOutcome = useCallback((operationOutcome: OperationOutcome): ProcessedOperationOutcome => { if (!operationOutcome || !operationOutcome.issue) { return { hasErrors: false, hasWarnings: false, errorCount: 0, warningCount: 0, issues: [], summary: 'No issues found' }; } const processedIssues: ProcessedOperationOutcomeIssue[] = operationOutcome.issue.map((issue: OperationOutcomeIssue) => { return { severity: issue.severity, code: issue.code, diagnostics: issue.diagnostics || 'No diagnostic message provided', location: issue.location, description: generateIssueDescription(issue) }; }); const errorCount = processedIssues.filter(issue => issue.severity === 'error' || issue.severity === 'fatal').length; const warningCount = processedIssues.filter(issue => issue.severity === 'warning').length; return { hasErrors: errorCount > 0, hasWarnings: warningCount > 0, errorCount, warningCount, issues: processedIssues, summary: generateSummary(errorCount, warningCount, processedIssues.length) }; }, []); const generateIssueDescription = useCallback((issue: OperationOutcomeIssue): string => { const severityText = issue.severity.toUpperCase(); const locationText = issue.location && issue.location.length > 0 ? ` at ${issue.location.join(', ')}` : ''; return `${severityText}: ${issue.diagnostics || 'Unknown issue'}${locationText}`; }, []); const generateSummary = useCallback((errorCount: number, warningCount: number, totalIssues: number): string => { if (totalIssues === 0) { return 'No issues found'; } const parts: string[] = []; if (errorCount > 0) { parts.push(`${errorCount} error${errorCount > 1 ? 's' : ''}`); } if (warningCount > 0) { parts.push(`${warningCount} warning${warningCount > 1 ? 's' : ''}`); } const infoCount = totalIssues - errorCount - warningCount; if (infoCount > 0) { parts.push(`${infoCount} info message${infoCount > 1 ? 's' : ''}`); } return `Found ${parts.join(', ')}`; }, []); const getIssuesByLocation = useCallback((processedOutcome: ProcessedOperationOutcome, location: string): ProcessedOperationOutcomeIssue[] => { return processedOutcome.issues.filter(issue => issue.location && issue.location.some(loc => loc.includes(location)) ); }, []); const getIssuesBySeverity = useCallback((processedOutcome: ProcessedOperationOutcome, severity: 'fatal' | 'error' | 'warning' | 'information'): ProcessedOperationOutcomeIssue[] => { return processedOutcome.issues.filter(issue => issue.severity === severity); }, []); const formatIssuesForDisplay = useCallback((issues: ProcessedOperationOutcomeIssue[]): string[] => { return issues.map(issue => issue.description); }, []); const hasValidationErrors = useCallback((processedOutcome: ProcessedOperationOutcome): boolean => { return processedOutcome.issues.some(issue => (issue.severity === 'error' || issue.severity === 'fatal') && issue.code === 'processing' ); }, []); return { processOperationOutcome, generateIssueDescription, generateSummary, getIssuesByLocation, getIssuesBySeverity, formatIssuesForDisplay, hasValidationErrors }; }; const ErrorHandlerServiceContext = createContext | undefined>(undefined); export const ErrorHandlerServiceProvider: React.FC<{ children: ReactNode }> = ({ children }) => { const errorHandlerService = useErrorHandlerService(); return ( {children} ); }; export const useErrorHandlerServiceContext = () => { const context = useContext(ErrorHandlerServiceContext); if (context === undefined) { throw new Error('useErrorHandlerServiceContext must be used within an ErrorHandlerServiceProvider'); } return context; };