State management

This commit is contained in:
Sean Edmunds
2025-05-02 14:50:14 -05:00
parent 16787969fc
commit 97a59d6a15
21 changed files with 525 additions and 320 deletions

View File

@@ -1,10 +1,11 @@
import { Box, Group, Stack, Text } from '@mantine/core';
import { useDebouncedValue, useDisclosure } from '@mantine/hooks';
import { useCommonHooks, useMutationAPI, useQueryAPI } from 'hooks';
import { useState } from 'react';
import { useEffect, useState } from 'react';
import { FiChevronRight } from 'react-icons/fi';
import { textClasses } from 'styles';
import type { ThemePlaylist } from 'types';
import NoItemsFound from '../Shared/NoItemsFound';
import SettingsHeader from '../Shared/SettingsHeader';
import ThemePlaylistCard from './ThemePlaylistCard';
import ThemePlaylistModal from './ThemePlaylistModal';
@@ -15,9 +16,10 @@ function ThemePlaylists() {
endpoint: themesEndpoint,
});
const themePlaylistsEndpoint = 'api/themePlaylists';
const { data: themePlaylistData } = useQueryAPI({
const { data: themePlaylistData, isFetched: isThemePlaylistDataFetched } = useQueryAPI({
endpoint: themePlaylistsEndpoint,
});
const [themePlaylists, setThemePlaylists] = useState<ThemePlaylist[]>([]);
const defaultPlaylist = {
id: undefined,
default: 0,
@@ -31,6 +33,7 @@ function ThemePlaylists() {
const { currentThemePlaylist, theme, isMobile } = useCommonHooks();
const [searchValue, setSearchValue] = useState('');
const [debouncedSearch] = useDebouncedValue(searchValue, 500);
const [isLoading, setIsLoading] = useState(false);
const handleOpen = (playlist: ThemePlaylist) => {
setSelectedPlaylist(playlist);
@@ -51,6 +54,19 @@ function ThemePlaylists() {
close();
};
useEffect(() => {
if (themePlaylistData && isThemePlaylistDataFetched) {
setThemePlaylists(
themePlaylistData.filter((a: ThemePlaylist) =>
a.name.toLowerCase().includes(debouncedSearch.toLowerCase()),
),
);
}
if (debouncedSearch === searchValue) {
setIsLoading(false);
}
}, [themePlaylistData, isThemePlaylistDataFetched, debouncedSearch]);
return (
<Stack>
<ThemePlaylistModal
@@ -77,6 +93,8 @@ function ThemePlaylists() {
searchValue={searchValue}
setSearchValue={setSearchValue}
searchPlaceholder={'Search Theme Playlists...'}
isLoading={isLoading}
setIsLoading={setIsLoading}
/>
<Group mt={'6rem'} justify='center' align='center' pos={'relative'}>
<Text p={0} className={textClasses.settingsSubTitle} classNames={textClasses}>
@@ -84,41 +102,44 @@ function ThemePlaylists() {
</Text>
</Group>
<Group justify='center' align='center' pos={'relative'}>
{themePlaylistData
?.filter((playlist: ThemePlaylist) => playlist.default === 1)
?.filter((a: ThemePlaylist) =>
a.name.toLowerCase().includes(debouncedSearch.toLowerCase()),
)
.map((cardPlaylist: ThemePlaylist) => {
return (
<Group key={cardPlaylist.name} pos={'relative'}>
{cardPlaylist.name === currentThemePlaylist && (
<FiChevronRight
style={{
position: 'absolute',
left: -14,
zIndex: 10,
fontSize: '2em',
fontWeight: 'bold',
borderRadius: '50%',
backgroundColor: 'var(--mantine-color-border-0)',
color:
theme.borderColor === theme.primaryColor
? 'var(--mantine-color-accent-0)'
: 'var(--mantine-color-background-0)',
}}
/>
)}
<Box>
<ThemePlaylistCard
cardPlaylist={cardPlaylist}
handleOpen={handleOpen}
allThemes={allThemeData}
/>
</Box>
</Group>
);
})}
{themePlaylists.length > 0 ? (
themePlaylists
.filter((playlist: ThemePlaylist) => playlist.default === 1)
.map((cardPlaylist: ThemePlaylist) => {
return (
<Group key={cardPlaylist.name} pos={'relative'}>
{cardPlaylist.name === currentThemePlaylist && (
<FiChevronRight
style={{
position: 'absolute',
left: -14,
zIndex: 10,
fontSize: '2em',
fontWeight: 'bold',
borderRadius: '50%',
backgroundColor: 'var(--mantine-color-border-0)',
color:
theme.borderColor === theme.primaryColor
? 'var(--mantine-color-accent-0)'
: 'var(--mantine-color-background-0)',
}}
/>
)}
<Box>
<ThemePlaylistCard
cardPlaylist={cardPlaylist}
handleOpen={handleOpen}
allThemes={allThemeData}
/>
</Box>
</Group>
);
})
) : (
<Group w={'100%'} style={{ display: 'flex', justifyContent: 'center' }}>
<NoItemsFound />
</Group>
)}
</Group>
<Group justify='center' align='center' pos={'relative'}>
<Text p={0} className={textClasses.settingsSubTitle} classNames={textClasses}>
@@ -131,42 +152,45 @@ function ThemePlaylists() {
pos={'relative'}
mb={isMobile ? '6rem' : undefined}
>
{themePlaylistData
?.filter((playlist: ThemePlaylist) => playlist.default === 0)
?.filter((a: ThemePlaylist) =>
a.name.toLowerCase().includes(debouncedSearch.toLowerCase()),
)
.sort((a: ThemePlaylist, b: ThemePlaylist) => (a.name > b.name ? 1 : -1))
.map((cardPlaylist: ThemePlaylist) => {
return (
<Group key={cardPlaylist.name} pos={'relative'}>
{cardPlaylist.name === currentThemePlaylist && (
<FiChevronRight
style={{
position: 'absolute',
left: -14,
zIndex: 10,
fontSize: '2em',
fontWeight: 'bold',
borderRadius: '50%',
backgroundColor: 'var(--mantine-color-border-0)',
color:
theme.borderColor === theme.primaryColor
? 'var(--mantine-color-accent-0)'
: 'var(--mantine-color-primary-0)',
}}
/>
)}
<Box>
<ThemePlaylistCard
cardPlaylist={cardPlaylist}
handleOpen={handleOpen}
allThemes={allThemeData}
/>
</Box>
</Group>
);
})}
{themePlaylists.length > 0 ? (
themePlaylists
.filter((playlist: ThemePlaylist) => playlist.default === 0)
.sort((a: ThemePlaylist, b: ThemePlaylist) => (a.name > b.name ? 1 : -1))
.map((cardPlaylist: ThemePlaylist) => {
return (
<Group key={cardPlaylist.name} pos={'relative'}>
{cardPlaylist.name === currentThemePlaylist && (
<FiChevronRight
style={{
position: 'absolute',
left: -14,
zIndex: 10,
fontSize: '2em',
fontWeight: 'bold',
borderRadius: '50%',
backgroundColor: 'var(--mantine-color-border-0)',
color:
theme.borderColor === theme.primaryColor
? 'var(--mantine-color-accent-0)'
: 'var(--mantine-color-primary-0)',
}}
/>
)}
<Box>
<ThemePlaylistCard
cardPlaylist={cardPlaylist}
handleOpen={handleOpen}
allThemes={allThemeData}
/>
</Box>
</Group>
);
})
) : (
<Group w={'100%'} style={{ display: 'flex', justifyContent: 'center' }}>
<NoItemsFound />
</Group>
)}
</Group>
</Stack>
</Stack>