Files
sbd2-frontend/src/components/playlists/PlaylistsHeader.tsx

150 lines
4.7 KiB
TypeScript

import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from '@/components/ui/select'
import type { PlaylistSortField, SortOrder } from '@/lib/api/services/playlists'
import { Heart, Plus, RefreshCw, Search, SortAsc, SortDesc, X } from 'lucide-react'
interface PlaylistsHeaderProps {
searchQuery: string
onSearchChange: (query: string) => void
sortBy: PlaylistSortField
onSortByChange: (sortBy: PlaylistSortField) => void
sortOrder: SortOrder
onSortOrderChange: (order: SortOrder) => void
onRefresh: () => void
onCreateClick: () => void
loading: boolean
error: string | null
playlistCount: number
showFavoritesOnly: boolean
onFavoritesToggle: (show: boolean) => void
}
export function PlaylistsHeader({
searchQuery,
onSearchChange,
sortBy,
onSortByChange,
sortOrder,
onSortOrderChange,
onRefresh,
onCreateClick,
loading,
error,
playlistCount,
showFavoritesOnly,
onFavoritesToggle,
}: PlaylistsHeaderProps) {
return (
<>
{/* Header */}
<div className="flex items-center justify-between mb-6">
<div>
<h1 className="text-2xl font-bold">Playlists</h1>
<p className="text-muted-foreground">
Manage and browse your soundboard playlists
</p>
</div>
<div className="flex items-center gap-4">
{!loading && !error && (
<div className="text-sm text-muted-foreground">
{showFavoritesOnly
? `${playlistCount} favorite playlist${playlistCount !== 1 ? 's' : ''}`
: `${playlistCount} playlist${playlistCount !== 1 ? 's' : ''}`
}
</div>
)}
<Button onClick={onCreateClick}>
<Plus className="h-4 w-4 mr-2" />
Add Playlist
</Button>
</div>
</div>
{/* Search and Sort Controls */}
<div className="flex flex-col sm:flex-row gap-4 mb-6">
<div className="flex-1">
<div className="relative">
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-muted-foreground" />
<Input
placeholder="Search playlists..."
value={searchQuery}
onChange={e => onSearchChange(e.target.value)}
className="pl-9 pr-9"
/>
{searchQuery && (
<Button
variant="ghost"
size="sm"
onClick={() => onSearchChange('')}
className="absolute right-1 top-1/2 transform -translate-y-1/2 h-7 w-7 p-0 hover:bg-muted"
title="Clear search"
>
<X className="h-3 w-3" />
</Button>
)}
</div>
</div>
<div className="flex gap-2">
<Select
value={sortBy}
onValueChange={value => onSortByChange(value as PlaylistSortField)}
>
<SelectTrigger className="w-[180px]">
<SelectValue placeholder="Sort by" />
</SelectTrigger>
<SelectContent>
<SelectItem value="name">Name</SelectItem>
<SelectItem value="genre">Genre</SelectItem>
<SelectItem value="sound_count">Track Count</SelectItem>
<SelectItem value="total_duration">Duration</SelectItem>
<SelectItem value="created_at">Created Date</SelectItem>
<SelectItem value="updated_at">Updated Date</SelectItem>
</SelectContent>
</Select>
<Button
variant="outline"
size="icon"
onClick={() => onSortOrderChange(sortOrder === 'asc' ? 'desc' : 'asc')}
title={sortOrder === 'asc' ? 'Sort ascending' : 'Sort descending'}
>
{sortOrder === 'asc' ? (
<SortAsc className="h-4 w-4" />
) : (
<SortDesc className="h-4 w-4" />
)}
</Button>
<Button
variant={showFavoritesOnly ? "default" : "outline"}
size="icon"
onClick={() => onFavoritesToggle(!showFavoritesOnly)}
title={showFavoritesOnly ? "Show all playlists" : "Show only favorites"}
>
<Heart className={`h-4 w-4 ${showFavoritesOnly ? 'fill-current' : ''}`} />
</Button>
<Button
variant="outline"
size="icon"
onClick={onRefresh}
disabled={loading}
title="Refresh playlists"
>
<RefreshCw
className={`h-4 w-4 ${loading ? 'animate-spin' : ''}`}
/>
</Button>
</div>
</div>
</>
)
}