Files
calendar/packages/app-store/_components/crm/WriteToObjectSettings.utils.ts
T
Amit SharmaGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
eacfcd15a4 feat: Hubspot write to meeting object (#26039)
* feat: Hubspot write to meeting object

* fix: translate hardcoded strings and remove debug console.log

Co-Authored-By: amit@cal.com <samit91848@gmail.com>

* refactor

* fix: improve static value detection for placeholder replacement

- Changed condition from startsWith/endsWith to includes('{') to properly detect embedded placeholders
- Strings like 'Hello {name}!' are now correctly processed for placeholder replacement
- Pure placeholder tokens that can't be resolved return null
- Partially resolved values are returned as-is

Co-Authored-By: amit@cal.com <samit91848@gmail.com>

* refactor: split WriteToObjectSettings into types and utils files

- Extract interfaces, enums, and type definitions to WriteToObjectSettings.types.ts
- Extract constants and utility functions to WriteToObjectSettings.utils.ts
- Update main component to use the new utility functions
- Improves code organization and maintainability

Co-Authored-By: amit@cal.com <samit91848@gmail.com>

* revert: restore original static value detection logic

Per user request - the startsWith/endsWith check was intentional

Co-Authored-By: amit@cal.com <samit91848@gmail.com>

* test: add unit tests for HubSpot CRM service

Tests cover:
- ensureFieldsExistOnMeeting: field validation against HubSpot properties
- getTextValueFromBookingTracking: UTM parameter extraction
- getTextValueFromBookingResponse: placeholder replacement
- getDateFieldValue: date field resolution for different date types
- getFieldValue: main field value resolution for all field types
- generateWriteToMeetingBody: write-to-meeting body generation
- getContacts: contact search functionality

Co-Authored-By: amit@cal.com <samit91848@gmail.com>

* fix: correct type errors in HubSpot CRM service tests

- Import WhenToWrite enum from crm-enums
- Replace string literals with WhenToWrite.EVERY_BOOKING enum values
- Add missing whenToWrite property to field config objects

Co-Authored-By: amit@cal.com <samit91848@gmail.com>

* fix: use type casting for intentional type errors in tests

- Cast numeric fieldValue to string for testing non-string handling
- Cast invalid field type string to CrmFieldType for testing unsupported types

Co-Authored-By: amit@cal.com <samit91848@gmail.com>

* fix: prevent unhandled promise rejections in HubSpot CRM tests

- Re-apply mockGetAppKeysFromSlug implementation in beforeEach to ensure
  mock is always set correctly after clearAllMocks
- Change vi.resetAllMocks() to vi.clearAllMocks() to preserve mock
  implementations between tests
- Add explicit types to satisfy biome lint rules
- This fixes the 'Cannot read properties of undefined (reading client_id)'
  errors that were causing CI to fail with exit code 1

Co-Authored-By: amit@cal.com <samit91848@gmail.com>

* refactor: convert HubSpot tests to black-box testing through public methods

Co-Authored-By: amit@cal.com <samit91848@gmail.com>

* fix: properly type mock CalendarEvent in HubSpot tests

Co-Authored-By: amit@cal.com <samit91848@gmail.com>

* fix: properly type TFunction in mock CalendarEvent

Co-Authored-By: amit@cal.com <samit91848@gmail.com>

* chore: graceful owner fail test

* refactor

* fix: type check

* fix: remove null fields

* Update packages/app-store/hubspot/lib/CrmService.ts

Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
2026-01-06 14:58:46 -03:00

71 lines
2.7 KiB
TypeScript

import { CrmFieldType, DateFieldType, WhenToWrite } from "@calcom/app-store/_lib/crm-enums";
import type { SelectOption } from "./WriteToObjectSettings.types";
import { BookingActionEnum } from "./WriteToObjectSettings.types";
export const DATE_FIELD_TYPE = CrmFieldType.DATE;
export const CHECKBOX_FIELD_TYPE = CrmFieldType.CHECKBOX;
export const FIELD_TYPE_LABELS: Record<CrmFieldType, string> = {
[CrmFieldType.TEXT]: "text",
[CrmFieldType.STRING]: "text",
[CrmFieldType.DATE]: "date",
[CrmFieldType.DATETIME]: "datetime",
[CrmFieldType.PHONE]: "phone",
[CrmFieldType.CHECKBOX]: "checkbox",
[CrmFieldType.PICKLIST]: "picklist",
[CrmFieldType.CUSTOM]: "custom",
[CrmFieldType.TEXTAREA]: "textarea",
};
export const DATE_FIELD_LABEL_MAP: Record<DateFieldType, string> = {
[DateFieldType.BOOKING_CANCEL_DATE]: "booking_cancel_date",
[DateFieldType.BOOKING_START_DATE]: "booking_start_date",
[DateFieldType.BOOKING_CREATED_DATE]: "booking_created_date",
};
export const getWhenToWriteLabelMap = (
bookingAction: BookingActionEnum
): Record<WhenToWrite, string> => ({
[WhenToWrite.EVERY_BOOKING]:
bookingAction === BookingActionEnum.ON_CANCEL ? "salesforce_on_every_cancellation" : "on_every_booking",
[WhenToWrite.FIELD_EMPTY]: "only_if_field_is_empty",
});
export const buildFieldTypeOptions = (
supportedFieldTypes: readonly CrmFieldType[],
t: (key: string) => string
): SelectOption<CrmFieldType>[] =>
supportedFieldTypes.map((type) => ({
label: t(FIELD_TYPE_LABELS[type]),
value: type,
}));
export const buildDateFieldValueOptions = (
bookingAction: BookingActionEnum,
supportedDateFields: readonly DateFieldType[] | undefined,
t: (key: string) => string
): SelectOption<DateFieldType>[] => {
const defaultDateFields =
bookingAction === BookingActionEnum.ON_CANCEL
? [DateFieldType.BOOKING_CANCEL_DATE, DateFieldType.BOOKING_START_DATE, DateFieldType.BOOKING_CREATED_DATE]
: [DateFieldType.BOOKING_START_DATE, DateFieldType.BOOKING_CREATED_DATE];
const fields = supportedDateFields ?? defaultDateFields;
return fields.map((type) => ({ label: t(DATE_FIELD_LABEL_MAP[type]), value: type }));
};
export const buildWhenToWriteOptions = (
supportedWriteTriggers: readonly WhenToWrite[],
bookingAction: BookingActionEnum,
t: (key: string) => string
): SelectOption<WhenToWrite>[] => {
const labelMap = getWhenToWriteLabelMap(bookingAction);
return supportedWriteTriggers.map((trigger) => ({ label: t(labelMap[trigger]), value: trigger }));
};
export const buildCheckboxFieldValueOptions = (t: (key: string) => string): SelectOption<boolean>[] => [
{ label: t("true"), value: true },
{ label: t("false"), value: false },
];