All files / src/components/common/Error ErrorCatcher.tsx

19.56% Statements 9/46
38.09% Branches 8/21
50% Functions 3/6
19.56% Lines 9/46

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 193 194 195 196 197              309x                         309x                                                                                                                                                                                                                                                                     309x                   3080x 3080x   3080x 620x     3080x     4x                                                  
import { useEffect } from "react";
import { ErrorBoundary, FallbackProps } from "react-error-boundary";
import { useErrorUtilities } from "./useErrorUtilities";
import { useResetAction } from "./ResetActionContext";
import ErrorFallback from "./ErrorFallback";
 
const rocketSvgPath =
  "M13.625 24.5C13.625 24.7321 13.5328 24.9546 13.3687 25.1187C13.2046 25.2828 12.9821 25.375 12.75 25.375H9.25001C9.01795 25.375 8.79539 25.2828 8.63129 25.1187C8.4672 24.9546 8.37501 24.7321 8.37501 24.5C8.37501 24.268 8.4672 24.0454 8.63129 23.8813C8.79539 23.7172 9.01795 23.625 9.25001 23.625H12.75C12.9821 23.625 13.2046 23.7172 13.3687 23.8813C13.5328 24.0454 13.625 24.268 13.625 24.5ZM11 12.25C11.2596 12.25 11.5134 12.173 11.7292 12.0288C11.945 11.8846 12.1133 11.6796 12.2126 11.4398C12.3119 11.2 12.3379 10.9361 12.2873 10.6815C12.2366 10.4269 12.1116 10.193 11.9281 10.0094C11.7445 9.82589 11.5107 9.70088 11.2561 9.65024C11.0015 9.5996 10.7376 9.62559 10.4977 9.72493C10.2579 9.82427 10.0529 9.9925 9.90871 10.2083C9.76449 10.4242 9.68751 10.6779 9.68751 10.9375C9.68751 11.2856 9.82579 11.6195 10.0719 11.8656C10.3181 12.1117 10.6519 12.25 11 12.25ZM21.4584 17.0439L20.1066 23.1285C20.0424 23.4174 19.9061 23.6853 19.7102 23.9073C19.5144 24.1292 19.2654 24.2978 18.9867 24.3973C18.708 24.4968 18.4085 24.5241 18.1164 24.4764C17.8243 24.4288 17.5491 24.3078 17.3164 24.1249L14.337 21.875H7.66517L4.6836 24.1249C4.45095 24.3078 4.1757 24.4288 3.88358 24.4764C3.59147 24.5241 3.29205 24.4968 3.01332 24.3973C2.73459 24.2978 2.48566 24.1292 2.28981 23.9073C2.09395 23.6853 1.95758 23.4174 1.89345 23.1285L0.541573 17.0439C0.48423 16.7828 0.487127 16.5121 0.550046 16.2522C0.612965 15.9924 0.734251 15.7503 0.904698 15.5444L4.02845 11.7972C4.13329 10.4201 4.44944 9.06735 4.96579 7.78643C6.37673 4.24924 8.90329 2.03002 9.92814 1.24033C10.2349 1.00264 10.6119 0.873657 11 0.873657C11.3881 0.873657 11.7651 1.00264 12.0719 1.24033C13.0934 2.03002 15.6233 4.24924 17.0342 7.78643C17.5506 9.06735 17.8667 10.4201 17.9716 11.7972L21.0953 15.5444C21.2658 15.7503 21.3871 15.9924 21.45 16.2522C21.5129 16.5121 21.5158 16.7828 21.4584 17.0439ZM7.87517 20.125H14.1249C16.4349 16.0191 16.8669 12.0881 15.4089 8.43502C14.1227 5.21065 11.7099 3.1719 11 2.62502C10.288 3.1719 7.87517 5.21065 6.58892 8.43502C5.13314 12.0881 5.56517 16.0191 7.87517 20.125ZM6.23454 20.7649C5.05694 18.6248 4.34235 16.5215 4.09079 14.455L2.25001 16.6644L3.60189 22.75L3.62157 22.7358L6.23454 20.7649ZM19.75 16.6644L17.9092 14.455C17.6599 16.5171 16.9467 18.6204 15.7699 20.7649L18.3784 22.7336L18.3981 22.7478L19.75 16.6644Z";
 
type ErrorBoundaryProps<T> = {
  resetKeys?: T[];
  children: any;
  shouldLogError?: boolean;
  errorID: string;
  actionOnCrash?: <T>(...rest: T & any) => void;
  customMessage?: string;
  shouldRetry?: boolean;
  Fallback?: () => JSX.Element;
};
 
export const buildFallbackError = ({
  customTitle,
  customBody,
  customSvg,
}: {
  customTitle?: string;
  customBody?: string;
  customSvg?: {
    svgPath?: string;
    viewBox?: string;
  };
} = {}) => {
  const handleReload = async () => {
    try {
      await fetch(window.location.href, {
        headers: {
          Pragma: "no-cache",
          Expires: "-1",
          "Cache-Control": "no-cache",
        },
      });
    } finally {
      window.location.reload();
    }
  };
 
  //************   MAIN CONTAINER ************/
  const container = document.createElement("div");
  container.id = "crash-ui-fallback";
  Object.assign(container.style, {
    display: "flex",
    position: "fixed",
    top: "0",
    left: "0",
    height: "100dvh",
    width: "100%",
    background: "#fff",
    flexDirection: "column",
    alignItems: "center",
    justifyContent: "center",
    gap: "24px",
    zIndex: "10000",
    fontFamily: "Give Whyte,sans-serif",
  });
 
  //************ ICON CONTAINER ************/
  const iconWrapper = document.createElement("div");
  Object.assign(iconWrapper.style, {
    display: "flex",
    justifyContent: "center",
    alignItems: "center",
    width: "68px",
    height: "68px",
    borderRadius: "64px",
    background: "rgba(0, 0, 0, 0.05)",
  });
 
  //************ SVG ************/
  const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
  svg.setAttribute("viewBox", customSvg?.viewBox ?? "0 0 22 26");
  Object.assign(svg.style, {
    width: "24px",
    height: "24px",
    fill: "rgba(102, 102, 101, 1)",
  });
 
  const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
  path.setAttribute("d", customSvg?.svgPath ?? rocketSvgPath);
  svg.appendChild(path);
  iconWrapper.appendChild(svg);
 
  //************ CONTENT TITLE ************/
  const title = document.createElement("p");
  title.innerText = customTitle ?? "App Update";
  Object.assign(title.style, {
    textAlign: "center",
    fontSize: "18px",
    fontWeight: "regular",
    fontFamily: "Give Whyte,sans-serif",
    color: "rgba(41, 41, 40, 1)",
    margin: 0,
  });
 
  //************ CONTENT BODY ************/
  const message = document.createElement("p");
  message.innerText =
    customBody ??
    "We’ve made some improvements! Reload the app to check them out.";
  Object.assign(message.style, {
    textAlign: "center",
    color: "rgba(102, 102, 101, 1)",
    fontSize: "14px",
    fontFamily: "Give Whyte,sans-serif",
    margin: 0,
  });
 
  //************ RELOAD BUTTON ************/
  const button = document.createElement("button");
  button.innerText = "Reload Page";
  button.onclick = handleReload;
  Object.assign(button.style, {
    padding: "12px 24px",
    fontSize: "14px",
    border: "1.5px solid rgba(18, 18, 18, 1)",
    background: "transparent",
    borderRadius: "20px",
    cursor: "pointer",
    transition: "background 0.2s ease",
    color: "rgba(41, 41, 40, 1)",
    fontFamily: "Give Whyte,sans-serif",
  });
 
  //************ CONTENT WRAPPER ************/
  const contentWrapper = document.createElement("div");
  Object.assign(contentWrapper.style, {
    display: "flex",
    flexDirection: "column",
    alignItems: "center",
    justifyContent: "center",
    gap: "12px",
  });
 
  container.appendChild(iconWrapper);
  contentWrapper.appendChild(title);
  contentWrapper.appendChild(message);
  container.appendChild(contentWrapper);
  container.appendChild(button);
 
  document.body.appendChild(container);
};
 
const ErrorCatcher = <T,>({
  shouldLogError = false,
  resetKeys = [],
  children,
  errorID,
  actionOnCrash,
  customMessage = "Something went wrong",
  shouldRetry = false,
  Fallback,
}: ErrorBoundaryProps<T>) => {
  const { logError } = useErrorUtilities();
  const { getResetAction } = useResetAction();
 
  useEffect(() => {
    actionOnCrash && actionOnCrash();
  }, []);
 
  return (
    <ErrorBoundary
      FallbackComponent={(fallbackProps: FallbackProps) =>
        Fallback ? (
          <Fallback />
        ) : (
          <ErrorFallback
            {...fallbackProps}
            customMessage={customMessage}
            shouldRetry={shouldRetry}
          />
        )
      }
      onError={shouldLogError ? logError : undefined}
      onReset={() => {
        const resetAction = getResetAction(errorID);
        if (resetAction) {
          resetAction();
        }
      }}
      resetKeys={resetKeys}
    >
      {children}
    </ErrorBoundary>
  );
};
 
export default ErrorCatcher;