โ† Back
โ˜†
import { useState, useEffect } from 'react';
import { usePrivy } from '@privy-io/react-auth';
import { useNavigate } from 'react-router-dom';
import { usePolymarketAuth } from '../../hooks/usePolymarketAuth';
import { useTheme } from '../../hooks/useTheme';
import { useT } from '../../i18n/LanguageContext';
import { readPusdBalance } from '../../utils/dwApprovals';

export default function TopBar() {
  const { isConnected, isAuthenticated, loading, error, deriveApiKey } = usePolymarketAuth();
  const { authenticated, user, login, getAccessToken } = usePrivy();
  const navigate = useNavigate();
  const { theme, toggleTheme } = useTheme();
  const { t } = useT();
  const emailPrefix = user?.email?.address?.split('@')[0];

  // Live free-cash (pUSD) balance for the header chip. Resolve the user's own deposit wallet
  // from the backend, then read its pUSD balance; poll every 30s.
  const [cashRaw, setCash] = useState<number | null>(null);
  // Derived: null when logged out (no synchronous reset inside the effect).
  const cash = authenticated ? cashRaw : null;
  useEffect(() => {
    if (!authenticated) return;
    let alive = true;
    const load = async () => {
      try {
        const token = await getAccessToken();
        if (!token) return;
        const r = await fetch('/api/copy/wallet', { headers: { authorization: `Bearer ${token}` } });
        const dw = (await r.json())?.data?.depositWallet;
        if (!dw) { if (alive) setCash(null); return; }
        const bal = await readPusdBalance(dw);
        if (alive) setCash(Number(bal) / 1e6);
      } catch { /* leave last-known */ }
    };
    load();
    const id = setInterval(load, 30000);
    return () => { alive = false; clearInterval(id); };
  }, [authenticated, getAccessToken]);

  return (
    <>
    <header className="topbar">
      <div className="topbar-logo">
        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
          <path d="M3 12c4 0 4-4 8-4s5 4 9 4" />
          <path d="M3 17c4 0 4-3 8-3s5 3 9 3" />
          <path d="M16 6l3-2v4z" />
        </svg>
        <span>ะŸะพะปะธะบะพะฟะธ</span>
      </div>
      <div className="topbar-actions">
        <button className="theme-toggle" onClick={toggleTheme} title={`Switch to ${theme === 'dark' ? 'light' : 'dark'} mode`}>
          {theme === 'dark' ? (
            <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" width="18" height="18">
              <circle cx="12" cy="12" r="5" />
              <path d="M12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42" />
            </svg>
          ) : (
            <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" width="18" height="18">
              <path d="M21 12.79A9 9 0 1111.21 3 7 7 0 0021 12.79z" />
            </svg>
          )}
        </button>
        {isConnected && !isAuthenticated && (
          <button
            className="btn-sign"
            onClick={deriveApiKey}
            disabled={loading}
            title={error || 'Sign to enable trading'}
          >
            {loading ? 'Signingโ€ฆ' : '๐Ÿ”‘ Sign to Trade'}
          </button>
        )}
        {isConnected && isAuthenticated && (
          <span className="trade-ready" title="CLOB API key active">โœ“ Ready</span>
        )}
        {authenticated ? (
          <button className="wallet-cta" onClick={() => navigate('/wallet')} title={emailPrefix || t('nav.wallet')}>
            ๐Ÿ‘› {cash != null ? `$${cash.toFixed(2)}` : t('nav.wallet')}
          </button>
        ) : (
          <button className="wallet-cta" onClick={login}>{t('nav.signin')}</button>
        )}
      </div>
    </header>
    {isConnected && !isAuthenticated && error && (
      <div className="sign-error-banner" onClick={deriveApiKey} role="button">
        {error}
      </div>
    )}
    </>
  );
}

๐Ÿ“œ Git History

6c47fa4chore: local Polikopi project home + Phase 1 redesign artifacts12 days ago
Show last diff
Loading...