← back to Ken

react-dash/src/pages/Markets.jsx

44 lines

import React, { useState, useEffect } from 'react';
import { api, post } from '../api';

export default function Markets() {
  const [markets, setM] = useState([]);
  const [loading, setL] = useState(true);
  const [busy, setB] = useState(false);

  const load = () => api('/markets').then(d => { setM(d.markets||[]); setL(false); });
  useEffect(() => { load(); }, []);

  async function ingest() { setB(true); const r = await post('/markets', {action:'ingest'}); alert(`Ingested ${r.ingested||0} weather markets from ${r.total_scanned||0} scanned`); load(); setB(false); }
  async function parse(id) { const r = await post('/markets', {action:'parse', condition_id:id}); alert(JSON.stringify(r.parsed,null,2)); load(); }

  if (loading) return <div className="flex items-center justify-center h-64"><div className="animate-spin w-8 h-8 border-2 border-blue-500 border-t-transparent rounded-full"/></div>;

  return (
    <div className="space-y-6">
      <div className="flex items-center justify-between">
        <div><h1 className="text-2xl font-bold">Markets</h1><p className="text-gray-500 text-sm">Polymarket weather-related markets</p></div>
        <button onClick={ingest} disabled={busy} className="btn btn-p">{busy?'Ingesting...':'Ingest Markets'}</button>
      </div>
      <div className="grid grid-cols-3 gap-4">
        <div className="card"><p className="text-xs text-gray-500 uppercase mb-1">Total</p><p className="stat-v text-blue-400">{markets.length}</p></div>
        <div className="card"><p className="text-xs text-gray-500 uppercase mb-1">Active</p><p className="stat-v text-green-400">{markets.filter(m=>m.active).length}</p></div>
        <div className="card"><p className="text-xs text-gray-500 uppercase mb-1">Parsed</p><p className="stat-v text-purple-400">{markets.filter(m=>m.parsed_event?.variable).length}</p></div>
      </div>
      <div className="card overflow-x-auto">
        <table><thead><tr><th>Question</th><th>Category</th><th>Liquidity</th><th>End Date</th><th>Parsed</th><th>Actions</th></tr></thead><tbody>
          {markets.length===0?<tr><td colSpan={6} className="text-center text-gray-500 py-8">No markets. Click Ingest.</td></tr>
          :markets.map(m=><tr key={m.condition_id}>
            <td className="max-w-[300px]"><p className="truncate font-medium">{m.question}</p><p className="text-xs text-gray-500 truncate">{m.condition_id}</p></td>
            <td><span className="badge bg-blue">{m.category||'weather'}</span></td>
            <td className="font-mono">${parseFloat(m.liquidity||0).toFixed(0)}</td>
            <td className="text-gray-400 text-sm">{m.end_ts?new Date(m.end_ts).toLocaleDateString():'-'}</td>
            <td>{m.parsed_event?.variable?<span className="badge bg-green">Yes</span>:<span className="badge bg-yellow">No</span>}</td>
            <td><button onClick={()=>parse(m.condition_id)} className="text-xs text-blue-400 hover:text-blue-300">Parse</button></td>
          </tr>)}
        </tbody></table>
      </div>
    </div>
  );
}