Skip to content

Commit

Permalink
feat: add-to-waitlist form
Browse files Browse the repository at this point in the history
  • Loading branch information
johnshift committed Aug 30, 2024
1 parent ba6d8f1 commit a91cbe1
Show file tree
Hide file tree
Showing 6 changed files with 188 additions and 12 deletions.
Binary file removed public/rocket.png
Binary file not shown.
132 changes: 132 additions & 0 deletions src/app/coming-soon/coming-soon-form.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
'use client';

import { useState } from 'react';

import { Button, Input } from '@nextui-org/react';

import { useAddToWaitlist } from '@/shared/hooks/use-add-to-waitlist';

const EmailIcon = () => (
<svg
fill="none"
strokeWidth={1.5}
stroke="currentColor"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
aria-hidden="true"
className="pointer-events-none size-6 shrink-0 text-default-400"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M21.75 6.75v10.5a2.25 2.25 0 0 1-2.25 2.25h-15a2.25 2.25 0 0 1-2.25-2.25V6.75m19.5 0A2.25 2.25 0 0 0 19.5 4.5h-15a2.25 2.25 0 0 0-2.25 2.25m19.5 0v.243a2.25 2.25 0 0 1-1.07 1.916l-7.5 4.615a2.25 2.25 0 0 1-2.36 0L3.32 8.91a2.25 2.25 0 0 1-1.07-1.916V6.75"
/>
</svg>
);

const CompanyIcon = () => (
<svg
fill="none"
strokeWidth={1.5}
stroke="currentColor"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
aria-hidden="true"
className="pointer-events-none size-6 shrink-0 text-default-400"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M2.25 21h19.5m-18-18v18m10.5-18v18m6-13.5V21M6.75 6.75h.75m-.75 3h.75m-.75 3h.75m3-6h.75m-.75 3h.75m-.75 3h.75M6.75 21v-3.375c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125V21M3 3h12m-.75 4.5H21m-3.75 3.75h.008v.008h-.008v-.008Zm0 3h.008v.008h-.008v-.008Zm0 3h.008v.008h-.008v-.008Z"
/>
</svg>
);

const RoleIcon = () => (
<svg
fill="none"
strokeWidth={1.5}
stroke="currentColor"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
aria-hidden="true"
className="pointer-events-none size-6 shrink-0 text-default-400"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M15.75 6a3.75 3.75 0 1 1-7.5 0 3.75 3.75 0 0 1 7.5 0ZM4.501 20.118a7.5 7.5 0 0 1 14.998 0A17.933 17.933 0 0 1 12 21.75c-2.676 0-5.216-.584-7.499-1.632Z"
/>
</svg>
);

const inputs = [
{
name: 'email',
placeholder: 'Email',
icon: <EmailIcon />,
},
{
name: 'company',
placeholder: 'Company',
icon: <CompanyIcon />,
},
{
name: 'role',
placeholder: 'Role',
icon: <RoleIcon />,
},
];

const DEFAULT_FORM_STATE = {
email: '',
company: '',
role: '',
};

export const ComingSoonForm = () => {
const [formState, setFormState] = useState(DEFAULT_FORM_STATE);

const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const { name, value } = e.target;
setFormState((prevState) => ({
...prevState,
[name]: value,
}));
};

const { mutate, isPending } = useAddToWaitlist();

const handleSubmit = () => {
mutate(formState, { onSuccess: () => setFormState(DEFAULT_FORM_STATE) });
};

return (
<div className="w-full max-w-xs space-y-4">
{inputs.map((input) => (
<Input
key={input.name}
size="lg"
startContent={input.icon}
fullWidth
variant="bordered"
placeholder={input.placeholder}
name={input.name}
isDisabled={isPending}
value={formState[input.name as keyof typeof formState]}
onChange={handleChange}
/>
))}
<div className="pt-4">
<Button
fullWidth
className="is-active font-medium"
isLoading={isPending}
onClick={handleSubmit}
>
Join Waitlist
</Button>
</div>
</div>
);
};
4 changes: 2 additions & 2 deletions src/app/coming-soon/coming-soon-text.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import React from 'react';

const TEXT = 'Coming Soon';
const TEXT = 'Coming Soon!';

export const ComingSoonText = () => {
return (
<div className="stack max-w-lg font-grotesk text-4xl font-bold text-white">
<div className="stack max-w-2xl font-grotesk font-bold text-white">
{Array.from({ length: 3 }).map((_, index) => (
<span
key={index}
Expand Down
22 changes: 12 additions & 10 deletions src/app/coming-soon/page.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
import Image from 'next/image';

import { ComingSoonForm } from '@/app/coming-soon/coming-soon-form';
import { ComingSoonText } from '@/app/coming-soon/coming-soon-text';

const Page = () => {
return (
<div className="relative flex h-screen w-full flex-col items-center justify-center gap-2">
<Image
priority
src={'/rocket.png'}
quality={100}
alt={'Coming Soon'}
width={371}
height={371}
/>
<ComingSoonText />
<div className="mt-4 flex max-w-sm flex-col items-center justify-center space-y-4">
<h2 className="bg-gradient-to-r from-white to-[#D99073] bg-clip-text text-4xl font-extrabold text-transparent">
Join our waitlist!
</h2>
<span className="pb-4 text-white/60">
Connect with Web3 leaders, get paid as a verified rep, and enjoy
dynamic fees that match demand.
</span>

<ComingSoonForm />
</div>
</div>
);
};
Expand Down
1 change: 1 addition & 0 deletions src/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ html {
}

.stack span {
font-size: 4.0rem;
grid-row-start: 1;
grid-column-start: 1;
--stack-height: calc(100% / 3 - 1px);
Expand Down
41 changes: 41 additions & 0 deletions src/shared/hooks/use-add-to-waitlist.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import toast from 'react-hot-toast';

import { useMutation } from '@tanstack/react-query';
import { z } from 'zod';

import { MW_URL } from '@/shared/core/envs';
import { genericResponseSchema } from '@/shared/core/schemas';
import { mwPOST } from '@/shared/utils/mw-post';

const waitlistPayloadSchema = z.object({
email: z
.string()
.min(1, { message: 'Email is required' })
.email({ message: 'Invalid email address' }),
company: z.string().min(1, { message: 'Company is required' }),
role: z.string().min(1, { message: 'Role is required' }),
});
type WaitlistPayload = z.infer<typeof waitlistPayloadSchema>;

const addToWaitlist = async (payload: WaitlistPayload) => {
const { success, message } = await mwPOST({
url: `${MW_URL}/grants/mail`,
label: 'addToWaitlist',
payload,
payloadSchema: waitlistPayloadSchema,
responseSchema: genericResponseSchema,
});

if (!success) {
throw new Error(message);
}

return { message };
};

export const useAddToWaitlist = () =>
useMutation({
mutationFn: (payload: WaitlistPayload) => addToWaitlist(payload),
onSuccess: () => toast.success('You have been added to the waitlist!'),
onError: (error) => toast.error(error.message),
});

0 comments on commit a91cbe1

Please sign in to comment.