All files / src/hooks useCIAContentService.ts

100% Statements 20/20
100% Branches 0/0
100% Functions 4/4
100% Lines 20/20

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192                                                                                                                                                                                                                                                                                                            9x 815x   815x 815x   815x 423x 423x   423x   423x 422x 422x   1x 1x   423x         815x   1x 1x     815x 422x     815x              
import { useEffect, useState } from "react";
import {
  CIAContentService,
  createCIAContentService,
} from "../services/ciaContentService";
import { toErrorObject } from "../utils";
 
/**
 * Return type for useCIAContentService hook
 * 
 * Provides access to the CIA content service along with loading
 * and error states for proper UI handling.
 * 
 * @example
 * ```tsx
 * const { ciaContentService, isLoading, error, refresh } = useCIAContentService();
 * 
 * if (isLoading) return <LoadingSpinner />;
 * if (error) return <ErrorMessage error={error} onRetry={refresh} />;
 * if (!ciaContentService) return null;
 * 
 * // Use the service
 * const details = ciaContentService.getCIADetails('availability', 'High');
 * ```
 */
export interface UseCIAContentServiceReturn {
  /**
   * CIA content service instance
   * 
   * Null while loading or if initialization failed. Check isLoading
   * and error states before using.
   */
  ciaContentService: CIAContentService | null;
  
  /**
   * Loading state indicator
   * 
   * True during initial service initialization or when refresh() is called.
   * Use to show loading UI.
   */
  isLoading: boolean;
  
  /**
   * Error object if initialization failed
   * 
   * Null if no error occurred. When present, ciaContentService will be null.
   * Use to show error UI and provide retry option.
   */
  error: Error | null;
  
  /**
   * Function to retry service initialization
   * 
   * Call this to re-attempt service creation after an error,
   * or to refresh the service instance.
   * 
   * @example
   * ```tsx
   * {error && (
   *   <button onClick={refresh}>
   *     Retry Loading
   *   </button>
   * )}
   * ```
   */
  refresh: () => void;
}
 
/**
 * Custom hook to access the CIA content service with loading and error states
 * 
 * Provides a convenient way to access the CIAContentService in React components
 * with automatic initialization, loading states, and error handling. The service
 * is initialized once when the component mounts and can be refreshed on demand.
 * 
 * ## Features
 * - Automatic service initialization on mount
 * - Loading state management
 * - Error handling with retry capability
 * - Async initialization support
 * - Type-safe return values
 * 
 * ## Usage Guidelines
 * - Always check `isLoading` before rendering content
 * - Handle `error` state to provide user feedback
 * - Verify `ciaContentService` is not null before use
 * - Use `refresh()` to retry after errors
 * 
 * @returns Object containing the CIA content service, loading state, error state, and refresh function
 * 
 * @example
 * ```tsx
 * // Basic usage with loading and error handling
 * function MyComponent() {
 *   const { ciaContentService, isLoading, error, refresh } = useCIAContentService();
 * 
 *   if (isLoading) {
 *     return <div>Loading CIA content service...</div>;
 *   }
 * 
 *   if (error) {
 *     return (
 *       <div>
 *         <p>Error: {error.message}</p>
 *         <button onClick={refresh}>Retry</button>
 *       </div>
 *     );
 *   }
 * 
 *   if (!ciaContentService) {
 *     return <div>Service not available</div>;
 *   }
 * 
 *   // Safe to use the service here
 *   const availabilityDetails = ciaContentService.getCIADetails('availability', 'High');
 * 
 *   return <div>{availabilityDetails.description}</div>;
 * }
 * ```
 * 
 * @example
 * ```tsx
 * // Advanced usage with multiple service calls
 * function SecurityDashboard() {
 *   const { ciaContentService, isLoading, error } = useCIAContentService();
 *   const [selectedLevel, setSelectedLevel] = useState<SecurityLevel>('Moderate');
 * 
 *   if (isLoading || !ciaContentService) {
 *     return <LoadingSpinner />;
 *   }
 * 
 *   if (error) {
 *     return <ErrorBoundary error={error} />;
 *   }
 * 
 *   const availDetails = ciaContentService.getCIADetails('availability', selectedLevel);
 *   const integrityDetails = ciaContentService.getCIADetails('integrity', selectedLevel);
 *   const confDetails = ciaContentService.getCIADetails('confidentiality', selectedLevel);
 * 
 *   return (
 *     <div>
 *       <h2>Security Level: {selectedLevel}</h2>
 *       <ComponentCard title="Availability" details={availDetails} />
 *       <ComponentCard title="Integrity" details={integrityDetails} />
 *       <ComponentCard title="Confidentiality" details={confDetails} />
 *     </div>
 *   );
 * }
 * ```
 */
export const useCIAContentService = (): UseCIAContentServiceReturn => {
  const [ciaContentService, setCIAContentService] =
    useState<CIAContentService | null>(null);
  const [isLoading, setIsLoading] = useState<boolean>(true);
  const [error, setError] = useState<Error | null>(null);
 
  const initService = async () => {
    try {
      setIsLoading(true);
      // Create the service using the createCIAContentService factory function
      const service = createCIAContentService();
      // Wait for any async initialization to complete
      await service.initialize();
      setCIAContentService(service);
      setError(null);
    } catch (err) {
      setCIAContentService(null);
      setError(toErrorObject(err));
    } finally {
      setIsLoading(false);
    }
  };
 
  // Refresh function to retry initialization if needed
  const refresh = () => {
    // Make sure we set isLoading immediately, not after the async part
    setIsLoading(true);
    initService();
  };
 
  useEffect(() => {
    initService();
  }, []);
 
  return {
    ciaContentService,
    isLoading,
    error,
    refresh,
  };
};