← Back
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...