Skip to content

Commit

Permalink
feat(project): show error page when config fails
Browse files Browse the repository at this point in the history
  • Loading branch information
ChristiaanScheermeijer committed Jun 18, 2021
1 parent fb28192 commit abe95c2
Show file tree
Hide file tree
Showing 9 changed files with 85 additions and 29 deletions.
18 changes: 15 additions & 3 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,27 @@ class App extends Component {
initializeFavorites();
}

configLoadingHandler = (isLoading: boolean) => {
console.info(`Loading config: ${isLoading}`)
};

configErrorHandler = (error: Error) => {
this.setState({ error });
};

configValidationCompletedHandler = (config: Config) => {
this.initializeServices(config);
};

render() {
return (
<I18nextProvider i18n={getI18n()}>
<QueryProvider>
<ConfigProvider
configLocation={window.configLocation}
onLoading={(isLoading: boolean) => console.info(`Loading config: ${isLoading}`)}
onValidationError={(error: Error) => console.error(`Config ${error}`)}
onValidationCompleted={(config) => this.initializeServices(config)}
onLoading={this.configLoadingHandler}
onValidationError={this.configErrorHandler}
onValidationCompleted={this.configValidationCompletedHandler}
>
<Router>
<Root error={this.state.error} />
Expand Down
10 changes: 9 additions & 1 deletion src/components/Root/Root.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React, { FC } from 'react';
import { Route, Switch } from 'react-router-dom';
import { useTranslation } from 'react-i18next';

import Series from '../../screens/Series/Series';
import Layout from '../Layout/Layout';
Expand All @@ -8,14 +9,21 @@ import Playlist from '../../screens/Playlist/Playlist';
import Settings from '../../screens/Settings/Settings';
import Movie from '../../screens/Movie/Movie';
import Search from '../../screens/Search/Search';
import ErrorPage from '../ErrorPage/ErrorPage';

type Props = {
error?: Error | null;
};

const Root: FC<Props> = ({ error }: Props) => {
const { t } = useTranslation('error');

if (error) {
return <div>Error!</div>;
return (
<ErrorPage title={t('generic_error_heading', 'There was an issue loading the application')}>
<p>{t('generic_error_description', 'Try refreshing this page or come back later.')}</p>
</ErrorPage>
);
}

return (
Expand Down
23 changes: 21 additions & 2 deletions src/components/Root/__snapshots__/Root.test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -135,8 +135,27 @@ exports[`<Root /> renders and matches snapshot 1`] = `

exports[`<Root /> renders error page when error prop is passed 1`] = `
<div>
<div>
Error!
<div
class="errorPage"
>
<div
class="box"
>
<header>
<h1
class="title"
>
generic_error_heading
</h1>
</header>
<main
class="main"
>
<p>
generic_error_description
</p>
</main>
</div>
</div>
</div>
`;
1 change: 1 addition & 0 deletions src/i18n/locales/en_US.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Run `$ yarn i18next:scan` to update this file

export { default as common } from './en_US/common.json';
export { default as error } from './en_US/error.json';
export { default as menu } from './en_US/menu.json';
export { default as search } from './en_US/search.json';
export { default as video } from './en_US/video.json';
4 changes: 4 additions & 0 deletions src/i18n/locales/en_US/error.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"generic_error_description": "There was an issue loading the application",
"generic_error_heading": "Try refreshing this page or come back later."
}
1 change: 1 addition & 0 deletions src/i18n/locales/nl_NL.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Run `$ yarn i18next:scan` to update this file

export { default as common } from './nl_NL/common.json';
export { default as error } from './nl_NL/error.json';
export { default as menu } from './nl_NL/menu.json';
export { default as search } from './nl_NL/search.json';
export { default as video } from './nl_NL/video.json';
4 changes: 4 additions & 0 deletions src/i18n/locales/nl_NL/error.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"generic_error_description": "",
"generic_error_heading": ""
}
21 changes: 13 additions & 8 deletions src/providers/ConfigProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,21 +30,26 @@ export type ProviderProps = {
onValidationCompleted: (config: Config) => void;
};

const ConfigProvider: FunctionComponent<ProviderProps> = ({
children,
configLocation,
onLoading,
onValidationError,
onValidationCompleted,
}) => {
const ConfigProvider: FunctionComponent<ProviderProps> = (
{
children,
configLocation,
onLoading,
onValidationError,
onValidationCompleted,
}
) => {
const [config, setConfig] = useState<Config>(defaultConfig);
const [loading, setLoading] = useState<boolean>(true);

useEffect(() => {
const loadAndValidateConfig = async (configLocation: string) => {
onLoading(true);
setLoading(true);
const config = await loadConfig(configLocation);
const config = await loadConfig(configLocation).catch((error) => {
onValidationError(error);
});

validateConfig(config)
.then((configValidated) => {
setConfig(() => merge({}, defaultConfig, configValidated));
Expand Down
32 changes: 17 additions & 15 deletions src/services/config.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,25 +54,27 @@ const loadConfig = async (configLocation: string) => {
if (!configLocation) {
return null;
}
try {
const response = await fetch(configLocation, {
headers: {
Accept: 'application/json',
},
method: 'GET',
});

const data = await response.json();
const response = await fetch(configLocation, {
headers: {
Accept: 'application/json',
},
method: 'GET',
});

addPersonalShelves(data);
if (!response.ok) {
throw new Error('Failed to load the config');
}

if (data.version) {
return parseDeprecatedConfig(data);
}
return data;
} catch (error: unknown) {
return error;
const data = await response.json();

addPersonalShelves(data);

if (data.version) {
return parseDeprecatedConfig(data);
}

return data;
};

/**
Expand Down

0 comments on commit abe95c2

Please sign in to comment.