abmp-npm 1.1.62 → 1.1.63

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/backend/consts.js CHANGED
@@ -1,6 +1,4 @@
1
1
  const PAC_API_URL = 'https://members.abmp.com/eweb/api/Wix';
2
- const SSO_TOKEN_AUTH_API_URL = 'https://members.professionalassistcorp.com/';
3
- const SSO_TOKEN_AUTH_API_KEY = 'testkey';
4
2
 
5
3
  /**
6
4
  * Valid configuration keys for getSiteConfigs function
@@ -40,6 +38,4 @@ module.exports = {
40
38
  PAC_API_URL,
41
39
  COMPILED_FILTERS_FIELDS,
42
40
  MEMBERSHIPS_TYPES,
43
- SSO_TOKEN_AUTH_API_URL,
44
- SSO_TOKEN_AUTH_API_KEY,
45
41
  };
@@ -2,7 +2,7 @@ const { taskManager } = require('psdev-task-manager');
2
2
 
3
3
  const { CONFIG_KEYS } = require('../consts');
4
4
  const { fetchPACMembers } = require('../pac-api-methods');
5
- const { TASKS_NAMES } = require('../tasks/consts');
5
+ const { TASKS_NAMES } = require('../tasks');
6
6
  const { getSiteConfigs } = require('../utils');
7
7
 
8
8
  const { bulkProcessAndSaveMemberData } = require('./bulk-process-methods');
package/backend/index.js CHANGED
@@ -9,6 +9,7 @@ module.exports = {
9
9
  ...require('./members-area-methods'), //TODO: remove it once we finish NPM movement
10
10
  ...require('./members-data-methods'), //TODO: remove it once we finish NPM movement
11
11
  ...require('./cms-data-methods'), //TODO: remove it once we finish NPM movement
12
+ ...require('./routers'),
12
13
  ...require('./sso-methods'),
13
14
  ...require('./data-hooks'),
14
15
  };
@@ -2,7 +2,7 @@ const { COLLECTIONS } = require('../public/consts');
2
2
 
3
3
  const { MEMBERSHIPS_TYPES } = require('./consts');
4
4
  const { updateMemberContactInfo } = require('./contacts-methods');
5
- const { MEMBER_ACTIONS } = require('./daily-pull/consts');
5
+ const { MEMBER_ACTIONS } = require('./daily-pull');
6
6
  const { wixData } = require('./elevated-modules');
7
7
  const { createSiteMember } = require('./members-area-methods');
8
8
  const {
@@ -296,27 +296,6 @@ async function urlExists(url, excludeMemberId) {
296
296
  }
297
297
  }
298
298
 
299
- /**
300
- * Checks URL uniqueness for a member
301
- * @param {string} url - The URL to check
302
- * @param {string} memberId - The member ID to exclude from the check
303
- * @returns {Promise<Object>} Result object with isUnique boolean
304
- */
305
- async function checkUrlUniqueness(url, memberId) {
306
- if (!url || !memberId) {
307
- throw new Error('Missing required parameters: url and memberId are required');
308
- }
309
-
310
- try {
311
- const trimmedUrl = url.trim();
312
- const exists = await urlExists(trimmedUrl, memberId);
313
-
314
- return { isUnique: !exists };
315
- } catch (error) {
316
- console.error('Error checking URL uniqueness:', error);
317
- throw new Error(`Failed to check URL uniqueness: ${error.message}`);
318
- }
319
- }
320
299
  /**
321
300
  * Get all members with external profile images
322
301
  * @returns {Promise<Array>} - Array of member IDs
@@ -421,42 +400,6 @@ const getMembersByIds = async memberIds => {
421
400
  }
422
401
  };
423
402
 
424
- async function getSiteMemberId(data) {
425
- try {
426
- console.log('data', data);
427
- const memberId = data?.pac?.cst_recno;
428
- if (!memberId) {
429
- const errorMessage = `Member ID is missing in passed data ${JSON.stringify(data)}`;
430
- console.error(errorMessage);
431
- throw new Error(errorMessage);
432
- }
433
- const queryMemberResult = await wixData
434
- .query(COLLECTIONS.MEMBERS_DATA)
435
- .eq('memberId', Number(memberId))
436
- .find()
437
- .then(res => res.items);
438
- if (!queryMemberResult.length || queryMemberResult.length > 1) {
439
- throw new Error(
440
- `Invalid Members count found in DB for email ${data.email} members count is : [${
441
- queryMemberResult.length
442
- }] membersIds are : [${queryMemberResult.map(member => member.memberId).join(', ')}]`
443
- );
444
- }
445
- let memberData = queryMemberResult[0];
446
- console.log('memberData', memberData);
447
- const isNewUser = !memberData.contactId;
448
- if (isNewUser) {
449
- const memberDataWithContactId = await createContactAndMemberIfNew(memberData);
450
- console.log('memberDataWithContactId', memberDataWithContactId);
451
- memberData = memberDataWithContactId;
452
- }
453
- return memberData;
454
- } catch (error) {
455
- console.error('Error in getSiteMemberId', error.message);
456
- throw error;
457
- }
458
- }
459
-
460
403
  module.exports = {
461
404
  findMemberByWixDataId,
462
405
  createContactAndMemberIfNew,
@@ -472,6 +415,4 @@ module.exports = {
472
415
  getAllMembersWithoutContactFormEmail,
473
416
  getAllUpdatedLoginEmails,
474
417
  getMembersByIds,
475
- getSiteMemberId,
476
- checkUrlUniqueness,
477
418
  };
@@ -0,0 +1,3 @@
1
+ module.exports = {
2
+ ...require('./methods'),
3
+ };
@@ -0,0 +1,177 @@
1
+ const { PAGES_PATHS } = require('../../public/consts');
2
+ //const { fetchAllItemsInParallel } = require('../cms-data-methods'); unused at host site
3
+ const { CONFIG_KEYS } = require('../consts');
4
+ const { getSiteConfigs } = require('../utils');
5
+
6
+ const { generateSEOTitle, stripHtmlTags, getMemberProfileData } = require('./utils');
7
+
8
+ const createRoutersHandlers = wixRouterMethods => {
9
+ const {
10
+ redirect,
11
+ ok,
12
+ notFound,
13
+ sendStatus,
14
+ WixRouterSitemapEntry: _WixRouterSitemapEntry,
15
+ } = wixRouterMethods;
16
+
17
+ async function profileRouter(request) {
18
+ const slug = request.path[0];
19
+ if (!slug) {
20
+ return redirect(request.baseUrl);
21
+ }
22
+ try {
23
+ const siteConfigs = await getSiteConfigs();
24
+ const siteAssociation = siteConfigs[CONFIG_KEYS.SITE_ASSOCIATION];
25
+ const defaultSEODescription = siteConfigs[CONFIG_KEYS.DEFAULT_PROFILE_SEO_DESCRIPTION];
26
+ const siteLogoUrl = siteConfigs[CONFIG_KEYS.SITE_LOGO_URL];
27
+ const defaultProfileImage = siteConfigs[CONFIG_KEYS.DEFAULT_PROFILE_IMAGE];
28
+ const profileData = await getMemberProfileData(slug, siteAssociation);
29
+ if (profileData && profileData.showWixUrl) {
30
+ const ogImage = profileData.profileImage || profileData.logoImage || siteLogoUrl;
31
+ const seoTitle = generateSEOTitle({
32
+ fullName: profileData.fullName,
33
+ areasOfPractices: profileData.areasOfPractices,
34
+ siteAssociation,
35
+ });
36
+ // Use stripped HTML from aboutService rich text content
37
+ let description = stripHtmlTags(profileData.aboutService) || defaultSEODescription;
38
+
39
+ // Limit description to 160 characters for optimal SEO
40
+ if (description.length > 160) {
41
+ description = description.substring(0, 157) + '...';
42
+ }
43
+ const profileUrl = `${request.baseUrl}/${PAGES_PATHS.PROFILE}/${profileData.url}`;
44
+ const isPrivateMember = profileData.isPrivateMember;
45
+ const seoData = {
46
+ title: seoTitle,
47
+ description: description,
48
+ noIndex: isPrivateMember,
49
+ metaTags: [
50
+ {
51
+ name: 'description',
52
+ content: description,
53
+ },
54
+ {
55
+ name: 'keywords',
56
+ content:
57
+ `${profileData.fullName}, ${profileData.areasOfPractices ? profileData.areasOfPractices.slice(0, 3).join(', ') : ''}, ${siteAssociation}, ${profileData.city || ''}, ${profileData.state || ''}`
58
+ .replace(/,\s*,/g, ',')
59
+ .replace(/^,|,$/g, ''),
60
+ },
61
+ {
62
+ name: 'author',
63
+ content: profileData.fullName,
64
+ },
65
+ {
66
+ name: 'robots',
67
+ content: isPrivateMember ? 'noindex, nofollow' : 'index, follow',
68
+ },
69
+ // Open Graph tags
70
+ {
71
+ property: 'og:type',
72
+ content: 'profile',
73
+ },
74
+ {
75
+ property: 'og:title',
76
+ content: seoTitle,
77
+ },
78
+ {
79
+ property: 'og:description',
80
+ content: description,
81
+ },
82
+ {
83
+ property: 'og:image',
84
+ content: ogImage,
85
+ },
86
+ {
87
+ property: 'og:url',
88
+ content: profileUrl,
89
+ },
90
+ {
91
+ property: 'og:site_name',
92
+ content: `${siteAssociation} Members`,
93
+ },
94
+ // Twitter Card tags
95
+ {
96
+ name: 'twitter:card',
97
+ content: 'summary_large_image',
98
+ },
99
+ {
100
+ name: 'twitter:title',
101
+ content: seoTitle,
102
+ },
103
+ {
104
+ name: 'twitter:description',
105
+ content: description,
106
+ },
107
+ {
108
+ name: 'twitter:image',
109
+ content: ogImage,
110
+ },
111
+ // Additional SEO tags
112
+ {
113
+ name: 'geo.region',
114
+ content: profileData.state || '',
115
+ },
116
+ {
117
+ name: 'geo.placename',
118
+ content: profileData.city || '',
119
+ },
120
+ ].filter(tag => tag.content && tag.content.trim() !== ''), // Remove empty tags
121
+ };
122
+ return ok('profile', { ...profileData, defaultProfileImage }, seoData);
123
+ }
124
+ return notFound();
125
+ } catch (error) {
126
+ console.error(error);
127
+ return sendStatus('500', 'Internal Server Error');
128
+ }
129
+ }
130
+ function profileSiteMap(_sitemapRequest) {
131
+ return [];
132
+ // Commented out - currently disabled in host site
133
+ // try {
134
+ // const membersQuery = wixData
135
+ // .query(COLLECTIONS.MEMBERS_DATA)
136
+ // .eq('showWixUrl', true)
137
+ // .isNotEmpty('url')
138
+ // .ne('action', 'drop')
139
+ // .fields('url', 'fullName');
140
+
141
+ // const allMembers = await fetchAllItemsInParallel(membersQuery);
142
+
143
+ // const batchSize = 1000;
144
+ // const sitemapEntries = [];
145
+ // const totalItems = allMembers.items.length;
146
+
147
+ // for (let i = 0; i < totalItems; i += batchSize) {
148
+ // const batch = allMembers.items.slice(i, i + batchSize);
149
+ // const batchEntries = batch.map(member => {
150
+ // const entry = new WixRouterSitemapEntry(member.fullName);
151
+ // entry.pageName = 'profile';
152
+ // entry.url = `${PAGES_PATHS.PROFILE}/${member.url}`;
153
+ // entry.title = member.fullName;
154
+ // entry.changeFrequency = 'monthly';
155
+ // entry.priority = 1.0;
156
+ // return entry;
157
+ // });
158
+ // sitemapEntries.push(...batchEntries);
159
+ // }
160
+
161
+ // return sitemapEntries;
162
+ // } catch (error) {
163
+ // console.error('Error generating profile sitemap:', error);
164
+ // return [];
165
+ // }
166
+ }
167
+ //Add other routers here
168
+ return {
169
+ profileRouter,
170
+ profileSiteMap,
171
+ //Add other routers here
172
+ };
173
+ };
174
+
175
+ module.exports = {
176
+ createRoutersHandlers,
177
+ };
@@ -0,0 +1,118 @@
1
+ const { getMainAddress } = require('../../public/Utils/sharedUtils');
2
+ const { getMemberBySlug } = require('../members-data-methods');
3
+ const {
4
+ getAddressesByStatus,
5
+ formatDateToMonthYear,
6
+ hasStudentMembership,
7
+ isPAC_STAFF,
8
+ } = require('../utils');
9
+
10
+ function generateSEOTitle({ fullName, areasOfPractices, siteAssociation }) {
11
+ return `${fullName}${
12
+ areasOfPractices && areasOfPractices.length > 0
13
+ ? ` | ${areasOfPractices.slice(0, 3).join(', ')}`
14
+ : ''
15
+ } | ${siteAssociation} Member`;
16
+ }
17
+
18
+ function stripHtmlTags(html) {
19
+ if (!html) return '';
20
+ // Remove HTML tags and decode HTML entities
21
+ return html
22
+ .replace(/<[^>]*>/g, '') // Remove HTML tags
23
+ .replace(/&nbsp;/g, ' ') // Replace non-breaking spaces
24
+ .replace(/&amp;/g, '&') // Replace encoded ampersands
25
+ .replace(/&lt;/g, '<') // Replace encoded less than
26
+ .replace(/&gt;/g, '>') // Replace encoded greater than
27
+ .replace(/&quot;/g, '"') // Replace encoded quotes
28
+ .replace(/&#39;/g, "'") // Replace encoded apostrophes
29
+ .replace(/\s+/g, ' ') // Replace multiple whitespace with single space
30
+ .trim(); // Remove leading/trailing whitespace
31
+ }
32
+
33
+ function shouldHaveStudentBadge(member, siteAssociation) {
34
+ return hasStudentMembership({
35
+ member,
36
+ checkAssociation: true,
37
+ siteAssociation,
38
+ });
39
+ }
40
+
41
+ function transformMemberToProfileData(member, siteAssociation) {
42
+ if (!member) {
43
+ throw new Error('member is required');
44
+ }
45
+ const addresses = member.addresses || [];
46
+ const mainAddress = getMainAddress(member.addressDisplayOption, addresses);
47
+ const licenceNo = member.licenses
48
+ ?.map(val => val.license)
49
+ .filter(Boolean)
50
+ .join(', ');
51
+ const processedAddresses = getAddressesByStatus(member.addresses, member.addressDisplayOption);
52
+
53
+ const memberships = member.memberships || [];
54
+ const siteAssociationMembership = memberships.find(m => m.association === siteAssociation);
55
+
56
+ const areasOfPractices =
57
+ member.areasOfPractices
58
+ ?.filter(item => typeof item === 'string' && item.trim().length > 0)
59
+ .map(item => item.trim())
60
+ .sort((a, b) =>
61
+ a.localeCompare(b, undefined, {
62
+ sensitivity: 'base',
63
+ numeric: true,
64
+ })
65
+ ) || [];
66
+ return {
67
+ mainAddress,
68
+ testimonials: member.testimonial || [],
69
+ licenceNo,
70
+ processedAddresses,
71
+ memberSince:
72
+ (member.showABMP &&
73
+ siteAssociationMembership &&
74
+ formatDateToMonthYear(siteAssociationMembership?.membersince)) ||
75
+ '',
76
+ shouldHaveStudentBadge: shouldHaveStudentBadge(member, siteAssociation),
77
+ logoImage: member.logoImage,
78
+ fullName: member.fullName,
79
+ profileImage: member.profileImage,
80
+ showContactForm: member.showContactForm,
81
+ bookingUrl: member.bookingUrl,
82
+ aboutService: member.aboutService,
83
+ businessName: (member.showBusinessName && member.businessName) || '',
84
+ phone: member.toShowPhone || '',
85
+ areasOfPractices,
86
+ gallery: member.gallery,
87
+ bannerImages: member.bannerImages,
88
+ showWixUrl: member.showWixUrl,
89
+ _id: member._id,
90
+ url: member.url,
91
+ isPrivateMember: isPAC_STAFF(member),
92
+ };
93
+ }
94
+
95
+ const getMemberProfileData = async (slug, siteAssociation) => {
96
+ try {
97
+ const member = await getMemberBySlug({
98
+ slug,
99
+ excludeDropped: true,
100
+ excludeSearchedMember: false,
101
+ });
102
+
103
+ if (!member) {
104
+ return null;
105
+ }
106
+
107
+ return transformMemberToProfileData(member, siteAssociation);
108
+ } catch (error) {
109
+ console.error(error);
110
+ throw error;
111
+ }
112
+ };
113
+
114
+ module.exports = {
115
+ generateSEOTitle,
116
+ stripHtmlTags,
117
+ getMemberProfileData,
118
+ };
@@ -1,14 +1,7 @@
1
- const { createHmac } = require('crypto');
2
-
3
- const { auth } = require('@wix/essentials');
4
- const { authentication } = require('@wix/identity'); //importing from @wix/identity because @wix/members authentication do not have generateSessionToken method
5
- const generateSessionToken = auth.elevate(authentication.signOn);
6
- const { decode } = require('jwt-js-decode');
7
-
8
- const { CONFIG_KEYS, SSO_TOKEN_AUTH_API_URL, SSO_TOKEN_AUTH_API_KEY } = require('./consts');
1
+ const { CONFIG_KEYS } = require('./consts');
9
2
  const { MEMBER_ACTIONS } = require('./daily-pull');
10
3
  const { getCurrentMember } = require('./members-area-methods');
11
- const { getMemberByContactId, getSiteMemberId } = require('./members-data-methods');
4
+ const { getMemberByContactId } = require('./members-data-methods');
12
5
  const {
13
6
  formatDateToMonthYear,
14
7
  getAddressDisplayOptions,
@@ -89,73 +82,7 @@ async function validateMemberToken(memberIdInput) {
89
82
  throw error;
90
83
  }
91
84
  }
92
- async function checkAndFetchSSO(token) {
93
- const signature = createHmac('sha256', SSO_TOKEN_AUTH_API_KEY).update(token).digest('hex');
94
- const professionalassistcorpUrl = `${SSO_TOKEN_AUTH_API_URL}/eweb/SSOToken.ashx?token=${token}&Partner=Wix&Signature=${signature}`;
95
- const options = {
96
- method: 'get',
97
- };
98
- try {
99
- const httpResponse = await fetch(professionalassistcorpUrl, options);
100
- console.log('httpResponse status', httpResponse.status);
101
- if (!httpResponse.ok) {
102
- throw new Error('Fetch did not succeed with status: ' + httpResponse.status);
103
- }
104
- const responseToken = await httpResponse.text();
105
- return responseToken;
106
- } catch (error) {
107
- console.error('Error in checkAndFetchSSO', error);
108
- return null;
109
- }
110
- }
111
-
112
- function generateSessionTokenFunction(email) {
113
- return generateSessionToken({ email })
114
- .then(response => response.sessionToken)
115
- .catch(error => {
116
- console.error('Error in generateSessionTokenFunction', error);
117
- throw error;
118
- });
119
- }
120
-
121
- const authenticateSSOToken = async token => {
122
- const responseToken = await checkAndFetchSSO(token);
123
- const isValidToken = Boolean(
124
- responseToken && typeof responseToken === 'string' && responseToken?.trim()
125
- );
126
- const toLogTokenData = {
127
- isValidToken,
128
- tokenData: responseToken
129
- ? {
130
- length: responseToken.length,
131
- preview: responseToken.substring(0, 50),
132
- }
133
- : 'No token',
134
- };
135
- console.log('checkAndFetchSSO responseToken data', JSON.stringify(toLogTokenData, null, 2));
136
- if (isValidToken) {
137
- const jwt = decode(responseToken);
138
- const payload = jwt.payload;
139
- const membersData = await getSiteMemberId(payload);
140
- console.log('membersDataCollectionId', membersData._id);
141
- const sessionToken = await generateSessionTokenFunction(membersData.email);
142
- const authObj = {
143
- type: 'success',
144
- memberId: membersData._id,
145
- sessionToken,
146
- };
147
- return authObj;
148
- } else {
149
- console.log('invalid Token responseToken is: ', responseToken);
150
- return {
151
- type: 'error',
152
- memberId: '',
153
- sessionToken: '',
154
- };
155
- }
156
- };
157
85
 
158
86
  module.exports = {
159
87
  validateMemberToken,
160
- authenticateSSOToken,
161
88
  };
package/backend/utils.js CHANGED
@@ -1,19 +1,19 @@
1
- const { auth } = require('@wix/essentials');
1
+ const { elevate } = require('@wix/essentials');
2
2
  const { secrets } = require('@wix/secrets');
3
3
  const { site } = require('@wix/urls');
4
4
  const { encode } = require('ngeohash');
5
5
 
6
- const { COLLECTIONS } = require('../public/consts');
6
+ const { COLLECTIONS, ADDRESS_STATUS_TYPES } = require('../public/consts');
7
+ const { formatAddress, generateId } = require('../public/Utils/sharedUtils');
7
8
 
8
- const { CONFIG_KEYS, GEO_HASH_PRECISION } = require('./consts');
9
+ const { CONFIG_KEYS, GEO_HASH_PRECISION, MEMBERSHIPS_TYPES } = require('./consts');
9
10
  const { wixData } = require('./elevated-modules');
10
- const elevatedGetSecretValue = auth.elevate(secrets.getSecretValue);
11
+ const { urlExists } = require('./members-data-methods');
12
+ const elevatedGetSecretValue = elevate(secrets.getSecretValue);
11
13
 
12
14
  /**
13
15
  * Retrieves site configuration values from the database
14
- * @param {string} [configKey] - The configuration key to retrieve. Must be one of:
15
- * - 'AUTOMATION_EMAIL_TRIGGER_ID' - Email template ID for triggered emails
16
- * - 'SITE_ASSOCIATION' - Site association configuration
16
+ * @param {keyof typeof CONFIG_KEYS} [configKey] - The configuration key to retrieve
17
17
  * @returns {Promise<any>} The configuration value for the specified key, or all configs if no key provided
18
18
  * @example
19
19
  * // Get specific config
@@ -59,18 +59,26 @@ function formatDateToMonthYear(dateString) {
59
59
  return date.toLocaleDateString('en-US', options);
60
60
  }
61
61
 
62
- /**
63
- * Check if member is a student
64
- * @param {Object} member - The member object
65
- * @returns {boolean} True if member has student membership
66
- */
67
- function isStudent(member) {
62
+ function hasStudentMembership({ member, checkAssociation = false, siteAssociation = null }) {
68
63
  const memberships = member?.memberships;
69
64
  if (!Array.isArray(memberships)) return false;
70
65
 
71
- return memberships.some(membership => membership.membertype === 'student');
66
+ return memberships.some(membership => {
67
+ const isStudent = membership.membertype === MEMBERSHIPS_TYPES.STUDENT;
68
+ const hasCorrectAssociation = !checkAssociation || membership.association === siteAssociation;
69
+ return isStudent && hasCorrectAssociation;
70
+ });
72
71
  }
73
72
 
73
+ function isStudent(member) {
74
+ return hasStudentMembership({ member, checkAssociation: false });
75
+ }
76
+
77
+ function isPAC_STAFF(member) {
78
+ return Boolean(
79
+ member?.memberships?.some(membership => membership.membertype === MEMBERSHIPS_TYPES.PAC_STAFF)
80
+ );
81
+ }
74
82
  /**
75
83
  * Get address display options for member
76
84
  * @param {Object} member - The member object
@@ -84,7 +92,22 @@ function getAddressDisplayOptions(member) {
84
92
  }
85
93
  return displayOptions;
86
94
  }
87
-
95
+ function getAddressesByStatus(addresses = [], addressDisplayOption = []) {
96
+ const visible = addresses.filter(addr => addr.addressStatus !== ADDRESS_STATUS_TYPES.DONT_SHOW);
97
+ if (visible.length < 2) {
98
+ return [];
99
+ }
100
+ const opts = Array.isArray(addressDisplayOption) ? addressDisplayOption : [];
101
+ const mainOpt = opts.find(o => o.isMain);
102
+ const mainKey = mainOpt ? mainOpt.key : visible[0].key; // fallback to the first visible if none marked
103
+ return visible
104
+ .filter(addr => addr?.key !== mainKey)
105
+ .map(addr => {
106
+ const addressString = formatAddress(addr);
107
+ return addressString ? { _id: generateId(), address: addressString } : null;
108
+ })
109
+ .filter(Boolean);
110
+ }
88
111
  const queryAllItems = async query => {
89
112
  console.log('start query');
90
113
  let oldResults = await query.find();
@@ -131,6 +154,28 @@ const normalizeUrlForComparison = url => {
131
154
  return url.toLowerCase().replace(/-\d+$/, '');
132
155
  };
133
156
 
157
+ /**
158
+ * Checks URL uniqueness for a member
159
+ * @param {string} url - The URL to check
160
+ * @param {string} memberId - The member ID to exclude from the check
161
+ * @returns {Promise<Object>} Result object with isUnique boolean
162
+ */
163
+ async function checkUrlUniqueness(url, memberId) {
164
+ if (!url || !memberId) {
165
+ throw new Error('Missing required parameters: url and memberId are required');
166
+ }
167
+
168
+ try {
169
+ const trimmedUrl = url.trim();
170
+ const exists = await urlExists(trimmedUrl, memberId);
171
+
172
+ return { isUnique: !exists };
173
+ } catch (error) {
174
+ console.error('Error checking URL uniqueness:', error);
175
+ throw new Error(`Failed to check URL uniqueness: ${error.message}`);
176
+ }
177
+ }
178
+
134
179
  async function getSecret(secretKey) {
135
180
  return await elevatedGetSecretValue(secretKey).value;
136
181
  }
@@ -174,11 +219,15 @@ module.exports = {
174
219
  isValidArray,
175
220
  normalizeUrlForComparison,
176
221
  queryAllItems,
222
+ checkUrlUniqueness,
177
223
  formatDateToMonthYear,
178
224
  isStudent,
225
+ hasStudentMembership,
179
226
  getAddressDisplayOptions,
180
227
  getSecret,
181
228
  getSiteBaseUrl,
182
229
  encodeXml,
183
230
  formatDateOnly,
231
+ getAddressesByStatus,
232
+ isPAC_STAFF,
184
233
  };
package/package.json CHANGED
@@ -1,11 +1,10 @@
1
1
  {
2
2
  "name": "abmp-npm",
3
- "version": "1.1.62",
3
+ "version": "1.1.63",
4
4
  "main": "index.js",
5
5
  "scripts": {
6
- "check-cycles": "madge --circular .",
7
6
  "test": "echo \"Error: no test specified\" && exit 1",
8
- "lint": "npm run check-cycles && eslint .",
7
+ "lint": "eslint .",
9
8
  "lint:fix": "eslint . --fix",
10
9
  "format": "prettier --write \"**/*.{js,json,md}\"",
11
10
  "format:check": "prettier --check \"**/*.{js,json,md}\"",
@@ -24,7 +23,6 @@
24
23
  "eslint-plugin-promise": "^7.1.0",
25
24
  "globals": "^15.10.0",
26
25
  "husky": "^9.1.6",
27
- "madge": "^8.0.0",
28
26
  "prettier": "^3.3.3"
29
27
  },
30
28
  "dependencies": {
@@ -32,19 +30,15 @@
32
30
  "@wix/crm": "^1.0.1061",
33
31
  "@wix/data": "^1.0.303",
34
32
  "@wix/essentials": "^0.1.28",
35
- "@wix/identity": "^1.0.178",
36
33
  "@wix/media": "^1.0.213",
37
34
  "@wix/members": "^1.0.365",
38
35
  "@wix/secrets": "^1.0.62",
39
36
  "@wix/site-location": "^1.31.0",
40
- "@wix/site-members": "^1.32.0",
41
- "@wix/site-storage": "^1.22.0",
42
37
  "@wix/site-window": "^1.44.0",
43
38
  "@wix/urls": "^1.0.57",
44
39
  "aws4": "^1.13.2",
45
40
  "axios": "^1.13.1",
46
41
  "crypto": "^1.0.1",
47
- "jwt-js-decode": "^1.9.0",
48
42
  "lodash": "^4.17.21",
49
43
  "ngeohash": "^0.6.3",
50
44
  "phone": "^3.1.67",
package/pages/index.js CHANGED
@@ -3,5 +3,4 @@ module.exports = {
3
3
  ...require('./Profile.js'),
4
4
  ...require('./Home.js'),
5
5
  ...require('./personalDetails.js'),
6
- ...require('./LoadingPage.js'),
7
6
  };
@@ -168,4 +168,5 @@ module.exports = {
168
168
  calculateDistance,
169
169
  toRadians,
170
170
  generateId,
171
+ formatAddress,
171
172
  };
package/public/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  module.exports = {
2
2
  ...require('./consts'),
3
3
  ...require('./messages'),
4
+ ...require('./Utils/sharedUtils'),
4
5
  };
@@ -1,20 +0,0 @@
1
- const { window: wixWindow, rendering } = require('@wix/site-window');
2
-
3
- const { LIGHTBOX_NAMES } = require('../public/consts');
4
- const { checkAndLogin } = require('../public/sso-auth-methods');
5
-
6
- async function loadingPageOnReady(authenticateSSOToken) {
7
- const renderingEnv = await rendering.env();
8
- //This calls needs to triggered on client side, otherwise PAC API will return 401 error
9
- if (renderingEnv === 'browser') {
10
- //Need to pass processSubmission to checkAndLogin so it will run as a web method not a public one.
11
- await checkAndLogin(authenticateSSOToken).catch(error => {
12
- wixWindow.openLightbox(LIGHTBOX_NAMES.LOGIN_ERROR_ALERT);
13
- console.error(`Something went wrong while logging in: ${error}`);
14
- });
15
- }
16
- }
17
-
18
- module.exports = {
19
- loadingPageOnReady,
20
- };
@@ -1,43 +0,0 @@
1
- const { location: wixLocationFrontend } = require('@wix/site-location');
2
- const { authentication } = require('@wix/site-members');
3
- const { local } = require('@wix/site-storage');
4
-
5
- const { PAGES_PATHS } = require('./consts');
6
-
7
- const checkAndLogin = async authenticateSSOToken => {
8
- const query = await wixLocationFrontend.query();
9
- const token = query['token']?.trim();
10
- try {
11
- if (token) {
12
- const authObj = await authenticateSSOToken(token);
13
- console.log('authObj', authObj);
14
- if (authObj.type == 'success') {
15
- console.log('success');
16
- await Promise.all([
17
- authentication.applySessionToken(authObj?.sessionToken),
18
- local.setItem('memberId', authObj.memberId),
19
- ]);
20
- console.log('memberId', authObj.memberId);
21
- const queryParams = {
22
- ...query,
23
- token: authObj?.memberId,
24
- };
25
- const redirectTo = `${PAGES_PATHS.MEMBERS_FORM}?${new URLSearchParams(queryParams).toString()}`;
26
- await wixLocationFrontend.to(`/${redirectTo}`);
27
- } else {
28
- console.error('Something went wrong while logging in');
29
- throw new Error('Authentication failed - invalid response from server');
30
- }
31
- } else {
32
- console.log('checkAndLogin: No token found');
33
- throw new Error('No authentication token found in URL');
34
- }
35
- } catch (error) {
36
- console.error('Error in checkAndLogin', error);
37
- throw error;
38
- }
39
- };
40
-
41
- module.exports = {
42
- checkAndLogin,
43
- };