feat: implement favorites functionality with SoundCard integration and FavoritesService
This commit is contained in:
@@ -17,9 +17,11 @@ import {
|
||||
type SoundSortField,
|
||||
soundsService,
|
||||
} from '@/lib/api/services/sounds'
|
||||
import { favoritesService } from '@/lib/api/services/favorites'
|
||||
import { SOUND_EVENTS, soundEvents } from '@/lib/events'
|
||||
import {
|
||||
AlertCircle,
|
||||
Heart,
|
||||
RefreshCw,
|
||||
Search,
|
||||
SortAsc,
|
||||
@@ -77,6 +79,7 @@ export function SoundsPage() {
|
||||
const [searchQuery, setSearchQuery] = useState('')
|
||||
const [sortBy, setSortBy] = useState<SoundSortField>('name')
|
||||
const [sortOrder, setSortOrder] = useState<SortOrder>('asc')
|
||||
const [showFavoritesOnly, setShowFavoritesOnly] = useState(false)
|
||||
|
||||
const handlePlaySound = async (sound: Sound) => {
|
||||
try {
|
||||
@@ -89,6 +92,39 @@ export function SoundsPage() {
|
||||
}
|
||||
}
|
||||
|
||||
const handleFavoriteToggle = async (soundId: number, shouldFavorite: boolean) => {
|
||||
try {
|
||||
if (shouldFavorite) {
|
||||
await favoritesService.addSoundFavorite(soundId)
|
||||
toast.success('Added to favorites')
|
||||
} else {
|
||||
await favoritesService.removeSoundFavorite(soundId)
|
||||
toast.success('Removed from favorites')
|
||||
}
|
||||
|
||||
// Update the sound in the local state
|
||||
setSounds(prevSounds =>
|
||||
prevSounds.map(sound =>
|
||||
sound.id === soundId
|
||||
? {
|
||||
...sound,
|
||||
is_favorited: shouldFavorite,
|
||||
favorite_count: shouldFavorite
|
||||
? sound.favorite_count + 1
|
||||
: Math.max(0, sound.favorite_count - 1),
|
||||
}
|
||||
: sound,
|
||||
),
|
||||
)
|
||||
} catch (error) {
|
||||
toast.error(
|
||||
`Failed to ${shouldFavorite ? 'add to' : 'remove from'} favorites: ${
|
||||
error instanceof Error ? error.message : 'Unknown error'
|
||||
}`,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const { theme } = useTheme()
|
||||
|
||||
useEffect(() => {
|
||||
@@ -188,15 +224,23 @@ export function SoundsPage() {
|
||||
)
|
||||
}
|
||||
|
||||
if (sounds.length === 0) {
|
||||
// Filter sounds based on favorites filter
|
||||
const filteredSounds = showFavoritesOnly ? sounds.filter(sound => sound.is_favorited) : sounds
|
||||
|
||||
if (filteredSounds.length === 0) {
|
||||
return (
|
||||
<div className="flex flex-col items-center justify-center py-12 text-center">
|
||||
<div className="h-12 w-12 rounded-full bg-muted flex items-center justify-center mb-4">
|
||||
<span className="text-2xl">🎵</span>
|
||||
<span className="text-2xl">{showFavoritesOnly ? '💝' : '🎵'}</span>
|
||||
</div>
|
||||
<h3 className="text-lg font-semibold mb-2">No sounds found</h3>
|
||||
<h3 className="text-lg font-semibold mb-2">
|
||||
{showFavoritesOnly ? 'No favorite sounds found' : 'No sounds found'}
|
||||
</h3>
|
||||
<p className="text-muted-foreground">
|
||||
No SDB type sounds are available in your library.
|
||||
{showFavoritesOnly
|
||||
? 'You haven\'t favorited any sounds yet. Click the heart icon on sounds to add them to your favorites.'
|
||||
: 'No SDB type sounds are available in your library.'
|
||||
}
|
||||
</p>
|
||||
</div>
|
||||
)
|
||||
@@ -204,11 +248,12 @@ export function SoundsPage() {
|
||||
|
||||
return (
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5 gap-4">
|
||||
{sounds.map((sound, idx) => (
|
||||
{filteredSounds.map((sound, idx) => (
|
||||
<SoundCard
|
||||
key={sound.id}
|
||||
sound={sound}
|
||||
playSound={handlePlaySound}
|
||||
onFavoriteToggle={handleFavoriteToggle}
|
||||
colorClasses={getSoundColor(idx)}
|
||||
/>
|
||||
))}
|
||||
@@ -232,7 +277,10 @@ export function SoundsPage() {
|
||||
</div>
|
||||
{!loading && !error && (
|
||||
<div className="text-sm text-muted-foreground">
|
||||
{sounds.length} sound{sounds.length !== 1 ? 's' : ''}
|
||||
{showFavoritesOnly
|
||||
? `${sounds.filter(s => s.is_favorited).length} favorite sound${sounds.filter(s => s.is_favorited).length !== 1 ? 's' : ''}`
|
||||
: `${sounds.length} sound${sounds.length !== 1 ? 's' : ''}`
|
||||
}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@@ -293,6 +341,15 @@ export function SoundsPage() {
|
||||
)}
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
variant={showFavoritesOnly ? "default" : "outline"}
|
||||
size="icon"
|
||||
onClick={() => setShowFavoritesOnly(!showFavoritesOnly)}
|
||||
title={showFavoritesOnly ? "Show all sounds" : "Show only favorites"}
|
||||
>
|
||||
<Heart className={`h-4 w-4 ${showFavoritesOnly ? 'fill-current' : ''}`} />
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
variant="outline"
|
||||
size="icon"
|
||||
|
||||
Reference in New Issue
Block a user