@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.
- package/package.json +2 -5
- package/public/dist/index.js +242 -121
- package/src/WebComponent/Launcher.ts +8 -2
- package/src/WebComponent/Scheduler/tour-scheduler.ts +259 -110
- package/src/WebComponent/Scheduler/tour-type-option.ts +1 -5
- package/src/WebComponent/actions/action-confirm-button.ts +30 -2
- package/src/WebComponent/me-chat.ts +2 -0
- package/src/createConversation.ts +1 -1
- package/src/getAvailabilities.ts +64 -23
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
|
57
|
-
|
|
58
|
-
@query("input
|
|
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("
|
|
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
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
276
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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 =
|
|
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
|
-
|
|
802
|
-
|
|
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
|
-
<
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
}
|
|
839
|
-
|
|
840
|
-
|
|
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
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
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
|
|
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
|
|
904
|
-
|
|
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
|
-
|
|
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
|
|
1068
|
+
<div
|
|
1069
|
+
class="${classnames("tour-scheduler", {
|
|
1070
|
+
loading: this.waitingForAvailabilities,
|
|
1071
|
+
})}"
|
|
1072
|
+
>
|
|
930
1073
|
<div id="topControls">
|
|
931
|
-
<h1 id="scheduleATour">
|
|
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
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
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?: (
|
|
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:
|
|
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
|
|
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
|
|
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;
|