import { useState, useEffect } from 'react' import './App.css' const API_BASE = (import.meta.env.VITE_API_URL || 'https://vycka12-binance-data-backend.hf.space') + '/api'; function App() { const [symbols, setSymbols] = useState(['BTC/USDT']); const [selectedSymbol, setSelectedSymbol] = useState('BTC/USDT'); const [interval, setInterval] = useState('1m'); const [dataType, setDataType] = useState('Klines (OHLCV)'); // Date setup (last 7 days default) const defaultEnd = new Date().toISOString().split('T')[0]; const defaultStart = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString().split('T')[0]; const [startDate, setStartDate] = useState(defaultStart); const [endDate, setEndDate] = useState(defaultEnd); // Status and data const [loading, setLoading] = useState(false); const [error, setError] = useState(null); const [successMsg, setSuccessMsg] = useState(null); const [previewData, setPreviewData] = useState([]); const [csvData, setCsvData] = useState(null); const [modalCmd, setModalCmd] = useState(null); const [dollarThreshold, setDollarThreshold] = useState(1000000); const [aggMode, setAggMode] = useState('Standard (Klines + Liq)'); // Progress simulation (since real SSE would require more backend work) const [progress, setProgress] = useState(0); const intervals = ['1s', '1m', '3m', '5m', '15m', '30m', '1h', '2h', '4h', '6h', '8h', '12h', '1d', '3d', '1w', '1mo']; const dataTypes = ['Klines (OHLCV)', 'Liquidations', 'AggTrades', 'Dollar Bars (ML Ready)', 'VPIN (Flow Toxicity)', 'Time-Series Aggregator (Cloud)']; useEffect(() => { fetch(`${API_BASE}/symbols`) .then(res => res.json()) .then(data => { if (data.symbols && data.symbols.length > 0) { setSymbols(data.symbols); if (data.symbols.includes('BTC/USDT')) { setSelectedSymbol('BTC/USDT'); } else { setSelectedSymbol(data.symbols[0]); } } }) .catch(err => console.error("Error fetching symbols:", err)); }, []); // Simulate progress bar — slower for bigger date ranges useEffect(() => { let intervalId; if (loading && progress < 90) { const start = new Date(startDate); const end = new Date(endDate); const daysDiff = Math.max(1, (end - start) / (1000 * 60 * 60 * 24)); // Slower increments for bigger date ranges const increment = daysDiff > 365 ? 0.5 : daysDiff > 30 ? 2 : 10; intervalId = window.setInterval(() => { setProgress(p => Math.min(p + Math.random() * increment, 90)); }, 1000); } else if (!loading && progress > 0 && progress < 100) { setProgress(100); setTimeout(() => setProgress(0), 1000); } return () => clearInterval(intervalId); }, [loading, progress, startDate, endDate]); const handleDownload = async () => { setLoading(true); setError(null); setSuccessMsg(null); setPreviewData([]); setCsvData(null); setModalCmd(null); setProgress(2); try { const response = await fetch(`${API_BASE}/download`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ symbol: selectedSymbol, interval: interval, data_type: dataType, start_date: startDate, end_date: endDate, threshold: dollarThreshold, agg_mode: aggMode }) }); const result = await response.json(); if (!response.ok) { throw new Error(result.detail || "Įvyko nežinoma klaida"); } if (result.success) { let msg = `✅ Apdorojimas baigtas! Iš viso: ${result.row_count} eilučių.`; if (result.hf_url) { msg += ` Failas automatiškai įkeltas į Hugging Face!`; } setSuccessMsg(msg); setPreviewData(result.preview); setCsvData(result.csv_data); if (result.hf_url) { // You could also store this URL in state if you want to show a dedicated button console.log("HF URL:", result.hf_url); } } else { setError(result.message || "Duomenų nerasta."); } } catch (err) { setError(`❌ Klaida: ${err.message}`); } finally { setLoading(false); } }; const downloadCsvFile = () => { if (!csvData) return; const blob = new Blob([csvData], { type: 'text/csv;charset=utf-8;' }); const url = window.URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `${selectedSymbol.replace('/', '_')}_${dataType.split(' ')[0]}_${startDate}_${endDate}.csv`; document.body.appendChild(a); a.click(); document.body.removeChild(a); window.URL.revokeObjectURL(url); }; return (
{/* Sidebar */} {/* Main Content */}

📊 Binance {dataType} Dashboard

Simbolis: {selectedSymbol}
Intervalas: {interval}
Laikotarpis: {startDate} iki {endDate}
{loading ? (

Kraunami duomenys...

Apdorojama: {dataType}

{(() => { const days = Math.max(1, (new Date(endDate) - new Date(startDate)) / (1000 * 60 * 60 * 24)); if (days > 365) return ⏱️ Didelis laikotarpis ({Math.round(days / 365)} m.) — gali užtrukti 2-5 min.; if (days > 30) return ⏱️ ~{Math.round(days / 30)} mėn. duomenų — gali užtrukti ~1-2 min.; return null; })()}
) : ( <> {error &&
{error}
} {successMsg &&
{successMsg}
} {modalCmd && (
🌩️ Modal Cloud Data Processing Ši funkcija skirta didelių duomenų kiekių apjungimui (2+ metai). Vykdykite terminale:
{modalCmd}
)} {!modalCmd && previewData.length > 0 ? ( <>

Duomenų peržiūra (Paskutinės 100 eilučių)

{Object.keys(previewData[0]).map(key => ( ))} {previewData.map((row, i) => ( {Object.values(row).map((val, j) => ( ))} ))}
{key}
{val}
) : ( !error && !loading && !modalCmd && (
Pasirinkite nustatymus ir spauskite "Vykdyti", kad atsisiųstumėte duomenis.
) )} )}
) } export default App