2021-07-31 15:57:43 +00:00
|
|
|
import type { ErrorInfo, FunctionComponent } from "react";
|
|
|
|
import { Component } from "react";
|
2021-08-01 10:36:32 +00:00
|
|
|
import {
|
|
|
|
Head,
|
|
|
|
withRouter,
|
|
|
|
AuthenticationError,
|
|
|
|
AuthorizationError,
|
|
|
|
CSRFTokenMismatchError,
|
|
|
|
NotFoundError,
|
|
|
|
RedirectError,
|
|
|
|
} from "blitz";
|
2021-07-31 15:57:43 +00:00
|
|
|
import type { WithRouterProps } from "next/dist/client/with-router";
|
2021-07-18 15:32:45 +00:00
|
|
|
|
2021-07-31 15:57:43 +00:00
|
|
|
import appLogger from "../../../../integrations/logger";
|
2021-07-18 15:32:45 +00:00
|
|
|
|
2021-07-31 15:57:43 +00:00
|
|
|
import Footer from "./footer";
|
2021-07-18 15:32:45 +00:00
|
|
|
|
|
|
|
type Props = {
|
2021-07-31 15:57:43 +00:00
|
|
|
title: string;
|
|
|
|
pageTitle?: string;
|
|
|
|
hideFooter?: true;
|
|
|
|
};
|
2021-07-18 15:32:45 +00:00
|
|
|
|
2021-07-31 15:57:43 +00:00
|
|
|
const logger = appLogger.child({ module: "Layout" });
|
2021-07-18 15:32:45 +00:00
|
|
|
|
2021-08-01 14:03:49 +00:00
|
|
|
const Layout: FunctionComponent<Props> = ({ children, title, pageTitle = title, hideFooter = false }) => {
|
2021-07-18 15:32:45 +00:00
|
|
|
return (
|
|
|
|
<>
|
|
|
|
{pageTitle ? (
|
|
|
|
<Head>
|
|
|
|
<title>{pageTitle}</title>
|
|
|
|
</Head>
|
|
|
|
) : null}
|
|
|
|
|
|
|
|
<div className="h-full w-full overflow-hidden fixed bg-gray-50">
|
|
|
|
<div className="flex flex-col w-full h-full">
|
|
|
|
<div className="flex flex-col flex-1 w-full overflow-y-auto">
|
2021-09-24 23:07:40 +00:00
|
|
|
<main className="flex flex-col flex-1 my-0 h-full">
|
2021-07-18 15:32:45 +00:00
|
|
|
<ErrorBoundary>{children}</ErrorBoundary>
|
|
|
|
</main>
|
|
|
|
</div>
|
2021-07-31 14:33:18 +00:00
|
|
|
{!hideFooter ? <Footer /> : null}
|
2021-07-18 15:32:45 +00:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</>
|
2021-07-31 15:57:43 +00:00
|
|
|
);
|
|
|
|
};
|
2021-07-18 15:32:45 +00:00
|
|
|
|
|
|
|
type ErrorBoundaryState =
|
|
|
|
| {
|
2021-07-31 15:57:43 +00:00
|
|
|
isError: false;
|
2021-07-18 15:32:45 +00:00
|
|
|
}
|
|
|
|
| {
|
2021-07-31 15:57:43 +00:00
|
|
|
isError: true;
|
|
|
|
errorMessage: string;
|
|
|
|
};
|
2021-07-18 15:32:45 +00:00
|
|
|
|
2021-08-01 14:03:49 +00:00
|
|
|
const blitzErrors = [RedirectError, AuthenticationError, AuthorizationError, CSRFTokenMismatchError, NotFoundError];
|
2021-08-01 10:36:32 +00:00
|
|
|
|
2021-07-18 15:32:45 +00:00
|
|
|
const ErrorBoundary = withRouter(
|
|
|
|
class ErrorBoundary extends Component<WithRouterProps, ErrorBoundaryState> {
|
|
|
|
public readonly state = {
|
|
|
|
isError: false,
|
2021-07-31 15:57:43 +00:00
|
|
|
} as const;
|
2021-07-18 15:32:45 +00:00
|
|
|
|
|
|
|
static getDerivedStateFromError(error: Error): ErrorBoundaryState {
|
|
|
|
return {
|
|
|
|
isError: true,
|
|
|
|
errorMessage: error.message,
|
2021-07-31 15:57:43 +00:00
|
|
|
};
|
2021-07-18 15:32:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public componentDidCatch(error: Error, errorInfo: ErrorInfo) {
|
2021-08-04 05:49:45 +00:00
|
|
|
console.trace("ddd");
|
2021-07-31 15:57:43 +00:00
|
|
|
logger.error(error, errorInfo.componentStack);
|
2021-08-01 11:21:49 +00:00
|
|
|
if (blitzErrors.some((blitzError) => error instanceof blitzError)) {
|
2021-08-01 10:36:32 +00:00
|
|
|
// let Blitz ErrorBoundary handle this one
|
|
|
|
throw error;
|
|
|
|
}
|
2021-08-05 17:07:15 +00:00
|
|
|
|
|
|
|
// if network error and connection lost, display the auto-reload page with countdown
|
2021-07-18 15:32:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public render() {
|
|
|
|
if (this.state.isError) {
|
|
|
|
return (
|
|
|
|
<>
|
|
|
|
<h2 className="mt-6 text-center text-3xl leading-9 font-extrabold text-gray-900">
|
|
|
|
Oops, something went wrong.
|
|
|
|
</h2>
|
|
|
|
<p className="mt-2 text-center text-lg leading-5 text-gray-600">
|
|
|
|
Would you like to{" "}
|
|
|
|
<button
|
|
|
|
className="inline-flex space-x-2 items-center text-left"
|
|
|
|
onClick={this.props.router.reload}
|
|
|
|
>
|
|
|
|
<span className="transition-colors duration-150 border-b border-primary-200 hover:border-primary-500">
|
|
|
|
reload the page
|
|
|
|
</span>
|
|
|
|
</button>{" "}
|
|
|
|
?
|
|
|
|
</p>
|
|
|
|
</>
|
2021-07-31 15:57:43 +00:00
|
|
|
);
|
2021-07-18 15:32:45 +00:00
|
|
|
}
|
|
|
|
|
2021-07-31 15:57:43 +00:00
|
|
|
return this.props.children;
|
2021-07-18 15:32:45 +00:00
|
|
|
}
|
2021-08-01 12:04:04 +00:00
|
|
|
},
|
2021-07-31 15:57:43 +00:00
|
|
|
);
|
2021-07-18 15:32:45 +00:00
|
|
|
|
2021-07-31 15:57:43 +00:00
|
|
|
export default Layout;
|