import { useState, useRef, useEffect } from 'react' // ── Types & Mock Data ── interface MediaFile { id: number incident: string location: string filename: string equipment: string equipType: 'drone' | 'plane' | 'satellite' mediaType: '사진' | '영상' | '적외선' | 'SAR' | '가시광' | '광학' datetime: string size: string resolution: string } const mediaFiles: MediaFile[] = [ { id: 1, incident: '여수 유조선 충돌', location: '34.73°N, 127.68°E', filename: '여수항_드론_001.jpg', equipment: 'DJI M300', equipType: 'drone', mediaType: '사진', datetime: '2026-01-18 15:20', size: '12.4 MB', resolution: '5472×3648' }, { id: 2, incident: '여수 유조선 충돌', location: '34.73°N, 127.68°E', filename: '여수항_드론_002.jpg', equipment: 'DJI M300', equipType: 'drone', mediaType: '사진', datetime: '2026-01-18 15:21', size: '11.8 MB', resolution: '5472×3648' }, { id: 3, incident: '여수 유조선 충돌', location: '34.73°N, 127.68°E', filename: '여수항_드론_003.jpg', equipment: 'DJI M300', equipType: 'drone', mediaType: '사진', datetime: '2026-01-18 15:22', size: '13.1 MB', resolution: '5472×3648' }, { id: 4, incident: '여수 유조선 충돌', location: '34.73°N, 127.68°E', filename: '여수항_드론_004.jpg', equipment: 'DJI M300', equipType: 'drone', mediaType: '사진', datetime: '2026-01-18 15:23', size: '12.9 MB', resolution: '5472×3648' }, { id: 5, incident: '여수 유조선 충돌', location: '34.73°N, 127.68°E', filename: '여수항_드론_005.jpg', equipment: 'Mavic3', equipType: 'drone', mediaType: '사진', datetime: '2026-01-18 15:24', size: '11.5 MB', resolution: '5472×3648' }, { id: 6, incident: '여수 유조선 충돌', location: '34.73°N, 127.68°E', filename: '여수항_드론_006.jpg', equipment: 'Mavic3', equipType: 'drone', mediaType: '사진', datetime: '2026-01-18 15:25', size: '13.3 MB', resolution: '5472×3648' }, { id: 7, incident: '여수 유조선 충돌', location: '34.73°N, 127.68°E', filename: '여수항_드론영상_01.mp4', equipment: 'DJI M300', equipType: 'drone', mediaType: '영상', datetime: '2026-01-18 15:30', size: '842 MB', resolution: '4K 30fps' }, { id: 8, incident: '여수 유조선 충돌', location: '34.73°N, 127.68°E', filename: '여수항_드론영상_02.mp4', equipment: 'Mavic3', equipType: 'drone', mediaType: '영상', datetime: '2026-01-18 16:00', size: '624 MB', resolution: '4K 30fps' }, { id: 9, incident: '여수 유조선 충돌', location: '34.73°N, 127.68°E', filename: '여수항_항공_광역_01.tif', equipment: 'CN-235', equipType: 'plane', mediaType: '적외선', datetime: '2026-01-18 14:00', size: '156 MB', resolution: '8192×6144' }, { id: 10, incident: '여수 유조선 충돌', location: '34.73°N, 127.68°E', filename: '여수항_항공_광역_02.tif', equipment: 'CN-235', equipType: 'plane', mediaType: '가시광', datetime: '2026-01-18 14:10', size: '148 MB', resolution: '8192×6144' }, { id: 11, incident: '여수 유조선 충돌', location: '34.73°N, 127.68°E', filename: '여수항_항공영상_01.mp4', equipment: 'B-512', equipType: 'plane', mediaType: '영상', datetime: '2026-01-18 14:30', size: '1.2 GB', resolution: 'FHD 60fps' }, { id: 12, incident: '여수 유조선 충돌', location: '34.73°N, 127.68°E', filename: 'Sentinel1_SAR_20260118.tif', equipment: 'Sentinel-1', equipType: 'satellite', mediaType: 'SAR', datetime: '2026-01-18 10:00', size: '420 MB', resolution: '10m/px' }, { id: 13, incident: '여수 유조선 충돌', location: '34.73°N, 127.68°E', filename: 'KompSat5_여수_20260118.tif', equipment: '다목적5호', equipType: 'satellite', mediaType: 'SAR', datetime: '2026-01-18 11:00', size: '380 MB', resolution: '1m/px' }, { id: 14, incident: '통영 해역 기름오염', location: '34.85°N, 128.43°E', filename: '통영_드론_001.jpg', equipment: 'Mavic3', equipType: 'drone', mediaType: '사진', datetime: '2026-01-18 09:30', size: '10.2 MB', resolution: '5472×3648' }, { id: 15, incident: '군산항 인근 오염', location: '35.97°N, 126.72°E', filename: '군산_항공촬영_01.tif', equipment: 'B-512', equipType: 'plane', mediaType: '가시광', datetime: '2026-01-18 13:00', size: '132 MB', resolution: '8192×6144' }, ] const equipIcon = (t: string) => t === 'drone' ? '🛸' : t === 'plane' ? '✈' : '🛰' const equipTagCls = (t: string) => t === 'drone' ? 'bg-[rgba(59,130,246,0.12)] text-primary-blue' : t === 'plane' ? 'bg-[rgba(34,197,94,0.12)] text-status-green' : 'bg-[rgba(168,85,247,0.12)] text-primary-purple' const mediaTagCls = (t: string) => t === '영상' ? 'bg-[rgba(239,68,68,0.12)] text-status-red' : 'bg-[rgba(234,179,8,0.12)] text-status-yellow' const FilterBtn = ({ label, active, onClick }: { label: string; active: boolean; onClick: () => void }) => ( ) // ── Component ── export function MediaManagement() { const [selectedIds, setSelectedIds] = useState>(new Set()) const [equipFilter, setEquipFilter] = useState('all') const [typeFilter, setTypeFilter] = useState>(new Set()) const [searchTerm, setSearchTerm] = useState('') const [sortBy, setSortBy] = useState('latest') const [showUpload, setShowUpload] = useState(false) const modalRef = useRef(null) useEffect(() => { const handler = (e: MouseEvent) => { if (modalRef.current && !modalRef.current.contains(e.target as Node)) { setShowUpload(false) } } if (showUpload) document.addEventListener('mousedown', handler) return () => document.removeEventListener('mousedown', handler) }, [showUpload]) const filtered = mediaFiles.filter(f => { if (equipFilter !== 'all' && f.equipType !== equipFilter) return false if (typeFilter.size > 0) { const isPhoto = !['영상'].includes(f.mediaType) const isVideo = f.mediaType === '영상' if (typeFilter.has('photo') && !isPhoto) return false if (typeFilter.has('video') && !isVideo) return false } if (searchTerm && !f.filename.toLowerCase().includes(searchTerm.toLowerCase())) return false return true }) const sorted = [...filtered].sort((a, b) => { if (sortBy === 'name') return a.filename.localeCompare(b.filename) if (sortBy === 'size') return parseFloat(b.size) - parseFloat(a.size) return b.datetime.localeCompare(a.datetime) }) const toggleId = (id: number) => { setSelectedIds(prev => { const next = new Set(prev) if (next.has(id)) { next.delete(id) } else { next.add(id) } return next }) } const toggleAll = () => { if (selectedIds.size === sorted.length) { setSelectedIds(new Set()) } else { setSelectedIds(new Set(sorted.map(f => f.id))) } } const toggleTypeFilter = (t: string) => { setTypeFilter(prev => { const next = new Set(prev) if (next.has(t)) { next.delete(t) } else { next.add(t) } return next }) } const droneCount = mediaFiles.filter(f => f.equipType === 'drone').length const planeCount = mediaFiles.filter(f => f.equipType === 'plane').length const satCount = mediaFiles.filter(f => f.equipType === 'satellite').length return (
{/* Filters */}
촬영 장비: setEquipFilter('all')} /> setEquipFilter('drone')} /> setEquipFilter('plane')} /> setEquipFilter('satellite')} /> 유형: toggleTypeFilter('photo')} /> toggleTypeFilter('video')} />
setSearchTerm(e.target.value)} className="px-3 py-1.5 bg-bg-0 border border-border rounded-sm text-text-1 font-korean text-[11px] outline-none w-40 focus:border-primary-cyan" />
{/* Summary Stats */}
{[ { icon: '📸', value: String(mediaFiles.length), label: '총 파일', color: 'text-primary-cyan' }, { icon: '🛸', value: String(droneCount), label: '드론', color: 'text-text-1' }, { icon: '✈', value: String(planeCount), label: '유인항공기', color: 'text-text-1' }, { icon: '🛰', value: String(satCount), label: '위성', color: 'text-text-1' }, { icon: '💾', value: '3.8 GB', label: '총 용량', color: 'text-text-1' }, ].map((s, i) => (
{s.icon}
{s.value}
{s.label}
))}
{/* File Table */}
{sorted.map(f => ( toggleId(f.id)} className={`border-b border-border/50 cursor-pointer transition-colors hover:bg-[rgba(255,255,255,0.02)] ${ selectedIds.has(f.id) ? 'bg-[rgba(6,182,212,0.06)]' : '' }`} > ))}
0} onChange={toggleAll} className="accent-primary-blue" /> 사고명 위치 파일명 장비 유형 촬영일시 용량 해상도 📥
e.stopPropagation()}> toggleId(f.id)} className="accent-primary-blue" /> {equipIcon(f.equipType)} {f.incident} {f.location} {f.filename} {f.equipment} {f.mediaType === '영상' ? '🎬' : '📷'} {f.mediaType} {f.datetime} {f.size} {f.resolution} e.stopPropagation()}>
{/* Bottom Actions */}
선택된 파일: {selectedIds.size}
{/* Upload Modal */} {showUpload && (
📤 영상·사진 업로드
📁
파일을 드래그하거나 클릭하여 업로드
JPG, TIFF, GeoTIFF, MP4, MOV 지원 · 최대 2GB