mirror of
https://github.com/jeffvli/feishin.git
synced 2026-06-17 00:44:23 +02:00
add skip to duplicates to playlist ctx menu - persist value
This commit is contained in:
@@ -4,6 +4,8 @@ import Fuse from 'fuse.js';
|
|||||||
import { useCallback, useMemo, useState } from 'react';
|
import { useCallback, useMemo, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
|
import { api } from '/@/renderer/api';
|
||||||
|
import { queryKeys } from '/@/renderer/api/query-keys';
|
||||||
import {
|
import {
|
||||||
getAlbumArtistSongsById,
|
getAlbumArtistSongsById,
|
||||||
getAlbumSongsById,
|
getAlbumSongsById,
|
||||||
@@ -15,11 +17,14 @@ import { playlistsQueries } from '/@/renderer/features/playlists/api/playlists-a
|
|||||||
import { useRecentPlaylists } from '/@/renderer/features/playlists/hooks/use-recent-playlists';
|
import { useRecentPlaylists } from '/@/renderer/features/playlists/hooks/use-recent-playlists';
|
||||||
import { useAddToPlaylist } from '/@/renderer/features/playlists/mutations/add-to-playlist-mutation';
|
import { useAddToPlaylist } from '/@/renderer/features/playlists/mutations/add-to-playlist-mutation';
|
||||||
import { useCurrentServer, useCurrentServerId } from '/@/renderer/store';
|
import { useCurrentServer, useCurrentServerId } from '/@/renderer/store';
|
||||||
|
import { Checkbox } from '/@/shared/components/checkbox/checkbox';
|
||||||
import { ContextMenu } from '/@/shared/components/context-menu/context-menu';
|
import { ContextMenu } from '/@/shared/components/context-menu/context-menu';
|
||||||
import { Icon } from '/@/shared/components/icon/icon';
|
import { Icon } from '/@/shared/components/icon/icon';
|
||||||
import { Spinner } from '/@/shared/components/spinner/spinner';
|
import { Spinner } from '/@/shared/components/spinner/spinner';
|
||||||
import { TextInput } from '/@/shared/components/text-input/text-input';
|
import { TextInput } from '/@/shared/components/text-input/text-input';
|
||||||
import { toast } from '/@/shared/components/toast/toast';
|
import { toast } from '/@/shared/components/toast/toast';
|
||||||
|
import { Tooltip } from '/@/shared/components/tooltip/tooltip';
|
||||||
|
import { useLocalStorage } from '/@/shared/hooks/use-local-storage';
|
||||||
import { LibraryItem, PlaylistListSort, SortOrder } from '/@/shared/types/domain-types';
|
import { LibraryItem, PlaylistListSort, SortOrder } from '/@/shared/types/domain-types';
|
||||||
|
|
||||||
interface AddToPlaylistActionProps {
|
interface AddToPlaylistActionProps {
|
||||||
@@ -33,6 +38,10 @@ export const AddToPlaylistAction = ({ items, itemType }: AddToPlaylistActionProp
|
|||||||
const serverId = useCurrentServerId();
|
const serverId = useCurrentServerId();
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
const [searchTerm, setSearchTerm] = useState('');
|
const [searchTerm, setSearchTerm] = useState('');
|
||||||
|
const [skipDuplicates, setSkipDuplicates] = useLocalStorage({
|
||||||
|
defaultValue: true,
|
||||||
|
key: 'playlist-skip-duplicate',
|
||||||
|
});
|
||||||
const addToPlaylistMutation = useAddToPlaylist({});
|
const addToPlaylistMutation = useAddToPlaylist({});
|
||||||
|
|
||||||
const playlistsQuery = useQuery(
|
const playlistsQuery = useQuery(
|
||||||
@@ -193,8 +202,47 @@ export const AddToPlaylistAction = ({ items, itemType }: AddToPlaylistActionProp
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (allSongIds.length === 0) {
|
if (allSongIds.length === 0) {
|
||||||
toast.error({
|
toast.warn({
|
||||||
message: t('error.noItemsSelected', { postProcess: 'sentenceCase' }),
|
message: t('common.noResultsFromQuery', { postProcess: 'sentenceCase' }),
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let songsToAdd: string[] = allSongIds;
|
||||||
|
|
||||||
|
if (skipDuplicates) {
|
||||||
|
const queryKey = queryKeys.playlists.songList(serverId, playlistId);
|
||||||
|
|
||||||
|
const playlistSongsRes = await queryClient.fetchQuery({
|
||||||
|
queryFn: ({ signal }) => {
|
||||||
|
return api.controller.getPlaylistSongList({
|
||||||
|
apiClientProps: {
|
||||||
|
serverId,
|
||||||
|
signal,
|
||||||
|
},
|
||||||
|
query: {
|
||||||
|
id: playlistId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
queryKey,
|
||||||
|
});
|
||||||
|
|
||||||
|
const playlistSongIds = playlistSongsRes?.items?.map((song) => song.id);
|
||||||
|
const uniqueSongIds: string[] = [];
|
||||||
|
|
||||||
|
for (const songId of allSongIds) {
|
||||||
|
if (!playlistSongIds?.includes(songId)) {
|
||||||
|
uniqueSongIds.push(songId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
songsToAdd = uniqueSongIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (songsToAdd.length === 0) {
|
||||||
|
toast.warn({
|
||||||
|
message: t('common.noResultsFromQuery', { postProcess: 'sentenceCase' }),
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -203,7 +251,7 @@ export const AddToPlaylistAction = ({ items, itemType }: AddToPlaylistActionProp
|
|||||||
{
|
{
|
||||||
apiClientProps: { serverId },
|
apiClientProps: { serverId },
|
||||||
body: {
|
body: {
|
||||||
songId: allSongIds,
|
songId: songsToAdd,
|
||||||
},
|
},
|
||||||
query: {
|
query: {
|
||||||
id: playlistId,
|
id: playlistId,
|
||||||
@@ -222,7 +270,7 @@ export const AddToPlaylistAction = ({ items, itemType }: AddToPlaylistActionProp
|
|||||||
|
|
||||||
toast.success({
|
toast.success({
|
||||||
message: t('form.addToPlaylist.success', {
|
message: t('form.addToPlaylist.success', {
|
||||||
message: allSongIds.length,
|
message: songsToAdd.length,
|
||||||
numOfPlaylists: 1,
|
numOfPlaylists: 1,
|
||||||
postProcess: 'sentenceCase',
|
postProcess: 'sentenceCase',
|
||||||
}),
|
}),
|
||||||
@@ -243,7 +291,9 @@ export const AddToPlaylistAction = ({ items, itemType }: AddToPlaylistActionProp
|
|||||||
getSongsByPlaylist,
|
getSongsByPlaylist,
|
||||||
itemType,
|
itemType,
|
||||||
items,
|
items,
|
||||||
|
queryClient,
|
||||||
serverId,
|
serverId,
|
||||||
|
skipDuplicates,
|
||||||
t,
|
t,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
@@ -307,6 +357,24 @@ export const AddToPlaylistAction = ({ items, itemType }: AddToPlaylistActionProp
|
|||||||
onPointerDown={(e) => e.stopPropagation()}
|
onPointerDown={(e) => e.stopPropagation()}
|
||||||
pb="xs"
|
pb="xs"
|
||||||
placeholder={t('common.search', { postProcess: 'sentenceCase' })}
|
placeholder={t('common.search', { postProcess: 'sentenceCase' })}
|
||||||
|
rightSection={
|
||||||
|
<Tooltip
|
||||||
|
label={t('form.addToPlaylist.input', {
|
||||||
|
context: 'skipDuplicates',
|
||||||
|
postProcess: 'titleCase',
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<Checkbox
|
||||||
|
checked={skipDuplicates}
|
||||||
|
onChange={(e) => {
|
||||||
|
setSkipDuplicates(e.target.checked);
|
||||||
|
e.stopPropagation();
|
||||||
|
}}
|
||||||
|
onClick={(e) => e.stopPropagation()}
|
||||||
|
size="sm"
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
}
|
||||||
size="sm"
|
size="sm"
|
||||||
value={searchTerm}
|
value={searchTerm}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ import { TextInput } from '/@/shared/components/text-input/text-input';
|
|||||||
import { Text } from '/@/shared/components/text/text';
|
import { Text } from '/@/shared/components/text/text';
|
||||||
import { toast } from '/@/shared/components/toast/toast';
|
import { toast } from '/@/shared/components/toast/toast';
|
||||||
import { useForm } from '/@/shared/hooks/use-form';
|
import { useForm } from '/@/shared/hooks/use-form';
|
||||||
|
import { useLocalStorage } from '/@/shared/hooks/use-local-storage';
|
||||||
import { Playlist, PlaylistListSort, SortOrder } from '/@/shared/types/domain-types';
|
import { Playlist, PlaylistListSort, SortOrder } from '/@/shared/types/domain-types';
|
||||||
|
|
||||||
export const AddToPlaylistContextModal = ({
|
export const AddToPlaylistContextModal = ({
|
||||||
@@ -61,14 +62,23 @@ export const AddToPlaylistContextModal = ({
|
|||||||
const rowRefs = useRef<(HTMLTableRowElement | null)[]>([]);
|
const rowRefs = useRef<(HTMLTableRowElement | null)[]>([]);
|
||||||
const formRef = useRef<HTMLFormElement>(null);
|
const formRef = useRef<HTMLFormElement>(null);
|
||||||
|
|
||||||
|
const [skipDuplicates, setSkipDuplicates] = useLocalStorage({
|
||||||
|
defaultValue: true,
|
||||||
|
key: 'playlist-skip-duplicate',
|
||||||
|
});
|
||||||
|
|
||||||
const form = useForm({
|
const form = useForm({
|
||||||
initialValues: {
|
initialValues: {
|
||||||
newPlaylists: [] as string[],
|
newPlaylists: [] as string[],
|
||||||
selectedPlaylistIds: initialSelectedIds || [],
|
selectedPlaylistIds: initialSelectedIds || [],
|
||||||
skipDuplicates: true,
|
skipDuplicates: skipDuplicates,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
form.watch('skipDuplicates', (event) => {
|
||||||
|
setSkipDuplicates(event.value);
|
||||||
|
});
|
||||||
|
|
||||||
const addToPlaylistMutation = useAddToPlaylist({});
|
const addToPlaylistMutation = useAddToPlaylist({});
|
||||||
|
|
||||||
const playlistList = useQuery(
|
const playlistList = useQuery(
|
||||||
|
|||||||
Reference in New Issue
Block a user