import{useState,useEffect}from "react"; import{useNavigate}from "react-router-dom"; import{getLeaderboard}from "./api"; import{FiFilter,FiTrendingUp,FiTrendingDown}from "react-icons/fi"; function Leaderboard(){const [stocks,setStocks] = useState([]);const [filteredStocks,setFilteredStocks] = useState([]);const [loading,setLoading] = useState(true);const [error,setError] = useState(null);const [selectedSector,setSelectedSector] = useState("all");const [sortBy,setSortBy] = useState("final_score");const [sortOrder,setSortOrder] = useState("desc");const navigate = useNavigate();useEffect(() => {loadLeaderboard();},[]);useEffect(() => {filterAndSort();},[stocks,selectedSector,sortBy,sortOrder]);const loadLeaderboard = async () =>{try{setLoading(true);const data = await getLeaderboard();setStocks(data)}catch (err){setError(err.message)}finally{setLoading(false)}}const filterAndSort = () =>{let filtered = [...stocks];// Filter by sector if (selectedSector !== "all"){filtered = filtered.filter(stock => stock.sector === selectedSector)}// Sort filtered.sort((a,b) => {const aVal = parseFloat(a[sortBy] || 0); const bVal = parseFloat(b[sortBy] || 0); return sortOrder === "desc" ? bVal - aVal : aVal - bVal;});setFilteredStocks(filtered)}const sectors = ["all",...new Set(stocks.map(s => s.sector))];const scoreCategories = [{key: "final_score",label: "Overall Score"},{key: "financial_score",label: "Financial Health"},{key: "profitability_score",label: "Profitability"},{key: "growth_score",label: "Growth"},{key: "momentum_score",label: "Momentum"},{key: "risk_score",label: "Risk"},];if (loading) return <div style={styles.container}>Loading...</div>;if (error) return <div style={styles.container}>Error:{error}</div>;return (<div style={styles.container}> <h1 style={styles.title}>MERCATO</h1> <h2 style={styles.subtitle}>Top Performers</h2> <p style={styles.description}>{filteredStocks.length} SECURITIES</p> {} <div style={styles.filters}> <div style={styles.filterGroup}> <FiFilter style={styles.icon} /> <select style={styles.select} value={selectedSector} onChange={(e) => setSelectedSector(e.target.value)} > {sectors.map(sector => (<option key={sector} value={sector}> {sector === "all" ? "All Sectors" : sector} </option>))} </select> </div> <div style={styles.filterGroup}> <select style={styles.select} value={sortBy} onChange={(e) => setSortBy(e.target.value)} > {scoreCategories.map(cat => (<option key={cat.key} value={cat.key}>{cat.label}</option>))} </select> </div> <button style={styles.sortButton} onClick={() => setSortOrder(sortOrder === "desc" ? "asc" : "desc")} > {sortOrder === "desc" ? <FiTrendingDown /> : <FiTrendingUp />} {sortOrder === "desc" ? " Highest First" : " Lowest First"} </button> </div> <div style={styles.tableContainer}> <table style={styles.table}> <thead> <tr style={styles.headerRow}> <th style={styles.th}>Rank</th> <th style={styles.th}>Logo</th> <th style={styles.th}>Ticker</th> <th style={styles.th}>Name</th> <th style={styles.th}>Sector</th> <th style={styles.th}>Score</th> </tr> </thead> <tbody> {filteredStocks.map((stock,index) => (<tr key={stock.ticker} style={styles.row} onClick={() => navigate(`/stock/${stock.ticker}`)} > <td style={styles.td}>{index + 1}</td> <td style={styles.td}> <img src={`https://logo.clearbit.com/${stock.ticker.toLowerCase()}.com`} alt={stock.ticker} style={styles.logo} onError={(e) => {e.target.style.display = "none";}} /> </td> <td style={{...styles.td,fontWeight: "bold"}}>{stock.ticker}</td> <td style={styles.td}>{stock.name}</td> <td style={styles.td}>{stock.sector}</td> <td style={{...styles.td,color: "#4CAF50",fontWeight: "bold"}}> {parseFloat(stock[sortBy]).toFixed(2)} </td> </tr>))} </tbody> </table> </div> </div>)}const styles ={container:{maxWidth:"1400px",margin: "0 auto",padding: "20px",paddingTop: "100px",backgroundColor: "#0a1a2f",minHeight: "100vh",color: "#ede8dd",},title:{fontSize:"48px",textAlign: "center",marginBottom: "10px",color: "#ede8dd"},subtitle:{fontSize:"36px",textAlign: "center",marginBottom: "10px",color: "#ede8dd"},description:{textAlign:"center",color: "#ede8dd",marginBottom: "30px",opacity: .8},filters:{display:"flex",gap: "20px",marginBottom: "30px",flexWrap: "wrap",justifyContent: "center",alignItems: "center",},filterGroup:{display:"flex",alignItems: "center",gap: "10px",},icon:{fontSize:"20px",},select:{backgroundColor:"rgba(237, 232, 221, 0.1)",color: "#ede8dd",border: "1px solid rgba(237, 232, 221, 0.3)",padding: "10px 16px",borderRadius: "8px",fontSize: "16px",cursor: "pointer",},sortButton:{backgroundColor:"rgba(237, 232, 221, 0.1)",color: "#ede8dd",border: "1px solid rgba(237, 232, 221, 0.3)",padding: "10px 20px",borderRadius: "8px",fontSize: "16px",cursor: "pointer",display: "flex",alignItems: "center",gap: "8px",},tableContainer:{overflowX:"auto"},table:{width:"100%",borderCollapse: "collapse"},headerRow:{backgroundColor:"rgba(237, 232, 221, 0.1)"},th:{padding:"16px",textAlign: "left",borderBottom: "2px solid rgba(237, 232, 221, 0.2)",fontWeight: "bold",color: "#ede8dd"},row:{cursor:"pointer",transition: "background-color 0.2s"},td:{padding:"16px",borderBottom: "1px solid rgba(237, 232, 221, 0.1)",color: "#ede8dd"},logo:{width:"32px",height: "32px",borderRadius: "50%",objectFit: "cover",},}; export default Leaderboard;{}
