@meetelise/chat 1.53.6 → 1.54.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/WebComponent/actions/details-window.d.ts +7 -0
- package/dist/src/WebComponent/actions/email-us-window.d.ts +30 -0
- package/dist/src/WebComponent/launcher/Launcher.d.ts +1 -0
- package/dist/src/WebComponent/me-chat.d.ts +1 -0
- package/dist/src/fetchFeatureFlag.d.ts +2 -0
- package/package.json +1 -1
- package/public/dist/index.js +526 -441
- package/src/WebComponent/FeeCalculator/components/charge-inputs/charge-inputs.ts +1 -11
- package/src/WebComponent/actions/details-window.ts +24 -0
- package/src/WebComponent/actions/email-us-window.ts +280 -22
- package/src/WebComponent/launcher/Launcher.ts +3 -0
- package/src/WebComponent/me-chat.ts +7 -0
- package/src/brokerReferralSubmission.test.ts +287 -0
- package/src/fetchFeatureFlag.ts +20 -0
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
import { expect } from "@esm-bundle/chai";
|
|
2
|
+
import { restore, useFakeXMLHttpRequest } from "sinon/pkg/sinon-esm";
|
|
3
|
+
import "../public/dist/index";
|
|
4
|
+
import type { EmailUsWindow } from "./WebComponent/actions/email-us-window";
|
|
5
|
+
|
|
6
|
+
type FakeRequest = XMLHttpRequest & {
|
|
7
|
+
requestBody?: string;
|
|
8
|
+
respond: (
|
|
9
|
+
status: number,
|
|
10
|
+
headers?: Record<string, string>,
|
|
11
|
+
body?: string
|
|
12
|
+
) => void;
|
|
13
|
+
url: string;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const clientFields = {
|
|
17
|
+
firstName: "Cora",
|
|
18
|
+
lastName: "Client",
|
|
19
|
+
email: "cora@example.com",
|
|
20
|
+
phoneNumber: "(312) 555-0100",
|
|
21
|
+
phoneNumberE164: "+13125550100",
|
|
22
|
+
message: "Cora is looking at 2-bedrooms.",
|
|
23
|
+
buildingId: 445038,
|
|
24
|
+
buildingSlug: "test-building",
|
|
25
|
+
orgSlug: "test-org",
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const brokerFields = {
|
|
29
|
+
brokerFirstName: "Bea",
|
|
30
|
+
brokerLastName: "Broker",
|
|
31
|
+
brokerEmail: "bea@realty.example.com",
|
|
32
|
+
brokerFirmName: "Demo Realty",
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const createForm = (fields: Record<string, unknown>): EmailUsWindow => {
|
|
36
|
+
const emailUs = document.createElement("email-us-window") as EmailUsWindow;
|
|
37
|
+
Object.assign(emailUs, clientFields, fields);
|
|
38
|
+
return emailUs;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const captureRequests = (): FakeRequest[] => {
|
|
42
|
+
const fakeXhr = useFakeXMLHttpRequest();
|
|
43
|
+
const requests: FakeRequest[] = [];
|
|
44
|
+
fakeXhr.onCreate = (request: FakeRequest) => requests.push(request);
|
|
45
|
+
return requests;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
afterEach(() => {
|
|
49
|
+
restore();
|
|
50
|
+
window.dataLayer = [];
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it("sends a broker referral with the client as the prospect and the broker fields", async () => {
|
|
54
|
+
const requests = captureRequests();
|
|
55
|
+
const emailUs = createForm({
|
|
56
|
+
brokerIntakeEnabled: true,
|
|
57
|
+
isBrokerReferral: true,
|
|
58
|
+
...brokerFields,
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
const submission = emailUs.onClick();
|
|
62
|
+
|
|
63
|
+
expect(requests).to.have.length(1);
|
|
64
|
+
expect(JSON.parse(requests[0].requestBody ?? "{}")).to.include({
|
|
65
|
+
first_name: "Cora",
|
|
66
|
+
last_name: "Client",
|
|
67
|
+
email_address: "cora@example.com",
|
|
68
|
+
broker_first_name: "Bea",
|
|
69
|
+
broker_last_name: "Broker",
|
|
70
|
+
broker_email: "bea@realty.example.com",
|
|
71
|
+
broker_firm_name: "Demo Realty",
|
|
72
|
+
});
|
|
73
|
+
requests[0].respond(200, { "Content-Type": "application/json" }, "{}");
|
|
74
|
+
await submission;
|
|
75
|
+
|
|
76
|
+
const event = window.dataLayer[window.dataLayer.length - 1];
|
|
77
|
+
expect(event).to.include({
|
|
78
|
+
event: "emailUsSubmitted",
|
|
79
|
+
isBrokerReferral: true,
|
|
80
|
+
});
|
|
81
|
+
expect(JSON.stringify(event)).not.to.contain("bea@realty.example.com");
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it("sends no broker fields when broker intake is off, whatever the form holds", async () => {
|
|
85
|
+
const requests = captureRequests();
|
|
86
|
+
const emailUs = createForm({
|
|
87
|
+
brokerIntakeEnabled: false,
|
|
88
|
+
isBrokerReferral: true,
|
|
89
|
+
...brokerFields,
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
const submission = emailUs.onClick();
|
|
93
|
+
|
|
94
|
+
expect(requests).to.have.length(1);
|
|
95
|
+
const body = JSON.parse(requests[0].requestBody ?? "{}");
|
|
96
|
+
expect(body).not.to.have.any.keys(
|
|
97
|
+
"broker_first_name",
|
|
98
|
+
"broker_last_name",
|
|
99
|
+
"broker_email",
|
|
100
|
+
"broker_firm_name"
|
|
101
|
+
);
|
|
102
|
+
requests[0].respond(200, { "Content-Type": "application/json" }, "{}");
|
|
103
|
+
await submission;
|
|
104
|
+
expect(window.dataLayer[window.dataLayer.length - 1]).not.to.have.property(
|
|
105
|
+
"isBrokerReferral"
|
|
106
|
+
);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it("sends no broker fields when the submitter is not referring a client", async () => {
|
|
110
|
+
const requests = captureRequests();
|
|
111
|
+
const emailUs = createForm({
|
|
112
|
+
brokerIntakeEnabled: true,
|
|
113
|
+
isBrokerReferral: false,
|
|
114
|
+
...brokerFields,
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
const submission = emailUs.onClick();
|
|
118
|
+
|
|
119
|
+
expect(requests).to.have.length(1);
|
|
120
|
+
expect(JSON.parse(requests[0].requestBody ?? "{}")).not.to.have.property(
|
|
121
|
+
"broker_email"
|
|
122
|
+
);
|
|
123
|
+
requests[0].respond(200, { "Content-Type": "application/json" }, "{}");
|
|
124
|
+
await submission;
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it("refuses a referral without a valid broker email", async () => {
|
|
128
|
+
const requests = captureRequests();
|
|
129
|
+
const emailUs = createForm({
|
|
130
|
+
brokerIntakeEnabled: true,
|
|
131
|
+
isBrokerReferral: true,
|
|
132
|
+
...brokerFields,
|
|
133
|
+
brokerEmail: "not-an-email",
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
await emailUs.onClick();
|
|
137
|
+
|
|
138
|
+
expect(requests).to.have.length(0);
|
|
139
|
+
expect(emailUs.brokerEmailError).to.equal("Enter your valid email address");
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it("refuses a referral where the broker entered themselves as the client", async () => {
|
|
143
|
+
const requests = captureRequests();
|
|
144
|
+
const emailUs = createForm({
|
|
145
|
+
brokerIntakeEnabled: true,
|
|
146
|
+
isBrokerReferral: true,
|
|
147
|
+
...brokerFields,
|
|
148
|
+
email: "BEA@realty.example.com",
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
await emailUs.onClick();
|
|
152
|
+
|
|
153
|
+
expect(requests).to.have.length(0);
|
|
154
|
+
expect(emailUs.brokerEmailError).to.equal(
|
|
155
|
+
"Enter your client's details below, not yours"
|
|
156
|
+
);
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it("refuses a referral without the broker's name", async () => {
|
|
160
|
+
const requests = captureRequests();
|
|
161
|
+
const emailUs = createForm({
|
|
162
|
+
brokerIntakeEnabled: true,
|
|
163
|
+
isBrokerReferral: true,
|
|
164
|
+
...brokerFields,
|
|
165
|
+
brokerLastName: " ",
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
await emailUs.onClick();
|
|
169
|
+
|
|
170
|
+
expect(requests).to.have.length(0);
|
|
171
|
+
expect(emailUs.hasBrokerNameError).to.equal(true);
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
it("takes broker details that were autofilled or pasted, not only typed", async () => {
|
|
175
|
+
const emailUs = createForm({ brokerIntakeEnabled: true });
|
|
176
|
+
document.body.appendChild(emailUs);
|
|
177
|
+
await emailUs.updateComplete;
|
|
178
|
+
const checkbox = emailUs.shadowRoot?.querySelector(
|
|
179
|
+
'input[type="checkbox"]'
|
|
180
|
+
) as HTMLInputElement;
|
|
181
|
+
checkbox.click();
|
|
182
|
+
await emailUs.updateComplete;
|
|
183
|
+
|
|
184
|
+
// Autofill and a mouse paste set the value and fire "input", with no key events.
|
|
185
|
+
const fill = (placeholder: string, value: string) => {
|
|
186
|
+
const input = emailUs.shadowRoot?.querySelector(
|
|
187
|
+
`input[placeholder="${placeholder}"]`
|
|
188
|
+
) as HTMLInputElement;
|
|
189
|
+
input.value = value;
|
|
190
|
+
input.dispatchEvent(new Event("input", { bubbles: true, composed: true }));
|
|
191
|
+
};
|
|
192
|
+
fill("Your first name", "Bea");
|
|
193
|
+
fill("Your last name", "Broker");
|
|
194
|
+
fill("Your email", "bea@realty.example.com");
|
|
195
|
+
fill("Brokerage (optional)", "Demo Realty");
|
|
196
|
+
await emailUs.updateComplete;
|
|
197
|
+
|
|
198
|
+
expect(emailUs.brokerFirstName).to.equal("Bea");
|
|
199
|
+
expect(emailUs.brokerLastName).to.equal("Broker");
|
|
200
|
+
expect(emailUs.brokerEmail).to.equal("bea@realty.example.com");
|
|
201
|
+
expect(emailUs.brokerFirmName).to.equal("Demo Realty");
|
|
202
|
+
emailUs.remove();
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
it("moves what a broker typed into their own details when they tick the referral box", async () => {
|
|
206
|
+
const emailUs = document.createElement("email-us-window") as EmailUsWindow;
|
|
207
|
+
Object.assign(emailUs, { brokerIntakeEnabled: true, buildingId: 445038 });
|
|
208
|
+
document.body.appendChild(emailUs);
|
|
209
|
+
await emailUs.updateComplete;
|
|
210
|
+
|
|
211
|
+
const fill = (placeholder: string, value: string) => {
|
|
212
|
+
const input = emailUs.shadowRoot?.querySelector(
|
|
213
|
+
`input[placeholder="${placeholder}"]`
|
|
214
|
+
) as HTMLInputElement;
|
|
215
|
+
input.value = value;
|
|
216
|
+
input.dispatchEvent(new Event("input", { bubbles: true, composed: true }));
|
|
217
|
+
};
|
|
218
|
+
fill("First name", "Bea");
|
|
219
|
+
fill("Last name", "Broker");
|
|
220
|
+
fill("Email", "bea@realty.example.com");
|
|
221
|
+
await emailUs.updateComplete;
|
|
222
|
+
|
|
223
|
+
const checkbox = emailUs.shadowRoot?.querySelector(
|
|
224
|
+
"#broker-referral-toggle"
|
|
225
|
+
) as HTMLInputElement;
|
|
226
|
+
checkbox.click();
|
|
227
|
+
await emailUs.updateComplete;
|
|
228
|
+
|
|
229
|
+
expect(emailUs.brokerFirstName).to.equal("Bea");
|
|
230
|
+
expect(emailUs.brokerLastName).to.equal("Broker");
|
|
231
|
+
expect(emailUs.brokerEmail).to.equal("bea@realty.example.com");
|
|
232
|
+
expect([emailUs.firstName, emailUs.lastName, emailUs.email]).to.deep.equal([
|
|
233
|
+
"",
|
|
234
|
+
"",
|
|
235
|
+
"",
|
|
236
|
+
]);
|
|
237
|
+
const clientFirstName = emailUs.shadowRoot?.querySelector(
|
|
238
|
+
'input[placeholder="Client first name"]'
|
|
239
|
+
) as HTMLInputElement;
|
|
240
|
+
expect(clientFirstName.value).to.equal("");
|
|
241
|
+
|
|
242
|
+
// Unticking before entering a client puts the details back.
|
|
243
|
+
checkbox.click();
|
|
244
|
+
await emailUs.updateComplete;
|
|
245
|
+
expect(emailUs.firstName).to.equal("Bea");
|
|
246
|
+
expect(emailUs.email).to.equal("bea@realty.example.com");
|
|
247
|
+
expect(emailUs.brokerEmail).to.equal("");
|
|
248
|
+
emailUs.remove();
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
it("keeps a filled client when the referral box is unticked and ticked again", async () => {
|
|
252
|
+
const emailUs = document.createElement("email-us-window") as EmailUsWindow;
|
|
253
|
+
Object.assign(emailUs, { brokerIntakeEnabled: true, buildingId: 445038 });
|
|
254
|
+
document.body.appendChild(emailUs);
|
|
255
|
+
await emailUs.updateComplete;
|
|
256
|
+
const checkbox = emailUs.shadowRoot?.querySelector(
|
|
257
|
+
"#broker-referral-toggle"
|
|
258
|
+
) as HTMLInputElement;
|
|
259
|
+
checkbox.click();
|
|
260
|
+
await emailUs.updateComplete;
|
|
261
|
+
Object.assign(emailUs, {
|
|
262
|
+
...brokerFields,
|
|
263
|
+
firstName: "Cora",
|
|
264
|
+
lastName: "Client",
|
|
265
|
+
email: "cora@example.com",
|
|
266
|
+
phoneNumber: "(312) 555-0100",
|
|
267
|
+
phoneNumberE164: "+13125550100",
|
|
268
|
+
});
|
|
269
|
+
await emailUs.updateComplete;
|
|
270
|
+
|
|
271
|
+
checkbox.click();
|
|
272
|
+
await emailUs.updateComplete;
|
|
273
|
+
checkbox.click();
|
|
274
|
+
await emailUs.updateComplete;
|
|
275
|
+
|
|
276
|
+
expect(emailUs.isBrokerReferral).to.equal(true);
|
|
277
|
+
expect([
|
|
278
|
+
emailUs.firstName,
|
|
279
|
+
emailUs.email,
|
|
280
|
+
emailUs.phoneNumberE164,
|
|
281
|
+
]).to.deep.equal(["Cora", "cora@example.com", "+13125550100"]);
|
|
282
|
+
expect([emailUs.brokerFirstName, emailUs.brokerEmail]).to.deep.equal([
|
|
283
|
+
"Bea",
|
|
284
|
+
"bea@realty.example.com",
|
|
285
|
+
]);
|
|
286
|
+
emailUs.remove();
|
|
287
|
+
});
|
package/src/fetchFeatureFlag.ts
CHANGED
|
@@ -136,3 +136,23 @@ export async function fetchTrackedRolloutBedroomPreferenceRequired(
|
|
|
136
136
|
return false;
|
|
137
137
|
}
|
|
138
138
|
}
|
|
139
|
+
|
|
140
|
+
/** Whether the building has broker intake on, so the email form offers the broker referral fields. */
|
|
141
|
+
export async function fetchTrackedRolloutBrokerIntake(
|
|
142
|
+
buildingSlug: string
|
|
143
|
+
): Promise<boolean> {
|
|
144
|
+
if (!buildingSlug) return false;
|
|
145
|
+
try {
|
|
146
|
+
const response = await axios.get(trackedRolloutEndpoint(buildingSlug), {
|
|
147
|
+
params: {
|
|
148
|
+
rollout_name: "broker_intake",
|
|
149
|
+
default_value: false,
|
|
150
|
+
},
|
|
151
|
+
// The widget waits on this with its other startup reads; a slow answer means "off", not a slow widget.
|
|
152
|
+
timeout: 3000,
|
|
153
|
+
});
|
|
154
|
+
return response.data === true;
|
|
155
|
+
} catch (_) {
|
|
156
|
+
return false;
|
|
157
|
+
}
|
|
158
|
+
}
|