Task B — founder checkout is SEAT-GATED; payment-decline grace spans retries
1+2. Checkout price was CODE-gated (founder price only with a valid founder
code) — so "Claim a Founder Desk" would have charged the $44.99 standard
price, not the advertised $34.99. Now it's SEAT-gated: resolveCheckoutPrice()
attaches the founder price while founder seats remain (< FOUNDER_SEATS_TOTAL,
read from the SAME countFounderSeats() truth as the ClaimMeter), and flips to
standard at seat 100. createCheckoutSession uses it; the founderCode param is
kept for back-compat but no longer drives price. The meter flips to "SOLD
OUT" at capacity. When the count can't be verified we honor the advertised
founder price (never overcharge).
- Also hardened countFounderSeats to manual pagination (the for-await form
broke on non-async-iterable list mocks).
3. Tests: resolveCheckoutPrice at seat 0 → founder, seat 100 → standard, the
99/100 boundary, null-count → advertised founder price.
4. Grace: invoice.payment_failed now sets a 14-DAY grace (spans Stripe's Smart
Retry window) instead of 48h — a transient decline no longer revokes access
mid-retry. Access is revoked only when Stripe actually cancels
(customer.subscription.deleted keeps its 48h grace). Test updated.
Stripe + founders suites green, web build exit 0.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -37,13 +37,16 @@ export default function ClaimMeter() {
|
||||
const total = data.total || 100;
|
||||
const claimed = Math.max(0, Math.min(total, data.claimed));
|
||||
const pct = Math.min(100, Math.round((claimed / total) * 100));
|
||||
// Item B — at capacity the meter flips to sold-out (checkout has already
|
||||
// flipped to standard pricing via the same countFounderSeats truth).
|
||||
const soldOut = claimed >= total;
|
||||
|
||||
return (
|
||||
<div style={{ maxWidth: 420, margin: '0 auto', width: '100%' }}>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', marginBottom: 8 }}>
|
||||
<SectionHead accent="var(--amber)">FOUNDER SEATS</SectionHead>
|
||||
<span className="mono amber-glow" style={{ fontSize: 13, fontWeight: 700, color: 'var(--amber)' }}>
|
||||
{claimed} / {total} CLAIMED
|
||||
{soldOut ? 'SOLD OUT' : `${claimed} / ${total} CLAIMED`}
|
||||
</span>
|
||||
</div>
|
||||
<div style={{ height: 6, background: 'var(--bg-2)', border: '1px solid var(--border)', borderRadius: 4, overflow: 'hidden' }}>
|
||||
@@ -59,7 +62,9 @@ export default function ClaimMeter() {
|
||||
/>
|
||||
</div>
|
||||
<div className="mono" style={{ fontSize: 11, color: 'var(--text-1)', marginTop: 8, letterSpacing: '0.02em' }}>
|
||||
Founder pricing locks for life. When the seats are gone, the rate is gone.
|
||||
{soldOut
|
||||
? 'Founder seats are gone — standard pricing now applies.'
|
||||
: 'Founder pricing locks for life. When the seats are gone, the rate is gone.'}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user