mirror of
https://github.com/sct/overseerr.git
synced 2025-09-17 17:24:35 +02:00
feat(frontend): add option to hide all available items from discovery (#699)
This commit is contained in:
@@ -62,6 +62,9 @@ components:
|
||||
applicationUrl:
|
||||
type: string
|
||||
example: https://os.example.com
|
||||
hideAvailable:
|
||||
type: boolean
|
||||
example: false
|
||||
defaultPermissions:
|
||||
type: number
|
||||
example: 32
|
||||
|
@@ -9,4 +9,5 @@ export interface PublicSettingsResponse {
|
||||
initialized: boolean;
|
||||
movie4kEnabled: boolean;
|
||||
series4kEnabled: boolean;
|
||||
hideAvailable: boolean;
|
||||
}
|
||||
|
@@ -49,6 +49,7 @@ export interface MainSettings {
|
||||
apiKey: string;
|
||||
applicationUrl: string;
|
||||
defaultPermissions: number;
|
||||
hideAvailable: boolean;
|
||||
}
|
||||
|
||||
interface PublicSettings {
|
||||
@@ -58,6 +59,7 @@ interface PublicSettings {
|
||||
interface FullPublicSettings extends PublicSettings {
|
||||
movie4kEnabled: boolean;
|
||||
series4kEnabled: boolean;
|
||||
hideAvailable: boolean;
|
||||
}
|
||||
|
||||
export interface NotificationAgentConfig {
|
||||
@@ -150,6 +152,7 @@ class Settings {
|
||||
main: {
|
||||
apiKey: '',
|
||||
applicationUrl: '',
|
||||
hideAvailable: false,
|
||||
defaultPermissions: Permission.REQUEST,
|
||||
},
|
||||
plex: {
|
||||
@@ -281,6 +284,7 @@ class Settings {
|
||||
series4kEnabled: this.data.sonarr.some(
|
||||
(sonarr) => sonarr.is4k && sonarr.isDefault
|
||||
),
|
||||
hideAvailable: this.data.main.hideAvailable,
|
||||
};
|
||||
}
|
||||
|
||||
|
@@ -5,6 +5,8 @@ import ListView from '../Common/ListView';
|
||||
import { LanguageContext } from '../../context/LanguageContext';
|
||||
import { defineMessages, FormattedMessage } from 'react-intl';
|
||||
import Header from '../Common/Header';
|
||||
import useSettings from '../../hooks/useSettings';
|
||||
import { MediaStatus } from '../../../server/constants/media';
|
||||
|
||||
const messages = defineMessages({
|
||||
discovermovies: 'Popular Movies',
|
||||
@@ -18,6 +20,7 @@ interface SearchResult {
|
||||
}
|
||||
|
||||
const DiscoverMovies: React.FC = () => {
|
||||
const settings = useSettings();
|
||||
const { locale } = useContext(LanguageContext);
|
||||
const { data, error, size, setSize } = useSWRInfinite<SearchResult>(
|
||||
(pageIndex: number, previousPageData: SearchResult | null) => {
|
||||
@@ -45,11 +48,20 @@ const DiscoverMovies: React.FC = () => {
|
||||
return <div>{error}</div>;
|
||||
}
|
||||
|
||||
const titles = data?.reduce(
|
||||
let titles = (data ?? []).reduce(
|
||||
(a, v) => [...a, ...v.results],
|
||||
[] as MovieResult[]
|
||||
);
|
||||
|
||||
if (settings.currentSettings.hideAvailable) {
|
||||
titles = titles.filter(
|
||||
(i) =>
|
||||
(i.mediaType === 'movie' || i.mediaType === 'tv') &&
|
||||
i.mediaInfo?.status !== MediaStatus.AVAILABLE &&
|
||||
i.mediaInfo?.status !== MediaStatus.PARTIALLY_AVAILABLE
|
||||
);
|
||||
}
|
||||
|
||||
const isEmpty = !isLoadingInitialData && titles?.length === 0;
|
||||
const isReachingEnd =
|
||||
isEmpty || (data && data[data.length - 1]?.results.length < 20);
|
||||
|
@@ -5,6 +5,8 @@ import ListView from '../Common/ListView';
|
||||
import { defineMessages, FormattedMessage } from 'react-intl';
|
||||
import { LanguageContext } from '../../context/LanguageContext';
|
||||
import Header from '../Common/Header';
|
||||
import useSettings from '../../hooks/useSettings';
|
||||
import { MediaStatus } from '../../../server/constants/media';
|
||||
|
||||
const messages = defineMessages({
|
||||
discovertv: 'Popular Series',
|
||||
@@ -18,6 +20,7 @@ interface SearchResult {
|
||||
}
|
||||
|
||||
const DiscoverTv: React.FC = () => {
|
||||
const settings = useSettings();
|
||||
const { locale } = useContext(LanguageContext);
|
||||
const { data, error, size, setSize } = useSWRInfinite<SearchResult>(
|
||||
(pageIndex: number, previousPageData: SearchResult | null) => {
|
||||
@@ -45,7 +48,18 @@ const DiscoverTv: React.FC = () => {
|
||||
return <div>{error}</div>;
|
||||
}
|
||||
|
||||
const titles = data?.reduce((a, v) => [...a, ...v.results], [] as TvResult[]);
|
||||
let titles = (data ?? []).reduce(
|
||||
(a, v) => [...a, ...v.results],
|
||||
[] as TvResult[]
|
||||
);
|
||||
|
||||
if (settings.currentSettings.hideAvailable) {
|
||||
titles = titles.filter(
|
||||
(i) =>
|
||||
i.mediaInfo?.status !== MediaStatus.AVAILABLE &&
|
||||
i.mediaInfo?.status !== MediaStatus.PARTIALLY_AVAILABLE
|
||||
);
|
||||
}
|
||||
|
||||
const isEmpty = !isLoadingInitialData && titles?.length === 0;
|
||||
const isReachingEnd =
|
||||
|
@@ -9,6 +9,8 @@ import ListView from '../Common/ListView';
|
||||
import { LanguageContext } from '../../context/LanguageContext';
|
||||
import { defineMessages, FormattedMessage } from 'react-intl';
|
||||
import Header from '../Common/Header';
|
||||
import useSettings from '../../hooks/useSettings';
|
||||
import { MediaStatus } from '../../../server/constants/media';
|
||||
|
||||
const messages = defineMessages({
|
||||
trending: 'Trending',
|
||||
@@ -22,6 +24,7 @@ interface SearchResult {
|
||||
}
|
||||
|
||||
const Trending: React.FC = () => {
|
||||
const settings = useSettings();
|
||||
const { locale } = useContext(LanguageContext);
|
||||
const { data, error, size, setSize } = useSWRInfinite<SearchResult>(
|
||||
(pageIndex: number, previousPageData: SearchResult | null) => {
|
||||
@@ -51,11 +54,20 @@ const Trending: React.FC = () => {
|
||||
return <div>{error}</div>;
|
||||
}
|
||||
|
||||
const titles = data?.reduce(
|
||||
let titles = (data ?? []).reduce(
|
||||
(a, v) => [...a, ...v.results],
|
||||
[] as (MovieResult | TvResult | PersonResult)[]
|
||||
);
|
||||
|
||||
if (settings.currentSettings.hideAvailable) {
|
||||
titles = titles.filter(
|
||||
(i) =>
|
||||
(i.mediaType === 'movie' || i.mediaType === 'tv') &&
|
||||
i.mediaInfo?.status !== MediaStatus.AVAILABLE &&
|
||||
i.mediaInfo?.status !== MediaStatus.PARTIALLY_AVAILABLE
|
||||
);
|
||||
}
|
||||
|
||||
const isEmpty = !isLoadingInitialData && titles?.length === 0;
|
||||
const isReachingEnd =
|
||||
isEmpty || (data && data[data.length - 1]?.results.length < 20);
|
||||
|
@@ -5,6 +5,8 @@ import ListView from '../Common/ListView';
|
||||
import { LanguageContext } from '../../context/LanguageContext';
|
||||
import { defineMessages, FormattedMessage } from 'react-intl';
|
||||
import Header from '../Common/Header';
|
||||
import useSettings from '../../hooks/useSettings';
|
||||
import { MediaStatus } from '../../../server/constants/media';
|
||||
|
||||
const messages = defineMessages({
|
||||
upcomingmovies: 'Upcoming Movies',
|
||||
@@ -18,6 +20,7 @@ interface SearchResult {
|
||||
}
|
||||
|
||||
const UpcomingMovies: React.FC = () => {
|
||||
const settings = useSettings();
|
||||
const { locale } = useContext(LanguageContext);
|
||||
const { data, error, size, setSize } = useSWRInfinite<SearchResult>(
|
||||
(pageIndex: number, previousPageData: SearchResult | null) => {
|
||||
@@ -47,11 +50,19 @@ const UpcomingMovies: React.FC = () => {
|
||||
return <div>{error}</div>;
|
||||
}
|
||||
|
||||
const titles = data?.reduce(
|
||||
let titles = (data ?? []).reduce(
|
||||
(a, v) => [...a, ...v.results],
|
||||
[] as MovieResult[]
|
||||
);
|
||||
|
||||
if (settings.currentSettings.hideAvailable) {
|
||||
titles = titles.filter(
|
||||
(i) =>
|
||||
i.mediaInfo?.status !== MediaStatus.AVAILABLE &&
|
||||
i.mediaInfo?.status !== MediaStatus.PARTIALLY_AVAILABLE
|
||||
);
|
||||
}
|
||||
|
||||
const isEmpty = !isLoadingInitialData && titles?.length === 0;
|
||||
const isReachingEnd =
|
||||
isEmpty || (data && data[data.length - 1]?.results.length < 20);
|
||||
|
@@ -1,12 +1,14 @@
|
||||
import Link from 'next/link';
|
||||
import React, { useContext } from 'react';
|
||||
import React, { useContext, useEffect } from 'react';
|
||||
import { useSWRInfinite } from 'swr';
|
||||
import { MediaStatus } from '../../../server/constants/media';
|
||||
import type {
|
||||
MovieResult,
|
||||
PersonResult,
|
||||
TvResult,
|
||||
} from '../../../server/models/Search';
|
||||
import { LanguageContext } from '../../context/LanguageContext';
|
||||
import useSettings from '../../hooks/useSettings';
|
||||
import PersonCard from '../PersonCard';
|
||||
import Slider from '../Slider';
|
||||
import TitleCard from '../TitleCard';
|
||||
@@ -34,8 +36,9 @@ const MediaSlider: React.FC<MediaSliderProps> = ({
|
||||
sliderKey,
|
||||
hideWhenEmpty = false,
|
||||
}) => {
|
||||
const settings = useSettings();
|
||||
const { locale } = useContext(LanguageContext);
|
||||
const { data, error } = useSWRInfinite<MixedResult>(
|
||||
const { data, error, setSize, size } = useSWRInfinite<MixedResult>(
|
||||
(pageIndex: number, previousPageData: MixedResult | null) => {
|
||||
if (previousPageData && pageIndex + 1 > previousPageData.totalPages) {
|
||||
return null;
|
||||
@@ -48,15 +51,34 @@ const MediaSlider: React.FC<MediaSliderProps> = ({
|
||||
}
|
||||
);
|
||||
|
||||
if (hideWhenEmpty && (data?.[0].results ?? []).length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const titles = (data ?? []).reduce(
|
||||
let titles = (data ?? []).reduce(
|
||||
(a, v) => [...a, ...v.results],
|
||||
[] as (MovieResult | TvResult | PersonResult)[]
|
||||
);
|
||||
|
||||
if (settings.currentSettings.hideAvailable) {
|
||||
titles = titles.filter(
|
||||
(i) =>
|
||||
(i.mediaType === 'movie' || i.mediaType === 'tv') &&
|
||||
i.mediaInfo?.status !== MediaStatus.AVAILABLE &&
|
||||
i.mediaInfo?.status !== MediaStatus.PARTIALLY_AVAILABLE
|
||||
);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
titles.length < 24 &&
|
||||
size < 5 &&
|
||||
(data?.[0]?.totalResults ?? 0) > size * 20
|
||||
) {
|
||||
setSize(size + 1);
|
||||
}
|
||||
}, [titles, setSize, size, data]);
|
||||
|
||||
if (hideWhenEmpty && (data?.[0].results ?? []).length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const finalTitles = titles.slice(0, 20).map((title) => {
|
||||
switch (title.mediaType) {
|
||||
case 'movie':
|
||||
|
@@ -7,6 +7,8 @@ import Header from '../Common/Header';
|
||||
import type { MovieDetails } from '../../../server/models/Movie';
|
||||
import { LanguageContext } from '../../context/LanguageContext';
|
||||
import { defineMessages, useIntl, FormattedMessage } from 'react-intl';
|
||||
import useSettings from '../../hooks/useSettings';
|
||||
import { MediaStatus } from '../../../server/constants/media';
|
||||
|
||||
const messages = defineMessages({
|
||||
recommendations: 'Recommendations',
|
||||
@@ -21,6 +23,7 @@ interface SearchResult {
|
||||
}
|
||||
|
||||
const MovieRecommendations: React.FC = () => {
|
||||
const settings = useSettings();
|
||||
const intl = useIntl();
|
||||
const router = useRouter();
|
||||
const { locale } = useContext(LanguageContext);
|
||||
@@ -55,11 +58,19 @@ const MovieRecommendations: React.FC = () => {
|
||||
return <div>{error}</div>;
|
||||
}
|
||||
|
||||
const titles = data?.reduce(
|
||||
let titles = (data ?? []).reduce(
|
||||
(a, v) => [...a, ...v.results],
|
||||
[] as MovieResult[]
|
||||
);
|
||||
|
||||
if (settings.currentSettings.hideAvailable) {
|
||||
titles = titles.filter(
|
||||
(i) =>
|
||||
i.mediaInfo?.status !== MediaStatus.AVAILABLE &&
|
||||
i.mediaInfo?.status !== MediaStatus.PARTIALLY_AVAILABLE
|
||||
);
|
||||
}
|
||||
|
||||
const isEmpty = !isLoadingInitialData && titles?.length === 0;
|
||||
const isReachingEnd =
|
||||
isEmpty || (data && data[data.length - 1]?.results.length < 20);
|
||||
|
@@ -7,6 +7,8 @@ import Header from '../Common/Header';
|
||||
import { LanguageContext } from '../../context/LanguageContext';
|
||||
import type { MovieDetails } from '../../../server/models/Movie';
|
||||
import { defineMessages, useIntl, FormattedMessage } from 'react-intl';
|
||||
import { MediaStatus } from '../../../server/constants/media';
|
||||
import useSettings from '../../hooks/useSettings';
|
||||
|
||||
const messages = defineMessages({
|
||||
similar: 'Similar Titles',
|
||||
@@ -21,6 +23,7 @@ interface SearchResult {
|
||||
}
|
||||
|
||||
const MovieSimilar: React.FC = () => {
|
||||
const settings = useSettings();
|
||||
const router = useRouter();
|
||||
const intl = useIntl();
|
||||
const { locale } = useContext(LanguageContext);
|
||||
@@ -55,11 +58,19 @@ const MovieSimilar: React.FC = () => {
|
||||
return <div>{error}</div>;
|
||||
}
|
||||
|
||||
const titles = data?.reduce(
|
||||
let titles = (data ?? []).reduce(
|
||||
(a, v) => [...a, ...v.results],
|
||||
[] as MovieResult[]
|
||||
);
|
||||
|
||||
if (settings.currentSettings.hideAvailable) {
|
||||
titles = titles.filter(
|
||||
(i) =>
|
||||
i.mediaInfo?.status !== MediaStatus.AVAILABLE &&
|
||||
i.mediaInfo?.status !== MediaStatus.PARTIALLY_AVAILABLE
|
||||
);
|
||||
}
|
||||
|
||||
const isEmpty = !isLoadingInitialData && titles?.length === 0;
|
||||
const isReachingEnd =
|
||||
isEmpty || (data && data[data.length - 1]?.results.length < 20);
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import axios from 'axios';
|
||||
import React, { useContext, useState } from 'react';
|
||||
import React, { useState } from 'react';
|
||||
import { defineMessages, useIntl } from 'react-intl';
|
||||
import {
|
||||
MediaRequestStatus,
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
} from '../../../server/constants/media';
|
||||
import Media from '../../../server/entity/Media';
|
||||
import { MediaRequest } from '../../../server/entity/MediaRequest';
|
||||
import { SettingsContext } from '../../context/SettingsContext';
|
||||
import useSettings from '../../hooks/useSettings';
|
||||
import { Permission, useUser } from '../../hooks/useUser';
|
||||
import ButtonWithDropdown from '../Common/ButtonWithDropdown';
|
||||
import RequestModal from '../RequestModal';
|
||||
@@ -58,7 +58,7 @@ const RequestButton: React.FC<RequestButtonProps> = ({
|
||||
is4kShowComplete = false,
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
const settings = useContext(SettingsContext);
|
||||
const settings = useSettings();
|
||||
const { hasPermission } = useUser();
|
||||
const [showRequestModal, setShowRequestModal] = useState(false);
|
||||
const [showRequest4kModal, setShowRequest4kModal] = useState(false);
|
||||
|
@@ -11,6 +11,8 @@ import { useUser, Permission } from '../../hooks/useUser';
|
||||
import { useToasts } from 'react-toast-notifications';
|
||||
import { messages as permissionMessages } from '../UserEdit';
|
||||
import PermissionOption, { PermissionItem } from '../PermissionOption';
|
||||
import Badge from '../Common/Badge';
|
||||
import globalMessages from '../../i18n/globalMessages';
|
||||
|
||||
const messages = defineMessages({
|
||||
generalsettings: 'General Settings',
|
||||
@@ -25,6 +27,7 @@ const messages = defineMessages({
|
||||
toastSettingsSuccess: 'Settings saved.',
|
||||
toastSettingsFailure: 'Something went wrong saving settings.',
|
||||
defaultPermissions: 'Default User Permissions',
|
||||
hideAvailable: 'Hide available media',
|
||||
});
|
||||
|
||||
const SettingsMain: React.FC = () => {
|
||||
@@ -166,6 +169,7 @@ const SettingsMain: React.FC = () => {
|
||||
initialValues={{
|
||||
applicationUrl: data?.applicationUrl,
|
||||
defaultPermissions: data?.defaultPermissions ?? 0,
|
||||
hideAvailable: data?.hideAvailable,
|
||||
}}
|
||||
enableReinitialize
|
||||
onSubmit={async (values) => {
|
||||
@@ -173,6 +177,7 @@ const SettingsMain: React.FC = () => {
|
||||
await axios.post('/api/v1/settings/main', {
|
||||
applicationUrl: values.applicationUrl,
|
||||
defaultPermissions: values.defaultPermissions,
|
||||
hideAvailable: values.hideAvailable,
|
||||
});
|
||||
|
||||
addToast(intl.formatMessage(messages.toastSettingsSuccess), {
|
||||
@@ -256,6 +261,30 @@ const SettingsMain: React.FC = () => {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-6 sm:mt-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:items-start sm:border-t sm:border-gray-800">
|
||||
<label
|
||||
htmlFor="name"
|
||||
className="block text-sm font-medium leading-5 text-gray-400 sm:mt-px"
|
||||
>
|
||||
<span className="mr-2">
|
||||
{intl.formatMessage(messages.hideAvailable)}
|
||||
</span>
|
||||
<Badge badgeType="warning">
|
||||
{intl.formatMessage(globalMessages.experimental)}
|
||||
</Badge>
|
||||
</label>
|
||||
<div className="mt-1 sm:mt-0 sm:col-span-2">
|
||||
<Field
|
||||
type="checkbox"
|
||||
id="hideAvailable"
|
||||
name="hideAvailable"
|
||||
onChange={() => {
|
||||
setFieldValue('hideAvailable', !values.hideAvailable);
|
||||
}}
|
||||
className="w-6 h-6 text-indigo-600 transition duration-150 ease-in-out rounded-md form-checkbox"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-6">
|
||||
<div role="group" aria-labelledby="label-permissions">
|
||||
<div className="sm:grid sm:grid-cols-3 sm:gap-4 sm:items-baseline">
|
||||
|
@@ -7,6 +7,8 @@ import { LanguageContext } from '../../context/LanguageContext';
|
||||
import Header from '../Common/Header';
|
||||
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
||||
import { TvDetails } from '../../../server/models/Tv';
|
||||
import { MediaStatus } from '../../../server/constants/media';
|
||||
import useSettings from '../../hooks/useSettings';
|
||||
|
||||
const messages = defineMessages({
|
||||
recommendations: 'Recommendations',
|
||||
@@ -21,6 +23,7 @@ interface SearchResult {
|
||||
}
|
||||
|
||||
const TvRecommendations: React.FC = () => {
|
||||
const settings = useSettings();
|
||||
const router = useRouter();
|
||||
const intl = useIntl();
|
||||
const { locale } = useContext(LanguageContext);
|
||||
@@ -55,7 +58,18 @@ const TvRecommendations: React.FC = () => {
|
||||
return <div>{error}</div>;
|
||||
}
|
||||
|
||||
const titles = data?.reduce((a, v) => [...a, ...v.results], [] as TvResult[]);
|
||||
let titles = (data ?? []).reduce(
|
||||
(a, v) => [...a, ...v.results],
|
||||
[] as TvResult[]
|
||||
);
|
||||
|
||||
if (settings.currentSettings.hideAvailable) {
|
||||
titles = titles.filter(
|
||||
(i) =>
|
||||
i.mediaInfo?.status !== MediaStatus.AVAILABLE &&
|
||||
i.mediaInfo?.status !== MediaStatus.PARTIALLY_AVAILABLE
|
||||
);
|
||||
}
|
||||
|
||||
const isEmpty = !isLoadingInitialData && titles?.length === 0;
|
||||
const isReachingEnd =
|
||||
|
@@ -7,6 +7,8 @@ import { LanguageContext } from '../../context/LanguageContext';
|
||||
import { useIntl, defineMessages, FormattedMessage } from 'react-intl';
|
||||
import type { TvDetails } from '../../../server/models/Tv';
|
||||
import Header from '../Common/Header';
|
||||
import { MediaStatus } from '../../../server/constants/media';
|
||||
import useSettings from '../../hooks/useSettings';
|
||||
|
||||
const messages = defineMessages({
|
||||
similar: 'Similar Series',
|
||||
@@ -21,6 +23,7 @@ interface SearchResult {
|
||||
}
|
||||
|
||||
const TvSimilar: React.FC = () => {
|
||||
const settings = useSettings();
|
||||
const router = useRouter();
|
||||
const intl = useIntl();
|
||||
const { locale } = useContext(LanguageContext);
|
||||
@@ -55,11 +58,19 @@ const TvSimilar: React.FC = () => {
|
||||
return <div>{error}</div>;
|
||||
}
|
||||
|
||||
const titles = data?.reduce(
|
||||
let titles = (data ?? []).reduce(
|
||||
(a, v) => [...a, ...v.results],
|
||||
[] as MovieResult[]
|
||||
);
|
||||
|
||||
if (settings.currentSettings.hideAvailable) {
|
||||
titles = titles.filter(
|
||||
(i) =>
|
||||
i.mediaInfo?.status !== MediaStatus.AVAILABLE &&
|
||||
i.mediaInfo?.status !== MediaStatus.PARTIALLY_AVAILABLE
|
||||
);
|
||||
}
|
||||
|
||||
const isEmpty = !isLoadingInitialData && titles?.length === 0;
|
||||
const isReachingEnd =
|
||||
isEmpty || (data && data[data.length - 1]?.results.length < 20);
|
||||
|
@@ -2,7 +2,7 @@ import React from 'react';
|
||||
import { PublicSettingsResponse } from '../../server/interfaces/api/settingsInterfaces';
|
||||
import useSWR from 'swr';
|
||||
|
||||
interface SettingsContextProps {
|
||||
export interface SettingsContextProps {
|
||||
currentSettings: PublicSettingsResponse;
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ const defaultSettings = {
|
||||
initialized: false,
|
||||
movie4kEnabled: false,
|
||||
series4kEnabled: false,
|
||||
hideAvailable: false,
|
||||
};
|
||||
|
||||
export const SettingsContext = React.createContext<SettingsContextProps>({
|
||||
|
13
src/hooks/useSettings.ts
Normal file
13
src/hooks/useSettings.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { useContext } from 'react';
|
||||
import {
|
||||
SettingsContext,
|
||||
SettingsContextProps,
|
||||
} from '../context/SettingsContext';
|
||||
|
||||
const useSettings = (): SettingsContextProps => {
|
||||
const settings = useContext(SettingsContext);
|
||||
|
||||
return settings;
|
||||
};
|
||||
|
||||
export default useSettings;
|
@@ -21,6 +21,7 @@ const globalMessages = defineMessages({
|
||||
deleting: 'Deleting…',
|
||||
close: 'Close',
|
||||
edit: 'Edit',
|
||||
experimental: 'Experimental',
|
||||
});
|
||||
|
||||
export default globalMessages;
|
||||
|
@@ -351,6 +351,7 @@
|
||||
"components.Settings.edit": "Edit",
|
||||
"components.Settings.generalsettings": "General Settings",
|
||||
"components.Settings.generalsettingsDescription": "These are settings related to general Overseerr configuration.",
|
||||
"components.Settings.hideAvailable": "Hide available media",
|
||||
"components.Settings.hostname": "Hostname/IP",
|
||||
"components.Settings.jobname": "Job Name",
|
||||
"components.Settings.librariesRemaining": "Libraries Remaining: {count}",
|
||||
@@ -517,6 +518,7 @@
|
||||
"i18n.delete": "Delete",
|
||||
"i18n.deleting": "Deleting…",
|
||||
"i18n.edit": "Edit",
|
||||
"i18n.experimental": "Experimental",
|
||||
"i18n.failed": "Failed",
|
||||
"i18n.movies": "Movies",
|
||||
"i18n.partiallyavailable": "Partially Available",
|
||||
|
@@ -135,6 +135,7 @@ CoreApp.getInitialProps = async (initialProps) => {
|
||||
let user = undefined;
|
||||
let currentSettings: PublicSettingsResponse = {
|
||||
initialized: false,
|
||||
hideAvailable: false,
|
||||
movie4kEnabled: false,
|
||||
series4kEnabled: false,
|
||||
};
|
||||
|
Reference in New Issue
Block a user