You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
overseerr/src/pages/_app.tsx

258 lines
8.0 KiB

import Layout from '@app/components/Layout';
import LoadingBar from '@app/components/LoadingBar';
import PWAHeader from '@app/components/PWAHeader';
import ServiceWorkerSetup from '@app/components/ServiceWorkerSetup';
import StatusChecker from '@app/components/StatusChecker';
import Toast from '@app/components/Toast';
import ToastContainer from '@app/components/ToastContainer';
import { InteractionProvider } from '@app/context/InteractionContext';
import type { AvailableLocale } from '@app/context/LanguageContext';
import { LanguageContext } from '@app/context/LanguageContext';
import { SettingsProvider } from '@app/context/SettingsContext';
import { UserContext } from '@app/context/UserContext';
import type { User } from '@app/hooks/useUser';
import '@app/styles/globals.css';
import { polyfillIntl } from '@app/utils/polyfillIntl';
import type { PublicSettingsResponse } from '@server/interfaces/api/settingsInterfaces';
import axios from 'axios';
import type { AppInitialProps, AppProps } from 'next/app';
import App from 'next/app';
import Head from 'next/head';
import { useEffect, useState } from 'react';
import { IntlProvider } from 'react-intl';
import { ToastProvider } from 'react-toast-notifications';
import { SWRConfig } from 'swr';
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const loadLocaleData = (locale: AvailableLocale): Promise<any> => {
switch (locale) {
case 'ar':
return import('../i18n/locale/ar.json');
case 'ca':
return import('../i18n/locale/ca.json');
case 'cs':
return import('../i18n/locale/cs.json');
case 'da':
return import('../i18n/locale/da.json');
case 'de':
return import('../i18n/locale/de.json');
case 'el':
return import('../i18n/locale/el.json');
case 'es':
return import('../i18n/locale/es.json');
case 'fr':
return import('../i18n/locale/fr.json');
case 'hr':
return import('../i18n/locale/hr.json');
case 'hu':
return import('../i18n/locale/hu.json');
case 'it':
return import('../i18n/locale/it.json');
case 'ja':
return import('../i18n/locale/ja.json');
case 'ko':
return import('../i18n/locale/ko.json');
case 'lt':
return import('../i18n/locale/lt.json');
case 'nb-NO':
return import('../i18n/locale/nb_NO.json');
case 'nl':
return import('../i18n/locale/nl.json');
case 'pl':
return import('../i18n/locale/pl.json');
case 'pt-BR':
return import('../i18n/locale/pt_BR.json');
case 'pt-PT':
return import('../i18n/locale/pt_PT.json');
case 'ru':
return import('../i18n/locale/ru.json');
case 'sq':
return import('../i18n/locale/sq.json');
case 'sr':
return import('../i18n/locale/sr.json');
case 'sv':
return import('../i18n/locale/sv.json');
case 'zh-CN':
return import('../i18n/locale/zh_Hans.json');
case 'zh-TW':
return import('../i18n/locale/zh_Hant.json');
default:
return import('../i18n/locale/en.json');
}
};
// Custom types so we can correctly type our GetInitialProps function
// with our combined user prop
// This is specific to _app.tsx. Other pages will not need to do this!
type NextAppComponentType = typeof App;
type MessagesType = Record<string, string>;
interface ExtendedAppProps extends AppProps {
user: User;
messages: MessagesType;
locale: AvailableLocale;
currentSettings: PublicSettingsResponse;
}
if (typeof window === 'undefined') {
global.Intl = require('intl');
}
const CoreApp: Omit<NextAppComponentType, 'origGetInitialProps'> = ({
Component,
pageProps,
router,
user,
messages,
locale,
currentSettings,
}: ExtendedAppProps) => {
let component: React.ReactNode;
const [loadedMessages, setMessages] = useState<MessagesType>(messages);
const [currentLocale, setLocale] = useState<AvailableLocale>(locale);
useEffect(() => {
loadLocaleData(currentLocale).then(setMessages);
}, [currentLocale]);
if (router.pathname.match(/(login|setup|resetpassword)/)) {
component = <Component {...pageProps} />;
} else {
component = (
<Layout>
<Component {...pageProps} />
</Layout>
);
}
return (
<SWRConfig
value={{
fetcher: (url) => axios.get(url).then((res) => res.data),
fallback: {
'/api/v1/auth/me': user,
},
}}
>
<LanguageContext.Provider value={{ locale: currentLocale, setLocale }}>
<IntlProvider
locale={currentLocale}
defaultLocale="en"
messages={loadedMessages}
>
<LoadingBar />
<SettingsProvider currentSettings={currentSettings}>
<InteractionProvider>
<ToastProvider components={{ Toast, ToastContainer }}>
<Head>
<title>{currentSettings.applicationTitle}</title>
<meta
name="viewport"
content="initial-scale=1, viewport-fit=cover, width=device-width"
></meta>
<PWAHeader
applicationTitle={currentSettings.applicationTitle}
/>
</Head>
<StatusChecker />
<ServiceWorkerSetup />
<UserContext initialUser={user}>{component}</UserContext>
</ToastProvider>
</InteractionProvider>
</SettingsProvider>
</IntlProvider>
</LanguageContext.Provider>
</SWRConfig>
);
};
CoreApp.getInitialProps = async (initialProps) => {
const { ctx, router } = initialProps;
let user: User | undefined = undefined;
let currentSettings: PublicSettingsResponse = {
initialized: false,
applicationTitle: '',
applicationUrl: '',
hideAvailable: false,
movie4kEnabled: false,
series4kEnabled: false,
localLogin: true,
region: '',
originalLanguage: '',
partialRequestsEnabled: true,
cacheImages: false,
vapidPublic: '',
enablePushRegistration: false,
locale: 'en',
emailEnabled: false,
newPlexLogin: true,
};
if (ctx.res) {
// Check if app is initialized and redirect if necessary
const response = await axios.get<PublicSettingsResponse>(
`http://localhost:${process.env.PORT || 5055}/api/v1/settings/public`
);
currentSettings = response.data;
const initialized = response.data.initialized;
if (!initialized) {
if (!router.pathname.match(/(setup|login\/plex)/)) {
ctx.res.writeHead(307, {
Location: '/setup',
});
ctx.res.end();
}
} else {
try {
// Attempt to get the user by running a request to the local api
const response = await axios.get<User>(
`http://localhost:${process.env.PORT || 5055}/api/v1/auth/me`,
build(deps): bump dependencies (#2454) * build(deps): bump react-select from 4.3.1 to 5.2.2 * build(deps): bump axios from 0.21.4 to 0.25.0 * build(deps-dev): bump lint-staged from 12.2.1 to 12.2.2 Bumps [lint-staged](https://github.com/okonet/lint-staged) from 12.2.1 to 12.2.2. - [Release notes](https://github.com/okonet/lint-staged/releases) - [Commits](https://github.com/okonet/lint-staged/compare/v12.2.1...v12.2.2) --- updated-dependencies: - dependency-name: lint-staged dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> * build(deps-dev): bump typescript from 4.5.4 to 4.5.5 Bumps [typescript](https://github.com/Microsoft/TypeScript) from 4.5.4 to 4.5.5. - [Release notes](https://github.com/Microsoft/TypeScript/releases) - [Commits](https://github.com/Microsoft/TypeScript/commits) --- updated-dependencies: - dependency-name: typescript dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> * build(deps-dev): bump eslint-plugin-formatjs from 2.20.3 to 2.20.4 Bumps [eslint-plugin-formatjs](https://github.com/formatjs/formatjs) from 2.20.3 to 2.20.4. - [Release notes](https://github.com/formatjs/formatjs/releases) - [Commits](https://github.com/formatjs/formatjs/compare/eslint-plugin-formatjs@2.20.3...eslint-plugin-formatjs@2.20.4) --- updated-dependencies: - dependency-name: eslint-plugin-formatjs dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> * build(deps-dev): bump @commitlint/cli from 16.0.3 to 16.1.0 Bumps [@commitlint/cli](https://github.com/conventional-changelog/commitlint/tree/HEAD/@commitlint/cli) from 16.0.3 to 16.1.0. - [Release notes](https://github.com/conventional-changelog/commitlint/releases) - [Changelog](https://github.com/conventional-changelog/commitlint/blob/master/@commitlint/cli/CHANGELOG.md) - [Commits](https://github.com/conventional-changelog/commitlint/commits/v16.1.0/@commitlint/cli) --- updated-dependencies: - dependency-name: "@commitlint/cli" dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> * build(deps): bump @tanem/react-nprogress from 4.0.3 to 4.0.4 Bumps [@tanem/react-nprogress](https://github.com/tanem/react-nprogress) from 4.0.3 to 4.0.4. - [Release notes](https://github.com/tanem/react-nprogress/releases) - [Changelog](https://github.com/tanem/react-nprogress/blob/master/CHANGELOG.md) - [Commits](https://github.com/tanem/react-nprogress/compare/v4.0.3...v4.0.4) --- updated-dependencies: - dependency-name: "@tanem/react-nprogress" dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> * fix: cleanup comments * build(deps-dev): bump lint-staged from 12.2.1 to 12.3.1 Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Ryan Cohen <ryan@sct.dev>
3 years ago
{
headers:
ctx.req && ctx.req.headers.cookie
? { cookie: ctx.req.headers.cookie }
: undefined,
}
);
user = response.data;
if (router.pathname.match(/(setup|login)/)) {
ctx.res.writeHead(307, {
Location: '/',
});
ctx.res.end();
}
} catch (e) {
// If there is no user, and ctx.res is set (to check if we are on the server side)
// _AND_ we are not already on the login or setup route, redirect to /login with a 307
// before anything actually renders
if (!router.pathname.match(/(login|setup|resetpassword)/)) {
ctx.res.writeHead(307, {
Location: '/login',
});
ctx.res.end();
}
}
}
}
// Run the default getInitialProps for the main nextjs initialProps
const appInitialProps: AppInitialProps = await App.getInitialProps(
initialProps
);
const locale = user?.settings?.locale
? user.settings.locale
: currentSettings.locale;
const messages = await loadLocaleData(locale as AvailableLocale);
await polyfillIntl(locale);
return { ...appInitialProps, user, messages, locale, currentSettings };
};
export default CoreApp;