HubSpot app improvement: create contacts (#3502)

* WIP

* Last changes

* Create non-existing contacts from attendees

* Adding list of features

* Removing unneeded code

* Missing error when creating contacts

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
pull/3523/head^2
Leo Giovanetti 2022-07-25 16:13:52 -03:00 committed by GitHub
parent 43a6e3f5ce
commit 82d8db5f70
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 65 additions and 17 deletions

View File

@ -261,7 +261,7 @@ export default function Success(props: SuccessProps) {
data-testid="success-page"> data-testid="success-page">
{userIsOwner && !isEmbed && ( {userIsOwner && !isEmbed && (
<div className="mt-2 ml-4 -mb-4"> <div className="mt-2 ml-4 -mb-4">
<Link href={eventType.recurringEvent?.count ? "/bookings/recurring" : "/bookings"}> <Link href={eventType.recurringEvent?.count ? "/bookings/recurring" : "/bookings/upcoming"}>
<a className="mt-2 inline-flex px-1 py-2 text-sm text-gray-500 hover:bg-gray-100 hover:text-gray-800"> <a className="mt-2 inline-flex px-1 py-2 text-sm text-gray-500 hover:bg-gray-100 hover:text-gray-800">
<ChevronLeftIcon className="h-5 w-5" /> {t("back_to_bookings")} <ChevronLeftIcon className="h-5 w-5" /> {t("back_to_bookings")}
</a> </a>

View File

@ -6,3 +6,7 @@ items:
<Slider items={items} /> <Slider items={items} />
HubSpot is a cloud-based CRM designed to help align sales and marketing teams, foster sales enablement, boost ROI and optimize your inbound marketing strategy to generate more, qualified leads. HubSpot is a cloud-based CRM designed to help align sales and marketing teams, foster sales enablement, boost ROI and optimize your inbound marketing strategy to generate more, qualified leads.
Features:
- Creates a meeting in HubSpot for one or many attendees
- Attendees that don't exist in HubSpot, gets created first to associate them in the meeting

View File

@ -15,6 +15,7 @@ import type {
EventBusyDate, EventBusyDate,
IntegrationCalendar, IntegrationCalendar,
NewCalendarEventType, NewCalendarEventType,
Person,
} from "@calcom/types/Calendar"; } from "@calcom/types/Calendar";
import getAppKeysFromSlug from "../../_utils/getAppKeysFromSlug"; import getAppKeysFromSlug from "../../_utils/getAppKeysFromSlug";
@ -38,6 +39,22 @@ export default class HubspotOtherCalendarService implements Calendar {
this.log = logger.getChildLogger({ prefix: [`[[lib] ${this.integrationName}`] }); this.log = logger.getChildLogger({ prefix: [`[[lib] ${this.integrationName}`] });
} }
private hubspotContactCreate = async (attendees: Person[]) => {
const simplePublicObjectInputs: SimplePublicObjectInput[] = attendees.map((attendee) => {
const [firstname, lastname] = attendee.name ? attendee.name.split(" ") : [attendee.email, ""];
return {
properties: {
firstname,
lastname,
email: attendee.email,
},
};
});
return Promise.all(
simplePublicObjectInputs.map((contact) => hubspotClient.crm.contacts.basicApi.create(contact))
);
};
private hubspotContactSearch = async (event: CalendarEvent) => { private hubspotContactSearch = async (event: CalendarEvent) => {
const publicObjectSearchRequest: PublicObjectSearchRequest = { const publicObjectSearchRequest: PublicObjectSearchRequest = {
filterGroups: event.attendees.map((attendee) => ({ filterGroups: event.attendees.map((attendee) => ({
@ -168,11 +185,7 @@ export default class HubspotOtherCalendarService implements Calendar {
}; };
}; };
async createEvent(event: CalendarEvent): Promise<NewCalendarEventType> { async handleMeetingCreation(event: CalendarEvent, contacts: SimplePublicObjectInput[]) {
const auth = await this.auth;
await auth.getToken();
const contacts = await this.hubspotContactSearch(event);
if (contacts) {
const meetingEvent = await this.hubspotCreateMeeting(event); const meetingEvent = await this.hubspotCreateMeeting(event);
if (meetingEvent) { if (meetingEvent) {
const associatedMeeting = await this.hubspotAssociate(meetingEvent, contacts); const associatedMeeting = await this.hubspotAssociate(meetingEvent, contacts);
@ -190,7 +203,38 @@ export default class HubspotOtherCalendarService implements Calendar {
} }
return Promise.reject("Something went wrong when creating a meeting in HubSpot"); return Promise.reject("Something went wrong when creating a meeting in HubSpot");
} }
return Promise.reject("Something went wrong when searching the atendee in HubSpot");
async createEvent(event: CalendarEvent): Promise<NewCalendarEventType> {
const auth = await this.auth;
await auth.getToken();
const contacts = await this.hubspotContactSearch(event);
if (contacts.length) {
if (contacts.length == event.attendees.length) {
// All attendees do exist in HubSpot
return await this.handleMeetingCreation(event, contacts);
} else {
// Some attendees don't exist in HubSpot
// Get the existing contacts' email to filter out
const existingContacts = contacts.map((contact) => contact.properties.email);
// Get non existing contacts filtering out existing from attendees
const nonExistingContacts = event.attendees.filter(
(attendee) => !existingContacts.includes(attendee.email)
);
// Only create contacts in HubSpot that were not present in the previous contact search
const createContacts = await this.hubspotContactCreate(nonExistingContacts);
// Continue with meeting creation and association only when all contacts are present in HubSpot
if (createContacts.length) {
return await this.handleMeetingCreation(event, createContacts.concat(contacts));
}
return Promise.reject("Something went wrong when creating non-existing attendees in HubSpot");
}
} else {
const createContacts = await this.hubspotContactCreate(event.attendees);
if (createContacts.length) {
return await this.handleMeetingCreation(event, createContacts);
}
}
return Promise.reject("Something went wrong when searching/creating the attendees in HubSpot");
} }
async updateEvent(uid: string, event: CalendarEvent): Promise<any> { async updateEvent(uid: string, event: CalendarEvent): Promise<any> {