Files
channels-seerr/src/components/Setup/index.tsx
Gauthier b36bb3fa58 refactor: switch from Axios for Fetch API (#840)
* refactor: switch ExternalAPI to Fetch API

* fix: add missing auth token in Plex request

* fix: send proper URL params

* ci: try to fix format checker

* ci: ci: try to fix format checker

* ci: try to fix format checker

* refactor: make tautulli use the ExternalAPI class

* refactor: add rate limit to fetch api

* refactor: add rate limit to fetch api

* refactor: switch server from axios to fetch api

* refactor: switch frontend from axios to fetch api

* fix: switch from URL objects to strings

* fix: use the right search params for ExternalAPI

* fix: better log for ExternalAPI errors

* feat: add retry to external API requests

* fix: try to fix network errors with IPv6

* fix: imageProxy rate limit

* revert: remove retry to external API requests

* feat: set IPv4 first as an option

* fix(jellyfinapi): add missing argument in JellyfinAPI constructor

* refactor: clean the rate limit utility
2024-07-14 19:04:36 +02:00

191 lines
6.6 KiB
TypeScript

import AppDataWarning from '@app/components/AppDataWarning';
import Badge from '@app/components/Common/Badge';
import Button from '@app/components/Common/Button';
import ImageFader from '@app/components/Common/ImageFader';
import PageTitle from '@app/components/Common/PageTitle';
import LanguagePicker from '@app/components/Layout/LanguagePicker';
import SettingsJellyfin from '@app/components/Settings/SettingsJellyfin';
import SettingsPlex from '@app/components/Settings/SettingsPlex';
import SettingsServices from '@app/components/Settings/SettingsServices';
import SetupSteps from '@app/components/Setup/SetupSteps';
import useLocale from '@app/hooks/useLocale';
import defineMessages from '@app/utils/defineMessages';
import { MediaServerType } from '@server/constants/server';
import Image from 'next/image';
import { useRouter } from 'next/router';
import { useState } from 'react';
import { useIntl } from 'react-intl';
import useSWR, { mutate } from 'swr';
import SetupLogin from './SetupLogin';
const messages = defineMessages('components.Setup', {
setup: 'Setup',
finish: 'Finish Setup',
finishing: 'Finishing…',
continue: 'Continue',
signin: 'Sign In',
configuremediaserver: 'Configure Media Server',
configureservices: 'Configure Services',
tip: 'Tip',
scanbackground:
'Scanning will run in the background. You can continue the setup process in the meantime.',
});
const Setup = () => {
const intl = useIntl();
const [isUpdating, setIsUpdating] = useState(false);
const [currentStep, setCurrentStep] = useState(1);
const [mediaServerSettingsComplete, setMediaServerSettingsComplete] =
useState(false);
const [mediaServerType, setMediaServerType] = useState(
MediaServerType.NOT_CONFIGURED
);
const router = useRouter();
const { locale } = useLocale();
const finishSetup = async () => {
setIsUpdating(true);
const res = await fetch('/api/v1/settings/initialize', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
});
if (!res.ok) throw new Error();
const data: { initialized: boolean } = await res.json();
setIsUpdating(false);
if (data.initialized) {
const mainRes = await fetch('/api/v1/settings/main', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ locale }),
});
if (!mainRes.ok) throw new Error();
mutate('/api/v1/settings/public');
router.push('/');
}
};
const { data: backdrops } = useSWR<string[]>('/api/v1/backdrops', {
refreshInterval: 0,
refreshWhenHidden: false,
revalidateOnFocus: false,
});
return (
<div className="relative flex min-h-screen flex-col justify-center bg-gray-900 py-12">
<PageTitle title={intl.formatMessage(messages.setup)} />
<ImageFader
backgroundImages={
backdrops?.map(
(backdrop) => `https://image.tmdb.org/t/p/original${backdrop}`
) ?? []
}
/>
<div className="absolute top-4 right-4 z-50">
<LanguagePicker />
</div>
<div className="relative z-40 px-4 sm:mx-auto sm:w-full sm:max-w-4xl">
<div className="relative mb-10 h-48 max-w-full sm:mx-auto sm:h-64 sm:max-w-md">
<Image src="/logo_stacked.svg" alt="Logo" fill />
</div>
<AppDataWarning />
<nav className="relative z-50">
<ul
className="divide-y divide-gray-600 rounded-md border border-gray-600 bg-gray-800 bg-opacity-50 md:flex md:divide-y-0"
style={{ backdropFilter: 'blur(5px)' }}
>
<SetupSteps
stepNumber={1}
description={intl.formatMessage(messages.signin)}
active={currentStep === 1}
completed={currentStep > 1}
/>
<SetupSteps
stepNumber={2}
description={intl.formatMessage(messages.configuremediaserver)}
active={currentStep === 2}
completed={currentStep > 2}
/>
<SetupSteps
stepNumber={3}
description={intl.formatMessage(messages.configureservices)}
active={currentStep === 3}
isLastStep
/>
</ul>
</nav>
<div className="mt-10 w-full rounded-md border border-gray-600 bg-gray-800 bg-opacity-50 p-4 text-white">
{currentStep === 1 && (
<SetupLogin
onComplete={(mServerType) => {
setMediaServerType(mServerType);
setCurrentStep(2);
}}
/>
)}
{currentStep === 2 && (
<div>
{mediaServerType === MediaServerType.PLEX ? (
<SettingsPlex
onComplete={() => setMediaServerSettingsComplete(true)}
/>
) : (
<SettingsJellyfin
showAdvancedSettings={false}
onComplete={() => setMediaServerSettingsComplete(true)}
/>
)}
<div className="mt-4 text-sm text-gray-500">
<span className="mr-2">
<Badge>{intl.formatMessage(messages.tip)}</Badge>
</span>
{intl.formatMessage(messages.scanbackground)}
</div>
<div className="actions">
<div className="flex justify-end">
<span className="ml-3 inline-flex rounded-md shadow-sm">
<Button
buttonType="primary"
disabled={!mediaServerSettingsComplete}
onClick={() => setCurrentStep(3)}
>
{intl.formatMessage(messages.continue)}
</Button>
</span>
</div>
</div>
</div>
)}
{currentStep === 3 && (
<div>
<SettingsServices />
<div className="actions">
<div className="flex justify-end">
<span className="ml-3 inline-flex rounded-md shadow-sm">
<Button
buttonType="primary"
onClick={() => finishSetup()}
disabled={isUpdating}
>
{isUpdating
? intl.formatMessage(messages.finishing)
: intl.formatMessage(messages.finish)}
</Button>
</span>
</div>
</div>
</div>
)}
</div>
</div>
</div>
);
};
export default Setup;