@meetelise/chat 1.24.1 → 1.25.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 (26) hide show
  1. package/package.json +1 -1
  2. package/public/dist/index.js +946 -265
  3. package/src/WebComponent/FeeCalculator/components/collapsible-fee-section/collapsible-fee-section-styles.ts +86 -0
  4. package/src/WebComponent/FeeCalculator/components/collapsible-fee-section/collapsible-fee-section.ts +94 -0
  5. package/src/WebComponent/FeeCalculator/components/fee-item/fee-item-styles.ts +47 -0
  6. package/src/WebComponent/FeeCalculator/components/fee-item/fee-item.ts +50 -0
  7. package/src/WebComponent/FeeCalculator/components/floor-plan-selector/floor-plan-selector-styles.ts +46 -0
  8. package/src/WebComponent/FeeCalculator/components/floor-plan-selector/floor-plan-selector.ts +70 -0
  9. package/src/WebComponent/FeeCalculator/components/index.ts +3 -0
  10. package/src/WebComponent/FeeCalculator/components/promo-card/promo-card-styles.ts +39 -0
  11. package/src/WebComponent/FeeCalculator/components/promo-card/promo-card.ts +39 -0
  12. package/src/WebComponent/FeeCalculator/fee-calculator-styles.ts +280 -0
  13. package/src/WebComponent/FeeCalculator/fee-calculator.ts +256 -0
  14. package/src/WebComponent/FeeCalculator/index.ts +4 -0
  15. package/src/WebComponent/FeeCalculator/model/building-fee.ts +83 -0
  16. package/src/WebComponent/FeeCalculator/model/transaction-category.ts +23 -0
  17. package/src/WebComponent/chat-additional-actions.ts +9 -7
  18. package/src/WebComponent/icons/CalculatorOutlineIcon.ts +22 -0
  19. package/src/WebComponent/icons/DollarOutlineIcon.ts +18 -0
  20. package/src/WebComponent/launcher/Launcher.ts +114 -1
  21. package/src/WebComponent/launcher/mobile-launcher.ts +13 -0
  22. package/src/WebComponent/me-chat.ts +26 -1
  23. package/src/fetchBuildingWebchatView.ts +5 -3
  24. package/src/globals.ts +1 -0
  25. package/src/services/fees/fetchBuildingFees.ts +28 -0
  26. package/src/utils.ts +32 -0
@@ -0,0 +1,18 @@
1
+ import { svg, SVGTemplateResult } from "lit";
2
+
3
+ const DollarOutlineIcon = (color = "#347FF7"): SVGTemplateResult => svg`
4
+ <svg width="24" height="25" viewBox="0 0 24 25" fill="none" xmlns="http://www.w3.org/2000/svg">
5
+ <g id="Frame" clip-path="url(#clip0_18718_332018)">
6
+ <path id="Vector" d="M3 12.5C3 13.6819 3.23279 14.8522 3.68508 15.9442C4.13738 17.0361 4.80031 18.0282 5.63604 18.864C6.47177 19.6997 7.46392 20.3626 8.55585 20.8149C9.64778 21.2672 10.8181 21.5 12 21.5C13.1819 21.5 14.3522 21.2672 15.4442 20.8149C16.5361 20.3626 17.5282 19.6997 18.364 18.864C19.1997 18.0282 19.8626 17.0361 20.3149 15.9442C20.7672 14.8522 21 13.6819 21 12.5C21 11.3181 20.7672 10.1478 20.3149 9.05585C19.8626 7.96392 19.1997 6.97177 18.364 6.13604C17.5282 5.30031 16.5361 4.63738 15.4442 4.18508C14.3522 3.73279 13.1819 3.5 12 3.5C10.8181 3.5 9.64778 3.73279 8.55585 4.18508C7.46392 4.63738 6.47177 5.30031 5.63604 6.13604C4.80031 6.97177 4.13738 7.96392 3.68508 9.05585C3.23279 10.1478 3 11.3181 3 12.5Z" stroke="${color}" stroke-linecap="round" stroke-linejoin="round"/>
7
+ <path id="Vector_2" d="M14.8 9.50016C14.6188 9.18592 14.3557 8.92686 14.0386 8.75071C13.7215 8.57456 13.3625 8.48795 13 8.50016H11C10.4696 8.50016 9.96086 8.71087 9.58579 9.08594C9.21071 9.46102 9 9.96972 9 10.5002C9 11.0306 9.21071 11.5393 9.58579 11.9144C9.96086 12.2894 10.4696 12.5002 11 12.5002H13C13.5304 12.5002 14.0391 12.7109 14.4142 13.0859C14.7893 13.461 15 13.9697 15 14.5002C15 15.0306 14.7893 15.5393 14.4142 15.9144C14.0391 16.2894 13.5304 16.5002 13 16.5002H11C10.6375 16.5124 10.2785 16.4258 9.96142 16.2496C9.64435 16.0735 9.38115 15.8144 9.2 15.5002" stroke="${color}" stroke-linecap="round" stroke-linejoin="round"/>
8
+ <path id="Vector_3" d="M12 7.5V17.5" stroke="${color}" stroke-linecap="round" stroke-linejoin="round"/>
9
+ </g>
10
+ <defs>
11
+ <clipPath id="clip0_18718_332018">
12
+ <rect width="24" height="24" fill="white" transform="translate(0 0.5)"/>
13
+ </clipPath>
14
+ </defs>
15
+ </svg>
16
+ `;
17
+
18
+ export default DollarOutlineIcon;
@@ -11,6 +11,8 @@ import {
11
11
  import { StyleInfo, styleMap } from "lit/directives/style-map.js";
12
12
  import { installCallUsWindow } from "../actions/call-us-window";
13
13
  import { TourScheduler } from "../Scheduler/tour-scheduler";
14
+ import { FeeCalculator } from "../FeeCalculator/fee-calculator";
15
+ import { installFeeCalculator } from "../FeeCalculator";
14
16
  import { LabeledOption } from "../../fetchBuildingInfo";
15
17
  import {
16
18
  defaultBackgroundColor,
@@ -38,6 +40,7 @@ import { PhoneOutlineIcon } from "../icons/PhoneOutlineIcon";
38
40
  import { HeyThereEmoji } from "../icons/HeyThereEmojiIcon";
39
41
  import { ContactResidentIcon } from "../icons/ContactResidentIcon";
40
42
  import { ApplyOutlineIcon } from "../icons/ApplyOutlineIcon";
43
+ import { CalculatorOutlineIcon } from "../icons/CalculatorOutlineIcon";
41
44
 
42
45
  @customElement("meetelise-launcher")
43
46
  export class Launcher extends LitElement {
@@ -93,40 +96,53 @@ export class Launcher extends LitElement {
93
96
  escortedToursLink = "";
94
97
  @property({ attribute: true })
95
98
  virtualToursLink = "";
99
+
96
100
  @property({ type: Boolean })
97
101
  hasChatEnabledDesktop = false;
98
102
  @property({ type: Boolean })
99
103
  hasChatEnabledMobile = false;
104
+
100
105
  @property({ type: Boolean })
101
106
  hasEmailEnabledDesktop = false;
102
107
  @property({ type: Boolean })
103
108
  hasEmailEnabledMobile = false;
109
+
104
110
  @property({ attribute: true })
105
111
  hasApplyNowEnabledDesktop = false;
106
112
  @property({ attribute: true })
107
113
  hasApplyNowEnabledMobile = false;
108
114
  @property({ attribute: true })
109
115
  applicationLink = "";
116
+
110
117
  @property({ type: Boolean })
111
118
  hasCallUsEnabledDesktop = false;
112
119
  @property({ type: Boolean })
113
120
  hasCallUsEnabledMobile = false;
121
+
114
122
  @property({ type: Boolean })
115
123
  hasTextUsEnabledDesktop = false;
116
124
  @property({ type: Boolean })
117
125
  hasTextUsEnabledMobile = false;
126
+
118
127
  @property({ type: Boolean })
119
128
  hasSSTEnabledDesktop = false;
120
129
  @property({ type: Boolean })
121
130
  hasSSTEnabledMobile = false;
131
+
122
132
  @property({ attribute: false })
123
133
  tourTypeOptions: LabeledOption[] = [];
124
134
  @property({ attribute: true })
125
135
  hasDynamicSchedulingEnabled = false;
136
+
137
+ @property({ attribute: true })
138
+ hasPricingCalculatorEnabledDesktop = false;
126
139
  @property({ attribute: true })
140
+ hasPricingCalculatorEnabledMobile = false;
141
+
127
142
  onExitChat: () => void = () => {
128
143
  return;
129
144
  };
145
+
130
146
  @property({ attribute: false })
131
147
  hasHideMobileFeatures = false;
132
148
 
@@ -186,6 +202,9 @@ export class Launcher extends LitElement {
186
202
  isSSTWindowOpen = false;
187
203
  @state()
188
204
  isTextUsWindowOpen = false;
205
+ @state()
206
+ isCalculatorWindowOpen = false;
207
+
189
208
  @state()
190
209
  private isMobileFeaturesExpanded = false;
191
210
 
@@ -200,6 +219,9 @@ export class Launcher extends LitElement {
200
219
  this.hasTextUsEnabledDesktop || this.hasTextUsEnabledMobile;
201
220
  const isApplyNowEnabled =
202
221
  this.hasApplyNowEnabledDesktop || this.hasApplyNowEnabledMobile;
222
+ const isPricingCalculatorEnabled =
223
+ this.hasPricingCalculatorEnabledDesktop ||
224
+ this.hasPricingCalculatorEnabledMobile;
203
225
 
204
226
  return [
205
227
  isEmailEnabled,
@@ -207,15 +229,18 @@ export class Launcher extends LitElement {
207
229
  isSSTEnabled,
208
230
  isTextUsEnabled,
209
231
  isApplyNowEnabled,
232
+ isPricingCalculatorEnabled,
210
233
  ].filter((v) => v).length;
211
234
  };
212
235
 
213
236
  emailUsWindowRef: Ref<EmailUsWindow> = createRef();
214
237
  tourSchedulerRef: Ref<TourScheduler> = createRef();
238
+ calculatorWindowRef: Ref<FeeCalculator> = createRef();
215
239
 
216
240
  updated = async (): Promise<void> => {
217
241
  this.attachOnClickToEmailUsWindow();
218
242
  this.attachOnClickToSSTWindow();
243
+ this.attachOnClickToCalculatorWindow();
219
244
 
220
245
  // If we have the SST tour popup open next to the chat widget, we want to close it
221
246
  if (
@@ -242,6 +267,12 @@ export class Launcher extends LitElement {
242
267
  sstWindowRef.onCloseClicked = this.onCloseSSTWindow;
243
268
  };
244
269
 
270
+ attachOnClickToCalculatorWindow = (): void => {
271
+ const calculatorWindowRef = this.calculatorWindowRef.value;
272
+ if (!calculatorWindowRef) return;
273
+ calculatorWindowRef.onCloseClicked = this.onCloseCalculatorWindow;
274
+ };
275
+
245
276
  onClickEmailOption = (e: MouseEvent): void => {
246
277
  e.preventDefault();
247
278
  e.stopPropagation();
@@ -268,6 +299,13 @@ export class Launcher extends LitElement {
268
299
  window.open(this.applicationLink, "_blank");
269
300
  };
270
301
 
302
+ onClickPriceCalculatorOption = (e: MouseEvent): void => {
303
+ e.preventDefault();
304
+ e.stopPropagation();
305
+ closeRengrataWidget();
306
+ this.isCalculatorWindowOpen = true;
307
+ };
308
+
271
309
  onClosePhoneWindow = (): void => {
272
310
  this.isCallUsWindowOpen = false;
273
311
  };
@@ -290,6 +328,11 @@ export class Launcher extends LitElement {
290
328
  );
291
329
  }
292
330
  };
331
+
332
+ onCloseCalculatorWindow = (): void => {
333
+ this.isCalculatorWindowOpen = false;
334
+ };
335
+
293
336
  onClickTextUsOption = (e: MouseEvent): void => {
294
337
  e.preventDefault();
295
338
  e.stopPropagation();
@@ -303,6 +346,7 @@ export class Launcher extends LitElement {
303
346
  this.isCallUsWindowOpen,
304
347
  this.isSSTWindowOpen,
305
348
  this.isTextUsWindowOpen,
349
+ this.isCalculatorWindowOpen,
306
350
  ].filter((v) => v).length === 1
307
351
  );
308
352
  };
@@ -331,6 +375,7 @@ export class Launcher extends LitElement {
331
375
  .onClickSSTOption=${this.onClickSSTOption}
332
376
  .onChatTapped=${this.onChatTapped}
333
377
  .onClickApplyNowOption=${this.onClickApplyNowOption}
378
+ .onClickPriceCalculatorOption=${this.onClickPriceCalculatorOption}
334
379
  .overrideRentgrata=${this.overrideRentgrata}
335
380
  .isMobileDesign=${isMobile() ||
336
381
  this.designConcept === DesignConcepts.MINIMIZED}
@@ -365,6 +410,11 @@ export class Launcher extends LitElement {
365
410
  ? false
366
411
  : this.hasApplyNowEnabledMobile}
367
412
  .applicationLink=${this.applicationLink}
413
+ .hasPricingCalculatorEnabled=${!isMobile()
414
+ ? this.hasPricingCalculatorEnabledDesktop
415
+ : this.hasHideMobileFeatures && !this.isMobileFeaturesExpanded
416
+ ? false
417
+ : this.hasPricingCalculatorEnabledMobile}
368
418
  ></mobile-launcher>`;
369
419
  }
370
420
 
@@ -629,6 +679,36 @@ export class Launcher extends LitElement {
629
679
  `
630
680
  : null,
631
681
  },
682
+ {
683
+ pillKey: "Price Calculator",
684
+ pill: this.hasPricingCalculatorEnabledDesktop
685
+ ? html`
686
+ <div
687
+ @click=${this.onClickPriceCalculatorOption}
688
+ class="inner-pill-wrapper"
689
+ style=${styleMap({
690
+ background: this.backgroundColor,
691
+ })}
692
+ >
693
+ <div class="vertical-pill-left">
694
+ <div class="vertical-pill-icon">
695
+ ${CalculatorOutlineIcon(
696
+ this.foregroundColorOnSecondaryBackgroundColor
697
+ )}
698
+ </div>
699
+ <div class="vertical-pill-title">
700
+ <span class="vertical-pill-bold">Calculate</span> Cost
701
+ </div>
702
+ </div>
703
+ <div class="chevron-right">
704
+ ${ChevronRightIcon(
705
+ this.foregroundColorOnSecondaryBackgroundColor
706
+ )}
707
+ </div>
708
+ </div>
709
+ `
710
+ : null,
711
+ },
632
712
  {
633
713
  pillKey: "SST",
634
714
  pill: this.hasSSTEnabledDesktop
@@ -872,6 +952,7 @@ export class Launcher extends LitElement {
872
952
  render(): TemplateResult {
873
953
  installEmailUsWindow();
874
954
  installCallUsWindow();
955
+ installFeeCalculator();
875
956
 
876
957
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
877
958
  (window as any).eliseAi.onOpenSST = (callBack?: () => void) => {
@@ -920,7 +1001,20 @@ export class Launcher extends LitElement {
920
1001
  }
921
1002
  };
922
1003
  }
923
-
1004
+ if (
1005
+ this.hasPricingCalculatorEnabledDesktop ||
1006
+ this.hasPricingCalculatorEnabledMobile
1007
+ ) {
1008
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1009
+ (window as any).eliseAi.onOpenPriceCalculatorWindow = (
1010
+ callBack?: () => void
1011
+ ) => {
1012
+ this.isCalculatorWindowOpen = true;
1013
+ if (callBack) {
1014
+ callBack();
1015
+ }
1016
+ };
1017
+ }
924
1018
  const overrideStyleWindows = {
925
1019
  top:
926
1020
  !isMobile() && this.top !== undefined && !isNaN(this.top)
@@ -939,6 +1033,7 @@ export class Launcher extends LitElement {
939
1033
  ? `${this.right}px`
940
1034
  : undefined,
941
1035
  };
1036
+
942
1037
  return html`
943
1038
  <div
944
1039
  class=${classNames({
@@ -1065,6 +1160,24 @@ export class Launcher extends LitElement {
1065
1160
  </div>
1066
1161
  `
1067
1162
  : ""}
1163
+ ${this.isCalculatorWindowOpen
1164
+ ? html`
1165
+ <div
1166
+ class="launcher__window-wrapper"
1167
+ style=${styleMap(overrideStyleWindows)}
1168
+ >
1169
+ <fee-calculator
1170
+ id="fee-calculator-window"
1171
+ ${ref(this.calculatorWindowRef)}
1172
+ buildingSlug=${this.buildingSlug}
1173
+ orgSlug="${this.orgSlug}"
1174
+ primaryColor="${this.primaryColor}"
1175
+ backgroundColor="${this.backgroundColor}"
1176
+ .compactDesign=${this.showTourNextToChat}
1177
+ ></fee-calculator>
1178
+ </div>
1179
+ `
1180
+ : ""}
1068
1181
  ${!this.isCallToActionWindowOpen() && !this.showTourNextToChat
1069
1182
  ? this.renderActionPills()
1070
1183
  : ""}
@@ -8,6 +8,7 @@ import { PhoneOutlineIcon } from "../icons/PhoneOutlineIcon";
8
8
  import { BookTourOutlineIcon } from "../icons/BookTourOutlineIcon";
9
9
  import { ChatOutlineIcon } from "../icons/ChatOutlineIcon";
10
10
  import { ApplyOutlineIcon } from "../icons/ApplyOutlineIcon";
11
+ import { CalculatorOutlineIcon } from "../icons/CalculatorOutlineIcon";
11
12
 
12
13
  @customElement("mobile-launcher")
13
14
  export class MobileLauncher extends LitElement {
@@ -35,6 +36,10 @@ export class MobileLauncher extends LitElement {
35
36
  return;
36
37
  };
37
38
  @property({ attribute: true })
39
+ onClickPriceCalculatorOption: (e: MouseEvent) => void = () => {
40
+ return;
41
+ };
42
+ @property({ attribute: true })
38
43
  onChatTapped: (e: MouseEvent) => void = () => {
39
44
  return;
40
45
  };
@@ -69,6 +74,9 @@ export class MobileLauncher extends LitElement {
69
74
  @property({ attribute: true })
70
75
  hasApplyNowEnabled = false;
71
76
 
77
+ @property({ attribute: true })
78
+ hasPricingCalculatorEnabled = false;
79
+
72
80
  @property({ attribute: true })
73
81
  applicationLink = "";
74
82
 
@@ -109,6 +117,11 @@ export class MobileLauncher extends LitElement {
109
117
  this.onClickApplyNowOption,
110
118
  ApplyOutlineIcon("black")
111
119
  )}
120
+ ${this.renderListElement(
121
+ this.hasPricingCalculatorEnabled,
122
+ this.onClickPriceCalculatorOption,
123
+ CalculatorOutlineIcon("black")
124
+ )}
112
125
  ${this.renderListElement(
113
126
  this.hasEmailEnabled,
114
127
  this.onClickEmailOption,
@@ -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 } from "../utils";
27
+ import { isMobile, isTestEnv } 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";
@@ -217,6 +217,8 @@ export class MEChat extends LitElement {
217
217
  textMobile: boolean;
218
218
  sstDesktop: boolean;
219
219
  sstMobile: boolean;
220
+ calcDesktop: boolean;
221
+ calcMobile: boolean;
220
222
  } = {
221
223
  callDesktop: false,
222
224
  callMobile: false,
@@ -228,6 +230,8 @@ export class MEChat extends LitElement {
228
230
  textMobile: false,
229
231
  sstDesktop: false,
230
232
  sstMobile: false,
233
+ calcDesktop: false,
234
+ calcMobile: false,
231
235
  };
232
236
 
233
237
  @state()
@@ -350,6 +354,15 @@ export class MEChat extends LitElement {
350
354
  ? buildingDetails.textWithUsPhoneNumber
351
355
  : await getBuildingPhoneNumber(this.buildingSlug);
352
356
 
357
+ const shouldShowCalcDesktop =
358
+ (this.buildingWebchatView?.shouldShowPricingCalculatorDesktop &&
359
+ isTestEnv()) ??
360
+ false;
361
+ const shouldShowCalcMobile =
362
+ (this.buildingWebchatView?.shouldShowPricingCalculatorMobile &&
363
+ isTestEnv()) ??
364
+ false;
365
+
353
366
  this.enabledChatWidgets = {
354
367
  callDesktop: this.buildingWebchatView?.shouldShowPhoneDesktop ?? false,
355
368
  callMobile: this.buildingWebchatView?.shouldShowPhoneMobile ?? false,
@@ -367,6 +380,8 @@ export class MEChat extends LitElement {
367
380
  false,
368
381
  sstDesktop: this.buildingWebchatView?.shouldShowSstDesktop ?? false,
369
382
  sstMobile: this.buildingWebchatView?.shouldShowSstMobile ?? false,
383
+ calcDesktop: shouldShowCalcDesktop,
384
+ calcMobile: shouldShowCalcMobile,
370
385
  };
371
386
 
372
387
  if (
@@ -439,6 +454,9 @@ export class MEChat extends LitElement {
439
454
  if (phoneNumberForSource && !phoneNumberForSource.isMatch) {
440
455
  phoneNumberForSource.number = buildingsPhoneNumber;
441
456
  }
457
+ if (!this.LeadSourceClient?.leadSource && phoneNumberForSource) {
458
+ phoneNumberForSource.number = buildingsPhoneNumber;
459
+ }
442
460
  }
443
461
  if (featureFlagInsertDNIWebsite && phoneNumberForSource?.number) {
444
462
  const totalReplacements = insertDNIIntoWebsite(
@@ -668,11 +686,13 @@ export class MEChat extends LitElement {
668
686
  headerRef.style.left = `${pubnubPopupCoords.left}px`;
669
687
  headerRef.style.top = `${pubnubPopupCoords.bottom}px`;
670
688
  };
689
+
671
690
  connectedCallback(): void {
672
691
  super.connectedCallback();
673
692
  window.addEventListener("resize", this.adjustPositionChatAdditionalActions);
674
693
  window.addEventListener("keydown", this.handleKeydownTab);
675
694
  }
695
+
676
696
  handleKeydownTab = (e: KeyboardEvent): void => {
677
697
  if (e.key === "Tab") {
678
698
  const pubnubContainerElement = this.displayPubnubChat
@@ -836,6 +856,7 @@ export class MEChat extends LitElement {
836
856
  `
837
857
  : ""
838
858
  }
859
+
839
860
  <div
840
861
  id='meetelise-chat-launcher-container'
841
862
  class=${classMap({
@@ -924,6 +945,10 @@ export class MEChat extends LitElement {
924
945
  .hasApplyNowEnabledMobile=${this.buildingWebchatView
925
946
  .shouldShowApplyNowMobile}
926
947
  .applicationLink=${this.buildingWebchatView.applicationLink}
948
+ .hasPricingCalculatorEnabledDesktop=${this.enabledChatWidgets
949
+ .calcDesktop}
950
+ .hasPricingCalculatorEnabledMobile=${this.enabledChatWidgets
951
+ .calcMobile}
927
952
  .hasHideMobileFeatures=${this.hideMobileFeatures}
928
953
  .top=${this.top}
929
954
  .bottom=${this.bottom}
@@ -28,9 +28,9 @@ enum TourAccessType {
28
28
  SCHEDULED_BY_ME_MANAGED_BY_CONCIERGE = "scheduled_by_ME_managed_by_concierge",
29
29
  }
30
30
 
31
- interface LayoutOption {
32
- id: number;
33
- name: string;
31
+ export interface LayoutOption {
32
+ value: number;
33
+ label: string;
34
34
  }
35
35
 
36
36
  interface TourTypeOption {
@@ -107,6 +107,8 @@ export interface BuildingWebchatView {
107
107
  shouldShowSstMobile: boolean | null;
108
108
  shouldShowApplyNowDesktop: boolean | null;
109
109
  shouldShowApplyNowMobile: boolean | null;
110
+ shouldShowPricingCalculatorDesktop: boolean | null;
111
+ shouldShowPricingCalculatorMobile: boolean | null;
110
112
  applicationLink: string | null;
111
113
  isLiveOnCollect: boolean | null;
112
114
  requiresConsentForChat: boolean | null;
package/src/globals.ts ADDED
@@ -0,0 +1 @@
1
+ export const BASE_DOMAIN = "https://app.meetelise.com";
@@ -0,0 +1,28 @@
1
+ import axios from "axios";
2
+ import { LogType, sendLoggingEvent } from "../../analytics";
3
+ import { BASE_DOMAIN } from "../../globals";
4
+ import { BuildingFee } from "../../WebComponent/FeeCalculator/model/building-fee";
5
+ import { camelize } from "../../utils";
6
+
7
+ const fetchBuildingFees = async (
8
+ buildingSlug: string
9
+ ): Promise<BuildingFee[]> => {
10
+ try {
11
+ const feesResponse = await axios.get(
12
+ `${BASE_DOMAIN}/platformApi/webchat/${buildingSlug}/fees`
13
+ );
14
+ if (feesResponse.data) {
15
+ return camelize<BuildingFee[]>(feesResponse.data);
16
+ }
17
+ } catch (error) {
18
+ sendLoggingEvent({
19
+ logType: LogType.error,
20
+ buildingSlug,
21
+ logTitle: "[ERROR_GETTING_FEES]",
22
+ logData: { error },
23
+ });
24
+ }
25
+ return [];
26
+ };
27
+
28
+ export default fetchBuildingFees;
package/src/utils.ts CHANGED
@@ -5,6 +5,7 @@ import isObject from "lodash/isObject";
5
5
  import transform from "lodash/transform";
6
6
  import addHours from "date-fns/addHours";
7
7
  import isBefore from "date-fns/isBefore";
8
+ import { BASE_DOMAIN } from "./globals";
8
9
 
9
10
  export const camelize = <T>(
10
11
  snakeCasedObject: Record<string, unknown>,
@@ -87,3 +88,34 @@ export const isContainingEmail = (message: string): boolean => {
87
88
  return false;
88
89
  }
89
90
  };
91
+
92
+ /**
93
+ * FooBarBizzBazz -> Foo Bar Bizz Bazz
94
+ */
95
+ export const sentenceTitleCase = (str: string): string => {
96
+ const spaced = str.replace(/([A-Z])/g, " $1").trim();
97
+ return spaced
98
+ .split(" ")
99
+ .map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase())
100
+ .join(" ");
101
+ };
102
+
103
+ export const formatCurrency = (
104
+ amount: number,
105
+ maximumFractionDigits = 0
106
+ ): string => {
107
+ return Intl.NumberFormat("en-US", {
108
+ style: "currency",
109
+ currency: "USD",
110
+ minimumFractionDigits: 0,
111
+ maximumFractionDigits,
112
+ }).format(amount ?? 0);
113
+ };
114
+
115
+ export const isTestEnv = (): boolean => {
116
+ const href = location.href;
117
+ if (href.startsWith(BASE_DOMAIN + "/settings/widgets")) return true;
118
+ if (href.startsWith(BASE_DOMAIN + "/demo")) return true;
119
+ if (href.startsWith("http://localhost")) return true;
120
+ return false;
121
+ };