@meetelise/chat 1.44.0 → 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.
@@ -62,6 +62,9 @@ import { getTimezoneAbbreviation } from "../../getTimezoneString";
62
62
  import startOfDay from "date-fns/startOfDay";
63
63
  import isSameDay from "date-fns/isSameDay";
64
64
  import { LeadSourceMultitouchClient } from "../LeadSourceMultitouchClient";
65
+ import fetchBuildingUnitsSummary, {
66
+ UnitSummary,
67
+ } from "../../fetchBuildingUnitsSummary";
65
68
 
66
69
  @customElement("tour-scheduler")
67
70
  export class TourScheduler extends LitElement {
@@ -196,6 +199,8 @@ export class TourScheduler extends LitElement {
196
199
  selectedLeadSource!: MESelect;
197
200
  @query("me-select#layout")
198
201
  selectedLayoutEl?: MESelect;
202
+ @query("me-select#unit")
203
+ selectedUnitEl?: MESelect;
199
204
 
200
205
  @state()
201
206
  firstNameInputValue = "";
@@ -205,6 +210,12 @@ export class TourScheduler extends LitElement {
205
210
  leadSourceInputValue = "";
206
211
  @state()
207
212
  selectedLayoutValue = "";
213
+ @state()
214
+ selectedUnitValue = "";
215
+ @state()
216
+ private units: UnitSummary[] = [];
217
+ @state()
218
+ private allowOccupiedUnitTours = false;
208
219
 
209
220
  @state()
210
221
  errorGettingAvailabilities = false;
@@ -410,8 +421,51 @@ export class TourScheduler extends LitElement {
410
421
  return null;
411
422
  };
412
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
+
413
457
  firstUpdated = async (): Promise<void> => {
414
- await this._setAvailabilities();
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
+ ]);
415
469
  };
416
470
 
417
471
  protected willUpdate = async (
@@ -652,6 +706,8 @@ export class TourScheduler extends LitElement {
652
706
  this.leadSourceInputValue = parsedLeadSource;
653
707
  const selectedLayout =
654
708
  this.selectedLayoutEl?.value || this.selectedLayoutValue || null;
709
+ const selectedUnit =
710
+ this.selectedUnitEl?.value || this.selectedUnitValue || null;
655
711
  pushGtmEvent("scheduleTourSubmitted", {
656
712
  email: this.email,
657
713
  phone: `+1${this.phoneNumber.match(/\d/g)?.join("")}`,
@@ -662,6 +718,7 @@ export class TourScheduler extends LitElement {
662
718
  originatingSource:
663
719
  leadSources.find((i) => i !== "property-website") || null,
664
720
  layout: selectedLayout,
721
+ unit: selectedUnit,
665
722
  });
666
723
  const data = {
667
724
  referrer: document.referrer,
@@ -683,6 +740,7 @@ export class TourScheduler extends LitElement {
683
740
  query_params: Object.fromEntries(queryParams.entries()),
684
741
  conversation_tracking_id: this.leadSourceClient?.chatId,
685
742
  layouts: selectedLayout ? [selectedLayout] : undefined,
743
+ unit_numbers: selectedUnit ? [selectedUnit] : undefined,
686
744
  lead_sources_with_timestamps: (
687
745
  this.leadSourceMultitouchClient?.getSafeLeadSourceTouchpointsWithDefault(
688
746
  {
@@ -1247,6 +1305,21 @@ export class TourScheduler extends LitElement {
1247
1305
  @change=${() => {
1248
1306
  const v = this.selectedLayoutEl?.value || "";
1249
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
+ }
1250
1323
  if (v) {
1251
1324
  pushGtmEvent("tourLayoutSelected", {
1252
1325
  layout: v,
@@ -1257,6 +1330,25 @@ export class TourScheduler extends LitElement {
1257
1330
  >
1258
1331
  </me-select>`
1259
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
+ : ""}
1260
1352
  ${this.leadSources.length > 0 &&
1261
1353
  (this.featureFlagShowDropdown === FeatureFlagsShowDropdown.always ||
1262
1354
  (this.featureFlagShowDropdown ===
@@ -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
- export type { TourAvailabilityResponse } from "@meetelise/rest-sdk";
13
+ import type { TourAvailabilityResponse as SdkTourAvailabilityResponse } from "@meetelise/rest-sdk";
14
+
15
+ export type TourAvailabilityResponse = SdkTourAvailabilityResponse & {
16
+ allowOccupiedUnitTours?: boolean;
17
+ };