feat: add search functionality to filter available sounds in PlaylistEditPage
This commit is contained in:
@@ -16,6 +16,7 @@ import { SimpleSortableRow } from '@/components/playlists/playlist-edit/SimpleSo
|
|||||||
import { SortableTableRow } from '@/components/playlists/playlist-edit/SortableTableRow'
|
import { SortableTableRow } from '@/components/playlists/playlist-edit/SortableTableRow'
|
||||||
import { Button } from '@/components/ui/button'
|
import { Button } from '@/components/ui/button'
|
||||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
|
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
|
||||||
|
import { Input } from '@/components/ui/input'
|
||||||
import { Skeleton } from '@/components/ui/skeleton'
|
import { Skeleton } from '@/components/ui/skeleton'
|
||||||
import {
|
import {
|
||||||
Table,
|
Table,
|
||||||
@@ -46,7 +47,7 @@ import {
|
|||||||
SortableContext,
|
SortableContext,
|
||||||
verticalListSortingStrategy,
|
verticalListSortingStrategy,
|
||||||
} from '@dnd-kit/sortable'
|
} from '@dnd-kit/sortable'
|
||||||
import { Minus, Music, Plus, RefreshCw } from 'lucide-react'
|
import { Minus, Music, Plus, RefreshCw, Search, X } from 'lucide-react'
|
||||||
import { useCallback, useEffect, useState } from 'react'
|
import { useCallback, useEffect, useState } from 'react'
|
||||||
import { useNavigate, useParams } from 'react-router'
|
import { useNavigate, useParams } from 'react-router'
|
||||||
import { toast } from 'sonner'
|
import { toast } from 'sonner'
|
||||||
@@ -74,6 +75,7 @@ export function PlaylistEditPage() {
|
|||||||
Sound | PlaylistSound | null
|
Sound | PlaylistSound | null
|
||||||
>(null)
|
>(null)
|
||||||
const [dropPosition, setDropPosition] = useState<number | null>(null)
|
const [dropPosition, setDropPosition] = useState<number | null>(null)
|
||||||
|
const [searchQuery, setSearchQuery] = useState('')
|
||||||
|
|
||||||
// dnd-kit sensors
|
// dnd-kit sensors
|
||||||
const sensors = useSensors(
|
const sensors = useSensors(
|
||||||
@@ -152,10 +154,18 @@ export function PlaylistEditPage() {
|
|||||||
if (!isAddMode) {
|
if (!isAddMode) {
|
||||||
// Entering add mode - fetch available sounds
|
// Entering add mode - fetch available sounds
|
||||||
await fetchAvailableSounds()
|
await fetchAvailableSounds()
|
||||||
|
} else {
|
||||||
|
// Exiting add mode - clear search
|
||||||
|
setSearchQuery('')
|
||||||
}
|
}
|
||||||
setIsAddMode(!isAddMode)
|
setIsAddMode(!isAddMode)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Filter available sounds based on search query
|
||||||
|
const filteredAvailableSounds = availableSounds.filter(sound =>
|
||||||
|
sound.name.toLowerCase().includes(searchQuery.toLowerCase())
|
||||||
|
)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isNaN(playlistId)) {
|
if (!isNaN(playlistId)) {
|
||||||
fetchPlaylist()
|
fetchPlaylist()
|
||||||
@@ -807,9 +817,30 @@ export function PlaylistEditPage() {
|
|||||||
|
|
||||||
{/* Available Sounds */}
|
{/* Available Sounds */}
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<h4 className="font-medium text-sm text-muted-foreground mb-3">
|
<div className="flex items-center justify-between mb-3">
|
||||||
Available EXT Sounds ({availableSounds.length})
|
<h4 className="font-medium text-sm text-muted-foreground">
|
||||||
</h4>
|
Available EXT Sounds ({filteredAvailableSounds.length}/{availableSounds.length})
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
<div className="relative mb-3">
|
||||||
|
<Search className="absolute left-2 top-1/2 transform -translate-y-1/2 h-4 w-4 text-muted-foreground" />
|
||||||
|
<Input
|
||||||
|
type="text"
|
||||||
|
placeholder="Search sounds..."
|
||||||
|
value={searchQuery}
|
||||||
|
onChange={(e) => setSearchQuery(e.target.value)}
|
||||||
|
className="pl-8 pr-8"
|
||||||
|
/>
|
||||||
|
{searchQuery && (
|
||||||
|
<button
|
||||||
|
onClick={() => setSearchQuery('')}
|
||||||
|
className="absolute right-2 top-1/2 transform -translate-y-1/2 text-muted-foreground hover:text-foreground transition-colors"
|
||||||
|
title="Clear search"
|
||||||
|
>
|
||||||
|
<X className="h-4 w-4" />
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
{availableSoundsLoading ? (
|
{availableSoundsLoading ? (
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
{Array.from({ length: 3 }).map((_, i) => (
|
{Array.from({ length: 3 }).map((_, i) => (
|
||||||
@@ -824,15 +855,23 @@ export function PlaylistEditPage() {
|
|||||||
All EXT sounds are already in this playlist
|
All EXT sounds are already in this playlist
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
) : filteredAvailableSounds.length === 0 ? (
|
||||||
|
<div className="text-center py-8 text-muted-foreground">
|
||||||
|
<Search className="h-8 w-8 mx-auto mb-2 opacity-50" />
|
||||||
|
<p className="text-sm">No sounds match your search</p>
|
||||||
|
<p className="text-xs mt-1">
|
||||||
|
Try a different search term
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<SortableContext
|
<SortableContext
|
||||||
items={availableSounds.map(
|
items={filteredAvailableSounds.map(
|
||||||
sound => `available-sound-${sound.id}`,
|
sound => `available-sound-${sound.id}`,
|
||||||
)}
|
)}
|
||||||
strategy={verticalListSortingStrategy}
|
strategy={verticalListSortingStrategy}
|
||||||
>
|
>
|
||||||
<div className="space-y-2 max-h-96 overflow-y-auto">
|
<div className="space-y-2 max-h-96 overflow-y-auto">
|
||||||
{availableSounds.map(sound => (
|
{filteredAvailableSounds.map(sound => (
|
||||||
<AvailableSound
|
<AvailableSound
|
||||||
key={sound.id}
|
key={sound.id}
|
||||||
sound={sound}
|
sound={sound}
|
||||||
|
|||||||
Reference in New Issue
Block a user