Skip to content

Commit 12f56e6

Browse files
authored
Merge pull request #380 from 4site-interactive-studios/fresh-address-proxy
Add option for using a proxy to AtData Safe To Send API for FreshAddress Component
2 parents 8e97b73 + ba36452 commit 12f56e6

5 files changed

Lines changed: 166 additions & 6 deletions

File tree

packages/scripts/dist/freshaddress.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,6 @@ export declare class FreshAddress {
1515
private callAPI;
1616
private validateResponse;
1717
private validate;
18+
private callProxy;
19+
private validateProxyResponse;
1820
}

packages/scripts/dist/freshaddress.js

Lines changed: 76 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { ENGrid, EngridLogger } from ".";
99
import { EnForm } from "./events";
1010
export class FreshAddress {
1111
constructor() {
12+
var _a;
1213
this.form = EnForm.getInstance();
1314
this.emailField = null;
1415
this.emailWrapper = document.querySelector(".en__field--emailAddress");
@@ -18,8 +19,10 @@ export class FreshAddress {
1819
this.logger = new EngridLogger("FreshAddress", "#039bc4", "#dfdfdf", "📧");
1920
this.shouldRun = true;
2021
this.options = ENGrid.getOption("FreshAddress");
21-
if (this.options === false || !window.FreshAddress)
22+
if (this.options === false ||
23+
(!window.FreshAddress && !((_a = this.options) === null || _a === void 0 ? void 0 : _a.proxyUrl))) {
2224
return;
25+
}
2326
this.emailField = document.getElementById("en__field_supporter_emailAddress");
2427
if (this.emailField) {
2528
this.createFields();
@@ -89,7 +92,12 @@ export class FreshAddress {
8992
return;
9093
}
9194
this.logger.log("Validating " + ((_b = this.emailField) === null || _b === void 0 ? void 0 : _b.value));
92-
this.callAPI();
95+
if (this.options && this.options.proxyUrl) {
96+
this.callProxy();
97+
}
98+
else {
99+
this.callAPI();
100+
}
93101
});
94102
// Add event listener to submit
95103
this.form.onValidate.subscribe(this.validate.bind(this));
@@ -192,7 +200,7 @@ export class FreshAddress {
192200
else if (this.faStatus.value === "Invalid") {
193201
this.form.validate = false;
194202
window.setTimeout(() => {
195-
ENGrid.setError(this.emailWrapper, this.faMessage.value);
203+
ENGrid.setError(this.emailWrapper, "This email address is not valid.");
196204
}, 100);
197205
(_a = this.emailField) === null || _a === void 0 ? void 0 : _a.focus();
198206
ENGrid.enableSubmit();
@@ -201,4 +209,69 @@ export class FreshAddress {
201209
this.form.validate = true;
202210
return true;
203211
}
212+
callProxy() {
213+
var _a;
214+
if (!this.options || !this.shouldRun)
215+
return;
216+
window.FreshAddressStatus = "validating";
217+
ENGrid.disableSubmit("Validating Email Address...");
218+
fetch(this.options.proxyUrl, {
219+
method: "POST",
220+
headers: {
221+
"Content-Type": "application/json",
222+
},
223+
body: JSON.stringify({ email: (_a = this.emailField) === null || _a === void 0 ? void 0 : _a.value }),
224+
signal: AbortSignal.timeout(5000),
225+
})
226+
.then((response) => {
227+
if (!response.ok) {
228+
throw new Error(`HTTP error ${response.status}`);
229+
}
230+
return response.json();
231+
})
232+
.then((data) => {
233+
this.logger.log("Proxy API Response", data);
234+
this.validateProxyResponse(data);
235+
})
236+
.catch((error) => {
237+
if (error.name === "AbortError") {
238+
this.logger.log("Proxy API request timed out");
239+
this.writeToFields("Request Timeout", "The request took too long.");
240+
}
241+
else {
242+
this.logger.log("Proxy API Error", error);
243+
this.writeToFields("Service Error", error.toString());
244+
}
245+
})
246+
.finally(() => {
247+
window.FreshAddressStatus = "idle";
248+
ENGrid.enableSubmit();
249+
});
250+
}
251+
/*
252+
* Validate a request proxied to AtData's Safe To Send API.
253+
* https://docs.atdata.com/reference/safe-to-send
254+
* https://docs.atdata.com/reference/email-status
255+
* https://docs.atdata.com/reference/status-codes-safe-to-send
256+
*/
257+
validateProxyResponse(data) {
258+
var _a;
259+
// If response is not in expected format, log error and let through.
260+
if (!data.safe_to_send) {
261+
this.logger.log("Invalid Proxy Response");
262+
this.writeToFields("Service Error", "Invalid Proxy Response");
263+
return true;
264+
}
265+
const res = data.safe_to_send;
266+
ENGrid.removeError(this.emailWrapper);
267+
this.writeToFields(res.status, res.status_code);
268+
if (["invalid", "trap"].includes(res.status)) {
269+
this.writeToFields("Invalid", res.status_code); // Must be "Invalid" to trigger validation error on submit
270+
ENGrid.setError(this.emailWrapper, "This email address is not valid.");
271+
(_a = this.emailField) === null || _a === void 0 ? void 0 : _a.focus();
272+
if (res.email_corrections && res.email_corrections.length > 0) {
273+
ENGrid.setError(this.emailWrapper, `This email address is not valid. Did you mean ${res.email_corrections[0]}?`);
274+
}
275+
}
276+
}
204277
}

packages/scripts/dist/interfaces/options.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ export interface Options {
2828
dateFieldFormat?: string;
2929
statusField?: string;
3030
messageField?: string;
31+
proxyUrl?: string;
3132
};
3233
ProgressBar?: boolean | null;
3334
AutoYear?: boolean;

packages/scripts/src/freshaddress.ts

Lines changed: 86 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,12 @@ export class FreshAddress {
3030

3131
constructor() {
3232
this.options = ENGrid.getOption("FreshAddress") as Options["FreshAddress"];
33-
if (this.options === false || !window.FreshAddress) return;
33+
if (
34+
this.options === false ||
35+
(!window.FreshAddress && !this.options?.proxyUrl)
36+
) {
37+
return;
38+
}
3439
this.emailField = document.getElementById(
3540
"en__field_supporter_emailAddress"
3641
) as HTMLInputElement;
@@ -111,7 +116,12 @@ export class FreshAddress {
111116
return;
112117
}
113118
this.logger.log("Validating " + this.emailField?.value);
114-
this.callAPI();
119+
120+
if (this.options && this.options.proxyUrl) {
121+
this.callProxy();
122+
} else {
123+
this.callAPI();
124+
}
115125
});
116126

117127
// Add event listener to submit
@@ -135,6 +145,7 @@ export class FreshAddress {
135145
}
136146
);
137147
}
148+
138149
private validateResponse(data: any) {
139150
/* ERROR HANDLING: Let through in case of a service error. Enable form submission. */
140151
if (data.isServiceError()) {
@@ -188,6 +199,7 @@ export class FreshAddress {
188199
window.FreshAddressStatus = "idle";
189200
ENGrid.enableSubmit();
190201
}
202+
191203
private validate() {
192204
ENGrid.removeError(this.emailWrapper);
193205
if (!this.form.validate) return;
@@ -220,7 +232,7 @@ export class FreshAddress {
220232
} else if (this.faStatus!.value === "Invalid") {
221233
this.form.validate = false;
222234
window.setTimeout(() => {
223-
ENGrid.setError(this.emailWrapper, this.faMessage!.value);
235+
ENGrid.setError(this.emailWrapper, "This email address is not valid.");
224236
}, 100);
225237
this.emailField?.focus();
226238
ENGrid.enableSubmit();
@@ -229,4 +241,75 @@ export class FreshAddress {
229241
this.form.validate = true;
230242
return true;
231243
}
244+
245+
private callProxy() {
246+
if (!this.options || !this.shouldRun) return;
247+
248+
window.FreshAddressStatus = "validating";
249+
ENGrid.disableSubmit("Validating Email Address...");
250+
251+
fetch(this.options!.proxyUrl!, {
252+
method: "POST",
253+
headers: {
254+
"Content-Type": "application/json",
255+
},
256+
body: JSON.stringify({ email: this.emailField?.value }),
257+
signal: AbortSignal.timeout(5000),
258+
})
259+
.then((response) => {
260+
if (!response.ok) {
261+
throw new Error(`HTTP error ${response.status}`);
262+
}
263+
return response.json();
264+
})
265+
.then((data) => {
266+
this.logger.log("Proxy API Response", data);
267+
this.validateProxyResponse(data);
268+
})
269+
.catch((error) => {
270+
if (error.name === "AbortError") {
271+
this.logger.log("Proxy API request timed out");
272+
this.writeToFields("Request Timeout", "The request took too long.");
273+
} else {
274+
this.logger.log("Proxy API Error", error);
275+
this.writeToFields("Service Error", error.toString());
276+
}
277+
})
278+
.finally(() => {
279+
window.FreshAddressStatus = "idle";
280+
ENGrid.enableSubmit();
281+
});
282+
}
283+
284+
/*
285+
* Validate a request proxied to AtData's Safe To Send API.
286+
* https://docs.atdata.com/reference/safe-to-send
287+
* https://docs.atdata.com/reference/email-status
288+
* https://docs.atdata.com/reference/status-codes-safe-to-send
289+
*/
290+
private validateProxyResponse(data: any) {
291+
// If response is not in expected format, log error and let through.
292+
if (!data.safe_to_send) {
293+
this.logger.log("Invalid Proxy Response");
294+
this.writeToFields("Service Error", "Invalid Proxy Response");
295+
return true;
296+
}
297+
298+
const res = data.safe_to_send;
299+
300+
ENGrid.removeError(this.emailWrapper);
301+
this.writeToFields(res.status, res.status_code);
302+
303+
if (["invalid", "trap"].includes(res.status)) {
304+
this.writeToFields("Invalid", res.status_code); // Must be "Invalid" to trigger validation error on submit
305+
ENGrid.setError(this.emailWrapper, "This email address is not valid.");
306+
this.emailField?.focus();
307+
if (res.email_corrections && res.email_corrections.length > 0) {
308+
ENGrid.setError(
309+
this.emailWrapper,
310+
`This email address is not valid. Did you mean ${res.email_corrections[0]}?`
311+
);
312+
}
313+
}
314+
}
232315
}

packages/scripts/src/interfaces/options.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ export interface Options {
3030
dateFieldFormat?: string;
3131
statusField?: string;
3232
messageField?: string;
33+
proxyUrl?: string;
3334
};
3435
ProgressBar?: boolean | null;
3536
AutoYear?: boolean;

0 commit comments

Comments
 (0)