@4site/engrid-scripts 0.23.4 → 0.23.6

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.
@@ -3,17 +3,24 @@ export declare class DataLayer {
3
3
  private dataLayer;
4
4
  private _form;
5
5
  private static instance;
6
+ private encoder;
6
7
  private endOfGiftProcessStorageKey;
7
8
  private excludedFields;
8
9
  private hashedFields;
10
+ private retainedEmailField;
11
+ private retainedAddressFields;
12
+ private retainedPhoneFields;
9
13
  constructor();
10
14
  static getInstance(): DataLayer;
11
15
  private transformJSON;
12
16
  private onLoad;
17
+ private addRetainedHashesToDataLayer;
13
18
  private onSubmit;
14
19
  private attachEventListeners;
15
20
  private handleFieldValueChange;
21
+ private geRetainedFieldsValue;
16
22
  private hash;
23
+ private shaHash;
17
24
  private getFieldLabel;
18
25
  addEndOfGiftProcessEvent(eventName: string, eventProperties?: object): void;
19
26
  addEndOfGiftProcessVariable(variableName: string, variableValue?: any): void;
@@ -7,12 +7,22 @@
7
7
  // are replayed after a successful gift process load.
8
8
  // Sensitive payment/bank fields are excluded; selected PII fields are Base64 “hashed” (btoa — not cryptographic).
9
9
  // Replace with a real hash (e.g., SHA‑256) if required.
10
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
11
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
12
+ return new (P || (P = Promise))(function (resolve, reject) {
13
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
14
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
15
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
16
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
17
+ });
18
+ };
10
19
  import { EngridLogger, ENGrid, EnForm, RememberMeEvents } from ".";
11
20
  export class DataLayer {
12
21
  constructor() {
13
22
  this.logger = new EngridLogger("DataLayer", "#f1e5bc", "#009cdc", "📊");
14
23
  this.dataLayer = window.dataLayer || [];
15
24
  this._form = EnForm.getInstance();
25
+ this.encoder = new TextEncoder();
16
26
  this.endOfGiftProcessStorageKey = "ENGRID_END_OF_GIFT_PROCESS_EVENTS";
17
27
  this.excludedFields = [
18
28
  // Credit Card
@@ -45,6 +55,16 @@ export class DataLayer {
45
55
  "supporter.billingAddress2",
46
56
  "supporter.billingAddress3",
47
57
  ];
58
+ this.retainedEmailField = "supporter.emailAddress";
59
+ this.retainedAddressFields = [
60
+ "supporter.address1",
61
+ "supporter.address2",
62
+ "supporter.address3",
63
+ ];
64
+ this.retainedPhoneFields = [
65
+ "supporter.phoneNumber2",
66
+ "supporter.phoneNumber",
67
+ ];
48
68
  if (ENGrid.getOption("RememberMe")) {
49
69
  RememberMeEvents.getInstance().onLoad.subscribe((hasData) => {
50
70
  this.logger.log("Remember me - onLoad", hasData);
@@ -102,6 +122,7 @@ export class DataLayer {
102
122
  dataLayerData[`EN_URLPARAM_${key.toUpperCase()}`] =
103
123
  this.transformJSON(value);
104
124
  });
125
+ this.addRetainedHashesToDataLayer(dataLayerData);
105
126
  if (ENGrid.getPageType() === "DONATION") {
106
127
  const recurrFreqEls = document.querySelectorAll('[name="transaction.recurrfreq"]');
107
128
  const recurrValues = [...recurrFreqEls].map((el) => el.value);
@@ -114,6 +135,18 @@ export class DataLayer {
114
135
  }
115
136
  this.attachEventListeners();
116
137
  }
138
+ addRetainedHashesToDataLayer(dataLayerData) {
139
+ if (typeof window === "undefined" || !window.localStorage) {
140
+ return;
141
+ }
142
+ ["EMAIL", "ADDRESS", "PHONE"].forEach((suffix) => {
143
+ const storageKey = `EN_HASH_${suffix}`;
144
+ const storedValue = window.localStorage.getItem(storageKey);
145
+ if (storedValue) {
146
+ dataLayerData[storageKey] = storedValue;
147
+ }
148
+ });
149
+ }
117
150
  onSubmit() {
118
151
  const optIn = document.querySelector(".en__field__item:not(.en__field--question) input[name^='supporter.questions'][type='checkbox']:checked");
119
152
  if (optIn) {
@@ -151,45 +184,118 @@ export class DataLayer {
151
184
  }
152
185
  handleFieldValueChange(el) {
153
186
  var _a, _b, _c;
154
- if (el.value === "" || this.excludedFields.includes(el.name))
155
- return;
156
- const value = this.hashedFields.includes(el.name)
157
- ? this.hash(el.value)
158
- : el.value;
159
- if (["checkbox", "radio"].includes(el.type)) {
160
- if (el.checked) {
161
- if (el.name === "en__pg") {
162
- //Premium gift handling
163
- this.dataLayer.push({
164
- event: "EN_FORM_VALUE_UPDATED",
165
- enFieldName: el.name,
166
- enFieldLabel: "Premium Gift",
167
- enFieldValue: (_b = (_a = el
168
- .closest(".en__pg__body")) === null || _a === void 0 ? void 0 : _a.querySelector(".en__pg__name")) === null || _b === void 0 ? void 0 : _b.textContent,
169
- enProductId: (_c = document.querySelector('[name="transaction.selprodvariantid"]')) === null || _c === void 0 ? void 0 : _c.value,
170
- });
171
- }
172
- else {
173
- this.dataLayer.push({
174
- event: "EN_FORM_VALUE_UPDATED",
175
- enFieldName: el.name,
176
- enFieldLabel: this.getFieldLabel(el),
177
- enFieldValue: value,
178
- });
187
+ return __awaiter(this, void 0, void 0, function* () {
188
+ if (el.value === "" || this.excludedFields.includes(el.name))
189
+ return;
190
+ const value = this.hashedFields.includes(el.name)
191
+ ? this.hash(el.value)
192
+ : el.value;
193
+ if (["checkbox", "radio"].includes(el.type)) {
194
+ if (el.checked) {
195
+ if (el.name === "en__pg") {
196
+ //Premium gift handling
197
+ this.dataLayer.push({
198
+ event: "EN_FORM_VALUE_UPDATED",
199
+ enFieldName: el.name,
200
+ enFieldLabel: "Premium Gift",
201
+ enFieldValue: (_b = (_a = el
202
+ .closest(".en__pg__body")) === null || _a === void 0 ? void 0 : _a.querySelector(".en__pg__name")) === null || _b === void 0 ? void 0 : _b.textContent,
203
+ enProductId: (_c = document.querySelector('[name="transaction.selprodvariantid"]')) === null || _c === void 0 ? void 0 : _c.value,
204
+ });
205
+ }
206
+ else {
207
+ this.dataLayer.push({
208
+ event: "EN_FORM_VALUE_UPDATED",
209
+ enFieldName: el.name,
210
+ enFieldLabel: this.getFieldLabel(el),
211
+ enFieldValue: value,
212
+ });
213
+ }
179
214
  }
215
+ return;
180
216
  }
181
- return;
182
- }
183
- this.dataLayer.push({
184
- event: "EN_FORM_VALUE_UPDATED",
185
- enFieldName: el.name,
186
- enFieldLabel: this.getFieldLabel(el),
187
- enFieldValue: value,
217
+ if (el.name === this.retainedEmailField) {
218
+ const retainedEmailValue = this.geRetainedFieldsValue("email");
219
+ const sha256value = yield this.shaHash(retainedEmailValue);
220
+ localStorage.setItem(`EN_HASH_EMAIL`, sha256value);
221
+ this.dataLayer.push({
222
+ event: "EN_HASH_VALUE_UPDATED",
223
+ enFieldName: "email",
224
+ enFieldLabel: this.getFieldLabel(el),
225
+ enFieldValue: sha256value,
226
+ });
227
+ return;
228
+ }
229
+ else if (this.retainedAddressFields.includes(el.name)) {
230
+ const retainedAddressValue = this.geRetainedFieldsValue("address");
231
+ const sha256value = yield this.shaHash(retainedAddressValue);
232
+ localStorage.setItem(`EN_HASH_ADDRESS`, sha256value);
233
+ this.dataLayer.push({
234
+ event: "EN_HASH_VALUE_UPDATED",
235
+ enFieldName: "address",
236
+ enFieldLabel: "Supporter Address",
237
+ enFieldValue: sha256value,
238
+ });
239
+ }
240
+ else if (this.retainedPhoneFields.includes(el.name)) {
241
+ const retainedPhoneValue = this.geRetainedFieldsValue("phone");
242
+ const sha256value = yield this.shaHash(retainedPhoneValue);
243
+ localStorage.setItem(`EN_HASH_PHONE`, sha256value);
244
+ this.dataLayer.push({
245
+ event: "EN_HASH_VALUE_UPDATED",
246
+ enFieldName: "phone",
247
+ enFieldLabel: "Supporter Phone",
248
+ enFieldValue: sha256value,
249
+ });
250
+ }
251
+ this.dataLayer.push({
252
+ event: "EN_FORM_VALUE_UPDATED",
253
+ enFieldName: el.name,
254
+ enFieldLabel: this.getFieldLabel(el),
255
+ enFieldValue: value,
256
+ });
188
257
  });
189
258
  }
259
+ geRetainedFieldsValue(kind) {
260
+ switch (kind) {
261
+ case "email":
262
+ return ENGrid.getFieldValue(this.retainedEmailField);
263
+ case "address":
264
+ return this.retainedAddressFields
265
+ .map((field) => ENGrid.getFieldValue(field))
266
+ .filter((value) => value !== "")
267
+ .join("")
268
+ .toLocaleLowerCase()
269
+ .replace(/\s+/g, "");
270
+ case "phone":
271
+ // Only return the first phone number found - prioritize phoneNumber2 over phoneNumber and remove non-numeric characters
272
+ for (const field of this.retainedPhoneFields) {
273
+ const value = ENGrid.getFieldValue(field);
274
+ if (value !== "") {
275
+ return value.replace(/\D/g, "");
276
+ }
277
+ }
278
+ return "";
279
+ default:
280
+ return "";
281
+ }
282
+ }
190
283
  hash(value) {
191
284
  return btoa(value);
192
285
  }
286
+ // TODO: Replace the hash function with this secure SHA-256 implementation later
287
+ shaHash(value) {
288
+ return __awaiter(this, void 0, void 0, function* () {
289
+ const data = this.encoder.encode(value);
290
+ const hashBuffer = yield crypto.subtle.digest("SHA-256", data);
291
+ return Array.from(new Uint8Array(hashBuffer))
292
+ .map((byte) => {
293
+ const hex = byte.toString(16);
294
+ return hex.length === 1 ? "0" + hex : hex;
295
+ })
296
+ .join("");
297
+ });
298
+ }
193
299
  getFieldLabel(el) {
194
300
  var _a, _b;
195
301
  return ((_b = (_a = el.closest(".en__field")) === null || _a === void 0 ? void 0 : _a.querySelector("label")) === null || _b === void 0 ? void 0 : _b.textContent) || "";
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const AppVersion = "0.23.4";
1
+ export declare const AppVersion = "0.23.6";
package/dist/version.js CHANGED
@@ -1 +1 @@
1
- export const AppVersion = "0.23.4";
1
+ export const AppVersion = "0.23.6";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@4site/engrid-scripts",
3
- "version": "0.23.4",
3
+ "version": "0.23.6",
4
4
  "description": "Scripts for the ENGRID Project",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -25,7 +25,7 @@
25
25
  "strongly-typed-events": "^2.0.9"
26
26
  },
27
27
  "homepage": "https://github.com/4site-interactive-studios/engrid#readme",
28
- "gitHead": "4d66eb24160b1946e151ef2c6ee8a713e36e2800",
28
+ "gitHead": "9089bb5a58a68a07e619c7e9a3d196bf986b3c43",
29
29
  "devDependencies": {
30
30
  "nodemon": "^2.0.20"
31
31
  }