@meetelise/chat 1.21.0 → 1.21.2
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/.github/pull_request_template.md +61 -0
- package/.idea/codeStyles/Project.xml +57 -0
- package/.idea/codeStyles/codeStyleConfig.xml +5 -0
- package/.idea/inspectionProfiles/Project_Default.xml +6 -0
- package/.idea/vcs.xml +6 -0
- package/.idea/workspace.xml +67 -0
- package/README.md +29 -14
- package/declarations.d.ts +12 -0
- package/package.json +5 -1
- package/public/demo/index.html +62 -4
- package/public/demo/secret.html +63 -0
- package/public/dist/index.js +3184 -1105
- package/public/dist/index.js.LICENSE.txt +19 -9
- package/public/index.html +6 -4
- package/src/MEChat.ts +207 -52
- package/src/MyPubnub.ts +657 -0
- package/src/WebComponent/LeadSourceClient.ts +300 -0
- package/src/WebComponent/Scheduler/date-picker.ts +1 -1
- package/src/WebComponent/Scheduler/time-picker.ts +86 -76
- package/src/WebComponent/Scheduler/tour-scheduler.ts +694 -764
- package/src/WebComponent/Scheduler/tour-type-option.ts +17 -3
- package/src/WebComponent/Scheduler/tourSchedulerStyles.ts +418 -0
- package/src/WebComponent/actions/InputStyles.ts +32 -10
- package/src/WebComponent/actions/action-confirm-button.ts +16 -11
- package/src/WebComponent/actions/call-us-window.ts +341 -58
- package/src/WebComponent/actions/details-window.ts +30 -16
- package/src/WebComponent/actions/email-us-window.ts +89 -58
- package/src/WebComponent/actions/formatPhoneNumber.ts +15 -1
- package/src/WebComponent/actions/minimize-expand-button.ts +92 -0
- package/src/WebComponent/health-chat.ts +267 -0
- package/src/WebComponent/healthcare/healthcare-launcher-styles.ts +34 -0
- package/src/WebComponent/healthcare/healthcare-launcher.ts +100 -0
- package/src/WebComponent/healthchat-styles.ts +119 -0
- package/src/WebComponent/index.ts +1 -1
- package/src/WebComponent/launcher/Launcher.ts +919 -0
- package/src/WebComponent/{launcherStyles.ts → launcher/launcherStyles.ts} +172 -29
- package/src/WebComponent/launcher/mobile-launcher.ts +127 -0
- package/src/WebComponent/launcher/typeEmojiStyles.ts +161 -0
- package/src/WebComponent/launcher/typeMiniStyles.ts +60 -0
- package/src/WebComponent/launcher/typeMobileStyles.ts +50 -0
- package/src/WebComponent/leasing-chat-styles.ts +114 -0
- package/src/WebComponent/me-chat.ts +964 -351
- package/src/WebComponent/me-select.ts +48 -21
- package/src/WebComponent/mini-loader.ts +28 -0
- package/src/WebComponent/pubnub-chat-styles.ts +192 -0
- package/src/WebComponent/pubnub-chat.ts +707 -0
- package/src/WebComponent/pubnub-media.ts +208 -0
- package/src/WebComponent/pubnub-message-styles.ts +54 -0
- package/src/WebComponent/pubnub-message.ts +421 -0
- package/src/analytics.ts +114 -14
- package/src/assetUrls.ts +2 -0
- package/src/disclaimers.ts +56 -0
- package/src/fetchBuildingABTestType.ts +4 -0
- package/src/fetchBuildingInfo.ts +25 -17
- package/src/fetchFeatureFlag.ts +147 -0
- package/src/fetchLeadSources.ts +67 -1
- package/src/fetchPhoneNumberFromSource.ts +31 -0
- package/src/fetchWebchatPreferences.ts +55 -0
- package/src/getAvailabilities.ts +7 -3
- package/src/getBuildingPhoneNumber.ts +26 -0
- package/src/getShouldAllowScheduling.ts +16 -0
- package/src/getTimezoneString.ts +39 -0
- package/src/gtm.ts +17 -0
- package/src/handleChatId.ts +101 -0
- package/src/insertDNIIntoWebsite.ts +136 -0
- package/src/insertLeadSourceIntoSchedulerLinks.ts +50 -0
- package/src/postLeadSources.ts +39 -35
- package/src/svgIcons.ts +62 -53
- package/src/themes.ts +47 -121
- package/src/utils.ts +88 -1
- package/src/WebComponent/Launcher.ts +0 -559
- package/src/WebComponent/actions/text-us-window.ts +0 -279
- package/src/chatID.ts +0 -64
- package/src/createConversation.ts +0 -57
- package/src/fetchCurrentParsedLeadSource.ts +0 -24
- package/src/getRegisteredPhoneNumbers.ts +0 -56
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { html, LitElement, PropertyValueMap, TemplateResult } from "lit";
|
|
2
2
|
import { customElement, property, query, state } from "lit/decorators.js";
|
|
3
3
|
import {
|
|
4
4
|
shortcutKeyIsPressed,
|
|
5
|
-
|
|
5
|
+
formatToPhoneInput,
|
|
6
6
|
isPrintableCharacter,
|
|
7
7
|
} from "../actions/formatPhoneNumber";
|
|
8
8
|
import "./tour-type-option.ts";
|
|
@@ -19,39 +19,28 @@ import { format } from "date-fns";
|
|
|
19
19
|
import { DatePicker } from "./date-picker";
|
|
20
20
|
import { MESelect } from "../me-select";
|
|
21
21
|
import { TimePicker } from "./time-picker";
|
|
22
|
-
import { LabeledOption
|
|
23
|
-
import { isMobile } from "../../utils";
|
|
24
|
-
import axios from "axios";
|
|
25
|
-
import
|
|
22
|
+
import { LabeledOption } from "../../fetchBuildingInfo";
|
|
23
|
+
import { isMobile, isValidPhoneNumber } from "../../utils";
|
|
24
|
+
import axios, { AxiosError } from "axios";
|
|
25
|
+
import mapValues from "lodash/mapValues";
|
|
26
26
|
import classnames from "classnames";
|
|
27
27
|
import parseISO from "date-fns/parseISO";
|
|
28
28
|
import compareAsc from "date-fns/compareAsc";
|
|
29
29
|
import { InputStyles } from "../actions/InputStyles";
|
|
30
30
|
import { classMap } from "lit/directives/class-map.js";
|
|
31
|
-
import
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
"6br": "6 bedroom",
|
|
42
|
-
"7br": "7 bedroom",
|
|
43
|
-
"8br": "8 bedroom",
|
|
44
|
-
"9br": "9 bedroom",
|
|
45
|
-
"10br": "10 bedroom",
|
|
46
|
-
}[layout];
|
|
47
|
-
};
|
|
31
|
+
import { FeatureFlagsShowDropdown } from "../../fetchFeatureFlag";
|
|
32
|
+
import { pushGtmEvent } from "../../gtm";
|
|
33
|
+
import disclaimer from "../../disclaimers";
|
|
34
|
+
import { tourSchedulerStyles } from "./tourSchedulerStyles";
|
|
35
|
+
import { defaultBrandColor, defaultBackgroundColor } from "../../themes";
|
|
36
|
+
import { LogType, sendLoggingEvent } from "../../analytics";
|
|
37
|
+
import LeadSourceClient, {
|
|
38
|
+
getDefaultLeadSourceAttribution,
|
|
39
|
+
} from "../LeadSourceClient";
|
|
40
|
+
import { getShouldAllowScheduling } from "../../getShouldAllowScheduling";
|
|
48
41
|
|
|
49
42
|
@customElement("tour-scheduler")
|
|
50
43
|
export class TourScheduler extends LitElement {
|
|
51
|
-
@property({ attribute: false })
|
|
52
|
-
layoutOptions: string[] = [];
|
|
53
|
-
@property({ attribute: false })
|
|
54
|
-
unitOptions: UnitV2[] = [];
|
|
55
44
|
@property({ attribute: false })
|
|
56
45
|
tourTypeOptions: LabeledOption[] = [];
|
|
57
46
|
@property({ attribute: true })
|
|
@@ -68,6 +57,15 @@ export class TourScheduler extends LitElement {
|
|
|
68
57
|
virtualToursLink = "";
|
|
69
58
|
@property({ attribute: true })
|
|
70
59
|
orgSlug = "";
|
|
60
|
+
@property({ attribute: true })
|
|
61
|
+
hasDynamicSchedulingEnabled = false;
|
|
62
|
+
|
|
63
|
+
@property({ attribute: true })
|
|
64
|
+
private leadSourceClient: LeadSourceClient | null = null;
|
|
65
|
+
|
|
66
|
+
@property({ attribute: true })
|
|
67
|
+
buildingName = "";
|
|
68
|
+
|
|
71
69
|
onCloseClicked?: (e: MouseEvent) => void;
|
|
72
70
|
|
|
73
71
|
@state()
|
|
@@ -98,12 +96,32 @@ export class TourScheduler extends LitElement {
|
|
|
98
96
|
private isSubmitting = false;
|
|
99
97
|
@state()
|
|
100
98
|
private tourIsBooked = false;
|
|
99
|
+
@state()
|
|
100
|
+
private shouldAllowScheduling = false;
|
|
101
|
+
@state()
|
|
102
|
+
private shouldAllowScheduleLoading = true;
|
|
103
|
+
@state()
|
|
104
|
+
private promptForReschedule = false;
|
|
105
|
+
@state()
|
|
106
|
+
private canceledReschedule = false;
|
|
101
107
|
|
|
102
108
|
@property({ attribute: false })
|
|
103
109
|
leadSources: string[] = [];
|
|
104
110
|
|
|
105
111
|
@property({ attribute: true })
|
|
106
|
-
currentLeadSource = ""; // the default lead source based on referrer and query params
|
|
112
|
+
currentLeadSource = ""; // the default lead source based on referrer and query params.
|
|
113
|
+
|
|
114
|
+
@property({ attribute: true })
|
|
115
|
+
featureFlagShowDropdown = "";
|
|
116
|
+
|
|
117
|
+
@property({ attribute: true })
|
|
118
|
+
compactDesign = false;
|
|
119
|
+
|
|
120
|
+
@property({ attribute: true })
|
|
121
|
+
brandColor: string = defaultBrandColor;
|
|
122
|
+
|
|
123
|
+
@property({ attribute: true })
|
|
124
|
+
backgroundColor: string = defaultBackgroundColor;
|
|
107
125
|
|
|
108
126
|
@query(".nameContainer#firstName input")
|
|
109
127
|
firstNameInput!: HTMLInputElement;
|
|
@@ -113,35 +131,118 @@ export class TourScheduler extends LitElement {
|
|
|
113
131
|
emailInput!: HTMLInputElement;
|
|
114
132
|
@query(".inputContainer#phone input")
|
|
115
133
|
phoneInput!: HTMLInputElement;
|
|
116
|
-
@query("me-select#unitType")
|
|
117
|
-
unitTypeSelect!: MESelect;
|
|
118
|
-
@query("me-select#layoutType")
|
|
119
|
-
layoutTypeSelect!: MESelect;
|
|
120
134
|
@query("me-select#leadSource")
|
|
121
135
|
selectedLeadSource!: MESelect;
|
|
122
136
|
|
|
137
|
+
@state()
|
|
138
|
+
firstNameInputValue = "";
|
|
139
|
+
@state()
|
|
140
|
+
lastNameInputValue = "";
|
|
141
|
+
@state()
|
|
142
|
+
leadSourceInputValue = "";
|
|
143
|
+
|
|
144
|
+
@state()
|
|
145
|
+
errorGettingAvailabilities = false;
|
|
146
|
+
|
|
123
147
|
firstUpdated = async (): Promise<void> => {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
148
|
+
try {
|
|
149
|
+
const [allowScheduling, availabilitiesExistForTourType] =
|
|
150
|
+
await Promise.all([
|
|
151
|
+
getShouldAllowScheduling(
|
|
152
|
+
this.buildingId,
|
|
153
|
+
this.hasDynamicSchedulingEnabled
|
|
154
|
+
),
|
|
155
|
+
getExistenceOfAvailabilitiesByTourType(),
|
|
156
|
+
]);
|
|
157
|
+
|
|
158
|
+
this.shouldAllowScheduling = allowScheduling;
|
|
159
|
+
this.shouldAllowScheduleLoading = false;
|
|
160
|
+
|
|
161
|
+
sendLoggingEvent({
|
|
162
|
+
logTitle: "AVAILABILITIES_EXIST_FOR_TOUR_TYPE",
|
|
163
|
+
logData: availabilitiesExistForTourType,
|
|
164
|
+
logType: LogType.info,
|
|
165
|
+
buildingSlug: this.buildingSlug,
|
|
166
|
+
orgSlug: this.orgSlug,
|
|
167
|
+
});
|
|
168
|
+
const allValuesAreFalse = Object.values(
|
|
169
|
+
availabilitiesExistForTourType
|
|
170
|
+
).every((v) => v === false);
|
|
171
|
+
const hasNoTourLinks =
|
|
172
|
+
!this.sgtUrl && !this.escortedToursLink && !this.virtualToursLink;
|
|
173
|
+
if (allValuesAreFalse && hasNoTourLinks) {
|
|
174
|
+
this.errorGettingAvailabilities = true;
|
|
175
|
+
this.waitingForAvailabilities = false;
|
|
176
|
+
sendLoggingEvent({
|
|
177
|
+
logTitle: "NO_AVAILABILITIES_EXIST",
|
|
178
|
+
logData: null,
|
|
179
|
+
logType: LogType.warn,
|
|
180
|
+
buildingSlug: this.buildingSlug,
|
|
181
|
+
orgSlug: this.orgSlug,
|
|
182
|
+
});
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
this.shouldShowTourType = {
|
|
186
|
+
[TourType.Guided]:
|
|
187
|
+
this.tourTypeOptions.map((o) => o.value).includes("WITH_AGENT") &&
|
|
188
|
+
(availabilitiesExistForTourType[TourType.Guided] ||
|
|
189
|
+
!!this.escortedToursLink),
|
|
190
|
+
[TourType.Self]:
|
|
191
|
+
this.tourTypeOptions.map((o) => o.value).includes("SELF_GUIDED") &&
|
|
192
|
+
(availabilitiesExistForTourType[TourType.Self] || !!this.sgtUrl),
|
|
193
|
+
[TourType.Virtual]:
|
|
194
|
+
this.tourTypeOptions
|
|
195
|
+
.map((o) => o.value)
|
|
196
|
+
.includes("VIRTUAL_SHOWING") &&
|
|
197
|
+
(availabilitiesExistForTourType[TourType.Virtual] ||
|
|
198
|
+
!!this.virtualToursLink),
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
// if there is only a single option for tour type, have that be the default
|
|
202
|
+
const hasOneShowTourType =
|
|
203
|
+
Object.values(this.shouldShowTourType).reduce((acc, cur) => {
|
|
204
|
+
if (cur === true) {
|
|
205
|
+
return acc + 1;
|
|
206
|
+
} else {
|
|
207
|
+
return acc;
|
|
208
|
+
}
|
|
209
|
+
}, 0) === 1;
|
|
210
|
+
|
|
211
|
+
if (hasOneShowTourType) {
|
|
212
|
+
this.tourType = Object.keys(this.shouldShowTourType).find(
|
|
213
|
+
(key) => this.shouldShowTourType[key as TourType]
|
|
214
|
+
) as TourType;
|
|
215
|
+
} else {
|
|
216
|
+
// if we have multiple tour types, then check if there is a default that the client wants selected
|
|
217
|
+
// HACK: FOR DEMO, FOR https://www.sofioceanhills.com/ -
|
|
218
|
+
// THIS SHOULD BE ADDED TO WEBCHAT CONFIGURATION
|
|
219
|
+
// if (
|
|
220
|
+
// this.buildingSlug === "1ac49f90-6150-11ed-b327-1b3f05e7b9db" &&
|
|
221
|
+
// this.shouldShowTourType[TourType.Self]
|
|
222
|
+
// ) {
|
|
223
|
+
// this.tourType = TourType.Self;
|
|
224
|
+
// }
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
if (this.tourType === null) {
|
|
228
|
+
this.waitingForAvailabilities = false;
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
this.availabilitiesGroupedByDay = await getAvailabilitiesGroupedByDay(
|
|
232
|
+
tourTypeMap[this.tourType]
|
|
233
|
+
);
|
|
138
234
|
this.waitingForAvailabilities = false;
|
|
139
|
-
|
|
235
|
+
} catch (e) {
|
|
236
|
+
this.errorGettingAvailabilities = true;
|
|
237
|
+
this.waitingForAvailabilities = false;
|
|
238
|
+
sendLoggingEvent({
|
|
239
|
+
logTitle: "ERROR_LOADING_AVAILABILITIES",
|
|
240
|
+
logData: { error: e },
|
|
241
|
+
logType: LogType.error,
|
|
242
|
+
buildingSlug: this.buildingSlug,
|
|
243
|
+
orgSlug: this.orgSlug,
|
|
244
|
+
});
|
|
140
245
|
}
|
|
141
|
-
this.availabilitiesGroupedByDay = await getAvailabilitiesGroupedByDay(
|
|
142
|
-
tourTypeMap[this.tourType]
|
|
143
|
-
);
|
|
144
|
-
this.waitingForAvailabilities = false;
|
|
145
246
|
};
|
|
146
247
|
|
|
147
248
|
protected willUpdate = async (
|
|
@@ -176,7 +277,7 @@ export class TourScheduler extends LitElement {
|
|
|
176
277
|
this.phoneNumber.slice(0, cursorPosition) +
|
|
177
278
|
e.key +
|
|
178
279
|
this.phoneNumber.slice(cursorPosition);
|
|
179
|
-
this.phoneNumber =
|
|
280
|
+
this.phoneNumber = formatToPhoneInput(updated.replace(/\D/g, ""));
|
|
180
281
|
this.phoneInput.value = this.phoneNumber;
|
|
181
282
|
} else if (e.key === "Backspace") {
|
|
182
283
|
/*
|
|
@@ -212,7 +313,7 @@ export class TourScheduler extends LitElement {
|
|
|
212
313
|
0,
|
|
213
314
|
-1
|
|
214
315
|
)}${digitsAfterCursor}`;
|
|
215
|
-
this.phoneNumber =
|
|
316
|
+
this.phoneNumber = formatToPhoneInput(updatedDigits);
|
|
216
317
|
this.phoneInput.value = this.phoneNumber;
|
|
217
318
|
const numOfCharactersDeleted =
|
|
218
319
|
originalCharacterCount - this.phoneNumber.length;
|
|
@@ -283,7 +384,7 @@ export class TourScheduler extends LitElement {
|
|
|
283
384
|
const numbersAfterCursor = cursorPosition
|
|
284
385
|
? this.phoneInput.value.slice(cursorPosition).replace(/\D/g, "")
|
|
285
386
|
: "";
|
|
286
|
-
this.phoneNumber =
|
|
387
|
+
this.phoneNumber = formatToPhoneInput(this.phoneInput.value);
|
|
287
388
|
|
|
288
389
|
// EXAMPLES: (123)| 4 numbersAfterCursor will be '4'.
|
|
289
390
|
let cursorNegativeIndex = 0;
|
|
@@ -316,19 +417,17 @@ export class TourScheduler extends LitElement {
|
|
|
316
417
|
this.emailInput?.value.includes("@") &&
|
|
317
418
|
// TODO: deleting phone number doesn't cause validation to fail, at least on mobile
|
|
318
419
|
!!this.phoneNumber &&
|
|
319
|
-
this.phoneNumber.length === 14
|
|
420
|
+
this.phoneNumber.length === 14 &&
|
|
421
|
+
isValidPhoneNumber(this.phoneNumber)
|
|
320
422
|
);
|
|
321
423
|
},
|
|
322
|
-
leadSource: (): boolean =>
|
|
323
|
-
this.leadSources.length > 0 ? !!this.selectedLeadSource?.value : true,
|
|
324
424
|
};
|
|
325
425
|
|
|
326
426
|
formIsValidForSubmission = (): boolean => {
|
|
327
427
|
const isValid =
|
|
328
428
|
this.validators.tourType() &&
|
|
329
429
|
this.validators.dateAndTime() &&
|
|
330
|
-
this.validators.leadInfo()
|
|
331
|
-
this.validators.leadSource();
|
|
430
|
+
this.validators.leadInfo();
|
|
332
431
|
return isValid;
|
|
333
432
|
};
|
|
334
433
|
|
|
@@ -347,36 +446,62 @@ export class TourScheduler extends LitElement {
|
|
|
347
446
|
};
|
|
348
447
|
|
|
349
448
|
submit = async (): Promise<void> => {
|
|
350
|
-
if (!this.selectedDate || !this.selectedTime || this.tourType === null)
|
|
449
|
+
if (!this.selectedDate || !this.selectedTime || this.tourType === null) {
|
|
351
450
|
return;
|
|
451
|
+
}
|
|
352
452
|
const queryParams = new URLSearchParams(window.location.search);
|
|
453
|
+
|
|
454
|
+
const parsedLeadSource =
|
|
455
|
+
this.selectedLeadSource && this.selectedLeadSource.value
|
|
456
|
+
? this.selectedLeadSource.value
|
|
457
|
+
: this.leadSourceInputValue ?? this.currentLeadSource;
|
|
458
|
+
|
|
459
|
+
const leadSources = [
|
|
460
|
+
...new Set(
|
|
461
|
+
parsedLeadSource
|
|
462
|
+
? [parsedLeadSource, "property-website"]
|
|
463
|
+
: ["property-website"]
|
|
464
|
+
),
|
|
465
|
+
];
|
|
466
|
+
if (this.firstNameInput) {
|
|
467
|
+
this.firstNameInputValue = this.firstNameInput.value;
|
|
468
|
+
}
|
|
469
|
+
if (this.lastNameInput) {
|
|
470
|
+
this.lastNameInputValue = this.lastNameInput.value;
|
|
471
|
+
}
|
|
472
|
+
this.leadSourceInputValue = parsedLeadSource;
|
|
473
|
+
pushGtmEvent("scheduleTourSubmitted", {
|
|
474
|
+
email: this.email,
|
|
475
|
+
phone: `+1${this.phoneNumber.match(/\d/g)?.join("")}`,
|
|
476
|
+
firstName: this.firstNameInput?.value ?? this.firstNameInputValue,
|
|
477
|
+
lastName: this.lastNameInput?.value ?? this.lastNameInputValue,
|
|
478
|
+
tourType: tourTypeForSubmission[this.tourType],
|
|
479
|
+
tourTime: `${this.selectedTime.datetime}${this.selectedTime.offset}`,
|
|
480
|
+
originatingSource:
|
|
481
|
+
leadSources.find((i) => i !== "property-website") || null,
|
|
482
|
+
});
|
|
353
483
|
const data = {
|
|
354
484
|
referrer: document.referrer,
|
|
355
485
|
email_address: this.email,
|
|
356
486
|
phone_number: `+1${this.phoneNumber.match(/\d/g)?.join("")}`, // e.g. +12125555555
|
|
357
487
|
building_id: this.buildingId,
|
|
358
|
-
first_name: this.firstNameInput.
|
|
359
|
-
last_name: this.lastNameInput.
|
|
488
|
+
first_name: this.firstNameInput?.value ?? this.firstNameInputValue,
|
|
489
|
+
last_name: this.lastNameInput?.value ?? this.lastNameInputValue,
|
|
360
490
|
tour_type: tourTypeForSubmission[this.tourType],
|
|
361
491
|
tour_time: `${this.selectedTime.datetime}${this.selectedTime.offset}`, // e.g., "2022-06-27T09:00:00-07:00"
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
this.selectedLeadSource && this.selectedLeadSource.value
|
|
371
|
-
? [this.selectedLeadSource.value, "property-website"]
|
|
372
|
-
: ["property-website"],
|
|
373
|
-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
374
|
-
// @ts-ignore
|
|
492
|
+
cancel_existing_tours: this.promptForReschedule,
|
|
493
|
+
lead_sources: [
|
|
494
|
+
...new Set(
|
|
495
|
+
parsedLeadSource
|
|
496
|
+
? [parsedLeadSource, getDefaultLeadSourceAttribution(this.orgSlug)]
|
|
497
|
+
: [getDefaultLeadSourceAttribution(this.orgSlug)]
|
|
498
|
+
),
|
|
499
|
+
],
|
|
375
500
|
query_params: Object.fromEntries(queryParams.entries()),
|
|
501
|
+
conversation_tracking_id: this.leadSourceClient?.chatId,
|
|
376
502
|
};
|
|
377
|
-
const url = `https://app.meetelise.com/platformApi/state/create/scheduleMe`;
|
|
503
|
+
const url = `https://app.meetelise.com/platformApi/state/create/v2/scheduleMe`;
|
|
378
504
|
this.isSubmitting = true;
|
|
379
|
-
|
|
380
505
|
try {
|
|
381
506
|
await axios.post(url, data, {
|
|
382
507
|
headers: {
|
|
@@ -385,496 +510,134 @@ export class TourScheduler extends LitElement {
|
|
|
385
510
|
["org-slug"]: this.orgSlug,
|
|
386
511
|
},
|
|
387
512
|
});
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
buildingSlug: this.buildingSlug,
|
|
393
|
-
selectedLeadSource:
|
|
394
|
-
this.selectedLeadSource && this.selectedLeadSource.value
|
|
395
|
-
? this.selectedLeadSource.value
|
|
396
|
-
: "",
|
|
513
|
+
|
|
514
|
+
this.leadSourceClient?.checkAndHandleForLogLeadSource({
|
|
515
|
+
webchatAction: "tour-scheduler",
|
|
516
|
+
stateId: null,
|
|
397
517
|
});
|
|
398
518
|
this.isSubmitting = false;
|
|
399
519
|
this.tourIsBooked = true;
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
const message =
|
|
520
|
+
} catch (e: unknown) {
|
|
521
|
+
const typedError = e as AxiosError<{ detail: string }>;
|
|
522
|
+
const message =
|
|
523
|
+
typedError.response?.data?.["detail"] || "Failed to book tour";
|
|
524
|
+
if (
|
|
525
|
+
typedError.response &&
|
|
526
|
+
typedError.response.headers &&
|
|
527
|
+
typedError.response.headers[
|
|
528
|
+
"funnel-prospect-conflicting-appointment-error"
|
|
529
|
+
]
|
|
530
|
+
) {
|
|
531
|
+
if (this.selectedDate && this.selectedTime) {
|
|
532
|
+
const dateAvailabilities =
|
|
533
|
+
this.availabilitiesGroupedByDay[
|
|
534
|
+
format(this.selectedDate, "yyyy-MM-dd")
|
|
535
|
+
];
|
|
536
|
+
if (dateAvailabilities) {
|
|
537
|
+
this.availabilitiesGroupedByDay[
|
|
538
|
+
format(this.selectedDate, "yyyy-MM-dd")
|
|
539
|
+
] = dateAvailabilities.filter(
|
|
540
|
+
(availability) => availability !== this.selectedTime
|
|
541
|
+
);
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
} else if (
|
|
545
|
+
typedError.response?.status === 409 &&
|
|
546
|
+
!this.promptForReschedule
|
|
547
|
+
) {
|
|
548
|
+
this.promptForReschedule = true;
|
|
549
|
+
this.isSubmitting = false;
|
|
550
|
+
this.tourIsBooked = false;
|
|
551
|
+
return;
|
|
552
|
+
}
|
|
403
553
|
alert(message);
|
|
404
554
|
this.isSubmitting = false;
|
|
405
555
|
this.tourIsBooked = false;
|
|
406
556
|
}
|
|
407
557
|
};
|
|
408
558
|
|
|
409
|
-
static styles = [
|
|
410
|
-
css`
|
|
411
|
-
* {
|
|
412
|
-
box-sizing: border-box;
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
.tour-scheduler {
|
|
416
|
-
position: fixed;
|
|
417
|
-
left: 50%;
|
|
418
|
-
top: 50%;
|
|
419
|
-
transform: translate(-50%, -50%);
|
|
420
|
-
width: 1018px;
|
|
421
|
-
height: 573px;
|
|
422
|
-
background: #ffffff;
|
|
423
|
-
box-shadow: 0px 16px 18px 10px rgba(21, 21, 21, 0.4);
|
|
424
|
-
border-radius: 10px;
|
|
425
|
-
font-family: "Poppins";
|
|
426
|
-
color: #202020;
|
|
427
|
-
padding: 0 25px 0 27px;
|
|
428
|
-
|
|
429
|
-
/* grid stuff */
|
|
430
|
-
display: grid;
|
|
431
|
-
grid-template-columns: 229px 432px 305px;
|
|
432
|
-
grid-template-rows: 44px 54px 32px 245px 117px 1px;
|
|
433
|
-
}
|
|
434
|
-
|
|
435
|
-
@media screen and (max-width: 1000px) {
|
|
436
|
-
.tour-scheduler {
|
|
437
|
-
transform: translate(-50%, -50%) scale(0.8, 0.6);
|
|
438
|
-
}
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
h1,
|
|
442
|
-
h2 {
|
|
443
|
-
margin: 0;
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
.tour-scheduler > :is(h1, h2) {
|
|
447
|
-
align-self: end;
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
h1 {
|
|
451
|
-
font-size: 14px;
|
|
452
|
-
font-weight: 700;
|
|
453
|
-
}
|
|
454
|
-
|
|
455
|
-
h1#scheduleATour {
|
|
456
|
-
grid-row: 1 / 2;
|
|
457
|
-
grid-column: 1;
|
|
458
|
-
align-self: end;
|
|
459
|
-
z-index: 1; // idk why, but it's invisible on the confirmation page otherwise
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
button#closeButton {
|
|
463
|
-
grid-row: 1 / 2;
|
|
464
|
-
grid-column: 3;
|
|
465
|
-
background: none;
|
|
466
|
-
border: none;
|
|
467
|
-
align-self: end;
|
|
468
|
-
justify-self: end;
|
|
469
|
-
z-index: 1; // idk why, but it's invisible on the confirmation page otherwise
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
/*
|
|
473
|
-
makes button fit size of SVG:
|
|
474
|
-
https://stackoverflow.com/questions/45423874/button-height-is-greater-than-the-nested-contents-height
|
|
475
|
-
otherwise there's some empty space at the bottom of the button, which interferes with vertical centering
|
|
476
|
-
*/
|
|
477
|
-
button#closeButton > svg {
|
|
478
|
-
vertical-align: middle;
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
#tourTypeMenu {
|
|
482
|
-
grid-row: 4 / 5;
|
|
483
|
-
grid-column: 1;
|
|
484
|
-
align-self: start;
|
|
485
|
-
display: flex;
|
|
486
|
-
flex-direction: column;
|
|
487
|
-
gap: 15px;
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
h2 {
|
|
491
|
-
font-weight: 600;
|
|
492
|
-
font-size: 14px;
|
|
493
|
-
grid-row: label-row;
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
h2#tourType {
|
|
497
|
-
grid-column: 1;
|
|
498
|
-
grid-row: 2;
|
|
499
|
-
}
|
|
500
|
-
|
|
501
|
-
h2#dateAndTime {
|
|
502
|
-
grid-column: 2;
|
|
503
|
-
grid-row: 2;
|
|
504
|
-
}
|
|
505
|
-
|
|
506
|
-
h2#yourInformation {
|
|
507
|
-
grid-column: 3;
|
|
508
|
-
grid-row: 2;
|
|
509
|
-
}
|
|
510
|
-
|
|
511
|
-
#datePicker {
|
|
512
|
-
display: flex;
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
#dateAndTimeMenu {
|
|
516
|
-
grid-row: 4 / 5;
|
|
517
|
-
grid-column: 2;
|
|
518
|
-
align-self: start;
|
|
519
|
-
display: flex;
|
|
520
|
-
flex-direction: column;
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
#yourInformationMenu {
|
|
524
|
-
grid-row: 4 / 5;
|
|
525
|
-
grid-column: 3;
|
|
526
|
-
display: flex;
|
|
527
|
-
flex-direction: column;
|
|
528
|
-
gap: 12px;
|
|
529
|
-
}
|
|
530
|
-
|
|
531
|
-
#yourInformationMenu input {
|
|
532
|
-
width: 100%;
|
|
533
|
-
height: 49px;
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
.unitLayoutChoices {
|
|
537
|
-
grid-row: 5 / 6;
|
|
538
|
-
grid-column: 3;
|
|
539
|
-
align-self: start;
|
|
540
|
-
display: flex;
|
|
541
|
-
flex-direction: column;
|
|
542
|
-
}
|
|
543
|
-
.unitLayoutChoicesDropdowns {
|
|
544
|
-
display: flex;
|
|
545
|
-
justify-content: space-between;
|
|
546
|
-
gap: 6px;
|
|
547
|
-
}
|
|
548
|
-
|
|
549
|
-
.unitLayoutChoice {
|
|
550
|
-
margin-bottom: 12px;
|
|
551
|
-
width: -webkit-fill-available;
|
|
552
|
-
}
|
|
553
|
-
|
|
554
|
-
h2.unitLayoutChoice {
|
|
555
|
-
margin-bottom: 7px;
|
|
556
|
-
}
|
|
557
|
-
|
|
558
|
-
.unitLayoutOptions {
|
|
559
|
-
display: flex;
|
|
560
|
-
flex-direction: column;
|
|
561
|
-
gap: 8px;
|
|
562
|
-
}
|
|
563
|
-
|
|
564
|
-
hr {
|
|
565
|
-
grid-row: 6;
|
|
566
|
-
grid-column: 1 / 5;
|
|
567
|
-
/* remove side margins because of this
|
|
568
|
-
* (https://stackoverflow.com/questions/34365271/hr-inside-container-with-display-flex-become-corrupted)
|
|
569
|
-
* and top/bottom margins to position the line exactly at the gridline
|
|
570
|
-
*/
|
|
571
|
-
margin: 0;
|
|
572
|
-
}
|
|
573
|
-
|
|
574
|
-
p {
|
|
575
|
-
font-weight: 400;
|
|
576
|
-
font-size: 12px;
|
|
577
|
-
grid-row: 7;
|
|
578
|
-
grid-column: 1 / 3;
|
|
579
|
-
align-self: start;
|
|
580
|
-
margin: 0;
|
|
581
|
-
padding-top: 32px;
|
|
582
|
-
}
|
|
583
|
-
|
|
584
|
-
#schedule {
|
|
585
|
-
width: 145px;
|
|
586
|
-
height: 50px;
|
|
587
|
-
grid-row: 7;
|
|
588
|
-
grid-column: 3;
|
|
589
|
-
justify-self: end;
|
|
590
|
-
align-self: start;
|
|
591
|
-
margin-top: 18px;
|
|
592
|
-
}
|
|
593
|
-
|
|
594
|
-
#confirmationMessage {
|
|
595
|
-
grid-row: 3;
|
|
596
|
-
width: 625px;
|
|
597
|
-
}
|
|
598
|
-
|
|
599
|
-
#confirmationMessage > p {
|
|
600
|
-
font-size: 18px;
|
|
601
|
-
}
|
|
602
|
-
|
|
603
|
-
/* Loading styles: pulsing gray overlay on all the form elements */
|
|
604
|
-
|
|
605
|
-
@keyframes spin {
|
|
606
|
-
0% {
|
|
607
|
-
transform: none;
|
|
608
|
-
}
|
|
609
|
-
50% {
|
|
610
|
-
transform: rotateZ(180deg);
|
|
611
|
-
}
|
|
612
|
-
100% {
|
|
613
|
-
transform: rotateZ(360deg);
|
|
614
|
-
}
|
|
615
|
-
}
|
|
616
|
-
|
|
617
|
-
svg#loadingIcon {
|
|
618
|
-
animation: spin 2s infinite linear;
|
|
619
|
-
}
|
|
620
|
-
|
|
621
|
-
.tour-scheduler.loading #scheduleATour {
|
|
622
|
-
display: flex;
|
|
623
|
-
gap: 10px;
|
|
624
|
-
}
|
|
625
|
-
|
|
626
|
-
@keyframes loadingPulse {
|
|
627
|
-
0% {
|
|
628
|
-
background-color: #e7e7e7;
|
|
629
|
-
}
|
|
630
|
-
50% {
|
|
631
|
-
background-color: white;
|
|
632
|
-
}
|
|
633
|
-
100% {
|
|
634
|
-
background-color: #e7e7e7;
|
|
635
|
-
}
|
|
636
|
-
}
|
|
637
|
-
|
|
638
|
-
tour-type-option,
|
|
639
|
-
date-picker,
|
|
640
|
-
#yourInformationMenu .inputContainer {
|
|
641
|
-
position: relative;
|
|
642
|
-
}
|
|
643
|
-
|
|
644
|
-
.tour-scheduler.loading
|
|
645
|
-
:is(tour-type-option, date-picker, #yourInformationMenu
|
|
646
|
-
.inputContainer)::after {
|
|
647
|
-
content: "";
|
|
648
|
-
position: absolute;
|
|
649
|
-
top: 0;
|
|
650
|
-
left: 0;
|
|
651
|
-
height: 100%;
|
|
652
|
-
z-index: 1;
|
|
653
|
-
animation: loadingPulse 2s infinite;
|
|
654
|
-
}
|
|
655
|
-
|
|
656
|
-
.tour-scheduler.loading tour-type-option::after {
|
|
657
|
-
border-radius: 10px;
|
|
658
|
-
width: 200px;
|
|
659
|
-
}
|
|
660
|
-
|
|
661
|
-
.tour-scheduler.loading date-picker::after {
|
|
662
|
-
border-radius: 10px;
|
|
663
|
-
width: 205px;
|
|
664
|
-
}
|
|
665
|
-
|
|
666
|
-
.tour-scheduler.loading #yourInformationMenu .inputContainer input {
|
|
667
|
-
visibility: hidden;
|
|
668
|
-
}
|
|
669
|
-
|
|
670
|
-
.tour-scheduler.loading time-picker {
|
|
671
|
-
display: none;
|
|
672
|
-
}
|
|
673
|
-
|
|
674
|
-
#namesWrapper {
|
|
675
|
-
display: flex;
|
|
676
|
-
justify-content: space-between;
|
|
677
|
-
}
|
|
678
|
-
|
|
679
|
-
.nameContainer {
|
|
680
|
-
width: 48%;
|
|
681
|
-
}
|
|
682
|
-
|
|
683
|
-
.nameInput {
|
|
684
|
-
width: 100%;
|
|
685
|
-
}
|
|
686
|
-
|
|
687
|
-
@media (max-width: 767px) {
|
|
688
|
-
/* TODO: separate styles into general, desktop-specific, and mobile-specific.
|
|
689
|
-
basically everything I have "unset" or "initial" on should become desktop-specific. the grid layout is only for desktop.
|
|
690
|
-
*/
|
|
691
|
-
.tour-scheduler {
|
|
692
|
-
position: fixed;
|
|
693
|
-
left: 0;
|
|
694
|
-
right: 0;
|
|
695
|
-
bottom: 0;
|
|
696
|
-
top: initial;
|
|
697
|
-
height: 93vh;
|
|
698
|
-
width: 100vw;
|
|
699
|
-
background: #ffffff;
|
|
700
|
-
transform: none;
|
|
701
|
-
box-shadow: none;
|
|
702
|
-
border-radius: 0;
|
|
703
|
-
padding: 25px 20px 0 22px;
|
|
704
|
-
display: flex;
|
|
705
|
-
flex-direction: column;
|
|
706
|
-
}
|
|
707
|
-
|
|
708
|
-
#topControls {
|
|
709
|
-
display: flex;
|
|
710
|
-
justify-content: space-between;
|
|
711
|
-
align-items: center;
|
|
712
|
-
}
|
|
713
|
-
|
|
714
|
-
.tour-scheduler > :is(h1, h2) {
|
|
715
|
-
align-self: unset;
|
|
716
|
-
}
|
|
717
|
-
|
|
718
|
-
/* TODO: this and :disabled is duplicated from Schedule button. make a class,
|
|
719
|
-
or better a component, for the button styles
|
|
720
|
-
*/
|
|
721
|
-
button#next {
|
|
722
|
-
height: 50px;
|
|
723
|
-
/* width: 74px; */
|
|
724
|
-
padding: 13px 22px 14px 22px;
|
|
725
|
-
align-self: flex-start;
|
|
726
|
-
background: #202020;
|
|
727
|
-
border: 1px solid #ffffff;
|
|
728
|
-
border-radius: 10px;
|
|
729
|
-
font-family: "Poppins";
|
|
730
|
-
font-weight: 700;
|
|
731
|
-
font-size: 14px;
|
|
732
|
-
color: #ffffff;
|
|
733
|
-
box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.5);
|
|
734
|
-
margin-top: 22px;
|
|
735
|
-
}
|
|
736
|
-
|
|
737
|
-
button#next:disabled {
|
|
738
|
-
background: #e7e7e7;
|
|
739
|
-
box-shadow: none;
|
|
740
|
-
}
|
|
741
|
-
|
|
742
|
-
h1#scheduleATour {
|
|
743
|
-
grid-row: unset;
|
|
744
|
-
grid-column: unset;
|
|
745
|
-
align-self: unset;
|
|
746
|
-
}
|
|
747
|
-
|
|
748
|
-
button#closeButton {
|
|
749
|
-
grid-row: unset;
|
|
750
|
-
grid-column: unset;
|
|
751
|
-
align-self: unset;
|
|
752
|
-
justify-self: unset;
|
|
753
|
-
}
|
|
754
|
-
|
|
755
|
-
h2 {
|
|
756
|
-
grid-row: unset;
|
|
757
|
-
margin-top: 37px;
|
|
758
|
-
margin-bottom: 25px;
|
|
759
|
-
}
|
|
760
|
-
|
|
761
|
-
#tourTypeMenu {
|
|
762
|
-
display: flex;
|
|
763
|
-
flex-direction: column;
|
|
764
|
-
gap: 15px;
|
|
765
|
-
margin-bottom: 36px;
|
|
766
|
-
}
|
|
767
|
-
|
|
768
|
-
h2#tourType {
|
|
769
|
-
grid-column: unset;
|
|
770
|
-
grid-row: unset;
|
|
771
|
-
}
|
|
772
|
-
|
|
773
|
-
#datePicker {
|
|
774
|
-
display: flex;
|
|
775
|
-
flex-direction: column;
|
|
776
|
-
gap: 18px;
|
|
777
|
-
}
|
|
778
|
-
|
|
779
|
-
time-picker {
|
|
780
|
-
/* so the Next button doesn't jump when the date is selected and the time slots appear */
|
|
781
|
-
height: 93px;
|
|
782
|
-
}
|
|
783
|
-
|
|
784
|
-
#dateAndTimeMenu {
|
|
785
|
-
grid-row: unset;
|
|
786
|
-
grid-column: unset;
|
|
787
|
-
align-self: unset;
|
|
788
|
-
display: unset;
|
|
789
|
-
flex-direction: unset;
|
|
790
|
-
}
|
|
791
|
-
|
|
792
|
-
#confirmationMessage {
|
|
793
|
-
grid-row: unset;
|
|
794
|
-
width: 90%;
|
|
795
|
-
margin-top: 37px;
|
|
796
|
-
}
|
|
797
|
-
}
|
|
798
|
-
`,
|
|
799
|
-
InputStyles,
|
|
800
|
-
];
|
|
559
|
+
static styles = [tourSchedulerStyles, InputStyles];
|
|
801
560
|
|
|
802
561
|
tourTypeMenu(): TemplateResult {
|
|
803
|
-
return html`<h2
|
|
804
|
-
<div id="
|
|
805
|
-
${this.shouldShowTourType[TourType.
|
|
562
|
+
return html`<h2 class="journey-header">Tour Type</h2>
|
|
563
|
+
<div id="tour-type-menu">
|
|
564
|
+
${this.shouldShowTourType[TourType.Self]
|
|
806
565
|
? html` <tour-type-option
|
|
807
|
-
heading="
|
|
808
|
-
subtitle="
|
|
566
|
+
heading="Take a tour"
|
|
567
|
+
subtitle="on your own"
|
|
568
|
+
.brandColor=${this.brandColor}
|
|
569
|
+
.backgroundColor=${this.backgroundColor}
|
|
809
570
|
@click="${async () => {
|
|
810
|
-
this.tourType = TourType.
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
window.open(this.escortedToursLink, "_blank");
|
|
571
|
+
this.tourType = TourType.Self;
|
|
572
|
+
if (this.sgtUrl) {
|
|
573
|
+
window.open(this.sgtUrl, "_blank");
|
|
814
574
|
}
|
|
815
575
|
this.availabilitiesGroupedByDay =
|
|
816
576
|
await getAvailabilitiesGroupedByDay(
|
|
817
|
-
tourTypeMap[TourType.
|
|
577
|
+
tourTypeMap[TourType.Self]
|
|
818
578
|
);
|
|
819
579
|
}}"
|
|
820
580
|
@keydown="${(e: KeyboardEvent) => {
|
|
821
581
|
if ([" ", "Enter"].includes(e.key)) {
|
|
822
582
|
e.preventDefault();
|
|
823
|
-
this.tourType = TourType.
|
|
583
|
+
this.tourType = TourType.Self;
|
|
824
584
|
}
|
|
825
585
|
}}"
|
|
826
|
-
?selected="${this.tourType === TourType.
|
|
586
|
+
?selected="${this.tourType === TourType.Self}"
|
|
827
587
|
>
|
|
828
588
|
<svg
|
|
829
589
|
slot="icon"
|
|
830
|
-
width="
|
|
590
|
+
width="28"
|
|
831
591
|
height="31"
|
|
832
|
-
viewBox="0 0
|
|
592
|
+
viewBox="0 0 28 31"
|
|
833
593
|
fill="none"
|
|
834
594
|
xmlns="http://www.w3.org/2000/svg"
|
|
835
595
|
>
|
|
836
596
|
<path
|
|
837
|
-
d="
|
|
838
|
-
fill="${this.tourType === TourType.
|
|
597
|
+
d="M14.8334 19.1903V30.1667H0.666687C0.666248 28.4367 1.06183 26.7297 1.82311 25.1763C2.58439 23.6229 3.69118 22.2644 5.05866 21.2049C6.42614 20.1453 8.01802 19.4129 9.71232 19.0637C11.4066 18.7145 13.1584 18.7578 14.8334 19.1903ZM12 17.4167C7.30377 17.4167 3.50002 13.6129 3.50002 8.91666C3.50002 4.22041 7.30377 0.416656 12 0.416656C16.6963 0.416656 20.5 4.22041 20.5 8.91666C20.5 13.6129 16.6963 17.4167 12 17.4167ZM20.5 23.0833V18.125L27.5834 24.5L20.5 30.875V25.9167H16.25V23.0833H20.5Z"
|
|
598
|
+
fill="${this.tourType === TourType.Self
|
|
839
599
|
? "#ffffff"
|
|
840
600
|
: "#202020"}"
|
|
841
601
|
/>
|
|
842
602
|
</svg>
|
|
843
603
|
</tour-type-option>`
|
|
844
604
|
: ""}
|
|
845
|
-
${this.shouldShowTourType[TourType.
|
|
846
|
-
? html
|
|
847
|
-
heading="
|
|
848
|
-
subtitle="
|
|
605
|
+
${this.shouldShowTourType[TourType.Guided]
|
|
606
|
+
? html` <tour-type-option
|
|
607
|
+
heading="Guided tour"
|
|
608
|
+
subtitle="with an agent"
|
|
609
|
+
.brandColor=${this.brandColor}
|
|
610
|
+
.backgroundColor=${this.backgroundColor}
|
|
849
611
|
@click="${async () => {
|
|
850
|
-
this.tourType = TourType.
|
|
851
|
-
|
|
852
|
-
|
|
612
|
+
this.tourType = TourType.Guided;
|
|
613
|
+
|
|
614
|
+
if (this.escortedToursLink) {
|
|
615
|
+
window.open(this.escortedToursLink, "_blank");
|
|
853
616
|
}
|
|
854
617
|
this.availabilitiesGroupedByDay =
|
|
855
618
|
await getAvailabilitiesGroupedByDay(
|
|
856
|
-
tourTypeMap[TourType.
|
|
619
|
+
tourTypeMap[TourType.Guided]
|
|
857
620
|
);
|
|
858
621
|
}}"
|
|
859
622
|
@keydown="${(e: KeyboardEvent) => {
|
|
860
623
|
if ([" ", "Enter"].includes(e.key)) {
|
|
861
624
|
e.preventDefault();
|
|
862
|
-
this.tourType = TourType.
|
|
625
|
+
this.tourType = TourType.Guided;
|
|
863
626
|
}
|
|
864
627
|
}}"
|
|
865
|
-
?selected="${this.tourType === TourType.
|
|
628
|
+
?selected="${this.tourType === TourType.Guided}"
|
|
866
629
|
>
|
|
867
630
|
<svg
|
|
868
631
|
slot="icon"
|
|
869
|
-
width="
|
|
632
|
+
width="31"
|
|
870
633
|
height="31"
|
|
871
|
-
viewBox="0 0
|
|
634
|
+
viewBox="0 0 31 31"
|
|
872
635
|
fill="none"
|
|
873
636
|
xmlns="http://www.w3.org/2000/svg"
|
|
874
637
|
>
|
|
875
638
|
<path
|
|
876
|
-
d="
|
|
877
|
-
fill="${this.tourType === TourType.
|
|
639
|
+
d="M0.833252 30.1666C0.833252 27.1608 2.0273 24.2782 4.15271 22.1527C6.27812 20.0273 9.1608 18.8333 12.1666 18.8333C15.1724 18.8333 18.0551 20.0273 20.1805 22.1527C22.3059 24.2782 23.4999 27.1608 23.4999 30.1666H0.833252ZM12.1666 17.4166C7.47034 17.4166 3.66659 13.6129 3.66659 8.91663C3.66659 4.22038 7.47034 0.416626 12.1666 0.416626C16.8628 0.416626 20.6666 4.22038 20.6666 8.91663C20.6666 13.6129 16.8628 17.4166 12.1666 17.4166ZM22.5975 20.58C24.7645 21.137 26.7006 22.3634 28.13 24.0846C29.5595 25.8059 30.4096 27.9342 30.5592 30.1666H26.3333C26.3333 26.4691 24.9166 23.1031 22.5975 20.58ZM19.7316 17.3557C20.9187 16.2939 21.8681 14.9932 22.5175 13.5388C23.167 12.0845 23.5017 10.5094 23.4999 8.91663C23.5029 6.9807 23.0078 5.07657 22.062 3.38738C23.6666 3.70979 25.11 4.5779 26.1469 5.84415C27.1838 7.1104 27.7502 8.69666 27.7499 10.3333C27.7503 11.3426 27.5349 12.3404 27.1182 13.2597C26.7016 14.179 26.0932 14.9986 25.3339 15.6636C24.5746 16.3285 23.6819 16.8236 22.7157 17.1154C21.7495 17.4072 20.7321 17.4892 19.7316 17.3557V17.3557Z"
|
|
640
|
+
fill="${this.tourType === TourType.Guided
|
|
878
641
|
? "#ffffff"
|
|
879
642
|
: "#202020"}"
|
|
880
643
|
/>
|
|
@@ -882,9 +645,11 @@ export class TourScheduler extends LitElement {
|
|
|
882
645
|
</tour-type-option>`
|
|
883
646
|
: ""}
|
|
884
647
|
${this.shouldShowTourType[TourType.Virtual]
|
|
885
|
-
? html
|
|
648
|
+
? html` <tour-type-option
|
|
886
649
|
heading="Virtual tour"
|
|
887
650
|
subtitle="over video"
|
|
651
|
+
.brandColor=${this.brandColor}
|
|
652
|
+
.backgroundColor=${this.backgroundColor}
|
|
888
653
|
@click="${async () => {
|
|
889
654
|
this.tourType = TourType.Virtual;
|
|
890
655
|
if (this.virtualToursLink) {
|
|
@@ -923,8 +688,19 @@ export class TourScheduler extends LitElement {
|
|
|
923
688
|
</div>`;
|
|
924
689
|
}
|
|
925
690
|
|
|
926
|
-
dateAndTimeMenu(
|
|
927
|
-
|
|
691
|
+
dateAndTimeMenu(): TemplateResult {
|
|
692
|
+
if (this.tourType === TourType.Self && this.sgtUrl) {
|
|
693
|
+
return html`<h2 class="journey-header">Date and Time</h2>
|
|
694
|
+
<div id="dateAndTimeMenu">
|
|
695
|
+
<button
|
|
696
|
+
id="self-guided-redirect-bttn"
|
|
697
|
+
@click=${() => window.open(this.sgtUrl, "_blank")}
|
|
698
|
+
>
|
|
699
|
+
View Self Guided Tour Times
|
|
700
|
+
</button>
|
|
701
|
+
</div>`;
|
|
702
|
+
}
|
|
703
|
+
return html`<h2 class="journey-header">Date and Time</h2>
|
|
928
704
|
<div id="dateAndTimeMenu">
|
|
929
705
|
<div id="datePicker">
|
|
930
706
|
<date-picker
|
|
@@ -933,54 +709,70 @@ export class TourScheduler extends LitElement {
|
|
|
933
709
|
(dates) => dates.map((date) => new Date(date.offset))
|
|
934
710
|
)}
|
|
935
711
|
@change=${(e: Event) => {
|
|
712
|
+
// if the user clicked a tour type that is suppose to redirect, we redirect that use when they select a date
|
|
713
|
+
// This can happen if the user clicks, is redirect, and then comes back to the webchat
|
|
714
|
+
if (this.tourType === TourType.Self && this.sgtUrl) {
|
|
715
|
+
window.open(this.sgtUrl, "_blank");
|
|
716
|
+
return;
|
|
717
|
+
}
|
|
718
|
+
if (this.tourType === TourType.Guided && this.escortedToursLink) {
|
|
719
|
+
window.open(this.escortedToursLink, "_blank");
|
|
720
|
+
return;
|
|
721
|
+
}
|
|
722
|
+
if (this.tourType === TourType.Virtual && this.virtualToursLink) {
|
|
723
|
+
window.open(this.virtualToursLink, "_blank");
|
|
724
|
+
return;
|
|
725
|
+
}
|
|
726
|
+
|
|
936
727
|
if (e.target instanceof DatePicker) {
|
|
937
728
|
this.selectedDate = e.target.selectedDate;
|
|
938
729
|
}
|
|
939
730
|
}}
|
|
940
731
|
></date-picker>
|
|
941
|
-
<
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
)
|
|
951
|
-
.map((date) => {
|
|
952
|
-
return {
|
|
953
|
-
dateWithTimeZoneOffset: date,
|
|
954
|
-
displayTime: format(
|
|
955
|
-
parseISO(`${date.datetime}${date.offset}`),
|
|
956
|
-
"h:mmaaa"
|
|
957
|
-
),
|
|
958
|
-
};
|
|
959
|
-
})
|
|
960
|
-
: []}
|
|
961
|
-
@change=${(e: Event) => {
|
|
962
|
-
if (e.target instanceof TimePicker) {
|
|
963
|
-
if (!this.selectedDate) return;
|
|
964
|
-
const daysAvailabilities =
|
|
965
|
-
this.availabilitiesGroupedByDay[
|
|
966
|
-
format(new Date(this.selectedDate), "y-MM-dd")
|
|
967
|
-
];
|
|
968
|
-
const index = e.target.selectedTime
|
|
969
|
-
? daysAvailabilities.indexOf(
|
|
970
|
-
e.target.selectedTime.dateWithTimeZoneOffset
|
|
732
|
+
<div>
|
|
733
|
+
<time-picker
|
|
734
|
+
?selecteddateexists=${!!this.selectedDate}
|
|
735
|
+
.options=${this.selectedDate
|
|
736
|
+
? this.availabilitiesGroupedByDay[
|
|
737
|
+
format(this.selectedDate, "y-MM-dd")
|
|
738
|
+
]
|
|
739
|
+
?.sort((a, b) =>
|
|
740
|
+
compareAsc(parseISO(a.datetime), parseISO(b.datetime))
|
|
971
741
|
)
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
742
|
+
.map((date) => {
|
|
743
|
+
return {
|
|
744
|
+
dateWithTimeZoneOffset: date,
|
|
745
|
+
displayTime: format(
|
|
746
|
+
parseISO(`${date.datetime}${date.offset}`),
|
|
747
|
+
"h:mmaaa"
|
|
748
|
+
),
|
|
749
|
+
};
|
|
750
|
+
})
|
|
751
|
+
: []}
|
|
752
|
+
@change=${(e: Event) => {
|
|
753
|
+
if (e.target instanceof TimePicker) {
|
|
754
|
+
if (!this.selectedDate) return;
|
|
755
|
+
const daysAvailabilities =
|
|
756
|
+
this.availabilitiesGroupedByDay[
|
|
757
|
+
format(new Date(this.selectedDate), "y-MM-dd")
|
|
758
|
+
];
|
|
759
|
+
const index = e.target.selectedTime
|
|
760
|
+
? daysAvailabilities.indexOf(
|
|
761
|
+
e.target.selectedTime.dateWithTimeZoneOffset
|
|
762
|
+
)
|
|
763
|
+
: null;
|
|
764
|
+
this.selectedTime =
|
|
765
|
+
index !== null ? daysAvailabilities[index] : null;
|
|
766
|
+
}
|
|
767
|
+
}}
|
|
768
|
+
></time-picker>
|
|
769
|
+
</div>
|
|
978
770
|
</div>
|
|
979
771
|
</div>`;
|
|
980
772
|
}
|
|
981
773
|
|
|
982
774
|
closeButton(): TemplateResult {
|
|
983
|
-
return html
|
|
775
|
+
return html` <button id="close-button" @click=${this.onCloseClicked}>
|
|
984
776
|
<svg
|
|
985
777
|
width="19"
|
|
986
778
|
height="19"
|
|
@@ -1023,15 +815,15 @@ export class TourScheduler extends LitElement {
|
|
|
1023
815
|
this.mobilePageIndex++;
|
|
1024
816
|
},
|
|
1025
817
|
render: (): TemplateResult => {
|
|
1026
|
-
return html`${this.dateAndTimeMenu(
|
|
818
|
+
return html`${this.dateAndTimeMenu()}`;
|
|
1027
819
|
},
|
|
1028
820
|
},
|
|
1029
821
|
{
|
|
1030
822
|
validate: (): boolean => this.validators.leadInfo(),
|
|
1031
823
|
// last page gets <action-confirm-button> instead of the regular button
|
|
1032
824
|
nextButtonText: null,
|
|
1033
|
-
renderNextButton: (): TemplateResult => html
|
|
1034
|
-
id="schedule"
|
|
825
|
+
renderNextButton: (): TemplateResult => html` <action-confirm-button
|
|
826
|
+
id="schedule-bttn"
|
|
1035
827
|
.onClick=${this.submit}
|
|
1036
828
|
.isLoading=${this.isSubmitting}
|
|
1037
829
|
height="50px"
|
|
@@ -1047,7 +839,7 @@ export class TourScheduler extends LitElement {
|
|
|
1047
839
|
];
|
|
1048
840
|
|
|
1049
841
|
userInfoAndLayoutMenu(): TemplateResult {
|
|
1050
|
-
return html`<h2
|
|
842
|
+
return html`<h2 class="journey-header">Your Information</h2>
|
|
1051
843
|
<div id="yourInformationMenu">
|
|
1052
844
|
<div id="namesWrapper">
|
|
1053
845
|
<div class="nameContainer" id="firstName">
|
|
@@ -1055,6 +847,8 @@ export class TourScheduler extends LitElement {
|
|
|
1055
847
|
class=${classMap({
|
|
1056
848
|
["webchat-input"]: true,
|
|
1057
849
|
["nameInput"]: true,
|
|
850
|
+
["webchat-font__desktop"]: !isMobile(),
|
|
851
|
+
["webchat-font__mobile"]: isMobile(),
|
|
1058
852
|
})}
|
|
1059
853
|
type="text"
|
|
1060
854
|
placeholder="First name"
|
|
@@ -1068,6 +862,8 @@ export class TourScheduler extends LitElement {
|
|
|
1068
862
|
class=${classMap({
|
|
1069
863
|
["webchat-input"]: true,
|
|
1070
864
|
["nameInput"]: true,
|
|
865
|
+
["webchat-font__desktop"]: !isMobile(),
|
|
866
|
+
["webchat-font__mobile"]: isMobile(),
|
|
1071
867
|
})}
|
|
1072
868
|
type="text"
|
|
1073
869
|
placeholder="Last name"
|
|
@@ -1078,125 +874,74 @@ export class TourScheduler extends LitElement {
|
|
|
1078
874
|
</div>
|
|
1079
875
|
</div>
|
|
1080
876
|
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
type="tel"
|
|
1097
|
-
inputmode="tel"
|
|
1098
|
-
placeholder="Phone"
|
|
1099
|
-
name="phone"
|
|
1100
|
-
autocomplete="tel-national"
|
|
1101
|
-
maxlength="14"
|
|
1102
|
-
.value=${this.phoneNumber}
|
|
1103
|
-
@keydown=${this.handlePhoneKeydown}
|
|
1104
|
-
@keyup=${this.handlePhoneKeyup}
|
|
1105
|
-
@input=${(e: Event) => {
|
|
1106
|
-
if (!e.target) {
|
|
1107
|
-
return;
|
|
1108
|
-
}
|
|
1109
|
-
this.phoneNumber = formatToPhone(
|
|
1110
|
-
(e.target as HTMLInputElement).value
|
|
1111
|
-
);
|
|
1112
|
-
}}
|
|
1113
|
-
/>
|
|
1114
|
-
</div>
|
|
1115
|
-
${
|
|
1116
|
-
this.leadSources.length > 0
|
|
1117
|
-
? html` <me-select
|
|
1118
|
-
id="leadSource"
|
|
1119
|
-
value="${this.currentLeadSource}"
|
|
1120
|
-
placeholder="How did you hear about us?"
|
|
1121
|
-
.options="${this.leadSources.map((i) => ({
|
|
1122
|
-
label: i,
|
|
1123
|
-
value: i,
|
|
1124
|
-
}))}"
|
|
1125
|
-
@change=${() => {
|
|
1126
|
-
this.requestUpdate();
|
|
1127
|
-
}}
|
|
1128
|
-
>
|
|
1129
|
-
</me-select>`
|
|
1130
|
-
: ""
|
|
1131
|
-
}
|
|
877
|
+
<div class="inputContainer" id="email">
|
|
878
|
+
<input
|
|
879
|
+
class=${classMap({
|
|
880
|
+
["webchat-input"]: true,
|
|
881
|
+
["webchat-font__desktop"]: !isMobile(),
|
|
882
|
+
["webchat-font__mobile"]: isMobile(),
|
|
883
|
+
})}
|
|
884
|
+
type="email"
|
|
885
|
+
inputmode="email"
|
|
886
|
+
placeholder="Email"
|
|
887
|
+
name="email"
|
|
888
|
+
autocomplete="email"
|
|
889
|
+
.value=${this.email}
|
|
890
|
+
@input=${this.onChangeEmail}
|
|
891
|
+
/>
|
|
1132
892
|
</div>
|
|
1133
|
-
<div class="
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
}
|
|
1166
|
-
${
|
|
1167
|
-
this.unitOptions.filter(
|
|
1168
|
-
(i) =>
|
|
1169
|
-
!this.layoutTypeSelect ||
|
|
1170
|
-
i.layout === this.layoutTypeSelect.value
|
|
1171
|
-
).length > 0
|
|
1172
|
-
? html`
|
|
1173
|
-
<me-select
|
|
1174
|
-
id="unitType"
|
|
1175
|
-
placeholder="Select unit"
|
|
1176
|
-
.options="${this.unitOptions
|
|
1177
|
-
.filter(
|
|
1178
|
-
(i) =>
|
|
1179
|
-
!this.layoutTypeSelect ||
|
|
1180
|
-
i.layout === this.layoutTypeSelect.value
|
|
1181
|
-
)
|
|
1182
|
-
.map((i) => ({
|
|
1183
|
-
label: i.name,
|
|
1184
|
-
value: i.name,
|
|
1185
|
-
}))}"
|
|
1186
|
-
defaultOption="Studio"
|
|
1187
|
-
@change=${() => {
|
|
1188
|
-
// to revalidate the form
|
|
1189
|
-
this.requestUpdate();
|
|
1190
|
-
}}
|
|
1191
|
-
>Studio
|
|
1192
|
-
</me-select>
|
|
1193
|
-
`
|
|
1194
|
-
: ""
|
|
1195
|
-
}
|
|
1196
|
-
</div>
|
|
1197
|
-
|
|
1198
|
-
|
|
893
|
+
<div class="inputContainer" id="phone">
|
|
894
|
+
<input
|
|
895
|
+
class=${classMap({
|
|
896
|
+
["webchat-input"]: true,
|
|
897
|
+
["webchat-font__desktop"]: !isMobile(),
|
|
898
|
+
["webchat-font__mobile"]: isMobile(),
|
|
899
|
+
["webchat-input__error"]:
|
|
900
|
+
this.phoneNumber.length === 14 &&
|
|
901
|
+
!isValidPhoneNumber(this.phoneNumber),
|
|
902
|
+
})}
|
|
903
|
+
type="tel"
|
|
904
|
+
inputmode="tel"
|
|
905
|
+
placeholder="Phone"
|
|
906
|
+
name="phone"
|
|
907
|
+
autocomplete="tel-national"
|
|
908
|
+
maxlength="14"
|
|
909
|
+
.value=${this.phoneNumber}
|
|
910
|
+
@keydown=${this.handlePhoneKeydown}
|
|
911
|
+
@keyup=${this.handlePhoneKeyup}
|
|
912
|
+
@input=${(e: Event) => {
|
|
913
|
+
if (!e.target) {
|
|
914
|
+
return;
|
|
915
|
+
}
|
|
916
|
+
this.phoneNumber = formatToPhoneInput(
|
|
917
|
+
(e.target as HTMLInputElement).value
|
|
918
|
+
);
|
|
919
|
+
}}
|
|
920
|
+
/>
|
|
921
|
+
${this.phoneNumber.length === 14 &&
|
|
922
|
+
!isValidPhoneNumber(this.phoneNumber)
|
|
923
|
+
? html`<p class="error-message">Invalid phone number</p>`
|
|
924
|
+
: ""}
|
|
1199
925
|
</div>
|
|
926
|
+
${this.leadSources.length > 0 &&
|
|
927
|
+
(this.featureFlagShowDropdown === FeatureFlagsShowDropdown.always ||
|
|
928
|
+
(this.featureFlagShowDropdown ===
|
|
929
|
+
FeatureFlagsShowDropdown.onAttributionFailure &&
|
|
930
|
+
this.currentLeadSource.length === 0))
|
|
931
|
+
? html` <me-select
|
|
932
|
+
id="leadSource"
|
|
933
|
+
value="${this.currentLeadSource}"
|
|
934
|
+
placeholder="How did you hear about us?"
|
|
935
|
+
.options="${this.leadSources.map((i) => ({
|
|
936
|
+
label: i,
|
|
937
|
+
value: i,
|
|
938
|
+
}))}"
|
|
939
|
+
@change=${() => {
|
|
940
|
+
this.requestUpdate();
|
|
941
|
+
}}
|
|
942
|
+
>
|
|
943
|
+
</me-select>`
|
|
944
|
+
: ""}
|
|
1200
945
|
</div> `;
|
|
1201
946
|
}
|
|
1202
947
|
|
|
@@ -1208,6 +953,28 @@ export class TourScheduler extends LitElement {
|
|
|
1208
953
|
parseISO(`${this.selectedTime.datetime}${this.selectedTime.offset}`),
|
|
1209
954
|
"h:mmaaa"
|
|
1210
955
|
);
|
|
956
|
+
|
|
957
|
+
if (this.canceledReschedule) {
|
|
958
|
+
return html`
|
|
959
|
+
<div id="confirmationMessage">
|
|
960
|
+
<svg
|
|
961
|
+
width="20"
|
|
962
|
+
height="20"
|
|
963
|
+
viewBox="0 0 20 20"
|
|
964
|
+
fill="none"
|
|
965
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
966
|
+
>
|
|
967
|
+
<path
|
|
968
|
+
d="M7 0V2H13V0H15V2H19C19.2652 2 19.5196 2.10536 19.7071 2.29289C19.8946 2.48043 20 2.73478 20 3V19C20 19.2652 19.8946 19.5196 19.7071 19.7071C19.5196 19.8946 19.2652 20 19 20H1C0.734784 20 0.48043 19.8946 0.292893 19.7071C0.105357 19.5196 0 19.2652 0 19V3C0 2.73478 0.105357 2.48043 0.292893 2.29289C0.48043 2.10536 0.734784 2 1 2H5V0H7ZM18 9H2V18H18V9ZM13.036 10.136L14.45 11.55L9.5 16.5L5.964 12.964L7.38 11.55L9.501 13.672L13.037 10.136H13.036ZM5 4H2V7H18V4H15V5H13V4H7V5H5V4Z"
|
|
969
|
+
fill="#202020"
|
|
970
|
+
/>
|
|
971
|
+
</svg>
|
|
972
|
+
<p>Thank you!</p>
|
|
973
|
+
<p>We'll see you at your originally schedule tour time.</p>
|
|
974
|
+
</div>
|
|
975
|
+
`;
|
|
976
|
+
}
|
|
977
|
+
|
|
1211
978
|
return html`
|
|
1212
979
|
<div id="confirmationMessage">
|
|
1213
980
|
<svg
|
|
@@ -1222,16 +989,17 @@ export class TourScheduler extends LitElement {
|
|
|
1222
989
|
fill="#202020"
|
|
1223
990
|
/>
|
|
1224
991
|
</svg>
|
|
992
|
+
<p>Thank you!</p>
|
|
1225
993
|
<p>
|
|
1226
|
-
Thank you!
|
|
1227
|
-
<br />
|
|
1228
994
|
Your
|
|
1229
995
|
${{
|
|
1230
996
|
[TourType.Guided]: "guided",
|
|
1231
997
|
[TourType.Self]: "self-guided",
|
|
1232
998
|
[TourType.Virtual]: "virtual",
|
|
1233
999
|
}[this.tourType]}
|
|
1234
|
-
tour is
|
|
1000
|
+
tour is
|
|
1001
|
+
${this.promptForReschedule ? html`rescheduled` : html`scheduled`} for
|
|
1002
|
+
${readableDateAndTime}.
|
|
1235
1003
|
</p>
|
|
1236
1004
|
<p>
|
|
1237
1005
|
Look for an email confirmation along with instructions and directions.
|
|
@@ -1241,11 +1009,11 @@ export class TourScheduler extends LitElement {
|
|
|
1241
1009
|
`;
|
|
1242
1010
|
}
|
|
1243
1011
|
|
|
1244
|
-
loadingIcon(): TemplateResult {
|
|
1245
|
-
return html
|
|
1012
|
+
loadingIcon(size = 21): TemplateResult {
|
|
1013
|
+
return html` <svg
|
|
1246
1014
|
id="loadingIcon"
|
|
1247
|
-
width
|
|
1248
|
-
height
|
|
1015
|
+
width=${size}
|
|
1016
|
+
height=${size}
|
|
1249
1017
|
viewBox="0 0 21 21"
|
|
1250
1018
|
fill="none"
|
|
1251
1019
|
xmlns="http://www.w3.org/2000/svg"
|
|
@@ -1258,75 +1026,277 @@ export class TourScheduler extends LitElement {
|
|
|
1258
1026
|
}
|
|
1259
1027
|
|
|
1260
1028
|
render(): TemplateResult {
|
|
1029
|
+
const isLoading =
|
|
1030
|
+
this.waitingForAvailabilities || this.shouldAllowScheduleLoading;
|
|
1031
|
+
if (!this.shouldAllowScheduling && !isLoading) {
|
|
1032
|
+
return html` <div
|
|
1033
|
+
id="tour-scheduler-inner-form"
|
|
1034
|
+
class="${classnames({
|
|
1035
|
+
"tour-scheduler-full": !this.compactDesign && !isMobile(),
|
|
1036
|
+
"tour-scheduler-compact": this.compactDesign && !isMobile(),
|
|
1037
|
+
"tour-scheduler-mobile": isMobile(),
|
|
1038
|
+
})}"
|
|
1039
|
+
>
|
|
1040
|
+
<div id="top-header">
|
|
1041
|
+
<div></div>
|
|
1042
|
+
${this.closeButton()}
|
|
1043
|
+
</div>
|
|
1044
|
+
<div class="center-tour-not-avail">
|
|
1045
|
+
<h1>Sorry, there are currently no tour availabilities</h1>
|
|
1046
|
+
<p>Please check back again later</p>
|
|
1047
|
+
</div>
|
|
1048
|
+
</div>`;
|
|
1049
|
+
}
|
|
1050
|
+
if (isLoading) {
|
|
1051
|
+
return html` <div
|
|
1052
|
+
id="tour-scheduler-inner-form"
|
|
1053
|
+
class="${classnames({
|
|
1054
|
+
"tour-scheduler-full": !this.compactDesign && !isMobile(),
|
|
1055
|
+
"tour-scheduler-compact": this.compactDesign && !isMobile(),
|
|
1056
|
+
"tour-scheduler-mobile": isMobile(),
|
|
1057
|
+
})}"
|
|
1058
|
+
>
|
|
1059
|
+
<div class="center-tour-not-avail">
|
|
1060
|
+
<h1>Searching for availabilities...</h1>
|
|
1061
|
+
<div class="loading-entire-tour-icon">${this.loadingIcon(48)}</div>
|
|
1062
|
+
</div>
|
|
1063
|
+
</div>`;
|
|
1064
|
+
}
|
|
1065
|
+
if (this.errorGettingAvailabilities) {
|
|
1066
|
+
return html` <div
|
|
1067
|
+
class="${classnames({
|
|
1068
|
+
"tour-scheduler-full": !this.compactDesign && !isMobile(),
|
|
1069
|
+
"tour-scheduler-compact": this.compactDesign && !isMobile(),
|
|
1070
|
+
"tour-scheduler-mobile": isMobile(),
|
|
1071
|
+
})}"
|
|
1072
|
+
>
|
|
1073
|
+
<div id="top-header">
|
|
1074
|
+
<div></div>
|
|
1075
|
+
${this.closeButton()}
|
|
1076
|
+
</div>
|
|
1077
|
+
<div class="center-tour-not-avail">
|
|
1078
|
+
<h1>Sorry, there are currently no tour availabilities!</h1>
|
|
1079
|
+
<p>
|
|
1080
|
+
We apologize, but there are currently no tours available. This could
|
|
1081
|
+
be due to all slots being filled, off-season periods, or
|
|
1082
|
+
maintenance.
|
|
1083
|
+
</p>
|
|
1084
|
+
<p>
|
|
1085
|
+
We understand that this may be disappointing and we apologize for
|
|
1086
|
+
any inconvenience. We recommend checking back soon as our schedule
|
|
1087
|
+
frequently updates.
|
|
1088
|
+
</p>
|
|
1089
|
+
<p>
|
|
1090
|
+
In the meantime, feel free to explore our website for other
|
|
1091
|
+
information and attractions. Thank you for your understanding and
|
|
1092
|
+
patience!
|
|
1093
|
+
</p>
|
|
1094
|
+
</div>
|
|
1095
|
+
</div>`;
|
|
1096
|
+
}
|
|
1261
1097
|
if (!isMobile()) {
|
|
1262
1098
|
return html`
|
|
1263
1099
|
<div
|
|
1264
|
-
class="${classnames(
|
|
1265
|
-
|
|
1100
|
+
class="${classnames({
|
|
1101
|
+
"tour-scheduler-full": !this.compactDesign,
|
|
1102
|
+
"tour-scheduler-compact": this.compactDesign,
|
|
1103
|
+
loading: isLoading,
|
|
1266
1104
|
})}"
|
|
1267
1105
|
@leadsource="${(e: CustomEvent) =>
|
|
1268
1106
|
(this.selectedLeadSource = e.detail.selectedLeadSource)}"
|
|
1269
1107
|
>
|
|
1270
|
-
<
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1108
|
+
<div id="top-header">
|
|
1109
|
+
<h1 id="tour-header-title">
|
|
1110
|
+
${isLoading
|
|
1111
|
+
? html`${this.loadingIcon()} Searching availabilities...`
|
|
1112
|
+
: "Schedule a Tour"}
|
|
1113
|
+
</h1>
|
|
1114
|
+
${this.closeButton()}
|
|
1115
|
+
</div>
|
|
1116
|
+
|
|
1117
|
+
${this.tourIsBooked || this.canceledReschedule
|
|
1277
1118
|
? html`
|
|
1278
1119
|
<div class="tour-scheduler">${this.confirmationMessage()}</div>
|
|
1279
1120
|
`
|
|
1280
|
-
:
|
|
1281
|
-
|
|
1282
|
-
<
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1121
|
+
: this.promptForReschedule
|
|
1122
|
+
? html`
|
|
1123
|
+
<div id="scheduler-container">
|
|
1124
|
+
<div>
|
|
1125
|
+
<h2 class="journey-header">Reschedule Tour</h2>
|
|
1126
|
+
<p class="explanation">
|
|
1127
|
+
You already have a tour scheduled. Would you like to
|
|
1128
|
+
reschedule?
|
|
1129
|
+
</p>
|
|
1130
|
+
</div>
|
|
1131
|
+
</div>
|
|
1132
|
+
<div id="tour-scheduler-footer">
|
|
1133
|
+
<p class="explanation">
|
|
1134
|
+
We'll send a confirmation and any follow-ups to your email
|
|
1135
|
+
address.
|
|
1136
|
+
${disclaimer({
|
|
1137
|
+
buildingName: this.buildingName,
|
|
1138
|
+
phoneNumberInput: this.phoneInput?.value,
|
|
1139
|
+
emailInput: this.emailInput?.value,
|
|
1140
|
+
})}
|
|
1141
|
+
</p>
|
|
1142
|
+
|
|
1143
|
+
<div class="reschedule-buttons-wrapper">
|
|
1144
|
+
<action-confirm-button
|
|
1145
|
+
id="cancel-reschedule-bttn"
|
|
1146
|
+
.onClick=${() => {
|
|
1147
|
+
this.canceledReschedule = true;
|
|
1148
|
+
}}
|
|
1149
|
+
.isLoading=${this.isSubmitting}
|
|
1150
|
+
height="50px"
|
|
1151
|
+
width="145px"
|
|
1152
|
+
text="Cancel"
|
|
1153
|
+
?disabled=${!this.formIsValidForSubmission()}
|
|
1154
|
+
></action-confirm-button>
|
|
1155
|
+
<action-confirm-button
|
|
1156
|
+
id="reschedule-button"
|
|
1157
|
+
.onClick=${this.submit}
|
|
1158
|
+
.isLoading=${this.isSubmitting}
|
|
1159
|
+
height="50px"
|
|
1160
|
+
width="145px"
|
|
1161
|
+
text="Reschedule"
|
|
1162
|
+
?disabled=${!this.formIsValidForSubmission()}
|
|
1163
|
+
></action-confirm-button>
|
|
1164
|
+
</div>
|
|
1165
|
+
</div>
|
|
1166
|
+
`
|
|
1167
|
+
: html`
|
|
1168
|
+
<div id="scheduler-container">
|
|
1169
|
+
<div id="book-tour-journey-items">
|
|
1170
|
+
<div id="tour-type-menu-outer-container">
|
|
1171
|
+
${this.tourTypeMenu()}
|
|
1172
|
+
</div>
|
|
1173
|
+
<div id="date-and-time-menu-outer-container">
|
|
1174
|
+
${this.dateAndTimeMenu()}
|
|
1175
|
+
</div>
|
|
1176
|
+
|
|
1177
|
+
<div id="user-info-and-layout-menu-outer-container">
|
|
1178
|
+
${this.userInfoAndLayoutMenu()}
|
|
1179
|
+
</div>
|
|
1180
|
+
</div>
|
|
1181
|
+
</div>
|
|
1182
|
+
<div id="tour-scheduler-footer">
|
|
1183
|
+
<p class="explanation">
|
|
1184
|
+
We'll send a confirmation and any follow-ups to your email
|
|
1185
|
+
address.
|
|
1186
|
+
${disclaimer({
|
|
1187
|
+
buildingName: this.buildingName,
|
|
1188
|
+
phoneNumberInput: this.phoneInput?.value,
|
|
1189
|
+
emailInput: this.emailInput?.value,
|
|
1190
|
+
})}
|
|
1191
|
+
</p>
|
|
1192
|
+
|
|
1193
|
+
<action-confirm-button
|
|
1194
|
+
id="schedule-bttn"
|
|
1195
|
+
.onClick=${this.submit}
|
|
1196
|
+
.isLoading=${this.isSubmitting}
|
|
1197
|
+
height="50px"
|
|
1198
|
+
width="145px"
|
|
1199
|
+
text="Schedule tour"
|
|
1200
|
+
?disabled=${!this.formIsValidForSubmission()}
|
|
1201
|
+
></action-confirm-button>
|
|
1202
|
+
</div>
|
|
1203
|
+
`}
|
|
1296
1204
|
</div>
|
|
1297
1205
|
`;
|
|
1298
1206
|
} else {
|
|
1299
1207
|
const currentPage = this.mobilePages[this.mobilePageIndex];
|
|
1300
1208
|
return html`
|
|
1301
1209
|
<div
|
|
1302
|
-
class="${classnames("tour-scheduler", {
|
|
1303
|
-
loading:
|
|
1210
|
+
class="${classnames("tour-scheduler-mobile", {
|
|
1211
|
+
loading: isLoading,
|
|
1304
1212
|
})}"
|
|
1305
1213
|
>
|
|
1306
|
-
<div id="
|
|
1214
|
+
<div id="top-header">
|
|
1307
1215
|
<h1 id="scheduleATour">
|
|
1308
|
-
${
|
|
1216
|
+
${isLoading
|
|
1309
1217
|
? html`${this.loadingIcon()} Searching availabilities...`
|
|
1310
1218
|
: "Schedule a tour"}
|
|
1311
1219
|
</h1>
|
|
1312
1220
|
${this.closeButton()}
|
|
1313
1221
|
</div>
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1222
|
+
<div id="mobile-body-container">
|
|
1223
|
+
${this.canceledReschedule
|
|
1224
|
+
? html`
|
|
1225
|
+
<div id="confirmationMessage">
|
|
1226
|
+
<svg
|
|
1227
|
+
width="20"
|
|
1228
|
+
height="20"
|
|
1229
|
+
viewBox="0 0 20 20"
|
|
1230
|
+
fill="none"
|
|
1231
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
1232
|
+
>
|
|
1233
|
+
<path
|
|
1234
|
+
d="M7 0V2H13V0H15V2H19C19.2652 2 19.5196 2.10536 19.7071 2.29289C19.8946 2.48043 20 2.73478 20 3V19C20 19.2652 19.8946 19.5196 19.7071 19.7071C19.5196 19.8946 19.2652 20 19 20H1C0.734784 20 0.48043 19.8946 0.292893 19.7071C0.105357 19.5196 0 19.2652 0 19V3C0 2.73478 0.105357 2.48043 0.292893 2.29289C0.48043 2.10536 0.734784 2 1 2H5V0H7ZM18 9H2V18H18V9ZM13.036 10.136L14.45 11.55L9.5 16.5L5.964 12.964L7.38 11.55L9.501 13.672L13.037 10.136H13.036ZM5 4H2V7H18V4H15V5H13V4H7V5H5V4Z"
|
|
1235
|
+
fill="#202020"
|
|
1236
|
+
/>
|
|
1237
|
+
</svg>
|
|
1238
|
+
<p>Thank you!</p>
|
|
1239
|
+
<p>We'll see you at your originally schedule tour time.</p>
|
|
1240
|
+
</div>
|
|
1241
|
+
`
|
|
1242
|
+
: this.tourIsBooked
|
|
1243
|
+
? this.confirmationMessage()
|
|
1244
|
+
: this.promptForReschedule
|
|
1245
|
+
? html` <div id="scheduler-container">
|
|
1246
|
+
<div>
|
|
1247
|
+
<h2 class="journey-header">Reschedule Tour</h2>
|
|
1248
|
+
<p class="explanation">
|
|
1249
|
+
You already have a tour scheduled. Would you like to
|
|
1250
|
+
reschedule?
|
|
1251
|
+
</p>
|
|
1252
|
+
</div>
|
|
1253
|
+
</div>
|
|
1254
|
+
<div id="tour-scheduler-footer">
|
|
1255
|
+
<div class="reschedule-buttons-wrapper">
|
|
1256
|
+
<action-confirm-button
|
|
1257
|
+
id="cancel-reschedule-bttn"
|
|
1258
|
+
.onClick=${() => {
|
|
1259
|
+
this.canceledReschedule = true;
|
|
1260
|
+
}}
|
|
1261
|
+
.isLoading=${this.isSubmitting}
|
|
1262
|
+
height="50px"
|
|
1263
|
+
width="145px"
|
|
1264
|
+
text="Cancel"
|
|
1265
|
+
?disabled=${!this.formIsValidForSubmission()}
|
|
1266
|
+
></action-confirm-button>
|
|
1267
|
+
<action-confirm-button
|
|
1268
|
+
id="reschedule-button"
|
|
1269
|
+
.onClick=${this.submit}
|
|
1270
|
+
.isLoading=${this.isSubmitting}
|
|
1271
|
+
height="50px"
|
|
1272
|
+
width="145px"
|
|
1273
|
+
text="Reschedule"
|
|
1274
|
+
?disabled=${!this.formIsValidForSubmission()}
|
|
1275
|
+
></action-confirm-button>
|
|
1276
|
+
</div>
|
|
1277
|
+
</div>`
|
|
1278
|
+
: html` ${currentPage.render()}
|
|
1279
|
+
${!currentPage.renderNextButton
|
|
1280
|
+
? html` <button
|
|
1281
|
+
id="mobile-next-bttn"
|
|
1282
|
+
@click=${currentPage.nextButtonAction}
|
|
1283
|
+
?disabled=${(() => {
|
|
1284
|
+
return !currentPage.validate() || isLoading;
|
|
1285
|
+
})()}
|
|
1286
|
+
>
|
|
1287
|
+
${currentPage.nextButtonText}
|
|
1288
|
+
</button>`
|
|
1289
|
+
: currentPage.renderNextButton()}`}
|
|
1290
|
+
${this.mobilePageIndex + 1 === this.mobilePages.length
|
|
1291
|
+
? html`
|
|
1292
|
+
${disclaimer({
|
|
1293
|
+
buildingName: this.buildingName,
|
|
1294
|
+
phoneNumberInput: this.phoneInput?.value,
|
|
1295
|
+
emailInput: this.emailInput?.value,
|
|
1296
|
+
})}
|
|
1297
|
+
`
|
|
1298
|
+
: html``}
|
|
1299
|
+
</div>
|
|
1330
1300
|
</div>
|
|
1331
1301
|
`;
|
|
1332
1302
|
}
|
|
@@ -1353,43 +1323,3 @@ const tourTypeForSubmission = {
|
|
|
1353
1323
|
[TourType.Self]: "self-guided-tour",
|
|
1354
1324
|
[TourType.Virtual]: "live-virtual-tour",
|
|
1355
1325
|
};
|
|
1356
|
-
|
|
1357
|
-
const getLayoutOrder = (layout: string) => {
|
|
1358
|
-
return {
|
|
1359
|
-
studio: 0,
|
|
1360
|
-
"1br": 1,
|
|
1361
|
-
"2br": 2,
|
|
1362
|
-
"3br": 3,
|
|
1363
|
-
"4br": 4,
|
|
1364
|
-
"5br": 5,
|
|
1365
|
-
"6br": 6,
|
|
1366
|
-
"7br": 7,
|
|
1367
|
-
"8br": 8,
|
|
1368
|
-
"9br": 9,
|
|
1369
|
-
"10br": 10,
|
|
1370
|
-
}[layout];
|
|
1371
|
-
};
|
|
1372
|
-
|
|
1373
|
-
const getLayoutFromOrder = (order: number) => {
|
|
1374
|
-
return {
|
|
1375
|
-
0: "studio",
|
|
1376
|
-
1: "1br",
|
|
1377
|
-
2: "2br",
|
|
1378
|
-
3: "3br",
|
|
1379
|
-
4: "4br",
|
|
1380
|
-
5: "5br",
|
|
1381
|
-
6: "6br",
|
|
1382
|
-
7: "7br",
|
|
1383
|
-
8: "8br",
|
|
1384
|
-
9: "9br",
|
|
1385
|
-
10: "10br",
|
|
1386
|
-
}[order];
|
|
1387
|
-
};
|
|
1388
|
-
|
|
1389
|
-
const sortedLayouts = (layouts: string[]) => {
|
|
1390
|
-
const layoutOrder = layouts
|
|
1391
|
-
.map((layout) => getLayoutOrder(layout))
|
|
1392
|
-
.filter(isNumber)
|
|
1393
|
-
.sort();
|
|
1394
|
-
return layoutOrder.map((order) => getLayoutFromOrder(order)).filter(isString);
|
|
1395
|
-
};
|