@meetelise/chat 1.13.10 → 1.15.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
|
-
|
|
88
|
+
// TODO: replace this with a 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 (this.buildingId === 3660 && schedulingIsEnabled) {
|
|
89
95
|
this.hasSSTEnabled = true;
|
|
90
96
|
}
|
|
91
97
|
}
|
|
@@ -12,6 +12,7 @@ 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,6 +53,8 @@ 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;
|
|
@@ -53,11 +63,13 @@ export class TourScheduler extends LitElement {
|
|
|
53
63
|
@state()
|
|
54
64
|
private tourIsBooked = false;
|
|
55
65
|
|
|
56
|
-
@query("input
|
|
57
|
-
|
|
58
|
-
@query("input
|
|
66
|
+
@query(".inputContainer#firstName input")
|
|
67
|
+
firstNameInput!: HTMLInputElement;
|
|
68
|
+
@query(".inputContainer#lastName input")
|
|
69
|
+
lastNameInput!: HTMLInputElement;
|
|
70
|
+
@query(".inputContainer#email input")
|
|
59
71
|
emailInput!: HTMLInputElement;
|
|
60
|
-
@query("
|
|
72
|
+
@query(".inputContainer#phone input")
|
|
61
73
|
phoneInput!: HTMLInputElement;
|
|
62
74
|
@query("me-select#unitType")
|
|
63
75
|
unitTypeSelect!: MESelect;
|
|
@@ -66,6 +78,23 @@ export class TourScheduler extends LitElement {
|
|
|
66
78
|
this.availabilitiesGroupedByDay = await getAvailabilitiesGroupedByDay(
|
|
67
79
|
tourTypeMap[this.tourType]
|
|
68
80
|
);
|
|
81
|
+
this.waitingForAvailabilities = false;
|
|
82
|
+
|
|
83
|
+
// Show a tour type only if it is supported by the building and has
|
|
84
|
+
// time slots available.
|
|
85
|
+
const availabilitiesExistForTourType =
|
|
86
|
+
await getExistenceOfAvailabilitiesByTourType();
|
|
87
|
+
this.shouldShowTourType = {
|
|
88
|
+
[TourType.Guided]:
|
|
89
|
+
this.tourTypeOptions.map((o) => o.value).includes("WITH_AGENT") &&
|
|
90
|
+
availabilitiesExistForTourType[TourType.Guided],
|
|
91
|
+
[TourType.Self]:
|
|
92
|
+
this.tourTypeOptions.map((o) => o.value).includes("SELF_GUIDED") &&
|
|
93
|
+
availabilitiesExistForTourType[TourType.Self],
|
|
94
|
+
[TourType.Virtual]:
|
|
95
|
+
this.tourTypeOptions.map((o) => o.value).includes("VIRTUAL_SHOWING") &&
|
|
96
|
+
availabilitiesExistForTourType[TourType.Virtual],
|
|
97
|
+
};
|
|
69
98
|
};
|
|
70
99
|
|
|
71
100
|
protected willUpdate = async (
|
|
@@ -236,7 +265,7 @@ export class TourScheduler extends LitElement {
|
|
|
236
265
|
dateAndTime: (): boolean => !!this.selectedDate && !!this.selectedTime,
|
|
237
266
|
leadInfo: (): boolean => {
|
|
238
267
|
return (
|
|
239
|
-
!!this.
|
|
268
|
+
(!!this.firstNameInput?.value || !!this.lastNameInput?.value) &&
|
|
240
269
|
this.emailInput?.value.includes("@") &&
|
|
241
270
|
// TODO: deleting phone number doesn't cause validation to fail, at least on mobile
|
|
242
271
|
!!this.phoneNumber &&
|
|
@@ -273,9 +302,8 @@ export class TourScheduler extends LitElement {
|
|
|
273
302
|
email_address: this.email,
|
|
274
303
|
phone_number: `+1${this.phoneNumber.match(/\d/g)?.join("")}`, // e.g. +12125555555
|
|
275
304
|
building_id: this.buildingId,
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
last_name: this.nameInput.value.split(" ").slice(1).join(" "),
|
|
305
|
+
first_name: this.firstNameInput.value,
|
|
306
|
+
last_name: this.lastNameInput.value,
|
|
279
307
|
tour_type: tourTypeForSubmission[this.tourType],
|
|
280
308
|
tour_time: `${this.selectedTime.datetime}${this.selectedTime.offset}`, // e.g., "2022-06-27T09:00:00-07:00"
|
|
281
309
|
};
|
|
@@ -403,7 +431,7 @@ export class TourScheduler extends LitElement {
|
|
|
403
431
|
gap: 12px;
|
|
404
432
|
}
|
|
405
433
|
|
|
406
|
-
#yourInformationMenu
|
|
434
|
+
#yourInformationMenu input {
|
|
407
435
|
width: 305px;
|
|
408
436
|
height: 49px;
|
|
409
437
|
border: 1px solid #83818e;
|
|
@@ -415,7 +443,7 @@ export class TourScheduler extends LitElement {
|
|
|
415
443
|
color: #202020;
|
|
416
444
|
}
|
|
417
445
|
|
|
418
|
-
#yourInformationMenu
|
|
446
|
+
#yourInformationMenu input::placeholder {
|
|
419
447
|
color: #202020;
|
|
420
448
|
}
|
|
421
449
|
|
|
@@ -475,6 +503,15 @@ export class TourScheduler extends LitElement {
|
|
|
475
503
|
box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.5);
|
|
476
504
|
}
|
|
477
505
|
|
|
506
|
+
button#schedule:not(:disabled):hover {
|
|
507
|
+
opacity: 0.7;
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
button#schedule:not(:disabled):active {
|
|
511
|
+
box-shadow: none;
|
|
512
|
+
opacity: 1;
|
|
513
|
+
}
|
|
514
|
+
|
|
478
515
|
button#schedule:disabled {
|
|
479
516
|
background: #e7e7e7;
|
|
480
517
|
box-shadow: none;
|
|
@@ -489,6 +526,81 @@ export class TourScheduler extends LitElement {
|
|
|
489
526
|
font-size: 18px;
|
|
490
527
|
}
|
|
491
528
|
|
|
529
|
+
/* Loading styles: pulsing gray overlay on all the form elements */
|
|
530
|
+
|
|
531
|
+
@keyframes spin {
|
|
532
|
+
0% {
|
|
533
|
+
transform: none;
|
|
534
|
+
}
|
|
535
|
+
50% {
|
|
536
|
+
transform: rotateZ(180deg);
|
|
537
|
+
}
|
|
538
|
+
100% {
|
|
539
|
+
transform: rotateZ(360deg);
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
svg#loadingIcon {
|
|
544
|
+
animation: spin 2s infinite linear;
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
.tour-scheduler.loading #scheduleATour {
|
|
548
|
+
display: flex;
|
|
549
|
+
gap: 10px;
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
@keyframes loadingPulse {
|
|
553
|
+
0% {
|
|
554
|
+
background-color: #e7e7e7;
|
|
555
|
+
}
|
|
556
|
+
50% {
|
|
557
|
+
background-color: white;
|
|
558
|
+
}
|
|
559
|
+
100% {
|
|
560
|
+
background-color: #e7e7e7;
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
tour-type-option,
|
|
565
|
+
date-picker,
|
|
566
|
+
#yourInformationMenu .inputContainer {
|
|
567
|
+
position: relative;
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
.tour-scheduler.loading
|
|
571
|
+
:is(tour-type-option, date-picker, #yourInformationMenu
|
|
572
|
+
.inputContainer)::after {
|
|
573
|
+
content: "";
|
|
574
|
+
position: absolute;
|
|
575
|
+
top: 0;
|
|
576
|
+
left: 0;
|
|
577
|
+
height: 100%;
|
|
578
|
+
z-index: 1;
|
|
579
|
+
animation: loadingPulse 2s infinite;
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
.tour-scheduler.loading tour-type-option::after {
|
|
583
|
+
border-radius: 10px;
|
|
584
|
+
width: 200px;
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
.tour-scheduler.loading date-picker::after {
|
|
588
|
+
border-radius: 10px;
|
|
589
|
+
width: 205px;
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
.tour-scheduler.loading #yourInformationMenu .inputContainer::after {
|
|
593
|
+
width: 100%;
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
.tour-scheduler.loading #yourInformationMenu .inputContainer input {
|
|
597
|
+
visibility: hidden;
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
.tour-scheduler.loading time-picker {
|
|
601
|
+
display: none;
|
|
602
|
+
}
|
|
603
|
+
|
|
492
604
|
@media (max-width: 767px) {
|
|
493
605
|
/* TODO: separate styles into general, desktop-specific, and mobile-specific.
|
|
494
606
|
basically everything I have "unset" or "initial" on should become desktop-specific. the grid layout is only for desktop.
|
|
@@ -605,7 +717,7 @@ export class TourScheduler extends LitElement {
|
|
|
605
717
|
tourTypeMenu(): TemplateResult {
|
|
606
718
|
return html`<h2 id="tourType">Tour Type</h2>
|
|
607
719
|
<div id="tourTypeMenu">
|
|
608
|
-
${this.
|
|
720
|
+
${this.shouldShowTourType[TourType.Guided]
|
|
609
721
|
? html` <tour-type-option
|
|
610
722
|
heading="Guided tour"
|
|
611
723
|
subtitle="with an agent"
|
|
@@ -637,7 +749,7 @@ export class TourScheduler extends LitElement {
|
|
|
637
749
|
</svg>
|
|
638
750
|
</tour-type-option>`
|
|
639
751
|
: ""}
|
|
640
|
-
${this.
|
|
752
|
+
${this.shouldShowTourType[TourType.Self]
|
|
641
753
|
? html`<tour-type-option
|
|
642
754
|
heading="Take a tour"
|
|
643
755
|
subtitle="on your own"
|
|
@@ -669,7 +781,7 @@ export class TourScheduler extends LitElement {
|
|
|
669
781
|
</svg>
|
|
670
782
|
</tour-type-option>`
|
|
671
783
|
: ""}
|
|
672
|
-
${this.
|
|
784
|
+
${this.shouldShowTourType[TourType.Virtual]
|
|
673
785
|
? html`<tour-type-option
|
|
674
786
|
heading="Virtual tour"
|
|
675
787
|
subtitle="over video"
|
|
@@ -739,7 +851,8 @@ export class TourScheduler extends LitElement {
|
|
|
739
851
|
.map((date) => format(new Date(date.datetime), "h:mmaaa"))
|
|
740
852
|
.indexOf(e.target.selectedTime)
|
|
741
853
|
: null;
|
|
742
|
-
this.selectedTime =
|
|
854
|
+
this.selectedTime =
|
|
855
|
+
index !== null ? daysAvailabilities[index] : null;
|
|
743
856
|
}
|
|
744
857
|
}}
|
|
745
858
|
></time-picker>
|
|
@@ -807,38 +920,56 @@ export class TourScheduler extends LitElement {
|
|
|
807
920
|
userInfoAndLayoutMenu(): TemplateResult {
|
|
808
921
|
return html`<h2 id="yourInformation">Your information</h2>
|
|
809
922
|
<div id="yourInformationMenu">
|
|
810
|
-
<
|
|
811
|
-
|
|
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
|
-
|
|
923
|
+
<div class="inputContainer" id="firstName">
|
|
924
|
+
<input
|
|
925
|
+
type="text"
|
|
926
|
+
placeholder="First name"
|
|
927
|
+
name="firstName"
|
|
928
|
+
autocomplete="given-name"
|
|
929
|
+
@input=${() => this.requestUpdate()}
|
|
930
|
+
/>
|
|
931
|
+
</div>
|
|
932
|
+
<div class="inputContainer" id="lastName">
|
|
933
|
+
<input
|
|
934
|
+
type="text"
|
|
935
|
+
placeholder="Last name"
|
|
936
|
+
name="lastName"
|
|
937
|
+
autocomplete="family-name"
|
|
938
|
+
@input=${() => this.requestUpdate()}
|
|
939
|
+
/>
|
|
940
|
+
</div>
|
|
941
|
+
<div class="inputContainer" id="email">
|
|
942
|
+
<input
|
|
943
|
+
type="email"
|
|
944
|
+
inputmode="email"
|
|
945
|
+
placeholder="Email"
|
|
946
|
+
name="email"
|
|
947
|
+
autocomplete="email"
|
|
948
|
+
.value=${this.email}
|
|
949
|
+
@input=${this.onChangeEmail}
|
|
950
|
+
/>
|
|
951
|
+
</div>
|
|
952
|
+
<div class="inputContainer" id="phone">
|
|
953
|
+
<input
|
|
954
|
+
type="tel"
|
|
955
|
+
inputmode="tel"
|
|
956
|
+
placeholder="Phone"
|
|
957
|
+
name="phone"
|
|
958
|
+
autocomplete="tel-national"
|
|
959
|
+
maxlength="14"
|
|
960
|
+
.value=${this.phoneNumber}
|
|
961
|
+
@keydown=${this.handlePhoneKeydown}
|
|
962
|
+
@keyup=${this.handlePhoneKeyup}
|
|
963
|
+
@input=${(e: Event) => {
|
|
964
|
+
if (!e.target) {
|
|
965
|
+
return;
|
|
966
|
+
}
|
|
967
|
+
this.phoneNumber = formatToPhone(
|
|
968
|
+
(e.target as HTMLInputElement).value
|
|
969
|
+
);
|
|
970
|
+
}}
|
|
971
|
+
/>
|
|
972
|
+
</div>
|
|
842
973
|
</div>
|
|
843
974
|
<!--
|
|
844
975
|
Layout dropdown would go here, but has been removed pending backend support.
|
|
@@ -871,7 +1002,13 @@ export class TourScheduler extends LitElement {
|
|
|
871
1002
|
<p>
|
|
872
1003
|
Thank you!
|
|
873
1004
|
<br />
|
|
874
|
-
Your
|
|
1005
|
+
Your
|
|
1006
|
+
${{
|
|
1007
|
+
[TourType.Guided]: "guided",
|
|
1008
|
+
[TourType.Self]: "self-guided",
|
|
1009
|
+
[TourType.Virtual]: "virtual",
|
|
1010
|
+
}[this.tourType]}
|
|
1011
|
+
tour is scheduled for ${readableDateAndTime}.
|
|
875
1012
|
</p>
|
|
876
1013
|
<p>
|
|
877
1014
|
Look for an email confirmation along with instructions and directions.
|
|
@@ -881,11 +1018,35 @@ export class TourScheduler extends LitElement {
|
|
|
881
1018
|
`;
|
|
882
1019
|
}
|
|
883
1020
|
|
|
1021
|
+
loadingIcon(): TemplateResult {
|
|
1022
|
+
return html`<svg
|
|
1023
|
+
id="loadingIcon"
|
|
1024
|
+
width="21"
|
|
1025
|
+
height="21"
|
|
1026
|
+
viewBox="0 0 21 21"
|
|
1027
|
+
fill="none"
|
|
1028
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
1029
|
+
>
|
|
1030
|
+
<path
|
|
1031
|
+
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"
|
|
1032
|
+
fill="#1E1E1E"
|
|
1033
|
+
/>
|
|
1034
|
+
</svg>`;
|
|
1035
|
+
}
|
|
1036
|
+
|
|
884
1037
|
render(): TemplateResult {
|
|
885
1038
|
if (!isMobile()) {
|
|
886
1039
|
return html`
|
|
887
|
-
<div
|
|
888
|
-
|
|
1040
|
+
<div
|
|
1041
|
+
class="${classnames("tour-scheduler", {
|
|
1042
|
+
loading: this.waitingForAvailabilities,
|
|
1043
|
+
})}"
|
|
1044
|
+
>
|
|
1045
|
+
<h1 id="scheduleATour">
|
|
1046
|
+
${this.waitingForAvailabilities
|
|
1047
|
+
? html`${this.loadingIcon()} Searching availabilities...`
|
|
1048
|
+
: "Schedule a tour"}
|
|
1049
|
+
</h1>
|
|
889
1050
|
${this.closeButton()}
|
|
890
1051
|
${this.tourIsBooked
|
|
891
1052
|
? html`
|
|
@@ -910,9 +1071,17 @@ export class TourScheduler extends LitElement {
|
|
|
910
1071
|
} else {
|
|
911
1072
|
const currentPage = this.mobilePages[this.mobilePageIndex];
|
|
912
1073
|
return html`
|
|
913
|
-
<div
|
|
1074
|
+
<div
|
|
1075
|
+
class="${classnames("tour-scheduler", {
|
|
1076
|
+
loading: this.waitingForAvailabilities,
|
|
1077
|
+
})}"
|
|
1078
|
+
>
|
|
914
1079
|
<div id="topControls">
|
|
915
|
-
<h1 id="scheduleATour">
|
|
1080
|
+
<h1 id="scheduleATour">
|
|
1081
|
+
${this.waitingForAvailabilities
|
|
1082
|
+
? html`${this.loadingIcon()} Searching availabilities...`
|
|
1083
|
+
: "Schedule a tour"}
|
|
1084
|
+
</h1>
|
|
916
1085
|
${this.closeButton()}
|
|
917
1086
|
</div>
|
|
918
1087
|
${this.tourIsBooked
|
|
@@ -922,7 +1091,9 @@ export class TourScheduler extends LitElement {
|
|
|
922
1091
|
id="next"
|
|
923
1092
|
@click=${currentPage.nextButtonAction}
|
|
924
1093
|
?disabled=${(() => {
|
|
925
|
-
return
|
|
1094
|
+
return (
|
|
1095
|
+
!currentPage.validate() || this.waitingForAvailabilities
|
|
1096
|
+
);
|
|
926
1097
|
})()}
|
|
927
1098
|
>
|
|
928
1099
|
${currentPage.nextButtonText}
|
|
@@ -939,8 +1110,6 @@ export enum TourType {
|
|
|
939
1110
|
Virtual,
|
|
940
1111
|
}
|
|
941
1112
|
|
|
942
|
-
// TODO: we have three UI options and five TourAvailabilityResponseRankOrderedSupportedTourTypesEnum values
|
|
943
|
-
// how should they map?
|
|
944
1113
|
const tourTypeMap = {
|
|
945
1114
|
[TourType.Guided]:
|
|
946
1115
|
TourAvailabilityResponseRankOrderedSupportedTourTypesEnum.WithAgent,
|
package/src/getAvailabilities.ts
CHANGED
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
TourAvailabilityResponseRankOrderedSupportedTourTypesEnum,
|
|
11
11
|
} from "@meetelise/rest-sdk";
|
|
12
12
|
import groupBy from "lodash/groupBy";
|
|
13
|
+
import { TourType } from "./WebComponent/Scheduler/tour-scheduler";
|
|
13
14
|
|
|
14
15
|
const availabilitiesCache: {
|
|
15
16
|
buildingId?: number | null;
|
|
@@ -85,6 +86,39 @@ export interface DateWithTimeZoneOffset {
|
|
|
85
86
|
offset: string;
|
|
86
87
|
}
|
|
87
88
|
|
|
89
|
+
/**
|
|
90
|
+
* Returns an object that reveals whether each tour type supported by
|
|
91
|
+
* `tour-scheduler` has availabilities (time slots available for scheduling) in
|
|
92
|
+
* the time window of interest.
|
|
93
|
+
*
|
|
94
|
+
* Note that the existence of current availabilities is distinct from the
|
|
95
|
+
* question of whether the community supports the tour type at all. The first
|
|
96
|
+
* implies the second but not vice versa.
|
|
97
|
+
*/
|
|
98
|
+
export const getExistenceOfAvailabilitiesByTourType = async (): Promise<{
|
|
99
|
+
[TourType.Guided]: boolean;
|
|
100
|
+
[TourType.Self]: boolean;
|
|
101
|
+
[TourType.Virtual]: boolean;
|
|
102
|
+
}> => {
|
|
103
|
+
return {
|
|
104
|
+
[TourType.Guided]: !!(
|
|
105
|
+
await getAvailabilitiesForTourType(
|
|
106
|
+
TourAvailabilityResponseRankOrderedSupportedTourTypesEnum.WithAgent
|
|
107
|
+
)
|
|
108
|
+
)?.availableTourStartTimes?.length,
|
|
109
|
+
[TourType.Self]: !!(
|
|
110
|
+
await getAvailabilitiesForTourType(
|
|
111
|
+
TourAvailabilityResponseRankOrderedSupportedTourTypesEnum.SelfGuided
|
|
112
|
+
)
|
|
113
|
+
)?.availableTourStartTimes?.length,
|
|
114
|
+
[TourType.Virtual]: !!(
|
|
115
|
+
await getAvailabilitiesForTourType(
|
|
116
|
+
TourAvailabilityResponseRankOrderedSupportedTourTypesEnum.VirtualShowing
|
|
117
|
+
)
|
|
118
|
+
)?.availableTourStartTimes?.length,
|
|
119
|
+
};
|
|
120
|
+
};
|
|
121
|
+
|
|
88
122
|
export const getAvailabilitiesGroupedByDay = async (
|
|
89
123
|
tourType: TourAvailabilityResponseRankOrderedSupportedTourTypesEnum,
|
|
90
124
|
buildingId?: number
|