From 366074c12a4d407b3d7ae1392aed317ea042b0c6 Mon Sep 17 00:00:00 2001 From: Jeff Bentley <57953093+jbentleyjp@users.noreply.github.com> Date: Thu, 12 Nov 2020 11:03:10 +0900 Subject: [PATCH] [Design/Routes] Welcome Screen / Initial Setup (#42) * feat(new component): welcome screen and initial setup component * feat(frontend): setup with login, settings, radarr/sonarr * feat(frontend): add login functionality to login step for setup Co-authored-by: Alexander Zoitos --- src/components/PlexLoginButton/index.tsx | 2 +- src/components/Settings/SettingsPlex.tsx | 9 +- src/components/Setup/LoginWithPlex.tsx | 54 ++++++++++++ src/components/Setup/SetupSteps.tsx | 76 +++++++++++++++++ src/components/Setup/index.tsx | 101 +++++++++++++++++++++++ src/pages/setup.tsx | 9 ++ 6 files changed, 249 insertions(+), 2 deletions(-) create mode 100644 src/components/Setup/LoginWithPlex.tsx create mode 100644 src/components/Setup/SetupSteps.tsx create mode 100644 src/components/Setup/index.tsx create mode 100644 src/pages/setup.tsx diff --git a/src/components/PlexLoginButton/index.tsx b/src/components/PlexLoginButton/index.tsx index 5a108fc64..4b18b9fe0 100644 --- a/src/components/PlexLoginButton/index.tsx +++ b/src/components/PlexLoginButton/index.tsx @@ -18,8 +18,8 @@ const PlexLoginButton: React.FC = ({ setLoading(true); try { const authToken = await plexOAuth.login(); - onAuthToken(authToken); setLoading(false); + onAuthToken(authToken); } catch (e) { if (onError) { onError(e.message); diff --git a/src/components/Settings/SettingsPlex.tsx b/src/components/Settings/SettingsPlex.tsx index c39c0e3b6..a1ef6f81f 100644 --- a/src/components/Settings/SettingsPlex.tsx +++ b/src/components/Settings/SettingsPlex.tsx @@ -48,7 +48,11 @@ interface SyncStatus { libraries: Library[]; } -const SettingsPlex: React.FC = () => { +interface SettingsPlexProps { + onComplete?: () => void; +} + +const SettingsPlex: React.FC = ({ onComplete }) => { const intl = useIntl(); const { data, error, revalidate } = useSWR( '/api/v1/settings/plex' @@ -78,6 +82,9 @@ const SettingsPlex: React.FC = () => { } as PlexSettings); revalidate(); + if (onComplete) { + onComplete(); + } } catch (e) { setSubmitError(e.response.data.message); } finally { diff --git a/src/components/Setup/LoginWithPlex.tsx b/src/components/Setup/LoginWithPlex.tsx new file mode 100644 index 000000000..77b33e653 --- /dev/null +++ b/src/components/Setup/LoginWithPlex.tsx @@ -0,0 +1,54 @@ +import React, { useEffect, useState } from 'react'; +import { useUser } from '../../hooks/useUser'; +import PlexLoginButton from '../PlexLoginButton'; +import axios from 'axios'; + +interface LoginWithPlexProps { + onComplete: () => void; +} + +const LoginWithPlex: React.FC = ({ onComplete }) => { + const [authToken, setAuthToken] = useState(undefined); + const { user, revalidate } = useUser(); + + // Effect that is triggered when the `authToken` comes back from the Plex OAuth + // We take the token and attempt to login. If we get a success message, we will + // ask swr to revalidate the user which _shouid_ come back with a valid user. + + useEffect(() => { + const login = async () => { + const response = await axios.post('/api/v1/auth/login', { authToken }); + + if (response.data?.email) { + revalidate(); + } + }; + if (authToken) { + login(); + } + }, [authToken, revalidate]); + + // Effect that is triggered whenever `useUser`'s user changes. If we get a new + // valid user, we call onComplete which will take us to the next step in Setup. + useEffect(() => { + if (user) { + onComplete(); + } + }, [user, onComplete]); + + return ( +
+
+ Welcome to Overseerr +
+
+ Get started by logging in with your Plex account +
+
+ setAuthToken(authToken)} /> +
+
+ ); +}; + +export default LoginWithPlex; diff --git a/src/components/Setup/SetupSteps.tsx b/src/components/Setup/SetupSteps.tsx new file mode 100644 index 000000000..2cb198ceb --- /dev/null +++ b/src/components/Setup/SetupSteps.tsx @@ -0,0 +1,76 @@ +import React from 'react'; + +interface CurrentStep { + stepNumber: number; + description: string; + active?: boolean; + completed?: boolean; + isLastStep?: boolean; +} + +const SetupSteps: React.FC = ({ + stepNumber, + description, + active = false, + completed = false, + isLastStep = false, +}) => { + return ( +
  • +
    +
    + {completed && ( + + + + )} + {!completed && ( +

    + {stepNumber} +

    + )} +
    +

    + {description} +

    +
    + + {!isLastStep && ( +
    + + + +
    + )} +
  • + ); +}; + +export default SetupSteps; diff --git a/src/components/Setup/index.tsx b/src/components/Setup/index.tsx new file mode 100644 index 000000000..b571b529a --- /dev/null +++ b/src/components/Setup/index.tsx @@ -0,0 +1,101 @@ +import { useRouter } from 'next/router'; +import React, { useState } from 'react'; +import Button from '../Common/Button'; +import ImageFader from '../Common/ImageFader'; +import SettingsPlex from '../Settings/SettingsPlex'; +import SettingsServices from '../Settings/SettingsServices'; +import LoginWithPlex from './LoginWithPlex'; +import SetupSteps from './SetupSteps'; + +const Setup: React.FC = () => { + const [currentStep, setCurrentStep] = useState(1); + const [plexSettingsComplete, setPlexSettingsComplete] = useState(false); + const router = useRouter(); + + return ( +
    + +
    + Overseerr Logo + +
    + {currentStep === 1 && ( + setCurrentStep(2)} /> + )} + {currentStep === 2 && ( +
    + setPlexSettingsComplete(true)} /> +
    +
    + + + +
    +
    +
    + )} + {currentStep === 3 && ( +
    + +
    +
    + + + +
    +
    +
    + )} +
    +
    +
    + ); +}; + +export default Setup; diff --git a/src/pages/setup.tsx b/src/pages/setup.tsx new file mode 100644 index 000000000..82a9c4597 --- /dev/null +++ b/src/pages/setup.tsx @@ -0,0 +1,9 @@ +import React from 'react'; +import { NextPage } from 'next'; +import Setup from '../components/Setup'; + +const SetupPage: NextPage = () => { + return ; +}; + +export default SetupPage;