import React,{useState,useMemo,useTransition,useEffect}from'react';interface Dashboard{id:string;name:string;folder:string;components:number;lastViewed:string}const useDebounce=<T,>(value:T,delay:number):T=>{const[debouncedValue,setDebouncedValue]=useState(value);useEffect(()=>{const handler=setTimeout(()=>setDebouncedValue(value),delay);return()=>clearTimeout(handler)},[value,delay]);return debouncedValue};const useToast=()=>{const[toasts,setToasts]=useState<Array<{id:number;message:string}>>([]);const show=(message:string)=>{const id=Date.now();setToasts(prev=>[...prev,{id,message}]);setTimeout(()=>setToasts(prev=>prev.filter(t=>t.id!==id)),3000)};return{toasts,show}};const mockDashboards:Dashboard[]=[{id:'d001',name:'Sales Dashboard',folder:'Sales',components:8,lastViewed:'2025-02-13'},{id:'d002',name:'Executive Overview',folder:'Executive',components:12,lastViewed:'2025-02-12'},{id:'d003',name:'Service Metrics',folder:'Service',components:6,lastViewed:'2025-02-11'},{id:'d004',name:'Marketing ROI',folder:'Marketing',components:10,lastViewed:'2025-02-10'}];const App:React.FC=()=>{const[searchQuery,setSearchQuery]=useState('');const[isPending,startTransition]=useTransition();const{toasts,show}=useToast();const debouncedSearch=useDebounce(searchQuery,300);const filteredDashboards=useMemo(()=>{return mockDashboards.filter(d=>d.name.toLowerCase().includes(debouncedSearch.toLowerCase())||d.folder.toLowerCase().includes(debouncedSearch.toLowerCase()))},[debouncedSearch]);const stats=useMemo(()=>({total:mockDashboards.length,avgComponents:Math.round(mockDashboards.reduce((sum,d)=>sum+d.components,0)/mockDashboards.length),totalComponents:mockDashboards.reduce((sum,d)=>sum+d.components,0)}),[]);const handleSearch=(e:React.ChangeEvent<HTMLInputElement>)=>{startTransition(()=>{setSearchQuery(e.target.value)})};const handleView=(dashboard:Dashboard)=>{show(`Viewing ${dashboard.name}`)};return(<div className="app-container"><header className="app-header"><h1>Dashboard Viewer</h1><p>Dashboard components and charts</p></header><div className="stats-grid"><div className="stat-card"><div className="stat-label">Total Dashboards</div><div className="stat-value">{stats.total}</div></div><div className="stat-card"><div className="stat-label">Avg Components</div><div className="stat-value">{stats.avgComponents}</div></div><div className="stat-card"><div className="stat-label">Total Components</div><div className="stat-value">{stats.totalComponents}</div></div></div><div className="controls"><input type="text" placeholder="Search dashboards..." value={searchQuery} onChange={handleSearch} className="search-input"/></div>{filteredDashboards.length===0?(<div className="empty-state"><div className="empty-icon">📈</div><h3>No dashboards found</h3><p>Try adjusting your search</p></div>):(<div className="data-grid"><table><thead><tr><th>Dashboard Name</th><th>Folder</th><th>Components</th><th>Last Viewed</th><th>Actions</th></tr></thead><tbody className={isPending?'loading':''}>{filteredDashboards.map(d=>(<tr key={d.id}><td><strong>{d.name}</strong></td><td>{d.folder}</td><td>{d.components}</td><td>{d.lastViewed}</td><td><button className="btn-primary" onClick={()=>handleView(d)}>View</button></td></tr>))}</tbody></table></div>)}<div className="toast-container">{toasts.map(toast=>(<div key={toast.id} className="toast">{toast.message}</div>))}</div></div>)};export default App;
