Skip to content

Commit

Permalink
Feature: add Hubspot Lead Gen form api (#96)
Browse files Browse the repository at this point in the history
  • Loading branch information
wadehammes authored Oct 10, 2024
1 parent e65aef2 commit ee64f4e
Show file tree
Hide file tree
Showing 7 changed files with 135 additions and 17 deletions.
6 changes: 5 additions & 1 deletion next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,21 @@ module.exports = {
ignoreDuringBuilds: true,
},
env: {
ENVIRONMENT: process.env.ENVIRONMENT,
CONTENTFUL_CONTENT_DELIVERY_API_KEY:
process.env.CONTENTFUL_CONTENT_DELIVERY_API_KEY,
CONTENTFUL_PREVIEW_API_KEY: process.env.CONTENTFUL_PREVIEW_API_KEY,
CONTENTFUL_PREVIEW_SECRET: process.env.CONTENTFUL_PREVIEW_SECRET,
CONTENTFUL_SPACE_ID: process.env.CONTENTFUL_SPACE_ID,
ENVIRONMENT: process.env.ENVIRONMENT,
GA_MEASUREMENT_ID: process.env.GA_MEASUREMENT_ID,
HUBSPOT_API_KEY: process.env.HUBSPOT_API_KEY,
HUBSPOT_LEAD_GENERATION_FORM_ID: process.env.HUBSPOT_LEAD_GENERATION_FORM_ID,
HUBSPOT_PORTAL_ID: process.env.HUBSPOT_PORTAL_ID,
RECAPTCHA_SITE_KEY: process.env.RECAPTCHA_SITE_KEY,
RESEND_API_KEY: process.env.RESEND_API_KEY,
RESEND_GENERAL_AUDIENCE_ID: process.env.RESEND_GENERAL_AUDIENCE_ID,
VERCEL_API_TOKEN: process.env.VERCEL_API_TOKEN,
VERCEL_TEAM_ID: process.env.VERCEL_TEAM_ID,
},
images: {
remotePatterns: [
Expand Down
14 changes: 2 additions & 12 deletions pnpm-lock.yaml

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

15 changes: 15 additions & 0 deletions src/api/urls.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,19 @@ export const api = {
}),
),
},
hubspot: {
leadGeneration: ({
companyName,
email,
name,
phone,
}: Partial<ContactFormInputs>) =>
fetch(
"/api/hubspot/lead-generation",
fetchOptions({
method: FetchMethods.Post,
body: JSON.stringify({ companyName, email, name, phone }),
}),
),
},
};
89 changes: 89 additions & 0 deletions src/app/api/hubspot/lead-generation/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { FetchMethods } from "src/api/helpers";
import type { ContactFormInputs } from "src/components/ContactForm/ContactForm.component";

export async function POST(request: Request) {
const res: ContactFormInputs = await request.json();

const email = res.email;
const firstName = res.name.split(" ")[0] || "";
const lastName = res.name.split(" ")[1] || "";
const phone = res.phone;
const companyName = res.companyName || "";

// API endpoint to check if email is already in Hubspot
const checkEmailInHubspotApiUrl = `https://api.hubapi.com/contacts/v1/contact/email/${email}/profile`;

// API endpoint for the Hubspot lead generation form
const leadGenFormApiUrl = `https://api.hsforms.com/submissions/v3/integration/secure/submit/${process.env.HUBSPOT_PORTAL_ID}/${process.env.HUBSPOT_LEAD_GENERATION_FORM_ID}`;

try {
const checkEmailInHubspot = await fetch(checkEmailInHubspotApiUrl, {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.HUBSPOT_API_KEY}`,
"Content-Type": "application/json",
},
});

if (checkEmailInHubspot.status === 200) {
return Response.json({
message: "Email already exists in Hubspot!",
status: 200,
});
}

const submitLeadForm = await fetch(leadGenFormApiUrl, {
method: FetchMethods.Post,
headers: {
Authorization: `Bearer ${process.env.HUBSPOT_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
fields: [
{
objectTypeId: "0-1",
name: "email",
value: email,
},
{
objectTypeId: "0-1",
name: "firstname",
value: firstName,
},
{
objectTypeId: "0-1",
name: "lastname",
value: lastName,
},
{
objectTypeId: "0-1",
name: "phone",
value: phone,
},
{
objectTypeId: "0-1",
name: "company",
value: companyName,
},
{
objectTypeId: "0-2",
name: "hs_lead_status",
value: "New",
},
],
}),
});

if (submitLeadForm.ok) {
const leadFormResponse = await submitLeadForm.json();

if (leadFormResponse) {
return Response.json(leadFormResponse, { status: 200 });
}
}

return Response.json({ error: "Failed to submit lead form.", status: 500 });
} catch (error) {
return Response.json({ error, status: 500 });
}
}
8 changes: 4 additions & 4 deletions src/app/api/send-email/contact/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ export async function POST(request: Request) {
replyTo: `${name} <${email}>`,
to: "After Avenue <hello@afteravenue.com>",
subject: `Contact Form Submission - ${companyName}`,
text: `You have a new message from ${name} at ${companyName}. ${message} Their contact info is: ${email} ${phone}.`,
html: `<div>You have a new message from ${name} at ${companyName}!<br /><br />Message:<br />${message}<br /><br />Their contact info is:<br />${name}<br />${email}<br />${phone}</div>`,
text: `You have a new message from ${name} at ${companyName}. ${message} Their contact info is: ${email} ${phone}. They have been added to Hubspot and Resend if they are a new contact lead.`,
html: `<div>You have a new message from ${name} at ${companyName}!<br /><br />Message:<br />${message}<br /><br />Their contact info is:<br />${name}<br />${email}<br />${phone}<br /><br />They have been added to Hubspot and Resend if they are a new contact lead.<br /><br />View this lead in Hubspot: https://app.hubspot.com/contacts/${process.env.HUBSPOT_PORTAL_ID}/lists/2/filters?query=${email}</div>`,
});

const delayConfirmationEmail = setTimeout(async () => {
Expand All @@ -48,9 +48,9 @@ export async function POST(request: Request) {
from: "After Avenue <hello@afteravenue.com>",
subject: "We received your contact info.",
text: `Hi, ${name}! We've received your contact for ${companyName} and will respond to you shortly. Feel free to reply back to this email. Thanks, After Avenue - hello@afteravenue.com | https://afteravenue.com`,
html: `<div>Hi, ${name}!<br /><br />We've received your contact for ${companyName} and will respond to you shortly. Feel free to reply back to this email.<br /><br />Thanks, After Avenue<br />hello@afteravenue.com<br />https://afteravenue.com</div>`,
html: `<div>Hi, ${name}!<br /><br />We've received your contact for ${companyName} and will respond to you shortly. Feel free to reply back to this email.<br /><br />Thanks, After Avenue<br />hello@afteravenue.com<br />https://www.afteravenue.com</div>`,
});
}, 1000);
}, 500);

if (data.error) {
clearTimeout(delayConfirmationEmail);
Expand Down
10 changes: 10 additions & 0 deletions src/components/ContactForm/ContactForm.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { StyledButton } from "src/components/StyledButton/StyledButton.component
import { StyledInput } from "src/components/StyledInput/StyledInput.component";
import { StyledTextArea } from "src/components/StyledInput/StyledTextArea.component";
import { useGlobalVariables } from "src/context/globalContext.context";
import { useHubspotLeadGenerationFormApiMutation } from "src/hooks/mutations/useHubspotLeadGenerationFormApi.mutation";
import { useSendContactEmailApiMutation } from "src/hooks/mutations/useSendContactEmailApi.mutation";
import {
EMAIL_VALIDATION_REGEX,
Expand Down Expand Up @@ -47,6 +48,8 @@ export const ContactForm = () => {
reValidateMode: "onBlur",
});
const useSendContactEmailApi = useSendContactEmailApiMutation();
const useHubspotLeadGenerationFormApi =
useHubspotLeadGenerationFormApiMutation();

const submitToNotion: SubmitHandler<ContactFormInputs> = async (data) => {
clearErrors("email");
Expand Down Expand Up @@ -75,6 +78,13 @@ export const ContactForm = () => {
name,
phone,
});

await useHubspotLeadGenerationFormApi.mutateAsync({
companyName,
email: emailToLowerCase,
name,
phone,
});
} catch (_e) {
throw new Error("Failed to submit contact. Please try again.");
}
Expand Down
10 changes: 10 additions & 0 deletions src/hooks/mutations/useHubspotLeadGenerationFormApi.mutation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { useMutation } from "@tanstack/react-query";
import { api } from "src/api/urls";

export const useHubspotLeadGenerationFormApiMutation = () => {
const mutation = useMutation({
mutationFn: api.hubspot.leadGeneration,
});

return mutation;
};

0 comments on commit ee64f4e

Please sign in to comment.