Lint all files

This commit is contained in:
jeffvli 2023-07-01 19:10:05 -07:00
parent 22af76b4d6
commit 30e52ebb54
334 changed files with 76519 additions and 75932 deletions

View file

@ -4,37 +4,37 @@ import { motion } from 'framer-motion';
import styled from 'styled-components';
interface AnimatedPageProps {
children: ReactNode;
children: ReactNode;
}
const StyledAnimatedPage = styled(motion.main)`
position: relative;
display: flex;
flex-direction: column;
width: 100%;
height: 100%;
overflow: hidden;
position: relative;
display: flex;
flex-direction: column;
width: 100%;
height: 100%;
overflow: hidden;
`;
const variants = {
animate: { opacity: 1 },
exit: { opacity: 0 },
initial: { opacity: 0 },
animate: { opacity: 1 },
exit: { opacity: 0 },
initial: { opacity: 0 },
};
export const AnimatedPage = forwardRef(
({ children }: AnimatedPageProps, ref: Ref<HTMLDivElement>) => {
return (
<StyledAnimatedPage
ref={ref}
animate="animate"
exit="exit"
initial="initial"
transition={{ duration: 0.5, ease: 'anticipate' }}
variants={variants}
>
{children}
</StyledAnimatedPage>
);
},
({ children }: AnimatedPageProps, ref: Ref<HTMLDivElement>) => {
return (
<StyledAnimatedPage
ref={ref}
animate="animate"
exit="exit"
initial="initial"
transition={{ duration: 0.5, ease: 'anticipate' }}
variants={variants}
>
{children}
</StyledAnimatedPage>
);
},
);

View file

@ -3,11 +3,11 @@ import styled from 'styled-components';
import { Paper } from '/@/renderer/components';
const StyledFilterBar = styled(Paper)`
z-index: 1;
padding: 1rem;
box-shadow: 0 5px 15px rgba(0, 0, 0, 65%);
z-index: 1;
padding: 1rem;
box-shadow: 0 5px 15px rgba(0, 0, 0, 65%);
`;
export const FilterBar = ({ children, ...props }: PaperProps) => {
return <StyledFilterBar {...props}>{children}</StyledFilterBar>;
return <StyledFilterBar {...props}>{children}</StyledFilterBar>;
};

View file

@ -5,67 +5,67 @@ import { PlayButton as PlayBtn } from '/@/renderer/features/shared/components/pl
import styled from 'styled-components';
interface LibraryHeaderBarProps {
children: ReactNode;
children: ReactNode;
}
const HeaderContainer = styled.div`
display: flex;
flex-wrap: nowrap;
gap: 1rem;
align-items: center;
width: 100%;
height: 100%;
padding: 0 1rem;
display: flex;
flex-wrap: nowrap;
gap: 1rem;
align-items: center;
width: 100%;
height: 100%;
padding: 0 1rem;
`;
export const LibraryHeaderBar = ({ children }: LibraryHeaderBarProps) => {
return <HeaderContainer>{children}</HeaderContainer>;
return <HeaderContainer>{children}</HeaderContainer>;
};
interface TitleProps {
children: ReactNode;
children: ReactNode;
}
const Title = ({ children }: TitleProps) => {
return (
<TextTitle
order={1}
overflow="hidden"
weight={700}
>
{children}
</TextTitle>
);
return (
<TextTitle
order={1}
overflow="hidden"
weight={700}
>
{children}
</TextTitle>
);
};
interface PlayButtonProps {
onClick: () => void;
onClick: () => void;
}
const PlayButton = ({ onClick }: PlayButtonProps) => {
return (
<Box>
<PlayBtn
h="45px"
w="45px"
onClick={onClick}
/>
</Box>
);
return (
<Box>
<PlayBtn
h="45px"
w="45px"
onClick={onClick}
/>
</Box>
);
};
const Badge = styled(Paper)`
padding: 0.3rem 1rem;
font-weight: 600;
border-radius: 0.3rem;
padding: 0.3rem 1rem;
font-weight: 600;
border-radius: 0.3rem;
`;
interface HeaderBadgeProps extends PaperProps {
isLoading?: boolean;
isLoading?: boolean;
}
const HeaderBadge = ({ children, isLoading, ...props }: HeaderBadgeProps) => {
return <Badge {...props}>{isLoading ? <SpinnerIcon /> : children}</Badge>;
return <Badge {...props}>{isLoading ? <SpinnerIcon /> : children}</Badge>;
};
LibraryHeaderBar.Title = Title;

View file

@ -10,150 +10,151 @@ import { Text, TextTitle } from '/@/renderer/components';
import { useContainerQuery } from '/@/renderer/hooks';
const HeaderContainer = styled.div<{ imageSize: number }>`
position: relative;
display: grid;
grid-auto-columns: 1fr;
grid-template-areas: 'image info';
grid-template-rows: 1fr;
grid-template-columns: ${(props) => props.imageSize + 25}px minmax(0, 1fr);
gap: 0.5rem;
width: 100%;
max-width: 100%;
height: 30vh;
min-height: 340px;
max-height: 500px;
padding: 5rem 2rem 2rem;
position: relative;
display: grid;
grid-auto-columns: 1fr;
grid-template-areas: 'image info';
grid-template-rows: 1fr;
grid-template-columns: ${(props) => props.imageSize + 25}px minmax(0, 1fr);
gap: 0.5rem;
width: 100%;
max-width: 100%;
height: 30vh;
min-height: 340px;
max-height: 500px;
padding: 5rem 2rem 2rem;
`;
const CoverImageWrapper = styled.div`
z-index: 15;
display: flex;
grid-area: image;
align-items: flex-end;
justify-content: center;
height: 100%;
filter: drop-shadow(0 0 8px rgb(0, 0, 0, 50%));
z-index: 15;
display: flex;
grid-area: image;
align-items: flex-end;
justify-content: center;
height: 100%;
filter: drop-shadow(0 0 8px rgb(0, 0, 0, 50%));
`;
const MetadataWrapper = styled.div`
z-index: 15;
display: flex;
flex-direction: column;
grid-area: info;
justify-content: flex-end;
width: 100%;
z-index: 15;
display: flex;
flex-direction: column;
grid-area: info;
justify-content: flex-end;
width: 100%;
`;
const StyledImage = styled(SimpleImg)`
img {
object-fit: cover;
}
img {
object-fit: cover;
}
`;
const BackgroundImage = styled.div<{ background: string }>`
position: absolute;
top: 0;
z-index: 0;
width: 100%;
height: 100%;
background: ${(props) => props.background};
position: absolute;
top: 0;
z-index: 0;
width: 100%;
height: 100%;
background: ${(props) => props.background};
`;
const BackgroundImageOverlay = styled.div`
position: absolute;
top: 0;
left: 0;
z-index: 0;
width: 100%;
height: 100%;
background: linear-gradient(180deg, rgba(25, 26, 28, 5%), var(--main-bg)), var(--background-noise);
position: absolute;
top: 0;
left: 0;
z-index: 0;
width: 100%;
height: 100%;
background: linear-gradient(180deg, rgba(25, 26, 28, 5%), var(--main-bg)),
var(--background-noise);
`;
interface LibraryHeaderProps {
background: string;
children?: ReactNode;
imagePlaceholderUrl?: string | null;
imageUrl?: string | null;
item: { route: string; type: LibraryItem };
title: string;
background: string;
children?: ReactNode;
imagePlaceholderUrl?: string | null;
imageUrl?: string | null;
item: { route: string; type: LibraryItem };
title: string;
}
export const LibraryHeader = forwardRef(
(
{ imageUrl, imagePlaceholderUrl, background, title, item, children }: LibraryHeaderProps,
ref: Ref<HTMLDivElement>,
) => {
const cq = useContainerQuery();
const mergedRef = useMergedRef(ref, cq.ref);
const titleSize = cq.isXl
? '6rem'
: cq.isLg
? '5.5rem'
: cq.isMd
? '5rem'
: cq.isSm
? '4.5rem'
: '3rem';
(
{ imageUrl, imagePlaceholderUrl, background, title, item, children }: LibraryHeaderProps,
ref: Ref<HTMLDivElement>,
) => {
const cq = useContainerQuery();
const mergedRef = useMergedRef(ref, cq.ref);
const titleSize = cq.isXl
? '6rem'
: cq.isLg
? '5.5rem'
: cq.isMd
? '5rem'
: cq.isSm
? '4.5rem'
: '3rem';
const imageSize = cq.isLg ? 250 : cq.isMd ? 225 : cq.isSm ? 200 : 175;
const imageSize = cq.isLg ? 250 : cq.isMd ? 225 : cq.isSm ? 200 : 175;
return (
<HeaderContainer
ref={mergedRef}
imageSize={imageSize}
>
<BackgroundImage background={background} />
<BackgroundImageOverlay />
<CoverImageWrapper>
{imageUrl ? (
<StyledImage
alt="cover"
height={imageSize}
placeholder={imagePlaceholderUrl || 'var(--placeholder-bg)'}
src={imageUrl}
width={imageSize}
/>
) : (
<Center
sx={{
background: 'var(--placeholder-bg)',
borderRadius: 'var(--card-default-radius)',
height: `${imageSize}px`,
width: `${imageSize}px`,
}}
return (
<HeaderContainer
ref={mergedRef}
imageSize={imageSize}
>
<RiAlbumFill
color="var(--placeholder-fg)"
size={35}
/>
</Center>
)}
</CoverImageWrapper>
<MetadataWrapper>
<Group>
<Text
$link
component={Link}
to={item.route}
tt="uppercase"
weight={600}
>
{item.type}
</Text>
</Group>
<TextTitle
lh={1.15}
lineClamp={2}
overflow="hidden"
pb={cq.isXs ? '0' : cq.isSm ? '0.2rem' : '0.36rem'}
sx={{ fontSize: titleSize, overflow: 'hidden' }}
weight={900}
>
{title}
</TextTitle>
{children}
</MetadataWrapper>
</HeaderContainer>
);
},
<BackgroundImage background={background} />
<BackgroundImageOverlay />
<CoverImageWrapper>
{imageUrl ? (
<StyledImage
alt="cover"
height={imageSize}
placeholder={imagePlaceholderUrl || 'var(--placeholder-bg)'}
src={imageUrl}
width={imageSize}
/>
) : (
<Center
sx={{
background: 'var(--placeholder-bg)',
borderRadius: 'var(--card-default-radius)',
height: `${imageSize}px`,
width: `${imageSize}px`,
}}
>
<RiAlbumFill
color="var(--placeholder-fg)"
size={35}
/>
</Center>
)}
</CoverImageWrapper>
<MetadataWrapper>
<Group>
<Text
$link
component={Link}
to={item.route}
tt="uppercase"
weight={600}
>
{item.type}
</Text>
</Group>
<TextTitle
lh={1.15}
lineClamp={2}
overflow="hidden"
pb={cq.isXs ? '0' : cq.isSm ? '0.2rem' : '0.36rem'}
sx={{ fontSize: titleSize, overflow: 'hidden' }}
weight={900}
>
{title}
</TextTitle>
{children}
</MetadataWrapper>
</HeaderContainer>
);
},
);

View file

@ -3,43 +3,43 @@ import { RiPlayFill } from 'react-icons/ri';
import styled from 'styled-components';
const MotionButton = styled(UnstyledButton)`
display: flex;
align-items: center;
justify-content: center;
background-color: var(--btn-filled-bg);
border: none;
border-radius: 50%;
opacity: 0.8;
svg {
fill: var(--btn-filled-fg);
}
&:hover {
background-color: var(--btn-filled-bg-hover);
transform: scale(1.1);
display: flex;
align-items: center;
justify-content: center;
background-color: var(--btn-filled-bg);
border: none;
border-radius: 50%;
opacity: 0.8;
svg {
fill: var(--btn-filled-fg-hover);
fill: var(--btn-filled-fg);
}
}
&:active {
transform: scale(0.95);
}
&:hover {
background-color: var(--btn-filled-bg-hover);
transform: scale(1.1);
transition: background-color 0.2s ease-in-out;
transition: transform 0.2s ease-in-out;
svg {
fill: var(--btn-filled-fg-hover);
}
}
&:active {
transform: scale(0.95);
}
transition: background-color 0.2s ease-in-out;
transition: transform 0.2s ease-in-out;
`;
export const PlayButton = ({ ...props }: any) => {
return (
<MotionButton
{...props}
h="45px"
w="45px"
>
<RiPlayFill size={20} />
</MotionButton>
);
return (
<MotionButton
{...props}
h="45px"
w="45px"
>
<RiPlayFill size={20} />
</MotionButton>
);
};

View file

@ -1,33 +1,33 @@
import styled from 'styled-components';
export const ResizeHandle = styled.div<{
isResizing: boolean;
placement: 'top' | 'left' | 'bottom' | 'right';
isResizing: boolean;
placement: 'top' | 'left' | 'bottom' | 'right';
}>`
position: absolute;
top: ${(props) => props.placement === 'top' && 0};
right: ${(props) => props.placement === 'right' && 0};
bottom: ${(props) => props.placement === 'bottom' && 0};
left: ${(props) => props.placement === 'left' && 0};
z-index: 90;
width: 4px;
height: 100%;
cursor: ew-resize;
opacity: ${(props) => (props.isResizing ? 1 : 0)};
&:hover {
opacity: 0.7;
}
&::before {
position: absolute;
top: ${(props) => props.placement === 'top' && 0};
right: ${(props) => props.placement === 'right' && 0};
bottom: ${(props) => props.placement === 'bottom' && 0};
left: ${(props) => props.placement === 'left' && 0};
width: 1px;
z-index: 90;
width: 4px;
height: 100%;
background-color: var(--sidebar-handle-bg);
content: '';
}
cursor: ew-resize;
opacity: ${(props) => (props.isResizing ? 1 : 0)};
&:hover {
opacity: 0.7;
}
&::before {
position: absolute;
top: ${(props) => props.placement === 'top' && 0};
right: ${(props) => props.placement === 'right' && 0};
bottom: ${(props) => props.placement === 'bottom' && 0};
left: ${(props) => props.placement === 'left' && 0};
width: 1px;
height: 100%;
background-color: var(--sidebar-handle-bg);
content: '';
}
`;

View file

@ -3,77 +3,80 @@ import { AxiosError } from 'axios';
import { api } from '/@/renderer/api';
import { queryKeys } from '/@/renderer/api/query-keys';
import {
AlbumArtistDetailResponse,
AlbumDetailResponse,
FavoriteArgs,
FavoriteResponse,
LibraryItem,
AlbumArtistDetailResponse,
AlbumDetailResponse,
FavoriteArgs,
FavoriteResponse,
LibraryItem,
} from '/@/renderer/api/types';
import { MutationHookArgs } from '/@/renderer/lib/react-query';
import { getServerById, useSetAlbumListItemDataById, useSetQueueFavorite } from '/@/renderer/store';
export const useCreateFavorite = (args: MutationHookArgs) => {
const { options } = args || {};
const queryClient = useQueryClient();
const setAlbumListData = useSetAlbumListItemDataById();
const setQueueFavorite = useSetQueueFavorite();
const { options } = args || {};
const queryClient = useQueryClient();
const setAlbumListData = useSetAlbumListItemDataById();
const setQueueFavorite = useSetQueueFavorite();
return useMutation<
FavoriteResponse,
AxiosError,
Omit<FavoriteArgs, 'server' | 'apiClientProps'>,
null
>({
mutationFn: (args) => {
const server = getServerById(args.serverId);
if (!server) throw new Error('Server not found');
return api.controller.createFavorite({ ...args, apiClientProps: { server } });
},
onSuccess: (_data, variables) => {
const { serverId } = variables;
return useMutation<
FavoriteResponse,
AxiosError,
Omit<FavoriteArgs, 'server' | 'apiClientProps'>,
null
>({
mutationFn: (args) => {
const server = getServerById(args.serverId);
if (!server) throw new Error('Server not found');
return api.controller.createFavorite({ ...args, apiClientProps: { server } });
},
onSuccess: (_data, variables) => {
const { serverId } = variables;
if (!serverId) return;
if (!serverId) return;
for (const id of variables.query.id) {
// Set the userFavorite property to true for the album in the album list data store
if (variables.query.type === LibraryItem.ALBUM) {
setAlbumListData(id, { userFavorite: true });
}
}
for (const id of variables.query.id) {
// Set the userFavorite property to true for the album in the album list data store
if (variables.query.type === LibraryItem.ALBUM) {
setAlbumListData(id, { userFavorite: true });
}
}
if (variables.query.type === LibraryItem.SONG) {
setQueueFavorite(variables.query.id, true);
}
if (variables.query.type === LibraryItem.SONG) {
setQueueFavorite(variables.query.id, true);
}
// We only need to set if we're already on the album detail page
if (variables.query.type === LibraryItem.ALBUM && variables.query.id.length === 1) {
const queryKey = queryKeys.albums.detail(serverId, { id: variables.query.id[0] });
const previous = queryClient.getQueryData<AlbumDetailResponse>(queryKey);
// We only need to set if we're already on the album detail page
if (variables.query.type === LibraryItem.ALBUM && variables.query.id.length === 1) {
const queryKey = queryKeys.albums.detail(serverId, { id: variables.query.id[0] });
const previous = queryClient.getQueryData<AlbumDetailResponse>(queryKey);
if (previous) {
queryClient.setQueryData<AlbumDetailResponse>(queryKey, {
...previous,
userFavorite: true,
});
}
}
if (previous) {
queryClient.setQueryData<AlbumDetailResponse>(queryKey, {
...previous,
userFavorite: true,
});
}
}
// We only need to set if we're already on the album detail page
if (variables.query.type === LibraryItem.ALBUM_ARTIST && variables.query.id.length === 1) {
const queryKey = queryKeys.albumArtists.detail(serverId, {
id: variables.query.id[0],
});
// We only need to set if we're already on the album detail page
if (
variables.query.type === LibraryItem.ALBUM_ARTIST &&
variables.query.id.length === 1
) {
const queryKey = queryKeys.albumArtists.detail(serverId, {
id: variables.query.id[0],
});
const previous = queryClient.getQueryData<AlbumArtistDetailResponse>(queryKey);
const previous = queryClient.getQueryData<AlbumArtistDetailResponse>(queryKey);
if (previous) {
queryClient.setQueryData<AlbumArtistDetailResponse>(queryKey, {
...previous,
userFavorite: true,
});
}
}
},
...options,
});
if (previous) {
queryClient.setQueryData<AlbumArtistDetailResponse>(queryKey, {
...previous,
userFavorite: true,
});
}
}
},
...options,
});
};

View file

@ -3,76 +3,79 @@ import { AxiosError } from 'axios';
import { api } from '/@/renderer/api';
import { queryKeys } from '/@/renderer/api/query-keys';
import {
AlbumArtistDetailResponse,
AlbumDetailResponse,
FavoriteArgs,
FavoriteResponse,
LibraryItem,
AlbumArtistDetailResponse,
AlbumDetailResponse,
FavoriteArgs,
FavoriteResponse,
LibraryItem,
} from '/@/renderer/api/types';
import { MutationHookArgs } from '/@/renderer/lib/react-query';
import { getServerById, useSetAlbumListItemDataById, useSetQueueFavorite } from '/@/renderer/store';
export const useDeleteFavorite = (args: MutationHookArgs) => {
const { options } = args || {};
const queryClient = useQueryClient();
const setAlbumListData = useSetAlbumListItemDataById();
const setQueueFavorite = useSetQueueFavorite();
const { options } = args || {};
const queryClient = useQueryClient();
const setAlbumListData = useSetAlbumListItemDataById();
const setQueueFavorite = useSetQueueFavorite();
return useMutation<
FavoriteResponse,
AxiosError,
Omit<FavoriteArgs, 'server' | 'apiClientProps'>,
null
>({
mutationFn: (args) => {
const server = getServerById(args.serverId);
if (!server) throw new Error('Server not found');
return api.controller.deleteFavorite({ ...args, apiClientProps: { server } });
},
onSuccess: (_data, variables) => {
const { serverId } = variables;
return useMutation<
FavoriteResponse,
AxiosError,
Omit<FavoriteArgs, 'server' | 'apiClientProps'>,
null
>({
mutationFn: (args) => {
const server = getServerById(args.serverId);
if (!server) throw new Error('Server not found');
return api.controller.deleteFavorite({ ...args, apiClientProps: { server } });
},
onSuccess: (_data, variables) => {
const { serverId } = variables;
if (!serverId) return;
if (!serverId) return;
for (const id of variables.query.id) {
// Set the userFavorite property to false for the album in the album list data store
if (variables.query.type === LibraryItem.ALBUM) {
setAlbumListData(id, { userFavorite: false });
}
}
for (const id of variables.query.id) {
// Set the userFavorite property to false for the album in the album list data store
if (variables.query.type === LibraryItem.ALBUM) {
setAlbumListData(id, { userFavorite: false });
}
}
if (variables.query.type === LibraryItem.SONG) {
setQueueFavorite(variables.query.id, false);
}
if (variables.query.type === LibraryItem.SONG) {
setQueueFavorite(variables.query.id, false);
}
// We only need to set if we're already on the album detail page
if (variables.query.type === LibraryItem.ALBUM && variables.query.id.length === 1) {
const queryKey = queryKeys.albums.detail(serverId, { id: variables.query.id[0] });
const previous = queryClient.getQueryData<AlbumDetailResponse>(queryKey);
// We only need to set if we're already on the album detail page
if (variables.query.type === LibraryItem.ALBUM && variables.query.id.length === 1) {
const queryKey = queryKeys.albums.detail(serverId, { id: variables.query.id[0] });
const previous = queryClient.getQueryData<AlbumDetailResponse>(queryKey);
if (previous) {
queryClient.setQueryData<AlbumDetailResponse>(queryKey, {
...previous,
userFavorite: false,
});
}
}
if (previous) {
queryClient.setQueryData<AlbumDetailResponse>(queryKey, {
...previous,
userFavorite: false,
});
}
}
// We only need to set if we're already on the album artist detail page
if (variables.query.type === LibraryItem.ALBUM_ARTIST && variables.query.id.length === 1) {
const queryKey = queryKeys.albumArtists.detail(serverId, {
id: variables.query.id[0],
});
const previous = queryClient.getQueryData<AlbumArtistDetailResponse>(queryKey);
// We only need to set if we're already on the album artist detail page
if (
variables.query.type === LibraryItem.ALBUM_ARTIST &&
variables.query.id.length === 1
) {
const queryKey = queryKeys.albumArtists.detail(serverId, {
id: variables.query.id[0],
});
const previous = queryClient.getQueryData<AlbumArtistDetailResponse>(queryKey);
if (previous) {
queryClient.setQueryData<AlbumArtistDetailResponse>(queryKey, {
...previous,
userFavorite: false,
});
}
}
},
...options,
});
if (previous) {
queryClient.setQueryData<AlbumArtistDetailResponse>(queryKey, {
...previous,
userFavorite: false,
});
}
}
},
...options,
});
};

View file

@ -3,99 +3,100 @@ import { AxiosError } from 'axios';
import { api } from '/@/renderer/api';
import { queryKeys } from '/@/renderer/api/query-keys';
import {
Album,
AlbumArtist,
AnyLibraryItems,
LibraryItem,
SetRatingArgs,
RatingResponse,
AlbumDetailResponse,
AlbumArtistDetailResponse,
Album,
AlbumArtist,
AnyLibraryItems,
LibraryItem,
SetRatingArgs,
RatingResponse,
AlbumDetailResponse,
AlbumArtistDetailResponse,
} from '/@/renderer/api/types';
import { MutationHookArgs } from '/@/renderer/lib/react-query';
import { getServerById, useSetAlbumListItemDataById, useSetQueueRating } from '/@/renderer/store';
export const useSetRating = (args: MutationHookArgs) => {
const { options } = args || {};
const queryClient = useQueryClient();
const setAlbumListData = useSetAlbumListItemDataById();
const setQueueRating = useSetQueueRating();
const { options } = args || {};
const queryClient = useQueryClient();
const setAlbumListData = useSetAlbumListItemDataById();
const setQueueRating = useSetQueueRating();
return useMutation<
RatingResponse,
AxiosError,
Omit<SetRatingArgs, 'server' | 'apiClientProps'>,
{ previous: { items: AnyLibraryItems } | undefined }
>({
mutationFn: (args) => {
const server = getServerById(args.serverId);
if (!server) throw new Error('Server not found');
return api.controller.updateRating({ ...args, apiClientProps: { server } });
},
onError: (_error, _variables, context) => {
for (const item of context?.previous?.items || []) {
switch (item.itemType) {
case LibraryItem.ALBUM:
setAlbumListData(item.id, { userRating: item.userRating });
break;
case LibraryItem.SONG:
setQueueRating([item.id], item.userRating);
break;
}
}
},
onMutate: (variables) => {
for (const item of variables.query.item) {
switch (item.itemType) {
case LibraryItem.ALBUM:
setAlbumListData(item.id, { userRating: variables.query.rating });
break;
case LibraryItem.SONG:
setQueueRating([item.id], variables.query.rating);
break;
}
}
return useMutation<
RatingResponse,
AxiosError,
Omit<SetRatingArgs, 'server' | 'apiClientProps'>,
{ previous: { items: AnyLibraryItems } | undefined }
>({
mutationFn: (args) => {
const server = getServerById(args.serverId);
if (!server) throw new Error('Server not found');
return api.controller.updateRating({ ...args, apiClientProps: { server } });
},
onError: (_error, _variables, context) => {
for (const item of context?.previous?.items || []) {
switch (item.itemType) {
case LibraryItem.ALBUM:
setAlbumListData(item.id, { userRating: item.userRating });
break;
case LibraryItem.SONG:
setQueueRating([item.id], item.userRating);
break;
}
}
},
onMutate: (variables) => {
for (const item of variables.query.item) {
switch (item.itemType) {
case LibraryItem.ALBUM:
setAlbumListData(item.id, { userRating: variables.query.rating });
break;
case LibraryItem.SONG:
setQueueRating([item.id], variables.query.rating);
break;
}
}
return { previous: { items: variables.query.item } };
},
onSuccess: (_data, variables) => {
// We only need to set if we're already on the album detail page
const isAlbumDetailPage =
variables.query.item.length === 1 && variables.query.item[0].itemType === LibraryItem.ALBUM;
return { previous: { items: variables.query.item } };
},
onSuccess: (_data, variables) => {
// We only need to set if we're already on the album detail page
const isAlbumDetailPage =
variables.query.item.length === 1 &&
variables.query.item[0].itemType === LibraryItem.ALBUM;
if (isAlbumDetailPage) {
const { id: albumId, serverId } = variables.query.item[0] as Album;
if (isAlbumDetailPage) {
const { id: albumId, serverId } = variables.query.item[0] as Album;
const queryKey = queryKeys.albums.detail(serverId || '', { id: albumId });
const previous = queryClient.getQueryData<AlbumDetailResponse>(queryKey);
if (previous) {
queryClient.setQueryData<AlbumDetailResponse>(queryKey, {
...previous,
userRating: variables.query.rating,
});
}
}
const queryKey = queryKeys.albums.detail(serverId || '', { id: albumId });
const previous = queryClient.getQueryData<AlbumDetailResponse>(queryKey);
if (previous) {
queryClient.setQueryData<AlbumDetailResponse>(queryKey, {
...previous,
userRating: variables.query.rating,
});
}
}
// We only need to set if we're already on the album artist detail page
const isAlbumArtistDetailPage =
variables.query.item.length === 1 &&
variables.query.item[0].itemType === LibraryItem.ALBUM_ARTIST;
// We only need to set if we're already on the album artist detail page
const isAlbumArtistDetailPage =
variables.query.item.length === 1 &&
variables.query.item[0].itemType === LibraryItem.ALBUM_ARTIST;
if (isAlbumArtistDetailPage) {
const { id: albumArtistId, serverId } = variables.query.item[0] as AlbumArtist;
if (isAlbumArtistDetailPage) {
const { id: albumArtistId, serverId } = variables.query.item[0] as AlbumArtist;
const queryKey = queryKeys.albumArtists.detail(serverId || '', {
id: albumArtistId,
});
const previous = queryClient.getQueryData<AlbumArtistDetailResponse>(queryKey);
if (previous) {
queryClient.setQueryData<AlbumArtistDetailResponse>(queryKey, {
...previous,
userRating: variables.query.rating,
});
}
}
},
...options,
});
const queryKey = queryKeys.albumArtists.detail(serverId || '', {
id: albumArtistId,
});
const previous = queryClient.getQueryData<AlbumArtistDetailResponse>(queryKey);
if (previous) {
queryClient.setQueryData<AlbumArtistDetailResponse>(queryKey, {
...previous,
userRating: variables.query.rating,
});
}
}
},
...options,
});
};

View file

@ -6,18 +6,18 @@ import { MusicFolderListQuery } from '../../../api/types';
import { QueryHookArgs } from '../../../lib/react-query';
export const useMusicFolders = (args: QueryHookArgs<MusicFolderListQuery>) => {
const { options, serverId } = args || {};
const server = getServerById(serverId);
const { options, serverId } = args || {};
const server = getServerById(serverId);
const query = useQuery({
enabled: !!server,
queryFn: ({ signal }) => {
if (!server) throw new Error('Server not found');
return api.controller.getMusicFolderList({ apiClientProps: { server, signal } });
},
queryKey: queryKeys.musicFolders.list(server?.id || ''),
...options,
});
const query = useQuery({
enabled: !!server,
queryFn: ({ signal }) => {
if (!server) throw new Error('Server not found');
return api.controller.getMusicFolderList({ apiClientProps: { server, signal } });
},
queryKey: queryKeys.musicFolders.list(server?.id || ''),
...options,
});
return query;
return query;
};

View file

@ -1,16 +1,16 @@
import { Play } from '/@/renderer/types';
export const PLAY_TYPES = [
{
label: 'Play',
play: Play.NOW,
},
{
label: 'Add to queue',
play: Play.LAST,
},
{
label: 'Add to queue next',
play: Play.NEXT,
},
{
label: 'Play',
play: Play.NOW,
},
{
label: 'Add to queue',
play: Play.LAST,
},
{
label: 'Add to queue next',
play: Play.NEXT,
},
];