Merge remote-tracking branch 'overseerr/develop' into develop

This commit is contained in:
notfakie
2022-09-01 18:11:15 +12:00
473 changed files with 15548 additions and 8433 deletions

View File

@@ -1,30 +1,28 @@
import Badge from '@app/components/Common/Badge';
import Button from '@app/components/Common/Button';
import LoadingSpinner from '@app/components/Common/LoadingSpinner';
import PageTitle from '@app/components/Common/PageTitle';
import LanguageSelector from '@app/components/LanguageSelector';
import QuotaSelector from '@app/components/QuotaSelector';
import RegionSelector from '@app/components/RegionSelector';
import type { AvailableLocale } from '@app/context/LanguageContext';
import { availableLanguages } from '@app/context/LanguageContext';
import useLocale from '@app/hooks/useLocale';
import useSettings from '@app/hooks/useSettings';
import { Permission, UserType, useUser } from '@app/hooks/useUser';
import globalMessages from '@app/i18n/globalMessages';
import Error from '@app/pages/_error';
import { SaveIcon } from '@heroicons/react/outline';
import type { UserSettingsGeneralResponse } from '@server/interfaces/api/userSettingsInterfaces';
import axios from 'axios';
import { Field, Form, Formik } from 'formik';
import getConfig from 'next/config';
import { useRouter } from 'next/router';
import React, { useEffect, useState } from 'react';
import { useEffect, useState } from 'react';
import { defineMessages, useIntl } from 'react-intl';
import { useToasts } from 'react-toast-notifications';
import useSWR from 'swr';
import * as Yup from 'yup';
import { UserSettingsGeneralResponse } from '../../../../../server/interfaces/api/userSettingsInterfaces';
import {
availableLanguages,
AvailableLocale,
} from '../../../../context/LanguageContext';
import useLocale from '../../../../hooks/useLocale';
import useSettings from '../../../../hooks/useSettings';
import { Permission, UserType, useUser } from '../../../../hooks/useUser';
import globalMessages from '../../../../i18n/globalMessages';
import Error from '../../../../pages/_error';
import Badge from '../../../Common/Badge';
import Button from '../../../Common/Button';
import LoadingSpinner from '../../../Common/LoadingSpinner';
import PageTitle from '../../../Common/PageTitle';
import LanguageSelector from '../../../LanguageSelector';
import QuotaSelector from '../../../QuotaSelector';
import RegionSelector from '../../../RegionSelector';
import getConfig from 'next/config';
const messages = defineMessages({
general: 'General',
@@ -56,9 +54,15 @@ const messages = defineMessages({
discordIdTip:
'The <FindDiscordIdLink>multi-digit ID number</FindDiscordIdLink> associated with your Discord user account',
validationDiscordId: 'You must provide a valid Discord user ID',
plexwatchlistsyncmovies: 'Auto-Request Movies',
plexwatchlistsyncmoviestip:
'Automatically request movies on your <PlexWatchlistSupportLink>Plex Watchlist</PlexWatchlistSupportLink>',
plexwatchlistsyncseries: 'Auto-Request Series',
plexwatchlistsyncseriestip:
'Automatically request series on your <PlexWatchlistSupportLink>Plex Watchlist</PlexWatchlistSupportLink>',
});
const UserGeneralSettings: React.FC = () => {
const UserGeneralSettings = () => {
const intl = useIntl();
const { publicRuntimeConfig } = getConfig();
const { addToast } = useToasts();
@@ -86,7 +90,7 @@ const UserGeneralSettings: React.FC = () => {
const UserGeneralSettingsSchema = Yup.object().shape({
discordId: Yup.string()
.nullable()
.matches(/^\d{17,18}$/, intl.formatMessage(messages.validationDiscordId)),
.matches(/^\d{17,19}$/, intl.formatMessage(messages.validationDiscordId)),
});
useEffect(() => {
@@ -131,6 +135,8 @@ const UserGeneralSettings: React.FC = () => {
movieQuotaDays: data?.movieQuotaDays,
tvQuotaLimit: data?.tvQuotaLimit,
tvQuotaDays: data?.tvQuotaDays,
watchlistSyncMovies: data?.watchlistSyncMovies,
watchlistSyncTv: data?.watchlistSyncTv,
}}
validationSchema={UserGeneralSettingsSchema}
enableReinitialize
@@ -149,6 +155,8 @@ const UserGeneralSettings: React.FC = () => {
movieQuotaDays: movieQuotaEnabled ? values.movieQuotaDays : null,
tvQuotaLimit: tvQuotaEnabled ? values.tvQuotaLimit : null,
tvQuotaDays: tvQuotaEnabled ? values.tvQuotaDays : null,
watchlistSyncMovies: values.watchlistSyncMovies,
watchlistSyncTv: values.watchlistSyncTv,
});
if (currentUser?.id === user?.id && setLocale) {
@@ -243,9 +251,11 @@ const UserGeneralSettings: React.FC = () => {
}
/>
</div>
{errors.displayName && touched.displayName && (
<div className="error">{errors.displayName}</div>
)}
{errors.displayName &&
touched.displayName &&
typeof errors.displayName === 'string' && (
<div className="error">{errors.displayName}</div>
)}
</div>
</div>
<div className="form-row">
@@ -280,17 +290,15 @@ const UserGeneralSettings: React.FC = () => {
{currentUser?.id === user?.id && (
<span className="label-tip">
{intl.formatMessage(messages.discordIdTip, {
FindDiscordIdLink: function FindDiscordIdLink(msg) {
return (
<a
href="https://support.discord.com/hc/en-us/articles/206346498-Where-can-I-find-my-User-Server-Message-ID-"
target="_blank"
rel="noreferrer"
>
{msg}
</a>
);
},
FindDiscordIdLink: (msg: React.ReactNode) => (
<a
href="https://support.discord.com/hc/en-us/articles/206346498-Where-can-I-find-my-User-Server-Message-ID-"
target="_blank"
rel="noreferrer"
>
{msg}
</a>
),
})}
</span>
)}
@@ -299,9 +307,11 @@ const UserGeneralSettings: React.FC = () => {
<div className="form-input-field">
<Field id="discordId" name="discordId" type="text" />
</div>
{errors.discordId && touched.discordId && (
<div className="error">{errors.discordId}</div>
)}
{errors.discordId &&
touched.discordId &&
typeof errors.discordId === 'string' && (
<div className="error">{errors.discordId}</div>
)}
</div>
</div>
<div className="form-row">
@@ -455,6 +465,99 @@ const UserGeneralSettings: React.FC = () => {
</div>
</>
)}
{hasPermission(
[Permission.AUTO_REQUEST, Permission.AUTO_REQUEST_MOVIE],
{ type: 'or' }
) &&
user?.userType === UserType.PLEX && (
<div className="form-row">
<label
htmlFor="watchlistSyncMovies"
className="checkbox-label"
>
<span>
{intl.formatMessage(messages.plexwatchlistsyncmovies)}
</span>
<span className="label-tip">
{intl.formatMessage(
messages.plexwatchlistsyncmoviestip,
{
PlexWatchlistSupportLink: (
msg: React.ReactNode
) => (
<a
href="https://support.plex.tv/articles/universal-watchlist/"
className="text-white transition duration-300 hover:underline"
target="_blank"
rel="noreferrer"
>
{msg}
</a>
),
}
)}
</span>
</label>
<div className="form-input-area">
<Field
type="checkbox"
id="watchlistSyncMovies"
name="watchlistSyncMovies"
onChange={() => {
setFieldValue(
'watchlistSyncMovies',
!values.watchlistSyncMovies
);
}}
/>
</div>
</div>
)}
{hasPermission(
[Permission.AUTO_REQUEST, Permission.AUTO_REQUEST_TV],
{ type: 'or' }
) &&
user?.userType === UserType.PLEX && (
<div className="form-row">
<label htmlFor="watchlistSyncTv" className="checkbox-label">
<span>
{intl.formatMessage(messages.plexwatchlistsyncseries)}
</span>
<span className="label-tip">
{intl.formatMessage(
messages.plexwatchlistsyncseriestip,
{
PlexWatchlistSupportLink: (
msg: React.ReactNode
) => (
<a
href="https://support.plex.tv/articles/universal-watchlist/"
className="text-white transition duration-300 hover:underline"
target="_blank"
rel="noreferrer"
>
{msg}
</a>
),
}
)}
</span>
</label>
<div className="form-input-area">
<Field
type="checkbox"
id="watchlistSyncTv"
name="watchlistSyncTv"
onChange={() => {
setFieldValue(
'watchlistSyncTv',
!values.watchlistSyncTv
);
}}
/>
</div>
</div>
)}
<div className="actions">
<div className="flex justify-end">
<span className="ml-3 inline-flex rounded-md shadow-sm">