fix(web): footer rebrand + disable unbuilt paid-tier cta
Two launch-day cleanups:
**Footer rebrand** — full rewrite of modules/marketing/layout/footer.tsx
from TurboStarter boilerplate (Twitter/Facebook/LinkedIn socials,
Chrome/Firefox/Edge extension links, turbostarter repo links, broken
/legal routes) to lean claudemesh structure:
- claudemesh wordmark (mesh glyph + serif) + tagline
- 2 columns: Product (Docs / Pricing / Changelog / Contact) +
Protocol (GitHub / claude-intercom OSS / Protocol spec / Self-host
broker)
- GitHub social icon linking to github.com/alezmad/claudemesh
- I18n controls
- Bottom bar: "© 2026 claudemesh · MIT licensed" + the existing
BuiltWith credit pointing at claude-intercom (from cdd7931)
No trash links. No turbostarter refs. Matches landing design tokens
(--cm-*).
**Manage-plan CTA guard** — settings/billing → ManagePlan previously
always rendered an active "Visit billing portal" button that would
500 on launch day because Stripe isn't set up. For FREE-tier users
(everyone at v0.1.0) the button is now disabled + labelled
"Paid tiers coming soon". When someone is on a paid tier (future)
the real portal flow re-engages.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -48,24 +48,39 @@ export const ManagePlan = () => {
|
||||
</SettingsCardHeader>
|
||||
|
||||
<SettingsCardContent>
|
||||
<Button
|
||||
className="w-fit gap-1"
|
||||
disabled={getPortal.isPending}
|
||||
onClick={() =>
|
||||
getPortal.mutate({
|
||||
query: {
|
||||
redirectUrl: window.location.href,
|
||||
},
|
||||
})
|
||||
}
|
||||
>
|
||||
{t("manage.billing.visitPortal")}
|
||||
{getPortal.isPending ? (
|
||||
<Icons.Loader2 className="size-4 animate-spin" />
|
||||
) : (
|
||||
<Icons.ArrowUpRight className="size-4" />
|
||||
)}
|
||||
</Button>
|
||||
{plan.id === PricingPlanType.FREE ? (
|
||||
// v0.1.0: only the free tier is live. Paid-tier checkout +
|
||||
// Stripe customer portal land post-launch; surface that
|
||||
// honestly instead of a button that would hit a 500.
|
||||
<div className="flex items-center gap-2">
|
||||
<Button className="w-fit gap-1" disabled>
|
||||
{t("manage.billing.visitPortal")}
|
||||
<Icons.ArrowUpRight className="size-4" />
|
||||
</Button>
|
||||
<span className="text-muted-foreground text-xs">
|
||||
Paid tiers coming soon
|
||||
</span>
|
||||
</div>
|
||||
) : (
|
||||
<Button
|
||||
className="w-fit gap-1"
|
||||
disabled={getPortal.isPending}
|
||||
onClick={() =>
|
||||
getPortal.mutate({
|
||||
query: {
|
||||
redirectUrl: window.location.href,
|
||||
},
|
||||
})
|
||||
}
|
||||
>
|
||||
{t("manage.billing.visitPortal")}
|
||||
{getPortal.isPending ? (
|
||||
<Icons.Loader2 className="size-4 animate-spin" />
|
||||
) : (
|
||||
<Icons.ArrowUpRight className="size-4" />
|
||||
)}
|
||||
</Button>
|
||||
)}
|
||||
</SettingsCardContent>
|
||||
</SettingsCard>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user