chore(deps): update react to 18 (#2943)

pull/2944/merge
Ryan Cohen 2 years ago committed by GitHub
parent 72d7a3477f
commit e5d8c93ab8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,3 +1,6 @@
/**
* @type {import('next').NextConfig}
*/
module.exports = { module.exports = {
env: { env: {
commitTag: process.env.COMMIT_TAG || 'local', commitTag: process.env.COMMIT_TAG || 'local',

@ -29,6 +29,9 @@
}, },
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@formatjs/intl-displaynames": "^6.0.3",
"@formatjs/intl-locale": "^3.0.3",
"@formatjs/intl-pluralrules": "^5.0.3",
"@headlessui/react": "1.6.6", "@headlessui/react": "1.6.6",
"@heroicons/react": "1.0.6", "@heroicons/react": "1.0.6",
"@supercharge/request-ip": "1.2.0", "@supercharge/request-ip": "1.2.0",
@ -62,12 +65,12 @@
"openpgp": "5.4.0", "openpgp": "5.4.0",
"plex-api": "5.3.2", "plex-api": "5.3.2",
"pug": "3.0.2", "pug": "3.0.2",
"react": "17.0.2", "react": "18.2.0",
"react-ace": "10.1.0", "react-ace": "10.1.0",
"react-animate-height": "2.1.2", "react-animate-height": "2.1.2",
"react-dom": "17.0.2", "react-dom": "18.2.0",
"react-intersection-observer": "9.4.0", "react-intersection-observer": "9.4.0",
"react-intl": "5.25.1", "react-intl": "6.0.5",
"react-markdown": "8.0.3", "react-markdown": "8.0.3",
"react-select": "5.4.0", "react-select": "5.4.0",
"react-spring": "9.5.2", "react-spring": "9.5.2",
@ -111,8 +114,8 @@
"@types/node": "17.0.36", "@types/node": "17.0.36",
"@types/node-schedule": "2.1.0", "@types/node-schedule": "2.1.0",
"@types/nodemailer": "6.4.5", "@types/nodemailer": "6.4.5",
"@types/react": "17.0.45", "@types/react": "18.0.17",
"@types/react-dom": "17.0.17", "@types/react-dom": "18.0.6",
"@types/react-transition-group": "4.4.5", "@types/react-transition-group": "4.4.5",
"@types/secure-random-password": "0.2.1", "@types/secure-random-password": "0.2.1",
"@types/semver": "7.3.12", "@types/semver": "7.3.12",
@ -153,7 +156,9 @@
"typescript": "4.7.4" "typescript": "4.7.4"
}, },
"resolutions": { "resolutions": {
"sqlite3/node-gyp": "8.4.1" "sqlite3/node-gyp": "8.4.1",
"@types/react": "18.0.17",
"@types/react-dom": "18.0.6"
}, },
"config": { "config": {
"commitizen": { "commitizen": {

@ -8,7 +8,7 @@ const messages = defineMessages({
'The <code>{appDataPath}</code> volume mount was not configured properly. All data will be cleared when the container is stopped or restarted.', 'The <code>{appDataPath}</code> volume mount was not configured properly. All data will be cleared when the container is stopped or restarted.',
}); });
const AppDataWarning: React.FC = () => { const AppDataWarning = () => {
const intl = useIntl(); const intl = useIntl();
const { data, error } = useSWR<{ appData: boolean; appDataPath: string }>( const { data, error } = useSWR<{ appData: boolean; appDataPath: string }>(
'/api/v1/status/appdata' '/api/v1/status/appdata'
@ -27,9 +27,9 @@ const AppDataWarning: React.FC = () => {
{!data.appData && ( {!data.appData && (
<Alert <Alert
title={intl.formatMessage(messages.dockerVolumeMissingDescription, { title={intl.formatMessage(messages.dockerVolumeMissingDescription, {
code: function code(msg) { code: (msg: React.ReactNode) => (
return <code className="bg-opacity-50">{msg}</code>; <code className="bg-opacity-50">{msg}</code>
}, ),
appDataPath: data.appDataPath, appDataPath: data.appDataPath,
})} })}
/> />

@ -31,9 +31,7 @@ interface CollectionDetailsProps {
collection?: Collection; collection?: Collection;
} }
const CollectionDetails: React.FC<CollectionDetailsProps> = ({ const CollectionDetails = ({ collection }: CollectionDetailsProps) => {
collection,
}) => {
const intl = useIntl(); const intl = useIntl();
const router = useRouter(); const router = useRouter();
const settings = useSettings(); const settings = useSettings();

@ -16,19 +16,24 @@ export interface AccordionChildProps {
AccordionContent: any; AccordionContent: any;
} }
export const AccordionContent: React.FC<{ isOpen: boolean }> = ({ type AccordionContentProps = {
isOpen: boolean;
children: React.ReactNode;
};
export const AccordionContent = ({
isOpen, isOpen,
children, children,
}) => { }: AccordionContentProps) => {
return <AnimateHeight height={isOpen ? 'auto' : 0}>{children}</AnimateHeight>; return <AnimateHeight height={isOpen ? 'auto' : 0}>{children}</AnimateHeight>;
}; };
const Accordion: React.FC<AccordionProps> = ({ const Accordion = ({
single, single,
atLeastOne, atLeastOne,
initialOpenIndexes, initialOpenIndexes,
children, children,
}) => { }: AccordionProps) => {
const initialState = initialOpenIndexes || (atLeastOne && [0]) || []; const initialState = initialOpenIndexes || (atLeastOne && [0]) || [];
const [openIndexes, setOpenIndexes] = useState<number[]>(initialState); const [openIndexes, setOpenIndexes] = useState<number[]>(initialState);

@ -8,9 +8,10 @@ import React from 'react';
interface AlertProps { interface AlertProps {
title?: React.ReactNode; title?: React.ReactNode;
type?: 'warning' | 'info' | 'error'; type?: 'warning' | 'info' | 'error';
children?: React.ReactNode;
} }
const Alert: React.FC<AlertProps> = ({ title, children, type }) => { const Alert = ({ title, children, type }: AlertProps) => {
let design = { let design = {
bgColor: 'bg-yellow-600', bgColor: 'bg-yellow-600',
titleColor: 'text-yellow-100', titleColor: 'text-yellow-100',

@ -5,14 +5,15 @@ interface BadgeProps {
badgeType?: 'default' | 'primary' | 'danger' | 'warning' | 'success'; badgeType?: 'default' | 'primary' | 'danger' | 'warning' | 'success';
className?: string; className?: string;
href?: string; href?: string;
children: React.ReactNode;
} }
const Badge: React.FC<BadgeProps> = ({ const Badge = ({
badgeType = 'default', badgeType = 'default',
className, className,
href, href,
children, children,
}) => { }: BadgeProps) => {
const badgeStyle = [ const badgeStyle = [
'px-2 inline-flex text-xs leading-5 font-semibold rounded-full whitespace-nowrap', 'px-2 inline-flex text-xs leading-5 font-semibold rounded-full whitespace-nowrap',
]; ];

@ -13,11 +13,11 @@ interface DropdownItemProps extends AnchorHTMLAttributes<HTMLAnchorElement> {
buttonType?: 'primary' | 'ghost'; buttonType?: 'primary' | 'ghost';
} }
const DropdownItem: React.FC<DropdownItemProps> = ({ const DropdownItem = ({
children, children,
buttonType = 'primary', buttonType = 'primary',
...props ...props
}) => { }: DropdownItemProps) => {
let styleClass = 'button-md text-white'; let styleClass = 'button-md text-white';
switch (buttonType) { switch (buttonType) {
@ -46,14 +46,14 @@ interface ButtonWithDropdownProps
buttonType?: 'primary' | 'ghost'; buttonType?: 'primary' | 'ghost';
} }
const ButtonWithDropdown: React.FC<ButtonWithDropdownProps> = ({ const ButtonWithDropdown = ({
text, text,
children, children,
dropdownIcon, dropdownIcon,
className, className,
buttonType = 'primary', buttonType = 'primary',
...props ...props
}) => { }: ButtonWithDropdownProps) => {
const [isOpen, setIsOpen] = useState(false); const [isOpen, setIsOpen] = useState(false);
const buttonRef = useRef<HTMLButtonElement>(null); const buttonRef = useRef<HTMLButtonElement>(null);
useClickOutside(buttonRef, () => setIsOpen(false)); useClickOutside(buttonRef, () => setIsOpen(false));

@ -10,7 +10,7 @@ import useSettings from '../../../hooks/useSettings';
* It uses the `next/image` Image component but overrides * It uses the `next/image` Image component but overrides
* the `unoptimized` prop based on the application setting `cacheImages`. * the `unoptimized` prop based on the application setting `cacheImages`.
**/ **/
const CachedImage: React.FC<ImageProps> = (props) => { const CachedImage = (props: ImageProps) => {
const { currentSettings } = useSettings(); const { currentSettings } = useSettings();
return <Image unoptimized={!currentSettings.cacheImages} {...props} />; return <Image unoptimized={!currentSettings.cacheImages} {...props} />;

@ -6,14 +6,15 @@ interface ConfirmButtonProps {
onClick: () => void; onClick: () => void;
confirmText: React.ReactNode; confirmText: React.ReactNode;
className?: string; className?: string;
children: React.ReactNode;
} }
const ConfirmButton: React.FC<ConfirmButtonProps> = ({ const ConfirmButton = ({
onClick, onClick,
children, children,
confirmText, confirmText,
className, className,
}) => { }: ConfirmButtonProps) => {
const ref = useRef(null); const ref = useRef(null);
useClickOutside(ref, () => setIsClicked(false)); useClickOutside(ref, () => setIsClicked(false));
const [isClicked, setIsClicked] = useState(false); const [isClicked, setIsClicked] = useState(false);

@ -3,13 +3,10 @@ import React from 'react';
interface HeaderProps { interface HeaderProps {
extraMargin?: number; extraMargin?: number;
subtext?: React.ReactNode; subtext?: React.ReactNode;
children: React.ReactNode;
} }
const Header: React.FC<HeaderProps> = ({ const Header = ({ children, extraMargin = 0, subtext }: HeaderProps) => {
children,
extraMargin = 0,
subtext,
}) => {
return ( return (
<div className="mt-8 md:flex md:items-center md:justify-between"> <div className="mt-8 md:flex md:items-center md:justify-between">
<div className={`min-w-0 flex-1 mx-${extraMargin}`}> <div className={`min-w-0 flex-1 mx-${extraMargin}`}>

@ -4,9 +4,10 @@ import { withProperties } from '../../../utils/typeHelpers';
interface ListItemProps { interface ListItemProps {
title: string; title: string;
className?: string; className?: string;
children: React.ReactNode;
} }
const ListItem: React.FC<ListItemProps> = ({ title, className, children }) => { const ListItem = ({ title, className, children }: ListItemProps) => {
return ( return (
<div> <div>
<div className="max-w-6xl py-4 sm:grid sm:grid-cols-3 sm:gap-4"> <div className="max-w-6xl py-4 sm:grid sm:grid-cols-3 sm:gap-4">
@ -22,9 +23,10 @@ const ListItem: React.FC<ListItemProps> = ({ title, className, children }) => {
interface ListProps { interface ListProps {
title: string; title: string;
subTitle?: string; subTitle?: string;
children: React.ReactNode;
} }
const List: React.FC<ListProps> = ({ title, subTitle, children }) => { const List = ({ title, subTitle, children }: ListProps) => {
return ( return (
<> <>
<div> <div>

@ -18,13 +18,13 @@ interface ListViewProps {
onScrollBottom: () => void; onScrollBottom: () => void;
} }
const ListView: React.FC<ListViewProps> = ({ const ListView = ({
items, items,
isEmpty, isEmpty,
isLoading, isLoading,
onScrollBottom, onScrollBottom,
isReachingEnd, isReachingEnd,
}) => { }: ListViewProps) => {
const intl = useIntl(); const intl = useIntl();
useVerticalScroll(onScrollBottom, !isLoading && !isEmpty && !isReachingEnd); useVerticalScroll(onScrollBottom, !isLoading && !isEmpty && !isReachingEnd);
return ( return (

@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
export const SmallLoadingSpinner: React.FC = () => { export const SmallLoadingSpinner = () => {
return ( return (
<div className="inset-0 flex h-full w-full items-center justify-center text-gray-200"> <div className="inset-0 flex h-full w-full items-center justify-center text-gray-200">
<svg <svg
@ -29,7 +29,7 @@ export const SmallLoadingSpinner: React.FC = () => {
); );
}; };
const LoadingSpinner: React.FC = () => { const LoadingSpinner = () => {
return ( return (
<div className="inset-0 flex h-64 items-center justify-center text-gray-200"> <div className="inset-0 flex h-64 items-center justify-center text-gray-200">
<svg <svg

@ -33,9 +33,10 @@ interface ModalProps {
iconSvg?: ReactNode; iconSvg?: ReactNode;
loading?: boolean; loading?: boolean;
backdrop?: string; backdrop?: string;
children?: ReactNode;
} }
const Modal: React.FC<ModalProps> = ({ const Modal = ({
title, title,
onCancel, onCancel,
onOk, onOk,
@ -58,7 +59,7 @@ const Modal: React.FC<ModalProps> = ({
tertiaryText, tertiaryText,
onTertiary, onTertiary,
backdrop, backdrop,
}) => { }: ModalProps) => {
const intl = useIntl(); const intl = useIntl();
const modalRef = useRef<HTMLDivElement>(null); const modalRef = useRef<HTMLDivElement>(null);
useClickOutside(modalRef, () => { useClickOutside(modalRef, () => {

@ -6,15 +6,16 @@ interface PageTitleProps {
title: string | (string | undefined)[]; title: string | (string | undefined)[];
} }
const PageTitle: React.FC<PageTitleProps> = ({ title }) => { const PageTitle = ({ title }: PageTitleProps) => {
const settings = useSettings(); const settings = useSettings();
const titleText = `${
Array.isArray(title) ? title.filter(Boolean).join(' - ') : title
} - ${settings.currentSettings.applicationTitle}`;
return ( return (
<Head> <Head>
<title> <title>{titleText}</title>
{Array.isArray(title) ? title.filter(Boolean).join(' - ') : title} -{' '}
{settings.currentSettings.applicationTitle}
</title>
</Head> </Head>
); );
}; };

@ -12,7 +12,7 @@ export interface PlayButtonLink {
svg: ReactNode; svg: ReactNode;
} }
const PlayButton: React.FC<PlayButtonProps> = ({ links }) => { const PlayButton = ({ links }: PlayButtonProps) => {
if (!links || !links.length) { if (!links || !links.length) {
return null; return null;
} }

@ -6,11 +6,11 @@ interface ProgressCircleProps {
useHeatLevel?: boolean; useHeatLevel?: boolean;
} }
const ProgressCircle: React.FC<ProgressCircleProps> = ({ const ProgressCircle = ({
className, className,
progress = 0, progress = 0,
useHeatLevel, useHeatLevel,
}) => { }: ProgressCircleProps) => {
const ref = useRef<SVGCircleElement>(null); const ref = useRef<SVGCircleElement>(null);
let color = ''; let color = '';

@ -12,10 +12,7 @@ interface CustomFieldProps extends React.ComponentProps<typeof Field> {
type SensitiveInputProps = CustomInputProps | CustomFieldProps; type SensitiveInputProps = CustomInputProps | CustomFieldProps;
const SensitiveInput: React.FC<SensitiveInputProps> = ({ const SensitiveInput = ({ as = 'input', ...props }: SensitiveInputProps) => {
as = 'input',
...props
}) => {
const [isHidden, setHidden] = useState(true); const [isHidden, setHidden] = useState(true);
const Component = as === 'input' ? 'input' : Field; const Component = as === 'input' ? 'input' : Field;
const componentProps = const componentProps =

@ -15,14 +15,17 @@ export interface SettingsRoute {
hidden?: boolean; hidden?: boolean;
} }
const SettingsLink: React.FC<{ type SettingsLinkProps = {
tabType: 'default' | 'button'; tabType: 'default' | 'button';
currentPath: string; currentPath: string;
route: string; route: string;
regex: RegExp; regex: RegExp;
hidden?: boolean; hidden?: boolean;
isMobile?: boolean; isMobile?: boolean;
}> = ({ children: React.ReactNode;
};
const SettingsLink = ({
children, children,
tabType, tabType,
currentPath, currentPath,
@ -30,7 +33,7 @@ const SettingsLink: React.FC<{
regex, regex,
hidden = false, hidden = false,
isMobile = false, isMobile = false,
}) => { }: SettingsLinkProps) => {
if (hidden) { if (hidden) {
return null; return null;
} }
@ -66,10 +69,13 @@ const SettingsLink: React.FC<{
); );
}; };
const SettingsTabs: React.FC<{ const SettingsTabs = ({
tabType = 'default',
settingsRoutes,
}: {
tabType?: 'default' | 'button'; tabType?: 'default' | 'button';
settingsRoutes: SettingsRoute[]; settingsRoutes: SettingsRoute[];
}> = ({ tabType = 'default', settingsRoutes }) => { }) => {
const router = useRouter(); const router = useRouter();
const { user: currentUser } = useUser(); const { user: currentUser } = useUser();

@ -10,15 +10,16 @@ interface SlideOverProps {
title: React.ReactNode; title: React.ReactNode;
subText?: string; subText?: string;
onClose: () => void; onClose: () => void;
children: React.ReactNode;
} }
const SlideOver: React.FC<SlideOverProps> = ({ const SlideOver = ({
show = false, show = false,
title, title,
subText, subText,
onClose, onClose,
children, children,
}) => { }: SlideOverProps) => {
const [isMounted, setIsMounted] = useState(false); const [isMounted, setIsMounted] = useState(false);
const slideoverRef = useRef(null); const slideoverRef = useRef(null);
useLockBodyScroll(show); useLockBodyScroll(show);

@ -1,18 +1,21 @@
import type { AllHTMLAttributes } from 'react';
import React from 'react'; import React from 'react';
import { withProperties } from '../../../utils/typeHelpers'; import { withProperties } from '../../../utils/typeHelpers';
const TBody: React.FC = ({ children }) => { type TBodyProps = {
children: React.ReactNode;
};
const TBody = ({ children }: TBodyProps) => {
return ( return (
<tbody className="divide-y divide-gray-700 bg-gray-800">{children}</tbody> <tbody className="divide-y divide-gray-700 bg-gray-800">{children}</tbody>
); );
}; };
const TH: React.FC<AllHTMLAttributes<HTMLTableHeaderCellElement>> = ({ const TH = ({
children, children,
className, className,
...props ...props
}) => { }: React.ComponentPropsWithoutRef<'th'>) => {
const style = [ const style = [
'px-4 py-3 bg-gray-500 text-left text-xs leading-4 font-medium text-gray-200 uppercase tracking-wider truncate', 'px-4 py-3 bg-gray-500 text-left text-xs leading-4 font-medium text-gray-200 uppercase tracking-wider truncate',
]; ];
@ -28,18 +31,18 @@ const TH: React.FC<AllHTMLAttributes<HTMLTableHeaderCellElement>> = ({
); );
}; };
interface TDProps extends AllHTMLAttributes<HTMLTableCellElement> { type TDProps = {
alignText?: 'left' | 'center' | 'right'; alignText?: 'left' | 'center' | 'right';
noPadding?: boolean; noPadding?: boolean;
} };
const TD: React.FC<TDProps> = ({ const TD = ({
children, children,
alignText = 'left', alignText = 'left',
noPadding, noPadding,
className, className,
...props ...props
}) => { }: TDProps & React.ComponentPropsWithoutRef<'td'>) => {
const style = ['text-sm leading-5 text-white']; const style = ['text-sm leading-5 text-white'];
switch (alignText) { switch (alignText) {
@ -69,7 +72,11 @@ const TD: React.FC<TDProps> = ({
); );
}; };
const Table: React.FC = ({ children }) => { type TableProps = {
children: React.ReactNode;
};
const Table = ({ children }: TableProps) => {
return ( return (
<div className="flex flex-col"> <div className="flex flex-col">
<div className="my-2 -mx-4 overflow-x-auto md:mx-0 lg:mx-0"> <div className="my-2 -mx-4 overflow-x-auto md:mx-0 lg:mx-0">

@ -7,7 +7,7 @@ interface CompanyCardProps {
url: string; url: string;
} }
const CompanyCard: React.FC<CompanyCardProps> = ({ image, url, name }) => { const CompanyCard = ({ image, url, name }: CompanyCardProps) => {
const [isHovered, setHovered] = useState(false); const [isHovered, setHovered] = useState(false);
return ( return (

@ -13,7 +13,7 @@ const messages = defineMessages({
genreMovies: '{genre} Movies', genreMovies: '{genre} Movies',
}); });
const DiscoverMovieGenre: React.FC = () => { const DiscoverMovieGenre = () => {
const router = useRouter(); const router = useRouter();
const intl = useIntl(); const intl = useIntl();

@ -13,7 +13,7 @@ const messages = defineMessages({
languageMovies: '{language} Movies', languageMovies: '{language} Movies',
}); });
const DiscoverMovieLanguage: React.FC = () => { const DiscoverMovieLanguage = () => {
const router = useRouter(); const router = useRouter();
const intl = useIntl(); const intl = useIntl();

@ -11,7 +11,7 @@ const messages = defineMessages({
discovermovies: 'Popular Movies', discovermovies: 'Popular Movies',
}); });
const DiscoverMovies: React.FC = () => { const DiscoverMovies = () => {
const intl = useIntl(); const intl = useIntl();
const { const {

@ -14,7 +14,7 @@ const messages = defineMessages({
networkSeries: '{network} Series', networkSeries: '{network} Series',
}); });
const DiscoverTvNetwork: React.FC = () => { const DiscoverTvNetwork = () => {
const router = useRouter(); const router = useRouter();
const intl = useIntl(); const intl = useIntl();

@ -14,7 +14,7 @@ const messages = defineMessages({
studioMovies: '{studio} Movies', studioMovies: '{studio} Movies',
}); });
const DiscoverMovieStudio: React.FC = () => { const DiscoverMovieStudio = () => {
const router = useRouter(); const router = useRouter();
const intl = useIntl(); const intl = useIntl();

@ -11,7 +11,7 @@ const messages = defineMessages({
discovertv: 'Popular Series', discovertv: 'Popular Series',
}); });
const DiscoverTv: React.FC = () => { const DiscoverTv = () => {
const intl = useIntl(); const intl = useIntl();
const { const {

@ -13,7 +13,7 @@ const messages = defineMessages({
genreSeries: '{genre} Series', genreSeries: '{genre} Series',
}); });
const DiscoverTvGenre: React.FC = () => { const DiscoverTvGenre = () => {
const router = useRouter(); const router = useRouter();
const intl = useIntl(); const intl = useIntl();

@ -13,7 +13,7 @@ const messages = defineMessages({
languageSeries: '{language} Series', languageSeries: '{language} Series',
}); });
const DiscoverTvLanguage: React.FC = () => { const DiscoverTvLanguage = () => {
const router = useRouter(); const router = useRouter();
const intl = useIntl(); const intl = useIntl();

@ -11,7 +11,7 @@ const messages = defineMessages({
upcomingtv: 'Upcoming Series', upcomingtv: 'Upcoming Series',
}); });
const DiscoverTvUpcoming: React.FC = () => { const DiscoverTvUpcoming = () => {
const intl = useIntl(); const intl = useIntl();
const { const {

@ -13,7 +13,7 @@ const messages = defineMessages({
moviegenres: 'Movie Genres', moviegenres: 'Movie Genres',
}); });
const MovieGenreList: React.FC = () => { const MovieGenreList = () => {
const intl = useIntl(); const intl = useIntl();
const { data, error } = useSWR<GenreSliderItem[]>( const { data, error } = useSWR<GenreSliderItem[]>(
`/api/v1/discover/genreslider/movie` `/api/v1/discover/genreslider/movie`

@ -12,7 +12,7 @@ const messages = defineMessages({
moviegenres: 'Movie Genres', moviegenres: 'Movie Genres',
}); });
const MovieGenreSlider: React.FC = () => { const MovieGenreSlider = () => {
const intl = useIntl(); const intl = useIntl();
const { data, error } = useSWR<GenreSliderItem[]>( const { data, error } = useSWR<GenreSliderItem[]>(
`/api/v1/discover/genreslider/movie`, `/api/v1/discover/genreslider/movie`,

@ -142,7 +142,7 @@ const networks: Network[] = [
}, },
]; ];
const NetworkSlider: React.FC = () => { const NetworkSlider = () => {
const intl = useIntl(); const intl = useIntl();
return ( return (

@ -76,7 +76,7 @@ const studios: Studio[] = [
}, },
]; ];
const StudioSlider: React.FC = () => { const StudioSlider = () => {
const intl = useIntl(); const intl = useIntl();
return ( return (

@ -15,7 +15,7 @@ const messages = defineMessages({
trending: 'Trending', trending: 'Trending',
}); });
const Trending: React.FC = () => { const Trending = () => {
const intl = useIntl(); const intl = useIntl();
const { const {
isLoadingInitialData, isLoadingInitialData,

@ -13,7 +13,7 @@ const messages = defineMessages({
seriesgenres: 'Series Genres', seriesgenres: 'Series Genres',
}); });
const TvGenreList: React.FC = () => { const TvGenreList = () => {
const intl = useIntl(); const intl = useIntl();
const { data, error } = useSWR<GenreSliderItem[]>( const { data, error } = useSWR<GenreSliderItem[]>(
`/api/v1/discover/genreslider/tv` `/api/v1/discover/genreslider/tv`

@ -12,7 +12,7 @@ const messages = defineMessages({
tvgenres: 'Series Genres', tvgenres: 'Series Genres',
}); });
const TvGenreSlider: React.FC = () => { const TvGenreSlider = () => {
const intl = useIntl(); const intl = useIntl();
const { data, error } = useSWR<GenreSliderItem[]>( const { data, error } = useSWR<GenreSliderItem[]>(
`/api/v1/discover/genreslider/tv`, `/api/v1/discover/genreslider/tv`,

@ -11,7 +11,7 @@ const messages = defineMessages({
upcomingmovies: 'Upcoming Movies', upcomingmovies: 'Upcoming Movies',
}); });
const UpcomingMovies: React.FC = () => { const UpcomingMovies = () => {
const intl = useIntl(); const intl = useIntl();
const { const {

@ -27,7 +27,7 @@ const messages = defineMessages({
trending: 'Trending', trending: 'Trending',
}); });
const Discover: React.FC = () => { const Discover = () => {
const intl = useIntl(); const intl = useIntl();
const { data: media, error: mediaError } = useSWR<MediaResultsResponse>( const { data: media, error: mediaError } = useSWR<MediaResultsResponse>(

@ -12,10 +12,7 @@ interface DownloadBlockProps {
is4k?: boolean; is4k?: boolean;
} }
const DownloadBlock: React.FC<DownloadBlockProps> = ({ const DownloadBlock = ({ downloadItem, is4k = false }: DownloadBlockProps) => {
downloadItem,
is4k = false,
}) => {
const intl = useIntl(); const intl = useIntl();
return ( return (

@ -17,14 +17,14 @@ interface ExternalLinkBlockProps {
plexUrl?: string; plexUrl?: string;
} }
const ExternalLinkBlock: React.FC<ExternalLinkBlockProps> = ({ const ExternalLinkBlock = ({
mediaType, mediaType,
tmdbId, tmdbId,
tvdbId, tvdbId,
imdbId, imdbId,
rtUrl, rtUrl,
plexUrl, plexUrl,
}) => { }: ExternalLinkBlockProps) => {
const { locale } = useLocale(); const { locale } = useLocale();
return ( return (

@ -10,12 +10,7 @@ interface GenreCardProps {
canExpand?: boolean; canExpand?: boolean;
} }
const GenreCard: React.FC<GenreCardProps> = ({ const GenreCard = ({ image, url, name, canExpand = false }: GenreCardProps) => {
image,
url,
name,
canExpand = false,
}) => {
const [isHovered, setHovered] = useState(false); const [isHovered, setHovered] = useState(false);
return ( return (
@ -54,7 +49,7 @@ const GenreCard: React.FC<GenreCardProps> = ({
); );
}; };
const GenreCardPlaceholder: React.FC = () => { const GenreCardPlaceholder = () => {
return ( return (
<div <div
className={`relative h-32 w-56 animate-pulse rounded-xl bg-gray-700 sm:h-40 sm:w-72`} className={`relative h-32 w-56 animate-pulse rounded-xl bg-gray-700 sm:h-40 sm:w-72`}

@ -16,7 +16,7 @@ interface IssueBlockProps {
issue: Issue; issue: Issue;
} }
const IssueBlock: React.FC<IssueBlockProps> = ({ issue }) => { const IssueBlock = ({ issue }: IssueBlockProps) => {
const { user } = useUser(); const { user } = useUser();
const intl = useIntl(); const intl = useIntl();
const issueOption = issueOptions.find( const issueOption = issueOptions.find(

@ -30,12 +30,12 @@ interface IssueCommentProps {
onUpdate?: () => void; onUpdate?: () => void;
} }
const IssueComment: React.FC<IssueCommentProps> = ({ const IssueComment = ({
comment, comment,
isReversed = false, isReversed = false,
isActiveUser = false, isActiveUser = false,
onUpdate, onUpdate,
}) => { }: IssueCommentProps) => {
const intl = useIntl(); const intl = useIntl();
const [showDeleteModal, setShowDeleteModal] = useState(false); const [showDeleteModal, setShowDeleteModal] = useState(false);
const [isEditing, setIsEditing] = useState(false); const [isEditing, setIsEditing] = useState(false);
@ -195,9 +195,11 @@ const IssueComment: React.FC<IssueCommentProps> = ({
name="newMessage" name="newMessage"
className="h-24" className="h-24"
/> />
{errors.newMessage && touched.newMessage && ( {errors.newMessage &&
<div className="error">{errors.newMessage}</div> touched.newMessage &&
)} typeof errors.newMessage === 'string' && (
<div className="error">{errors.newMessage}</div>
)}
<div className="mt-4 flex items-center justify-end space-x-2"> <div className="mt-4 flex items-center justify-end space-x-2">
<Button <Button
type="button" type="button"

@ -22,13 +22,13 @@ interface IssueDescriptionProps {
onDelete: () => void; onDelete: () => void;
} }
const IssueDescription: React.FC<IssueDescriptionProps> = ({ const IssueDescription = ({
description, description,
belongsToUser, belongsToUser,
commentCount, commentCount,
onEdit, onEdit,
onDelete, onDelete,
}) => { }: IssueDescriptionProps) => {
const intl = useIntl(); const intl = useIntl();
const { hasPermission } = useUser(); const { hasPermission } = useUser();
const [isEditing, setIsEditing] = useState(false); const [isEditing, setIsEditing] = useState(false);

@ -74,7 +74,7 @@ const isMovie = (movie: MovieDetails | TvDetails): movie is MovieDetails => {
return (movie as MovieDetails).title !== undefined; return (movie as MovieDetails).title !== undefined;
}; };
const IssueDetails: React.FC = () => { const IssueDetails = () => {
const { addToast } = useToasts(); const { addToast } = useToasts();
const router = useRouter(); const router = useRouter();
const intl = useIntl(); const intl = useIntl();

@ -36,7 +36,7 @@ interface IssueItemProps {
issue: Issue; issue: Issue;
} }
const IssueItem: React.FC<IssueItemProps> = ({ issue }) => { const IssueItem = ({ issue }: IssueItemProps) => {
const intl = useIntl(); const intl = useIntl();
const { hasPermission } = useUser(); const { hasPermission } = useUser();
const { ref, inView } = useInView({ const { ref, inView } = useInView({

@ -32,7 +32,7 @@ enum Filter {
type Sort = 'added' | 'modified'; type Sort = 'added' | 'modified';
const IssueList: React.FC = () => { const IssueList = () => {
const intl = useIntl(); const intl = useIntl();
const router = useRouter(); const router = useRouter();
const [currentFilter, setCurrentFilter] = useState<Filter>(Filter.OPEN); const [currentFilter, setCurrentFilter] = useState<Filter>(Filter.OPEN);
@ -194,9 +194,9 @@ const IssueList: React.FC = () => {
? pageIndex * currentPageSize + data.results.length ? pageIndex * currentPageSize + data.results.length
: (pageIndex + 1) * currentPageSize, : (pageIndex + 1) * currentPageSize,
total: data.pageInfo.results, total: data.pageInfo.results,
strong: function strong(msg) { strong: (msg: React.ReactNode) => (
return <span className="font-medium">{msg}</span>; <span className="font-medium">{msg}</span>
}, ),
})} })}
</p> </p>
</div> </div>

@ -55,11 +55,11 @@ interface CreateIssueModalProps {
onCancel?: () => void; onCancel?: () => void;
} }
const CreateIssueModal: React.FC<CreateIssueModalProps> = ({ const CreateIssueModal = ({
onCancel, onCancel,
mediaType, mediaType,
tmdbId, tmdbId,
}) => { }: CreateIssueModalProps) => {
const intl = useIntl(); const intl = useIntl();
const settings = useSettings(); const settings = useSettings();
const { hasPermission } = useUser(); const { hasPermission } = useUser();
@ -118,9 +118,7 @@ const CreateIssueModal: React.FC<CreateIssueModalProps> = ({
<div> <div>
{intl.formatMessage(messages.toastSuccessCreate, { {intl.formatMessage(messages.toastSuccessCreate, {
title: isMovie(data) ? data.title : data.name, title: isMovie(data) ? data.title : data.name,
strong: function strong(msg) { strong: (msg: React.ReactNode) => <strong>{msg}</strong>,
return <strong>{msg}</strong>;
},
})} })}
</div> </div>
<Link href={`/issues/${newIssue.data.id}`}> <Link href={`/issues/${newIssue.data.id}`}>
@ -315,9 +313,11 @@ const CreateIssueModal: React.FC<CreateIssueModalProps> = ({
className="h-28" className="h-28"
placeholder={intl.formatMessage(messages.providedetail)} placeholder={intl.formatMessage(messages.providedetail)}
/> />
{errors.message && touched.message && ( {errors.message &&
<div className="error">{errors.message}</div> touched.message &&
)} typeof errors.message === 'string' && (
<div className="error">{errors.message}</div>
)}
</div> </div>
</Modal> </Modal>
); );

@ -10,12 +10,7 @@ interface IssueModalProps {
issueId?: never; issueId?: never;
} }
const IssueModal: React.FC<IssueModalProps> = ({ const IssueModal = ({ show, mediaType, onCancel, tmdbId }: IssueModalProps) => (
show,
mediaType,
onCancel,
tmdbId,
}) => (
<Transition <Transition
enter="transition opacity-0 duration-300" enter="transition opacity-0 duration-300"
enterFrom="opacity-0" enterFrom="opacity-0"

@ -10,12 +10,7 @@ interface JSONEditorProps extends HTMLAttributes<HTMLDivElement> {
onUpdate: (value: string) => void; onUpdate: (value: string) => void;
} }
const JSONEditor: React.FC<JSONEditorProps> = ({ const JSONEditor = ({ name, value, onUpdate, onBlur }: JSONEditorProps) => {
name,
value,
onUpdate,
onBlur,
}) => {
return ( return (
<div className="w-full overflow-hidden rounded-md"> <div className="w-full overflow-hidden rounded-md">
<AceEditor <AceEditor

@ -34,12 +34,12 @@ interface LanguageSelectorProps {
isUserSettings?: boolean; isUserSettings?: boolean;
} }
const LanguageSelector: React.FC<LanguageSelectorProps> = ({ const LanguageSelector = ({
value, value,
setFieldValue, setFieldValue,
serverValue, serverValue,
isUserSettings = false, isUserSettings = false,
}) => { }: LanguageSelectorProps) => {
const intl = useIntl(); const intl = useIntl();
const { data: languages } = useSWR<Language[]>('/api/v1/languages'); const { data: languages } = useSWR<Language[]>('/api/v1/languages');

@ -11,7 +11,7 @@ const messages = defineMessages({
displaylanguage: 'Display Language', displaylanguage: 'Display Language',
}); });
const LanguagePicker: React.FC = () => { const LanguagePicker = () => {
const intl = useIntl(); const intl = useIntl();
const dropdownRef = useRef<HTMLDivElement>(null); const dropdownRef = useRef<HTMLDivElement>(null);
const { locale, setLocale } = useLocale(); const { locale, setLocale } = useLocale();

@ -1,7 +1,7 @@
import { BellIcon } from '@heroicons/react/outline'; import { BellIcon } from '@heroicons/react/outline';
import React from 'react'; import React from 'react';
const Notifications: React.FC = () => { const Notifications = () => {
return ( return (
<button <button
className="rounded-full p-1 text-gray-400 hover:bg-gray-500 hover:text-white focus:text-white focus:outline-none focus:ring" className="rounded-full p-1 text-gray-400 hover:bg-gray-500 hover:text-white focus:text-white focus:outline-none focus:ring"

@ -8,7 +8,7 @@ const messages = defineMessages({
searchPlaceholder: 'Search Movies & TV', searchPlaceholder: 'Search Movies & TV',
}); });
const SearchInput: React.FC = () => { const SearchInput = () => {
const intl = useIntl(); const intl = useIntl();
const { searchValue, setSearchValue, setIsOpen, clear } = useSearchInput(); const { searchValue, setSearchValue, setIsOpen, clear } = useSearchInput();
return ( return (

@ -85,7 +85,7 @@ const SidebarLinks: SidebarLinkProps[] = [
}, },
]; ];
const Sidebar: React.FC<SidebarProps> = ({ open, setClosed }) => { const Sidebar = ({ open, setClosed }: SidebarProps) => {
const navRef = useRef<HTMLDivElement>(null); const navRef = useRef<HTMLDivElement>(null);
const router = useRouter(); const router = useRouter();
const intl = useIntl(); const intl = useIntl();

@ -14,7 +14,7 @@ const messages = defineMessages({
signout: 'Sign Out', signout: 'Sign Out',
}); });
const UserDropdown: React.FC = () => { const UserDropdown = () => {
const intl = useIntl(); const intl = useIntl();
const dropdownRef = useRef<HTMLDivElement>(null); const dropdownRef = useRef<HTMLDivElement>(null);
const { user, revalidate } = useUser(); const { user, revalidate } = useUser();

@ -22,7 +22,7 @@ interface VersionStatusProps {
onClick?: () => void; onClick?: () => void;
} }
const VersionStatus: React.FC<VersionStatusProps> = ({ onClick }) => { const VersionStatus = ({ onClick }: VersionStatusProps) => {
const intl = useIntl(); const intl = useIntl();
const { data } = useSWR<StatusResponse>('/api/v1/status', { const { data } = useSWR<StatusResponse>('/api/v1/status', {
refreshInterval: 60 * 1000, refreshInterval: 60 * 1000,

@ -10,7 +10,11 @@ import SearchInput from './SearchInput';
import Sidebar from './Sidebar'; import Sidebar from './Sidebar';
import UserDropdown from './UserDropdown'; import UserDropdown from './UserDropdown';
const Layout: React.FC = ({ children }) => { type LayoutProps = {
children: React.ReactNode;
};
const Layout = ({ children }: LayoutProps) => {
const [isSidebarOpen, setSidebarOpen] = useState(false); const [isSidebarOpen, setSidebarOpen] = useState(false);
const [isScrolled, setIsScrolled] = useState(false); const [isScrolled, setIsScrolled] = useState(false);
const { user } = useUser(); const { user } = useUser();

@ -24,7 +24,7 @@ interface LocalLoginProps {
revalidate: () => void; revalidate: () => void;
} }
const LocalLogin: React.FC<LocalLoginProps> = ({ revalidate }) => { const LocalLogin = ({ revalidate }: LocalLoginProps) => {
const intl = useIntl(); const intl = useIntl();
const settings = useSettings(); const settings = useSettings();
const [loginError, setLoginError] = useState<string | null>(null); const [loginError, setLoginError] = useState<string | null>(null);
@ -80,9 +80,11 @@ const LocalLogin: React.FC<LocalLoginProps> = ({ revalidate }) => {
data-testid="email" data-testid="email"
/> />
</div> </div>
{errors.email && touched.email && ( {errors.email &&
<div className="error">{errors.email}</div> touched.email &&
)} typeof errors.email === 'string' && (
<div className="error">{errors.email}</div>
)}
</div> </div>
<label htmlFor="password" className="text-label"> <label htmlFor="password" className="text-label">
{intl.formatMessage(messages.password)} {intl.formatMessage(messages.password)}
@ -98,9 +100,11 @@ const LocalLogin: React.FC<LocalLoginProps> = ({ revalidate }) => {
data-testid="password" data-testid="password"
/> />
</div> </div>
{errors.password && touched.password && ( {errors.password &&
<div className="error">{errors.password}</div> touched.password &&
)} typeof errors.password === 'string' && (
<div className="error">{errors.password}</div>
)}
</div> </div>
{loginError && ( {loginError && (
<div className="mt-1 mb-2 sm:col-span-2 sm:mt-0"> <div className="mt-1 mb-2 sm:col-span-2 sm:mt-0">

@ -21,7 +21,7 @@ const messages = defineMessages({
signinwithoverseerr: 'Use your {applicationTitle} account', signinwithoverseerr: 'Use your {applicationTitle} account',
}); });
const Login: React.FC = () => { const Login = () => {
const intl = useIntl(); const intl = useIntl();
const [error, setError] = useState(''); const [error, setError] = useState('');
const [isProcessing, setProcessing] = useState(false); const [isProcessing, setProcessing] = useState(false);

@ -115,9 +115,9 @@ const ManageSlideOver: React.FC<
<> <>
{intl.formatMessage(messages.plays, { {intl.formatMessage(messages.plays, {
playCount, playCount,
strong: function strong(msg) { strong: (msg: React.ReactNode) => (
return <strong className="text-2xl font-semibold">{msg}</strong>; <strong className="text-2xl font-semibold">{msg}</strong>
}, ),
})} })}
</> </>
); );

@ -12,7 +12,7 @@ interface ShowMoreCardProps {
posters: (string | undefined)[]; posters: (string | undefined)[];
} }
const ShowMoreCard: React.FC<ShowMoreCardProps> = ({ url, posters }) => { const ShowMoreCard = ({ url, posters }: ShowMoreCardProps) => {
const intl = useIntl(); const intl = useIntl();
const [isHovered, setHovered] = useState(false); const [isHovered, setHovered] = useState(false);
return ( return (

@ -29,13 +29,13 @@ interface MediaSliderProps {
hideWhenEmpty?: boolean; hideWhenEmpty?: boolean;
} }
const MediaSlider: React.FC<MediaSliderProps> = ({ const MediaSlider = ({
title, title,
url, url,
linkUrl, linkUrl,
sliderKey, sliderKey,
hideWhenEmpty = false, hideWhenEmpty = false,
}) => { }: MediaSliderProps) => {
const settings = useSettings(); const settings = useSettings();
const { data, error, setSize, size } = useSWRInfinite<MixedResult>( const { data, error, setSize, size } = useSWRInfinite<MixedResult>(
(pageIndex: number, previousPageData: MixedResult | null) => { (pageIndex: number, previousPageData: MixedResult | null) => {

@ -14,7 +14,7 @@ const messages = defineMessages({
fullcast: 'Full Cast', fullcast: 'Full Cast',
}); });
const MovieCast: React.FC = () => { const MovieCast = () => {
const router = useRouter(); const router = useRouter();
const intl = useIntl(); const intl = useIntl();
const { data, error } = useSWR<MovieDetails>( const { data, error } = useSWR<MovieDetails>(

@ -14,7 +14,7 @@ const messages = defineMessages({
fullcrew: 'Full Crew', fullcrew: 'Full Crew',
}); });
const MovieCrew: React.FC = () => { const MovieCrew = () => {
const router = useRouter(); const router = useRouter();
const intl = useIntl(); const intl = useIntl();
const { data, error } = useSWR<MovieDetails>( const { data, error } = useSWR<MovieDetails>(

@ -15,7 +15,7 @@ const messages = defineMessages({
recommendations: 'Recommendations', recommendations: 'Recommendations',
}); });
const MovieRecommendations: React.FC = () => { const MovieRecommendations = () => {
const intl = useIntl(); const intl = useIntl();
const router = useRouter(); const router = useRouter();
const { data: movieData } = useSWR<MovieDetails>( const { data: movieData } = useSWR<MovieDetails>(

@ -15,7 +15,7 @@ const messages = defineMessages({
similar: 'Similar Titles', similar: 'Similar Titles',
}); });
const MovieSimilar: React.FC = () => { const MovieSimilar = () => {
const router = useRouter(); const router = useRouter();
const intl = useIntl(); const intl = useIntl();
const { data: movieData } = useSWR<MovieDetails>( const { data: movieData } = useSWR<MovieDetails>(

@ -80,7 +80,7 @@ interface MovieDetailsProps {
movie?: MovieDetailsType; movie?: MovieDetailsType;
} }
const MovieDetails: React.FC<MovieDetailsProps> = ({ movie }) => { const MovieDetails = ({ movie }: MovieDetailsProps) => {
const settings = useSettings(); const settings = useSettings();
const { user, hasPermission } = useUser(); const { user, hasPermission } = useUser();
const router = useRouter(); const router = useRouter();

@ -9,12 +9,12 @@ interface NotificationTypeProps {
onUpdate: (newTypes: number) => void; onUpdate: (newTypes: number) => void;
} }
const NotificationType: React.FC<NotificationTypeProps> = ({ const NotificationType = ({
option, option,
currentTypes, currentTypes,
onUpdate, onUpdate,
parent, parent,
}) => { }: NotificationTypeProps) => {
return ( return (
<> <>
<div <div

@ -125,13 +125,13 @@ interface NotificationTypeSelectorProps {
error?: string; error?: string;
} }
const NotificationTypeSelector: React.FC<NotificationTypeSelectorProps> = ({ const NotificationTypeSelector = ({
user, user,
enabledTypes = ALL_NOTIFICATIONS, enabledTypes = ALL_NOTIFICATIONS,
currentTypes, currentTypes,
onUpdate, onUpdate,
error, error,
}) => { }: NotificationTypeSelectorProps) => {
const intl = useIntl(); const intl = useIntl();
const settings = useSettings(); const settings = useSettings();
const { hasPermission } = useUser({ id: user?.id }); const { hasPermission } = useUser({ id: user?.id });

@ -4,9 +4,7 @@ interface PWAHeaderProps {
applicationTitle?: string; applicationTitle?: string;
} }
const PWAHeader: React.FC<PWAHeaderProps> = ({ const PWAHeader = ({ applicationTitle = 'Overseerr' }: PWAHeaderProps) => {
applicationTitle = 'Overseerr',
}) => {
return ( return (
<> <>
<link <link

@ -70,12 +70,12 @@ interface PermissionEditProps {
onUpdate: (newPermissions: number) => void; onUpdate: (newPermissions: number) => void;
} }
export const PermissionEdit: React.FC<PermissionEditProps> = ({ export const PermissionEdit = ({
actingUser, actingUser,
currentUser, currentUser,
currentPermission, currentPermission,
onUpdate, onUpdate,
}) => { }: PermissionEditProps) => {
const intl = useIntl(); const intl = useIntl();
const permissionList: PermissionItem[] = [ const permissionList: PermissionItem[] = [

@ -27,14 +27,14 @@ interface PermissionOptionProps {
onUpdate: (newPermissions: number) => void; onUpdate: (newPermissions: number) => void;
} }
const PermissionOption: React.FC<PermissionOptionProps> = ({ const PermissionOption = ({
option, option,
actingUser, actingUser,
currentUser, currentUser,
currentPermission, currentPermission,
onUpdate, onUpdate,
parent, parent,
}) => { }: PermissionOptionProps) => {
const settings = useSettings(); const settings = useSettings();
const autoApprovePermissions = [ const autoApprovePermissions = [

@ -11,13 +11,13 @@ interface PersonCardProps {
canExpand?: boolean; canExpand?: boolean;
} }
const PersonCard: React.FC<PersonCardProps> = ({ const PersonCard = ({
personId, personId,
name, name,
subName, subName,
profilePath, profilePath,
canExpand = false, canExpand = false,
}) => { }: PersonCardProps) => {
const [isHovered, setHovered] = useState(false); const [isHovered, setHovered] = useState(false);
return ( return (

@ -24,7 +24,7 @@ const messages = defineMessages({
ascharacter: 'as {character}', ascharacter: 'as {character}',
}); });
const PersonDetails: React.FC = () => { const PersonDetails = () => {
const intl = useIntl(); const intl = useIntl();
const router = useRouter(); const router = useRouter();
const { data, error } = useSWR<PersonDetailsType>( const { data, error } = useSWR<PersonDetailsType>(

@ -17,11 +17,11 @@ interface PlexLoginButtonProps {
onError?: (message: string) => void; onError?: (message: string) => void;
} }
const PlexLoginButton: React.FC<PlexLoginButtonProps> = ({ const PlexLoginButton = ({
onAuthToken, onAuthToken,
onError, onError,
isProcessing, isProcessing,
}) => { }: PlexLoginButtonProps) => {
const intl = useIntl(); const intl = useIntl();
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);

@ -24,7 +24,7 @@ interface QuotaSelectorProps {
onChange: (fieldName: string, value: number) => void; onChange: (fieldName: string, value: number) => void;
} }
const QuotaSelector: React.FC<QuotaSelectorProps> = ({ const QuotaSelector = ({
mediaType, mediaType,
dayFieldName, dayFieldName,
limitFieldName, limitFieldName,
@ -34,7 +34,7 @@ const QuotaSelector: React.FC<QuotaSelectorProps> = ({
limitOverride, limitOverride,
isDisabled = false, isDisabled = false,
onChange, onChange,
}) => { }: QuotaSelectorProps) => {
const initialDays = defaultDays ?? 7; const initialDays = defaultDays ?? 7;
const initialLimit = defaultLimit ?? 0; const initialLimit = defaultLimit ?? 0;
const [quotaDays, setQuotaDays] = useState(initialDays); const [quotaDays, setQuotaDays] = useState(initialDays);

@ -21,12 +21,12 @@ interface RegionSelectorProps {
onChange?: (fieldName: string, region: string) => void; onChange?: (fieldName: string, region: string) => void;
} }
const RegionSelector: React.FC<RegionSelectorProps> = ({ const RegionSelector = ({
name, name,
value, value,
isUserSetting = false, isUserSetting = false,
onChange, onChange,
}) => { }: RegionSelectorProps) => {
const { currentSettings } = useSettings(); const { currentSettings } = useSettings();
const intl = useIntl(); const intl = useIntl();
const { data: regions } = useSWR<Region[]>('/api/v1/regions'); const { data: regions } = useSWR<Region[]>('/api/v1/regions');

@ -34,7 +34,7 @@ interface RequestBlockProps {
onUpdate?: () => void; onUpdate?: () => void;
} }
const RequestBlock: React.FC<RequestBlockProps> = ({ request, onUpdate }) => { const RequestBlock = ({ request, onUpdate }: RequestBlockProps) => {
const { user } = useUser(); const { user } = useUser();
const intl = useIntl(); const intl = useIntl();
const [isUpdating, setIsUpdating] = useState(false); const [isUpdating, setIsUpdating] = useState(false);

@ -54,14 +54,14 @@ interface RequestButtonProps {
is4kShowComplete?: boolean; is4kShowComplete?: boolean;
} }
const RequestButton: React.FC<RequestButtonProps> = ({ const RequestButton = ({
tmdbId, tmdbId,
onUpdate, onUpdate,
media, media,
mediaType, mediaType,
isShowComplete = false, isShowComplete = false,
is4kShowComplete = false, is4kShowComplete = false,
}) => { }: RequestButtonProps) => {
const intl = useIntl(); const intl = useIntl();
const settings = useSettings(); const settings = useSettings();
const { user, hasPermission } = useUser(); const { user, hasPermission } = useUser();

@ -39,7 +39,7 @@ const isMovie = (movie: MovieDetails | TvDetails): movie is MovieDetails => {
return (movie as MovieDetails).title !== undefined; return (movie as MovieDetails).title !== undefined;
}; };
const RequestCardPlaceholder: React.FC = () => { const RequestCardPlaceholder = () => {
return ( return (
<div className="relative w-72 animate-pulse rounded-xl bg-gray-700 p-4 sm:w-96"> <div className="relative w-72 animate-pulse rounded-xl bg-gray-700 p-4 sm:w-96">
<div className="w-20 sm:w-28"> <div className="w-20 sm:w-28">
@ -53,7 +53,7 @@ interface RequestCardErrorProps {
mediaId?: number; mediaId?: number;
} }
const RequestCardError: React.FC<RequestCardErrorProps> = ({ mediaId }) => { const RequestCardError = ({ mediaId }: RequestCardErrorProps) => {
const { hasPermission } = useUser(); const { hasPermission } = useUser();
const intl = useIntl(); const intl = useIntl();
@ -93,7 +93,7 @@ interface RequestCardProps {
onTitleData?: (requestId: number, title: MovieDetails | TvDetails) => void; onTitleData?: (requestId: number, title: MovieDetails | TvDetails) => void;
} }
const RequestCard: React.FC<RequestCardProps> = ({ request, onTitleData }) => { const RequestCard = ({ request, onTitleData }: RequestCardProps) => {
const { ref, inView } = useInView({ const { ref, inView } = useInView({
triggerOnce: true, triggerOnce: true,
}); });

@ -50,10 +50,10 @@ interface RequestItemErroProps {
revalidateList: () => void; revalidateList: () => void;
} }
const RequestItemError: React.FC<RequestItemErroProps> = ({ const RequestItemError = ({
mediaId, mediaId,
revalidateList, revalidateList,
}) => { }: RequestItemErroProps) => {
const intl = useIntl(); const intl = useIntl();
const { hasPermission } = useUser(); const { hasPermission } = useUser();
@ -88,10 +88,7 @@ interface RequestItemProps {
revalidateList: () => void; revalidateList: () => void;
} }
const RequestItem: React.FC<RequestItemProps> = ({ const RequestItem = ({ request, revalidateList }: RequestItemProps) => {
request,
revalidateList,
}) => {
const { ref, inView } = useInView({ const { ref, inView } = useInView({
triggerOnce: true, triggerOnce: true,
}); });

@ -37,7 +37,7 @@ enum Filter {
type Sort = 'added' | 'modified'; type Sort = 'added' | 'modified';
const RequestList: React.FC = () => { const RequestList = () => {
const router = useRouter(); const router = useRouter();
const intl = useIntl(); const intl = useIntl();
const { user } = useUser({ const { user } = useUser({
@ -238,9 +238,9 @@ const RequestList: React.FC = () => {
? pageIndex * currentPageSize + data.results.length ? pageIndex * currentPageSize + data.results.length
: (pageIndex + 1) * currentPageSize, : (pageIndex + 1) * currentPageSize,
total: data.pageInfo.results, total: data.pageInfo.results,
strong: function strong(msg) { strong: (msg: React.ReactNode) => (
return <span className="font-medium">{msg}</span>; <span className="font-medium">{msg}</span>
}, ),
})} })}
</p> </p>
</div> </div>

@ -56,14 +56,14 @@ interface AdvancedRequesterProps {
onChange: (overrides: RequestOverrides) => void; onChange: (overrides: RequestOverrides) => void;
} }
const AdvancedRequester: React.FC<AdvancedRequesterProps> = ({ const AdvancedRequester = ({
type, type,
is4k = false, is4k = false,
isAnime = false, isAnime = false,
defaultOverrides, defaultOverrides,
requestUser, requestUser,
onChange, onChange,
}) => { }: AdvancedRequesterProps) => {
const intl = useIntl(); const intl = useIntl();
const { user, hasPermission } = useUser(); const { user, hasPermission } = useUser();
const { data, error } = useSWR<ServiceCommonServer[]>( const { data, error } = useSWR<ServiceCommonServer[]>(

@ -42,13 +42,13 @@ interface RequestModalProps extends React.HTMLAttributes<HTMLDivElement> {
onUpdating?: (isUpdating: boolean) => void; onUpdating?: (isUpdating: boolean) => void;
} }
const CollectionRequestModal: React.FC<RequestModalProps> = ({ const CollectionRequestModal = ({
onCancel, onCancel,
onComplete, onComplete,
tmdbId, tmdbId,
onUpdating, onUpdating,
is4k = false, is4k = false,
}) => { }: RequestModalProps) => {
const [isUpdating, setIsUpdating] = useState(false); const [isUpdating, setIsUpdating] = useState(false);
const [requestOverrides, setRequestOverrides] = const [requestOverrides, setRequestOverrides] =
useState<RequestOverrides | null>(null); useState<RequestOverrides | null>(null);
@ -221,9 +221,7 @@ const CollectionRequestModal: React.FC<RequestModalProps> = ({
<span> <span>
{intl.formatMessage(messages.requestSuccess, { {intl.formatMessage(messages.requestSuccess, {
title: data?.name, title: data?.name,
strong: function strong(msg) { strong: (msg: React.ReactNode) => <strong>{msg}</strong>,
return <strong>{msg}</strong>;
},
})} })}
</span>, </span>,
{ appearance: 'success', autoDismiss: true } { appearance: 'success', autoDismiss: true }

@ -45,14 +45,14 @@ interface RequestModalProps extends React.HTMLAttributes<HTMLDivElement> {
onUpdating?: (isUpdating: boolean) => void; onUpdating?: (isUpdating: boolean) => void;
} }
const MovieRequestModal: React.FC<RequestModalProps> = ({ const MovieRequestModal = ({
onCancel, onCancel,
onComplete, onComplete,
tmdbId, tmdbId,
onUpdating, onUpdating,
editRequest, editRequest,
is4k = false, is4k = false,
}) => { }: RequestModalProps) => {
const [isUpdating, setIsUpdating] = useState(false); const [isUpdating, setIsUpdating] = useState(false);
const [requestOverrides, setRequestOverrides] = const [requestOverrides, setRequestOverrides] =
useState<RequestOverrides | null>(null); useState<RequestOverrides | null>(null);
@ -115,9 +115,7 @@ const MovieRequestModal: React.FC<RequestModalProps> = ({
<span> <span>
{intl.formatMessage(messages.requestSuccess, { {intl.formatMessage(messages.requestSuccess, {
title: data?.title, title: data?.title,
strong: function strong(msg) { strong: (msg: React.ReactNode) => <strong>{msg}</strong>,
return <strong>{msg}</strong>;
},
})} })}
</span>, </span>,
{ appearance: 'success', autoDismiss: true } { appearance: 'success', autoDismiss: true }
@ -149,9 +147,7 @@ const MovieRequestModal: React.FC<RequestModalProps> = ({
<span> <span>
{intl.formatMessage(messages.requestCancel, { {intl.formatMessage(messages.requestCancel, {
title: data?.title, title: data?.title,
strong: function strong(msg) { strong: (msg: React.ReactNode) => <strong>{msg}</strong>,
return <strong>{msg}</strong>;
},
})} })}
</span>, </span>,
{ appearance: 'success', autoDismiss: true } { appearance: 'success', autoDismiss: true }
@ -187,9 +183,7 @@ const MovieRequestModal: React.FC<RequestModalProps> = ({
: messages.requestedited, : messages.requestedited,
{ {
title: data?.title, title: data?.title,
strong: function strong(msg) { strong: (msg: React.ReactNode) => <strong>{msg}</strong>,
return <strong>{msg}</strong>;
},
} }
)} )}
</span>, </span>,

@ -35,13 +35,13 @@ interface QuotaDisplayProps {
overLimit?: number; overLimit?: number;
} }
const QuotaDisplay: React.FC<QuotaDisplayProps> = ({ const QuotaDisplay = ({
quota, quota,
mediaType, mediaType,
userOverride, userOverride,
remaining, remaining,
overLimit, overLimit,
}) => { }: QuotaDisplayProps) => {
const intl = useIntl(); const intl = useIntl();
const [showDetails, setShowDetails] = useState(false); const [showDetails, setShowDetails] = useState(false);
return ( return (
@ -79,9 +79,7 @@ const QuotaDisplay: React.FC<QuotaDisplayProps> = ({
type: intl.formatMessage( type: intl.formatMessage(
mediaType === 'movie' ? messages.movie : messages.season mediaType === 'movie' ? messages.movie : messages.season
), ),
strong: function strong(msg) { strong: (msg: React.ReactNode) => <strong>{msg}</strong>,
return <span className="font-bold">{msg}</span>;
},
})} })}
</div> </div>
</div> </div>
@ -103,9 +101,7 @@ const QuotaDisplay: React.FC<QuotaDisplayProps> = ({
: messages.requiredquota, : messages.requiredquota,
{ {
seasons: overLimit, seasons: overLimit,
strong: function strong(msg) { strong: (msg: React.ReactNode) => <strong>{msg}</strong>,
return <span className="font-bold">{msg}</span>;
},
} }
)} )}
</div> </div>
@ -124,9 +120,7 @@ const QuotaDisplay: React.FC<QuotaDisplayProps> = ({
: messages.seasonlimit, : messages.seasonlimit,
{ limit: quota?.limit } { limit: quota?.limit }
), ),
strong: function strong(msg) { strong: (msg: React.ReactNode) => <strong>{msg}</strong>,
return <span className="font-bold">{msg}</span>;
},
} }
)} )}
</div> </div>
@ -134,19 +128,15 @@ const QuotaDisplay: React.FC<QuotaDisplayProps> = ({
{intl.formatMessage( {intl.formatMessage(
userOverride ? messages.quotaLinkUser : messages.quotaLink, userOverride ? messages.quotaLinkUser : messages.quotaLink,
{ {
ProfileLink: function ProfileLink(msg) { ProfileLink: (msg: React.ReactNode) => (
return ( <Link
<Link href={userOverride ? `/users/${userOverride}` : '/profile'}
href={ >
userOverride ? `/users/${userOverride}` : '/profile' <a className="text-white transition duration-300 hover:underline">
} {msg}
> </a>
<a className="text-white transition duration-300 hover:underline"> </Link>
{msg} ),
</a>
</Link>
);
},
} }
)} )}
</div> </div>

@ -24,7 +24,7 @@ interface SearchByNameModalProps {
tmdbId: number; tmdbId: number;
} }
const SearchByNameModal: React.FC<SearchByNameModalProps> = ({ const SearchByNameModal = ({
setTvdbId, setTvdbId,
tvdbId, tvdbId,
loading, loading,
@ -32,7 +32,7 @@ const SearchByNameModal: React.FC<SearchByNameModalProps> = ({
closeModal, closeModal,
modalTitle, modalTitle,
tmdbId, tmdbId,
}) => { }: SearchByNameModalProps) => {
const intl = useIntl(); const intl = useIntl();
const { data, error } = useSWR<SonarrSeries[]>( const { data, error } = useSWR<SonarrSeries[]>(
`/api/v1/service/sonarr/lookup/${tmdbId}` `/api/v1/service/sonarr/lookup/${tmdbId}`

@ -64,14 +64,14 @@ interface RequestModalProps extends React.HTMLAttributes<HTMLDivElement> {
editRequest?: MediaRequest; editRequest?: MediaRequest;
} }
const TvRequestModal: React.FC<RequestModalProps> = ({ const TvRequestModal = ({
onCancel, onCancel,
onComplete, onComplete,
tmdbId, tmdbId,
onUpdating, onUpdating,
editRequest, editRequest,
is4k = false, is4k = false,
}) => { }: RequestModalProps) => {
const settings = useSettings(); const settings = useSettings();
const { addToast } = useToasts(); const { addToast } = useToasts();
const editingSeasons: number[] = (editRequest?.seasons ?? []).map( const editingSeasons: number[] = (editRequest?.seasons ?? []).map(
@ -141,16 +141,12 @@ const TvRequestModal: React.FC<RequestModalProps> = ({
: messages.requestedited, : messages.requestedited,
{ {
title: data?.name, title: data?.name,
strong: function strong(msg) { strong: (msg: React.ReactNode) => <strong>{msg}</strong>,
return <strong>{msg}</strong>;
},
} }
) )
: intl.formatMessage(messages.requestcancelled, { : intl.formatMessage(messages.requestcancelled, {
title: data?.name, title: data?.name,
strong: function strong(msg) { strong: (msg: React.ReactNode) => <strong>{msg}</strong>,
return <strong>{msg}</strong>;
},
})} })}
</span>, </span>,
{ {
@ -218,9 +214,7 @@ const TvRequestModal: React.FC<RequestModalProps> = ({
<span> <span>
{intl.formatMessage(messages.requestSuccess, { {intl.formatMessage(messages.requestSuccess, {
title: data?.name, title: data?.name,
strong: function strong(msg) { strong: (msg: React.ReactNode) => <strong>{msg}</strong>,
return <strong>{msg}</strong>;
},
})} })}
</span>, </span>,
{ appearance: 'success', autoDismiss: true } { appearance: 'success', autoDismiss: true }

@ -17,7 +17,7 @@ interface RequestModalProps {
onUpdating?: (isUpdating: boolean) => void; onUpdating?: (isUpdating: boolean) => void;
} }
const RequestModal: React.FC<RequestModalProps> = ({ const RequestModal = ({
type, type,
show, show,
tmdbId, tmdbId,
@ -26,7 +26,7 @@ const RequestModal: React.FC<RequestModalProps> = ({
onComplete, onComplete,
onUpdating, onUpdating,
onCancel, onCancel,
}) => { }: RequestModalProps) => {
return ( return (
<Transition <Transition
enter="transition opacity-0 duration-300" enter="transition opacity-0 duration-300"

@ -21,7 +21,7 @@ const messages = defineMessages({
'A password reset link will be sent to the provided email address if it is associated with a valid user.', 'A password reset link will be sent to the provided email address if it is associated with a valid user.',
}); });
const ResetPassword: React.FC = () => { const ResetPassword = () => {
const intl = useIntl(); const intl = useIntl();
const [hasSubmitted, setSubmitted] = useState(false); const [hasSubmitted, setSubmitted] = useState(false);
@ -113,9 +113,11 @@ const ResetPassword: React.FC = () => {
className="form-input-area block w-full min-w-0 flex-1 rounded-md border border-gray-500 bg-gray-700 text-white transition duration-150 ease-in-out sm:text-sm sm:leading-5" className="form-input-area block w-full min-w-0 flex-1 rounded-md border border-gray-500 bg-gray-700 text-white transition duration-150 ease-in-out sm:text-sm sm:leading-5"
/> />
</div> </div>
{errors.email && touched.email && ( {errors.email &&
<div className="error">{errors.email}</div> touched.email &&
)} typeof errors.email === 'string' && (
<div className="error">{errors.email}</div>
)}
</div> </div>
</div> </div>
<div className="mt-4 border-t border-gray-700 pt-5"> <div className="mt-4 border-t border-gray-700 pt-5">

@ -25,7 +25,7 @@ const messages = defineMessages({
resetpasswordsuccessmessage: 'Password reset successfully!', resetpasswordsuccessmessage: 'Password reset successfully!',
}); });
const ResetPassword: React.FC = () => { const ResetPassword = () => {
const intl = useIntl(); const intl = useIntl();
const router = useRouter(); const router = useRouter();
const [hasSubmitted, setSubmitted] = useState(false); const [hasSubmitted, setSubmitted] = useState(false);
@ -129,9 +129,11 @@ const ResetPassword: React.FC = () => {
className="form-input-area block w-full min-w-0 flex-1 rounded-md border border-gray-500 bg-gray-700 text-white transition duration-150 ease-in-out sm:text-sm sm:leading-5" className="form-input-area block w-full min-w-0 flex-1 rounded-md border border-gray-500 bg-gray-700 text-white transition duration-150 ease-in-out sm:text-sm sm:leading-5"
/> />
</div> </div>
{errors.password && touched.password && ( {errors.password &&
<div className="error">{errors.password}</div> touched.password &&
)} typeof errors.password === 'string' && (
<div className="error">{errors.password}</div>
)}
</div> </div>
<label <label
htmlFor="confirmPassword" htmlFor="confirmPassword"

@ -17,7 +17,7 @@ const messages = defineMessages({
searchresults: 'Search Results', searchresults: 'Search Results',
}); });
const Search: React.FC = () => { const Search = () => {
const intl = useIntl(); const intl = useIntl();
const router = useRouter(); const router = useRouter();

@ -1,11 +1,10 @@
/* eslint-disable no-console */ /* eslint-disable no-console */
import axios from 'axios'; import axios from 'axios';
import type React from 'react';
import { useEffect } from 'react'; import { useEffect } from 'react';
import useSettings from '../../hooks/useSettings'; import useSettings from '../../hooks/useSettings';
import { useUser } from '../../hooks/useUser'; import { useUser } from '../../hooks/useUser';
const ServiceWorkerSetup: React.FC = () => { const ServiceWorkerSetup = () => {
const { currentSettings } = useSettings(); const { currentSettings } = useSettings();
const { user } = useUser(); const { user } = useUser();
useEffect(() => { useEffect(() => {

@ -8,7 +8,7 @@ const messages = defineMessages({
copied: 'Copied API key to clipboard.', copied: 'Copied API key to clipboard.',
}); });
const CopyButton: React.FC<{ textToCopy: string }> = ({ textToCopy }) => { const CopyButton = ({ textToCopy }: { textToCopy: string }) => {
const intl = useIntl(); const intl = useIntl();
const [isCopied, setCopied] = useClipboard(textToCopy, { const [isCopied, setCopied] = useClipboard(textToCopy, {
successDuration: 1000, successDuration: 1000,

@ -7,11 +7,7 @@ interface LibraryItemProps {
onToggle: () => void; onToggle: () => void;
} }
const LibraryItem: React.FC<LibraryItemProps> = ({ const LibraryItem = ({ isEnabled, name, onToggle }: LibraryItemProps) => {
isEnabled,
name,
onToggle,
}) => {
return ( return (
<li className="col-span-1 flex rounded-md shadow-sm"> <li className="col-span-1 flex rounded-md shadow-sm">
<div className="flex flex-1 items-center justify-between truncate rounded-md border-t border-b border-r border-gray-700 bg-gray-600"> <div className="flex flex-1 items-center justify-between truncate rounded-md border-t border-b border-r border-gray-700 bg-gray-600">

@ -29,7 +29,7 @@ const messages = defineMessages({
enableMentions: 'Enable Mentions', enableMentions: 'Enable Mentions',
}); });
const NotificationsDiscord: React.FC = () => { const NotificationsDiscord = () => {
const intl = useIntl(); const intl = useIntl();
const settings = useSettings(); const settings = useSettings();
const { addToast, removeToast } = useToasts(); const { addToast, removeToast } = useToasts();
@ -168,18 +168,16 @@ const NotificationsDiscord: React.FC = () => {
<span className="label-required">*</span> <span className="label-required">*</span>
<span className="label-tip"> <span className="label-tip">
{intl.formatMessage(messages.webhookUrlTip, { {intl.formatMessage(messages.webhookUrlTip, {
DiscordWebhookLink: function DiscordWebhookLink(msg) { DiscordWebhookLink: (msg: React.ReactNode) => (
return ( <a
<a href="https://support.discord.com/hc/en-us/articles/228383668-Intro-to-Webhooks"
href="https://support.discord.com/hc/en-us/articles/228383668-Intro-to-Webhooks" className="text-white transition duration-300 hover:underline"
className="text-white transition duration-300 hover:underline" target="_blank"
target="_blank" rel="noreferrer"
rel="noreferrer" >
> {msg}
{msg} </a>
</a> ),
);
},
})} })}
</span> </span>
</label> </label>
@ -192,9 +190,11 @@ const NotificationsDiscord: React.FC = () => {
inputMode="url" inputMode="url"
/> />
</div> </div>
{errors.webhookUrl && touched.webhookUrl && ( {errors.webhookUrl &&
<div className="error">{errors.webhookUrl}</div> touched.webhookUrl &&
)} typeof errors.webhookUrl === 'string' && (
<div className="error">{errors.webhookUrl}</div>
)}
</div> </div>
</div> </div>
<div className="form-row"> <div className="form-row">
@ -210,9 +210,11 @@ const NotificationsDiscord: React.FC = () => {
placeholder={settings.currentSettings.applicationTitle} placeholder={settings.currentSettings.applicationTitle}
/> />
</div> </div>
{errors.botUsername && touched.botUsername && ( {errors.botUsername &&
<div className="error">{errors.botUsername}</div> touched.botUsername &&
)} typeof errors.botUsername === 'string' && (
<div className="error">{errors.botUsername}</div>
)}
</div> </div>
</div> </div>
<div className="form-row"> <div className="form-row">
@ -228,9 +230,11 @@ const NotificationsDiscord: React.FC = () => {
inputMode="url" inputMode="url"
/> />
</div> </div>
{errors.botAvatarUrl && touched.botAvatarUrl && ( {errors.botAvatarUrl &&
<div className="error">{errors.botAvatarUrl}</div> touched.botAvatarUrl &&
)} typeof errors.botAvatarUrl === 'string' && (
<div className="error">{errors.botAvatarUrl}</div>
)}
</div> </div>
</div> </div>
<div className="form-row"> <div className="form-row">

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save