import { AppLayout } from '@/components/AppLayout' import { AppPagination } from '@/components/AppPagination' import { CreateTTSDialog } from '@/components/tts/CreateTTSDialog' import { TTSHeader } from '@/components/tts/TTSHeader' import { TTSEmpty, TTSError, TTSLoading, } from '@/components/tts/TTSLoadingStates' import { TTSTable } from '@/components/tts/TTSTable' import { type TTSResponse, type TTSSortField, type TTSSortOrder, ttsService, } from '@/lib/api/services/tts' import { TTS_EVENTS, ttsEvents } from '@/lib/events' import { useCallback, useEffect, useState } from 'react' import { toast } from 'sonner' export function TTSPage() { const [ttsHistory, setTTSHistory] = useState([]) const [loading, setLoading] = useState(true) const [error, setError] = useState(null) // Search and sorting state const [searchQuery, setSearchQuery] = useState('') const [sortBy, setSortBy] = useState('created_at') const [sortOrder, setSortOrder] = useState('desc') // Pagination state const [currentPage, setCurrentPage] = useState(1) const [totalPages, setTotalPages] = useState(1) const [totalCount, setTotalCount] = useState(0) const [pageSize, setPageSize] = useState(10) // Create TTS dialog state const [showCreateDialog, setShowCreateDialog] = useState(false) // Debounce search query const [debouncedSearchQuery, setDebouncedSearchQuery] = useState(searchQuery) useEffect(() => { const handler = setTimeout(() => { setDebouncedSearchQuery(searchQuery) }, 300) return () => clearTimeout(handler) }, [searchQuery]) const fetchTTSHistory = useCallback(async () => { try { setLoading(true) setError(null) const response = await ttsService.getTTSHistory({ search: debouncedSearchQuery.trim() || undefined, sort_by: sortBy, sort_order: sortOrder, page: currentPage, limit: pageSize, }) setTTSHistory(response.tts) setTotalPages(response.total_pages) setTotalCount(response.total) } catch (err) { const errorMessage = err instanceof Error ? err.message : 'Failed to fetch TTS history' setError(errorMessage) toast.error(errorMessage) } finally { setLoading(false) } }, [debouncedSearchQuery, sortBy, sortOrder, currentPage, pageSize]) useEffect(() => { fetchTTSHistory() }, [fetchTTSHistory]) // Reset to page 1 when filters change useEffect(() => { if (currentPage !== 1) { setCurrentPage(1) } }, [debouncedSearchQuery, sortBy, sortOrder, pageSize]) // Listen for TTS events to refresh the list useEffect(() => { const handleTTSCompleted = () => { fetchTTSHistory() } const handleTTSFailed = () => { fetchTTSHistory() } const handleTTSCreated = () => { fetchTTSHistory() } // Subscribe to TTS events ttsEvents.on(TTS_EVENTS.TTS_COMPLETED, handleTTSCompleted) ttsEvents.on(TTS_EVENTS.TTS_FAILED, handleTTSFailed) ttsEvents.on(TTS_EVENTS.TTS_CREATED, handleTTSCreated) return () => { // Cleanup event listeners ttsEvents.off(TTS_EVENTS.TTS_COMPLETED, handleTTSCompleted) ttsEvents.off(TTS_EVENTS.TTS_FAILED, handleTTSFailed) ttsEvents.off(TTS_EVENTS.TTS_CREATED, handleTTSCreated) } }, [fetchTTSHistory]) const handlePageChange = (page: number) => { setCurrentPage(page) } const handlePageSizeChange = (size: number) => { setPageSize(size) setCurrentPage(1) // Reset to first page when changing page size } const handleTTSDeleted = (ttsId: number) => { // Remove the deleted TTS from the current list setTTSHistory(prev => prev.filter(tts => tts.id !== ttsId)) // Update total count setTotalCount(prev => prev - 1) // If current page is now empty and not the first page, go to previous page const remainingOnCurrentPage = ttsHistory.length - 1 if (remainingOnCurrentPage === 0 && currentPage > 1) { setCurrentPage(currentPage - 1) } // Refresh the full list to ensure accuracy fetchTTSHistory() } const renderContent = () => { if (loading) { return } if (error) { return } if (!ttsHistory || ttsHistory.length === 0) { return } return (
) } return (
setShowCreateDialog(true)} loading={loading} error={error} ttsCount={totalCount} /> {renderContent()}
) }