Skip to content

Commit

Permalink
Plex settings: use the proper endpoints instead of patching settings (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
harshithmohan authored Sep 14, 2024
1 parent 7641e15 commit bc64b77
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 22 deletions.
42 changes: 23 additions & 19 deletions src/components/Settings/MetadataSitesSettings/PlexSettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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);
Expand All @@ -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<HTMLInputElement>) => {
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 (
Expand All @@ -177,9 +180,9 @@ const PlexSettings = () => {
</SelectSmall>
<AnimateHeight height={isAuthenticated && serversQuery.isSuccess && !!serverId ? 'auto' : 0}>
<div className="mb-2">Available Libraries</div>
<div className="flex flex-col gap-y-2 rounded-lg bg-panel-input px-4 py-2">
{librariesQuery.isPending && (
<div className="flex justify-center text-panel-text-primary">
<div className="relative flex min-h-10 flex-col gap-y-2 rounded-lg bg-panel-input px-4 py-2">
{(librariesQuery.isPending || changeLibraryPending) && (
<div className="absolute inset-0 flex items-center justify-center text-panel-text-primary">
<Icon path={mdiLoading} size={1} spin />
</div>
)}
Expand All @@ -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')}
/>
),
)}
Expand Down
16 changes: 16 additions & 0 deletions src/core/react-query/plex/mutations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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),
});
2 changes: 1 addition & 1 deletion src/core/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
7 changes: 5 additions & 2 deletions src/pages/settings/SettingsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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;
}
Expand All @@ -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);
Expand Down

0 comments on commit bc64b77

Please sign in to comment.