• T28 replaces the "开发中敬请期待" placeholder on dance.html's 传衣服
    tab with a real upload panel: file input, the live spend_garment price
    pulled from the new public GET /api/pricing (not hardcoded, per
    dev-plan-4.md's acceptance criterion), and a submit flow that POSTs to
    T27's /api/dance/upload-garment. Not logged in opens the existing T22
    login modal instead of failing silently; not email-verified shows an
    inline message; a 402 (insufficient balance) points at the new topup
    flow; success refreshes the balance and immediately polls the queue,
    same as the free wardrobe pick's own pollState() call.
    
    T29 adds a 充值 pill (visible once logged in) opening a tier picker
    built from GET /api/pricing's topup_tier entries, POSTing to T24's
    /api/credits/checkout and navigating to whatever URL comes back (the
    mock completion page today, Stripe's hosted Checkout once a real key
    lands tomorrow — both redirect back to dance.html?topup=success/
    cancelled). A one-shot banner reads that query param on load, then
    scrubs it via history.replaceState. The account button's own label
    now also shows creditBalance, riding on the field GET /api/auth/me
    already started returning in T24.
    
    Manually verified end to end against the live server (localhost:8934):
    register -> verify -> mock checkout -> balance updates in the header
    -> topup banner -> upload panel shows the live price and opens the
    login modal when logged out. The upload itself surfaced that
    production's one seed character had never been marked isDefault (see
    the preceding commit) — not a bug in this code, but blocked a live
    walk of the full generate path until fixed.
    
    Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_011DUiYs6UjxDMkfvnjtsKFo
    yibo authored
     
    Browse File »