@meetelise/chat 1.15.1 → 1.17.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.
@@ -50,7 +50,7 @@ export class Launcher extends LitElement {
50
50
  onChatTapped: () => void = () => {
51
51
  return;
52
52
  };
53
- @property()
53
+ @property({ attribute: false })
54
54
  launcherStyles: StyleInfo = {};
55
55
 
56
56
  @state()
@@ -85,7 +85,13 @@ export class Launcher extends LitElement {
85
85
  );
86
86
  this.hasTextUsEnabled =
87
87
  registeredPhoneNumbers.length > 0 && this.buildingId !== 4895;
88
- if (this.buildingId === 3660) {
88
+ // TODO: replace this with the real API call once the endpoint exists
89
+ const schedulingIsEnabled = await (async function putApiCallHere(
90
+ buildingId: number
91
+ ) {
92
+ return !!buildingId;
93
+ })(this.buildingId);
94
+ if (schedulingIsEnabled) {
89
95
  this.hasSSTEnabled = true;
90
96
  }
91
97
  }
@@ -11,7 +11,8 @@ import "./time-picker.ts";
11
11
  import "./me-select.ts";
12
12
  import {
13
13
  DateWithTimeZoneOffset,
14
- getAvailabilitiesGroupedByDayCached,
14
+ getAvailabilitiesGroupedByDay,
15
+ getExistenceOfAvailabilitiesByTourType,
15
16
  } from "../../getAvailabilities";
16
17
  import { TourAvailabilityResponseRankOrderedSupportedTourTypesEnum } from "@meetelise/rest-sdk";
17
18
  import { format } from "date-fns";
@@ -22,6 +23,7 @@ import { LabeledOption } from "../../fetchBuildingInfo";
22
23
  import { isMobile } from "../../utils";
23
24
  import axios from "axios";
24
25
  import { mapValues } from "lodash";
26
+ import classnames from "classnames";
25
27
 
26
28
  @customElement("tour-scheduler")
27
29
  export class TourScheduler extends LitElement {
@@ -37,6 +39,12 @@ export class TourScheduler extends LitElement {
37
39
  @state()
38
40
  private tourType = TourType.Guided;
39
41
  @state()
42
+ private shouldShowTourType = {
43
+ [TourType.Guided]: true,
44
+ [TourType.Self]: true,
45
+ [TourType.Virtual]: true,
46
+ };
47
+ @state()
40
48
  private email = "";
41
49
  @state()
42
50
  private phoneNumber = "";
@@ -45,27 +53,50 @@ export class TourScheduler extends LitElement {
45
53
  [day: string]: DateWithTimeZoneOffset[];
46
54
  } = {};
47
55
  @state()
56
+ private waitingForAvailabilities = true;
57
+ @state()
48
58
  private selectedDate?: Date;
49
59
  @state()
50
60
  private selectedTime?: DateWithTimeZoneOffset | null;
51
61
  @state()
52
62
  private mobilePageIndex = 0;
53
63
  @state()
64
+ private isSubmitting = false;
65
+ @state()
54
66
  private tourIsBooked = false;
55
67
 
56
- @query("input#name")
57
- nameInput!: HTMLInputElement;
58
- @query("input#email")
68
+ @query(".inputContainer#firstName input")
69
+ firstNameInput!: HTMLInputElement;
70
+ @query(".inputContainer#lastName input")
71
+ lastNameInput!: HTMLInputElement;
72
+ @query(".inputContainer#email input")
59
73
  emailInput!: HTMLInputElement;
60
- @query("input#phone")
74
+ @query(".inputContainer#phone input")
61
75
  phoneInput!: HTMLInputElement;
62
76
  @query("me-select#unitType")
63
77
  unitTypeSelect!: MESelect;
64
78
 
65
79
  firstUpdated = async (): Promise<void> => {
66
- this.availabilitiesGroupedByDay = await getAvailabilitiesGroupedByDayCached(
80
+ this.availabilitiesGroupedByDay = await getAvailabilitiesGroupedByDay(
67
81
  tourTypeMap[this.tourType]
68
82
  );
83
+ this.waitingForAvailabilities = false;
84
+
85
+ // Show a tour type only if it is supported by the building and has
86
+ // time slots available.
87
+ const availabilitiesExistForTourType =
88
+ await getExistenceOfAvailabilitiesByTourType();
89
+ this.shouldShowTourType = {
90
+ [TourType.Guided]:
91
+ this.tourTypeOptions.map((o) => o.value).includes("WITH_AGENT") &&
92
+ availabilitiesExistForTourType[TourType.Guided],
93
+ [TourType.Self]:
94
+ this.tourTypeOptions.map((o) => o.value).includes("SELF_GUIDED") &&
95
+ availabilitiesExistForTourType[TourType.Self],
96
+ [TourType.Virtual]:
97
+ this.tourTypeOptions.map((o) => o.value).includes("VIRTUAL_SHOWING") &&
98
+ availabilitiesExistForTourType[TourType.Virtual],
99
+ };
69
100
  };
70
101
 
71
102
  protected willUpdate = async (
@@ -74,8 +105,9 @@ export class TourScheduler extends LitElement {
74
105
  | Map<PropertyKey, unknown>
75
106
  ): Promise<void> => {
76
107
  if (_changedProperties.has("tourType")) {
77
- this.availabilitiesGroupedByDay =
78
- await getAvailabilitiesGroupedByDayCached(tourTypeMap[this.tourType]);
108
+ this.availabilitiesGroupedByDay = await getAvailabilitiesGroupedByDay(
109
+ tourTypeMap[this.tourType]
110
+ );
79
111
  }
80
112
  };
81
113
 
@@ -235,7 +267,7 @@ export class TourScheduler extends LitElement {
235
267
  dateAndTime: (): boolean => !!this.selectedDate && !!this.selectedTime,
236
268
  leadInfo: (): boolean => {
237
269
  return (
238
- !!this.nameInput?.value &&
270
+ (!!this.firstNameInput?.value || !!this.lastNameInput?.value) &&
239
271
  this.emailInput?.value.includes("@") &&
240
272
  // TODO: deleting phone number doesn't cause validation to fail, at least on mobile
241
273
  !!this.phoneNumber &&
@@ -272,17 +304,18 @@ export class TourScheduler extends LitElement {
272
304
  email_address: this.email,
273
305
  phone_number: `+1${this.phoneNumber.match(/\d/g)?.join("")}`, // e.g. +12125555555
274
306
  building_id: this.buildingId,
275
- // TODO: this is very bad dumb name-splitting logic! I'm only doing it because the design had one name field and the backend expects two
276
- first_name: this.nameInput.value.split(" ")[0],
277
- last_name: this.nameInput.value.split(" ").slice(1).join(" "),
307
+ first_name: this.firstNameInput.value,
308
+ last_name: this.lastNameInput.value,
278
309
  tour_type: tourTypeForSubmission[this.tourType],
279
310
  tour_time: `${this.selectedTime.datetime}${this.selectedTime.offset}`, // e.g., "2022-06-27T09:00:00-07:00"
280
311
  };
281
312
  const url = `https://app.meetelise.com/platformApi/state/create/scheduleMe`;
313
+ this.isSubmitting = true;
282
314
  const response = await axios.post(url, data, {
283
315
  headers: { ["X-SecurityKey"]: "JRL8jV4VcSCwOSir5gWkpgNLfKghmhBG" },
284
316
  });
285
317
  if (response.status === 200) {
318
+ this.isSubmitting = false;
286
319
  this.tourIsBooked = true;
287
320
  }
288
321
  };
@@ -402,7 +435,7 @@ export class TourScheduler extends LitElement {
402
435
  gap: 12px;
403
436
  }
404
437
 
405
- #yourInformationMenu > input {
438
+ #yourInformationMenu input {
406
439
  width: 305px;
407
440
  height: 49px;
408
441
  border: 1px solid #83818e;
@@ -414,7 +447,7 @@ export class TourScheduler extends LitElement {
414
447
  color: #202020;
415
448
  }
416
449
 
417
- #yourInformationMenu > input::placeholder {
450
+ #yourInformationMenu input::placeholder {
418
451
  color: #202020;
419
452
  }
420
453
 
@@ -456,27 +489,14 @@ export class TourScheduler extends LitElement {
456
489
  padding-top: 32px;
457
490
  }
458
491
 
459
- button#schedule {
492
+ #schedule {
460
493
  width: 145px;
461
494
  height: 50px;
462
- background: #202020;
463
- border: 1px solid #ffffff;
464
- border-radius: 10px;
465
495
  grid-row: 7;
466
496
  grid-column: 3;
467
497
  justify-self: end;
468
498
  align-self: start;
469
499
  margin-top: 18px;
470
- font-family: "Poppins";
471
- font-weight: 700;
472
- font-size: 14px;
473
- color: #ffffff;
474
- box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.5);
475
- }
476
-
477
- button#schedule:disabled {
478
- background: #e7e7e7;
479
- box-shadow: none;
480
500
  }
481
501
 
482
502
  #confirmationMessage {
@@ -488,6 +508,81 @@ export class TourScheduler extends LitElement {
488
508
  font-size: 18px;
489
509
  }
490
510
 
511
+ /* Loading styles: pulsing gray overlay on all the form elements */
512
+
513
+ @keyframes spin {
514
+ 0% {
515
+ transform: none;
516
+ }
517
+ 50% {
518
+ transform: rotateZ(180deg);
519
+ }
520
+ 100% {
521
+ transform: rotateZ(360deg);
522
+ }
523
+ }
524
+
525
+ svg#loadingIcon {
526
+ animation: spin 2s infinite linear;
527
+ }
528
+
529
+ .tour-scheduler.loading #scheduleATour {
530
+ display: flex;
531
+ gap: 10px;
532
+ }
533
+
534
+ @keyframes loadingPulse {
535
+ 0% {
536
+ background-color: #e7e7e7;
537
+ }
538
+ 50% {
539
+ background-color: white;
540
+ }
541
+ 100% {
542
+ background-color: #e7e7e7;
543
+ }
544
+ }
545
+
546
+ tour-type-option,
547
+ date-picker,
548
+ #yourInformationMenu .inputContainer {
549
+ position: relative;
550
+ }
551
+
552
+ .tour-scheduler.loading
553
+ :is(tour-type-option, date-picker, #yourInformationMenu
554
+ .inputContainer)::after {
555
+ content: "";
556
+ position: absolute;
557
+ top: 0;
558
+ left: 0;
559
+ height: 100%;
560
+ z-index: 1;
561
+ animation: loadingPulse 2s infinite;
562
+ }
563
+
564
+ .tour-scheduler.loading tour-type-option::after {
565
+ border-radius: 10px;
566
+ width: 200px;
567
+ }
568
+
569
+ .tour-scheduler.loading date-picker::after {
570
+ border-radius: 10px;
571
+ width: 205px;
572
+ }
573
+
574
+ .tour-scheduler.loading #yourInformationMenu .inputContainer::after {
575
+ width: 100%;
576
+ }
577
+
578
+ .tour-scheduler.loading #yourInformationMenu .inputContainer input {
579
+ visibility: hidden;
580
+ }
581
+
582
+ .tour-scheduler.loading time-picker {
583
+ display: none;
584
+ }
585
+
491
586
  @media (max-width: 767px) {
492
587
  /* TODO: separate styles into general, desktop-specific, and mobile-specific.
493
588
  basically everything I have "unset" or "initial" on should become desktop-specific. the grid layout is only for desktop.
@@ -604,9 +699,8 @@ export class TourScheduler extends LitElement {
604
699
  tourTypeMenu(): TemplateResult {
605
700
  return html`<h2 id="tourType">Tour Type</h2>
606
701
  <div id="tourTypeMenu">
607
- ${this.tourTypeOptions.map((o) => o.value).includes("WITH_AGENT")
702
+ ${this.shouldShowTourType[TourType.Guided]
608
703
  ? html` <tour-type-option
609
- tourtype="guided"
610
704
  heading="Guided tour"
611
705
  subtitle="with an agent"
612
706
  @click="${() => {
@@ -637,9 +731,8 @@ export class TourScheduler extends LitElement {
637
731
  </svg>
638
732
  </tour-type-option>`
639
733
  : ""}
640
- ${this.tourTypeOptions.map((o) => o.value).includes("SELF_GUIDED")
734
+ ${this.shouldShowTourType[TourType.Self]
641
735
  ? html`<tour-type-option
642
- tourtype="self"
643
736
  heading="Take a tour"
644
737
  subtitle="on your own"
645
738
  @click="${() => {
@@ -670,9 +763,8 @@ export class TourScheduler extends LitElement {
670
763
  </svg>
671
764
  </tour-type-option>`
672
765
  : ""}
673
- ${this.tourTypeOptions.map((o) => o.value).includes("SELF_GUIDED")
766
+ ${this.shouldShowTourType[TourType.Virtual]
674
767
  ? html`<tour-type-option
675
- tourtype="guided"
676
768
  heading="Virtual tour"
677
769
  subtitle="over video"
678
770
  @click="${() => {
@@ -741,7 +833,8 @@ export class TourScheduler extends LitElement {
741
833
  .map((date) => format(new Date(date.datetime), "h:mmaaa"))
742
834
  .indexOf(e.target.selectedTime)
743
835
  : null;
744
- this.selectedTime = index ? daysAvailabilities[index] : null; // this.selectedAvailabilityString ?
836
+ this.selectedTime =
837
+ index !== null ? daysAvailabilities[index] : null;
745
838
  }
746
839
  }}
747
840
  ></time-picker>
@@ -798,8 +891,18 @@ export class TourScheduler extends LitElement {
798
891
  },
799
892
  {
800
893
  validate: (): boolean => this.validators.leadInfo(),
801
- nextButtonText: "Schedule tour",
802
- nextButtonAction: this.submit,
894
+ // last page gets <action-confirm-button> instead of the regular button
895
+ nextButtonText: null,
896
+ renderNextButton: (): TemplateResult => html`<action-confirm-button
897
+ id="schedule"
898
+ .onClick=${this.submit}
899
+ .isLoading=${this.isSubmitting}
900
+ height="50px"
901
+ width="145px"
902
+ text="Schedule tour"
903
+ ?disabled=${!this.formIsValidForSubmission()}
904
+ ></action-confirm-button>`,
905
+ nextButtonAction: null,
803
906
  render: (): TemplateResult => {
804
907
  return html`${this.userInfoAndLayoutMenu()}`;
805
908
  },
@@ -809,58 +912,62 @@ export class TourScheduler extends LitElement {
809
912
  userInfoAndLayoutMenu(): TemplateResult {
810
913
  return html`<h2 id="yourInformation">Your information</h2>
811
914
  <div id="yourInformationMenu">
812
- <input
813
- type="text"
814
- placeholder="Name"
815
- id="name"
816
- @input=${() => this.requestUpdate()}
817
- />
818
- <input
819
- type="email"
820
- inputmode="email"
821
- placeholder="Email"
822
- id="email"
823
- .value=${this.email}
824
- @input=${this.onChangeEmail}
825
- />
826
- <input
827
- type="tel"
828
- inputmode="tel"
829
- placeholder="Phone"
830
- id="phone"
831
- maxlength="14"
832
- .value=${this.phoneNumber}
833
- @keydown=${this.handlePhoneKeydown}
834
- @keyup=${this.handlePhoneKeyup}
835
- @input=${(e: Event) => {
836
- if (!e.target) {
837
- return;
838
- }
839
- this.phoneNumber = formatToPhone(
840
- (e.target as HTMLInputElement).value
841
- );
842
- }}
843
- />
915
+ <div class="inputContainer" id="firstName">
916
+ <input
917
+ type="text"
918
+ placeholder="First name"
919
+ name="firstName"
920
+ autocomplete="given-name"
921
+ @input=${() => this.requestUpdate()}
922
+ />
923
+ </div>
924
+ <div class="inputContainer" id="lastName">
925
+ <input
926
+ type="text"
927
+ placeholder="Last name"
928
+ name="lastName"
929
+ autocomplete="family-name"
930
+ @input=${() => this.requestUpdate()}
931
+ />
932
+ </div>
933
+ <div class="inputContainer" id="email">
934
+ <input
935
+ type="email"
936
+ inputmode="email"
937
+ placeholder="Email"
938
+ name="email"
939
+ autocomplete="email"
940
+ .value=${this.email}
941
+ @input=${this.onChangeEmail}
942
+ />
943
+ </div>
944
+ <div class="inputContainer" id="phone">
945
+ <input
946
+ type="tel"
947
+ inputmode="tel"
948
+ placeholder="Phone"
949
+ name="phone"
950
+ autocomplete="tel-national"
951
+ maxlength="14"
952
+ .value=${this.phoneNumber}
953
+ @keydown=${this.handlePhoneKeydown}
954
+ @keyup=${this.handlePhoneKeyup}
955
+ @input=${(e: Event) => {
956
+ if (!e.target) {
957
+ return;
958
+ }
959
+ this.phoneNumber = formatToPhone(
960
+ (e.target as HTMLInputElement).value
961
+ );
962
+ }}
963
+ />
964
+ </div>
844
965
  </div>
845
-
846
- ${this.layoutOptions.length > 0
847
- ? html`<div id="unitChoiceMenu">
848
- <h2 id="unitChoice">What would you like to view?</h2>
849
- <div id="unitOptions">
850
- <me-select
851
- id="unitType"
852
- placeholder="Select type"
853
- .options="${this.layoutOptions.map((o) => o.label)}"
854
- defaultOption="Studio"
855
- @change=${() => {
856
- // to revalidate the form
857
- this.requestUpdate();
858
- }}
859
- >Studio
860
- </me-select>
861
- </div>
862
- </div>`
863
- : ""} `;
966
+ <!--
967
+ Layout dropdown would go here, but has been removed pending backend support.
968
+ Here is the code to add it back:
969
+ https://github.com/MeetElise/chat-ui/blob/e17aca8b39a0eed9430f22c182f2ebcdfb796417/src/WebComponent/Scheduler/tour-scheduler.ts#L846-L863
970
+ --> `;
864
971
  }
865
972
 
866
973
  confirmationMessage(): TemplateResult {
@@ -887,7 +994,13 @@ export class TourScheduler extends LitElement {
887
994
  <p>
888
995
  Thank you!
889
996
  <br />
890
- Your guided tour is scheduled for ${readableDateAndTime}.
997
+ Your
998
+ ${{
999
+ [TourType.Guided]: "guided",
1000
+ [TourType.Self]: "self-guided",
1001
+ [TourType.Virtual]: "virtual",
1002
+ }[this.tourType]}
1003
+ tour is scheduled for ${readableDateAndTime}.
891
1004
  </p>
892
1005
  <p>
893
1006
  Look for an email confirmation along with instructions and directions.
@@ -897,11 +1010,35 @@ export class TourScheduler extends LitElement {
897
1010
  `;
898
1011
  }
899
1012
 
1013
+ loadingIcon(): TemplateResult {
1014
+ return html`<svg
1015
+ id="loadingIcon"
1016
+ width="21"
1017
+ height="21"
1018
+ viewBox="0 0 21 21"
1019
+ fill="none"
1020
+ xmlns="http://www.w3.org/2000/svg"
1021
+ >
1022
+ <path
1023
+ d="M17.835 13.1045C18.4839 11.5628 18.6332 9.85647 18.2621 8.22548C17.8909 6.5945 17.018 5.12084 15.7659 4.0117C14.5139 2.90256 12.9457 2.21372 11.2818 2.04201C9.618 1.87031 7.94218 2.22438 6.49 3.05445L5.498 1.31745C7.01563 0.450066 8.73419 -0.00418222 10.4822 2.90165e-05C12.2302 0.00424025 13.9466 0.466764 15.46 1.34145C19.95 3.93345 21.67 9.48345 19.577 14.1115L20.919 14.8855L16.754 17.0995L16.589 12.3855L17.835 13.1045ZM3.085 6.89845C2.43614 8.44015 2.28678 10.1464 2.65792 11.7774C3.02905 13.4084 3.90201 14.8821 5.15407 15.9912C6.40613 17.1003 7.97432 17.7892 9.63816 17.9609C11.302 18.1326 12.9778 17.7785 14.43 16.9485L15.422 18.6855C13.9044 19.5528 12.1858 20.0071 10.4378 20.0029C8.68979 19.9987 6.97344 19.5361 5.46 18.6615C0.97 16.0695 -0.75 10.5195 1.343 5.89145L0 5.11845L4.165 2.90445L4.33 7.61845L3.084 6.89945L3.085 6.89845Z"
1024
+ fill="#1E1E1E"
1025
+ />
1026
+ </svg>`;
1027
+ }
1028
+
900
1029
  render(): TemplateResult {
901
1030
  if (!isMobile()) {
902
1031
  return html`
903
- <div class="tour-scheduler">
904
- <h1 id="scheduleATour">Schedule a tour</h1>
1032
+ <div
1033
+ class="${classnames("tour-scheduler", {
1034
+ loading: this.waitingForAvailabilities,
1035
+ })}"
1036
+ >
1037
+ <h1 id="scheduleATour">
1038
+ ${this.waitingForAvailabilities
1039
+ ? html`${this.loadingIcon()} Searching availabilities...`
1040
+ : "Schedule a tour"}
1041
+ </h1>
905
1042
  ${this.closeButton()}
906
1043
  ${this.tourIsBooked
907
1044
  ? html`
@@ -914,35 +1051,49 @@ export class TourScheduler extends LitElement {
914
1051
  We’ll send a confirmation and any follow-ups to your email
915
1052
  address.
916
1053
  </p>
917
- <button
1054
+ <action-confirm-button
918
1055
  id="schedule"
1056
+ .onClick=${this.submit}
1057
+ .isLoading=${this.isSubmitting}
1058
+ height="50px"
1059
+ width="145px"
1060
+ text="Schedule tour"
919
1061
  ?disabled=${!this.formIsValidForSubmission()}
920
- @click=${this.submit}
921
- >
922
- Schedule tour
923
- </button>`}
1062
+ ></action-confirm-button>`}
924
1063
  </div>
925
1064
  `;
926
1065
  } else {
927
1066
  const currentPage = this.mobilePages[this.mobilePageIndex];
928
1067
  return html`
929
- <div class="tour-scheduler">
1068
+ <div
1069
+ class="${classnames("tour-scheduler", {
1070
+ loading: this.waitingForAvailabilities,
1071
+ })}"
1072
+ >
930
1073
  <div id="topControls">
931
- <h1 id="scheduleATour">Schedule a tour</h1>
1074
+ <h1 id="scheduleATour">
1075
+ ${this.waitingForAvailabilities
1076
+ ? html`${this.loadingIcon()} Searching availabilities...`
1077
+ : "Schedule a tour"}
1078
+ </h1>
932
1079
  ${this.closeButton()}
933
1080
  </div>
934
1081
  ${this.tourIsBooked
935
1082
  ? this.confirmationMessage()
936
- : html`${currentPage.render()}
937
- <button
938
- id="next"
939
- @click=${currentPage.nextButtonAction}
940
- ?disabled=${(() => {
941
- return !currentPage.validate();
942
- })()}
943
- >
944
- ${currentPage.nextButtonText}
945
- </button>`}
1083
+ : html` ${currentPage.render()}
1084
+ ${!currentPage.renderNextButton
1085
+ ? html` <button
1086
+ id="next"
1087
+ @click=${currentPage.nextButtonAction}
1088
+ ?disabled=${(() => {
1089
+ return (
1090
+ !currentPage.validate() || this.waitingForAvailabilities
1091
+ );
1092
+ })()}
1093
+ >
1094
+ ${currentPage.nextButtonText}
1095
+ </button>`
1096
+ : currentPage.renderNextButton()}`}
946
1097
  </div>
947
1098
  `;
948
1099
  }
@@ -955,8 +1106,6 @@ export enum TourType {
955
1106
  Virtual,
956
1107
  }
957
1108
 
958
- // TODO: we have three UI options and five TourAvailabilityResponseRankOrderedSupportedTourTypesEnum values
959
- // how should they map?
960
1109
  const tourTypeMap = {
961
1110
  [TourType.Guided]:
962
1111
  TourAvailabilityResponseRankOrderedSupportedTourTypesEnum.WithAgent,
@@ -1,20 +1,16 @@
1
1
  import { css, html, LitElement, TemplateResult } from "lit";
2
2
  import { customElement, property } from "lit/decorators.js";
3
- import { TourType } from "./tour-scheduler";
4
3
 
5
4
  @customElement("tour-type-option")
6
5
  export class TourTypeOption extends LitElement {
7
- @property({ type: String })
8
- tourtype = "";
9
6
  @property({ type: String })
10
7
  heading = "";
11
8
  @property({ type: String })
12
9
  subtitle = "";
13
10
  @property({ type: Boolean })
14
11
  selected = false;
15
-
16
12
  @property({ attribute: false })
17
- onClick?: (tourType: TourType) => void;
13
+ onClick?: () => void;
18
14
 
19
15
  static styles = [
20
16
  css`
@@ -1,3 +1,4 @@
1
+ import classnames from "classnames";
1
2
  import { css, html, LitElement, TemplateResult } from "lit";
2
3
  import { customElement, property } from "lit/decorators.js";
3
4
 
@@ -6,6 +7,9 @@ export class ActionConfirmButton extends LitElement {
6
7
  static styles = [
7
8
  css`
8
9
  .action-confirm-button {
10
+ display: flex;
11
+ justify-content: center;
12
+ align-items: center;
9
13
  background: #1e1e1e;
10
14
  border: 2px solid #ffffff;
11
15
  box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.5);
@@ -23,11 +27,24 @@ export class ActionConfirmButton extends LitElement {
23
27
  cursor: pointer;
24
28
  }
25
29
 
26
- .action-confirm-button:active {
30
+ .action-confirm-button:disabled {
31
+ background: #e7e7e7;
32
+ box-shadow: none;
33
+ cursor: initial;
34
+ }
35
+ .action-confirm-button:not(:is(:disabled, .loading)):active {
27
36
  transform: translateY(2px);
28
37
  box-shadow: 0px 0px 0px rgba(36, 53, 141, 0.25);
29
38
  }
30
39
 
40
+ .action-confirm-button:not(:is(:active, :disabled, .loading)):hover {
41
+ opacity: 0.7;
42
+ }
43
+
44
+ .loading {
45
+ cursor: initial;
46
+ }
47
+
31
48
  .lds-ring {
32
49
  display: inline-block;
33
50
  position: relative;
@@ -71,9 +88,20 @@ export class ActionConfirmButton extends LitElement {
71
88
  text = "Submit";
72
89
  @property({ attribute: false })
73
90
  isLoading = false;
91
+ @property({ type: Boolean })
92
+ disabled = false;
93
+ @property({ type: String })
94
+ height = "initial";
95
+ @property({ type: String })
96
+ width = "initial";
74
97
 
75
98
  render = (): TemplateResult => {
76
- return html`<button class="action-confirm-button" @click=${this.onClick}>
99
+ return html`<button
100
+ class=${classnames("action-confirm-button", { loading: this.isLoading })}
101
+ @click=${!this.isLoading ? this.onClick : null}
102
+ ?disabled=${this.disabled}
103
+ style=${`height: ${this.height}; width: ${this.width};`}
104
+ >
77
105
  ${!this.isLoading
78
106
  ? this.text
79
107
  : html`<div class="lds-ring">
@@ -136,6 +136,8 @@ export class MEChat extends LitElement {
136
136
  await this.configureTalkJSPopup(building, theme, session, avatarSrc);
137
137
  this.configureLauncherElement();
138
138
 
139
+ this.analytics?.ping("load");
140
+
139
141
  this.yardiDNIScriptInterval = setInterval(
140
142
  () => this.pollForYardiCampaignSource(),
141
143
  1000
@@ -46,7 +46,7 @@ export default function createConversation(
46
46
  building.avatarType === "image" && building.avatarSrc
47
47
  ? avatarSrc
48
48
  : defaultAvatarUrl,
49
- // uncomment this to test changes to the default avatar if your test building has its own avatar
49
+ // uncomment the following line to test changes to the default avatar if your test building has its own avatar
50
50
  // avatarUrl: defaultAvatarUrl,
51
51
  };
52
52
  return conversation;