@meetelise/chat 1.35.0 → 1.35.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/MyPubnub.d.ts +116 -0
- package/dist/src/WebComponent/FeeCalculator/components/addons/addon-item-matrix-qty-selector/addon-item-matrix-qty-selector-styles.d.ts +2 -0
- package/dist/src/WebComponent/FeeCalculator/components/addons/addon-item-matrix-qty-selector/addon-item-matrix-qty-selector.d.ts +28 -0
- package/dist/src/WebComponent/FeeCalculator/components/addons/addon-item-qty-selector/addon-item-qty-selector-styles.d.ts +2 -0
- package/dist/src/WebComponent/FeeCalculator/components/addons/addon-item-qty-selector/addon-item-qty-selector.d.ts +18 -0
- package/dist/src/WebComponent/FeeCalculator/components/addons/common-addon-styles.d.ts +2 -0
- package/dist/src/WebComponent/FeeCalculator/components/addons/rentable-item-qty-selector/rentable-item-qty-selector-styles.d.ts +2 -0
- package/dist/src/WebComponent/FeeCalculator/components/addons/rentable-item-qty-selector/rentable-item-qty-selector.d.ts +22 -0
- package/dist/src/WebComponent/FeeCalculator/components/fee-calculator-layout/fee-calculator-layout-styles.d.ts +2 -0
- package/dist/src/WebComponent/FeeCalculator/components/fee-calculator-layout/fee-calculator-layout.d.ts +46 -0
- package/dist/src/WebComponent/FeeCalculator/components/fee-card/fee-card-styles.d.ts +2 -0
- package/dist/src/WebComponent/FeeCalculator/components/fee-card/fee-card.d.ts +21 -0
- package/dist/src/WebComponent/FeeCalculator/components/fee-item/fee-item-styles.d.ts +2 -0
- package/dist/src/WebComponent/FeeCalculator/components/fee-item/fee-item.d.ts +13 -0
- package/dist/src/WebComponent/FeeCalculator/components/floor-plan-selector/floor-plan-selector-styles.d.ts +2 -0
- package/dist/src/WebComponent/FeeCalculator/components/floor-plan-selector/floor-plan-selector.d.ts +34 -0
- package/dist/src/WebComponent/FeeCalculator/components/floorplan-image-card/floorplan-image-card-styles.d.ts +2 -0
- package/dist/src/WebComponent/FeeCalculator/components/floorplan-image-card/floorplan-image-card.d.ts +18 -0
- package/dist/src/WebComponent/FeeCalculator/components/incentive-banner/incentive-banner-styles.d.ts +1 -0
- package/dist/src/WebComponent/FeeCalculator/components/incentive-banner/incentive-banner.d.ts +8 -0
- package/dist/src/WebComponent/FeeCalculator/components/incentive-banner/index.d.ts +1 -0
- package/dist/src/WebComponent/FeeCalculator/components/index.d.ts +5 -0
- package/dist/src/WebComponent/FeeCalculator/components/promo-card/promo-card-styles.d.ts +2 -0
- package/dist/src/WebComponent/FeeCalculator/components/promo-card/promo-card.d.ts +13 -0
- package/dist/src/WebComponent/FeeCalculator/constants.d.ts +3 -0
- package/dist/src/WebComponent/FeeCalculator/fee-calculator-styles.d.ts +1 -0
- package/dist/src/WebComponent/FeeCalculator/fee-calculator.d.ts +55 -0
- package/dist/src/WebComponent/FeeCalculator/index.d.ts +2 -0
- package/dist/src/WebComponent/FeeCalculator/model/building-fee-view.d.ts +41 -0
- package/dist/src/WebComponent/FeeCalculator/model/building-fee.d.ts +82 -0
- package/dist/src/WebComponent/FeeCalculator/model/desired-addon.d.ts +5 -0
- package/dist/src/WebComponent/FeeCalculator/model/desired-rentable-item.d.ts +4 -0
- package/dist/src/WebComponent/FeeCalculator/model/index.d.ts +13 -0
- package/dist/src/WebComponent/FeeCalculator/model/item-combination.d.ts +6 -0
- package/dist/src/WebComponent/FeeCalculator/model/item-quantity.d.ts +4 -0
- package/dist/src/WebComponent/FeeCalculator/model/pricing-matrix.d.ts +18 -0
- package/dist/src/WebComponent/FeeCalculator/model/pricing-rule.d.ts +8 -0
- package/dist/src/WebComponent/FeeCalculator/model/rent-frequency.d.ts +1 -0
- package/dist/src/WebComponent/FeeCalculator/model/rentable-item-summary.d.ts +9 -0
- package/dist/src/WebComponent/FeeCalculator/model/rentable-item.d.ts +9 -0
- package/dist/src/WebComponent/FeeCalculator/model/transaction-category.d.ts +23 -0
- package/dist/src/WebComponent/FeeCalculator/model/unit-fee-bundle.d.ts +31 -0
- package/dist/src/WebComponent/LeadSourceClient.d.ts +46 -0
- package/dist/src/WebComponent/OfficeHours.d.ts +21 -0
- package/dist/src/WebComponent/Scheduler/date-picker.d.ts +28 -0
- package/dist/src/WebComponent/Scheduler/time-picker.d.ts +16 -0
- package/dist/src/WebComponent/Scheduler/tour-scheduler.d.ts +102 -0
- package/dist/src/WebComponent/Scheduler/tour-type-option.d.ts +13 -0
- package/dist/src/WebComponent/Scheduler/tourSchedulerStyles.d.ts +1 -0
- package/dist/src/WebComponent/actions/InputStyles.d.ts +1 -0
- package/dist/src/WebComponent/actions/action-confirm-button.d.ts +13 -0
- package/dist/src/WebComponent/actions/call-us-window.d.ts +37 -0
- package/dist/src/WebComponent/actions/collapse-expand-button.d.ts +8 -0
- package/dist/src/WebComponent/actions/details-window.d.ts +14 -0
- package/dist/src/WebComponent/actions/email-us-window.d.ts +46 -0
- package/dist/src/WebComponent/actions/formatPhoneNumber.d.ts +17 -0
- package/dist/src/WebComponent/actions/minimize-expand-button.d.ts +8 -0
- package/dist/src/WebComponent/chat-additional-actions.d.ts +28 -0
- package/dist/src/WebComponent/health-chat.d.ts +47 -0
- package/dist/src/WebComponent/healthchat-styles.d.ts +1 -0
- package/dist/src/WebComponent/icons/ApplyOutlineIcon.d.ts +2 -0
- package/dist/src/WebComponent/icons/BookTourOutlineIcon.d.ts +2 -0
- package/dist/src/WebComponent/icons/CalculatorOutlineIcon.d.ts +2 -0
- package/dist/src/WebComponent/icons/ChatOutlineIcon.d.ts +2 -0
- package/dist/src/WebComponent/icons/ChevronLeftIcon.d.ts +2 -0
- package/dist/src/WebComponent/icons/ChevronRightIcon.d.ts +2 -0
- package/dist/src/WebComponent/icons/ContactResidentIcon.d.ts +2 -0
- package/dist/src/WebComponent/icons/DollarOutlineIcon.d.ts +7 -0
- package/dist/src/WebComponent/icons/EmailOutlineIcon.d.ts +2 -0
- package/dist/src/WebComponent/icons/HeyThereEmojiIcon.d.ts +2 -0
- package/dist/src/WebComponent/icons/PhoneOutlineIcon.d.ts +2 -0
- package/dist/src/WebComponent/icons/SendMessageIcon.d.ts +3 -0
- package/dist/src/WebComponent/icons/TourSelfGuidedIcon.d.ts +2 -0
- package/dist/src/WebComponent/icons/TourVirtuallyIcon.d.ts +2 -0
- package/dist/src/WebComponent/icons/TourWithAgentIcon.d.ts +2 -0
- package/dist/src/WebComponent/icons/XOutlineIcon.d.ts +2 -0
- package/dist/src/WebComponent/index.d.ts +2 -0
- package/dist/src/WebComponent/launcher/Launcher.d.ts +99 -0
- package/dist/src/WebComponent/launcher/launcherStyles.d.ts +1 -0
- package/dist/src/WebComponent/launcher/mobile-launcher.d.ts +27 -0
- package/dist/src/WebComponent/launcher/typeEmojiStyles.d.ts +1 -0
- package/dist/src/WebComponent/launcher/typeMiniStyles.d.ts +1 -0
- package/dist/src/WebComponent/launcher/typeMobileStyles.d.ts +1 -0
- package/dist/src/WebComponent/leasing-chat-styles.d.ts +1 -0
- package/dist/src/WebComponent/loaders/index.d.ts +4 -0
- package/dist/src/WebComponent/loaders/mega-loader.d.ts +7 -0
- package/dist/src/WebComponent/loaders/skeleton-card.d.ts +12 -0
- package/dist/src/WebComponent/loaders/skeleton-loader-styles.d.ts +3 -0
- package/dist/src/WebComponent/loaders/skeleton-loader.d.ts +13 -0
- package/dist/src/WebComponent/me-chat.d.ts +91 -0
- package/dist/src/WebComponent/me-select.d.ts +24 -0
- package/dist/src/WebComponent/mini-loader.d.ts +5 -0
- package/dist/src/WebComponent/pubnub-chat-styles.d.ts +1 -0
- package/dist/src/WebComponent/pubnub-chat.d.ts +48 -0
- package/dist/src/WebComponent/pubnub-media.d.ts +14 -0
- package/dist/src/WebComponent/pubnub-message-styles.d.ts +1 -0
- package/dist/src/WebComponent/pubnub-message.d.ts +39 -0
- package/dist/src/WebComponent/simple-launcher/simple-launcher-styles.d.ts +1 -0
- package/dist/src/WebComponent/simple-launcher/simple-launcher.d.ts +12 -0
- package/dist/src/WebComponent/utilities-chat.d.ts +47 -0
- package/dist/src/WebComponent/utilities-styles.d.ts +1 -0
- package/dist/src/WebComponent/utils.d.ts +31 -0
- package/dist/src/analytics.d.ts +64 -0
- package/dist/src/disclaimers.d.ts +16 -0
- package/dist/src/fetchBuildingABTestType.d.ts +8 -0
- package/dist/src/fetchBuildingInfo.d.ts +58 -0
- package/dist/src/fetchBuildingWebchatView.d.ts +124 -0
- package/dist/src/fetchFeatureFlag.d.ts +14 -0
- package/dist/src/fetchLeadSources.d.ts +4 -0
- package/dist/src/fetchPhoneNumberFromSource.d.ts +6 -0
- package/dist/src/getAvailabilities.d.ts +46 -0
- package/dist/src/getBuildingPhoneNumber.d.ts +1 -0
- package/dist/src/getShouldAllowScheduling.d.ts +1 -0
- package/dist/src/getShouldShowWebchat.d.ts +3 -0
- package/dist/src/getTimezoneString.d.ts +1 -0
- package/dist/src/globals.d.ts +2 -0
- package/dist/src/gtm.d.ts +6 -0
- package/dist/src/handleChatId.d.ts +11 -0
- package/dist/src/insertDNIIntoWebsite.d.ts +5 -0
- package/dist/src/insertLeadSourceIntoSchedulerLinks.d.ts +4 -0
- package/dist/src/main/MEChat.d.ts +74 -0
- package/dist/src/main/utils.d.ts +2 -0
- package/dist/src/postLeadSources.d.ts +3 -0
- package/dist/src/rentgrata.d.ts +4 -0
- package/dist/src/replaceSelectButtonsWithNewLink.d.ts +5 -0
- package/dist/src/services/fees/calculateQuote.d.ts +14 -0
- package/dist/src/services/fees/fetchBuildingFeesV2.d.ts +10 -0
- package/dist/src/services/fees/fetchBuildingUnits.d.ts +29 -0
- package/dist/src/services/fees/utils.d.ts +1 -0
- package/dist/src/svgIcons.d.ts +5 -0
- package/dist/src/themes.d.ts +5 -0
- package/dist/src/types/incentive-v2.d.ts +23 -0
- package/dist/src/types/rest-sdk.types.d.ts +11 -0
- package/dist/src/types/webchat-no-show-reason.d.ts +1 -0
- package/dist/src/utils/getWidgetOverrides.d.ts +39 -0
- package/dist/src/utils/queryParamBuilder.d.ts +8 -0
- package/dist/src/utils.d.ts +13 -0
- package/package.json +1 -1
- package/src/MyPubnub.ts +792 -0
- package/src/WebComponent/FeeCalculator/components/addons/addon-item-matrix-qty-selector/addon-item-matrix-qty-selector-styles.ts +35 -0
- package/src/WebComponent/FeeCalculator/components/addons/addon-item-matrix-qty-selector/addon-item-matrix-qty-selector.ts +206 -0
- package/src/WebComponent/FeeCalculator/components/addons/addon-item-qty-selector/addon-item-qty-selector-styles.ts +6 -0
- package/src/WebComponent/FeeCalculator/components/addons/addon-item-qty-selector/addon-item-qty-selector.ts +101 -0
- package/src/WebComponent/FeeCalculator/components/addons/common-addon-styles.ts +82 -0
- package/src/WebComponent/FeeCalculator/components/addons/rentable-item-qty-selector/rentable-item-qty-selector-styles.ts +9 -0
- package/src/WebComponent/FeeCalculator/components/addons/rentable-item-qty-selector/rentable-item-qty-selector.ts +124 -0
- package/src/WebComponent/FeeCalculator/components/fee-calculator-layout/fee-calculator-layout-styles.ts +142 -0
- package/src/WebComponent/FeeCalculator/components/fee-calculator-layout/fee-calculator-layout.ts +243 -0
- package/src/WebComponent/FeeCalculator/components/fee-card/fee-card-styles.ts +65 -0
- package/src/WebComponent/FeeCalculator/components/fee-card/fee-card.ts +91 -0
- package/src/WebComponent/FeeCalculator/components/fee-item/fee-item-styles.ts +44 -0
- package/src/WebComponent/FeeCalculator/components/fee-item/fee-item.ts +38 -0
- package/src/WebComponent/FeeCalculator/components/floor-plan-selector/floor-plan-selector-styles.ts +151 -0
- package/src/WebComponent/FeeCalculator/components/floor-plan-selector/floor-plan-selector.ts +248 -0
- package/src/WebComponent/FeeCalculator/components/floorplan-image-card/floorplan-image-card-styles.ts +82 -0
- package/src/WebComponent/FeeCalculator/components/floorplan-image-card/floorplan-image-card.ts +76 -0
- package/src/WebComponent/FeeCalculator/components/incentive-banner/incentive-banner-styles.ts +40 -0
- package/src/WebComponent/FeeCalculator/components/incentive-banner/incentive-banner.ts +43 -0
- package/src/WebComponent/FeeCalculator/components/incentive-banner/index.ts +1 -0
- package/src/WebComponent/FeeCalculator/components/index.ts +5 -0
- package/src/WebComponent/FeeCalculator/components/promo-card/promo-card-styles.ts +39 -0
- package/src/WebComponent/FeeCalculator/components/promo-card/promo-card.ts +39 -0
- package/src/WebComponent/FeeCalculator/constants.ts +5 -0
- package/src/WebComponent/FeeCalculator/fee-calculator-styles.ts +310 -0
- package/src/WebComponent/FeeCalculator/fee-calculator.ts +341 -0
- package/src/WebComponent/FeeCalculator/index.ts +4 -0
- package/src/WebComponent/FeeCalculator/model/building-fee-view.ts +84 -0
- package/src/WebComponent/FeeCalculator/model/building-fee.ts +126 -0
- package/src/WebComponent/FeeCalculator/model/desired-addon.ts +6 -0
- package/src/WebComponent/FeeCalculator/model/desired-rentable-item.ts +4 -0
- package/src/WebComponent/FeeCalculator/model/index.ts +13 -0
- package/src/WebComponent/FeeCalculator/model/item-combination.ts +16 -0
- package/src/WebComponent/FeeCalculator/model/item-quantity.ts +4 -0
- package/src/WebComponent/FeeCalculator/model/pricing-matrix.ts +45 -0
- package/src/WebComponent/FeeCalculator/model/pricing-rule.ts +9 -0
- package/src/WebComponent/FeeCalculator/model/rent-frequency.ts +1 -0
- package/src/WebComponent/FeeCalculator/model/rentable-item-summary.ts +10 -0
- package/src/WebComponent/FeeCalculator/model/rentable-item.ts +10 -0
- package/src/WebComponent/FeeCalculator/model/transaction-category.ts +23 -0
- package/src/WebComponent/FeeCalculator/model/unit-fee-bundle.ts +54 -0
- package/src/WebComponent/LeadSourceClient.ts +332 -0
- package/src/WebComponent/MEChat.css +5 -0
- package/src/WebComponent/OfficeHours.ts +73 -0
- package/src/WebComponent/Scheduler/date-picker.ts +405 -0
- package/src/WebComponent/Scheduler/time-picker.ts +195 -0
- package/src/WebComponent/Scheduler/tour-scheduler.ts +1430 -0
- package/src/WebComponent/Scheduler/tour-type-option.ts +112 -0
- package/src/WebComponent/Scheduler/tourSchedulerStyles.ts +418 -0
- package/src/WebComponent/actions/InputStyles.ts +57 -0
- package/src/WebComponent/actions/action-confirm-button.ts +125 -0
- package/src/WebComponent/actions/call-us-window.ts +467 -0
- package/src/WebComponent/actions/collapse-expand-button.ts +65 -0
- package/src/WebComponent/actions/details-window.ts +150 -0
- package/src/WebComponent/actions/email-us-window.ts +556 -0
- package/src/WebComponent/actions/formatPhoneNumber.ts +72 -0
- package/src/WebComponent/actions/minimize-expand-button.ts +93 -0
- package/src/WebComponent/chat-additional-actions.ts +135 -0
- package/src/WebComponent/health-chat.ts +270 -0
- package/src/WebComponent/healthchat-styles.ts +119 -0
- package/src/WebComponent/icons/ApplyOutlineIcon.ts +22 -0
- package/src/WebComponent/icons/BookTourOutlineIcon.ts +13 -0
- package/src/WebComponent/icons/CalculatorOutlineIcon.ts +22 -0
- package/src/WebComponent/icons/ChatOutlineIcon.ts +10 -0
- package/src/WebComponent/icons/ChevronLeftIcon.ts +7 -0
- package/src/WebComponent/icons/ChevronRightIcon.ts +7 -0
- package/src/WebComponent/icons/ContactResidentIcon.ts +9 -0
- package/src/WebComponent/icons/DollarOutlineIcon.ts +26 -0
- package/src/WebComponent/icons/EmailOutlineIcon.ts +7 -0
- package/src/WebComponent/icons/HeyThereEmojiIcon.ts +12 -0
- package/src/WebComponent/icons/PhoneOutlineIcon.ts +7 -0
- package/src/WebComponent/icons/SendMessageIcon.ts +17 -0
- package/src/WebComponent/icons/TourSelfGuidedIcon.ts +17 -0
- package/src/WebComponent/icons/TourVirtuallyIcon.ts +17 -0
- package/src/WebComponent/icons/TourWithAgentIcon.ts +17 -0
- package/src/WebComponent/icons/XOutlineIcon.ts +8 -0
- package/src/WebComponent/index.ts +2 -0
- package/src/WebComponent/launcher/Launcher.ts +1284 -0
- package/src/WebComponent/launcher/launcherStyles.ts +500 -0
- package/src/WebComponent/launcher/mobile-launcher.ts +162 -0
- package/src/WebComponent/launcher/typeEmojiStyles.ts +161 -0
- package/src/WebComponent/launcher/typeMiniStyles.ts +60 -0
- package/src/WebComponent/launcher/typeMobileStyles.ts +50 -0
- package/src/WebComponent/leasing-chat-styles.ts +114 -0
- package/src/WebComponent/loaders/index.ts +7 -0
- package/src/WebComponent/loaders/mega-loader.ts +36 -0
- package/src/WebComponent/loaders/skeleton-card.ts +31 -0
- package/src/WebComponent/loaders/skeleton-loader-styles.ts +112 -0
- package/src/WebComponent/loaders/skeleton-loader.ts +34 -0
- package/src/WebComponent/me-chat.ts +1264 -0
- package/src/WebComponent/me-select.ts +322 -0
- package/src/WebComponent/mini-loader.ts +28 -0
- package/src/WebComponent/pubnub-chat-styles.ts +204 -0
- package/src/WebComponent/pubnub-chat.ts +771 -0
- package/src/WebComponent/pubnub-media.ts +208 -0
- package/src/WebComponent/pubnub-message-styles.ts +54 -0
- package/src/WebComponent/pubnub-message.ts +431 -0
- package/src/WebComponent/simple-launcher/simple-launcher-styles.ts +34 -0
- package/src/WebComponent/simple-launcher/simple-launcher.ts +100 -0
- package/src/WebComponent/utilities-chat.ts +270 -0
- package/src/WebComponent/utilities-styles.ts +110 -0
- package/src/WebComponent/utils.ts +82 -0
- package/src/analytics.ts +217 -0
- package/src/assetUrls.ts +6 -0
- package/src/disclaimers.ts +301 -0
- package/src/fetchBuildingABTestType.ts +21 -0
- package/src/fetchBuildingInfo.ts +88 -0
- package/src/fetchBuildingWebchatView.ts +176 -0
- package/src/fetchFeatureFlag.ts +250 -0
- package/src/fetchLeadSources.ts +98 -0
- package/src/fetchPhoneNumberFromSource.ts +31 -0
- package/src/fetchWebchatPreferences.ts +54 -0
- package/src/getAvailabilities.ts +189 -0
- package/src/getBuildingPhoneNumber.ts +26 -0
- package/src/getShouldAllowScheduling.ts +16 -0
- package/src/getShouldShowWebchat.ts +114 -0
- package/src/getTimezoneString.ts +40 -0
- package/src/globals.ts +3 -0
- package/src/gtm.ts +17 -0
- package/src/handleChatId.ts +101 -0
- package/src/insertDNIIntoWebsite.ts +146 -0
- package/src/insertLeadSourceIntoSchedulerLinks.ts +71 -0
- package/src/main/MEChat.test.ts +110 -0
- package/src/main/MEChat.ts +404 -0
- package/src/main/utils.ts +70 -0
- package/src/postLeadSources.ts +44 -0
- package/src/rentgrata.ts +74 -0
- package/src/replaceSelectButtonsWithNewLink.ts +91 -0
- package/src/services/fees/calculateQuote.ts +74 -0
- package/src/services/fees/fetchBuildingFees.ts +50 -0
- package/src/services/fees/fetchBuildingFeesV2.ts +56 -0
- package/src/services/fees/fetchBuildingFloorplans.ts +74 -0
- package/src/services/fees/fetchBuildingUnits.ts +86 -0
- package/src/services/fees/utils.ts +4 -0
- package/src/svgIcons.ts +14 -0
- package/src/themes.ts +65 -0
- package/src/types/incentive-v2.ts +24 -0
- package/src/types/rest-sdk.types.ts +13 -0
- package/src/types/webchat-no-show-reason.ts +6 -0
- package/src/utils/getWidgetOverrides.ts +91 -0
- package/src/utils/queryParamBuilder.ts +28 -0
- package/src/utils.ts +121 -0
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import formatISO from "date-fns/formatISO";
|
|
2
|
+
import startOfToday from "date-fns/startOfToday";
|
|
3
|
+
import endOfDay from "date-fns/endOfDay";
|
|
4
|
+
import addDays from "date-fns/addDays";
|
|
5
|
+
import format from "date-fns/format";
|
|
6
|
+
import axios from "axios";
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
TourAvailabilityResponse,
|
|
10
|
+
TourAvailabilityResponseRankOrderedSupportedTourTypesEnum,
|
|
11
|
+
} from "./types/rest-sdk.types";
|
|
12
|
+
import groupBy from "lodash/groupBy";
|
|
13
|
+
import { TourType } from "./WebComponent/Scheduler/tour-scheduler";
|
|
14
|
+
import isPast from "date-fns/isPast";
|
|
15
|
+
import parseISO from "date-fns/parseISO";
|
|
16
|
+
import isValid from "date-fns/isValid";
|
|
17
|
+
|
|
18
|
+
const availabilitiesCache: {
|
|
19
|
+
buildingId?: number | null;
|
|
20
|
+
availabilities: { [buildingId: number]: TourAvailabilityResponse };
|
|
21
|
+
} = { buildingId: null, availabilities: {} };
|
|
22
|
+
|
|
23
|
+
export const resetAvailabilitiesCache = (): void => {
|
|
24
|
+
availabilitiesCache.buildingId = null;
|
|
25
|
+
availabilitiesCache.availabilities = {};
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Returns the raw availabilities.
|
|
30
|
+
*
|
|
31
|
+
* If no `buildingId` is provided, it will use a cached buildingId from the previous call.
|
|
32
|
+
* If there is none cached, it will throw an error.
|
|
33
|
+
*/
|
|
34
|
+
export const getRawAvailabilities = async (
|
|
35
|
+
buildingId?: number
|
|
36
|
+
): Promise<TourAvailabilityResponse> => {
|
|
37
|
+
if (buildingId) {
|
|
38
|
+
availabilitiesCache.buildingId = buildingId;
|
|
39
|
+
}
|
|
40
|
+
const buildingIdToUse = availabilitiesCache.buildingId;
|
|
41
|
+
if (!buildingIdToUse) {
|
|
42
|
+
throw new Error(
|
|
43
|
+
"No buildingId was provided to getRawAvailabilities and there is no buildingId cached."
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
const availabilities = availabilitiesCache.availabilities;
|
|
47
|
+
if (availabilities[buildingIdToUse]) {
|
|
48
|
+
return availabilities[buildingIdToUse];
|
|
49
|
+
}
|
|
50
|
+
const startTime = startOfToday();
|
|
51
|
+
const endTime = formatISO(endOfDay(addDays(startTime, 30)));
|
|
52
|
+
|
|
53
|
+
// We MUST encode the URI components because a positive timezone offset counts as a space in urls!
|
|
54
|
+
const timeParams = `startTime=${encodeURIComponent(
|
|
55
|
+
formatISO(startTime)
|
|
56
|
+
)}&endTime=${encodeURIComponent(endTime)}`;
|
|
57
|
+
const url = `https://app.meetelise.com/api/pub/v1/buildings/${buildingIdToUse}/tour/availabilities?${timeParams}`;
|
|
58
|
+
|
|
59
|
+
const result = await axios.get<TourAvailabilityResponse>(url);
|
|
60
|
+
availabilitiesCache.availabilities[buildingIdToUse] = result.data;
|
|
61
|
+
// The endpoint INCORRECTLY states that these are returned as dates. They are, in fact, strings.
|
|
62
|
+
return result.data;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export const getTimezoneForBuilding = async (
|
|
66
|
+
buildingId: number
|
|
67
|
+
): Promise<string> => {
|
|
68
|
+
const availabilities = await getRawAvailabilities(buildingId);
|
|
69
|
+
return (
|
|
70
|
+
(availabilities.calendarTimeZone as string | undefined) ??
|
|
71
|
+
Intl.DateTimeFormat().resolvedOptions().timeZone
|
|
72
|
+
); // the type for calendrTimeZone is outdated. it's just a string, not this weird object thing
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
export const getAvailabilitiesForTourType = async (
|
|
76
|
+
tourType: TourAvailabilityResponseRankOrderedSupportedTourTypesEnum,
|
|
77
|
+
buildingId?: number
|
|
78
|
+
): Promise<{
|
|
79
|
+
/**
|
|
80
|
+
*
|
|
81
|
+
* @type {number}
|
|
82
|
+
* @memberof TourTypeAvailability
|
|
83
|
+
*/
|
|
84
|
+
tourDurationInMinutes?: number;
|
|
85
|
+
/**
|
|
86
|
+
*
|
|
87
|
+
* @type {Array<string>}
|
|
88
|
+
* @memberof TourTypeAvailability
|
|
89
|
+
*/
|
|
90
|
+
availableTourStartTimes?: Array<string>;
|
|
91
|
+
} | null> => {
|
|
92
|
+
// The endpoint INCORRECTLY states that these are returned as dates. They are, in fact, strings.
|
|
93
|
+
const availabilities = await getRawAvailabilities(buildingId);
|
|
94
|
+
const availableTimes = availabilities.availability?.[tourType]
|
|
95
|
+
? (availabilities.availability?.[tourType]
|
|
96
|
+
.availableTourStartTimes as unknown as string[])
|
|
97
|
+
: [];
|
|
98
|
+
return availabilities.availability
|
|
99
|
+
? {
|
|
100
|
+
...availabilities.availability[tourType],
|
|
101
|
+
availableTourStartTimes: availableTimes,
|
|
102
|
+
}
|
|
103
|
+
: null;
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
export interface DateWithTimeZoneOffset {
|
|
107
|
+
datetime: string;
|
|
108
|
+
offset: string;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Returns an object that reveals whether each tour type supported by
|
|
113
|
+
* `tour-scheduler` has availabilities (time slots available for scheduling) in
|
|
114
|
+
* the time window of interest.
|
|
115
|
+
*
|
|
116
|
+
* Note that the existence of current availabilities is distinct from the
|
|
117
|
+
* question of whether the community supports the tour type at all. The first
|
|
118
|
+
* implies the second but not vice versa.
|
|
119
|
+
*/
|
|
120
|
+
export const getExistenceOfAvailabilitiesByTourType = async (): Promise<{
|
|
121
|
+
[TourType.Guided]: boolean;
|
|
122
|
+
[TourType.Self]: boolean;
|
|
123
|
+
[TourType.Virtual]: boolean;
|
|
124
|
+
}> => {
|
|
125
|
+
return {
|
|
126
|
+
[TourType.Guided]: !!(
|
|
127
|
+
await getAvailabilitiesForTourType(
|
|
128
|
+
TourAvailabilityResponseRankOrderedSupportedTourTypesEnum.WithAgent
|
|
129
|
+
)
|
|
130
|
+
)?.availableTourStartTimes?.length,
|
|
131
|
+
[TourType.Self]: !!(
|
|
132
|
+
await getAvailabilitiesForTourType(
|
|
133
|
+
TourAvailabilityResponseRankOrderedSupportedTourTypesEnum.SelfGuided
|
|
134
|
+
)
|
|
135
|
+
)?.availableTourStartTimes?.length,
|
|
136
|
+
[TourType.Virtual]: !!(
|
|
137
|
+
await getAvailabilitiesForTourType(
|
|
138
|
+
TourAvailabilityResponseRankOrderedSupportedTourTypesEnum.VirtualShowing
|
|
139
|
+
)
|
|
140
|
+
)?.availableTourStartTimes?.length,
|
|
141
|
+
};
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
export const getAvailabilitiesGroupedByDay = async (
|
|
145
|
+
tourType: TourAvailabilityResponseRankOrderedSupportedTourTypesEnum,
|
|
146
|
+
buildingId?: number
|
|
147
|
+
): Promise<{ [day: string]: DateWithTimeZoneOffset[] }> => {
|
|
148
|
+
const availabilitiesForTourTypeRaw = await getAvailabilitiesForTourType(
|
|
149
|
+
tourType,
|
|
150
|
+
buildingId
|
|
151
|
+
);
|
|
152
|
+
|
|
153
|
+
if (!availabilitiesForTourTypeRaw) {
|
|
154
|
+
return {};
|
|
155
|
+
}
|
|
156
|
+
// Specify offset for each datetime in case availabilities span a daylight savings boundary, when offset will change.
|
|
157
|
+
// Cast availableTourStartTimes to string[], since the Date[] typing of the API is incorrect
|
|
158
|
+
const availabilitiesForTourType: {
|
|
159
|
+
availableTourStartTimes: DateWithTimeZoneOffset[] | undefined;
|
|
160
|
+
} = {
|
|
161
|
+
availableTourStartTimes:
|
|
162
|
+
(availabilitiesForTourTypeRaw.availableTourStartTimes
|
|
163
|
+
? (
|
|
164
|
+
availabilitiesForTourTypeRaw.availableTourStartTimes as unknown as string[]
|
|
165
|
+
).filter((dt) => isValid(parseISO(dt)) && !isPast(parseISO(dt)))
|
|
166
|
+
: []
|
|
167
|
+
)?.map((dateString) => dateStringToDateWithTimeZoneOffset(dateString)),
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
return groupBy(
|
|
171
|
+
availabilitiesForTourType.availableTourStartTimes ?? [],
|
|
172
|
+
(startTime) => format(new Date(startTime.datetime), "yyyy-MM-dd")
|
|
173
|
+
);
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Takes an ISO 8601 date string with time zone offset and returns
|
|
178
|
+
* an object of our custom type DateWithTimeZoneOffset.
|
|
179
|
+
*
|
|
180
|
+
* @example
|
|
181
|
+
* // returns { datetime: '2022-06-27T09:00:00', offset: '-07:00' }
|
|
182
|
+
* dateStringToDateWithTimeZoneOffset('2022-06-27T09:00:00-07:00')
|
|
183
|
+
* */
|
|
184
|
+
const dateStringToDateWithTimeZoneOffset = (
|
|
185
|
+
dateString: string
|
|
186
|
+
): DateWithTimeZoneOffset => ({
|
|
187
|
+
datetime: dateString.slice(0, 19),
|
|
188
|
+
offset: dateString.slice(19),
|
|
189
|
+
});
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import axios from "axios";
|
|
2
|
+
import { LogType, sendLoggingEvent } from "./analytics";
|
|
3
|
+
|
|
4
|
+
export const getBuildingPhoneNumber = async (
|
|
5
|
+
buildingSlug: string
|
|
6
|
+
): Promise<string | null> => {
|
|
7
|
+
try {
|
|
8
|
+
const host = "https://app.meetelise.com";
|
|
9
|
+
const webchatPreferencesResponse = await axios.get(
|
|
10
|
+
`${host}/platformApi/webchat/${buildingSlug}/phone-number`
|
|
11
|
+
);
|
|
12
|
+
if (webchatPreferencesResponse.data) {
|
|
13
|
+
return webchatPreferencesResponse.data;
|
|
14
|
+
}
|
|
15
|
+
} catch (error) {
|
|
16
|
+
sendLoggingEvent({
|
|
17
|
+
logType: LogType.error,
|
|
18
|
+
buildingSlug,
|
|
19
|
+
logTitle: "[ERROR_GETTING_PHONE_NUMBERS]",
|
|
20
|
+
logData: { error },
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
return null;
|
|
26
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import axios from "axios";
|
|
2
|
+
|
|
3
|
+
export const getShouldAllowScheduling = async (
|
|
4
|
+
buildingId: number,
|
|
5
|
+
isDynamicSchedulingEnabled = false
|
|
6
|
+
): Promise<boolean> => {
|
|
7
|
+
const host = "https://app.meetelise.com";
|
|
8
|
+
const url = `${host}/eliseCrmApi/building/${buildingId}/scheduling_status?observe_dynamic_scheduling=${isDynamicSchedulingEnabled}`;
|
|
9
|
+
|
|
10
|
+
try {
|
|
11
|
+
const response = await axios.get(url);
|
|
12
|
+
return response.data.is_enabled;
|
|
13
|
+
} catch (e) {
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
};
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { logSignal } from "./analytics";
|
|
2
|
+
import { BuildingWebchatView } from "./fetchBuildingWebchatView";
|
|
3
|
+
import { fetchFeatureFlagMaintenanceMode } from "./fetchFeatureFlag";
|
|
4
|
+
import { WebchatNoShowReason } from "./types/webchat-no-show-reason";
|
|
5
|
+
|
|
6
|
+
const getShouldShowWebchat = async (
|
|
7
|
+
buildingWebchatView: BuildingWebchatView | null,
|
|
8
|
+
buildingSlug: string,
|
|
9
|
+
orgSlug: string
|
|
10
|
+
): Promise<boolean> => {
|
|
11
|
+
const sampleRateForWebchat = 0.01;
|
|
12
|
+
|
|
13
|
+
if (!buildingWebchatView) {
|
|
14
|
+
// eslint-disable-next-line no-console
|
|
15
|
+
console.warn("MeetElise Chat will NOT appear. Building does NOT exist.");
|
|
16
|
+
log(
|
|
17
|
+
orgSlug,
|
|
18
|
+
buildingSlug,
|
|
19
|
+
true,
|
|
20
|
+
false,
|
|
21
|
+
"building_does_not_exist",
|
|
22
|
+
sampleRateForWebchat
|
|
23
|
+
);
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
if (!buildingWebchatView.launchedDateTime) {
|
|
27
|
+
// eslint-disable-next-line no-console
|
|
28
|
+
console.warn(
|
|
29
|
+
"MeetElise Chat will NOT appear. Building is NOT launched (based on launched date time)."
|
|
30
|
+
);
|
|
31
|
+
log(
|
|
32
|
+
orgSlug,
|
|
33
|
+
buildingSlug,
|
|
34
|
+
true,
|
|
35
|
+
false,
|
|
36
|
+
"building_not_launched",
|
|
37
|
+
sampleRateForWebchat
|
|
38
|
+
);
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (!buildingWebchatView.active) {
|
|
43
|
+
// eslint-disable-next-line no-console
|
|
44
|
+
console.warn("MeetElise Chat will NOT appear. Building is NOT active.");
|
|
45
|
+
log(
|
|
46
|
+
orgSlug,
|
|
47
|
+
buildingSlug,
|
|
48
|
+
true,
|
|
49
|
+
false,
|
|
50
|
+
"building_not_active",
|
|
51
|
+
sampleRateForWebchat
|
|
52
|
+
);
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
if (!buildingWebchatView.webchatScopeConfigured) {
|
|
56
|
+
// eslint-disable-next-line no-console
|
|
57
|
+
console.warn(
|
|
58
|
+
"MeetElise Chat will NOT appear. Building is NOT webchat scope configured."
|
|
59
|
+
);
|
|
60
|
+
log(
|
|
61
|
+
orgSlug,
|
|
62
|
+
buildingSlug,
|
|
63
|
+
true,
|
|
64
|
+
false,
|
|
65
|
+
"building_not_webchat_scope_configured",
|
|
66
|
+
sampleRateForWebchat
|
|
67
|
+
);
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const leasingMaintenanceMode = await fetchFeatureFlagMaintenanceMode(
|
|
72
|
+
buildingSlug
|
|
73
|
+
);
|
|
74
|
+
// https://app.launchdarkly.com/projects/default/flags/webchat-leasing-in-maintenance-mode/targeting?env=production&selected-env=production
|
|
75
|
+
if (leasingMaintenanceMode) {
|
|
76
|
+
// eslint-disable-next-line no-console
|
|
77
|
+
console.warn(
|
|
78
|
+
"MeetElise Chat will NOT appear. Chat is in maintenance mode."
|
|
79
|
+
);
|
|
80
|
+
log(
|
|
81
|
+
orgSlug,
|
|
82
|
+
buildingSlug,
|
|
83
|
+
true,
|
|
84
|
+
false,
|
|
85
|
+
"building_in_maintenance_mode",
|
|
86
|
+
sampleRateForWebchat
|
|
87
|
+
);
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
return true;
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
const log = (
|
|
94
|
+
orgSlug: string,
|
|
95
|
+
buildingSlug: string,
|
|
96
|
+
isPixelOnSite = true,
|
|
97
|
+
isAnyWebchatShowing = false,
|
|
98
|
+
webchatNoShowReason: WebchatNoShowReason,
|
|
99
|
+
sampleRate = 0.01
|
|
100
|
+
) =>
|
|
101
|
+
logSignal({
|
|
102
|
+
params: {
|
|
103
|
+
org_slug: orgSlug,
|
|
104
|
+
building_slug: buildingSlug,
|
|
105
|
+
is_pixel_on_site: isPixelOnSite,
|
|
106
|
+
is_any_webchat_showing: isAnyWebchatShowing,
|
|
107
|
+
extra_data: {
|
|
108
|
+
webchat_no_show_reason: webchatNoShowReason,
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
sampleRate,
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
export default getShouldShowWebchat;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
const isDaylightSavingTime = (date: Date): boolean => {
|
|
2
|
+
const jan = new Date(date.getFullYear(), 0, 1);
|
|
3
|
+
const jul = new Date(date.getFullYear(), 6, 1);
|
|
4
|
+
const stdTimezoneOffset = Math.max(
|
|
5
|
+
jan.getTimezoneOffset(),
|
|
6
|
+
jul.getTimezoneOffset()
|
|
7
|
+
);
|
|
8
|
+
|
|
9
|
+
return date.getTimezoneOffset() < stdTimezoneOffset;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export const getTimezoneAbbreviation = (timeZone?: string): string => {
|
|
13
|
+
const date = new Date();
|
|
14
|
+
const timeZoneToUse =
|
|
15
|
+
timeZone ?? Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
16
|
+
const isDST = isDaylightSavingTime(date);
|
|
17
|
+
|
|
18
|
+
switch (timeZoneToUse) {
|
|
19
|
+
case "America/New_York":
|
|
20
|
+
return isDST ? "EDT" : "EST";
|
|
21
|
+
case "America/Chicago":
|
|
22
|
+
return isDST ? "CDT" : "CST";
|
|
23
|
+
case "America/Denver":
|
|
24
|
+
return isDST ? "MDT" : "MST";
|
|
25
|
+
case "America/Los_Angeles":
|
|
26
|
+
return isDST ? "PDT" : "PST";
|
|
27
|
+
case "America/Anchorage":
|
|
28
|
+
return isDST ? "AKDT" : "AKST";
|
|
29
|
+
case "America/Honolulu":
|
|
30
|
+
return "HST";
|
|
31
|
+
case "America/Phoenix":
|
|
32
|
+
return "MST";
|
|
33
|
+
case "America/Indiana/Indianapolis":
|
|
34
|
+
return isDST ? "EDT" : "EST";
|
|
35
|
+
case "America/Indiana/Knox":
|
|
36
|
+
return isDST ? "CDT" : "CST";
|
|
37
|
+
default:
|
|
38
|
+
return "Unknown";
|
|
39
|
+
}
|
|
40
|
+
};
|
package/src/globals.ts
ADDED
package/src/gtm.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
declare global {
|
|
2
|
+
interface Window {
|
|
3
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
4
|
+
dataLayer: any[];
|
|
5
|
+
}
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export const pushGtmEvent = (
|
|
9
|
+
eventName: string,
|
|
10
|
+
event: Record<string, unknown> = {}
|
|
11
|
+
): void => {
|
|
12
|
+
window.dataLayer = window.dataLayer || [];
|
|
13
|
+
window.dataLayer.push({
|
|
14
|
+
event: eventName,
|
|
15
|
+
...event,
|
|
16
|
+
});
|
|
17
|
+
};
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import parseISO from "date-fns/parseISO";
|
|
2
|
+
import { v4 as uuid } from "uuid";
|
|
3
|
+
import formatISO from "date-fns/formatISO";
|
|
4
|
+
import { isTimestampExpired } from "./utils";
|
|
5
|
+
import isBefore from "date-fns/isBefore";
|
|
6
|
+
|
|
7
|
+
export interface ChatStorageKey {
|
|
8
|
+
leadId: string | null;
|
|
9
|
+
timestamp: Date | null;
|
|
10
|
+
buildingSlug: string | null;
|
|
11
|
+
initiatedChat: boolean;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const ttlHours = 24;
|
|
15
|
+
|
|
16
|
+
export const clearChatStorageKey = (buildingSlug: string): void =>
|
|
17
|
+
localStorage.removeItem("com.elise.webchat.slug=" + buildingSlug);
|
|
18
|
+
|
|
19
|
+
export const createChatStorageKey = (
|
|
20
|
+
buildingSlug: string,
|
|
21
|
+
withChatinitialized: boolean,
|
|
22
|
+
leadId?: string
|
|
23
|
+
): ChatStorageKey => {
|
|
24
|
+
const storageTimestamp = formatISO(new Date());
|
|
25
|
+
|
|
26
|
+
// must preface with lead for BE to extract lead id
|
|
27
|
+
const leadUserId = leadId ? leadId : `lead_${uuid()}`;
|
|
28
|
+
localStorage.setItem(
|
|
29
|
+
"com.elise.webchat.slug=" + buildingSlug,
|
|
30
|
+
JSON.stringify({
|
|
31
|
+
buildingSlug: buildingSlug,
|
|
32
|
+
leadId: leadUserId,
|
|
33
|
+
timestamp: storageTimestamp,
|
|
34
|
+
initiatedChat: withChatinitialized,
|
|
35
|
+
})
|
|
36
|
+
);
|
|
37
|
+
return {
|
|
38
|
+
leadId: leadUserId,
|
|
39
|
+
timestamp: parseISO(storageTimestamp),
|
|
40
|
+
buildingSlug: buildingSlug,
|
|
41
|
+
initiatedChat: withChatinitialized,
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export const getChatStorageKey = (buildingSlug: string): ChatStorageKey => {
|
|
46
|
+
const eliseaiLocalStorageValue = localStorage.getItem(
|
|
47
|
+
"com.elise.webchat.slug=" + buildingSlug
|
|
48
|
+
);
|
|
49
|
+
if (eliseaiLocalStorageValue) {
|
|
50
|
+
try {
|
|
51
|
+
const eliseaiLocalStorageValueParsed = JSON.parse(
|
|
52
|
+
eliseaiLocalStorageValue
|
|
53
|
+
);
|
|
54
|
+
const newStorageKey = {
|
|
55
|
+
leadId: eliseaiLocalStorageValueParsed.leadId,
|
|
56
|
+
timestamp: new Date(eliseaiLocalStorageValueParsed.timestamp),
|
|
57
|
+
buildingSlug: eliseaiLocalStorageValueParsed.buildingSlug,
|
|
58
|
+
initiatedChat: eliseaiLocalStorageValueParsed.initiatedChat,
|
|
59
|
+
};
|
|
60
|
+
if (isChatKeyValid(buildingSlug, newStorageKey)) {
|
|
61
|
+
return newStorageKey;
|
|
62
|
+
}
|
|
63
|
+
} catch (_) {
|
|
64
|
+
// eslint-disable-next-line no-console
|
|
65
|
+
console.warn("Error getting chat storage key");
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return {
|
|
70
|
+
leadId: null,
|
|
71
|
+
timestamp: null,
|
|
72
|
+
buildingSlug: null,
|
|
73
|
+
initiatedChat: false,
|
|
74
|
+
};
|
|
75
|
+
};
|
|
76
|
+
export const isChatKeyValid = (
|
|
77
|
+
buildingSlug: string,
|
|
78
|
+
storageValue: ChatStorageKey
|
|
79
|
+
): boolean => {
|
|
80
|
+
// If we want to do force invalidation
|
|
81
|
+
try {
|
|
82
|
+
if (storageValue.timestamp && storageValue.initiatedChat) {
|
|
83
|
+
const topBoundaryTimestamp = new Date("2024-06-06T21:30:00Z");
|
|
84
|
+
if (isBefore(storageValue.timestamp, topBoundaryTimestamp)) {
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
} catch (_) {
|
|
89
|
+
// eslint-disable-next-line no-console
|
|
90
|
+
console.warn("Error checking chat storage key validity");
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (
|
|
94
|
+
storageValue.buildingSlug !== buildingSlug ||
|
|
95
|
+
!storageValue.leadId ||
|
|
96
|
+
!storageValue.timestamp
|
|
97
|
+
) {
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
return !isTimestampExpired(storageValue.timestamp, ttlHours);
|
|
101
|
+
};
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* General script to find all phone numbers on a page and replace them with a
|
|
3
|
+
* DNI phone number.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { LogType, sendLoggingEvent } from "./analytics";
|
|
7
|
+
|
|
8
|
+
export const insertDNIIntoWebsite = (
|
|
9
|
+
cleanPhoneNumber: string, // format of 1234567890
|
|
10
|
+
orgSlug: string,
|
|
11
|
+
buildingSlug?: string
|
|
12
|
+
): number => {
|
|
13
|
+
const newHrefNumber = `tel:${cleanPhoneNumber}`;
|
|
14
|
+
const newHrefSmsNumber = `sms:${cleanPhoneNumber}`;
|
|
15
|
+
const newWhatsAppNumber = `whatsapp://send?phone=${cleanPhoneNumber}}`;
|
|
16
|
+
const newFacetimeNumber = `facetime:${cleanPhoneNumber}`;
|
|
17
|
+
const newFacetimeAudioNumber = `facetime-audio:${cleanPhoneNumber}`;
|
|
18
|
+
|
|
19
|
+
const phoneNumberPattern = /(?:\(\d{3}\)\s|\d{3}-)\d{3}-\d{4}/g;
|
|
20
|
+
const hrefNumberPattern = /(tel|sms):(?:\(\d{3}\)\s|\d{3}-)\d{3}-\d{4}/g;
|
|
21
|
+
|
|
22
|
+
const whatsappNumberPattern = /whatsapp:\/\/send\?phone=\d+/g;
|
|
23
|
+
const facetimeNumberPattern = /(facetime|facetime-audio):\d+/g;
|
|
24
|
+
|
|
25
|
+
const allHTMLItems = document.body.getElementsByTagName("*");
|
|
26
|
+
|
|
27
|
+
let foundPhoneNumber = false;
|
|
28
|
+
|
|
29
|
+
// from a phone format of 1234567890 to (123) 456-7890
|
|
30
|
+
const newPhoneNumber = cleanPhoneNumber.replace(
|
|
31
|
+
/(\d{3})(\d{3})(\d{4})/,
|
|
32
|
+
"($1) $2-$3"
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
let shouldLogTextInsertionError = false;
|
|
36
|
+
let shouldLogHrefInsertionError = false;
|
|
37
|
+
|
|
38
|
+
let totalReplacements = 0;
|
|
39
|
+
|
|
40
|
+
for (let i = 0; i < allHTMLItems.length; i++) {
|
|
41
|
+
if (allHTMLItems[i].nodeType !== Node.ELEMENT_NODE) {
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Handles the actual display phone number
|
|
46
|
+
if (
|
|
47
|
+
allHTMLItems[i].childNodes.length === 1 &&
|
|
48
|
+
allHTMLItems[i].childNodes[0].nodeType == Node.TEXT_NODE
|
|
49
|
+
) {
|
|
50
|
+
const oldInnerHTML = allHTMLItems[i].innerHTML;
|
|
51
|
+
const newInnerHTML = oldInnerHTML.replace(
|
|
52
|
+
phoneNumberPattern,
|
|
53
|
+
newPhoneNumber
|
|
54
|
+
);
|
|
55
|
+
if (oldInnerHTML !== newInnerHTML) {
|
|
56
|
+
totalReplacements++;
|
|
57
|
+
}
|
|
58
|
+
allHTMLItems[i].innerHTML = newInnerHTML;
|
|
59
|
+
|
|
60
|
+
foundPhoneNumber = true;
|
|
61
|
+
|
|
62
|
+
if (!shouldLogTextInsertionError) {
|
|
63
|
+
shouldLogTextInsertionError = true;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Handles the href phone number (so when you click the link, it will call the phone number)
|
|
68
|
+
if (allHTMLItems[i].hasAttribute("href")) {
|
|
69
|
+
const href = allHTMLItems[i].getAttribute("href");
|
|
70
|
+
if (!href) {
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
let newHrefValue = "";
|
|
75
|
+
let currentPattern = hrefNumberPattern;
|
|
76
|
+
|
|
77
|
+
if (href.startsWith("sms:")) {
|
|
78
|
+
newHrefValue = newHrefSmsNumber;
|
|
79
|
+
} else if (href.startsWith("whatsapp:")) {
|
|
80
|
+
newHrefValue = newWhatsAppNumber;
|
|
81
|
+
currentPattern = whatsappNumberPattern;
|
|
82
|
+
} else if (href.startsWith("facetime:")) {
|
|
83
|
+
newHrefValue = newFacetimeNumber;
|
|
84
|
+
currentPattern = facetimeNumberPattern;
|
|
85
|
+
} else if (href.startsWith("facetime-audio:")) {
|
|
86
|
+
newHrefValue = newFacetimeAudioNumber;
|
|
87
|
+
currentPattern = facetimeNumberPattern;
|
|
88
|
+
} else {
|
|
89
|
+
newHrefValue = newHrefNumber;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const newHref = href.replace(currentPattern, newHrefValue);
|
|
93
|
+
allHTMLItems[i].setAttribute("href", newHref);
|
|
94
|
+
|
|
95
|
+
if (!shouldLogHrefInsertionError) {
|
|
96
|
+
shouldLogHrefInsertionError = true;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// We could make these logs more specific but for now we'll just log the
|
|
102
|
+
// if there is even a single error to limit the error logs we throw
|
|
103
|
+
|
|
104
|
+
if (shouldLogTextInsertionError) {
|
|
105
|
+
sendLoggingEvent({
|
|
106
|
+
logTitle: "DNI_WEBSITE_INSERTION",
|
|
107
|
+
logData: {
|
|
108
|
+
type: "text-insertion",
|
|
109
|
+
newPhoneNumber,
|
|
110
|
+
website: window.location.href,
|
|
111
|
+
},
|
|
112
|
+
logType: LogType.info,
|
|
113
|
+
buildingSlug,
|
|
114
|
+
orgSlug,
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (shouldLogHrefInsertionError) {
|
|
119
|
+
sendLoggingEvent({
|
|
120
|
+
logTitle: "DNI_WEBSITE_INSERTION",
|
|
121
|
+
logData: {
|
|
122
|
+
type: "href-insertion",
|
|
123
|
+
newPhoneNumber,
|
|
124
|
+
website: window.location.href,
|
|
125
|
+
},
|
|
126
|
+
logType: LogType.info,
|
|
127
|
+
buildingSlug,
|
|
128
|
+
orgSlug,
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (!foundPhoneNumber) {
|
|
133
|
+
sendLoggingEvent({
|
|
134
|
+
logTitle: "DNI_WEBSITE_INSERTION",
|
|
135
|
+
logData: {
|
|
136
|
+
type: "no-phone-number-found",
|
|
137
|
+
website: window.location.href,
|
|
138
|
+
},
|
|
139
|
+
logType: LogType.warn,
|
|
140
|
+
buildingSlug,
|
|
141
|
+
orgSlug,
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return totalReplacements;
|
|
146
|
+
};
|