Skip to content

Commit

Permalink
feat: mailgun integration (#14)
Browse files Browse the repository at this point in the history
* feat: addToMailList from API Route

* feat: email submit form

* feat: mailgun integration

* feat: toasts
  • Loading branch information
StereoPT authored Jul 19, 2024
1 parent 67c84da commit f2dab17
Show file tree
Hide file tree
Showing 10 changed files with 289 additions and 3 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,5 @@ yarn-error.log*
# typescript
*.tsbuildinfo
next-env.d.ts

.env
128 changes: 128 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,17 @@
"@hookform/resolvers": "^3.6.0",
"@react-pdf/renderer": "^3.4.4",
"@vercel/analytics": "^1.3.1",
"axios": "^1.7.2",
"clsx": "^2.1.1",
"jotai": "^2.8.3",
"mailgun.js": "^10.2.3",
"next": "14.2.4",
"react": "^18",
"react-daisyui": "^5.0.0",
"react-dom": "^18",
"react-hook-form": "^7.52.0",
"react-icons": "^5.2.1",
"react-toastify": "^10.0.5",
"tailwind-merge": "^2.3.0",
"yup": "^1.4.0"
},
Expand Down
27 changes: 24 additions & 3 deletions src/components/LandingPage/EmailSignup.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,22 @@
import { Button, Input } from 'react-daisyui';
import { SubmitHandler, useForm } from 'react-hook-form';
import { yupResolver } from '@hookform/resolvers/yup';

import { MailListInputs, mailListSchema } from '@/schemas/mailList';

import useAddMailList from '@/hooks/useAddMailList';

const EmailSignup = () => {
const { addEmailToList } = useAddMailList();
const { register, handleSubmit, reset } = useForm<MailListInputs>({
resolver: yupResolver(mailListSchema),
});

const onFormSubmit: SubmitHandler<MailListInputs> = ({ email }) => {
addEmailToList(email);
reset();
};

return (
<section id="email">
<div className="px-4 lg:px-6 max-w-[72rem] mx-auto">
Expand All @@ -13,14 +29,19 @@ const EmailSignup = () => {
Join our community for news, insights, and special promotions.
</p>
</div>
<div className="flex flex-col sm:flex-row gap-4">
<form
onSubmit={handleSubmit(onFormSubmit)}
className="flex flex-col sm:flex-row gap-4">
<Input
{...register('email')}
type="email"
className="w-80"
placeholder="Your Email Address"
/>
<Button color="primary">Subscribe</Button>
</div>
<Button className="text-white" color="primary">
Subscribe
</Button>
</form>
</div>
</div>
</section>
Expand Down
24 changes: 24 additions & 0 deletions src/hooks/useAddMailList.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { postRequest } from '@/utils/axios';
import { toast } from 'react-toastify';

const useAddMailList = () => {
const addEmailToList = async (email: string) => {
try {
await postRequest('/joinMailList', {
email,
});

toast.success('Successfully Subscribed!', {
position: 'top-right',
});
} catch (error) {
toast.error('Something went Wrong!', {
position: 'top-right',
});
}
};

return { addEmailToList };
};

export default useAddMailList;
16 changes: 16 additions & 0 deletions src/libs/mailgun.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import formData from 'form-data';
import Mailgun from 'mailgun.js';

const mailgun = new Mailgun(formData);
const mailListAddress = process.env.MAILGUN_MAILLIST || 'dummy';

const mg = mailgun.client({
username: 'API',
key: process.env.MAILGUN_API_KEY || 'dummy',
});

export const addToMailList = async (email: string) => {
await mg.lists.members.createMember(mailListAddress, {
address: email,
});
};
3 changes: 3 additions & 0 deletions src/pages/_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ import { ReactElement, ReactNode } from 'react';
import { NextPage } from 'next';
import Head from 'next/head';
import { Theme } from 'react-daisyui';
import { ToastContainer } from 'react-toastify';

import '@/styles/globals.css';
import 'react-toastify/dist/ReactToastify.css';

import type { AppProps } from 'next/app';
import { Analytics } from '@vercel/analytics/react';
Expand Down Expand Up @@ -86,6 +88,7 @@ Menu design software"
</Head>
<Theme dataTheme="emerald">
{getLayout(<Component {...pageProps} />)}
<ToastContainer />
<Analytics />
</Theme>
</>
Expand Down
26 changes: 26 additions & 0 deletions src/pages/api/joinMailList.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import type { NextApiRequest, NextApiResponse } from 'next';

import { addToMailList } from '@/libs/mailgun';

type ResponseData = {
message: string;
};

export default async function handler(
req: NextApiRequest,
res: NextApiResponse<ResponseData>,
) {
try {
const { email } = req.body;

if (!email) {
throw new Error('Missing Email');
}

await addToMailList(email);
res.status(200).json({ message: 'Thanks for Joining my Mail List!' });
} catch (error) {
console.error(error);
res.status(500).json({ message: 'Something went wrong!' });
}
}
7 changes: 7 additions & 0 deletions src/schemas/mailList.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import * as yup from 'yup';

export const mailListSchema = yup.object({
email: yup.string().trim().email().required(),
});

export type MailListInputs = yup.InferType<typeof mailListSchema>;
Loading

0 comments on commit f2dab17

Please sign in to comment.