@meetelise/chat 1.31.0 → 1.32.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.
Files changed (39) hide show
  1. package/dist/src/WebComponent/FeeCalculator/components/{addon-item → addons/addon-item}/addon-item.d.ts +2 -2
  2. package/dist/src/WebComponent/FeeCalculator/components/addons/rentable-item/rentable-item-styles.d.ts +2 -0
  3. package/dist/src/WebComponent/FeeCalculator/components/addons/rentable-item/rentable-item.d.ts +25 -0
  4. package/dist/src/WebComponent/FeeCalculator/components/fee-calculator-layout/fee-calculator-layout.d.ts +13 -5
  5. package/dist/src/WebComponent/FeeCalculator/components/fee-item/fee-item.d.ts +1 -1
  6. package/dist/src/WebComponent/FeeCalculator/components/floor-plan-selector/floor-plan-selector.d.ts +8 -8
  7. package/dist/src/WebComponent/FeeCalculator/components/floorplan-image-card/floorplan-image-card.d.ts +3 -3
  8. package/dist/src/WebComponent/FeeCalculator/components/index.d.ts +1 -1
  9. package/dist/src/WebComponent/FeeCalculator/constants.d.ts +1 -0
  10. package/dist/src/WebComponent/FeeCalculator/fee-calculator.d.ts +4 -3
  11. package/dist/src/globals.d.ts +1 -0
  12. package/dist/src/services/fees/calculateQuote.d.ts +0 -1
  13. package/dist/src/services/fees/fetchBuildingUnits.d.ts +29 -0
  14. package/dist/src/utils/queryParamBuilder.d.ts +8 -0
  15. package/package.json +1 -1
  16. package/public/dist/index.js +302 -241
  17. package/src/WebComponent/FeeCalculator/components/{addon-item → addons/addon-item}/addon-item.ts +33 -35
  18. package/src/WebComponent/FeeCalculator/components/addons/rentable-item/rentable-item-styles.ts +9 -0
  19. package/src/WebComponent/FeeCalculator/components/addons/rentable-item/rentable-item.ts +138 -0
  20. package/src/WebComponent/FeeCalculator/components/fee-calculator-layout/fee-calculator-layout.ts +42 -17
  21. package/src/WebComponent/FeeCalculator/components/fee-item/fee-item.ts +1 -1
  22. package/src/WebComponent/FeeCalculator/components/floor-plan-selector/floor-plan-selector-styles.ts +0 -1
  23. package/src/WebComponent/FeeCalculator/components/floor-plan-selector/floor-plan-selector.ts +31 -35
  24. package/src/WebComponent/FeeCalculator/components/floorplan-image-card/floorplan-image-card.ts +13 -13
  25. package/src/WebComponent/FeeCalculator/components/index.ts +1 -1
  26. package/src/WebComponent/FeeCalculator/constants.ts +2 -0
  27. package/src/WebComponent/FeeCalculator/fee-calculator.ts +48 -25
  28. package/src/WebComponent/actions/call-us-window.ts +32 -10
  29. package/src/WebComponent/launcher/Launcher.ts +0 -1
  30. package/src/WebComponent/me-chat.ts +4 -7
  31. package/src/globals.ts +2 -0
  32. package/src/services/fees/calculateQuote.ts +0 -1
  33. package/src/services/fees/fetchBuildingUnits.ts +84 -0
  34. package/src/utils/queryParamBuilder.ts +28 -0
  35. package/dist/src/WebComponent/FeeCalculator/components/addon-item/index.d.ts +0 -1
  36. package/dist/src/services/fees/fetchBuildingFloorplans.d.ts +0 -21
  37. package/src/WebComponent/FeeCalculator/components/addon-item/index.ts +0 -1
  38. /package/dist/src/WebComponent/FeeCalculator/components/{addon-item/addon-item-styles.d.ts → addons/common-addon-styles.d.ts} +0 -0
  39. /package/src/WebComponent/FeeCalculator/components/{addon-item/addon-item-styles.ts → addons/common-addon-styles.ts} +0 -0
@@ -1,14 +1,19 @@
1
1
  import { LitElement, html, TemplateResult } from "lit";
2
2
  import { customElement, property, state } from "lit/decorators.js";
3
- import { classMap } from "lit/directives/class-map.js";
4
3
  import { feeCalculatorStyles } from "./fee-calculator-styles";
5
4
  import fetchBuildingWebchatView, {
6
5
  BuildingWebchatView,
7
6
  LayoutOption,
8
7
  } from "../../fetchBuildingWebchatView";
9
8
  import { BuildingFee, RecurrenceFrequency } from "./model/building-fee";
10
- import fetchBuildingFees from "../../services/fees/fetchBuildingFees";
11
- import { ALL_LAYOUTS_OPTION, CALCULATE_DEBOUNCE_MS } from "./constants";
9
+ import fetchBuildingFees, {
10
+ RentableItemSummary,
11
+ } from "../../services/fees/fetchBuildingFees";
12
+ import {
13
+ ALL_LAYOUTS_OPTION,
14
+ CALCULATE_DEBOUNCE_MS,
15
+ DEFAULT_LEASE_TERM,
16
+ } from "./constants";
12
17
  import {
13
18
  calculateQuote,
14
19
  CalculateQuoteResponse,
@@ -19,6 +24,8 @@ import { defaultBackgroundColor, defaultPrimaryColor } from "../../themes";
19
24
  import debounce from "lodash/debounce";
20
25
  import { XOutlineIcon } from "../icons/XOutlineIcon";
21
26
  import { IncentiveV2 } from "../../types/incentive-v2";
27
+ import { Unit } from "../../services/fees/fetchBuildingUnits";
28
+ import { TODAY } from "../../globals";
22
29
 
23
30
  import "./components";
24
31
  import "./components/fee-calculator-layout/fee-calculator-layout";
@@ -41,9 +48,6 @@ export class FeeCalculator extends LitElement {
41
48
  @property({ type: String })
42
49
  private backgroundColor: string = defaultBackgroundColor;
43
50
 
44
- @property({ attribute: true, type: Boolean })
45
- compactDesign = false;
46
-
47
51
  @property()
48
52
  onCloseClicked: (() => void) | null = null;
49
53
 
@@ -66,7 +70,7 @@ export class FeeCalculator extends LitElement {
66
70
  private selectedLayoutIds: number[] = [ALL_LAYOUTS_OPTION];
67
71
 
68
72
  @state()
69
- private selectedUnitId: number | null = null;
73
+ private selectedUnit: Unit | null = null;
70
74
 
71
75
  @state()
72
76
  private desiredAddons: DesiredAddon[] = [];
@@ -75,10 +79,10 @@ export class FeeCalculator extends LitElement {
75
79
  private desiredRentableItems: DesiredRentableItem[] = [];
76
80
 
77
81
  @state()
78
- private leaseTerm = 12;
82
+ private leaseTerm = DEFAULT_LEASE_TERM;
79
83
 
80
84
  @state()
81
- private moveInDate: Date | null = null;
85
+ private moveInDate: Date | null = TODAY;
82
86
 
83
87
  @state()
84
88
  private buildingWebchatView: BuildingWebchatView | null = null;
@@ -115,17 +119,27 @@ export class FeeCalculator extends LitElement {
115
119
  [RecurrenceFrequency.Unknown]: [],
116
120
  };
117
121
 
122
+ @state()
123
+ private rentableItems: RentableItemSummary[] = [];
124
+
118
125
  private debouncedCalculateQuote = debounce(async (): Promise<void> => {
119
- if (!this.selectedUnitId || !this.moveInDate) return;
126
+ if (!this.selectedUnit || !this.moveInDate) return;
127
+
128
+ // If lead's desired move in date is before the their selected unit's earliest available date
129
+ // use the unit's earliest available date (otherwise pricing will be incorrect)
130
+ const moveInDate =
131
+ this.moveInDate < new Date(this.selectedUnit.earliestAvailable)
132
+ ? this.selectedUnit.earliestAvailable
133
+ : this.moveInDate?.toISOString().split("T")[0];
120
134
 
121
135
  try {
122
136
  this.quote = await calculateQuote({
123
137
  buildingSlug: this.buildingSlug,
124
- unitId: this.selectedUnitId,
138
+ unitId: this.selectedUnit.id,
125
139
  addons: this.desiredAddons,
126
140
  rentableItems: this.desiredRentableItems,
127
141
  leaseTerm: this.leaseTerm,
128
- moveInDate: this.moveInDate.toISOString().split("T")[0],
142
+ moveInDate,
129
143
  });
130
144
  } finally {
131
145
  this.isLoading = false;
@@ -155,7 +169,10 @@ export class FeeCalculator extends LitElement {
155
169
 
156
170
  this.buildingWebchatView = buildingWebchatView;
157
171
  this.groupedFees = this.groupFees(buildingFeeResponse.fees);
158
- this.incentives = buildingFeeResponse.buildingIncentives;
172
+ this.rentableItems = buildingFeeResponse.rentableItems;
173
+
174
+ // TODO(Leo): Re-enable
175
+ // this.incentives = buildingFeeResponse.buildingIncentives;
159
176
 
160
177
  this.enabledChatWidgets = {
161
178
  callDesktop: this.buildingWebchatView?.shouldShowPhoneDesktop ?? false,
@@ -177,14 +194,14 @@ export class FeeCalculator extends LitElement {
177
194
  }
178
195
 
179
196
  calculateQuote = async (): Promise<void> => {
180
- if (!this.selectedUnitId || !this.moveInDate) return;
197
+ if (!this.selectedUnit || !this.moveInDate) return;
181
198
 
182
199
  this.isLoading = true;
183
200
  this.debouncedCalculateQuote();
184
201
  };
185
202
 
186
- handleUnitSelect = (unitId: number): void => {
187
- this.selectedUnitId = unitId;
203
+ handleUnitSelect = (unit: Unit): void => {
204
+ this.selectedUnit = unit;
188
205
  this.calculateQuote();
189
206
  };
190
207
 
@@ -216,9 +233,18 @@ export class FeeCalculator extends LitElement {
216
233
  };
217
234
 
218
235
  handleRentableItemSelect = (rentableItem: DesiredRentableItem): void => {
219
- this.desiredRentableItems = this.desiredRentableItems.filter(
220
- (item) => item.id !== rentableItem.id
236
+ const isExistingRentableItem = this.desiredRentableItems.some(
237
+ (item) => item.id === rentableItem.id
221
238
  );
239
+
240
+ if (isExistingRentableItem) {
241
+ this.desiredRentableItems = this.desiredRentableItems.filter(
242
+ (item) => item.id !== rentableItem.id
243
+ );
244
+ } else {
245
+ this.desiredRentableItems.push(rentableItem);
246
+ }
247
+
222
248
  this.calculateQuote();
223
249
  };
224
250
 
@@ -273,14 +299,9 @@ export class FeeCalculator extends LitElement {
273
299
  };
274
300
 
275
301
  render(): TemplateResult {
276
- const containerClasses = {
277
- "fee-calculator-container": true,
278
- compact: this.compactDesign,
279
- };
280
-
281
302
  return html`
282
303
  <div
283
- class=${classMap(containerClasses)}
304
+ class="fee-calculator-container"
284
305
  @keydown=${(e: KeyboardEvent) => e.stopPropagation()}
285
306
  @keyup=${(e: KeyboardEvent) => e.stopPropagation()}
286
307
  >
@@ -320,8 +341,9 @@ export class FeeCalculator extends LitElement {
320
341
  <fee-calculator-layout
321
342
  .buildingSlug=${this.buildingSlug}
322
343
  .isLoading=${this.isLoading}
323
- .selectedUnitId=${this.selectedUnitId}
344
+ .selectedUnit=${this.selectedUnit}
324
345
  .groupedFees=${this.groupedFees}
346
+ .rentableItems=${this.rentableItems}
325
347
  .quote=${this.quote}
326
348
  .layoutOptions=${this.layouts}
327
349
  .selectedLayoutIds=${this.selectedLayoutIds}
@@ -330,6 +352,7 @@ export class FeeCalculator extends LitElement {
330
352
  .onMoveInDateChange=${this.handleMoveInDateChange}
331
353
  .onLeaseTermChange=${this.handleLeaseTermChange}
332
354
  .onAddonSelect=${this.handleAddonSelect}
355
+ .onRentableItemSelect=${this.handleRentableItemSelect}
333
356
  ></fee-calculator-layout>
334
357
  </div>
335
358
 
@@ -300,16 +300,38 @@ export class CallUsWindow extends LitElement {
300
300
  </div>
301
301
 
302
302
  <div class="text-us-window__description">
303
- By providing your number and clicking send, you consent to receive
304
- recurring marketing calls and voice and text messages from or on behalf
305
- of ${this.orgLegalName} at this number using artificial voice or an
306
- autodialer system. Messages may be AI or human generated. This consent
307
- is not required to lease at this property. Msg & Data rates may apply.
308
- You consent to this
309
- <a target="_blank" href="http://bit.ly/me_privacy_policy"
310
- >privacy policy</a
311
- >, including having your number and communications recorded and used by
312
- a third party.
303
+ ${this.orgSlug === "greystar"
304
+ ? html`By providing your phone number and clicking send, you consent
305
+ to receive recurring marketing calls and voice and text messages
306
+ from Greystar or on its behalf at this number using artificial
307
+ voice and/or an autodialer. Messages may be AI or human-generated.
308
+ Your phone number and communications are shared with and recorded
309
+ and used by EliseAI. You are not required to provide your phone
310
+ number or consent to these terms to lease at this property. Msg &
311
+ Data rates may apply. You consent to
312
+ <a
313
+ href="https://www.greystar.com/privacy"
314
+ target="_blank"
315
+ rel="noopener noreferrer"
316
+ >Greystar's Global Privacy Policy</a
317
+ >
318
+ and
319
+ <a
320
+ href="http://bit.ly/me_privacy_policy"
321
+ target="_blank"
322
+ rel="noopener noreferrer"
323
+ >EliseAI's Privacy Policy</a
324
+ >.`
325
+ : html`By providing your number and clicking send, you consent to
326
+ receive recurring marketing calls and voice and text messages from
327
+ or on behalf of ${this.orgLegalName} at this number using
328
+ artificial voice or an autodialer system. Messages may be AI or
329
+ human generated. This consent is not required to lease at this
330
+ property. Msg & Data rates may apply. You consent to this
331
+ <a target="_blank" href="http://bit.ly/me_privacy_policy"
332
+ >privacy policy</a
333
+ >, including having your number and communications recorded and
334
+ used by a third party.`}
313
335
  </div>
314
336
  </div>`;
315
337
  };
@@ -1260,7 +1260,6 @@ export class Launcher extends LitElement {
1260
1260
  orgSlug="${this.orgSlug}"
1261
1261
  primaryColor="${this.primaryColor}"
1262
1262
  backgroundColor="${this.backgroundColor}"
1263
- .compactDesign=${this.showTourNextToChat}
1264
1263
  .onCloseClicked=${this.onCloseCalculatorWindow}
1265
1264
  .onClickEmailOption=${this.onClickEmailOption}
1266
1265
  .onClickPhoneOption=${this.onClickPhoneOption}
@@ -24,7 +24,7 @@ import fetchPhoneNumberFromSource, {
24
24
  } from "../fetchPhoneNumberFromSource";
25
25
  import { defaultPrimaryColor, defaultBackgroundColor } from "../themes";
26
26
  import getShouldShowWebchat from "../getShouldShowWebchat";
27
- import { isMobile, isTestEnv } from "../utils";
27
+ import { isMobile } from "../utils";
28
28
  import { installLauncher } from "./launcher/Launcher";
29
29
  import parseISO from "date-fns/parseISO";
30
30
  import isPast from "date-fns/isPast";
@@ -117,6 +117,7 @@ export class MEChat extends LitElement {
117
117
  bottom: 0;
118
118
  }
119
119
  `;
120
+
120
121
  @property({ type: String })
121
122
  private buildingSlug = "";
122
123
  @property({ type: String })
@@ -356,13 +357,9 @@ export class MEChat extends LitElement {
356
357
  : await getBuildingPhoneNumber(this.buildingSlug);
357
358
 
358
359
  const shouldShowCalcDesktop =
359
- (this.buildingWebchatView?.shouldShowPricingCalculatorDesktop &&
360
- isTestEnv()) ??
361
- false;
360
+ this.buildingWebchatView?.shouldShowPricingCalculatorDesktop ?? false;
362
361
  const shouldShowCalcMobile =
363
- (this.buildingWebchatView?.shouldShowPricingCalculatorMobile &&
364
- isTestEnv()) ??
365
- false;
362
+ this.buildingWebchatView?.shouldShowPricingCalculatorMobile ?? false;
366
363
 
367
364
  this.enabledChatWidgets = {
368
365
  callDesktop: this.buildingWebchatView?.shouldShowPhoneDesktop ?? false,
package/src/globals.ts CHANGED
@@ -1 +1,3 @@
1
1
  export const BASE_DOMAIN = "https://app.meetelise.com";
2
+
3
+ export const TODAY = new Date();
@@ -27,7 +27,6 @@ export type DesiredAddon = {
27
27
 
28
28
  export type DesiredRentableItem = {
29
29
  id: number;
30
- quantity: number;
31
30
  type: string;
32
31
  };
33
32
 
@@ -0,0 +1,84 @@
1
+ import axios from "axios";
2
+ import { LogType, sendLoggingEvent } from "../../analytics";
3
+ import { BASE_DOMAIN } from "../../globals";
4
+ import { camelize } from "../../utils";
5
+ import QueryParamBuilder from "../../utils/queryParamBuilder";
6
+
7
+ export type Unit = {
8
+ /**
9
+ * ID comes back in the format "u1234567890" - we strip the "u"
10
+ */
11
+ id: number;
12
+ unitNumber: string;
13
+ layout: number;
14
+ externalFloorPlanDescriptionId: string;
15
+ numberOfBedrooms: number;
16
+ numberOfBathrooms: number;
17
+ squareFootage: number;
18
+ floor: number;
19
+ floorplanName: string;
20
+ floorplanUrl: string;
21
+ availabilityStage: string;
22
+ earliestAvailable: string;
23
+ latestAvailable: string;
24
+ startingPrice: number;
25
+ maxPrice: number;
26
+ };
27
+
28
+ type FetchPropertyUnitsParams = {
29
+ buildingSlug: string;
30
+ numBedrooms?: number;
31
+ moveInDateEarliest?: Date;
32
+ moveInDateLatest?: Date;
33
+ leaseTermMin?: number;
34
+ };
35
+
36
+ const fetchBuildingUnits = async ({
37
+ buildingSlug,
38
+ numBedrooms,
39
+ moveInDateEarliest,
40
+ moveInDateLatest,
41
+ leaseTermMin,
42
+ }: FetchPropertyUnitsParams): Promise<Unit[]> => {
43
+ try {
44
+ const queryParamBuilder = new QueryParamBuilder();
45
+ queryParamBuilder
46
+ .addSingle("num_bedrooms", numBedrooms?.toString())
47
+ .addSingle(
48
+ "move_in_date_earliest",
49
+ moveInDateEarliest?.toISOString().split("T")[0]
50
+ )
51
+ .addSingle(
52
+ "move_in_date_latest",
53
+ moveInDateLatest?.toISOString().split("T")[0]
54
+ )
55
+ .addSingle("lease_term_min", leaseTermMin?.toString());
56
+
57
+ const queryString = queryParamBuilder.build();
58
+ const propertyUnitsResponse = await axios.get(
59
+ `${BASE_DOMAIN}/platformApi/webchat/${buildingSlug}/units${queryString}`
60
+ );
61
+
62
+ if (propertyUnitsResponse.data) {
63
+ const camelizedUnits = camelize<Unit[]>(propertyUnitsResponse.data);
64
+ return camelizedUnits.map((unit) => ({
65
+ ...unit,
66
+ id: parseInt(unit.id.toString().substring(1)),
67
+ }));
68
+ }
69
+ } catch (error) {
70
+ sendLoggingEvent({
71
+ logType: LogType.error,
72
+ buildingSlug,
73
+ logTitle: "[ERROR_GETTING_UNITS]",
74
+ logData: {
75
+ error,
76
+ params: { numBedrooms, moveInDateEarliest, moveInDateLatest },
77
+ },
78
+ });
79
+ }
80
+
81
+ return [];
82
+ };
83
+
84
+ export default fetchBuildingUnits;
@@ -0,0 +1,28 @@
1
+ class QueryParamBuilder {
2
+ private params: URLSearchParams;
3
+
4
+ constructor() {
5
+ this.params = new URLSearchParams();
6
+ }
7
+
8
+ addSingle(key: string, value?: string): QueryParamBuilder {
9
+ if (!value) return this;
10
+ this.params.append(key, value);
11
+ return this;
12
+ }
13
+
14
+ addArray(key: string, values?: string[]): QueryParamBuilder {
15
+ if (!values) return this;
16
+ values.forEach((value) => {
17
+ if (!value) return;
18
+ this.params.append(`${key}[]`, value);
19
+ });
20
+ return this;
21
+ }
22
+
23
+ build(): string {
24
+ return this.params.toString() ? `?${this.params.toString()}` : "";
25
+ }
26
+ }
27
+
28
+ export default QueryParamBuilder;
@@ -1 +0,0 @@
1
- export * from "./addon-item";
@@ -1,21 +0,0 @@
1
- export declare type Floorplan = {
2
- unitId: number;
3
- name: string;
4
- bedrooms: number;
5
- bathrooms: number;
6
- numAvailable: number;
7
- startingPrice: number;
8
- maxPrice: number;
9
- earliestAvailable: string;
10
- latestAvailable: string;
11
- squareFeet: number;
12
- url: string | null;
13
- };
14
- declare type FetchFloorplansParams = {
15
- buildingSlug: string;
16
- numBedrooms?: number;
17
- moveInDateEarliest?: Date;
18
- moveInDateLatest?: Date;
19
- };
20
- declare const fetchBuildingFloorplans: ({ buildingSlug, numBedrooms, moveInDateEarliest, moveInDateLatest, }: FetchFloorplansParams) => Promise<Floorplan[]>;
21
- export default fetchBuildingFloorplans;
@@ -1 +0,0 @@
1
- export * from "./addon-item";