@meetelise/chat 1.43.42 → 1.45.0
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/WebComponent/Scheduler/tour-scheduler.d.ts +13 -0
- package/dist/src/WebComponent/launcher/Launcher.d.ts +2 -0
- package/dist/src/fetchBuildingUnitsSummary.d.ts +10 -0
- package/dist/src/types/rest-sdk.types.d.ts +4 -1
- package/package.json +1 -1
- package/public/dist/index.js +221 -204
- package/src/WebComponent/Scheduler/tour-scheduler.ts +131 -1
- package/src/WebComponent/launcher/Launcher.ts +5 -1
- package/src/WebComponent/me-chat.ts +2 -0
- package/src/fetchBuildingUnitsSummary.ts +37 -0
- package/src/types/rest-sdk.types.ts +5 -1
|
@@ -29,6 +29,7 @@ import { DatePicker } from "./date-picker";
|
|
|
29
29
|
import { MESelect } from "../me-select";
|
|
30
30
|
import { TimePicker } from "./time-picker";
|
|
31
31
|
import { LabeledOption } from "../../fetchBuildingInfo";
|
|
32
|
+
import { LayoutOption } from "../../fetchBuildingWebchatView";
|
|
32
33
|
import {
|
|
33
34
|
isMobile,
|
|
34
35
|
isValidEmail,
|
|
@@ -61,6 +62,9 @@ import { getTimezoneAbbreviation } from "../../getTimezoneString";
|
|
|
61
62
|
import startOfDay from "date-fns/startOfDay";
|
|
62
63
|
import isSameDay from "date-fns/isSameDay";
|
|
63
64
|
import { LeadSourceMultitouchClient } from "../LeadSourceMultitouchClient";
|
|
65
|
+
import fetchBuildingUnitsSummary, {
|
|
66
|
+
UnitSummary,
|
|
67
|
+
} from "../../fetchBuildingUnitsSummary";
|
|
64
68
|
|
|
65
69
|
@customElement("tour-scheduler")
|
|
66
70
|
export class TourScheduler extends LitElement {
|
|
@@ -79,6 +83,8 @@ export class TourScheduler extends LitElement {
|
|
|
79
83
|
|
|
80
84
|
@property({ attribute: false })
|
|
81
85
|
tourTypeOptions: LabeledOption[] = [];
|
|
86
|
+
@property({ attribute: false })
|
|
87
|
+
layoutOptions: LayoutOption[] = [];
|
|
82
88
|
@property({ attribute: true })
|
|
83
89
|
chatId = "";
|
|
84
90
|
@property({ type: Number })
|
|
@@ -191,6 +197,10 @@ export class TourScheduler extends LitElement {
|
|
|
191
197
|
phoneInput!: HTMLInputElement;
|
|
192
198
|
@query("me-select#leadSource")
|
|
193
199
|
selectedLeadSource!: MESelect;
|
|
200
|
+
@query("me-select#layout")
|
|
201
|
+
selectedLayoutEl?: MESelect;
|
|
202
|
+
@query("me-select#unit")
|
|
203
|
+
selectedUnitEl?: MESelect;
|
|
194
204
|
|
|
195
205
|
@state()
|
|
196
206
|
firstNameInputValue = "";
|
|
@@ -198,6 +208,14 @@ export class TourScheduler extends LitElement {
|
|
|
198
208
|
lastNameInputValue = "";
|
|
199
209
|
@state()
|
|
200
210
|
leadSourceInputValue = "";
|
|
211
|
+
@state()
|
|
212
|
+
selectedLayoutValue = "";
|
|
213
|
+
@state()
|
|
214
|
+
selectedUnitValue = "";
|
|
215
|
+
@state()
|
|
216
|
+
private units: UnitSummary[] = [];
|
|
217
|
+
@state()
|
|
218
|
+
private allowOccupiedUnitTours = false;
|
|
201
219
|
|
|
202
220
|
@state()
|
|
203
221
|
errorGettingAvailabilities = false;
|
|
@@ -403,8 +421,51 @@ export class TourScheduler extends LitElement {
|
|
|
403
421
|
return null;
|
|
404
422
|
};
|
|
405
423
|
|
|
424
|
+
_getUnitOptions = (): { label: string; value: string }[] => {
|
|
425
|
+
const visible = this.selectedLayoutValue
|
|
426
|
+
? this.units.filter(
|
|
427
|
+
(u) =>
|
|
428
|
+
layoutValueToCanonical(u.numberOfBedrooms * 10) ===
|
|
429
|
+
this.selectedLayoutValue
|
|
430
|
+
)
|
|
431
|
+
: this.units;
|
|
432
|
+
const unitOptions = visible.map((u) => ({
|
|
433
|
+
label: u.unitNumber,
|
|
434
|
+
value: u.unitNumber,
|
|
435
|
+
}));
|
|
436
|
+
return unitOptions;
|
|
437
|
+
};
|
|
438
|
+
|
|
439
|
+
_fetchUnits = async (): Promise<void> => {
|
|
440
|
+
if (!this.buildingSlug) return;
|
|
441
|
+
try {
|
|
442
|
+
this.units = await fetchBuildingUnitsSummary({
|
|
443
|
+
buildingSlug: this.buildingSlug,
|
|
444
|
+
});
|
|
445
|
+
} catch (e) {
|
|
446
|
+
this.units = [];
|
|
447
|
+
sendLoggingEvent({
|
|
448
|
+
logTitle: "ERROR_LOADING_UNITS_FOR_TOUR_SCHEDULER",
|
|
449
|
+
logData: { error: e },
|
|
450
|
+
logType: LogType.error,
|
|
451
|
+
buildingSlug: this.buildingSlug,
|
|
452
|
+
orgSlug: this.orgSlug,
|
|
453
|
+
});
|
|
454
|
+
}
|
|
455
|
+
};
|
|
456
|
+
|
|
406
457
|
firstUpdated = async (): Promise<void> => {
|
|
407
|
-
await
|
|
458
|
+
await Promise.all([
|
|
459
|
+
this._setAvailabilities().then(async () => {
|
|
460
|
+
try {
|
|
461
|
+
const rawAvailabilities = await getRawAvailabilities(this.buildingId);
|
|
462
|
+
this.allowOccupiedUnitTours = !!rawAvailabilities.allowOccupiedUnitTours;
|
|
463
|
+
} catch (e) {
|
|
464
|
+
this.allowOccupiedUnitTours = false;
|
|
465
|
+
}
|
|
466
|
+
}),
|
|
467
|
+
this._fetchUnits(),
|
|
468
|
+
]);
|
|
408
469
|
};
|
|
409
470
|
|
|
410
471
|
protected willUpdate = async (
|
|
@@ -643,6 +704,10 @@ export class TourScheduler extends LitElement {
|
|
|
643
704
|
this.lastNameInputValue = this.lastNameInput.value;
|
|
644
705
|
}
|
|
645
706
|
this.leadSourceInputValue = parsedLeadSource;
|
|
707
|
+
const selectedLayout =
|
|
708
|
+
this.selectedLayoutEl?.value || this.selectedLayoutValue || null;
|
|
709
|
+
const selectedUnit =
|
|
710
|
+
this.selectedUnitEl?.value || this.selectedUnitValue || null;
|
|
646
711
|
pushGtmEvent("scheduleTourSubmitted", {
|
|
647
712
|
email: this.email,
|
|
648
713
|
phone: `+1${this.phoneNumber.match(/\d/g)?.join("")}`,
|
|
@@ -652,6 +717,8 @@ export class TourScheduler extends LitElement {
|
|
|
652
717
|
tourTime: `${this.selectedTime.datetime}${this.selectedTime.offset}`,
|
|
653
718
|
originatingSource:
|
|
654
719
|
leadSources.find((i) => i !== "property-website") || null,
|
|
720
|
+
layout: selectedLayout,
|
|
721
|
+
unit: selectedUnit,
|
|
655
722
|
});
|
|
656
723
|
const data = {
|
|
657
724
|
referrer: document.referrer,
|
|
@@ -672,6 +739,8 @@ export class TourScheduler extends LitElement {
|
|
|
672
739
|
],
|
|
673
740
|
query_params: Object.fromEntries(queryParams.entries()),
|
|
674
741
|
conversation_tracking_id: this.leadSourceClient?.chatId,
|
|
742
|
+
layouts: selectedLayout ? [selectedLayout] : undefined,
|
|
743
|
+
unit_numbers: selectedUnit ? [selectedUnit] : undefined,
|
|
675
744
|
lead_sources_with_timestamps: (
|
|
676
745
|
this.leadSourceMultitouchClient?.getSafeLeadSourceTouchpointsWithDefault(
|
|
677
746
|
{
|
|
@@ -1225,6 +1294,61 @@ export class TourScheduler extends LitElement {
|
|
|
1225
1294
|
? html`<p class="error-message">Invalid phone number</p>`
|
|
1226
1295
|
: ""}
|
|
1227
1296
|
</div>
|
|
1297
|
+
${this.layoutOptions.length > 0
|
|
1298
|
+
? html` <me-select
|
|
1299
|
+
id="layout"
|
|
1300
|
+
placeholder="Bedroom preference (optional)"
|
|
1301
|
+
.options="${this.layoutOptions.map((o) => ({
|
|
1302
|
+
label: o.label,
|
|
1303
|
+
value: layoutValueToCanonical(o.value),
|
|
1304
|
+
}))}"
|
|
1305
|
+
@change=${() => {
|
|
1306
|
+
const v = this.selectedLayoutEl?.value || "";
|
|
1307
|
+
this.selectedLayoutValue = v;
|
|
1308
|
+
// Clear unit selection if it no longer matches the new layout.
|
|
1309
|
+
if (v && this.selectedUnitValue) {
|
|
1310
|
+
const unit = this.units.find(
|
|
1311
|
+
(u) => u.unitNumber === this.selectedUnitValue
|
|
1312
|
+
);
|
|
1313
|
+
if (
|
|
1314
|
+
unit &&
|
|
1315
|
+
layoutValueToCanonical(unit.numberOfBedrooms * 10) !== v
|
|
1316
|
+
) {
|
|
1317
|
+
this.selectedUnitValue = "";
|
|
1318
|
+
if (this.selectedUnitEl) {
|
|
1319
|
+
this.selectedUnitEl.value = undefined;
|
|
1320
|
+
}
|
|
1321
|
+
}
|
|
1322
|
+
}
|
|
1323
|
+
if (v) {
|
|
1324
|
+
pushGtmEvent("tourLayoutSelected", {
|
|
1325
|
+
layout: v,
|
|
1326
|
+
buildingId: this.buildingId,
|
|
1327
|
+
});
|
|
1328
|
+
}
|
|
1329
|
+
}}
|
|
1330
|
+
>
|
|
1331
|
+
</me-select>`
|
|
1332
|
+
: ""}
|
|
1333
|
+
${this.allowOccupiedUnitTours && this._getUnitOptions().length > 0
|
|
1334
|
+
? html` <me-select
|
|
1335
|
+
id="unit"
|
|
1336
|
+
placeholder="Unit preference (optional)"
|
|
1337
|
+
.value=${this.selectedUnitValue}
|
|
1338
|
+
.options="${this._getUnitOptions()}"
|
|
1339
|
+
@change=${() => {
|
|
1340
|
+
const v = this.selectedUnitEl?.value || "";
|
|
1341
|
+
this.selectedUnitValue = v;
|
|
1342
|
+
if (v) {
|
|
1343
|
+
pushGtmEvent("tourUnitSelected", {
|
|
1344
|
+
unit: v,
|
|
1345
|
+
buildingId: this.buildingId,
|
|
1346
|
+
});
|
|
1347
|
+
}
|
|
1348
|
+
}}
|
|
1349
|
+
>
|
|
1350
|
+
</me-select>`
|
|
1351
|
+
: ""}
|
|
1228
1352
|
${this.leadSources.length > 0 &&
|
|
1229
1353
|
(this.featureFlagShowDropdown === FeatureFlagsShowDropdown.always ||
|
|
1230
1354
|
(this.featureFlagShowDropdown ===
|
|
@@ -1678,3 +1802,9 @@ const tourTypeForSubmission = {
|
|
|
1678
1802
|
[TourType.Self]: "self-guided-tour",
|
|
1679
1803
|
[TourType.Virtual]: "live-virtual-tour",
|
|
1680
1804
|
};
|
|
1805
|
+
|
|
1806
|
+
// LayoutOption.value is bedrooms * 10; EliseAI classifier expects `studio` / `Nbr`.
|
|
1807
|
+
function layoutValueToCanonical(value: number): string {
|
|
1808
|
+
const bedrooms = Math.round(value / 10);
|
|
1809
|
+
return bedrooms === 0 ? "studio" : `${bedrooms}br`;
|
|
1810
|
+
}
|
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
} from "../../themes";
|
|
22
22
|
import "./mobile-launcher";
|
|
23
23
|
import "../actions/collapse-expand-button";
|
|
24
|
-
import { DesignConcepts } from "../../fetchBuildingWebchatView";
|
|
24
|
+
import { DesignConcepts, LayoutOption } from "../../fetchBuildingWebchatView";
|
|
25
25
|
import { isMobile, onMobileChange } from "../../utils";
|
|
26
26
|
import classNames from "classnames";
|
|
27
27
|
import LeadSourceClient from "../LeadSourceClient";
|
|
@@ -141,6 +141,9 @@ export class Launcher extends LitElement {
|
|
|
141
141
|
|
|
142
142
|
@property({ attribute: false })
|
|
143
143
|
tourTypeOptions: LabeledOption[] = [];
|
|
144
|
+
|
|
145
|
+
@property({ attribute: false })
|
|
146
|
+
layoutOptions: LayoutOption[] = [];
|
|
144
147
|
@property({ attribute: true })
|
|
145
148
|
hasDynamicSchedulingEnabled = false;
|
|
146
149
|
|
|
@@ -1299,6 +1302,7 @@ export class Launcher extends LitElement {
|
|
|
1299
1302
|
.hasDynamicSchedulingEnabled=${this.hasDynamicSchedulingEnabled}
|
|
1300
1303
|
.leadSources="${this.leadSources}"
|
|
1301
1304
|
.tourTypeOptions=${this.tourTypeOptions}
|
|
1305
|
+
.layoutOptions=${this.layoutOptions}
|
|
1302
1306
|
.orgLegalName=${this.orgLegalName}
|
|
1303
1307
|
buildingId=${this.buildingId}
|
|
1304
1308
|
featureFlagShowDropdown="${this.featureFlagShowDropdown}"
|
|
@@ -1005,6 +1005,8 @@ export class MEChat extends LitElement {
|
|
|
1005
1005
|
.orgLegalName=${this.buildingWebchatView?.orgLegalName ?? ""}
|
|
1006
1006
|
.tourTypeOptions=${this.buildingWebchatView
|
|
1007
1007
|
?.tourTypeOptions ?? []}
|
|
1008
|
+
.layoutOptions=${this.buildingWebchatView?.layoutOptions ??
|
|
1009
|
+
[]}
|
|
1008
1010
|
.launcherStyles=${this.launcherStyles}
|
|
1009
1011
|
.primaryColor=${this.primaryColor}
|
|
1010
1012
|
.backgroundColor=${this.backgroundColor}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import axios from "axios";
|
|
2
|
+
import { LogType, sendLoggingEvent } from "./analytics";
|
|
3
|
+
import { BASE_DOMAIN } from "./globals";
|
|
4
|
+
import { camelize } from "./utils";
|
|
5
|
+
|
|
6
|
+
export type UnitSummary = {
|
|
7
|
+
id: string;
|
|
8
|
+
unitNumber: string;
|
|
9
|
+
numberOfBedrooms: number;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
type FetchBuildingUnitsSummaryParams = {
|
|
13
|
+
buildingSlug: string;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const fetchBuildingUnitsSummary = async ({
|
|
17
|
+
buildingSlug,
|
|
18
|
+
}: FetchBuildingUnitsSummaryParams): Promise<UnitSummary[]> => {
|
|
19
|
+
try {
|
|
20
|
+
const response = await axios.get(
|
|
21
|
+
`${BASE_DOMAIN}/platformApi/webchat/${buildingSlug}/units/summary`
|
|
22
|
+
);
|
|
23
|
+
if (response.data) {
|
|
24
|
+
return camelize<UnitSummary[]>(response.data);
|
|
25
|
+
}
|
|
26
|
+
} catch (error) {
|
|
27
|
+
sendLoggingEvent({
|
|
28
|
+
logType: LogType.error,
|
|
29
|
+
buildingSlug,
|
|
30
|
+
logTitle: "[ERROR_GETTING_UNITS_SUMMARY]",
|
|
31
|
+
logData: { error },
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
return [];
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export default fetchBuildingUnitsSummary;
|
|
@@ -10,4 +10,8 @@ export enum TourAvailabilityResponseRankOrderedSupportedTourTypesEnum {
|
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
// Types are safe to re-export as they are not included in runtime code.
|
|
13
|
-
|
|
13
|
+
import type { TourAvailabilityResponse as SdkTourAvailabilityResponse } from "@meetelise/rest-sdk";
|
|
14
|
+
|
|
15
|
+
export type TourAvailabilityResponse = SdkTourAvailabilityResponse & {
|
|
16
|
+
allowOccupiedUnitTours?: boolean;
|
|
17
|
+
};
|