Severity: Medium (revenue leak + permanent UI artifact)
File: apps/web/hooks/use-promo-code.ts
Description
usePromoCode() returns { getDiscounts, clear }. Across the whole app, only
getDiscounts is ever called:
$ grep -rn "promoCode\." apps/web
apps/web/components/add-document/connections.tsx:335: discounts: promoCode.getDiscounts(),
apps/web/components/add-document/index.tsx:347: discounts: promoCode.getDiscounts(),
apps/web/components/add-document/index.tsx:449: discounts: promoCode.getDiscounts(),
apps/web/components/integrations/plugins-detail.tsx:575: discounts: promoCode.getDiscounts(),
apps/web/components/integrations-view.tsx:2850: discounts: promoCode.getDiscounts(),
apps/web/components/onboarding-brain/step-sources.tsx:637: discounts: promoCode.getDiscounts(),
apps/web/components/settings/billing.tsx:703: discounts: promoCode.getDiscounts(),
apps/web/components/settings/connections-mcp.tsx:557: discounts: promoCode.getDiscounts(),
clear has zero call sites. Nothing ever removes sm.promoCode.org_<id> from
localStorage, and the stored code carries no expiry or use count.
Impact
Once a user lands on any page with ?discountCode=…:
- Every subsequent checkout for that org gets the discount, indefinitely —
including plan upgrades months later and any of the 8 unrelated checkout
entry points above. A one-time promo becomes a permanent price cut.
- The toast never goes away.
PromoCodeHost re-fires it on every mount
with duration: Number.POSITIVE_INFINITY and id: PROMO_TOAST_ID. Since
clear() (the only toast.dismiss(PROMO_TOAST_ID) caller) is never
invoked, "Discount code active — Code X will apply at checkout" sticks to the
app forever.
Clearing localStorage by hand is the only escape.
Suggested fix
Call promoCode.clear() from the checkout onSuccess path (or wherever
attach/checkout resolves successfully) in each of the 8 call sites — or,
less repetitively, clear it centrally once the org's subscription state flips.
An expiry timestamp stored alongside the code would also bound the blast radius
if a clear is ever missed.
Severity: Medium (revenue leak + permanent UI artifact)
File:
apps/web/hooks/use-promo-code.tsDescription
usePromoCode()returns{ getDiscounts, clear }. Across the whole app, onlygetDiscountsis ever called:clearhas zero call sites. Nothing ever removessm.promoCode.org_<id>fromlocalStorage, and the stored code carries no expiry or use count.Impact
Once a user lands on any page with
?discountCode=…:including plan upgrades months later and any of the 8 unrelated checkout
entry points above. A one-time promo becomes a permanent price cut.
PromoCodeHostre-fires it on every mountwith
duration: Number.POSITIVE_INFINITYandid: PROMO_TOAST_ID. Sinceclear()(the onlytoast.dismiss(PROMO_TOAST_ID)caller) is neverinvoked, "Discount code active — Code X will apply at checkout" sticks to the
app forever.
Clearing localStorage by hand is the only escape.
Suggested fix
Call
promoCode.clear()from the checkoutonSuccesspath (or whereverattach/checkoutresolves successfully) in each of the 8 call sites — or,less repetitively, clear it centrally once the org's subscription state flips.
An expiry timestamp stored alongside the code would also bound the blast radius
if a clear is ever missed.