← back to Bertha
src/app/dashboard/markets/page.js
102 lines
'use client';
import { useState, useEffect } from 'react';
export default function MarketsPage() {
const [markets, setMarkets] = useState([]);
const [loading, setLoading] = useState(true);
const [ingesting, setIngesting] = useState(false);
async function loadMarkets() {
try {
const res = await fetch('/api/markets');
const data = await res.json();
setMarkets(data.markets || []);
} catch (err) { console.error(err); }
setLoading(false);
}
useEffect(() => { loadMarkets(); }, []);
async function ingestMarkets() {
setIngesting(true);
try {
const res = await fetch('/api/markets', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ action: 'ingest' }) });
const data = await res.json();
alert(`Ingested ${data.ingested || 0} weather markets`);
loadMarkets();
} catch (err) { alert('Ingest error: ' + err.message); }
setIngesting(false);
}
async function parseMarket(conditionId) {
try {
const res = await fetch('/api/markets', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ action: 'parse', condition_id: conditionId }) });
const data = await res.json();
alert(JSON.stringify(data.parsed, null, 2));
loadMarkets();
} catch (err) { alert('Parse error: ' + err.message); }
}
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={ingestMarkets} disabled={ingesting} className="btn btn-primary">
{ingesting ? '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 Markets</p><p className="stat-value 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-value text-green-400">{markets.filter(m => m.active).length}</p></div>
<div className="card"><p className="text-xs text-gray-500 uppercase mb-1">With Predictions</p><p className="stat-value text-purple-400">{markets.filter(m => m.prediction_count > 0).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 yet. Click "Ingest Markets" to scan Polymarket.</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 badge-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 ? (
<span className="badge badge-green">Yes</span>
) : (
<span className="badge badge-yellow">No</span>
)}
</td>
<td>
<button onClick={() => parseMarket(m.condition_id)} className="text-xs text-blue-400 hover:text-blue-300">Parse</button>
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
);
}