refactor: update TTSHeader component for improved sorting and search functionality

This commit is contained in:
JSC
2025-09-21 13:21:02 +02:00
parent 6f477a1aa7
commit 620418c405

View File

@@ -1,6 +1,5 @@
import { Button } from '@/components/ui/button' import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input' import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'
import { import {
Select, Select,
SelectContent, SelectContent,
@@ -8,15 +7,16 @@ import {
SelectTrigger, SelectTrigger,
SelectValue, SelectValue,
} from '@/components/ui/select' } from '@/components/ui/select'
import { Plus, RefreshCw, Search } from 'lucide-react' import type { TTSSortField, TTSSortOrder } from '@/lib/api/services/tts'
import { Plus, RefreshCw, Search, SortAsc, SortDesc, X } from 'lucide-react'
interface TTSHeaderProps { interface TTSHeaderProps {
searchQuery: string searchQuery: string
onSearchChange: (query: string) => void onSearchChange: (query: string) => void
sortBy: string sortBy: TTSSortField
onSortByChange: (sortBy: string) => void onSortByChange: (sortBy: TTSSortField) => void
sortOrder: 'asc' | 'desc' sortOrder: TTSSortOrder
onSortOrderChange: (order: 'asc' | 'desc') => void onSortOrderChange: (order: TTSSortOrder) => void
onRefresh: () => void onRefresh: () => void
onCreateClick: () => void onCreateClick: () => void
loading: boolean loading: boolean
@@ -38,90 +38,94 @@ export function TTSHeader({
ttsCount, ttsCount,
}: TTSHeaderProps) { }: TTSHeaderProps) {
return ( return (
<div className="space-y-4"> <>
{/* Header */} {/* Header */}
<div className="flex items-center justify-between"> <div className="flex items-center justify-between mb-6">
<div> <div>
<h1 className="text-3xl font-bold tracking-tight">Text to Speech</h1> <h1 className="text-2xl font-bold">Text to Speech</h1>
<p className="text-muted-foreground"> <p className="text-muted-foreground">
Generate speech from text using various TTS providers Generate speech from text using various TTS providers
</p> </p>
</div> </div>
<Button onClick={onCreateClick}> <div className="flex items-center gap-4">
<Plus className="mr-2 h-4 w-4" /> {!loading && !error && (
Generate TTS <div className="text-sm text-muted-foreground">
</Button> {ttsCount} generation{ttsCount !== 1 ? 's' : ''}
</div>
)}
<Button onClick={onCreateClick}>
<Plus className="h-4 w-4 mr-2" />
Generate TTS
</Button>
</div>
</div> </div>
{/* Controls */} {/* Search and Sort Controls */}
<div className="flex flex-col gap-4 sm:flex-row sm:items-end"> <div className="flex flex-col sm:flex-row gap-4 mb-6">
<div className="flex-1"> <div className="flex-1">
<Label htmlFor="search">Search</Label>
<div className="relative"> <div className="relative">
<Search className="absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" /> <Search className="absolute left-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-muted-foreground" />
<Input <Input
id="search"
placeholder="Search by text or provider..." placeholder="Search by text or provider..."
value={searchQuery} value={searchQuery}
onChange={(e) => onSearchChange(e.target.value)} onChange={e => onSearchChange(e.target.value)}
className="pl-9" 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> </div>
<div className="flex gap-2"> <div className="flex gap-2">
<div> <Select
<Label htmlFor="sortBy">Sort by</Label> value={sortBy}
<Select value={sortBy} onValueChange={onSortByChange}> onValueChange={value => onSortByChange(value as TTSSortField)}
<SelectTrigger id="sortBy" className="w-40"> >
<SelectValue /> <SelectTrigger className="w-[180px]">
</SelectTrigger> <SelectValue placeholder="Sort by" />
<SelectContent> </SelectTrigger>
<SelectItem value="created_at">Created</SelectItem> <SelectContent>
<SelectItem value="text">Text</SelectItem> <SelectItem value="created_at">Created Date</SelectItem>
<SelectItem value="provider">Provider</SelectItem> <SelectItem value="text">Text</SelectItem>
</SelectContent> <SelectItem value="provider">Provider</SelectItem>
</Select> </SelectContent>
</div> </Select>
<div> <Button
<Label htmlFor="sortOrder">Order</Label> variant="outline"
<Select size="icon"
value={sortOrder} onClick={() => onSortOrderChange(sortOrder === 'asc' ? 'desc' : 'asc')}
onValueChange={(value: 'asc' | 'desc') => onSortOrderChange(value)} title={sortOrder === 'asc' ? 'Sort ascending' : 'Sort descending'}
> >
<SelectTrigger id="sortOrder" className="w-32"> {sortOrder === 'asc' ? (
<SelectValue /> <SortAsc className="h-4 w-4" />
</SelectTrigger> ) : (
<SelectContent> <SortDesc className="h-4 w-4" />
<SelectItem value="desc">Newest</SelectItem> )}
<SelectItem value="asc">Oldest</SelectItem> </Button>
</SelectContent>
</Select>
</div>
<div className="flex items-end"> <Button
<Button variant="outline"
variant="outline" size="icon"
size="icon" onClick={onRefresh}
onClick={onRefresh} disabled={loading}
disabled={loading} title="Refresh TTS history"
> >
<RefreshCw className={`h-4 w-4 ${loading ? 'animate-spin' : ''}`} /> <RefreshCw
</Button> className={`h-4 w-4 ${loading ? 'animate-spin' : ''}`}
</div> />
</Button>
</div> </div>
</div> </div>
</>
{/* Stats */}
<div className="flex items-center gap-4 text-sm text-muted-foreground">
<span>
{ttsCount} generation{ttsCount !== 1 ? 's' : ''}
</span>
{error && (
<span className="text-destructive">Error: {error}</span>
)}
</div>
</div>
) )
} }