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
parent
43a6e3f5ce
commit
82d8db5f70
|
@ -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>
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,29 +185,56 @@ export default class HubspotOtherCalendarService implements Calendar {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
async handleMeetingCreation(event: CalendarEvent, contacts: SimplePublicObjectInput[]) {
|
||||||
|
const meetingEvent = await this.hubspotCreateMeeting(event);
|
||||||
|
if (meetingEvent) {
|
||||||
|
const associatedMeeting = await this.hubspotAssociate(meetingEvent, contacts);
|
||||||
|
if (associatedMeeting) {
|
||||||
|
return Promise.resolve({
|
||||||
|
uid: meetingEvent.id,
|
||||||
|
id: meetingEvent.id,
|
||||||
|
type: "hubspot_other_calendar",
|
||||||
|
password: "",
|
||||||
|
url: "",
|
||||||
|
additionalInfo: { contacts, associatedMeeting },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return Promise.reject("Something went wrong when associating the meeting and attendees in HubSpot");
|
||||||
|
}
|
||||||
|
return Promise.reject("Something went wrong when creating a meeting in HubSpot");
|
||||||
|
}
|
||||||
|
|
||||||
async createEvent(event: CalendarEvent): Promise<NewCalendarEventType> {
|
async createEvent(event: CalendarEvent): Promise<NewCalendarEventType> {
|
||||||
const auth = await this.auth;
|
const auth = await this.auth;
|
||||||
await auth.getToken();
|
await auth.getToken();
|
||||||
const contacts = await this.hubspotContactSearch(event);
|
const contacts = await this.hubspotContactSearch(event);
|
||||||
if (contacts) {
|
if (contacts.length) {
|
||||||
const meetingEvent = await this.hubspotCreateMeeting(event);
|
if (contacts.length == event.attendees.length) {
|
||||||
if (meetingEvent) {
|
// All attendees do exist in HubSpot
|
||||||
const associatedMeeting = await this.hubspotAssociate(meetingEvent, contacts);
|
return await this.handleMeetingCreation(event, contacts);
|
||||||
if (associatedMeeting) {
|
} else {
|
||||||
return Promise.resolve({
|
// Some attendees don't exist in HubSpot
|
||||||
uid: meetingEvent.id,
|
// Get the existing contacts' email to filter out
|
||||||
id: meetingEvent.id,
|
const existingContacts = contacts.map((contact) => contact.properties.email);
|
||||||
type: "hubspot_other_calendar",
|
// Get non existing contacts filtering out existing from attendees
|
||||||
password: "",
|
const nonExistingContacts = event.attendees.filter(
|
||||||
url: "",
|
(attendee) => !existingContacts.includes(attendee.email)
|
||||||
additionalInfo: { contacts, associatedMeeting },
|
);
|
||||||
});
|
// 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 associating the meeting and attendees in HubSpot");
|
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 creating a meeting in HubSpot");
|
|
||||||
}
|
}
|
||||||
return Promise.reject("Something went wrong when searching the atendee in HubSpot");
|
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> {
|
||||||
|
|
Loading…
Reference in New Issue