Skip to content

Commit

Permalink
NEOS-574:Add peivate beta (#1014)
Browse files Browse the repository at this point in the history
  • Loading branch information
evisdrenova committed Jan 2, 2024
1 parent e34d9ad commit 77009c5
Show file tree
Hide file tree
Showing 4 changed files with 386 additions and 3 deletions.
53 changes: 53 additions & 0 deletions marketing/app/api/private-beta/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { env } from '@/env';
import axios from 'axios';
import { NextRequest, NextResponse } from 'next/server';

export async function POST(req: NextRequest, res: NextResponse) {
const body = await req.json();

const email = body.email;
const company = body.company;

const formData = {
legalConsentOptions: {
consent: {
consentToProcess: true,
text: 'I agree to allow Example Company to store and process my personal data.',
communications: [
{
value: true,
subscriptionTypeId: 999,
text: 'I agree to receive marketing communications from Example Company.',
},
],
},
},
fields: [
{
objectTypeId: '0-1',
name: 'email',
value: email,
},
{
objectTypeId: '0-2',
name: 'company',
value: company,
},
],
};

const options = {
Authorization: `Bearer ${env.HUBSPOT_TOKEN}`,
};

try {
await axios.post(
'https://api.hsforms.com/submissions/v3/integration/secure/submit/24034913/ebe98096-48dc-4009-b38e-8812ae9a9ea1',
formData,
{ headers: options }
);
return NextResponse.json({ message: 'successfully create the lead' });
} catch (e) {
throw e;
}
}
163 changes: 163 additions & 0 deletions marketing/components/buttons/PrivateBetaForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
'use client';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { ArrowRightIcon, ReloadIcon } from '@radix-ui/react-icons';
import { CheckCheckIcon } from 'lucide-react';
import { ReactElement, useState } from 'react';
import { BiErrorCircle } from 'react-icons/bi';
import { FireMixpanel } from '../../lib/mixpanel';
import { Alert, AlertTitle } from '../ui/alert';

type FormStatus = 'success' | 'error' | 'invalid email' | 'null';

export default function PrivateBetaForm(): ReactElement {
const [email, setEmail] = useState<string>('');
const [company, setCompany] = useState<string>('');
const [isSubmitting, setIsSubmitting] = useState<boolean>(false);
const [_, setSubmittedForm] = useState<boolean>(false);
const [formStatus, setFormStatus] = useState<FormStatus>('null');

const handleSubmit = () => {
FireMixpanel('submitted private beta', {
source: 'private beta page',
type: 'submitted pivate beta',
});

if (!isValidEmail(email)) {
setFormStatus('invalid email');
return;
}

setIsSubmitting(true);
const data = {
email: email,
company: company,
};

fetch(`/api/private-beta`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
}).then(async (res) => {
if (res.status == 200) {
setIsSubmitting(false);
setSubmittedForm(true);
setFormStatus('success');
await timeout(3000);
setFormStatus('null');
} else {
setSubmittedForm(false);
setFormStatus('error');
setIsSubmitting(false);
}
});
};

function isValidEmail(email: string): boolean {
const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
return emailRegex.test(email);
}

function timeout(delay: number) {
return new Promise((res) => setTimeout(res, delay));
}

return (
<div className=" flex flex-col z-40 w-full">
<div className="flex flex-col gap-3 pt-8 w-full">
<Input
type="email"
placeholder="Work email"
onChange={(e) => setEmail(e.target.value)}
/>
<Input
type="text"
placeholder="Company"
onChange={(e) => setCompany(e.target.value)}
/>
<Button
type="submit"
id="get-a-demo"
variant="secondary"
className="h-9"
disabled={isSubmitting}
onClick={handleSubmit}
>
{isSubmitting ? (
<ReloadIcon className="mr-2 h-4 w-4 animate-spin justify-c" />
) : (
<div className="flex flex-row items-center space-x-2 w-full justify-center">
<div className="font-normal py-2">Join</div>
<ArrowRightIcon />
</div>
)}
</Button>
</div>
<div className="mt-2">
<FormSubmissionAlert status={formStatus} />
</div>
</div>
);
}

interface SubmissionProps {
status: string;
}

function FormSubmissionAlert(props: SubmissionProps): JSX.Element {
const { status } = props;

if (status == 'success') {
return (
<div className=" w-full">
<Alert
variant="success"
className="flex flex-row items-center space-x-3"
>
<div className="text-green-800">
<CheckCheckIcon className="h-4 w-4" />
</div>
<div>
<AlertTitle>Success</AlertTitle>
</div>
</Alert>
</div>
);
} else if (status == 'error') {
return (
<div className=" w-full">
<Alert
variant="destructive"
className="flex flex-row items-center space-x-3"
>
<div className="text-red-800">
<BiErrorCircle className="h-4 w-4" />
</div>
<div>
<AlertTitle>Error: Try again</AlertTitle>
</div>
</Alert>
</div>
);
} else if (status == 'invalid email') {
return (
<div className=" w-full px-4">
<Alert
variant="destructive"
className="flex flex-row items-center space-x-3"
>
<div className="text-red-800">
<CheckCheckIcon className="h-4 w-4" />
</div>
<div>
<AlertTitle>Error: Invalid Email</AlertTitle>
</div>
</Alert>
</div>
);
}

return <div></div>;
}
51 changes: 48 additions & 3 deletions marketing/components/nav/TopNav.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,14 @@
'use client';
import {
Dialog,
DialogClose,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from '@/components/ui/dialog';
import {
Menubar,
MenubarContent,
Expand All @@ -8,12 +18,13 @@ import {
} from '@/components/ui/menubar';
import { env } from '@/env';
import { FireMixpanel } from '@/lib/mixpanel';
import { GitHubLogoIcon } from '@radix-ui/react-icons';
import { ArrowRightIcon, GitHubLogoIcon } from '@radix-ui/react-icons';
import Image from 'next/image';
import Link from 'next/link';
import { useRouter } from 'next/navigation';
import { ReactElement } from 'react';
import { GiHamburgerMenu } from 'react-icons/gi';
import PrivateBetaForm from '../buttons/PrivateBetaForm';
import { Button } from '../ui/button';

export default function TopNav(): ReactElement {
Expand Down Expand Up @@ -81,7 +92,7 @@ export default function TopNav(): ReactElement {
</div>
<div>
<Button
variant="default"
variant="navLink"
onClick={() => {
FireMixpanel('github button', {
source: 'top-nav',
Expand All @@ -91,11 +102,45 @@ export default function TopNav(): ReactElement {
>
<Link href="https://github.com/nucleuscloud/neosync">
<div className="flex flex-row items-center">
Star us on <GitHubLogoIcon className="ml-2 h-4 w-4" />
<GitHubLogoIcon className="ml-2 h-4 w-4" />
</div>
</Link>
</Button>
</div>
<div>
<Dialog>
<DialogTrigger asChild>
<Button variant="default">
Private Beta <ArrowRightIcon className="ml-2 h-5 w-5" />
</Button>
</DialogTrigger>
<DialogContent className="sm:max-w-lg bg-black border border-gray-600 p-6">
<DialogHeader>
<DialogTitle className="text-white text-2xl">
Join the Neosync Cloud Private Beta
</DialogTitle>
<DialogDescription className="pt-10 text-gray-300 text-md">
Want to use Neosync but don&apos;t want to host it yourself?
Sign up for the private beta of Neosync Cloud.
</DialogDescription>
</DialogHeader>
<div className="flex items-center space-x-2">
<PrivateBetaForm />
</div>
<DialogFooter className="sm:justify-start">
<DialogClose asChild>
<Button
type="button"
variant="ghost"
className="text-white hover:bg-gray-800 hover:text-white"
>
Close
</Button>
</DialogClose>
</DialogFooter>
</DialogContent>
</Dialog>
</div>
</div>
<MobileMenu />
</div>
Expand Down
Loading

1 comment on commit 77009c5

@vercel
Copy link

@vercel vercel bot commented on 77009c5 Jan 2, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.