← back to Ken
react-dash/src/setup/steps/IngestMarkets.jsx
95 lines
import React, { useState, useEffect } from 'react';
import { post } from '../../api';
export default function IngestMarkets({ data, update, next, back }) {
const [loading, setLoading] = useState(true);
const [result, setResult] = useState(null);
const [error, setError] = useState(null);
useEffect(() => {
runIngest();
}, []);
async function runIngest() {
setLoading(true);
setError(null);
try {
const r = await post('/markets', { action: 'ingest' });
setResult(r);
update({ marketsIngested: r.ingested || r.markets?.length || 0 });
} catch (err) {
setError('Failed to ingest markets');
}
setLoading(false);
}
return (
<div className="space-y-6">
<div className="text-center">
<h2 className="text-2xl font-bold mb-2">Ingest Markets</h2>
<p className="text-gray-400 text-sm">Scanning Polymarket for weather prediction markets</p>
</div>
<div className="card">
{loading ? (
<div className="flex flex-col items-center justify-center py-12 gap-4">
<div className="animate-spin w-10 h-10 border-3 border-purple-500 border-t-transparent rounded-full" />
<p className="text-sm text-gray-400">Scanning Polymarket for weather markets...</p>
</div>
) : error ? (
<div className="text-center py-8">
<div className="w-12 h-12 rounded-full bg-red-500/10 flex items-center justify-center mx-auto mb-3">
<svg className="w-6 h-6 text-red-400" fill="none" stroke="currentColor" strokeWidth="1.5" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" d="M12 9v3.75m9-.75a9 9 0 11-18 0 9 9 0 0118 0zm-9 3.75h.008v.008H12v-.008z" />
</svg>
</div>
<p className="text-red-400 text-sm mb-3">{error}</p>
<button onClick={runIngest} className="btn btn-s text-sm">Retry</button>
</div>
) : (
<div className="space-y-4">
<div className="grid grid-cols-3 gap-4">
<div className="text-center">
<p className="stat-v text-purple-400">{result?.scanned || '—'}</p>
<p className="text-xs text-gray-500 mt-1">Scanned</p>
</div>
<div className="text-center">
<p className="stat-v text-green-400">{result?.ingested || result?.markets?.length || 0}</p>
<p className="text-xs text-gray-500 mt-1">Ingested</p>
</div>
<div className="text-center">
<p className="stat-v text-blue-400">{result?.skipped || 0}</p>
<p className="text-xs text-gray-500 mt-1">Skipped</p>
</div>
</div>
{(result?.markets || []).length > 0 && (
<div className="border-t border-gray-800 pt-3 mt-3">
<p className="text-xs text-gray-500 mb-2 uppercase font-medium">Ingested Markets</p>
<div className="space-y-1.5 max-h-48 overflow-y-auto">
{(result.markets || []).slice(0, 10).map((m, i) => (
<div key={i} className="flex items-center gap-2 text-xs">
<span className="w-1.5 h-1.5 rounded-full bg-green-500 flex-shrink-0" />
<span className="text-gray-300 truncate">{m.question || m}</span>
</div>
))}
{(result.markets || []).length > 10 && (
<p className="text-xs text-gray-600">+{result.markets.length - 10} more</p>
)}
</div>
</div>
)}
</div>
)}
</div>
<div className="flex items-center justify-between">
<button onClick={back} className="text-sm text-gray-500 hover:text-gray-300">Back</button>
<button onClick={next} disabled={loading} className="wizard-btn">
{loading ? 'Processing...' : 'Continue'}
</button>
</div>
</div>
);
}