@meetelise/chat 1.13.8 → 1.13.11
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.
|
@@ -11,7 +11,7 @@ import "./time-picker.ts";
|
|
|
11
11
|
import "./me-select.ts";
|
|
12
12
|
import {
|
|
13
13
|
DateWithTimeZoneOffset,
|
|
14
|
-
|
|
14
|
+
getAvailabilitiesGroupedByDay,
|
|
15
15
|
} from "../../getAvailabilities";
|
|
16
16
|
import { TourAvailabilityResponseRankOrderedSupportedTourTypesEnum } from "@meetelise/rest-sdk";
|
|
17
17
|
import { format } from "date-fns";
|
|
@@ -53,8 +53,10 @@ export class TourScheduler extends LitElement {
|
|
|
53
53
|
@state()
|
|
54
54
|
private tourIsBooked = false;
|
|
55
55
|
|
|
56
|
-
@query("input#
|
|
57
|
-
|
|
56
|
+
@query("input#firstName")
|
|
57
|
+
firstNameInput!: HTMLInputElement;
|
|
58
|
+
@query("input#lastName")
|
|
59
|
+
lastNameInput!: HTMLInputElement;
|
|
58
60
|
@query("input#email")
|
|
59
61
|
emailInput!: HTMLInputElement;
|
|
60
62
|
@query("input#phone")
|
|
@@ -63,7 +65,7 @@ export class TourScheduler extends LitElement {
|
|
|
63
65
|
unitTypeSelect!: MESelect;
|
|
64
66
|
|
|
65
67
|
firstUpdated = async (): Promise<void> => {
|
|
66
|
-
this.availabilitiesGroupedByDay = await
|
|
68
|
+
this.availabilitiesGroupedByDay = await getAvailabilitiesGroupedByDay(
|
|
67
69
|
tourTypeMap[this.tourType]
|
|
68
70
|
);
|
|
69
71
|
};
|
|
@@ -74,8 +76,9 @@ export class TourScheduler extends LitElement {
|
|
|
74
76
|
| Map<PropertyKey, unknown>
|
|
75
77
|
): Promise<void> => {
|
|
76
78
|
if (_changedProperties.has("tourType")) {
|
|
77
|
-
this.availabilitiesGroupedByDay =
|
|
78
|
-
|
|
79
|
+
this.availabilitiesGroupedByDay = await getAvailabilitiesGroupedByDay(
|
|
80
|
+
tourTypeMap[this.tourType]
|
|
81
|
+
);
|
|
79
82
|
}
|
|
80
83
|
};
|
|
81
84
|
|
|
@@ -235,7 +238,7 @@ export class TourScheduler extends LitElement {
|
|
|
235
238
|
dateAndTime: (): boolean => !!this.selectedDate && !!this.selectedTime,
|
|
236
239
|
leadInfo: (): boolean => {
|
|
237
240
|
return (
|
|
238
|
-
!!this.
|
|
241
|
+
(!!this.firstNameInput?.value || !!this.lastNameInput?.value) &&
|
|
239
242
|
this.emailInput?.value.includes("@") &&
|
|
240
243
|
// TODO: deleting phone number doesn't cause validation to fail, at least on mobile
|
|
241
244
|
!!this.phoneNumber &&
|
|
@@ -272,9 +275,8 @@ export class TourScheduler extends LitElement {
|
|
|
272
275
|
email_address: this.email,
|
|
273
276
|
phone_number: `+1${this.phoneNumber.match(/\d/g)?.join("")}`, // e.g. +12125555555
|
|
274
277
|
building_id: this.buildingId,
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
last_name: this.nameInput.value.split(" ").slice(1).join(" "),
|
|
278
|
+
first_name: this.firstNameInput.value,
|
|
279
|
+
last_name: this.lastNameInput.value,
|
|
278
280
|
tour_type: tourTypeForSubmission[this.tourType],
|
|
279
281
|
tour_time: `${this.selectedTime.datetime}${this.selectedTime.offset}`, // e.g., "2022-06-27T09:00:00-07:00"
|
|
280
282
|
};
|
|
@@ -606,7 +608,6 @@ export class TourScheduler extends LitElement {
|
|
|
606
608
|
<div id="tourTypeMenu">
|
|
607
609
|
${this.tourTypeOptions.map((o) => o.value).includes("WITH_AGENT")
|
|
608
610
|
? html` <tour-type-option
|
|
609
|
-
tourtype="guided"
|
|
610
611
|
heading="Guided tour"
|
|
611
612
|
subtitle="with an agent"
|
|
612
613
|
@click="${() => {
|
|
@@ -639,7 +640,6 @@ export class TourScheduler extends LitElement {
|
|
|
639
640
|
: ""}
|
|
640
641
|
${this.tourTypeOptions.map((o) => o.value).includes("SELF_GUIDED")
|
|
641
642
|
? html`<tour-type-option
|
|
642
|
-
tourtype="self"
|
|
643
643
|
heading="Take a tour"
|
|
644
644
|
subtitle="on your own"
|
|
645
645
|
@click="${() => {
|
|
@@ -670,9 +670,8 @@ export class TourScheduler extends LitElement {
|
|
|
670
670
|
</svg>
|
|
671
671
|
</tour-type-option>`
|
|
672
672
|
: ""}
|
|
673
|
-
${this.tourTypeOptions.map((o) => o.value).includes("
|
|
673
|
+
${this.tourTypeOptions.map((o) => o.value).includes("VIRTUAL_SHOWING")
|
|
674
674
|
? html`<tour-type-option
|
|
675
|
-
tourtype="guided"
|
|
676
675
|
heading="Virtual tour"
|
|
677
676
|
subtitle="over video"
|
|
678
677
|
@click="${() => {
|
|
@@ -741,7 +740,8 @@ export class TourScheduler extends LitElement {
|
|
|
741
740
|
.map((date) => format(new Date(date.datetime), "h:mmaaa"))
|
|
742
741
|
.indexOf(e.target.selectedTime)
|
|
743
742
|
: null;
|
|
744
|
-
this.selectedTime =
|
|
743
|
+
this.selectedTime =
|
|
744
|
+
index !== null ? daysAvailabilities[index] : null;
|
|
745
745
|
}
|
|
746
746
|
}}
|
|
747
747
|
></time-picker>
|
|
@@ -811,8 +811,14 @@ export class TourScheduler extends LitElement {
|
|
|
811
811
|
<div id="yourInformationMenu">
|
|
812
812
|
<input
|
|
813
813
|
type="text"
|
|
814
|
-
placeholder="
|
|
815
|
-
id="
|
|
814
|
+
placeholder="First name"
|
|
815
|
+
id="firstName"
|
|
816
|
+
@input=${() => this.requestUpdate()}
|
|
817
|
+
/>
|
|
818
|
+
<input
|
|
819
|
+
type="text"
|
|
820
|
+
placeholder="Last name"
|
|
821
|
+
id="lastName"
|
|
816
822
|
@input=${() => this.requestUpdate()}
|
|
817
823
|
/>
|
|
818
824
|
<input
|
|
@@ -842,25 +848,11 @@ export class TourScheduler extends LitElement {
|
|
|
842
848
|
}}
|
|
843
849
|
/>
|
|
844
850
|
</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
|
-
: ""} `;
|
|
851
|
+
<!--
|
|
852
|
+
Layout dropdown would go here, but has been removed pending backend support.
|
|
853
|
+
Here is the code to add it back:
|
|
854
|
+
https://github.com/MeetElise/chat-ui/blob/e17aca8b39a0eed9430f22c182f2ebcdfb796417/src/WebComponent/Scheduler/tour-scheduler.ts#L846-L863
|
|
855
|
+
--> `;
|
|
864
856
|
}
|
|
865
857
|
|
|
866
858
|
confirmationMessage(): TemplateResult {
|
|
@@ -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`
|
|
@@ -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;
|
package/src/getAvailabilities.ts
CHANGED
|
@@ -12,29 +12,46 @@ import {
|
|
|
12
12
|
import groupBy from "lodash/groupBy";
|
|
13
13
|
|
|
14
14
|
const availabilitiesCache: {
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
buildingId?: number | null;
|
|
16
|
+
availabilities: { [buildingId: number]: TourAvailabilityResponse };
|
|
17
|
+
} = { buildingId: null, availabilities: {} };
|
|
17
18
|
|
|
19
|
+
/**
|
|
20
|
+
* Returns the raw availabilities.
|
|
21
|
+
*
|
|
22
|
+
* If no `buildingId` is provided, it will use a cached buildingId from the previous call.
|
|
23
|
+
* If there is none cached, it will throw an error.
|
|
24
|
+
*/
|
|
18
25
|
export const getRawAvailabilities = async (
|
|
19
|
-
buildingId
|
|
26
|
+
buildingId?: number
|
|
20
27
|
): Promise<TourAvailabilityResponse> => {
|
|
21
|
-
if (
|
|
22
|
-
|
|
28
|
+
if (buildingId) {
|
|
29
|
+
availabilitiesCache.buildingId = buildingId;
|
|
30
|
+
}
|
|
31
|
+
const buildingIdToUse = availabilitiesCache.buildingId;
|
|
32
|
+
if (!buildingIdToUse) {
|
|
33
|
+
throw new Error(
|
|
34
|
+
"No buildingId was provided to getRawAvailabilities and there is no buildingId cached."
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
const availabilities = availabilitiesCache.availabilities;
|
|
38
|
+
if (availabilities[buildingIdToUse]) {
|
|
39
|
+
return availabilities[buildingIdToUse];
|
|
23
40
|
}
|
|
24
41
|
const startTime = startOfToday();
|
|
25
42
|
const endTime = formatISO(endOfDay(addDays(startTime, 30)));
|
|
26
|
-
const url = `https://app.meetelise.com/api/pub/v1/buildings/${
|
|
43
|
+
const url = `https://app.meetelise.com/api/pub/v1/buildings/${buildingIdToUse}/tour/availabilities?startTime=${formatISO(
|
|
27
44
|
startTime
|
|
28
45
|
)}&endTime=${endTime}`;
|
|
29
46
|
const result = await axios.get<TourAvailabilityResponse>(url);
|
|
30
|
-
availabilitiesCache[
|
|
47
|
+
availabilitiesCache.availabilities[buildingIdToUse] = result.data;
|
|
31
48
|
// The endpoint INCORRECTLY states that these are returned as dates. They are, in fact, strings.
|
|
32
49
|
return result.data;
|
|
33
50
|
};
|
|
34
51
|
|
|
35
52
|
export const getAvailabilitiesForTourType = async (
|
|
36
|
-
|
|
37
|
-
|
|
53
|
+
tourType: TourAvailabilityResponseRankOrderedSupportedTourTypesEnum,
|
|
54
|
+
buildingId?: number
|
|
38
55
|
): Promise<{
|
|
39
56
|
/**
|
|
40
57
|
*
|
|
@@ -69,12 +86,12 @@ export interface DateWithTimeZoneOffset {
|
|
|
69
86
|
}
|
|
70
87
|
|
|
71
88
|
export const getAvailabilitiesGroupedByDay = async (
|
|
72
|
-
|
|
73
|
-
|
|
89
|
+
tourType: TourAvailabilityResponseRankOrderedSupportedTourTypesEnum,
|
|
90
|
+
buildingId?: number
|
|
74
91
|
): Promise<{ [day: string]: DateWithTimeZoneOffset[] }> => {
|
|
75
92
|
const availabilitiesForTourTypeRaw = await getAvailabilitiesForTourType(
|
|
76
|
-
|
|
77
|
-
|
|
93
|
+
tourType,
|
|
94
|
+
buildingId
|
|
78
95
|
);
|
|
79
96
|
if (!availabilitiesForTourTypeRaw) {
|
|
80
97
|
return {};
|
|
@@ -97,16 +114,6 @@ export const getAvailabilitiesGroupedByDay = async (
|
|
|
97
114
|
);
|
|
98
115
|
};
|
|
99
116
|
|
|
100
|
-
// TODO: if cache is empty, observe it and wait for it to be filled in.
|
|
101
|
-
// TODO: alternative to this: cache the building id when getRawAvailabilities is called. Then I can call the normal methods.
|
|
102
|
-
export const getAvailabilitiesGroupedByDayCached = async (
|
|
103
|
-
tourType: TourAvailabilityResponseRankOrderedSupportedTourTypesEnum
|
|
104
|
-
): Promise<{ [day: string]: DateWithTimeZoneOffset[] }> =>
|
|
105
|
-
getAvailabilitiesGroupedByDay(
|
|
106
|
-
Object.keys(availabilitiesCache).map(Number)[0],
|
|
107
|
-
tourType
|
|
108
|
-
);
|
|
109
|
-
|
|
110
117
|
/**
|
|
111
118
|
* Takes an ISO 8601 date string with time zone offset and returns
|
|
112
119
|
* an object of our custom type DateWithTimeZoneOffset.
|