diff --git a/apps/sim/app/(landing)/components/cta/cta.tsx b/apps/sim/app/(landing)/components/cta/cta.tsx index 61fe0cb64e4..b82a6bcf7ef 100644 --- a/apps/sim/app/(landing)/components/cta/cta.tsx +++ b/apps/sim/app/(landing)/components/cta/cta.tsx @@ -1,4 +1,5 @@ import { ChipLink } from '@sim/emcn' +import { DEMO_HREF, SIGNUP_HREF } from '@/app/(landing)/constants' /** * Landing pre-footer CTA - the page's final conversion band. A tall, centered @@ -28,10 +29,10 @@ export function Cta() { Build your first agent today.
- + Get started - + Contact sales
diff --git a/apps/sim/app/(landing)/components/hero-cta/hero-cta.tsx b/apps/sim/app/(landing)/components/hero-cta/hero-cta.tsx index 93a4dee3d6e..ff392fd0b2a 100644 --- a/apps/sim/app/(landing)/components/hero-cta/hero-cta.tsx +++ b/apps/sim/app/(landing)/components/hero-cta/hero-cta.tsx @@ -1,4 +1,5 @@ import { ChipLink, cn } from '@sim/emcn' +import { DEMO_HREF, SIGNUP_HREF } from '@/app/(landing)/constants' /** * Hero-scale sizing shared by both CTAs - one step up from the navbar's 30px @@ -24,11 +25,11 @@ const CTA_SIZE = 'h-[36px] px-[0.571em] text-[15px] [&>span]:[font-size:inherit] export function HeroCta() { return (
- + Request a demo diff --git a/apps/sim/app/(landing)/components/navbar/components/mobile-nav/mobile-nav.tsx b/apps/sim/app/(landing)/components/navbar/components/mobile-nav/mobile-nav.tsx index 59e31ad04a7..7be454b18ae 100644 --- a/apps/sim/app/(landing)/components/navbar/components/mobile-nav/mobile-nav.tsx +++ b/apps/sim/app/(landing)/components/navbar/components/mobile-nav/mobile-nav.tsx @@ -10,6 +10,7 @@ import { NAVBAR_GLASS_SURFACE, useNavbarFrost, } from '@/app/(landing)/components/navbar/components/navbar-shell' +import { DEMO_HREF, SIGNUP_HREF } from '@/app/(landing)/constants' /** * Mobile navigation - the `< lg` counterpart to the desktop nav clusters. @@ -70,7 +71,7 @@ export function MobileNav({ stars }: MobileNavProps) { return (
- + Sign up
diff --git a/apps/sim/app/(landing)/constants.ts b/apps/sim/app/(landing)/constants.ts new file mode 100644 index 00000000000..c16abe98f78 --- /dev/null +++ b/apps/sim/app/(landing)/constants.ts @@ -0,0 +1,8 @@ +/** + * Shared landing-page CTA destinations. Every "Get started"/"Sign up" CTA + * across the marketing site funnels to signup; every "Talk to sales"/ + * "Contact sales" CTA funnels to the demo-request form. Centralized here so + * no CTA can drift to the wrong destination independently. + */ +export const SIGNUP_HREF = '/signup' +export const DEMO_HREF = '/demo' diff --git a/apps/sim/app/(landing)/enterprise/enterprise.tsx b/apps/sim/app/(landing)/enterprise/enterprise.tsx index 100ab549b0d..677a23d1968 100644 --- a/apps/sim/app/(landing)/enterprise/enterprise.tsx +++ b/apps/sim/app/(landing)/enterprise/enterprise.tsx @@ -9,6 +9,7 @@ import { } from '@/app/(landing)/components/solutions-page/components' import { SOLUTIONS_SPACING } from '@/app/(landing)/components/solutions-page/constants' import type { SolutionsPageConfig } from '@/app/(landing)/components/solutions-page/types' +import { DEMO_HREF, SIGNUP_HREF } from '@/app/(landing)/constants' import { EnterpriseFeatureGrid } from '@/app/(landing)/enterprise/components/enterprise-feature-grid' import { EnterprisePlatformLoop } from '@/app/(landing)/enterprise/components/enterprise-platform-loop' import { @@ -84,7 +85,7 @@ const ENTERPRISE_CONFIG: SolutionsPageConfig = { title: 'Build, Deploy, and Manage Enterprise AI Agents in One Workspace', subtitle: 'Build enterprise AI agents, ship to production, and manage every version from one workspace.', - cta: { label: 'Start building', href: '/signup' }, + cta: { label: 'Start building', href: SIGNUP_HREF }, cards: [ { title: 'Build visually or with code', @@ -111,7 +112,7 @@ const ENTERPRISE_CONFIG: SolutionsPageConfig = { title: 'Governance and Security for Enterprise AI Agents', subtitle: 'Security, approvals, and controls keep enterprise AI agents trusted in production.', - cta: { label: 'See security', href: '/demo' }, + cta: { label: 'See security', href: DEMO_HREF }, cards: [ { title: 'Control who can do what', @@ -138,7 +139,7 @@ const ENTERPRISE_CONFIG: SolutionsPageConfig = { id: 'deploy', title: 'Deploy Enterprise Workflow Agents with Confidence', subtitle: 'Stage, observe, and version workflow agents before they reach production.', - cta: { label: 'Explore deployment', href: '/signup' }, + cta: { label: 'Explore deployment', href: SIGNUP_HREF }, cards: [ { title: 'Stage before you ship', @@ -162,7 +163,7 @@ const ENTERPRISE_CONFIG: SolutionsPageConfig = { title: 'Built for Enterprise Teams', subtitle: 'Built for the teams that own enterprise AI agents across IT, operations, and engineering.', - cta: { label: 'Talk to sales', href: '/demo' }, + cta: { label: 'Talk to sales', href: DEMO_HREF }, cards: [ { title: 'IT and platform teams', diff --git a/apps/sim/app/(landing)/pricing/components/pricing-plans/pricing-plans.tsx b/apps/sim/app/(landing)/pricing/components/pricing-plans/pricing-plans.tsx index efaf271b15e..5fc794978ef 100644 --- a/apps/sim/app/(landing)/pricing/components/pricing-plans/pricing-plans.tsx +++ b/apps/sim/app/(landing)/pricing/components/pricing-plans/pricing-plans.tsx @@ -4,6 +4,7 @@ import type { ReactNode } from 'react' import { useQueryStates } from 'nuqs' import { getUpgradeCardCta, type PlanTier, type UpgradeCardId } from '@/lib/billing/client' import { ANNUAL_DISCOUNT_RATE, CREDIT_TIERS } from '@/lib/billing/constants' +import { DEMO_HREF, SIGNUP_HREF } from '@/app/(landing)/constants' import { PricingCard, type PricingCardCta, @@ -18,14 +19,12 @@ import { /** * A public visitor has no subscription, so each card's canonical label and - * variant resolves against the `free` tier. On this page every CTA funnels to - * sign-up regardless of plan. + * variant resolves against the `free` tier. On this page every self-serve CTA + * funnels to sign-up regardless of plan; the enterprise CTA routes to the + * demo-request form instead. */ const VISITOR_TIER: PlanTier = 'free' -/** Every CTA on the public pricing page funnels logged-out visitors to sign-up. */ -const SIGNUP_HREF = '/signup' - /** This section's rows render on the public cards without their group header. */ const HEADERLESS_SECTION_TITLE = 'Credits & pricing' @@ -52,13 +51,27 @@ function sectionsForColumn(col: number): PricingCardSection[] { })) } +/** The four card columns (Free, Pro, Max, Enterprise) transposed once at module load - the source data is static, so this never needs to be redone per render. */ +const SECTIONS_BY_COLUMN = [0, 1, 2, 3].map(sectionsForColumn) + +/** Round a dollar amount down to the annual-billing discounted price. */ +function annualPrice(dollars: number): number { + return Math.round(dollars * (1 - ANNUAL_DISCOUNT_RATE)) +} + /** - * Resolve a card's canonical label and variant from the free-tier matrix; the - * CTA always funnels logged-out visitors to sign-up. + * Resolve a card's canonical label and variant from the free-tier matrix. A + * `sales` intent ("Talk to sales") routes to the demo-request form, matching + * every other "Contact sales" CTA on the landing site; every other intent + * funnels logged-out visitors to sign-up. */ function resolveCta(card: UpgradeCardId): PricingCardCta { const cta = getUpgradeCardCta(VISITOR_TIER, card) - return { label: cta.label, variant: cta.variant, href: SIGNUP_HREF } + return { + label: cta.label, + variant: cta.variant, + href: cta.intent === 'sales' ? DEMO_HREF : SIGNUP_HREF, + } } const FREE_CTA: PricingCardCta = { @@ -86,12 +99,8 @@ export function PricingPlans({ heading }: PricingPlansProps) { const setIsAnnual = (next: boolean) => setParams({ billing: next ? 'annual' : 'monthly' }) const discountPct = Math.round(ANNUAL_DISCOUNT_RATE * 100) - const proPrice = isAnnual - ? Math.round(CREDIT_TIERS[0].dollars * (1 - ANNUAL_DISCOUNT_RATE)) - : CREDIT_TIERS[0].dollars - const maxPrice = isAnnual - ? Math.round(CREDIT_TIERS[1].dollars * (1 - ANNUAL_DISCOUNT_RATE)) - : CREDIT_TIERS[1].dollars + const proPrice = isAnnual ? annualPrice(CREDIT_TIERS[0].dollars) : CREDIT_TIERS[0].dollars + const maxPrice = isAnnual ? annualPrice(CREDIT_TIERS[1].dollars) : CREDIT_TIERS[1].dollars const priceSubtext = isAnnual ? 'per user/month, billed annually' : 'per user/month, billed monthly' @@ -114,7 +123,7 @@ export function PricingPlans({ heading }: PricingPlansProps) { price='$0' priceSubtext='Free forever' cta={FREE_CTA} - sections={sectionsForColumn(0)} + sections={SECTIONS_BY_COLUMN[0]} />