← Back
import { useState, useEffect } from 'react';
import { usePrivy } from '@privy-io/react-auth';
import PrivyAccount from '../components/PrivyAccount';
import { readPusdBalance } from '../utils/dwApprovals';
import { useT } from '../i18n/LanguageContext';
import '../redesign/editorial.css';

/**
 * Dedicated wallet page (funding view): a balance summary + deposit / withdraw / wallet setup,
 * reached from the header balance chip. Trading positions & P&L stay on the Portfolio page.
 * Wraps the existing PrivyAccount block (deposit/withdraw/approvals/delegate) unchanged.
 */
export default function WalletPage() {
  const { t } = useT();
  const { authenticated, getAccessToken } = usePrivy();
  const [cashRaw, setCash] = useState<number | null>(null);
  const [posRaw, setPosValue] = useState<number | null>(null);
  // Derived: null when logged out (no synchronous reset inside the effect).
  const cash = authenticated ? cashRaw : null;
  const posValue = authenticated ? posRaw : null;

  // Available = free pUSD cash; In positions = live mark-to-market of open copies (Data API).
  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); setPosValue(null); } return; }
        const bal = await readPusdBalance(dw);
        if (alive) setCash(Number(bal) / 1e6);
        try {
          const v = await fetch(`https://data-api.polymarket.com/value?user=${dw}`);
          const d = await v.json();
          const val = Array.isArray(d) ? Number(d[0]?.value) : Number(d?.value);
          if (alive) setPosValue(Number.isFinite(val) ? val : 0);
        } catch { if (alive) setPosValue(0); }
      } catch { /* leave last-known */ }
    };
    load();
    const id = setInterval(load, 30000);
    return () => { alive = false; clearInterval(id); };
  }, [authenticated, getAccessToken]);

  const fmt = (n: number | null) => n == null ? '—' : `$${n.toFixed(2)}`;
  const total = cash != null && posValue != null ? cash + posValue : null;

  return (
    <div className="more-page pk-more pk-wallet">
      <h2 className="more-title">{t('nav.wallet')}</h2>

      {authenticated && (cash != null || posValue != null) && (
        <div className="wallet-summary" style={{ display: 'flex', gap: 8, margin: '0 0 14px' }}>
          {[
            { k: 'wallet.available', v: fmt(cash), strong: true },
            { k: 'wallet.inPositions', v: fmt(posValue) },
            { k: 'wallet.total', v: fmt(total) },
          ].map(({ k, v, strong }) => (
            <div key={k} style={{ flex: 1, background: 'var(--bg-card)', border: '1px solid var(--border)', borderRadius: 10, padding: '10px 8px', textAlign: 'center' }}>
              <div style={{ fontSize: 11, opacity: 0.7, marginBottom: 4 }}>{t(k)}</div>
              <div style={{ fontSize: strong ? 18 : 16, fontWeight: 700 }}>{v}</div>
            </div>
          ))}
        </div>
      )}

      <PrivyAccount />
    </div>
  );
}

📜 Git History

9dfe057feat(poli): editorial Wallet/MarketDetail/Copy-subs + serif-var fix (chunk 8)10 days ago
6c47fa4chore: local Polikopi project home + Phase 1 redesign artifacts12 days ago
Show last diff
Loading...