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 = {
env: {
commitTag: process.env.COMMIT_TAG || 'local',

@ -29,6 +29,9 @@
},
"license": "MIT",
"dependencies": {
"@formatjs/intl-displaynames": "^6.0.3",
"@formatjs/intl-locale": "^3.0.3",
"@formatjs/intl-pluralrules": "^5.0.3",
"@headlessui/react": "1.6.6",
"@heroicons/react": "1.0.6",
"@supercharge/request-ip": "1.2.0",
@ -62,12 +65,12 @@
"openpgp": "5.4.0",
"plex-api": "5.3.2",
"pug": "3.0.2",
"react": "17.0.2",
"react": "18.2.0",
"react-ace": "10.1.0",
"react-animate-height": "2.1.2",
"react-dom": "17.0.2",
"react-dom": "18.2.0",
"react-intersection-observer": "9.4.0",
"react-intl": "5.25.1",
"react-intl": "6.0.5",
"react-markdown": "8.0.3",
"react-select": "5.4.0",
"react-spring": "9.5.2",
@ -111,8 +114,8 @@
"@types/node": "17.0.36",
"@types/node-schedule": "2.1.0",
"@types/nodemailer": "6.4.5",
"@types/react": "17.0.45",
"@types/react-dom": "17.0.17",
"@types/react": "18.0.17",
"@types/react-dom": "18.0.6",
"@types/react-transition-group": "4.4.5",
"@types/secure-random-password": "0.2.1",
"@types/semver": "7.3.12",
@ -153,7 +156,9 @@
"typescript": "4.7.4"
},
"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": {
"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.',
});
const AppDataWarning: React.FC = () => {
const AppDataWarning = () => {
const intl = useIntl();
const { data, error } = useSWR<{ appData: boolean; appDataPath: string }>(
'/api/v1/status/appdata'
@ -27,9 +27,9 @@ const AppDataWarning: React.FC = () => {
{!data.appData && (
<Alert
title={intl.formatMessage(messages.dockerVolumeMissingDescription, {
code: function code(msg) {
return <code className="bg-opacity-50">{msg}</code>;
},
code: (msg: React.ReactNode) => (
<code className="bg-opacity-50">{msg}</code>
),
appDataPath: data.appDataPath,
})}
/>

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

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

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

@ -5,14 +5,15 @@ interface BadgeProps {
badgeType?: 'default' | 'primary' | 'danger' | 'warning' | 'success';
className?: string;
href?: string;
children: React.ReactNode;
}
const Badge: React.FC<BadgeProps> = ({
const Badge = ({
badgeType = 'default',
className,
href,
children,
}) => {
}: BadgeProps) => {
const badgeStyle = [
'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';
}
const DropdownItem: React.FC<DropdownItemProps> = ({
const DropdownItem = ({
children,
buttonType = 'primary',
...props
}) => {
}: DropdownItemProps) => {
let styleClass = 'button-md text-white';
switch (buttonType) {
@ -46,14 +46,14 @@ interface ButtonWithDropdownProps
buttonType?: 'primary' | 'ghost';
}
const ButtonWithDropdown: React.FC<ButtonWithDropdownProps> = ({
const ButtonWithDropdown = ({
text,
children,
dropdownIcon,
className,
buttonType = 'primary',
...props
}) => {
}: ButtonWithDropdownProps) => {
const [isOpen, setIsOpen] = useState(false);
const buttonRef = useRef<HTMLButtonElement>(null);
useClickOutside(buttonRef, () => setIsOpen(false));

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

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

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

@ -4,9 +4,10 @@ import { withProperties } from '../../../utils/typeHelpers';
interface ListItemProps {
title: string;
className?: string;
children: React.ReactNode;
}
const ListItem: React.FC<ListItemProps> = ({ title, className, children }) => {
const ListItem = ({ title, className, children }: ListItemProps) => {
return (
<div>
<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 {
title: string;
subTitle?: string;
children: React.ReactNode;
}
const List: React.FC<ListProps> = ({ title, subTitle, children }) => {
const List = ({ title, subTitle, children }: ListProps) => {
return (
<>
<div>

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

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

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

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

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

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

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

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

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

@ -1,18 +1,21 @@
import type { AllHTMLAttributes } from 'react';
import React from 'react';
import { withProperties } from '../../../utils/typeHelpers';
const TBody: React.FC = ({ children }) => {
type TBodyProps = {
children: React.ReactNode;
};
const TBody = ({ children }: TBodyProps) => {
return (
<tbody className="divide-y divide-gray-700 bg-gray-800">{children}</tbody>
);
};
const TH: React.FC<AllHTMLAttributes<HTMLTableHeaderCellElement>> = ({
const TH = ({
children,
className,
...props
}) => {
}: React.ComponentPropsWithoutRef<'th'>) => {
const style = [
'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';
noPadding?: boolean;
}
};
const TD: React.FC<TDProps> = ({
const TD = ({
children,
alignText = 'left',
noPadding,
className,
...props
}) => {
}: TDProps & React.ComponentPropsWithoutRef<'td'>) => {
const style = ['text-sm leading-5 text-white'];
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 (
<div className="flex flex-col">
<div className="my-2 -mx-4 overflow-x-auto md:mx-0 lg:mx-0">

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

@ -10,12 +10,7 @@ interface GenreCardProps {
canExpand?: boolean;
}
const GenreCard: React.FC<GenreCardProps> = ({
image,
url,
name,
canExpand = false,
}) => {
const GenreCard = ({ image, url, name, canExpand = false }: GenreCardProps) => {
const [isHovered, setHovered] = useState(false);
return (
@ -54,7 +49,7 @@ const GenreCard: React.FC<GenreCardProps> = ({
);
};
const GenreCardPlaceholder: React.FC = () => {
const GenreCardPlaceholder = () => {
return (
<div
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;
}
const IssueBlock: React.FC<IssueBlockProps> = ({ issue }) => {
const IssueBlock = ({ issue }: IssueBlockProps) => {
const { user } = useUser();
const intl = useIntl();
const issueOption = issueOptions.find(

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

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

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

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

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

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

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

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

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

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

@ -1,7 +1,7 @@
import { BellIcon } from '@heroicons/react/outline';
import React from 'react';
const Notifications: React.FC = () => {
const Notifications = () => {
return (
<button
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',
});
const SearchInput: React.FC = () => {
const SearchInput = () => {
const intl = useIntl();
const { searchValue, setSearchValue, setIsOpen, clear } = useSearchInput();
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 router = useRouter();
const intl = useIntl();

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

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

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

@ -24,7 +24,7 @@ interface LocalLoginProps {
revalidate: () => void;
}
const LocalLogin: React.FC<LocalLoginProps> = ({ revalidate }) => {
const LocalLogin = ({ revalidate }: LocalLoginProps) => {
const intl = useIntl();
const settings = useSettings();
const [loginError, setLoginError] = useState<string | null>(null);
@ -80,9 +80,11 @@ const LocalLogin: React.FC<LocalLoginProps> = ({ revalidate }) => {
data-testid="email"
/>
</div>
{errors.email && touched.email && (
<div className="error">{errors.email}</div>
)}
{errors.email &&
touched.email &&
typeof errors.email === 'string' && (
<div className="error">{errors.email}</div>
)}
</div>
<label htmlFor="password" className="text-label">
{intl.formatMessage(messages.password)}
@ -98,9 +100,11 @@ const LocalLogin: React.FC<LocalLoginProps> = ({ revalidate }) => {
data-testid="password"
/>
</div>
{errors.password && touched.password && (
<div className="error">{errors.password}</div>
)}
{errors.password &&
touched.password &&
typeof errors.password === 'string' && (
<div className="error">{errors.password}</div>
)}
</div>
{loginError && (
<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',
});
const Login: React.FC = () => {
const Login = () => {
const intl = useIntl();
const [error, setError] = useState('');
const [isProcessing, setProcessing] = useState(false);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

@ -17,7 +17,7 @@ interface RequestModalProps {
onUpdating?: (isUpdating: boolean) => void;
}
const RequestModal: React.FC<RequestModalProps> = ({
const RequestModal = ({
type,
show,
tmdbId,
@ -26,7 +26,7 @@ const RequestModal: React.FC<RequestModalProps> = ({
onComplete,
onUpdating,
onCancel,
}) => {
}: RequestModalProps) => {
return (
<Transition
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.',
});
const ResetPassword: React.FC = () => {
const ResetPassword = () => {
const intl = useIntl();
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"
/>
</div>
{errors.email && touched.email && (
<div className="error">{errors.email}</div>
)}
{errors.email &&
touched.email &&
typeof errors.email === 'string' && (
<div className="error">{errors.email}</div>
)}
</div>
</div>
<div className="mt-4 border-t border-gray-700 pt-5">

@ -25,7 +25,7 @@ const messages = defineMessages({
resetpasswordsuccessmessage: 'Password reset successfully!',
});
const ResetPassword: React.FC = () => {
const ResetPassword = () => {
const intl = useIntl();
const router = useRouter();
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"
/>
</div>
{errors.password && touched.password && (
<div className="error">{errors.password}</div>
)}
{errors.password &&
touched.password &&
typeof errors.password === 'string' && (
<div className="error">{errors.password}</div>
)}
</div>
<label
htmlFor="confirmPassword"

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

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

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

@ -7,11 +7,7 @@ interface LibraryItemProps {
onToggle: () => void;
}
const LibraryItem: React.FC<LibraryItemProps> = ({
isEnabled,
name,
onToggle,
}) => {
const LibraryItem = ({ isEnabled, name, onToggle }: LibraryItemProps) => {
return (
<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">

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

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

Loading…
Cancel
Save