PorterErrorBoundary.tsx 1.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556
  1. import UnexpectedErrorPage from "components/UnexpectedErrorPage";
  2. import React from "react";
  3. import { ErrorBoundary } from "react-error-boundary";
  4. import * as Sentry from "@sentry/react";
  5. import StackTrace from "stacktrace-js";
  6. export type PorterErrorBoundaryProps<OnResetProps = {}> = {
  7. // Component or useful name to describe where the error boundary was setted
  8. errorBoundaryLocation: string;
  9. // Used in case the boundary shouldn't refresh but instead do other action
  10. onReset?: (props: OnResetProps) => unknown;
  11. };
  12. const PorterErrorBoundary: React.FC<PorterErrorBoundaryProps> = ({
  13. errorBoundaryLocation,
  14. onReset,
  15. children,
  16. }) => {
  17. const handleError = (err: Error, info: { componentStack: string }) => {
  18. StackTrace.fromError(err).then((error) => {
  19. if (process.env.SENTRY_ENABLED) {
  20. Sentry.captureException(error, (scope) => {
  21. scope.setTags({
  22. error_boundary_location: errorBoundaryLocation,
  23. error_message: err?.message,
  24. component_stack: info?.componentStack,
  25. });
  26. return scope;
  27. });
  28. }
  29. window?.analytics?.track("React Error", {
  30. location: errorBoundaryLocation,
  31. error: error.toString(),
  32. componentStack: info?.componentStack,
  33. url: window.location.toString(),
  34. });
  35. });
  36. };
  37. const handleOnReset = (props: unknown) => {
  38. typeof onReset === "function" ? onReset(props) : window.location.reload();
  39. };
  40. return (
  41. <ErrorBoundary
  42. onError={handleError}
  43. FallbackComponent={UnexpectedErrorPage}
  44. onReset={handleOnReset}
  45. >
  46. {children}
  47. </ErrorBoundary>
  48. );
  49. };
  50. export default PorterErrorBoundary;