All files / src/components/ErrorBoundary PaymentErrorBoundary.tsx

93.33% Statements 14/15
83.33% Branches 10/12
100% Functions 4/4
93.33% Lines 14/15

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                                                                                                  14x                 237x   237x   14x                     14x 2x 2x   1x         237x   1x 1x 1x             237x         13x                                    
import React from "react";
import { ErrorBoundary, FallbackProps } from "react-error-boundary";
import PaymentErrorFallback from "./PaymentErrorFallback";
import { useNavigate } from "react-router-dom";
import { captureCheckoutError } from "@utils/errorHandling";
 
interface PaymentErrorBoundaryProps {
  children: React.ReactNode;
  /**
   * Whether this is a critical payment operation (checkout, payment processing)
   * If true, errors will be logged with high priority
   */
  isCritical?: boolean;
  onError?: (err: Error, errInfo: React.ErrorInfo) => void;
  /**
   * Callback to execute when user attempts to recover from error
   */
  onReset?: () => void;
  /**
   * Form ID for navigation and error context
   */
  formId?: string;
  FallbackComponent?: React.ComponentType<FallbackProps>;
  /**
   * Additional context to log with the error
   */
  errorContext?: Record<string, unknown>;
}
 
/**
 * PaymentErrorBoundary - Specialized error boundary for payment flows
 *
 * Features:
 * - Catches React errors in payment component tree
 * - Logs errors to Sentry with payment context
 * - Provides user-friendly fallback UI
 * - Offers safe recovery options
 *
 * Usage:
 * ```tsx
 * <PaymentErrorBoundary
 *   isCritical
 *   formId={formId}
 *   errorContext={{ cartItems, amount }}
 * >
 *   <CheckoutForm />
 * </PaymentErrorBoundary>
 * ```
 */
const PaymentErrorBoundary: React.FC<PaymentErrorBoundaryProps> = ({
  children,
  isCritical = true,
  onError,
  onReset,
  formId,
  FallbackComponent,
  errorContext = {},
}) => {
  const navigate = useNavigate();
 
  const handleError = (error: Error, errorInfo: React.ErrorInfo) => {
    // Log to Sentry with payment-specific context using captureCheckoutError
    captureCheckoutError(error, {
      level: isCritical ? "error" : "warning",
      isCritical,
      context: {
        formId,
        ...errorContext,
      },
      componentStack: errorInfo.componentStack || undefined,
    });
 
    // Execute custom error handler if provided
    if (onError) {
      try {
        onError(error, errorInfo);
      } catch (callbackError) {
        console.error("Error in onError callback:", callbackError);
      }
    }
  };
 
  const handleReset = () => {
    // Execute custom reset handler
    Eif (onReset) {
      try {
        onReset();
      } catch (callbackError) {
        console.error("Error in onReset callback:", callbackError);
      }
    }
  };
 
  return (
    <ErrorBoundary
      FallbackComponent={
        FallbackComponent ||
        ((props) => (
          <PaymentErrorFallback
            {...props}
            formId={formId}
            isCritical={isCritical}
            navigate={navigate}
            isBottomSheet={errorContext.isBottomSheet as boolean}
          />
        ))
      }
      onError={handleError}
      onReset={handleReset}
    >
      {children}
    </ErrorBoundary>
  );
};
 
export default PaymentErrorBoundary;