"use client" import React, { useEffect } from 'react' interface ScreenshotGalleryProps { screenshots: string[] symbol: string timeframes: string[] enlargedImage: string | null onImageClick: (src: string) => void onClose: () => void } export default function ScreenshotGallery({ screenshots, symbol, timeframes, enlargedImage, onImageClick, onClose }: ScreenshotGalleryProps) { // Handle ESC key to close enlarged image useEffect(() => { const handleKeyDown = (event: KeyboardEvent) => { if (event.key === 'Escape' && enlargedImage) { onClose() } } if (enlargedImage) { document.addEventListener('keydown', handleKeyDown) return () => document.removeEventListener('keydown', handleKeyDown) } }, [enlargedImage, onClose]) if (screenshots.length === 0) return null // Utility function to convert timeframe to sortable number const timeframeToMinutes = (timeframe: string): number => { const tf = timeframe.toLowerCase() if (tf.includes('5m') || tf === '5') return 5 if (tf.includes('15m') || tf === '15') return 15 if (tf.includes('30m') || tf === '30') return 30 if (tf.includes('1h') || tf === '60') return 60 if (tf.includes('2h') || tf === '120') return 120 if (tf.includes('4h') || tf === '240') return 240 if (tf.includes('1d') || tf === 'D') return 1440 // Default fallback return parseInt(tf) || 999 } // Extract timeframe from filename const extractTimeframeFromFilename = (filename: string) => { const match = filename.match(/_(\d+|D)_/) if (!match) return 'Unknown' const tf = match[1] if (tf === 'D') return '1D' if (tf === '5') return '5m' if (tf === '15') return '15m' if (tf === '30') return '30m' if (tf === '60') return '1h' if (tf === '120') return '2h' if (tf === '240') return '4h' return `${tf}m` } // Helper function to detect layout from filename const detectLayout = (filename: string) => { if (filename.includes('_ai_')) return 'AI' if (filename.includes('_diy_') || filename.includes('_Diy module_')) return 'DIY' return 'Default' } // Create screenshot data with layout and timeframe information const screenshotData = screenshots.map((screenshot, index) => { const screenshotUrl = typeof screenshot === 'string' ? screenshot : (screenshot as any)?.url || String(screenshot) const filename = screenshotUrl.split('/').pop() || '' const timeframe = timeframes[index] || extractTimeframeFromFilename(filename) const layout = detectLayout(filename) return { screenshot, screenshotUrl, filename, timeframe, layout, index, sortOrder: timeframeToMinutes(timeframe) } }) // Group screenshots by layout const aiScreenshots = screenshotData .filter(item => item.layout === 'AI') .sort((a, b) => a.sortOrder - b.sortOrder) const diyScreenshots = screenshotData .filter(item => item.layout === 'DIY') .sort((a, b) => a.sortOrder - b.sortOrder) const defaultScreenshots = screenshotData .filter(item => item.layout === 'Default') .sort((a, b) => a.sortOrder - b.sortOrder) // Helper function to format screenshot URL const formatScreenshotUrl = (screenshot: string | any) => { // Handle both string URLs and screenshot objects const screenshotUrl = typeof screenshot === 'string' ? screenshot : screenshot.url || screenshot // Extract just the filename from the full path const filename = screenshotUrl.split('/').pop() || screenshotUrl // Use the new API route with query parameter return `/api/image?file=${filename}` } // Helper function to render a screenshot row const renderScreenshotRow = (screenshots: any[], title: string, icon: string, bgGradient: string) => { if (screenshots.length === 0) return null return (
{icon} {title}
{screenshots.length} screenshot{screenshots.length !== 1 ? 's' : ''}
{screenshots.map((item, displayIndex) => { const imageUrl = formatScreenshotUrl(item.screenshot) return (
onImageClick(imageUrl)} > {/* Preview Image */}
{`${symbol} { const target = e.target as HTMLImageElement target.style.display = 'none' const fallback = target.nextElementSibling as HTMLElement if (fallback) fallback.classList.remove('hidden') }} />
📊
Chart Preview
{item.filename}
{/* Overlay */}
🔍
{/* Image Info */}
{symbol}
{item.timeframe} Timeframe
Click to view
) })}
) } return ( <> {/* Gallery Grid */}

📸 Chart Screenshots

{screenshotData.length} captured • Click to enlarge
{/* AI Layout Row */} {renderScreenshotRow( aiScreenshots, 'AI Layout - RSI, EMAs, MACD', '🤖', 'from-blue-500/30 to-cyan-500/30' )} {/* DIY Layout Row */} {renderScreenshotRow( diyScreenshots, 'DIY Module Layout - Stochastic RSI, VWAP, OBV', '🔧', 'from-orange-500/30 to-yellow-500/30' )} {/* Default Layout Row (if any) */} {renderScreenshotRow( defaultScreenshots, 'Default Layout', '📊', 'from-purple-500/30 to-indigo-500/30' )} {/* No Screenshots Message */} {screenshotData.length === 0 && (
📊
No screenshots available
)}
{/* Enlarged Image Modal */} {enlargedImage && (
e.stopPropagation()}> {/* Close Button */} {/* Image */} Enlarged chart { console.error('Failed to load enlarged image:', enlargedImage) const target = e.target as HTMLImageElement target.alt = 'Failed to load image' }} /> {/* Image Info Overlay */}
{symbol} Chart Analysis
AI analyzed screenshot • High resolution view
ESC to close • Click outside to close
)} ) }