From 4f328fab480080939f0ea91aee8c21b85c06366b Mon Sep 17 00:00:00 2001 From: mindesbunister Date: Thu, 17 Jul 2025 11:25:11 +0200 Subject: [PATCH] feat: update timeframe presets and improve sorting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add 30m and 2h timeframes to available options - Update Scalping preset: 5m, 15m, 30m (was 5m, 15m, 1h) - Update Day Trading preset: 1h, 2h, 4h (was 1h, 4h, 1d) - Enhance sorting logic for screenshots and analysis results - Ensure consistent timeframe order: 5m → 15m → 30m → 1h → 2h → 4h → 1d - Improve multi-timeframe analysis display with proper sorting - Update filename parsing to handle new timeframes Changes improve trading workflow with more logical timeframe progressions for scalping and day trading strategies. --- components/AIAnalysisPanel.tsx | 67 +++++++++++++++++++++++--- components/ScreenshotGallery.tsx | 83 ++++++++++++++++++++++---------- 2 files changed, 116 insertions(+), 34 deletions(-) diff --git a/components/AIAnalysisPanel.tsx b/components/AIAnalysisPanel.tsx index ce3fb02..3600650 100644 --- a/components/AIAnalysisPanel.tsx +++ b/components/AIAnalysisPanel.tsx @@ -8,7 +8,9 @@ const timeframes = [ { label: '1m', value: '1' }, { label: '5m', value: '5' }, { label: '15m', value: '15' }, + { label: '30m', value: '30' }, { label: '1h', value: '60' }, + { label: '2h', value: '120' }, { label: '4h', value: '240' }, { label: '1d', value: 'D' }, { label: '1w', value: 'W' }, @@ -38,7 +40,6 @@ interface ProgressStep { } interface AnalysisProgress { - sessionId: string currentStep: number totalSteps: number steps: ProgressStep[] @@ -545,16 +546,16 @@ export default function AIAnalysisPanel({ onAnalysisComplete }: AIAnalysisPanelP
- {result.results.map((timeframeResult: any, index: number) => ( + {result.results + .sort((a: any, b: any) => { + // Sort by timeframe order: 5m, 15m, 30m, 1h, 2h, 4h, 1D + const timeframeOrder: {[key: string]: number} = { + '5': 1, '5m': 1, + '15': 2, '15m': 2, + '30': 3, '30m': 3, + '60': 4, '1h': 4, + '120': 5, '2h': 5, + '240': 6, '4h': 6, + 'D': 7, '1D': 7 + } + const orderA = timeframeOrder[a.timeframe] || timeframeOrder[a.timeframeLabel] || 999 + const orderB = timeframeOrder[b.timeframe] || timeframeOrder[b.timeframeLabel] || 999 + return orderA - orderB + }) + .map((timeframeResult: any, index: number) => (
r.success && r.result.screenshots).flatMap((r: any) => r.result.screenshots)} + screenshots={result.results + .filter((r: any) => r.success && r.result.screenshots) + .sort((a: any, b: any) => { + // Sort by timeframe order: 5m, 15m, 30m, 1h, 2h, 4h, 1D + const timeframeOrder: {[key: string]: number} = { + '5': 1, '5m': 1, + '15': 2, '15m': 2, + '30': 3, '30m': 3, + '60': 4, '1h': 4, + '120': 5, '2h': 5, + '240': 6, '4h': 6, + 'D': 7, '1D': 7 + } + const orderA = timeframeOrder[a.timeframe] || timeframeOrder[a.timeframeLabel] || 999 + const orderB = timeframeOrder[b.timeframe] || timeframeOrder[b.timeframeLabel] || 999 + return orderA - orderB + }) + .flatMap((r: any) => r.result.screenshots)} symbol={symbol} - timeframes={result.results.filter((r: any) => r.success).map((r: any) => r.timeframeLabel)} + timeframes={result.results + .filter((r: any) => r.success) + .sort((a: any, b: any) => { + // Sort by timeframe order: 5m, 15m, 30m, 1h, 2h, 4h, 1D + const timeframeOrder: {[key: string]: number} = { + '5': 1, '5m': 1, + '15': 2, '15m': 2, + '30': 3, '30m': 3, + '60': 4, '1h': 4, + '120': 5, '2h': 5, + '240': 6, '4h': 6, + 'D': 7, '1D': 7 + } + const orderA = timeframeOrder[a.timeframe] || timeframeOrder[a.timeframeLabel] || 999 + const orderB = timeframeOrder[b.timeframe] || timeframeOrder[b.timeframeLabel] || 999 + return orderA - orderB + }) + .map((r: any) => r.timeframeLabel)} enlargedImage={enlargedScreenshot} onImageClick={handleScreenshotClick} onClose={() => setEnlargedScreenshot(null)} diff --git a/components/ScreenshotGallery.tsx b/components/ScreenshotGallery.tsx index a156d85..07d6648 100644 --- a/components/ScreenshotGallery.tsx +++ b/components/ScreenshotGallery.tsx @@ -34,6 +34,56 @@ export default function ScreenshotGallery({ 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` + } + + // Create sorted screenshot data with timeframes + 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) + + return { + screenshot, + screenshotUrl, + filename, + timeframe, + index, + sortOrder: timeframeToMinutes(timeframe) + } + }) + + // Sort by timeframe (smallest to largest) + const sortedData = screenshotData.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 @@ -56,36 +106,17 @@ export default function ScreenshotGallery({ Chart Screenshots
- {screenshots.length} captured • Click to enlarge + {sortedData.length} captured • Click to enlarge
- {screenshots.map((screenshot, index) => { - // Handle both string URLs and screenshot objects - const screenshotUrl = typeof screenshot === 'string' - ? screenshot - : (screenshot as any)?.url || String(screenshot) - const filename = screenshotUrl.split('/').pop() || '' - // Extract timeframe from filename (e.g., SOLUSD_5_ai_timestamp.png -> "5m") - 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 === '60') return '1h' - if (tf === '240') return '4h' - return `${tf}m` - } - - const timeframe = timeframes[index] || extractTimeframeFromFilename(filename) - const imageUrl = formatScreenshotUrl(screenshot) + {sortedData.map((item, displayIndex) => { + const imageUrl = formatScreenshotUrl(item.screenshot) return (
onImageClick(imageUrl)} > @@ -93,7 +124,7 @@ export default function ScreenshotGallery({
{`${symbol} { const target = e.target as HTMLImageElement @@ -106,7 +137,7 @@ export default function ScreenshotGallery({
📊
Chart Preview
-
{filename}
+
{item.filename}
@@ -125,7 +156,7 @@ export default function ScreenshotGallery({
{symbol}
-
{timeframe} Timeframe
+
{item.timeframe} Timeframe
Click to view