abmp-npm 1.10.13 → 1.10.15

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.
@@ -8,6 +8,7 @@ const {
8
8
  GEO_HASH_PRECISION,
9
9
  MAX__MEMBERS_SEARCH_RESULTS,
10
10
  WIX_QUERY_MAX_LIMIT,
11
+ MEMBERSHIPS_TYPES,
11
12
  } = require('./consts.js');
12
13
  const { wixData } = require('./elevated-modules');
13
14
 
@@ -31,6 +32,7 @@ function buildMembersSearchQuery(data) {
31
32
  .query(COLLECTIONS.MEMBERS_DATA)
32
33
  .ne('optOut', true)
33
34
  .ne('action', 'drop')
35
+ .ne('memberships.membertype', MEMBERSHIPS_TYPES.PAC_STAFF)
34
36
  .eq('isVisible', true);
35
37
  let filterConfig = [
36
38
  {
@@ -105,7 +107,7 @@ function buildMembersSearchQuery(data) {
105
107
  query = query.contains('fullName', filter.searchText);
106
108
  }
107
109
  if (!includeStudents) {
108
- query = query.ne('memberships.membertype', 'Student');
110
+ query = query.ne('memberships.membertype', MEMBERSHIPS_TYPES.STUDENT);
109
111
  }
110
112
  return query;
111
113
  },
@@ -35,7 +35,17 @@ const extractBaseUrl = url => {
35
35
  return url;
36
36
  };
37
37
  const incrementUrlCounter = (existingUrl, baseUrl) => {
38
- if (existingUrl && existingUrl === baseUrl) {
38
+ if (!existingUrl || !baseUrl) {
39
+ return baseUrl;
40
+ }
41
+ // Normalize for comparison (case-insensitive)
42
+ const normalizedExisting = existingUrl.toLowerCase();
43
+ const normalizedBase = baseUrl.toLowerCase();
44
+
45
+ if (
46
+ normalizedExisting === normalizedBase ||
47
+ normalizedExisting.startsWith(`${normalizedBase}-`)
48
+ ) {
39
49
  console.log(
40
50
  `Found member with same url ${existingUrl} for baseUrl ${baseUrl}, increasing counter by 1`
41
51
  );
@@ -44,6 +54,9 @@ const incrementUrlCounter = (existingUrl, baseUrl) => {
44
54
  const lastCounter = isNumeric ? parseInt(lastSegment, 10) : 0;
45
55
  return `${baseUrl}-${lastCounter + 1}`;
46
56
  }
57
+
58
+ // No conflict, return baseUrl with counter 1 to be safe
59
+ return `${baseUrl}-1`;
47
60
  };
48
61
  /**
49
62
  * Validates core member data requirements
@@ -477,6 +477,34 @@ async function getSiteMemberId(data) {
477
477
  }
478
478
  }
479
479
 
480
+ /**
481
+ * Tracks a button click with member and location info
482
+ * @param {Object} params - Parameters
483
+ * @param {string} params.memberName - Member's full name
484
+ * @param {string} params.memberId - Member's Wix member ID
485
+ * @param {string} params.pageName - Name of the page/popup where button was clicked
486
+ * @param {string} params.buttonName - Name/ID of the button that was clicked
487
+ * @returns {Promise<Object>} - Saved record
488
+ */
489
+ async function trackButtonClick({ memberName, memberId, pageName, buttonName }) {
490
+ const clickData = {
491
+ memberName,
492
+ memberId,
493
+ pageName,
494
+ buttonName,
495
+ clickedAt: new Date(),
496
+ };
497
+
498
+ try {
499
+ const result = await wixData.insert(COLLECTIONS.BUTTON_CLICKS, clickData);
500
+ console.log(`Tracked ${buttonName} click on ${pageName} for member ${memberId}`);
501
+ return result;
502
+ } catch (error) {
503
+ console.error(`Error tracking ${buttonName} click:`, error);
504
+ throw error;
505
+ }
506
+ }
507
+
480
508
  module.exports = {
481
509
  findMemberByWixDataId,
482
510
  createContactAndMemberIfNew,
@@ -496,4 +524,5 @@ module.exports = {
496
524
  getQAUsers,
497
525
  getSiteMemberId,
498
526
  checkUrlUniqueness,
527
+ trackButtonClick,
499
528
  };
@@ -307,7 +307,7 @@ async function generateUrlsChunk(data) {
307
307
  try {
308
308
  const uniqueUrl = await ensureUniqueUrl({
309
309
  url: '',
310
- memberId: member._id,
310
+ memberId: member.memberId,
311
311
  fullName: name || '', // Let ensureUniqueUrl handle fallback for empty names
312
312
  });
313
313
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "abmp-npm",
3
- "version": "1.10.13",
3
+ "version": "1.10.15",
4
4
  "main": "index.js",
5
5
  "scripts": {
6
6
  "check-cycles": "madge --circular .",
@@ -0,0 +1,46 @@
1
+ const { currentMember } = require('@wix/members');
2
+
3
+ const PAGE_NAME = 'Learn More';
4
+ const BUTTON_NAME = 'Upgrade Now';
5
+
6
+ /**
7
+ * Creates the Learn More popup handler
8
+ * @param {Object} params - Parameters
9
+ * @param {Function} params.$w - Wix $w selector
10
+ * @param {Function} params.trackClick - Backend function to track the click
11
+ * @param {Function} params.getMemberByContactId - Backend function to get member data by contact ID
12
+ */
13
+ function learnMoreOnReady({ $w: _$w, trackClick, getMemberByContactId }) {
14
+ _$w('#learnMoreBtn').onClick(async () => {
15
+ try {
16
+ const wixMember = await currentMember.getMember();
17
+
18
+ if (wixMember) {
19
+ const dbMember = await getMemberByContactId(wixMember._id);
20
+
21
+ if (!dbMember) {
22
+ console.warn('Member not found in MembersDataLatest');
23
+ return;
24
+ }
25
+
26
+ const memberName = dbMember.fullName || 'Unknown';
27
+ const memberId = dbMember.memberId;
28
+
29
+ await trackClick({
30
+ memberName,
31
+ memberId,
32
+ pageName: PAGE_NAME,
33
+ buttonName: BUTTON_NAME,
34
+ });
35
+
36
+ console.log(`Tracked ${BUTTON_NAME} click on ${PAGE_NAME} for member:`, memberId);
37
+ }
38
+ } catch (error) {
39
+ console.error('Error tracking button click:', error);
40
+ }
41
+ });
42
+ }
43
+
44
+ module.exports = {
45
+ learnMoreOnReady,
46
+ };
package/pages/index.js CHANGED
@@ -8,4 +8,5 @@ module.exports = {
8
8
  ...require('./SelectBannerImages.js'),
9
9
  ...require('./deleteConfirm.js'),
10
10
  ...require('./SaveAlerts.js'),
11
+ ...require('./LearnMore.js'),
11
12
  };
@@ -1294,6 +1294,7 @@ async function personalDetailsOnReady({
1294
1294
  streetAddress: {
1295
1295
  name: extractStreetName(address.line1),
1296
1296
  number: extractStreetNumber(address.line1),
1297
+ apt: address.line2 || '',
1297
1298
  },
1298
1299
  city: address.city || '',
1299
1300
  subdivision: address.state || '',
@@ -1309,20 +1310,49 @@ async function personalDetailsOnReady({
1309
1310
  if (!addressInputValue) return null;
1310
1311
 
1311
1312
  let line1 = '';
1313
+ let line2 = '';
1314
+
1312
1315
  if (addressInputValue.streetAddress) {
1313
1316
  const number = addressInputValue.streetAddress.number || '';
1314
1317
  const name = addressInputValue.streetAddress.name || '';
1315
1318
  line1 = `${number} ${name}`.trim();
1319
+
1320
+ // Capture apartment/suite/building info from streetAddress.apt (undocumented but exists)
1321
+ if (addressInputValue.streetAddress.apt) {
1322
+ line2 = addressInputValue.streetAddress.apt;
1323
+ }
1316
1324
  }
1317
1325
 
1318
1326
  if (!line1 && addressInputValue.formatted) {
1319
1327
  line1 = addressInputValue.formatted.split(',')[0]?.trim() || '';
1320
1328
  }
1321
1329
 
1330
+ // If line2 is still empty, try to extract building/suite info from formatted address
1331
+ if (!line2 && addressInputValue.formatted) {
1332
+ const formattedParts = addressInputValue.formatted.split(',').map(part => part.trim());
1333
+ // Look for BLDG/STE/APT/UNIT/SUITE info in the formatted parts
1334
+ for (let i = 1; i < formattedParts.length; i++) {
1335
+ const part = formattedParts[i];
1336
+ const lowerPart = part.toLowerCase();
1337
+ if (
1338
+ lowerPart.includes('bldg') ||
1339
+ lowerPart.includes('ste') ||
1340
+ lowerPart.includes('apt') ||
1341
+ lowerPart.includes('unit') ||
1342
+ lowerPart.includes('suite') ||
1343
+ lowerPart.includes('#') ||
1344
+ lowerPart.includes('building')
1345
+ ) {
1346
+ line2 = part;
1347
+ break;
1348
+ }
1349
+ }
1350
+ }
1351
+
1322
1352
  return {
1323
1353
  key: existingAddress?.key || generateId(),
1324
1354
  line1,
1325
- line2: existingAddress?.line2 || '',
1355
+ line2: line2 || existingAddress?.line2 || '',
1326
1356
  city: addressInputValue.city || '',
1327
1357
  state: addressInputValue.subdivision || '',
1328
1358
  postalcode: addressInputValue.postalCode || '',
@@ -1705,6 +1735,7 @@ async function personalDetailsOnReady({
1705
1735
  const parts = [];
1706
1736
 
1707
1737
  if (addr.line1) parts.push(addr.line1);
1738
+ if (addr.line2) parts.push(addr.line2); // Include building/suite info
1708
1739
  if (addr.city) parts.push(addr.city);
1709
1740
  if (addr.state && addr.postalcode) {
1710
1741
  parts.push(`${addr.state} ${addr.postalcode}`);
@@ -91,7 +91,7 @@ function formatAddress(item) {
91
91
  const limitedPostalCode = item.postalcode.slice(0, 5); //show only 5 digits to not show full user address
92
92
  switch (item.addressStatus) {
93
93
  case ADDRESS_STATUS_TYPES.FULL_ADDRESS:
94
- addressParts = [item.line1, item.city, item.state, limitedPostalCode];
94
+ addressParts = [item.line1, item.line2, item.city, item.state, limitedPostalCode];
95
95
  break;
96
96
  case ADDRESS_STATUS_TYPES.STATE_CITY_ZIP:
97
97
  addressParts = [item.city, item.state, limitedPostalCode];
package/public/consts.js CHANGED
@@ -13,6 +13,7 @@ const COLLECTIONS = {
13
13
  STATE_CITY_MAP: 'City',
14
14
  UPDATED_LOGIN_EMAILS: 'updatedLoginEmails',
15
15
  QA_USERS: 'QA_Users', //Make QA users configurable per site
16
+ BUTTON_CLICKS: 'ButtonClicks',
16
17
  };
17
18
 
18
19
  /**