From 52757c253615dcd18cbada69565a395552268b45 Mon Sep 17 00:00:00 2001 From: Harshith Mohan <26010946+harshithmohan@users.noreply.github.com> Date: Sat, 14 Sep 2024 17:05:23 +0530 Subject: [PATCH] Plex settings: use the proper endpoints instead of patching settings --- .../MetadataSitesSettings/PlexSettings.tsx | 42 ++++++++++--------- src/core/react-query/plex/mutations.ts | 16 +++++++ src/core/util.ts | 2 +- src/pages/settings/SettingsPage.tsx | 7 +++- 4 files changed, 45 insertions(+), 22 deletions(-) diff --git a/src/components/Settings/MetadataSitesSettings/PlexSettings.tsx b/src/components/Settings/MetadataSitesSettings/PlexSettings.tsx index 3479e2e68..73dffb722 100644 --- a/src/components/Settings/MetadataSitesSettings/PlexSettings.tsx +++ b/src/components/Settings/MetadataSitesSettings/PlexSettings.tsx @@ -3,14 +3,17 @@ import AnimateHeight from 'react-animate-height'; import { mdiLoading } from '@mdi/js'; import { Icon } from '@mdi/react'; import cx from 'classnames'; -import { produce } from 'immer'; import { map, pull, toNumber } from 'lodash'; import Button from '@/components/Input/Button'; import Checkbox from '@/components/Input/Checkbox'; import SelectSmall from '@/components/Input/SelectSmall'; import toast from '@/components/Toast'; -import { useInvalidatePlexTokenMutation } from '@/core/react-query/plex/mutations'; +import { + useChangePlexLibrariesMutation, + useChangePlexServerMutation, + useInvalidatePlexTokenMutation, +} from '@/core/react-query/plex/mutations'; import { usePlexLibrariesQuery, usePlexLoginUrlQuery, @@ -116,16 +119,16 @@ const PlexLinkButton = () => { }; const PlexSettings = () => { - const { newSettings, setNewSettings } = useSettingsContext(); + const { newSettings } = useSettingsContext(); const { Plex: plexSettings } = newSettings; const [serverId, setServerId] = useState(''); - const settings = useSettingsQuery().data; const isAuthenticated = usePlexStatusQuery().data; const serversQuery = usePlexServersQuery(isAuthenticated); - const librariesQuery = usePlexLibrariesQuery(isAuthenticated && serversQuery.isSuccess && !!serverId); - const { mutate: patchSettings } = usePatchSettingsMutation(); + const librariesQuery = usePlexLibrariesQuery(isAuthenticated && serversQuery.isSuccess && !!plexSettings.Server); + const { mutate: changeServer } = useChangePlexServerMutation(); + const { isPending: changeLibraryPending, mutate: changeLibraries } = useChangePlexLibrariesMutation(); useEffect(() => { if (plexSettings.Server) setServerId(plexSettings.Server); @@ -136,23 +139,23 @@ const PlexSettings = () => { // Optimistic update setServerId(event.target.value); - // We need to save it without pressing the save button to reload libraries. - patchSettings({ newSettings: { ...settings, Plex: { ...plexSettings, Server: event.target.value } } }, { - onSuccess: () => { - invalidateQueries(['plex', 'libraries']); - }, + // Revert optimistic update if save fails + changeServer(event.target.value, { + onSuccess: () => invalidateQueries(['settings']), + onError: () => setServerId(plexSettings.Server), }); }); const handleLibraryChange = useEventCallback((event: React.ChangeEvent) => { const key = toNumber(event.target.id); - const libraries = produce(plexSettings.Libraries, (draftState) => { - if (event.target.checked) draftState.push(key); - else pull(draftState, key); - }); + const newLibraries = plexSettings.Libraries.slice(); + if (event.target.checked) newLibraries.push(key); + else pull(newLibraries, key); - setNewSettings({ ...newSettings, Plex: { ...plexSettings, Libraries: libraries } }); + changeLibraries(newLibraries, { + onSuccess: () => invalidateQueries(['settings']), + }); }); return ( @@ -177,9 +180,9 @@ const PlexSettings = () => {
Available Libraries
-
- {librariesQuery.isPending && ( -
+
+ {(librariesQuery.isPending || changeLibraryPending) && ( +
)} @@ -201,6 +204,7 @@ const PlexSettings = () => { isChecked={newSettings.Plex.Libraries.includes(library.Key)} onChange={handleLibraryChange} key={library.Key} + className={cx(changeLibraryPending && 'pointer-events-none opacity-65')} /> ), )} diff --git a/src/core/react-query/plex/mutations.ts b/src/core/react-query/plex/mutations.ts index d7434f307..9dd1ddf46 100644 --- a/src/core/react-query/plex/mutations.ts +++ b/src/core/react-query/plex/mutations.ts @@ -8,3 +8,19 @@ export const useInvalidatePlexTokenMutation = () => mutationFn: () => axios.get('token/invalidate'), onSuccess: () => queryClient.resetQueries({ queryKey: ['plex', 'status'] }), }); + +export const useChangePlexServerMutation = () => + useMutation({ + mutationFn: (serverId: string) => + axios.post( + 'server', + serverId, + { headers: { 'Content-Type': 'application/json' } }, + ), + onSuccess: () => queryClient.resetQueries({ queryKey: ['plex', 'libraries'] }), + }); + +export const useChangePlexLibrariesMutation = () => + useMutation({ + mutationFn: (libraries: number[]) => axios.post('libraries', libraries), + }); diff --git a/src/core/util.ts b/src/core/util.ts index d34ddb19a..c7f3452b3 100644 --- a/src/core/util.ts +++ b/src/core/util.ts @@ -29,7 +29,7 @@ export function isDebug() { return DEV; } -export const minimumSupportedServerVersion = '4.2.2.152'; +export const minimumSupportedServerVersion = '4.2.2.157'; export const parseServerVersion = (version: string) => { const semverVersion = semver.coerce(version)?.raw; diff --git a/src/pages/settings/SettingsPage.tsx b/src/pages/settings/SettingsPage.tsx index a0b1176bc..e4924015e 100644 --- a/src/pages/settings/SettingsPage.tsx +++ b/src/pages/settings/SettingsPage.tsx @@ -7,6 +7,7 @@ import useMeasure from 'react-use-measure'; import { mdiLoading } from '@mdi/js'; import { Icon } from '@mdi/react'; import { isEqual } from 'lodash'; +import { useDebounceValue } from 'usehooks-ts'; import Button from '@/components/Input/Button'; import toast from '@/components/Toast'; @@ -56,9 +57,11 @@ function SettingsPage() { }, [newSettings, settings, settingsQuery.isSuccess], ); + const [debouncedUnsavedChanges] = useDebounceValue(unsavedChanges, 100); + // Use debounced value for unsaved changes to avoid flashing the toast for certain changes useEffect(() => { - if (!unsavedChanges) { + if (!debouncedUnsavedChanges) { if (toastId.current) toast.dismiss(toastId.current); return; } @@ -68,7 +71,7 @@ function SettingsPage() { 'Please save before leaving this page.', { autoClose: false, position: 'top-right' }, ); - }, [unsavedChanges]); + }, [debouncedUnsavedChanges]); useEffect(() => () => { if (toastId.current) toast.dismiss(toastId.current);