Spaces:
Running
Running
| import { useState, useEffect } from 'react'; | |
| import axios from 'axios'; | |
| import { Calendar, RefreshCw } from 'lucide-react'; | |
| import ClusterCard from './ClusterCard'; | |
| import { cn } from '../lib/utils'; | |
| import { motion } from 'framer-motion'; | |
| export default function Aggregator() { | |
| const [data, setData] = useState(null); | |
| const [loading, setLoading] = useState(true); | |
| const [error, setError] = useState(null); | |
| const [selectedDayIndex, setSelectedDayIndex] = useState(0); | |
| useEffect(() => { | |
| fetchData(); | |
| }, []); | |
| const fetchData = async () => { | |
| try { | |
| setLoading(true); | |
| setError(null); | |
| const response = await axios.get('/api/clusters'); | |
| // Sort daysdescending just in case or keep as valid from API | |
| // API returns top 3 days. We'll use them as is. | |
| setData(response.data); | |
| } catch (err) { | |
| console.error(err); | |
| setError("Failed to load clusters. Please try again."); | |
| } finally { | |
| setLoading(false); | |
| } | |
| }; | |
| if (loading) { | |
| return ( | |
| <div className="flex flex-col items-center justify-center py-20 text-slate-500"> | |
| <RefreshCw className="w-8 h-8 animate-spin mb-4 text-blue-500" /> | |
| <p>Loading intelligence stream...</p> | |
| </div> | |
| ); | |
| } | |
| if (error) { | |
| return ( | |
| <div className="text-center py-20 text-red-400 bg-red-900/10 rounded-xl border border-red-900/20"> | |
| <p className="mb-4">{error}</p> | |
| <button | |
| onClick={fetchData} | |
| className="px-4 py-2 bg-red-600 text-white rounded-lg hover:bg-red-500 transition-colors" | |
| > | |
| Retry | |
| </button> | |
| </div> | |
| ); | |
| } | |
| if (!data || data.length === 0) { | |
| return <div className="text-center py-20 text-slate-500">No data available.</div>; | |
| } | |
| const currentDay = data[selectedDayIndex]; | |
| return ( | |
| <div className="space-y-6"> | |
| {/* Day Tabs */} | |
| <div className="flex justify-center gap-4"> | |
| {data.map((dayItem, index) => ( | |
| <button | |
| key={dayItem.date} | |
| onClick={() => setSelectedDayIndex(index)} | |
| className={cn( | |
| "flex flex-col items-center p-3 rounded-xl border transition-all duration-300 w-32", | |
| selectedDayIndex === index | |
| ? "bg-slate-800 border-blue-500/50 shadow-lg shadow-blue-500/10 text-white" | |
| : "bg-slate-900/50 border-slate-800 text-slate-400 hover:bg-slate-800 hover:border-slate-700" | |
| )} | |
| > | |
| <span className="text-xs font-medium uppercase tracking-wider text-slate-500 mb-1"> | |
| {new Date(dayItem.date).toLocaleDateString(undefined, { weekday: 'short' })} | |
| </span> | |
| <span className="text-lg font-bold"> | |
| {new Date(dayItem.date).toLocaleDateString(undefined, { day: '2-digit', month: 'short' })} | |
| </span> | |
| </button> | |
| ))} | |
| </div> | |
| {/* Stats for the day */} | |
| <div className="flex items-center justify-between px-4 pb-2 text-slate-400 text-sm border-b border-slate-800"> | |
| <div className="flex items-center gap-2"> | |
| <Calendar className="w-4 h-4" /> | |
| <span>Events for {new Date(currentDay.date).toLocaleDateString()}</span> | |
| </div> | |
| <div> | |
| {currentDay.clusters.length} Event Clusters | |
| </div> | |
| </div> | |
| {/* Clusters Grid */} | |
| <div className="grid grid-cols-1 md:grid-cols-1 gap-4"> | |
| {currentDay.clusters.map((cluster) => ( | |
| <ClusterCard key={cluster.cluster_id} cluster={cluster} /> | |
| ))} | |
| </div> | |
| </div> | |
| ); | |
| } | |