import { useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import type { MarketDetail } from '../../types/market';
import { formatVolume, formatPrice, formatSpread, formatEndDate, getMarketTitle, getPolymarketUrl } from '../../utils/format';
import OrderbookMini from './OrderbookMini';
import PriceChart from './PriceChart';
interface Props {
marketId: string;
onClose: () => void;
}
export default function DetailsPanel({ marketId, onClose }: Props) {
const navigate = useNavigate();
const [market, setMarket] = useState<MarketDetail | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
const t = setTimeout(() => {
setLoading(true);
setError(null);
fetch(`/api/screener/market/${encodeURIComponent(marketId)}`)
.then(r => r.json())
.then(d => {
if (d.success) setMarket(d.data);
else setError(d.error || 'Failed to load');
})
.catch(() => setError('Network error'))
.finally(() => setLoading(false));
}, 0);
return () => { clearTimeout(t); };
}, [marketId]);
if (loading) {
return (
<div className="details-panel">
<div className="details-loading">
<div className="skeleton-line" style={{ width: '70%', height: 18 }} />
<div className="skeleton-line" style={{ width: '50%', height: 14, marginTop: 8 }} />
<div className="details-prices" style={{ marginTop: 16 }}>
<div className="skeleton-line" style={{ width: 100, height: 48 }} />
<div className="skeleton-line" style={{ width: 100, height: 48 }} />
</div>
</div>
</div>
);
}
if (error || !market) {
return (
<div className="details-panel">
<div className="details-error">
<span>{error || 'Market not found'}</span>
<button className="details-close" onClick={onClose}>Close</button>
</div>
</div>
);
}
const title = getMarketTitle(market);
const polymarketUrl = getPolymarketUrl(market);
return (
<div className="details-panel">
<div className="details-header">
<div className="details-title-row">
{market.image_url && (
<img
src={market.image_url}
alt=""
className="details-img"
onError={e => { (e.target as HTMLImageElement).style.display = 'none'; }}
/>
)}
<div className="details-title-text">
<h3 className="details-question">{title}</h3>
<div className="details-meta-row">
<span className="details-category">{market.category}</span>
<span className="details-sep">|</span>
<span className="details-ends">Ends {formatEndDate(market.end_date)}</span>
</div>
</div>
</div>
<button className="details-close" onClick={onClose} title="Close">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" width="18" height="18">
<path d="M18 6L6 18M6 6l12 12" />
</svg>
</button>
</div>
{/* Prices */}
<div className="details-prices">
<div className="price-block price-yes">
<div className="price-label">YES</div>
<div className="price-value">{formatPrice(market.yes_price)}</div>
</div>
<div className="price-block price-no">
<div className="price-label">NO</div>
<div className="price-value">{formatPrice(market.no_price)}</div>
</div>
</div>
{/* Stats grid */}
<div className="details-stats">
<div className="stat-item">
<span className="stat-label">Volume 24h</span>
<span className="stat-value">{formatVolume(market.volume_24h)}</span>
</div>
<div className="stat-item">
<span className="stat-label">Total Volume</span>
<span className="stat-value">{formatVolume(market.volume_total)}</span>
</div>
<div className="stat-item">
<span className="stat-label">Liquidity</span>
<span className="stat-value">{formatVolume(market.liquidity)}</span>
</div>
<div className="stat-item">
<span className="stat-label">Spread</span>
<span className="stat-value">{formatSpread(market.spread)}</span>
</div>
</div>
{/* Chart + Orderbook side by side */}
<div className="details-chart-ob">
<PriceChart marketId={marketId} />
<OrderbookMini marketId={marketId} />
</div>
{/* Tags */}
{market.tags && market.tags.length > 0 && (
<div className="details-tags">
{market.tags.map(tag => (
<span key={tag} className="details-tag">{tag}</span>
))}
</div>
)}
{/* Actions */}
<div className="details-actions">
<button className="btn-buy btn-buy-yes" onClick={() => navigate(`/market/${marketId}`)}>
Trade {formatPrice(market.yes_price)}
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" width="14" height="14">
<path d="M5 12h14M12 5l7 7-7 7" />
</svg>
</button>
<a href={polymarketUrl} target="_blank" rel="noopener noreferrer" className="btn-polymarket">
Polymarket
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" width="14" height="14">
<path d="M18 13v6a2 2 0 01-2 2H5a2 2 0 01-2-2V8a2 2 0 012-2h6M15 3h6v6M10 14L21 3" />
</svg>
</a>
</div>
</div>
);
}
📜 Git History
6c47fa4chore: local Polikopi project home + Phase 1 redesign artifacts12 days ago
Show last diff
Loading...