@meetelise/chat 1.12.1 → 1.12.4

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.
@@ -18,8 +18,6 @@ export class TourTypeOption extends LitElement {
18
18
 
19
19
  static styles = [
20
20
  css`
21
- @import url("https://fonts.googleapis.com/css2?family=Poppins:wght@400;600;700;900&display=swap");
22
-
23
21
  .tour-type-option {
24
22
  height: 90px;
25
23
  width: 200px;
@@ -40,7 +38,6 @@ export class TourTypeOption extends LitElement {
40
38
  display: flex;
41
39
  align-items: center;
42
40
  justify-content: center;
43
- /* TODO: may need to use grid, or something else, to get the icons/text to align */
44
41
  gap: 15px;
45
42
  width: 100%;
46
43
  position: absolute;
@@ -5,7 +5,6 @@ import { customElement, property } from "lit/decorators.js";
5
5
  export class ActionConfirmButton extends LitElement {
6
6
  static styles = [
7
7
  css`
8
- @import url("https://fonts.googleapis.com/css2?family=Poppins:wght@400;600;700;900&display=swap");
9
8
  .action-confirm-button {
10
9
  background: #1e1e1e;
11
10
  border: 2px solid #ffffff;
@@ -20,6 +20,11 @@ export class CallUsWindow extends LitElement {
20
20
  line-height: 24px;
21
21
  }
22
22
 
23
+ .call-us-window__call-us-text > a {
24
+ color: unset;
25
+ text-decoration: none;
26
+ }
27
+
23
28
  .call-us-window__office-hours-header {
24
29
  text-decoration: underline;
25
30
  font-size: 12px;
@@ -65,6 +70,21 @@ export class CallUsWindow extends LitElement {
65
70
  | { dayOfWeek: string; startTime: string; endTime: string }
66
71
  )[] = [];
67
72
 
73
+ getCallLink = (phoneNumber: string): TemplateResult => {
74
+ const rawNumber = (phoneNumber.match(/\d+/g) || []).join("");
75
+ const rawInternationalNumber =
76
+ rawNumber.length < 11 ? `1${rawNumber}` : rawNumber;
77
+ const formattedInternationalNumber = `+${
78
+ rawInternationalNumber[0]
79
+ }-${rawInternationalNumber.slice(1, 4)}-${rawInternationalNumber.slice(
80
+ 4,
81
+ 7
82
+ )}-${rawInternationalNumber.slice(7)}`;
83
+ return html`<a href="tel:${formattedInternationalNumber}"
84
+ >${phoneNumber}</a
85
+ >`;
86
+ };
87
+
68
88
  render = (): TemplateResult => {
69
89
  return html`
70
90
  <details-window
@@ -74,7 +94,9 @@ export class CallUsWindow extends LitElement {
74
94
  >
75
95
  <div class="call-us-window__content-wrapper">
76
96
  <div class="call-us-window__call-us-text">
77
- Contact our leasing team at <br />${this.phoneNumber}
97
+ Contact our leasing team at <br />${this.getCallLink(
98
+ this.phoneNumber
99
+ )}
78
100
  </div>
79
101
  <div class="call-us-window__office-hours-wrapper">
80
102
  <div class="call-us-window__office-hours-header">Office hours</div>
@@ -6,7 +6,6 @@ import { isMobile } from "../../utils";
6
6
  @customElement("details-window")
7
7
  export class DetailsWindow extends LitElement {
8
8
  static styles = css`
9
- @import url("https://fonts.googleapis.com/css2?family=Poppins:wght@400;600;700;900&display=swap");
10
9
  .details-window-wrapper {
11
10
  background: rgba(255, 255, 255, 0.75);
12
11
  box-shadow: 0px 0px 14px 5px rgba(0, 0, 0, 0.25);
@@ -16,7 +16,6 @@ import axios from "axios";
16
16
  export class EmailUsWindow extends LitElement {
17
17
  static styles = [
18
18
  css`
19
- @import url("https://fonts.googleapis.com/css2?family=Poppins:wght@400;600;700;900&display=swap");
20
19
  .email-us__name-input {
21
20
  width: 134px;
22
21
  height: 49px;
@@ -1,7 +1,6 @@
1
1
  import { css } from "lit";
2
2
 
3
3
  export const InputStyles = css`
4
- @import url("https://fonts.googleapis.com/css2?family=Poppins:wght@400;600;700;900&display=swap");
5
4
  .webchat-input {
6
5
  border: 1px solid #83818e;
7
6
  outline: none;
@@ -16,7 +16,6 @@ import axios from "axios";
16
16
  export class TextUsWindow extends LitElement {
17
17
  static styles = [
18
18
  css`
19
- @import url("https://fonts.googleapis.com/css2?family=Poppins:wght@400;600;700;900&display=swap");
20
19
  .text-us-wrapper {
21
20
  font-family: "Poppins";
22
21
  color: #202020;
@@ -3,18 +3,18 @@
3
3
  */
4
4
  export const formatToPhone = (phoneNumber: string): string => {
5
5
  const input = phoneNumber.replace(/\D/g, "").substring(0, 10);
6
- const zip = input.substring(0, 3);
6
+ const areaCode = input.substring(0, 3);
7
7
  const middle = input.substring(3, 6);
8
8
  const last = input.substring(6, 10);
9
9
 
10
- if (input.length > 6) {
11
- return `(${zip}) ${middle}-${last}`;
10
+ if (input.length > 5) {
11
+ return `(${areaCode}) ${middle}-${last}`;
12
12
  }
13
- if (input.length > 3) {
14
- return `(${zip}) ${middle}`;
13
+ if (input.length > 2) {
14
+ return `(${areaCode}) ${middle}`;
15
15
  }
16
16
  if (input.length > 0) {
17
- return `(${zip}`;
17
+ return `(${areaCode}`;
18
18
  }
19
19
  return "";
20
20
  };
@@ -24,11 +24,22 @@ export const isNumericInput = (event: KeyboardEvent): boolean => {
24
24
  return (key >= 48 && key <= 57) || (key >= 96 && key <= 105);
25
25
  };
26
26
 
27
+ export const isPrintableCharacter = (event: KeyboardEvent): boolean =>
28
+ event.key.length === 1;
29
+
30
+ /** Returns true if any key is pressed whose only function when typing text would be as part of a keyboard shortcut.
31
+ * For example, `Shift` or `f` would not suffice, because these are used for typing text.
32
+ * But `Command` or `Control` would.
33
+ */
34
+ export const shortcutKeyIsPressed = (event: KeyboardEvent): boolean =>
35
+ event.altKey || event.ctrlKey || event.metaKey;
36
+
27
37
  export const isModifierKey = (event: KeyboardEvent): boolean => {
28
38
  const key = event.keyCode;
29
- // Allow left, up, right, down, Backspace, Tab, Enter, Delete, Ctrl/Command + A,C,V,X,Z, Shift, Home, End
39
+ // TODO: whitelisting specific keyboard shortcuts is brittle (e.g. this is missing Cmd + R to reload)
40
+ // Allow left, up, right, down, Backspace, Tab, Enter, Delete, Ctrl/Command + A,C,L,V,X,Z, Shift, Home, End
30
41
  return (
31
- event.shiftKey === true ||
42
+ event.shiftKey ||
32
43
  key === 35 ||
33
44
  key === 36 || // Allow
34
45
  key === 8 ||
@@ -36,7 +47,12 @@ export const isModifierKey = (event: KeyboardEvent): boolean => {
36
47
  key === 13 ||
37
48
  key === 46 ||
38
49
  (key > 36 && key < 41) ||
39
- ((event.ctrlKey === true || event.metaKey === true) &&
40
- (key === 65 || key === 67 || key === 86 || key === 88 || key === 90))
50
+ ((event.ctrlKey || event.metaKey) &&
51
+ (key === 65 ||
52
+ key === 67 ||
53
+ key === 76 ||
54
+ key === 86 ||
55
+ key === 88 ||
56
+ key === 90))
41
57
  );
42
58
  };
@@ -1,7 +1,6 @@
1
1
  import { css } from "lit";
2
2
 
3
- export const inHousLauncherStyles = css`
4
- @import url("https://fonts.googleapis.com/css2?family=Poppins:wght@400;600;700;900&display=swap");
3
+ export const inHouseLauncherStyles = css`
5
4
  :host {
6
5
  --glowBarHeight: 11.2px;
7
6
  --enterAnimationDuration: 0.5s;
@@ -1,3 +1,8 @@
1
+ export interface LabeledOption {
2
+ label: string;
3
+ value: string | number;
4
+ }
5
+
1
6
  /**
2
7
  * The response from the API.
3
8
  */
@@ -15,6 +20,8 @@ export interface Building {
15
20
  conversationMaintenanceMode: boolean;
16
21
  orgId: number;
17
22
  phoneNumber: string;
23
+ layoutOptions: LabeledOption[];
24
+ tourTypeOptions: LabeledOption[];
18
25
  }
19
26
 
20
27
  /**
@@ -69,3 +69,13 @@ export const getAvailabilitiesGroupedByDay = async (
69
69
  (startTime) => format(startTime, "yyyy-MM-dd")
70
70
  );
71
71
  };
72
+
73
+ // TODO: if cache is empty, observe it and wait for it to be filled in.
74
+ // TODO: alternative to this: cache the building id when getRawAvailabilities is called. Then I can call the normal methods.
75
+ export const getAvailabilitiesGroupedByDayCached = async (
76
+ tourType: TourAvailabilityResponseRankOrderedSupportedTourTypesEnum
77
+ ): ReturnType<typeof getAvailabilitiesGroupedByDay> =>
78
+ getAvailabilitiesGroupedByDay(
79
+ Object.keys(availabilitiesCache).map(Number)[0],
80
+ tourType
81
+ );
@@ -0,0 +1,56 @@
1
+ import axios from "axios";
2
+
3
+ export interface ManagementSmsNumber {
4
+ id: number;
5
+ userId: number;
6
+ timeCreated: string;
7
+ active: number;
8
+ phoneNumber: string;
9
+ phoneNumberType: string;
10
+ description: string;
11
+ api: string;
12
+ buildingIds: number[];
13
+ source: string;
14
+ deleted: number;
15
+ buildingGroupId: number;
16
+ ivrRecordLink: number;
17
+ ivrFlowType: number;
18
+ numberToForwardTo: string | null;
19
+ customTimeout: number;
20
+ customOptionsRecording: string | null;
21
+ customOptionsUrl: string | null;
22
+ voiceMailRecipient: string | null;
23
+ callCenterNumber: string | null;
24
+ initialPauseInSeconds: number;
25
+ voiceUrl: string;
26
+ alternativeBuildingId: string | null;
27
+ timezone: string | null;
28
+ buildingId: number;
29
+ ivrFlowConfiguration: {
30
+ flowName: string;
31
+ callCenterNumber: string;
32
+ leasingOfficeNumber: string;
33
+ marketingSourceCallCenterNumber: string | null;
34
+ globalCallCenterNumber: string | null;
35
+ buildingIntroMp3Url: string | null;
36
+ buildingOptionsMp3Url: string | null;
37
+ textYouShortlyMp3Url: string | null;
38
+ };
39
+ v2Number: boolean;
40
+ }
41
+
42
+ const registeredPhoneNumbersCache: {
43
+ [buildingId: number]: ManagementSmsNumber[];
44
+ } = {};
45
+
46
+ export const getRegisteredPhoneNumbers = async (
47
+ buildingId: number
48
+ ): Promise<ManagementSmsNumber[]> => {
49
+ if (registeredPhoneNumbersCache[buildingId]) {
50
+ return registeredPhoneNumbersCache[buildingId];
51
+ }
52
+ const url = `http://ivr.internal-meetelise.com/sms_management_numbers/webchat/building/${buildingId}/numbers`;
53
+ const result = await axios.get<ManagementSmsNumber[]>(url);
54
+ registeredPhoneNumbersCache[buildingId] = result.data;
55
+ return result.data;
56
+ };