abmp-npm 2.0.15 → 2.0.17
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/daily-pull/utils.js +14 -1
- package/backend/members-data-methods.js +50 -3
- package/backend/routers/methods.js +6 -1
- package/backend/tasks/tasks-helpers-methods.js +21 -11
- package/package.json +1 -1
- package/pages/Home.js +12 -4
- package/pages/LearnMore.js +27 -0
- package/pages/Profile.js +6 -2
- package/pages/index.js +1 -0
- package/pages/personalDetails.js +9 -3
- package/public/Utils/sharedUtils.js +8 -0
- package/public/consts.js +1 -0
|
@@ -35,7 +35,17 @@ const extractBaseUrl = url => {
|
|
|
35
35
|
return url;
|
|
36
36
|
};
|
|
37
37
|
const incrementUrlCounter = (existingUrl, baseUrl) => {
|
|
38
|
-
if (existingUrl
|
|
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
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
const { COLLECTIONS } = require('../public/consts');
|
|
2
|
+
const { isWixHostedImage } = require('../public/Utils/sharedUtils');
|
|
2
3
|
|
|
3
4
|
const { MEMBERSHIPS_TYPES } = require('./consts');
|
|
4
5
|
const { updateMemberContactInfo } = require('./contacts-methods');
|
|
5
6
|
const { MEMBER_ACTIONS } = require('./daily-pull/consts');
|
|
6
7
|
const { wixData } = require('./elevated-modules');
|
|
7
|
-
const { createSiteMember } = require('./members-area-methods');
|
|
8
|
+
const { createSiteMember, getCurrentMember } = require('./members-area-methods');
|
|
8
9
|
const {
|
|
9
10
|
chunkArray,
|
|
10
11
|
normalizeUrlForComparison,
|
|
@@ -318,9 +319,9 @@ async function getAllMembersWithExternalImages() {
|
|
|
318
319
|
|
|
319
320
|
const allItems = await queryAllItems(membersQuery);
|
|
320
321
|
|
|
321
|
-
// Filter for external images (not
|
|
322
|
+
// Filter for external images (not 'wix hosted images')
|
|
322
323
|
const membersWithExternalImages = allItems.filter(
|
|
323
|
-
member => member.profileImage && !member.profileImage
|
|
324
|
+
member => member.profileImage && !isWixHostedImage(member.profileImage)
|
|
324
325
|
);
|
|
325
326
|
|
|
326
327
|
return membersWithExternalImages;
|
|
@@ -477,6 +478,51 @@ async function getSiteMemberId(data) {
|
|
|
477
478
|
}
|
|
478
479
|
}
|
|
479
480
|
|
|
481
|
+
/**
|
|
482
|
+
* Tracks a button click with member and location info.
|
|
483
|
+
* @param {Object} params - Parameters
|
|
484
|
+
* @param {string} params.pageName - Name of the page/popup where button was clicked
|
|
485
|
+
* @param {string} params.buttonName - Name/ID of the button that was clicked
|
|
486
|
+
* @returns {Promise<Object>} - Saved record or null if member not found
|
|
487
|
+
*/
|
|
488
|
+
async function trackButtonClick({ pageName, buttonName }) {
|
|
489
|
+
const wixMember = await getCurrentMember();
|
|
490
|
+
|
|
491
|
+
if (!wixMember) {
|
|
492
|
+
console.warn('[trackButtonClick]: No logged in member found');
|
|
493
|
+
return null;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
const dbMember = await getMemberByContactId(wixMember._id);
|
|
497
|
+
|
|
498
|
+
if (!dbMember) {
|
|
499
|
+
console.warn(
|
|
500
|
+
`[trackButtonClick]: Member not found in MembersDataLatest for contactId: ${wixMember._id}`
|
|
501
|
+
);
|
|
502
|
+
return null;
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
const memberName = dbMember.fullName || 'Unknown';
|
|
506
|
+
const memberId = dbMember.memberId;
|
|
507
|
+
|
|
508
|
+
const clickData = {
|
|
509
|
+
memberName,
|
|
510
|
+
memberId,
|
|
511
|
+
pageName,
|
|
512
|
+
buttonName,
|
|
513
|
+
clickedAt: new Date(),
|
|
514
|
+
};
|
|
515
|
+
|
|
516
|
+
try {
|
|
517
|
+
const result = await wixData.insert(COLLECTIONS.BUTTON_CLICKS, clickData);
|
|
518
|
+
console.log(`Tracked ${buttonName} click on ${pageName} for member ${memberId}`);
|
|
519
|
+
return result;
|
|
520
|
+
} catch (error) {
|
|
521
|
+
console.error(`Error tracking ${buttonName} click:`, error);
|
|
522
|
+
throw error;
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
|
|
480
526
|
module.exports = {
|
|
481
527
|
findMemberByWixDataId,
|
|
482
528
|
createContactAndMemberIfNew,
|
|
@@ -496,4 +542,5 @@ module.exports = {
|
|
|
496
542
|
getQAUsers,
|
|
497
543
|
getSiteMemberId,
|
|
498
544
|
checkUrlUniqueness,
|
|
545
|
+
trackButtonClick,
|
|
499
546
|
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const { PAGES_PATHS } = require('../../public/consts');
|
|
2
|
+
const { isWixHostedImage } = require('../../public/Utils/sharedUtils');
|
|
2
3
|
//const { fetchAllItemsInParallel } = require('../cms-data-methods'); unused at host site
|
|
3
4
|
const { CONFIG_KEYS } = require('../consts');
|
|
4
5
|
const { getSiteConfigs } = require('../utils');
|
|
@@ -27,7 +28,11 @@ const createRoutersHandlers = wixRouterMethods => {
|
|
|
27
28
|
const defaultProfileImage = siteConfigs[CONFIG_KEYS.DEFAULT_PROFILE_IMAGE];
|
|
28
29
|
const profileData = await getMemberProfileData(slug, siteAssociation);
|
|
29
30
|
if (profileData && profileData.showWixUrl) {
|
|
30
|
-
const
|
|
31
|
+
const profileImage =
|
|
32
|
+
profileData.profileImage?.trim() && isWixHostedImage(profileData.profileImage)
|
|
33
|
+
? profileData.profileImage
|
|
34
|
+
: defaultProfileImage;
|
|
35
|
+
const ogImage = profileImage || profileData.logoImage || siteLogoUrl;
|
|
31
36
|
const seoTitle = generateSEOTitle({
|
|
32
37
|
fullName: profileData.fullName,
|
|
33
38
|
areasOfPractices: profileData.areasOfPractices,
|
|
@@ -1,29 +1,36 @@
|
|
|
1
1
|
const crypto = require('crypto');
|
|
2
2
|
|
|
3
|
+
const { auth } = require('@wix/essentials');
|
|
3
4
|
const { files } = require('@wix/media');
|
|
4
5
|
const aws4 = require('aws4');
|
|
5
6
|
const axios = require('axios');
|
|
6
7
|
|
|
8
|
+
const elevatedGenerateFileUploadUrl = auth.elevate(files.generateFileUploadUrl);
|
|
9
|
+
|
|
7
10
|
const { PAGES_PATHS } = require('../../public/consts');
|
|
11
|
+
const { isWixHostedImage } = require('../../public/Utils/sharedUtils');
|
|
8
12
|
const { findMemberByWixDataId, updateMember } = require('../members-data-methods');
|
|
9
13
|
const { getSecret, getSiteBaseUrl, encodeXml, formatDateOnly } = require('../utils');
|
|
10
|
-
|
|
11
14
|
async function getServerlessAuth() {
|
|
12
15
|
const serverlessAuth = await getSecret('serverless_auth');
|
|
13
16
|
return serverlessAuth;
|
|
14
17
|
}
|
|
15
18
|
|
|
16
19
|
function isValidImageUrl(url) {
|
|
20
|
+
console.log('url', url);
|
|
21
|
+
console.log('typeof url', typeof url);
|
|
17
22
|
if (!url || typeof url !== 'string') return false;
|
|
18
23
|
|
|
19
24
|
// Check for valid URL format
|
|
20
25
|
let parsedUrl;
|
|
21
26
|
try {
|
|
22
27
|
parsedUrl = new URL(url);
|
|
28
|
+
console.log('parsedUrl', parsedUrl);
|
|
23
29
|
} catch {
|
|
24
30
|
return false;
|
|
25
31
|
}
|
|
26
|
-
|
|
32
|
+
console.log('parsedUrl', parsedUrl);
|
|
33
|
+
console.log('parsedUrl.protocol', parsedUrl.protocol);
|
|
27
34
|
// Only allow HTTP and HTTPS protocols (reject blob:, data:, file:, etc.)
|
|
28
35
|
const validProtocols = ['http:', 'https:'];
|
|
29
36
|
if (!validProtocols.includes(parsedUrl.protocol)) {
|
|
@@ -33,10 +40,10 @@ function isValidImageUrl(url) {
|
|
|
33
40
|
// Extract file extension from URL (handle query parameters)
|
|
34
41
|
const urlPath = url.split('?')[0].toLowerCase();
|
|
35
42
|
const validExtensions = ['.jpg', '.jpeg', '.png', '.gif', '.webp', '.bmp'];
|
|
36
|
-
|
|
43
|
+
console.log('urlPath', urlPath);
|
|
37
44
|
// Check if URL ends with valid extension
|
|
38
45
|
const hasValidExtension = validExtensions.some(ext => urlPath.endsWith(ext));
|
|
39
|
-
|
|
46
|
+
console.log('hasValidExtension', hasValidExtension);
|
|
40
47
|
// Reject obviously invalid extensions
|
|
41
48
|
const invalidExtensions = [
|
|
42
49
|
'.pdf',
|
|
@@ -51,7 +58,7 @@ function isValidImageUrl(url) {
|
|
|
51
58
|
'_gif',
|
|
52
59
|
];
|
|
53
60
|
const hasInvalidExtension = invalidExtensions.some(ext => urlPath.includes(ext));
|
|
54
|
-
|
|
61
|
+
console.log('hasInvalidExtension', hasInvalidExtension);
|
|
55
62
|
return hasValidExtension && !hasInvalidExtension;
|
|
56
63
|
}
|
|
57
64
|
|
|
@@ -138,20 +145,23 @@ async function updateMemberRichContent(memberId) {
|
|
|
138
145
|
async function updateMemberProfileImage(memberId) {
|
|
139
146
|
try {
|
|
140
147
|
const member = await findMemberByWixDataId(memberId);
|
|
141
|
-
|
|
148
|
+
const trimmedProfileImage = member.profileImage?.trim();
|
|
142
149
|
// Check if member has an external profile image URL
|
|
143
|
-
if (!
|
|
150
|
+
if (!trimmedProfileImage || isWixHostedImage(trimmedProfileImage)) {
|
|
144
151
|
console.log(`Member ${memberId} already has Wix-hosted image or no image`);
|
|
145
152
|
return { success: true, message: 'No update needed' };
|
|
146
153
|
}
|
|
147
154
|
|
|
148
155
|
// Validate image URL format before attempting download
|
|
149
|
-
if (!isValidImageUrl(
|
|
150
|
-
console.log(`Member ${memberId} has invalid image URL format: ${
|
|
156
|
+
if (!isValidImageUrl(trimmedProfileImage)) {
|
|
157
|
+
console.log(`Member ${memberId} has invalid image URL format: ${trimmedProfileImage}`);
|
|
151
158
|
return { success: true, message: 'Invalid image URL format - skipped' };
|
|
152
159
|
}
|
|
153
160
|
|
|
154
|
-
|
|
161
|
+
// Encode URL to handle spaces and special characters in the path
|
|
162
|
+
const encodedImageUrl = encodeURI(trimmedProfileImage);
|
|
163
|
+
|
|
164
|
+
const response = await axios.get(encodedImageUrl, {
|
|
155
165
|
responseType: 'arraybuffer',
|
|
156
166
|
headers: {
|
|
157
167
|
'User-Agent':
|
|
@@ -208,7 +218,7 @@ async function updateMemberProfileImage(memberId) {
|
|
|
208
218
|
|
|
209
219
|
const sanitizedFileName = `profile-${memberId}-${Date.now()}.${extension}`.replace(/\./g, '_');
|
|
210
220
|
const uploadUrl = (
|
|
211
|
-
await
|
|
221
|
+
await elevatedGenerateFileUploadUrl(contentType, {
|
|
212
222
|
fileName: sanitizedFileName,
|
|
213
223
|
filePath: 'member-profiles',
|
|
214
224
|
})
|
package/package.json
CHANGED
package/pages/Home.js
CHANGED
|
@@ -9,6 +9,7 @@ const {
|
|
|
9
9
|
getMainAddress,
|
|
10
10
|
formatPracticeAreasForDisplay,
|
|
11
11
|
checkAddressIsVisible,
|
|
12
|
+
isWixHostedImage,
|
|
12
13
|
} = require('../public/Utils/sharedUtils.js');
|
|
13
14
|
|
|
14
15
|
let filter = JSON.parse(JSON.stringify(DEFAULT_FILTER));
|
|
@@ -187,7 +188,7 @@ const homePageOnReady = async ({
|
|
|
187
188
|
: [];
|
|
188
189
|
|
|
189
190
|
// 2) Profile image
|
|
190
|
-
if (itemData.profileImage) {
|
|
191
|
+
if (itemData.profileImage?.trim() && isWixHostedImage(itemData.profileImage)) {
|
|
191
192
|
$item('#profileImage').src = itemData.profileImage;
|
|
192
193
|
}
|
|
193
194
|
|
|
@@ -216,12 +217,19 @@ const homePageOnReady = async ({
|
|
|
216
217
|
$item('#milesAwayText').text = '';
|
|
217
218
|
}
|
|
218
219
|
|
|
219
|
-
// 7) "Show maps" button enabled only if there's
|
|
220
|
+
// 7) "Show maps" button enabled only if there's a full address with valid coordinates
|
|
220
221
|
const visible = checkAddressIsVisible(addresses);
|
|
221
|
-
|
|
222
|
+
const fullAddressWithValidCoords = visible.find(
|
|
223
|
+
addr =>
|
|
224
|
+
addr.addressStatus === ADDRESS_STATUS_TYPES.FULL_ADDRESS &&
|
|
225
|
+
addr.latitude &&
|
|
226
|
+
addr.longitude
|
|
227
|
+
);
|
|
228
|
+
|
|
229
|
+
if (fullAddressWithValidCoords) {
|
|
222
230
|
$item('#showMaps').enable();
|
|
223
231
|
$item('#showMaps').show();
|
|
224
|
-
const { latitude, longitude } =
|
|
232
|
+
const { latitude, longitude } = fullAddressWithValidCoords;
|
|
225
233
|
$item('#showMaps').link = `https://maps.google.com/?q=${latitude},${longitude}`;
|
|
226
234
|
$item('#showMaps').target = '_blank';
|
|
227
235
|
} else {
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
const PAGE_NAME = 'Learn More';
|
|
2
|
+
const BUTTON_NAME = 'Upgrade Now';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Creates the Learn More popup handler
|
|
6
|
+
* @param {Object} params - Parameters
|
|
7
|
+
* @param {Function} params.$w - Wix $w selector
|
|
8
|
+
* @param {Function} params.trackClick - Backend function to track the click (handles member lookup internally)
|
|
9
|
+
*/
|
|
10
|
+
function learnMoreOnReady({ $w: _$w, trackClick }) {
|
|
11
|
+
_$w('#learnMoreBtn').onClick(async () => {
|
|
12
|
+
try {
|
|
13
|
+
await trackClick({
|
|
14
|
+
pageName: PAGE_NAME,
|
|
15
|
+
buttonName: BUTTON_NAME,
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
console.log(`Tracked ${BUTTON_NAME} click on ${PAGE_NAME}`);
|
|
19
|
+
} catch (error) {
|
|
20
|
+
console.error('Error tracking button click:', error);
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
module.exports = {
|
|
26
|
+
learnMoreOnReady,
|
|
27
|
+
};
|
package/pages/Profile.js
CHANGED
|
@@ -2,7 +2,11 @@ const { location: wixLocation } = require('@wix/site-location');
|
|
|
2
2
|
const { window: wixWindow } = require('@wix/site-window');
|
|
3
3
|
|
|
4
4
|
const { LIGHTBOX_NAMES } = require('../public/consts');
|
|
5
|
-
const {
|
|
5
|
+
const {
|
|
6
|
+
generateId,
|
|
7
|
+
formatPracticeAreasForDisplay,
|
|
8
|
+
isWixHostedImage,
|
|
9
|
+
} = require('../public/Utils/sharedUtils');
|
|
6
10
|
|
|
7
11
|
const TESTIMONIALS_PER_PAGE_CONFIG = {
|
|
8
12
|
DESKTOP: 4,
|
|
@@ -117,7 +121,7 @@ async function profileOnReady({ $w: _$w }) {
|
|
|
117
121
|
_$w('#logoImage').delete();
|
|
118
122
|
}
|
|
119
123
|
|
|
120
|
-
if (profileData.profileImage) {
|
|
124
|
+
if (profileData.profileImage && isWixHostedImage(profileData.profileImage)) {
|
|
121
125
|
_$w('#profileImage').src = profileData.profileImage;
|
|
122
126
|
} else {
|
|
123
127
|
_$w('#profileImage').src = profileData.defaultProfileImage;
|
package/pages/index.js
CHANGED
package/pages/personalDetails.js
CHANGED
|
@@ -9,7 +9,7 @@ const {
|
|
|
9
9
|
LIGHTBOX_NAMES,
|
|
10
10
|
} = require('../public/consts');
|
|
11
11
|
const { handleOnCustomValidation, isNotValidUrl } = require('../public/Utils/personalDetailsUtils');
|
|
12
|
-
const { generateId } = require('../public/Utils/sharedUtils');
|
|
12
|
+
const { generateId, isWixHostedImage } = require('../public/Utils/sharedUtils');
|
|
13
13
|
|
|
14
14
|
const MAX_PHONES_COUNT = 10;
|
|
15
15
|
const MAX_ADDRESSES_COUNT = 10;
|
|
@@ -793,8 +793,14 @@ async function personalDetailsOnReady({
|
|
|
793
793
|
: null
|
|
794
794
|
: itemMemberObj[key];
|
|
795
795
|
|
|
796
|
-
if (imageValue) {
|
|
797
|
-
|
|
796
|
+
if (imageValue && imageValue?.trim()) {
|
|
797
|
+
// Only set profile image if it's Wix-hosted; other images will always be wix url
|
|
798
|
+
const isProfileImage = imageSelector === '#profileImage';
|
|
799
|
+
const shouldSetImage = !isProfileImage || isWixHostedImage(imageValue);
|
|
800
|
+
|
|
801
|
+
if (shouldSetImage) {
|
|
802
|
+
_$w(imageSelector).src = imageValue;
|
|
803
|
+
}
|
|
798
804
|
_$w(nameSelector).text = formatFileName(extractFileName(imageValue));
|
|
799
805
|
_$w(containerSelector).expand();
|
|
800
806
|
uploadedImages[key === 'bannerImages' ? 'bannerImage' : key] = imageValue;
|
|
@@ -158,6 +158,13 @@ function generateId() {
|
|
|
158
158
|
return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
159
159
|
}
|
|
160
160
|
|
|
161
|
+
function isWixHostedImage(imageUrl) {
|
|
162
|
+
return (
|
|
163
|
+
imageUrl?.trim() &&
|
|
164
|
+
(imageUrl?.startsWith('wix:') || imageUrl?.startsWith('https://static.wixstatic.com'))
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
|
|
161
168
|
module.exports = {
|
|
162
169
|
checkAddressIsVisible,
|
|
163
170
|
formatPracticeAreasForDisplay,
|
|
@@ -169,4 +176,5 @@ module.exports = {
|
|
|
169
176
|
toRadians,
|
|
170
177
|
generateId,
|
|
171
178
|
formatAddress,
|
|
179
|
+
isWixHostedImage,
|
|
172
180
|
};
|