@meetelise/chat 1.20.66 → 1.20.67

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.
@@ -21,7 +21,7 @@ import fetchPhoneNumberFromSource, {
21
21
  NumberForSelectedSource,
22
22
  } from "../fetchPhoneNumberFromSource";
23
23
  import { defaultBrandColor, getTheme, Theme } from "../themes";
24
- import { isMobile } from "../utils";
24
+ import { isMobile, sleep } from "../utils";
25
25
  import { installLauncher } from "./launcher/Launcher";
26
26
  import parseISO from "date-fns/parseISO";
27
27
  import isPast from "date-fns/isPast";
@@ -161,12 +161,23 @@ export class MEChat extends LitElement {
161
161
  await this.initializeLaunchJS();
162
162
  this.attachOnClickToLauncher();
163
163
  this.isLoading = false;
164
+ if (localStorage.getItem("overrideContactUsForm") === "true") {
165
+ this
166
+ .overrideContactUsForm
167
+ // {
168
+ // orgSlug: this.orgSlug,
169
+ // buildingSlug: this.buildingSlug,
170
+ // buildingId: this.building?.id ?? null,
171
+ // }
172
+ ();
173
+ }
164
174
  };
165
175
 
166
176
  setBuildingDerivedInfo = async (): Promise<void> => {
167
177
  if (!this.buildingSlug || !this.orgSlug) {
168
178
  return;
169
179
  }
180
+ const beginTime = Date.now(); // used for widget delay
170
181
  const [
171
182
  building,
172
183
  buildingABTest,
@@ -199,6 +210,15 @@ export class MEChat extends LitElement {
199
210
  if (this.buildingABTestType === null) {
200
211
  this.buildingABTestType = webchatPreferences.designConcept ?? null;
201
212
  }
213
+ if (webchatPreferences.delayOpen) {
214
+ // We take into account the time it took to fetch the building info
215
+ const secondsAlreadyPassed = (Date.now() - beginTime) / 1000;
216
+ if (secondsAlreadyPassed < webchatPreferences.delayOpen) {
217
+ await sleep(
218
+ (webchatPreferences.delayOpen - secondsAlreadyPassed) * 1000
219
+ ); // delayOpen is in seconds
220
+ }
221
+ }
202
222
  }
203
223
 
204
224
  if (this.brandColor === null) {
@@ -474,6 +494,10 @@ export class MEChat extends LitElement {
474
494
  const showChatAdditionalActions =
475
495
  this.hideLauncher && !this.isLoading && !this.isMobile;
476
496
 
497
+ if (this.isLoading) {
498
+ return html``;
499
+ }
500
+
477
501
  return html`
478
502
  <meta name="viewport" content="width=device-width, initial-scale=1 user-scalable=1">
479
503
  <div id="aria-describe-info" style="display: none;">
@@ -591,6 +615,147 @@ export class MEChat extends LitElement {
591
615
  this.hasMounted = true;
592
616
  };
593
617
  };
618
+
619
+ private overrideContactUsForm = (): // {
620
+ // orgSlug,
621
+ // buildingSlug,
622
+ // buildingId,
623
+ // }: {
624
+ // orgSlug: MEChat["orgSlug"];
625
+ // buildingSlug: MEChat["buildingSlug"];
626
+ // buildingId: Building["id"] | null;
627
+ // }
628
+ void => {
629
+ const form = document.getElementById(
630
+ "myContactForm"
631
+ ) as HTMLFormElement | null;
632
+ let btn = undefined;
633
+ if (!form || !(form instanceof HTMLFormElement)) {
634
+ // TODO: Add log
635
+ // return console.log("No Contact Us Form Found");
636
+ return;
637
+ }
638
+
639
+ // Loop through the elements of the form
640
+ for (let i = 0; i < form.elements.length; i++) {
641
+ const element = form.elements[i];
642
+ if (
643
+ element.tagName.toLowerCase() === "button" &&
644
+ element.getAttribute("data-selenium-id") === "fakebutton"
645
+ ) {
646
+ btn = element;
647
+ break;
648
+ }
649
+ }
650
+
651
+ if (!btn) {
652
+ // TODO: Add log
653
+ // return console.log('No button with data-selenium-id="fakebutton" found');
654
+ return;
655
+ }
656
+
657
+ // Replace the original form element with the cloned one
658
+ const clonedButton = btn.cloneNode(true) as HTMLButtonElement;
659
+ btn.parentNode?.replaceChild(clonedButton, btn);
660
+ //TODO: Remove textContent after testing
661
+ clonedButton.textContent = "Elise Submit";
662
+
663
+ const eliseUrl =
664
+ "https://app.meetelise.com/platformApi/state/create/contactMe";
665
+
666
+ const getFormElements = () => {
667
+ const firstName = document.getElementById(
668
+ "firstname"
669
+ ) as HTMLInputElement | null;
670
+ const lastName = document.getElementById(
671
+ "lastname"
672
+ ) as HTMLInputElement | null;
673
+ const email = document.getElementById("email") as HTMLInputElement | null;
674
+ const phone = document.getElementById(
675
+ "phonenumber"
676
+ ) as HTMLInputElement | null;
677
+ const message = document.getElementById(
678
+ "message"
679
+ ) as HTMLTextAreaElement | null;
680
+
681
+ const formElements = { firstName, lastName, email, phone, message };
682
+
683
+ if (Object.values(formElements).some((el) => el === null)) {
684
+ // console.log("Form is missing elements");
685
+ // TODO: Add logger to log that form scraper is boken on el.name in current route or buildingId
686
+ }
687
+
688
+ return formElements;
689
+ };
690
+ const getFormValues = () => {
691
+ const formValues: { [key: string]: string | undefined } = {};
692
+ Object.entries(getFormElements()).forEach(
693
+ ([key, val]) => (formValues[key] = val?.value)
694
+ );
695
+ return formValues;
696
+ };
697
+
698
+ const isValid = () => {
699
+ return Object.values(getFormElements()).every((el) => {
700
+ if (el === null) return false;
701
+ //TODO: May need to not depend on aria-invalid
702
+ return el.getAttribute("aria-invalid") !== "true";
703
+ });
704
+ };
705
+
706
+ clonedButton.onclick = function (event) {
707
+ if (!isValid()) return;
708
+ event.preventDefault();
709
+ const formValues = getFormValues();
710
+
711
+ const data = {
712
+ email_address: formValues.email,
713
+ first_name: formValues.firstName,
714
+ last_name: formValues.lastName,
715
+ phone_number: formValues.phone,
716
+ first_message: formValues.message,
717
+
718
+ //TODO: Replace after testing is done
719
+ building_id: 3660,
720
+ };
721
+
722
+ // Convert the data object to a JSON string
723
+ const jsonData = JSON.stringify(data);
724
+
725
+ fetch(eliseUrl, {
726
+ method: "POST",
727
+ headers: {
728
+ "Content-Type": "application/json",
729
+ "building-slug": "e2e-test-yardi-building",
730
+ "org-slug": "test-company",
731
+ //TODO: Replace org and building slugs
732
+ },
733
+ body: jsonData,
734
+ }).then((response) => {
735
+ // TODO: What's needed here?
736
+ // console.log(response);
737
+ // Check if the request was successful
738
+ if (!response.ok) {
739
+ throw new Error(`HTTP error ${response.status}`);
740
+ }
741
+
742
+ form.reset();
743
+
744
+ // Parse the response as JSON
745
+ return response.json();
746
+ });
747
+ // .then((responseData) => {
748
+ // // Handle the JSON response data
749
+ // // TODO: What's needed here?
750
+ // // console.log("Response data:", responseData);
751
+ // })
752
+ // .catch((error) => {
753
+ // // Handle any errors that occurred during the request
754
+ // // TODO: What's needed here?
755
+ // // console.error("Error:", error);
756
+ // });
757
+ };
758
+ };
594
759
  }
595
760
 
596
761
  declare global {
package/src/utils.ts CHANGED
@@ -78,3 +78,7 @@ export const hexToAlmostWhite = (hexColor: string, ratio: number): string => {
78
78
  b.toString(16).padStart(2, "0")
79
79
  );
80
80
  };
81
+
82
+ export const sleep = (ms: number): Promise<void> => {
83
+ return new Promise((resolve) => setTimeout(resolve, ms));
84
+ };