feat: Enhance analysis view and market ticker
Adds a "View History" button to the AnalysisView, allowing users to navigate directly to the signal history. Updates the MarketTicker component to fetch real-time data from Binance, displaying a dynamic list of cryptocurrency and forex tickers.
This commit is contained in:
+1
-1
@@ -619,7 +619,7 @@ export default function App() {
|
||||
exit={{ opacity: 0, x: -15 }}
|
||||
transition={{ duration: 0.25, ease: 'easeOut' }}
|
||||
>
|
||||
{activeTab === 'scan' && <AnalysisView userData={userData} />}
|
||||
{activeTab === 'scan' && <AnalysisView userData={userData} onGoToHistory={() => setActiveTab('history')} />}
|
||||
{activeTab === 'history' && <SignalHistory />}
|
||||
{activeTab === 'stats' && <DashboardStats />}
|
||||
{activeTab === 'profile' && <ProfileView user={user} userData={userData} onUpdate={setUserData} onDeleted={handleLogout} />}
|
||||
|
||||
@@ -9,7 +9,7 @@ import { ref, uploadBytes, getDownloadURL } from 'firebase/storage';
|
||||
import { storage, auth, db, handleFirestoreError, OperationType } from '../lib/firebase';
|
||||
import { collection, addDoc, serverTimestamp, query, where, getDocs, Timestamp } from 'firebase/firestore';
|
||||
|
||||
export const AnalysisView: React.FC<{ userData?: any }> = ({ userData }) => {
|
||||
export const AnalysisView: React.FC<{ userData?: any, onGoToHistory?: () => void }> = ({ userData, onGoToHistory }) => {
|
||||
const [file, setFile] = useState<File | null>(null);
|
||||
const [preview, setPreview] = useState<string | null>(null);
|
||||
const [isAnalyzing, setIsAnalyzing] = useState(false);
|
||||
@@ -456,12 +456,23 @@ export const AnalysisView: React.FC<{ userData?: any }> = ({ userData }) => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button
|
||||
onClick={reset}
|
||||
className="w-full py-3 text-zinc-600 hover:text-white font-black text-xs uppercase tracking-widest transition-colors"
|
||||
>
|
||||
NOVO SCAN INSTITUCIONAL
|
||||
</button>
|
||||
<div className="flex flex-col gap-2">
|
||||
<button
|
||||
onClick={reset}
|
||||
className="w-full py-3 text-zinc-600 hover:text-white font-black text-xs uppercase tracking-widest transition-colors"
|
||||
>
|
||||
NOVO SCAN INSTITUCIONAL
|
||||
</button>
|
||||
|
||||
{onGoToHistory && (
|
||||
<button
|
||||
onClick={onGoToHistory}
|
||||
className="w-full py-2 text-zinc-500 hover:text-white font-medium text-[10px] uppercase tracking-widest transition-colors"
|
||||
>
|
||||
Ver Histórico de Sinais
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</motion.div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -8,41 +8,66 @@ interface TickerItem {
|
||||
isUp: boolean;
|
||||
}
|
||||
|
||||
const BINANCE_SYMBOLS = [
|
||||
'BTCUSDT',
|
||||
'ETHUSDT',
|
||||
'SOLUSDT',
|
||||
'EURUSDT',
|
||||
'GBPUSDT',
|
||||
'AUDUSDT',
|
||||
'BNBUSDT',
|
||||
'XRPUSDT',
|
||||
];
|
||||
|
||||
export const MarketTicker: React.FC = () => {
|
||||
const [items, setItems] = useState<TickerItem[]>([
|
||||
{ symbol: 'EURUSD', price: '1.08542', change: '+0.12%', isUp: true },
|
||||
{ symbol: 'GBPUSD', price: '1.26410', change: '-0.05%', isUp: false },
|
||||
{ symbol: 'USDJPY', price: '151.420', change: '+0.25%', isUp: true },
|
||||
{ symbol: 'XAUUSD', price: '2345.12', change: '+0.84%', isUp: true },
|
||||
{ symbol: 'BTCUSD', price: '64240.5', change: '-1.20%', isUp: false },
|
||||
{ symbol: 'NAS100', price: '18240.2', change: '+0.45%', isUp: true },
|
||||
{ symbol: 'AUDUSD', price: '0.65120', change: '+0.08%', isUp: true },
|
||||
{ symbol: 'USDCAD', price: '1.35410', change: '-0.02%', isUp: false },
|
||||
]);
|
||||
const [items, setItems] = useState<TickerItem[]>(
|
||||
BINANCE_SYMBOLS.map(sym => ({
|
||||
symbol: sym.replace('USDT', ''),
|
||||
price: '...',
|
||||
change: '...',
|
||||
isUp: true
|
||||
}))
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const interval = setInterval(() => {
|
||||
setItems(prev => prev.map(item => {
|
||||
const changeVal = (Math.random() * 0.0002) - 0.0001;
|
||||
const newPrice = parseFloat(item.price) + parseFloat(item.price) * changeVal;
|
||||
return {
|
||||
...item,
|
||||
price: newPrice.toFixed(item.symbol.includes('JPY') ? 3 : 5)
|
||||
};
|
||||
}));
|
||||
}, 3000);
|
||||
return () => clearInterval(interval);
|
||||
const streams = BINANCE_SYMBOLS.map(s => `${s.toLowerCase()}@ticker`).join('/');
|
||||
const ws = new WebSocket(`wss://stream.binance.com:9443/ws/${streams}`);
|
||||
|
||||
ws.onmessage = (event) => {
|
||||
const data = JSON.parse(event.data);
|
||||
if (data && data.s && data.c && data.P) {
|
||||
setItems(prev => {
|
||||
const newItems = [...prev];
|
||||
const index = newItems.findIndex(item => item.symbol === data.s.replace('USDT', ''));
|
||||
if (index !== -1) {
|
||||
const currentPrice = parseFloat(data.c);
|
||||
const priceChangePercent = parseFloat(data.P);
|
||||
newItems[index] = {
|
||||
...newItems[index],
|
||||
price: currentPrice >= 1 ? currentPrice.toFixed(2) : currentPrice.toFixed(4),
|
||||
change: `${priceChangePercent >= 0 ? '+' : ''}${priceChangePercent.toFixed(2)}%`,
|
||||
isUp: priceChangePercent >= 0
|
||||
};
|
||||
}
|
||||
return newItems;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return () => {
|
||||
ws.close();
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="w-full bg-brand-dark/50 border-y border-white/5 py-2 overflow-hidden select-none">
|
||||
<div className="flex animate-marquee whitespace-nowrap">
|
||||
{[...items, ...items].map((item, idx) => (
|
||||
{[...items, ...items, ...items].map((item, idx) => (
|
||||
<div key={`${item.symbol}-${idx}`} className="flex items-center gap-6 px-8 border-r border-white/5 last:border-r-0">
|
||||
<span className="text-[10px] font-black tracking-widest text-zinc-400 uppercase">{item.symbol}</span>
|
||||
<span className="text-xs font-mono font-bold tabular-nums text-white">{item.price}</span>
|
||||
<div className={`flex items-center gap-1 text-[10px] font-black ${item.isUp ? 'text-green-500' : 'text-brand-red'}`}>
|
||||
{item.isUp ? <TrendingUp size={12} /> : <TrendingDown size={12} />}
|
||||
<div className={`flex items-center gap-1 text-[10px] font-black ${item.change !== '...' ? (item.isUp ? 'text-green-500' : 'text-brand-red') : 'text-zinc-500'}`}>
|
||||
{item.change !== '...' && (item.isUp ? <TrendingUp size={12} /> : <TrendingDown size={12} />)}
|
||||
{item.change}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user