docs(nx-dev): add click tracking on pricing plans (#28902)

This commit is contained in:
Benjamin Cabanes 2024-11-12 10:33:15 -05:00 committed by GitHub
parent 06af0ee53b
commit f3d5787f97
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 188 additions and 62 deletions

View File

@ -1,5 +1,11 @@
import type { Metadata } from 'next'; import type { Metadata } from 'next';
import { Faq, Oss, ResourceClasses, PlansDisplay } from '@nx/nx-dev/ui-pricing'; import {
Faq,
Oss,
ResourceClasses,
PlansDisplay,
TrialCallout,
} from '@nx/nx-dev/ui-pricing';
import { import {
CallToAction, CallToAction,
DefaultLayout, DefaultLayout,
@ -30,13 +36,16 @@ export const metadata: Metadata = {
}, },
}; };
export default function PricingPageV2() { export default function PricingPage() {
return ( return (
<DefaultLayout> <DefaultLayout>
<PlansDisplay /> <PlansDisplay />
<div className="mt-18 lg:mt-32"> <div className="mt-18 lg:mt-32">
<TrustedBy utmSource="pricingpage" utmCampaign="pricing" /> <TrustedBy utmSource="pricingpage" utmCampaign="pricing" />
</div> </div>
<div className="mt-32 lg:mt-56">
<TrialCallout pageId="pricing" />
</div>
<div className="mt-32 lg:mt-56"> <div className="mt-32 lg:mt-56">
<ResourceClasses /> <ResourceClasses />
</div> </div>

View File

@ -12,6 +12,7 @@ import {
TrustedBy, TrustedBy,
SolveYourCi, SolveYourCi,
} from '@nx/nx-dev/ui-enterprise'; } from '@nx/nx-dev/ui-enterprise';
import { TrialCallout } from '@nx/nx-dev/ui-pricing';
export function Enterprise(): JSX.Element { export function Enterprise(): JSX.Element {
const router = useRouter(); const router = useRouter();
@ -46,6 +47,9 @@ export function Enterprise(): JSX.Element {
<div className="mt-32 lg:mt-40"> <div className="mt-32 lg:mt-40">
<MetricsAndCustomers /> <MetricsAndCustomers />
</div> </div>
<div className="mt-32 lg:mt-40">
<TrialCallout pageId="enterprise" />
</div>
<div className="mt-32 lg:mt-56"> <div className="mt-32 lg:mt-56">
<ScaleYourPeople /> <ScaleYourPeople />
</div> </div>

View File

@ -86,7 +86,10 @@ export function AgentNumberOverTime(): JSX.Element {
}; };
return ( return (
<section id="agent-number-over-time" className="overflow-hidden"> <section
id="agent-number-over-time"
className="scroll-mt-24 overflow-hidden"
>
<div className="mx-auto max-w-7xl md:px-6 lg:px-8"> <div className="mx-auto max-w-7xl md:px-6 lg:px-8">
<div className="mx-auto max-w-2xl text-center"> <div className="mx-auto max-w-2xl text-center">
<SectionHeading <SectionHeading

View File

@ -48,7 +48,7 @@ export function AutomatedAgentsManagement(): JSX.Element {
}; };
return ( return (
<section id="competitive-compute" className="overflow-hidden"> <section id="competitive-compute" className="scroll-mt-24 overflow-hidden">
<div className="mx-auto max-w-7xl md:px-6 lg:px-8"> <div className="mx-auto max-w-7xl md:px-6 lg:px-8">
<div className="grid grid-cols-1 gap-x-8 gap-y-16 sm:gap-y-20 lg:grid-cols-2 lg:items-start"> <div className="grid grid-cols-1 gap-x-8 gap-y-16 sm:gap-y-20 lg:grid-cols-2 lg:items-start">
<div className="px-6 md:px-0 lg:pr-4 lg:pt-4"> <div className="px-6 md:px-0 lg:pr-4 lg:pt-4">

View File

@ -6,6 +6,7 @@ import {
} from '@heroicons/react/24/outline'; } from '@heroicons/react/24/outline';
import { SectionHeading } from '@nx/nx-dev/ui-common'; import { SectionHeading } from '@nx/nx-dev/ui-common';
import Link from 'next/link'; import Link from 'next/link';
import { ReactElement } from 'react';
const features = [ const features = [
{ {
@ -41,9 +42,9 @@ const features = [
}, },
]; ];
export function EnhancedWithAi(): JSX.Element { export function EnhancedWithAi(): ReactElement {
return ( return (
<section id="ai-for-your-ci"> <section id="ai-for-your-ci" className="scroll-mt-24">
<div className="mx-auto max-w-7xl px-6 lg:px-8"> <div className="mx-auto max-w-7xl px-6 lg:px-8">
<div className="mx-auto max-w-3xl text-center"> <div className="mx-auto max-w-3xl text-center">
<SectionHeading as="h2" variant="title" id="deep-understanding"> <SectionHeading as="h2" variant="title" id="deep-understanding">

View File

@ -1,9 +1,10 @@
'use client'; 'use client';
import { Variants, motion } from 'framer-motion'; import { motion, Variants } from 'framer-motion';
import { Spotlight } from './elements/spotlight'; import { Spotlight } from './elements/spotlight';
import { AnimateValue } from '@nx/nx-dev/ui-animations'; import { AnimateValue } from '@nx/nx-dev/ui-animations';
import { ReactElement } from 'react';
export function FasterAndCheaper(): JSX.Element { export function FasterAndCheaper(): ReactElement {
const spotlight: Variants = { const spotlight: Variants = {
offscreen: { offscreen: {
display: 'none', display: 'none',
@ -14,7 +15,7 @@ export function FasterAndCheaper(): JSX.Element {
}; };
return ( return (
<section> <section id="faster-and-cheaper" className="scroll-mt-24">
<motion.div <motion.div
initial="offscreen" initial="offscreen"
whileInView="onscreen" whileInView="onscreen"

View File

@ -1,6 +1,6 @@
'use client'; 'use client';
import { motion } from 'framer-motion'; import { motion } from 'framer-motion';
import { useEffect, useState } from 'react'; import { ReactElement, useEffect, useState } from 'react';
import { SectionHeading } from '@nx/nx-dev/ui-common'; import { SectionHeading } from '@nx/nx-dev/ui-common';
import { usePrefersReducedMotion } from '@nx/nx-dev/ui-animations'; import { usePrefersReducedMotion } from '@nx/nx-dev/ui-animations';
@ -71,7 +71,7 @@ const stats = [
{ id: 4, name: 'Runs daily', value: 100, suffix: 'k+' }, { id: 4, name: 'Runs daily', value: 100, suffix: 'k+' },
]; ];
export function Statistics(): JSX.Element { export function Statistics(): ReactElement {
const shouldReduceMotion = usePrefersReducedMotion(); const shouldReduceMotion = usePrefersReducedMotion();
const variants = { const variants = {

View File

@ -8,9 +8,11 @@ import {
StorybookIcon, StorybookIcon,
VmwareIcon, VmwareIcon,
} from '@nx/nx-dev/ui-icons'; } from '@nx/nx-dev/ui-icons';
export function TrustedBy(): JSX.Element { import { ReactElement } from 'react';
export function TrustedBy(): ReactElement {
return ( return (
<section className=""> <section id="trust" className="scroll-mt-24">
<div className="mx-auto max-w-7xl px-4 pb-12 sm:px-6 lg:px-8 lg:pb-16"> <div className="mx-auto max-w-7xl px-4 pb-12 sm:px-6 lg:px-8 lg:pb-16">
<h2 className="text-center text-lg font-medium leading-8 text-slate-400"> <h2 className="text-center text-lg font-medium leading-8 text-slate-400">
Startups and Fortune 500 companies trust Nx Cloud Startups and Fortune 500 companies trust Nx Cloud

View File

@ -13,15 +13,15 @@ import { SectionHeading } from '@nx/nx-dev/ui-common';
import { BentoGrid, BentoGridItem } from './elements/bento-grid'; import { BentoGrid, BentoGridItem } from './elements/bento-grid';
import { cx } from '@nx/nx-dev/ui-primitives'; import { cx } from '@nx/nx-dev/ui-primitives';
import { animate, motion, useMotionValue, useTransform } from 'framer-motion'; import { animate, motion, useMotionValue, useTransform } from 'framer-motion';
import { useEffect } from 'react'; import { ReactElement, useEffect } from 'react';
import { usePrefersReducedMotion } from '@nx/nx-dev/ui-animations'; import { usePrefersReducedMotion } from '@nx/nx-dev/ui-animations';
export function UnderstandWorkspace(): JSX.Element { export function UnderstandWorkspace(): ReactElement {
return ( return (
<section> <section id="deep-understanding" className="scroll-mt-24">
<div className="mx-auto max-w-7xl px-6 lg:px-8"> <div className="mx-auto max-w-7xl px-6 lg:px-8">
<div className="mx-auto max-w-2xl text-center"> <div className="mx-auto max-w-2xl text-center">
<SectionHeading as="h2" variant="title" id="deep-understanding"> <SectionHeading as="h2" variant="title">
Deep understanding of your workspace Deep understanding of your workspace
</SectionHeading> </SectionHeading>
<SectionHeading as="p" variant="subtitle" className="mt-6"> <SectionHeading as="p" variant="subtitle" className="mt-6">

View File

@ -4,6 +4,7 @@ import { ChevronDownIcon } from '@heroicons/react/24/outline';
import { SectionHeading } from '@nx/nx-dev/ui-common'; import { SectionHeading } from '@nx/nx-dev/ui-common';
import { cx } from '@nx/nx-dev/ui-primitives'; import { cx } from '@nx/nx-dev/ui-primitives';
import { FAQPageJsonLd } from 'next-seo'; import { FAQPageJsonLd } from 'next-seo';
import Link from 'next/link';
import { ReactElement } from 'react'; import { ReactElement } from 'react';
export function Faq(): ReactElement { export function Faq(): ReactElement {
@ -89,11 +90,11 @@ export function Faq(): ReactElement {
{ {
question: 'What if I need help picking the right plan?', question: 'What if I need help picking the right plan?',
answer: answer:
'We have a helpful comparison above. If you have additional questions, or these plans dont fit your needs please reach out to cloud-support@nrwl.io and we will do our best to help.', 'We have a helpful comparison above. If you have additional questions, or these plans dont fit your needs please reach out to https://nx.dev/contact/sales and we will do our best to help.',
}, },
{ {
question: 'What if I need more than 70 active contributors?', question: 'What if I need more than 70 active contributors?',
answer: 'Please reach out to cloud-support@nrwl.io.', answer: 'Please reach out to https://nx.dev/contact/sales',
}, },
{ {
question: 'What payment methods do you accept?', question: 'What payment methods do you accept?',
@ -108,22 +109,20 @@ export function Faq(): ReactElement {
<div className="lg:grid lg:grid-cols-3 lg:gap-8"> <div className="lg:grid lg:grid-cols-3 lg:gap-8">
<header> <header>
<SectionHeading as="h2" variant="title"> <SectionHeading as="h2" variant="title">
Not sure yet? <br /> Have questions? Have questions?
</SectionHeading> </SectionHeading>
<SectionHeading as="p" variant="subtitle" className="mt-6"> <SectionHeading as="p" variant="subtitle" className="mt-6">
Here are the most asked question we condensed for your to get you Check out our most commonly asked questions.
setup quickly.
</SectionHeading> </SectionHeading>
<p className="text-md mt-4 text-slate-400 dark:text-slate-600"> <p className="text-md mt-4 text-slate-400 dark:text-slate-600">
Cant find the answer youre looking for? Reach out to our{' '} <Link
<a href="/contact"
href="mailto:cloud-support@nrwl.io" title="Reach out to the team"
className="font-medium underline" className="font-semibold"
> >
customer support Cant find the answer youre looking for?
</a>{' '} </Link>
team.
</p> </p>
</header> </header>
<FAQPageJsonLd <FAQPageJsonLd

View File

@ -1,13 +1,14 @@
'use client';
import { ReactElement } from 'react'; import { ReactElement } from 'react';
import { PlusIcon } from '@heroicons/react/24/outline'; import { PlusIcon } from '@heroicons/react/24/outline';
import { CheckCircleIcon } from '@heroicons/react/24/solid'; import { CheckCircleIcon } from '@heroicons/react/24/solid';
import { ButtonLink, SectionHeading } from '@nx/nx-dev/ui-common'; import { ButtonLink, SectionHeading } from '@nx/nx-dev/ui-common';
import { TrialCallout } from './trial-callout';
import Link from 'next/link'; import Link from 'next/link';
import { sendCustomEvent } from '@nx/nx-dev/feature-analytics';
export function PlansDisplay(): ReactElement { export function PlansDisplay(): ReactElement {
return ( return (
<section> <section id="plans" className="scroll-mt-24">
<div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8"> <div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
<header className="mx-auto max-w-4xl text-center"> <header className="mx-auto max-w-4xl text-center">
<SectionHeading as="h2" variant="display"> <SectionHeading as="h2" variant="display">
@ -19,7 +20,7 @@ export function PlansDisplay(): ReactElement {
</SectionHeading> </SectionHeading>
</header> </header>
<div className="mt-20 flow-root"> <div className="mt-20 flow-root">
<div className="isolate -mt-16 grid max-w-full grid-cols-1 gap-6 sm:mx-auto lg:mt-0 lg:grid-cols-3 xl:-mx-4 xl:gap-12"> <div className="isolate -mt-16 grid max-w-full grid-cols-1 gap-6 sm:mx-auto lg:mt-0 lg:grid-cols-3 xl:-mx-4 xl:gap-8">
{/*HOBBY*/} {/*HOBBY*/}
<div> <div>
<div className="rounded-lg border-2 border-blue-500 bg-white p-6 dark:border-sky-500 dark:bg-slate-950"> <div className="rounded-lg border-2 border-blue-500 bg-white p-6 dark:border-sky-500 dark:bg-slate-950">
@ -47,6 +48,13 @@ export function PlansDisplay(): ReactElement {
title="Start now" title="Start now"
size="default" size="default"
variant="primary" variant="primary"
onClick={() =>
sendCustomEvent(
'start-hobby-plan-click',
'plans-table',
'pricing-plans'
)
}
className="w-full" className="w-full"
> >
Get started Get started
@ -74,6 +82,13 @@ export function PlansDisplay(): ReactElement {
href="/ci/features/remote-cache" href="/ci/features/remote-cache"
target="_blank" target="_blank"
title="Learn how Nx Replay easily reduces CI execution time" title="Learn how Nx Replay easily reduces CI execution time"
onClick={() =>
sendCustomEvent(
'learn-nx-replay-click',
'plans-table',
'pricing-plans'
)
}
className="font-medium underline decoration-dotted" className="font-medium underline decoration-dotted"
> >
Nx Replay Nx Replay
@ -91,6 +106,13 @@ export function PlansDisplay(): ReactElement {
href="/ci/features/distribute-task-execution" href="/ci/features/distribute-task-execution"
target="_blank" target="_blank"
title="Learn how Nx Agents easily scale your CI pipelines" title="Learn how Nx Agents easily scale your CI pipelines"
onClick={() =>
sendCustomEvent(
'learn-nx-agents-click',
'plans-table',
'pricing-plans'
)
}
className="font-medium underline decoration-dotted" className="font-medium underline decoration-dotted"
> >
Nx Agents Nx Agents
@ -109,14 +131,16 @@ export function PlansDisplay(): ReactElement {
</h4> </h4>
</div> </div>
<p className="mt-2 text-sm"> <p className="mt-2 text-sm">
Scales with your team's needs. Billed on the first of each Start free, pay as you grow. Billed on the first of each month.
month.
</p> </p>
<p className="mt-4 leading-5"> <p className="mt-4 leading-5">
<span className="text-3xl font-semibold text-slate-950 dark:text-white"> <span className="text-3xl font-semibold text-slate-950 dark:text-white">
$19 $19
</span> </span>
<span className="text-lg"> per Active Contributor¹</span> <span className="text-lg"> per Active Contributor¹</span>{' '}
<span className="text-sm font-semibold italic">
(first 5 free)
</span>
<br /> <br />
<span className="text-sm">+ usage overages</span> <span className="text-sm">+ usage overages</span>
</p> </p>
@ -128,6 +152,13 @@ export function PlansDisplay(): ReactElement {
title="Get started" title="Get started"
size="default" size="default"
variant="secondary" variant="secondary"
onClick={() =>
sendCustomEvent(
'start-team-plan-click',
'plans-table',
'pricing-plans'
)
}
className="w-full" className="w-full"
> >
Get started Get started
@ -167,6 +198,13 @@ export function PlansDisplay(): ReactElement {
href="/nx-cloud#ai-for-your-ci" href="/nx-cloud#ai-for-your-ci"
target="_blank" target="_blank"
title="Check our AI integrations and how to use them" title="Check our AI integrations and how to use them"
onClick={() =>
sendCustomEvent(
'learn-ai-integrations-click',
'plans-table',
'pricing-plans'
)
}
className="font-medium underline decoration-dotted" className="font-medium underline decoration-dotted"
> >
AI integrations AI integrations
@ -218,8 +256,8 @@ export function PlansDisplay(): ReactElement {
</h4> </h4>
</div> </div>
<p className="mt-2 text-sm"> <p className="mt-2 text-sm">
The ultimate Nx toolchain, tailored to your needs of speed. The ultimate Nx toolchain, tailored for speed. Flexible billing
Flexible billing & payment options available. & payment options available.
</p> </p>
<p className="mt-4 pb-5 leading-5"> <p className="mt-4 pb-5 leading-5">
<span className="text-3xl font-semibold text-slate-950 dark:text-white"> <span className="text-3xl font-semibold text-slate-950 dark:text-white">
@ -233,6 +271,13 @@ export function PlansDisplay(): ReactElement {
title="Enterprise" title="Enterprise"
size="default" size="default"
variant="secondary" variant="secondary"
onClick={() =>
sendCustomEvent(
'learn-enterprise-click',
'plans-table',
'pricing-plans'
)
}
className="w-full" className="w-full"
> >
Learn more Learn more
@ -266,6 +311,13 @@ export function PlansDisplay(): ReactElement {
href="/powerpack" href="/powerpack"
target="_blank" target="_blank"
title="Check our AI integrations and how to use them" title="Check our AI integrations and how to use them"
onClick={() =>
sendCustomEvent(
'learn-nx-powerpack-click',
'plans-table',
'pricing-plans'
)
}
className="font-medium underline decoration-dotted" className="font-medium underline decoration-dotted"
> >
Nx Powerpack Nx Powerpack
@ -317,10 +369,6 @@ export function PlansDisplay(): ReactElement {
</p> </p>
</div> </div>
</div> </div>
<div className="mt-20">
<TrialCallout />
</div>
</div> </div>
</section> </section>
); );

View File

@ -17,7 +17,7 @@ const linuxAmd64 = [
}, },
{ {
icon: <LinuxIcon aria-hidden="true" className="size-6" />, icon: <LinuxIcon aria-hidden="true" className="size-6" />,
name: 'Medium plus', name: 'Medium +',
description: '3 vCPU, 6GB RAM', description: '3 vCPU, 6GB RAM',
creditCost: 15, creditCost: 15,
}, },

View File

@ -1,37 +1,96 @@
import { ButtonLink } from '@nx/nx-dev/ui-common'; 'use client';
import { ReactElement } from 'react'; import { ReactElement } from 'react';
import Image from 'next/image';
import { ButtonLink } from '@nx/nx-dev/ui-common';
import Link from 'next/link';
import { sendCustomEvent } from '@nx/nx-dev/feature-analytics';
export function TrialCallout(): ReactElement { export function TrialCallout({
pageId,
}: {
pageId: 'enterprise' | 'pricing';
}): ReactElement {
return ( return (
<section id="trial" className="isolate mx-auto max-w-xl"> <section id="start-trial" className="scroll-mt-24">
<div className="border border-slate-100 bg-white shadow-lg sm:rounded-lg dark:border-slate-800/60 dark:bg-slate-950"> <div className="mx-auto max-w-7xl sm:px-6 lg:px-8">
<div className="px-4 py-5 sm:p-6"> <div className="relative isolate overflow-hidden bg-white px-6 pt-16 shadow-2xl ring-1 ring-slate-200 sm:rounded-3xl sm:px-16 md:pt-24 lg:flex lg:gap-x-20 lg:px-24 lg:pt-0 dark:bg-slate-900 dark:ring-slate-800">
<h3 className="text-base font-semibold leading-6 text-slate-900 dark:text-slate-100"> <svg
Looking for a trial? viewBox="0 0 1024 1024"
</h3> aria-hidden="true"
<div className="mt-2 sm:flex sm:items-start sm:justify-between"> className="absolute left-1/2 top-1/2 -z-10 h-[64rem] w-[64rem] -translate-y-1/2 [mask-image:radial-gradient(closest-side,white,transparent)] sm:left-full sm:-ml-80 lg:left-1/2 lg:ml-0 lg:-translate-x-1/2 lg:translate-y-0"
<div className="max-w-xl text-sm"> >
<p> <circle
r={512}
cx={512}
cy={512}
fill="url(#1e3c1415-dh10-454c-aa3c-9a8019d0ap09d)"
fillOpacity="0.7"
/>
<defs>
<radialGradient id="1e3c1415-dh10-454c-aa3c-9a8019d0ap09d">
<stop stopColor="#9333ea" />
<stop offset={1} stopColor="#3b82f6" />
</radialGradient>
</defs>
</svg>
<div className="mx-auto max-w-md text-center lg:mx-0 lg:flex-auto lg:py-32 lg:text-left">
<h2 className="texxt-slate-950 text-balance text-3xl font-semibold tracking-tight sm:text-4xl dark:text-white">
Start a Trial
</h2>
<p className="mt-6 text-pretty text-lg/8">
Start with our Hobby Plan - free forever for teams of any size. Start with our Hobby Plan - free forever for teams of any size.
Perfect for proof of concept testing with up to 50,000 credits Perfect for proof of concept testing with up to 50,000 credits per
per month. month.
</p> </p>
</div> <div className="mt-4 flex items-center justify-center gap-x-6 lg:justify-start">
<div className="mt-5 sm:ml-6 sm:mt-0 sm:flex sm:flex-shrink-0 sm:items-center">
<ButtonLink <ButtonLink
href="https://cloud.nx.app" href="https://cloud.nx.app"
title="Start with Hobby"
variant="primary" variant="primary"
target="_blank"
size="default" size="default"
title="Start free trial"
onClick={() =>
sendCustomEvent(
'start-trial-click',
'trial-callout-' + pageId,
'trial-callout'
)
}
> >
Start for free Start for free
</ButtonLink> </ButtonLink>
</div> </div>
<p className="mt-8 text-pretty text-base/8 leading-normal">
Need a bit more? For larger teams we offer personalized support,{' '}
<Link
href="/contact-us/sales"
title="Reach out to us"
onClick={() =>
sendCustomEvent(
'contact-click',
'trial-callout-' + pageId,
'trial-callout'
)
}
className="font-semibold text-blue-500 dark:text-sky-500"
>
reach out to us and we'll help you get started with a trial
</Link>{' '}
that suites your team's needs.{' '}
</p>
</div>
<div className="relative mt-16 h-80 lg:mt-8">
<Image
src="/images/cloud/nrwl-ocean.avif"
alt="App screenshot: overview"
width={2550}
height={1622}
loading="eager"
priority
className="absolute left-0 top-0 w-[57rem] max-w-none rounded-md bg-white/5 ring-1 ring-slate-950/10"
/>
</div> </div>
</div> </div>
</div> </div>
{/*</motion.div>*/}
</section> </section>
); );
} }