Files
govoplan-core/webui/src/components/ModuleLoadBoundary.tsx
T

77 lines
2.0 KiB
TypeScript

import { Component, Suspense, type ErrorInfo, type ReactNode } from "react";
import Button from "./Button";
import DismissibleAlert from "./DismissibleAlert";
import LoadingIndicator from "./LoadingIndicator";
type ModuleLoadBoundaryProps = {
children: ReactNode;
resetKey: string;
loading?: boolean;
};
type ModuleLoadBoundaryState = {
error: Error | null;
};
export default class ModuleLoadBoundary extends Component<
ModuleLoadBoundaryProps,
ModuleLoadBoundaryState
> {
state: ModuleLoadBoundaryState = { error: null };
static getDerivedStateFromError(error: Error): ModuleLoadBoundaryState {
return { error };
}
componentDidCatch(error: Error, info: ErrorInfo) {
console.error("GovOPlaN module route failed to load", error, info);
}
componentDidUpdate(previousProps: ModuleLoadBoundaryProps) {
if (
previousProps.resetKey !== this.props.resetKey &&
this.state.error
) {
this.setState({ error: null });
}
}
render() {
if (this.props.loading) {
return <ModuleLoadProgress />;
}
if (this.state.error) {
return (
<div className="content-pad module-load-error">
<DismissibleAlert tone="danger" compact resetKey={`${this.props.resetKey}:${this.state.error.message}`}>
<p>i18n:govoplan-core.the_resource_could_not_be_loaded.0d1b6cbf</p>
<Button type="button" onClick={() => window.location.reload()}>
i18n:govoplan-core.reload.cce71553
</Button>
</DismissibleAlert>
</div>
);
}
return (
<Suspense
fallback={<ModuleLoadProgress />}
>
{this.props.children}
</Suspense>
);
}
}
function ModuleLoadProgress() {
return (
<div className="content-pad module-load-progress">
<LoadingIndicator
label="i18n:govoplan-core.loading_module.50161f3c"
size="md"
/>
<span>i18n:govoplan-core.loading_module.50161f3c</span>
</div>
);
}