"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 if (tf.includes('1w') || tf === 'W') return 10080 if (tf.includes('1M') || tf === 'M') return 43200 // Default fallback return parseInt(tf) || 999 } // Extract timeframe from filename const extractTimeframeFromFilename = (filename: string) => { // First try to match the pattern _timeframe_ const match = filename.match(/_(\d+|D|W|M)_/) if (match) { const tf = match[1] if (tf === 'D') return '1d' if (tf === 'W') return '1w' if (tf === 'M') return '1M' 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` } // Try to match timeframe patterns anywhere in the filename const timeframePatterns = [ { pattern: /5m|_5_/i, value: '5m' }, { pattern: /15m|_15_/i, value: '15m' }, { pattern: /30m|_30_/i, value: '30m' }, { pattern: /1h|60m|_60_/i, value: '1h' }, { pattern: /2h|120m|_120_/i, value: '2h' }, { pattern: /4h|240m|_240_/i, value: '4h' }, { pattern: /1d|daily|_D_/i, value: '1d' }, { pattern: /1w|weekly|_W_/i, value: '1w' }, { pattern: /1M|monthly|_M_/i, value: '1M' } ] for (const { pattern, value } of timeframePatterns) { if (pattern.test(filename)) { return value } } return 'Unknown' } // 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() || '' // Extract timeframe from filename first, then use timeframes array as fallback const extractedTimeframe = extractTimeframeFromFilename(filename) const timeframe = extractedTimeframe !== 'Unknown' ? extractedTimeframe : (timeframes[index] || extractedTimeframe) 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
)} ) }