SudhanvaD's picture
Upload 31 files
5400cf3 verified
import { useState, useEffect, useRef } from 'react'
import { useAuth0 } from '@auth0/auth0-react'
import { useNavigate } from 'react-router-dom'
import ChatInput from './components/chatinput'
import MessageBubble from './components/MessageBubble'
import './styles/App.css'
type Message = { role: 'user' | 'bot'; text: string }
type Session = { id: number; title: string; messages: Message[] }
function App() {
const { loginWithRedirect, logout, isAuthenticated } = useAuth0()
const navigate = useNavigate()
const [sidebarOpen, setSidebarOpen] = useState(true)
const [showPrompt, setShowPrompt] = useState(true)
const [sessions, setSessions] = useState<Session[]>([
{ id: 1, title: 'Session 1', messages: [] }
])
const [activeSessionId, setActiveSessionId] = useState(1)
const activeSession = sessions.find(s => s.id === activeSessionId) || sessions[0]
const videoRef = useRef<HTMLVideoElement>(null)
const handleSend = async (text: string) => {
const userMessage: Message = { role: 'user', text }
setSessions(prev =>
prev.map(session =>
session.id === activeSessionId
? { ...session, messages: [...session.messages, userMessage] }
: session
)
)
setShowPrompt(false)
try {
const res = await fetch('https://fintrack-backend-8dji.onrender.com/generate-strategy', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ user_input: text })
});
const data = await res.json()
const botText = data.strategy_code || data.error || 'Error: Empty response.'
const botMessage: Message = { role: 'bot', text: botText }
setSessions(prev =>
prev.map(session =>
session.id === activeSessionId
? { ...session, messages: [...session.messages, botMessage] }
: session
)
)
} catch (err) {
const errorMessage: Message = { role: 'bot', text: '鈿狅笍 Error: Failed to connect to server.' }
setSessions(prev =>
prev.map(session =>
session.id === activeSessionId
? { ...session, messages: [...session.messages, errorMessage] }
: session
)
)
}
}
const handleNewChat = () => {
const newId = sessions.length + 1
const newSession: Session = { id: newId, title: `Session ${newId}`, messages: [] }
setSessions(prev => [newSession, ...prev])
setActiveSessionId(newId)
setShowPrompt(true)
}
const suggestions = [
'Enter a stock trading strategy...',
'Backtest a moving average crossover...',
'Analyze S&P 500 signals...',
'Try a momentum-based portfolio...',
'Run a mean reversion strategy...',
'Backtest Bollinger Band breakouts...'
]
const [currentSuggestion, setCurrentSuggestion] = useState(suggestions[0])
useEffect(() => {
const interval = setInterval(() => {
setCurrentSuggestion(prev => {
let next = prev
while (next === prev) {
next = suggestions[Math.floor(Math.random() * suggestions.length)]
}
return next
})
}, 3000)
return () => clearInterval(interval)
}, [])
useEffect(() => {
const handleVisibility = () => {
if (videoRef.current) {
if (document.visibilityState === 'visible') {
videoRef.current.play().catch(() => {})
} else {
videoRef.current.pause()
}
}
}
document.addEventListener('visibilitychange', handleVisibility)
return () => {
document.removeEventListener('visibilitychange', handleVisibility)
}
}, [])
return (
<>
<video
ref={videoRef}
className="background-video"
autoPlay
loop
muted
playsInline
src="https://i.imgur.com/RCoLmZ9.mp4"
/>
<div className="app-container">
{sidebarOpen && (
<aside className="sidebar">
<div className="sidebar-header">
<img
src="/image.png"
alt="Collapse Sidebar"
className="sidebar-icon"
onClick={() => setSidebarOpen(false)}
/>
<h1 className="site-title">FinTrack</h1>
<img
src="/newchat.png"
alt="New Chat"
className="sidebar-icon"
onClick={handleNewChat}
/>
</div>
<div className="history-list">
{sessions.map(session => (
<div
key={session.id}
className={`history-item ${session.id === activeSessionId ? 'active' : ''}`}
onClick={() => setActiveSessionId(session.id)}
>
{session.title}
</div>
))}
</div>
</aside>
)}
{!sidebarOpen && (
<img
src="/opensidebar.png"
alt="Open Sidebar"
className="open-sidebar-button"
onClick={() => setSidebarOpen(true)}
/>
)}
<main className="main-panel">
<div className="top-ui-wrapper">
<div className="top-navbar">
<img
src="/Cropped_Image.png"
className="nav-logo"
alt="Logo"
onClick={() => navigate('/')}
/>
<span className="nav-link" onClick={() => navigate('/about')}>About</span>
<span className="nav-link" onClick={() => navigate('/about#founders')}>Founders</span>
</div>
<div className="auth-buttons">
{!isAuthenticated ? (
<>
<span className="auth-link" onClick={() => loginWithRedirect()}>Login</span>
<span
className="auth-link"
onClick={() =>
loginWithRedirect({ authorizationParams: { screen_hint: 'signup' } })
}
>
Sign Up
</span>
</>
) : (
<span className="auth-link" onClick={() => logout({ logoutParams: { returnTo: window.location.origin } })}>
Log Out
</span>
)}
</div>
</div>
{showPrompt && (
<div className="prompt-banner">
<h2 className="prompt-text fade-in">How can I help you?</h2>
<p className="suggestion-text">{currentSuggestion}</p>
</div>
)}
<div className="chat-area">
{activeSession.messages.map((msg, i) => (
<MessageBubble key={i} role={msg.role} text={msg.text} />
))}
</div>
<div className="chat-box-wrapper">
<ChatInput onSend={handleSend} />
</div>
</main>
</div>
</>
)
}
export default App