import React,{useState,useMemo,useTransition,useEffect}from'react';interface BulkJob{id:string;operation:string;object:string;status:'Queued'|'InProgress'|'Completed'|'Failed';recordsProcessed:number;recordsFailed:number;createdDate: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 mockJobs:BulkJob[]=[{id:'job001',operation:'Insert',object:'Account',status:'Completed',recordsProcessed:1500,recordsFailed:3,createdDate:'2025-02-13'},{id:'job002',operation:'Update',object:'Contact',status:'InProgress',recordsProcessed:850,recordsFailed:0,createdDate:'2025-02-13'},{id:'job003',operation:'Delete',object:'Lead',status:'Failed',recordsProcessed:0,recordsFailed:120,createdDate:'2025-02-12'},{id:'job004',operation:'Upsert',object:'Opportunity',status:'Queued',recordsProcessed:0,recordsFailed:0,createdDate:'2025-02-12'}];const App:React.FC=()=>{const[searchQuery,setSearchQuery]=useState('');const[statusFilter,setStatusFilter]=useState<string>('All');const[isPending,startTransition]=useTransition();const{toasts,show}=useToast();const debouncedSearch=useDebounce(searchQuery,300);const filteredJobs=useMemo(()=>{return mockJobs.filter(job=>{const matchesSearch=job.object.toLowerCase().includes(debouncedSearch.toLowerCase());const matchesStatus=statusFilter==='All'||job.status===statusFilter;return matchesSearch&&matchesStatus})},[debouncedSearch,statusFilter]);const stats=useMemo(()=>({total:mockJobs.length,completed:mockJobs.filter(j=>j.status==='Completed').length,inProgress:mockJobs.filter(j=>j.status==='InProgress').length,failed:mockJobs.filter(j=>j.status==='Failed').length}),[]);const handleSearch=(e:React.ChangeEvent<HTMLInputElement>)=>{startTransition(()=>{setSearchQuery(e.target.value)})};const handleViewJob=(job:BulkJob)=>{show(`Viewing job ${job.id}`)};return(<div className="app-container"><header className="app-header"><h1>Bulk Operations</h1><p>Bulk job manager, upload data, check status</p></header><div className="stats-grid"><div className="stat-card"><div className="stat-label">Total Jobs</div><div className="stat-value">{stats.total}</div></div><div className="stat-card"><div className="stat-label">Completed</div><div className="stat-value">{stats.completed}</div></div><div className="stat-card"><div className="stat-label">In Progress</div><div className="stat-value">{stats.inProgress}</div></div><div className="stat-card"><div className="stat-label">Failed</div><div className="stat-value">{stats.failed}</div></div></div><div className="controls"><input type="text" placeholder="Search by object..." value={searchQuery} onChange={handleSearch} className="search-input"/><select value={statusFilter} onChange={e=>setStatusFilter(e.target.value)} className="filter-select"><option value="All">All Status</option><option value="Queued">Queued</option><option value="InProgress">In Progress</option><option value="Completed">Completed</option><option value="Failed">Failed</option></select></div>{filteredJobs.length===0?(<div className="empty-state"><div className="empty-icon">⚙️</div><h3>No jobs found</h3><p>Try adjusting your filters</p></div>):(<div className="data-grid"><table><thead><tr><th>Job ID</th><th>Operation</th><th>Object</th><th>Status</th><th>Processed</th><th>Failed</th><th>Created</th><th>Actions</th></tr></thead><tbody className={isPending?'loading':''}>{filteredJobs.map(job=>(<tr key={job.id}><td><strong>{job.id}</strong></td><td>{job.operation}</td><td>{job.object}</td><td><span className={`badge badge-${job.status.toLowerCase()}`}>{job.status}</span></td><td>{job.recordsProcessed}</td><td>{job.recordsFailed}</td><td>{job.createdDate}</td><td><button className="btn-primary" onClick={()=>handleViewJob(job)}>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;
