feat(rebase): rebase

This commit is contained in:
Aiden Vigue
2021-02-15 20:29:55 -05:00
parent 9d61092f37
commit 3357343d98
14 changed files with 420 additions and 195 deletions

View File

@@ -0,0 +1,114 @@
import React from 'react';
import Transition from '../Transition';
import Modal from '../Common/Modal';
import { Formik, Field } from 'formik';
import * as Yup from 'yup';
import axios from 'axios';
import { defineMessages, useIntl } from 'react-intl';
import useSettings from '../../hooks/useSettings';
const messages = defineMessages({
title: 'Add Email',
description:
'Since this is your first time logging into {applicationName}, you are required to add a valid email address.',
email: 'Email address',
validationEmailRequired: 'You must provide an email',
validationEmailFormat: 'Invalid email',
saving: 'Adding…',
save: 'Add',
});
interface AddEmailModalProps {
username: string;
password: string;
onClose: () => void;
onSave: () => void;
}
const AddEmailModal: React.FC<AddEmailModalProps> = ({
onClose,
username,
password,
onSave,
}) => {
const intl = useIntl();
const settings = useSettings();
const EmailSettingsSchema = Yup.object().shape({
email: Yup.string()
.email(intl.formatMessage(messages.validationEmailFormat))
.required(intl.formatMessage(messages.validationEmailRequired)),
});
return (
<Transition
appear
show
enter="transition ease-in-out duration-300 transform opacity-0"
enterFrom="opacity-0"
enterTo="opacuty-100"
leave="transition ease-in-out duration-300 transform opacity-100"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<Formik
initialValues={{
email: '',
}}
validationSchema={EmailSettingsSchema}
onSubmit={async (values) => {
try {
await axios.post('/api/v1/auth/jellyfin', {
username: username,
password: password,
email: values.email,
});
onSave();
} catch (e) {
// set error here
}
}}
>
{({ errors, touched, handleSubmit, isSubmitting, isValid }) => {
return (
<Modal
onCancel={onClose}
okButtonType="primary"
okText={
isSubmitting
? intl.formatMessage(messages.saving)
: intl.formatMessage(messages.save)
}
okDisabled={isSubmitting || !isValid}
onOk={() => handleSubmit()}
title={intl.formatMessage(messages.title)}
>
{intl.formatMessage(messages.description, {
applicationName: settings.currentSettings.applicationTitle,
})}
<label htmlFor="email" className="text-label">
{intl.formatMessage(messages.email)}
</label>
<div className="mt-1 mb-2 sm:mt-0 sm:col-span-2">
<div className="flex rounded-md shadow-sm">
<Field
id="email"
name="email"
type="text"
placeholder={intl.formatMessage(messages.email)}
/>
</div>
{errors.email && touched.email && (
<div className="error">{errors.email}</div>
)}
</div>
</Modal>
);
}}
</Formik>
</Transition>
);
};
export default AddEmailModal;

View File

@@ -1,4 +1,4 @@
import React from 'react';
import React, { useState } from 'react';
import { defineMessages, useIntl } from 'react-intl';
import Button from '../Common/Button';
@@ -7,13 +7,17 @@ import * as Yup from 'yup';
import axios from 'axios';
import { useToasts } from 'react-toast-notifications';
import useSettings from '../../hooks/useSettings';
import AddEmailModal from './AddEmailModal';
const messages = defineMessages({
username: 'Username',
password: 'Password',
host: 'Jellyfin URL',
email: 'Email',
validationhostrequired: 'Jellyfin URL required',
validationhostformat: 'Valid URL required',
validationemailrequired: 'Email required',
validationemailformat: 'Valid email required',
validationusernamerequired: 'Username required',
validationpasswordrequired: 'Password required',
loginerror: 'Something went wrong while trying to sign in.',
@@ -34,6 +38,9 @@ const JellyfinLogin: React.FC<JellyfinLoginProps> = ({
revalidate,
initial,
}) => {
const [requiresEmail, setRequiresEmail] = useState<number>(0);
const [username, setUsername] = useState<string>();
const [password, setPassword] = useState<string>();
const toasts = useToasts();
const intl = useIntl();
const settings = useSettings();
@@ -43,6 +50,9 @@ const JellyfinLogin: React.FC<JellyfinLoginProps> = ({
host: Yup.string()
.url(intl.formatMessage(messages.validationhostformat))
.required(intl.formatMessage(messages.validationhostrequired)),
email: Yup.string()
.email(intl.formatMessage(messages.validationemailformat))
.required(intl.formatMessage(messages.validationemailrequired)),
username: Yup.string().required(
intl.formatMessage(messages.validationusernamerequired)
),
@@ -56,6 +66,7 @@ const JellyfinLogin: React.FC<JellyfinLoginProps> = ({
username: '',
password: '',
host: '',
email: '',
}}
validationSchema={LoginSchema}
onSubmit={async (values) => {
@@ -64,6 +75,7 @@ const JellyfinLogin: React.FC<JellyfinLoginProps> = ({
username: values.username,
password: values.password,
hostname: values.host,
email: values.email,
});
} catch (e) {
toasts.addToast(
@@ -101,6 +113,22 @@ const JellyfinLogin: React.FC<JellyfinLoginProps> = ({
<div className="error">{errors.host}</div>
)}
</div>
<label htmlFor="email" className="text-label">
{intl.formatMessage(messages.email)}
</label>
<div className="mt-1 mb-2 sm:mt-0 sm:col-span-2">
<div className="flex rounded-md shadow-sm">
<Field
id="email"
name="email"
type="text"
placeholder={intl.formatMessage(messages.email)}
/>
</div>
{errors.email && touched.email && (
<div className="error">{errors.email}</div>
)}
</div>
<label htmlFor="username" className="text-label">
{intl.formatMessage(messages.username)}
</label>
@@ -163,105 +191,121 @@ const JellyfinLogin: React.FC<JellyfinLoginProps> = ({
),
});
return (
<Formik
initialValues={{
username: '',
password: '',
}}
validationSchema={LoginSchema}
onSubmit={async (values) => {
try {
await axios.post('/api/v1/auth/jellyfin', {
username: values.username,
password: values.password,
});
} catch (e) {
toasts.addToast(
intl.formatMessage(
e.message == 'Request failed with status code 401'
? messages.credentialerror
: messages.loginerror
),
{
autoDismiss: true,
appearance: 'error',
<div>
{requiresEmail == 1 && (
<AddEmailModal
username={username ?? ''}
password={password ?? ''}
onSave={revalidate}
onClose={() => setRequiresEmail(0)}
></AddEmailModal>
)}
<Formik
initialValues={{
username: '',
password: '',
}}
validationSchema={LoginSchema}
onSubmit={async (values) => {
try {
await axios.post('/api/v1/auth/jellyfin', {
username: values.username,
password: values.password,
});
} catch (e) {
if (e.message === 'Request failed with status code 406') {
setUsername(values.username);
setPassword(values.password);
setRequiresEmail(1);
} else {
toasts.addToast(
intl.formatMessage(
e.message == 'Request failed with status code 401'
? messages.credentialerror
: messages.loginerror
),
{
autoDismiss: true,
appearance: 'error',
}
);
}
} finally {
revalidate();
}
}}
>
{({ errors, touched, isSubmitting, isValid }) => {
return (
<>
<Form>
<div className="sm:border-t sm:border-gray-800">
<label htmlFor="username" className="text-label">
{intl.formatMessage(messages.username)}
</label>
<div className="mt-1 mb-2 sm:mt-0 sm:col-span-2">
<div className="flex max-w-lg rounded-md shadow-sm">
<Field
id="username"
name="username"
type="text"
placeholder={intl.formatMessage(messages.username)}
/>
</div>
{errors.username && touched.username && (
<div className="error">{errors.username}</div>
)}
</div>
<label htmlFor="password" className="text-label">
{intl.formatMessage(messages.password)}
</label>
<div className="mt-1 mb-2 sm:mt-0 sm:col-span-2">
<div className="flex max-w-lg rounded-md shadow-sm">
<Field
id="password"
name="password"
type="password"
placeholder={intl.formatMessage(messages.password)}
/>
</div>
{errors.password && touched.password && (
<div className="error">{errors.password}</div>
)}
</div>
</div>
<div className="pt-5 mt-8 border-t border-gray-700">
<div className="flex justify-between">
<span className="inline-flex rounded-md shadow-sm">
<Button
as="a"
buttonType="ghost"
href={
settings.currentSettings.jellyfinHost +
'/web/#!/forgotpassword.html'
}
>
{intl.formatMessage(messages.forgotpassword)}
</Button>
</span>
<span className="inline-flex rounded-md shadow-sm">
<Button
buttonType="primary"
type="submit"
disabled={isSubmitting || !isValid}
>
{isSubmitting
? intl.formatMessage(messages.signingin)
: intl.formatMessage(messages.signin)}
</Button>
</span>
</div>
</div>
</Form>
</>
);
} finally {
revalidate();
}
}}
>
{({ errors, touched, isSubmitting, isValid }) => {
return (
<>
<Form>
<div className="sm:border-t sm:border-gray-800">
<label htmlFor="username" className="text-label">
{intl.formatMessage(messages.username)}
</label>
<div className="mt-1 mb-2 sm:mt-0 sm:col-span-2">
<div className="flex max-w-lg rounded-md shadow-sm">
<Field
id="username"
name="username"
type="text"
placeholder={intl.formatMessage(messages.username)}
/>
</div>
{errors.username && touched.username && (
<div className="error">{errors.username}</div>
)}
</div>
<label htmlFor="password" className="text-label">
{intl.formatMessage(messages.password)}
</label>
<div className="mt-1 mb-2 sm:mt-0 sm:col-span-2">
<div className="flex max-w-lg rounded-md shadow-sm">
<Field
id="password"
name="password"
type="password"
placeholder={intl.formatMessage(messages.password)}
/>
</div>
{errors.password && touched.password && (
<div className="error">{errors.password}</div>
)}
</div>
</div>
<div className="pt-5 mt-8 border-t border-gray-700">
<div className="flex justify-between">
<span className="inline-flex rounded-md shadow-sm">
<Button
as="a"
buttonType="ghost"
href={
settings.currentSettings.jellyfinHost +
'/web/#!/forgotpassword.html'
}
>
{intl.formatMessage(messages.forgotpassword)}
</Button>
</span>
<span className="inline-flex rounded-md shadow-sm">
<Button
buttonType="primary"
type="submit"
disabled={isSubmitting || !isValid}
>
{isSubmitting
? intl.formatMessage(messages.signingin)
: intl.formatMessage(messages.signin)}
</Button>
</span>
</div>
</div>
</Form>
</>
);
}}
</Formik>
}}
</Formik>
</div>
);
}
};

View File

@@ -62,18 +62,18 @@ const SetupLogin: React.FC<LoginWithMediaServerProps> = ({ onComplete }) => {
{({ openIndexes, handleClick, AccordionContent }) => (
<>
<button
className={`w-full py-2 text-sm text-center hover:bg-gray-700 hover:cursor-pointer text-gray-400 transition-colors duration-200 bg-gray-800 cursor-default focus:outline-none sm:rounded-t-lg ${
className={`w-full py-2 text-sm text-center hover:bg-gray-700 hover:cursor-pointer text-gray-400 transition-colors duration-200 bg-gray-900 cursor-default focus:outline-none sm:rounded-t-lg ${
openIndexes.includes(0) && 'text-indigo-500'
}`}
} ${openIndexes.includes(1) && 'border-b border-gray-500'}`}
onClick={() => handleClick(0)}
>
<FormattedMessage {...messages.signinWithPlex} />
</button>
<AccordionContent
className="bg-opacity-90"
isOpen={openIndexes.includes(0)}
>
<div className="px-10 py-8">
<AccordionContent isOpen={openIndexes.includes(0)}>
<div
className="px-10 py-8"
style={{ backgroundColor: 'rgba(0,0,0,0.3)' }}
>
<PlexLoginButton
onAuthToken={(authToken) => {
setMediaServerType(MediaServerType.PLEX);
@@ -84,7 +84,7 @@ const SetupLogin: React.FC<LoginWithMediaServerProps> = ({ onComplete }) => {
</AccordionContent>
<div>
<button
className={`w-full py-2 text-sm text-center text-gray-400 transition-colors duration-200 bg-gray-800 cursor-default focus:outline-none hover:bg-gray-700 hover:cursor-pointer ${
className={`w-full py-2 text-sm text-center text-gray-400 transition-colors duration-200 bg-gray-900 cursor-default focus:outline-none hover:bg-gray-700 hover:cursor-pointer ${
openIndexes.includes(1)
? 'text-indigo-500'
: 'sm:rounded-b-lg'
@@ -93,11 +93,11 @@ const SetupLogin: React.FC<LoginWithMediaServerProps> = ({ onComplete }) => {
>
<FormattedMessage {...messages.signinWithJellyfin} />
</button>
<AccordionContent
className="bg-opacity-90"
isOpen={openIndexes.includes(1)}
>
<div className="px-10 py-8">
<AccordionContent isOpen={openIndexes.includes(1)}>
<div
className="px-10 py-8 rounded-b-lg"
style={{ backgroundColor: 'rgba(0,0,0,0.3)' }}
>
<JellyfinLogin initial={true} revalidate={revalidate} />
</div>
</AccordionContent>

View File

@@ -104,7 +104,10 @@ const Setup: React.FC = () => {
/>
</ul>
</nav>
<div className="w-full p-4 mt-10 text-white bg-gray-800 bg-opacity-50 border border-gray-600 rounded-md">
<div
style={{ backdropFilter: 'blur(5px)' }}
className="w-full p-4 mt-10 text-white bg-gray-800 border border-gray-600 rounded-md bg-opacity-40"
>
{currentStep === 1 && (
<SetupLogin
onComplete={() => {

View File

@@ -37,6 +37,7 @@
"components.Layout.UserDropdown.signout": "Sign Out",
"components.Layout.alphawarning": "This is ALPHA software. Features may be broken and/or unstable. Please report issues on GitHub!",
"components.Login.credentialerror": "The username or password is incorrect.",
"components.Login.description": "Since this is your first time logging into {applicationName}, you are required to add a valid email address.",
"components.Login.email": "Email Address",
"components.Login.forgotpassword": "Forgot Password?",
"components.Login.host": "Jellyfin URL",
@@ -44,13 +45,19 @@
"components.Login.initialsigningin": "Connecting…",
"components.Login.loginerror": "Something went wrong while trying to sign in.",
"components.Login.password": "Password",
"components.Login.save": "Add",
"components.Login.saving": "Adding…",
"components.Login.signin": "Sign In",
"components.Login.signingin": "Signing in…",
"components.Login.signinheader": "Sign in to continue",
"components.Login.signinwithjellyfin": "Use your Jellyfin account",
"components.Login.signinwithoverseerr": "Use your {applicationTitle} account",
"components.Login.signinwithplex": "Use your Plex account",
"components.Login.title": "Add Email",
"components.Login.username": "Username",
"components.Login.validationEmailFormat": "Invalid email",
"components.Login.validationEmailRequired": "You must provide an email",
"components.Login.validationemailformat": "Valid email required",
"components.Login.validationemailrequired": "You must provide a valid email address",
"components.Login.validationhostformat": "Valid URL required",
"components.Login.validationhostrequired": "Jellyfin URL required",
@@ -598,8 +605,8 @@
"components.Setup.setup": "Setup",
"components.Setup.signin": "Sign In",
"components.Setup.signinMessage": "Get started by signing in",
"components.Setup.signinWithJellyfin": "Use Jellyfin",
"components.Setup.signinWithPlex": "Sign in with Plex",
"components.Setup.signinWithJellyfin": "Use your Jellyfin account",
"components.Setup.signinWithPlex": "Use your Plex account",
"components.Setup.syncingbackground": "Syncing will run in the background. You can continue the setup process in the meantime.",
"components.Setup.tip": "Tip",
"components.Setup.welcome": "Welcome to Overseerr",