diff --git a/apps/web/pages/success.tsx b/apps/web/pages/success.tsx
index a5069b273f..8e03816d91 100644
--- a/apps/web/pages/success.tsx
+++ b/apps/web/pages/success.tsx
@@ -261,7 +261,7 @@ export default function Success(props: SuccessProps) {
data-testid="success-page">
{userIsOwner && !isEmbed && (
-
+
{t("back_to_bookings")}
diff --git a/packages/app-store/hubspotothercalendar/README.mdx b/packages/app-store/hubspotothercalendar/README.mdx
index 7abdcaf237..bf621f6f65 100644
--- a/packages/app-store/hubspotothercalendar/README.mdx
+++ b/packages/app-store/hubspotothercalendar/README.mdx
@@ -6,3 +6,7 @@ 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.
+
+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
diff --git a/packages/app-store/hubspotothercalendar/lib/CalendarService.ts b/packages/app-store/hubspotothercalendar/lib/CalendarService.ts
index f3852147fa..7ff8896bb9 100644
--- a/packages/app-store/hubspotothercalendar/lib/CalendarService.ts
+++ b/packages/app-store/hubspotothercalendar/lib/CalendarService.ts
@@ -15,6 +15,7 @@ import type {
EventBusyDate,
IntegrationCalendar,
NewCalendarEventType,
+ Person,
} from "@calcom/types/Calendar";
import getAppKeysFromSlug from "../../_utils/getAppKeysFromSlug";
@@ -38,6 +39,22 @@ export default class HubspotOtherCalendarService implements Calendar {
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) => {
const publicObjectSearchRequest: PublicObjectSearchRequest = {
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
{
const auth = await this.auth;
await auth.getToken();
const contacts = await this.hubspotContactSearch(event);
- if (contacts) {
- 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 },
- });
+ 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 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 {