2024-04-29 16:35:08 +02:00
|
|
|
/*
|
|
|
|
|
* Copyright (C) Contributors to the Suwayomi project
|
|
|
|
|
*
|
|
|
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
import { Component, ErrorInfo, ReactNode, useEffect, useRef, useState } from 'react';
|
|
|
|
|
import { useLocation } from 'react-router-dom';
|
2024-12-21 23:27:03 +01:00
|
|
|
import { getErrorMessage } from '@/lib/HelperFunctions.ts';
|
2024-04-29 16:35:08 +02:00
|
|
|
|
|
|
|
|
interface Props {
|
|
|
|
|
children?: ReactNode;
|
|
|
|
|
setTrackPathChange: (change: boolean) => void;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
interface State {
|
|
|
|
|
error: any;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class RealErrorBoundary extends Component<Props, State> {
|
|
|
|
|
// eslint-disable-next-line react/state-in-constructor
|
|
|
|
|
public state: State = { error: null };
|
|
|
|
|
|
|
|
|
|
private prevPath: string = '';
|
|
|
|
|
|
|
|
|
|
public static getDerivedStateFromError(error: any): State {
|
|
|
|
|
// Update state so the next render will show the fallback UI.
|
|
|
|
|
return { error };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
componentDidMount() {
|
|
|
|
|
this.prevPath = window.location.pathname;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public componentDidUpdate() {
|
|
|
|
|
if (window.location.pathname !== this.prevPath) {
|
|
|
|
|
this.setState({ error: null });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.prevPath = window.location.pathname;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public componentDidCatch(error: Error, errorInfo: ErrorInfo) {
|
2024-05-04 22:45:01 +02:00
|
|
|
// eslint-disable-next-line
|
2024-04-29 16:35:08 +02:00
|
|
|
console.error('Uncaught error:', error, errorInfo);
|
|
|
|
|
// eslint-disable-next-line react/destructuring-assignment
|
|
|
|
|
this.props.setTrackPathChange(true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public render() {
|
|
|
|
|
const { error } = this.state;
|
|
|
|
|
|
|
|
|
|
if (error) {
|
|
|
|
|
return (
|
|
|
|
|
<>
|
|
|
|
|
<h1>Something went wrong.</h1>
|
2024-12-21 23:27:03 +01:00
|
|
|
<p>{getErrorMessage(error)}</p>
|
2024-04-29 16:35:08 +02:00
|
|
|
</>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const { children } = this.props;
|
|
|
|
|
return children;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export const ErrorBoundary = ({ children }: { children: React.ReactNode }) => {
|
|
|
|
|
const [key, setKey] = useState(0);
|
|
|
|
|
const { pathname } = useLocation();
|
|
|
|
|
const previousPathnameRef = useRef(pathname);
|
|
|
|
|
const [trackPathChange, setTrackPathChange] = useState(false);
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
if (trackPathChange && previousPathnameRef.current !== pathname) {
|
|
|
|
|
previousPathnameRef.current = pathname;
|
|
|
|
|
setKey((currentKey) => (currentKey + 1) % 999999);
|
|
|
|
|
setTrackPathChange(false);
|
|
|
|
|
}
|
|
|
|
|
}, [pathname, previousPathnameRef.current, trackPathChange]);
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<RealErrorBoundary key={key} setTrackPathChange={setTrackPathChange}>
|
|
|
|
|
{children}
|
|
|
|
|
</RealErrorBoundary>
|
|
|
|
|
);
|
|
|
|
|
};
|