diff --git a/src/contexts/SocketContext.tsx b/src/contexts/SocketContext.tsx index d5e8003..a906f95 100644 --- a/src/contexts/SocketContext.tsx +++ b/src/contexts/SocketContext.tsx @@ -9,10 +9,12 @@ import { Socket, io } from 'socket.io-client' import { toast } from 'sonner' import { AUTH_EVENTS, + EXTRACTION_EVENTS, PLAYER_EVENTS, SOUND_EVENTS, USER_EVENTS, authEvents, + extractionEvents, playerEvents, soundEvents, userEvents, @@ -127,6 +129,10 @@ export function SocketProvider({ children }: SocketProviderProps) { newSocket.on('extraction_status_update', data => { const { extraction_id, status, title, error } = data + // Emit local event for other components to listen to + extractionEvents.emit(EXTRACTION_EVENTS.EXTRACTION_STATUS_UPDATED, data) + + // Handle specific status events switch (status) { case 'processing': toast.loading(`Extracting: ${title}`, { @@ -139,6 +145,7 @@ export function SocketProvider({ children }: SocketProviderProps) { toast.success(`Extraction complete: ${title}`, { duration: 4000, }) + extractionEvents.emit(EXTRACTION_EVENTS.EXTRACTION_COMPLETED, data) break case 'failed': toast.dismiss(`extraction-${extraction_id}`) @@ -146,6 +153,7 @@ export function SocketProvider({ children }: SocketProviderProps) { description: error, duration: 6000, }) + extractionEvents.emit(EXTRACTION_EVENTS.EXTRACTION_FAILED, data) break } }) diff --git a/src/lib/events.ts b/src/lib/events.ts index 814b1ff..524de72 100644 --- a/src/lib/events.ts +++ b/src/lib/events.ts @@ -36,6 +36,7 @@ export const authEvents = new EventEmitter() export const playerEvents = new EventEmitter() export const soundEvents = new EventEmitter() export const userEvents = new EventEmitter() +export const extractionEvents = new EventEmitter() // Auth event types export const AUTH_EVENTS = { @@ -60,3 +61,11 @@ export const SOUND_EVENTS = { export const USER_EVENTS = { USER_CREDITS_CHANGED: 'user_credits_changed', } as const + +// Extraction event types +export const EXTRACTION_EVENTS = { + EXTRACTION_STATUS_UPDATED: 'extraction_status_updated', + EXTRACTION_CREATED: 'extraction_created', + EXTRACTION_COMPLETED: 'extraction_completed', + EXTRACTION_FAILED: 'extraction_failed', +} as const diff --git a/src/pages/ExtractionsPage.tsx b/src/pages/ExtractionsPage.tsx index 79c576b..74216ca 100644 --- a/src/pages/ExtractionsPage.tsx +++ b/src/pages/ExtractionsPage.tsx @@ -15,7 +15,8 @@ import { type ExtractionStatus, extractionsService, } from '@/lib/api/services/extractions' -import { useEffect, useState } from 'react' +import { EXTRACTION_EVENTS, extractionEvents } from '@/lib/events' +import { useCallback, useEffect, useState } from 'react' import { toast } from 'sonner' export function ExtractionsPage() { @@ -51,7 +52,7 @@ export function ExtractionsPage() { return () => clearTimeout(handler) }, [searchQuery]) - const fetchExtractions = async () => { + const fetchExtractions = useCallback(async () => { try { setLoading(true) setError(null) @@ -74,11 +75,11 @@ export function ExtractionsPage() { } finally { setLoading(false) } - } + }, [debouncedSearchQuery, sortBy, sortOrder, statusFilter, currentPage, pageSize]) useEffect(() => { fetchExtractions() - }, [debouncedSearchQuery, sortBy, sortOrder, statusFilter, currentPage, pageSize]) + }, [fetchExtractions]) // Reset to page 1 when filters change useEffect(() => { @@ -87,6 +88,33 @@ export function ExtractionsPage() { } }, [debouncedSearchQuery, sortBy, sortOrder, statusFilter, pageSize]) + // Listen for extraction events to refresh the list + useEffect(() => { + const handleExtractionStatusUpdate = () => { + fetchExtractions() + } + + const handleExtractionCompleted = () => { + fetchExtractions() + } + + const handleExtractionFailed = () => { + fetchExtractions() + } + + // Subscribe to extraction events + extractionEvents.on(EXTRACTION_EVENTS.EXTRACTION_STATUS_UPDATED, handleExtractionStatusUpdate) + extractionEvents.on(EXTRACTION_EVENTS.EXTRACTION_COMPLETED, handleExtractionCompleted) + extractionEvents.on(EXTRACTION_EVENTS.EXTRACTION_FAILED, handleExtractionFailed) + + return () => { + // Cleanup event listeners + extractionEvents.off(EXTRACTION_EVENTS.EXTRACTION_STATUS_UPDATED, handleExtractionStatusUpdate) + extractionEvents.off(EXTRACTION_EVENTS.EXTRACTION_COMPLETED, handleExtractionCompleted) + extractionEvents.off(EXTRACTION_EVENTS.EXTRACTION_FAILED, handleExtractionFailed) + } + }, [fetchExtractions]) + const handlePageChange = (page: number) => { setCurrentPage(page) } @@ -112,6 +140,9 @@ export function ExtractionsPage() { setUrl('') setShowCreateDialog(false) + // Emit event for new extraction created + extractionEvents.emit(EXTRACTION_EVENTS.EXTRACTION_CREATED, response.extraction) + // Refresh the extractions list fetchExtractions() } catch (err) {