import React, { useEffect, useState } from 'react'; import { Signal, SignalResult, SignalType } from '../types'; import { cn } from '../lib/utils'; import { Clock, TrendingUp, TrendingDown, ChevronDown, ChevronUp } from 'lucide-react'; import { collection, query, where, orderBy, onSnapshot } from 'firebase/firestore'; import { auth, db, handleFirestoreError, OperationType } from '../lib/firebase'; export const SignalHistory: React.FC = () => { const [signals, setSignals] = useState([]); const [loading, setLoading] = useState(true); const [startDate, setStartDate] = useState(''); const [endDate, setEndDate] = useState(''); const [expandedSignalIds, setExpandedSignalIds] = useState([]); useEffect(() => { if (!auth.currentUser) return; const q = query( collection(db, 'signals'), where('userId', '==', auth.currentUser.uid) ); // The onSnapshot listener below automatically handles updates // when data in Firestore changes. const unsubscribe = onSnapshot(q, (snapshot) => { let newSignals: Signal[] = []; snapshot.forEach((doc) => { newSignals.push({ id: doc.id, ...doc.data() } as Signal); }); newSignals.sort((a, b) => b.timestamp - a.timestamp); setSignals(newSignals); setLoading(false); }, (error) => { handleFirestoreError(error, OperationType.GET, 'signals'); setLoading(false); }); return () => { unsubscribe(); }; }, []); if (loading) { return (
); } const filteredSignals = signals.filter(signal => { if (!startDate && !endDate) return true; const signalDate = new Date(signal.timestamp); if (startDate) { const start = new Date(startDate); // We parse 'YYYY-MM-DD' dynamically. new Date('YYYY-MM-DD') returns midnight UTC. But let's be careful with local timezones. const [year, month, day] = startDate.split('-').map(Number); const localStart = new Date(year, month - 1, day, 0, 0, 0, 0); if (signalDate < localStart) return false; } if (endDate) { const [year, month, day] = endDate.split('-').map(Number); const localEnd = new Date(year, month - 1, day, 23, 59, 59, 999); if (signalDate > localEnd) return false; } return true; }); const toggleSignal = (id: string) => { setExpandedSignalIds(prev => prev.includes(id) ? prev.filter(i => i !== id) : [...prev, id] ); }; return (

Histórico de Sinais

setStartDate(e.target.value)} className="bg-transparent text-sm text-zinc-300 outline-none px-2 py-1 [color-scheme:dark]" /> - setEndDate(e.target.value)} className="bg-transparent text-sm text-zinc-300 outline-none px-2 py-1 [color-scheme:dark]" /> {(startDate || endDate) && ( )}
{filteredSignals.length} Sinais
{filteredSignals.length === 0 ? (
Nenhum sinal encontrado. Comece realizando um novo scan.
) : ( filteredSignals.map((signal) => { const isExpanded = expandedSignalIds.includes(signal.id); return (
toggleSignal(signal.id)} >
{signal.type === SignalType.BUY ? : }
Ativo / TF

{signal.pair} · {signal.timeframe}

Tipo

{signal.type}

Score

{signal.score}%

SL / TP

{signal.stopLoss} / {signal.takeProfit}

Data e Hora

{new Date(signal.timestamp).toLocaleString("pt-BR", { dateStyle: "short", timeStyle: "short" })}

Status
{signal.result === SignalResult.PENDING ? "Válido" : "Expirado"}
Resultado
{signal.result}
Detalhes
{isExpanded ? : }
{isExpanded && (
{signal.justification && (

Justificativa

{signal.justification}

)} {signal.analiseGeral && (

Análise Geral

{signal.analiseGeral}

)}
{signal.estrutura && (

Estrutura de Mercado

{signal.estrutura}

)} {signal.tecnica && (

Análise Técnica

{signal.tecnica}

)} {signal.fundamental && (

Análise Fundamental

{signal.fundamental}

)}
)}
); }) )}
); };