import { useState, useEffect, useCallback } from 'react' import { useTranslation } from 'react-i18next' import { useFlight } from '../../components/FlightContext' import { api } from '../../api/client' import { useDebounce } from '../../hooks/useDebounce' import ConfirmDialog from '../../components/ConfirmDialog' import type { Media, PaginatedResponse, AnnotationListItem } from '../../types' interface Props { selectedMedia: Media | null onSelect: (m: Media) => void onAnnotationsLoaded: (anns: AnnotationListItem[]) => void } export default function MediaList({ selectedMedia, onSelect, onAnnotationsLoaded }: Props) { const { t } = useTranslation() const { selectedFlight } = useFlight() const [media, setMedia] = useState([]) const [filter, setFilter] = useState('') const debouncedFilter = useDebounce(filter, 300) const [deleteId, setDeleteId] = useState(null) const [dragging, setDragging] = useState(false) const fetchMedia = useCallback(async () => { const params = new URLSearchParams({ pageSize: '1000' }) if (selectedFlight) params.set('flightId', selectedFlight.id) if (debouncedFilter) params.set('name', debouncedFilter) try { const res = await api.get>(`/api/annotations/media?${params}`) setMedia(res.items) } catch {} }, [selectedFlight, debouncedFilter]) useEffect(() => { fetchMedia() }, [fetchMedia]) const handleSelect = async (m: Media) => { onSelect(m) try { const res = await api.get>( `/api/annotations/annotations?mediaId=${m.id}&pageSize=1000` ) onAnnotationsLoaded(res.items) } catch {} } const handleDelete = async () => { if (!deleteId) return await api.delete(`/api/annotations/media/${deleteId}`) setDeleteId(null) fetchMedia() } const handleDrop = async (e: React.DragEvent) => { e.preventDefault() setDragging(false) if (!selectedFlight || !e.dataTransfer.files.length) return const form = new FormData() form.append('waypointId', '') for (const file of e.dataTransfer.files) form.append('files', file) await api.upload('/api/annotations/media/batch', form) fetchMedia() } const handleFileUpload = async (e: React.ChangeEvent) => { if (!e.target.files?.length) return const form = new FormData() form.append('waypointId', '') for (const file of e.target.files) form.append('files', file) await api.upload('/api/annotations/media/batch', form) fetchMedia() e.target.value = '' } return (
{ e.preventDefault(); setDragging(true) }} onDragLeave={() => setDragging(false)} onDrop={handleDrop} >
setFilter(e.target.value)} placeholder={t('annotations.mediaList')} className="flex-1 bg-az-bg border border-az-border rounded px-2 py-1 text-xs text-az-text outline-none" />
{media.map(m => (
handleSelect(m)} onContextMenu={e => { e.preventDefault(); setDeleteId(m.id) }} className={`px-2 py-1 cursor-pointer border-b border-az-border text-xs flex items-center gap-1.5 ${ selectedMedia?.id === m.id ? 'bg-az-bg text-white' : '' } ${m.annotationCount > 0 ? 'bg-az-bg/50' : ''} text-az-text hover:bg-az-bg`} > {m.mediaType === 2 ? 'V' : 'P'} {m.name} {m.duration && {m.duration}}
))}
setDeleteId(null)} />
) }