abmp-npm 1.1.89 → 1.1.91
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/contacts-methods.js +58 -35
- package/backend/daily-pull/bulk-process-methods.js +1 -1
- package/backend/daily-pull/utils.js +14 -1
- package/backend/dev-only-methods.js +13 -1
- package/backend/forms-methods.js +3 -3
- package/backend/login/qa-login-methods.js +8 -31
- package/backend/login/sso-methods.js +5 -5
- package/backend/members-area-methods.js +14 -11
- package/backend/members-data-methods.js +108 -30
- package/backend/tasks/consts.js +2 -0
- package/backend/tasks/tasks-configs.js +16 -0
- package/backend/tasks/tasks-process-methods.js +44 -0
- package/package.json +1 -1
- package/pages/Home.js +10 -3
- package/pages/LearnMore.js +27 -0
- package/pages/index.js +1 -0
- package/public/consts.js +1 -0
|
@@ -3,7 +3,33 @@ const { auth } = require('@wix/essentials');
|
|
|
3
3
|
|
|
4
4
|
const elevatedGetContact = auth.elevate(contacts.getContact);
|
|
5
5
|
const elevatedUpdateContact = auth.elevate(contacts.updateContact);
|
|
6
|
+
const elevatedCreateContact = auth.elevate(contacts.createContact);
|
|
6
7
|
|
|
8
|
+
/**
|
|
9
|
+
* Create a contact in Wix CRM
|
|
10
|
+
* @param {Object} contactData - Contact data
|
|
11
|
+
* @param {boolean} allowDuplicates - Allow duplicates if contact with same email already exists, will be true only when handling existing members, after that should be removed
|
|
12
|
+
* @returns {Promise<Object>} - Contact data
|
|
13
|
+
*/
|
|
14
|
+
async function createContact(contactData, allowDuplicates = false) {
|
|
15
|
+
if (!contactData || !(contactData.contactFormEmail || contactData.email)) {
|
|
16
|
+
throw new Error('Contact data is required');
|
|
17
|
+
}
|
|
18
|
+
const phones =
|
|
19
|
+
Array.isArray(contactData.phones) && contactData.phones.length > 0 ? contactData.phones : [];
|
|
20
|
+
const contactInfo = {
|
|
21
|
+
name: {
|
|
22
|
+
first: contactData.firstName,
|
|
23
|
+
last: contactData.lastName,
|
|
24
|
+
},
|
|
25
|
+
emails: [
|
|
26
|
+
{ items: [{ email: contactData.contactFormEmail || contactData.email, primary: true }] },
|
|
27
|
+
],
|
|
28
|
+
phones: [{ items: phones.map(phone => ({ phone })) }],
|
|
29
|
+
};
|
|
30
|
+
const createContactResponse = await elevatedCreateContact(contactInfo, { allowDuplicates });
|
|
31
|
+
return createContactResponse.contact._id;
|
|
32
|
+
}
|
|
7
33
|
/**
|
|
8
34
|
* Generic contact update helper function
|
|
9
35
|
* @param {string} contactId - The contact ID in Wix CRM
|
|
@@ -14,18 +40,13 @@ async function updateContactInfo(contactId, updateInfoCallback, operationName) {
|
|
|
14
40
|
if (!contactId) {
|
|
15
41
|
throw new Error('Contact ID is required');
|
|
16
42
|
}
|
|
17
|
-
|
|
18
|
-
console.log('updateContactInfo operationName', operationName);
|
|
43
|
+
|
|
19
44
|
try {
|
|
20
45
|
const contact = await elevatedGetContact(contactId);
|
|
21
|
-
console.log('updateContactInfo contact', contact);
|
|
22
46
|
const currentInfo = contact.info;
|
|
23
|
-
console.log('updateContactInfo currentInfo', currentInfo);
|
|
24
47
|
const updatedInfo = updateInfoCallback(currentInfo);
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
console.log('updateContactInfo updatedContact', updatedContact);
|
|
28
|
-
return updatedContact;
|
|
48
|
+
|
|
49
|
+
await elevatedUpdateContact(contactId, updatedInfo, contact.revision);
|
|
29
50
|
} catch (error) {
|
|
30
51
|
console.error(`Error in ${operationName}:`, error);
|
|
31
52
|
throw new Error(`Failed to ${operationName}: ${error.message}`);
|
|
@@ -38,8 +59,6 @@ async function updateContactInfo(contactId, updateInfoCallback, operationName) {
|
|
|
38
59
|
* @param {string} newEmail - The new email address
|
|
39
60
|
*/
|
|
40
61
|
async function updateContactEmail(contactId, newEmail) {
|
|
41
|
-
console.log('updateContactEmail contactId', contactId);
|
|
42
|
-
console.log('updateContactEmail newEmail', newEmail);
|
|
43
62
|
if (!newEmail) {
|
|
44
63
|
throw new Error('New email is required');
|
|
45
64
|
}
|
|
@@ -62,27 +81,33 @@ async function updateContactEmail(contactId, newEmail) {
|
|
|
62
81
|
}
|
|
63
82
|
|
|
64
83
|
/**
|
|
65
|
-
* Updates contact names in Wix CRM
|
|
66
|
-
* @param {
|
|
67
|
-
* @param {string}
|
|
68
|
-
* @param {string}
|
|
84
|
+
* Updates contact names in Wix CRM for both contact and member
|
|
85
|
+
* @param {Object} params - Parameters object
|
|
86
|
+
* @param {string} params.wixContactId - The contact ID in Wix CRM
|
|
87
|
+
* @param {string} params.wixMemberId - The member ID in Wix CRM
|
|
88
|
+
* @param {string} params.firstName - The new first name
|
|
89
|
+
* @param {string} params.lastName - The new last name
|
|
69
90
|
*/
|
|
70
|
-
async function
|
|
91
|
+
async function updateMemberAndContactNames({ wixContactId, wixMemberId, firstName, lastName }) {
|
|
92
|
+
//TODO: rethink if we should keep all info just in contact, meaning no need to update the member
|
|
71
93
|
if (!firstName && !lastName) {
|
|
72
94
|
throw new Error('At least one name field is required');
|
|
73
95
|
}
|
|
74
96
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
'update contact names'
|
|
85
|
-
|
|
97
|
+
const createNameUpdate = currentInfo => ({
|
|
98
|
+
...currentInfo,
|
|
99
|
+
name: {
|
|
100
|
+
first: firstName || currentInfo?.name?.first || '',
|
|
101
|
+
last: lastName || currentInfo?.name?.last || '',
|
|
102
|
+
},
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
const updatePromises = [
|
|
106
|
+
wixContactId && updateContactInfo(wixContactId, createNameUpdate, 'update contact names'),
|
|
107
|
+
wixMemberId && updateContactInfo(wixMemberId, createNameUpdate, 'update member names'),
|
|
108
|
+
].filter(Boolean);
|
|
109
|
+
|
|
110
|
+
return await Promise.all(updatePromises);
|
|
86
111
|
}
|
|
87
112
|
|
|
88
113
|
/**
|
|
@@ -95,7 +120,6 @@ async function updateContactNames(contactId, firstName, lastName) {
|
|
|
95
120
|
const updateIfChanged = (existingValues, newValues, updater, argsBuilder) => {
|
|
96
121
|
const hasChanged = existingValues.some((val, idx) => val !== newValues[idx]);
|
|
97
122
|
if (!hasChanged) return null;
|
|
98
|
-
console.log('updateIfChanged hasChanged', hasChanged);
|
|
99
123
|
return updater(...argsBuilder(newValues));
|
|
100
124
|
};
|
|
101
125
|
|
|
@@ -105,18 +129,18 @@ const updateIfChanged = (existingValues, newValues, updater, argsBuilder) => {
|
|
|
105
129
|
* @param {Object} existingMemberData - Existing member data
|
|
106
130
|
*/
|
|
107
131
|
const updateMemberContactInfo = async (data, existingMemberData) => {
|
|
108
|
-
const {
|
|
109
|
-
|
|
132
|
+
const { wixContactId, wixMemberId } = existingMemberData;
|
|
133
|
+
|
|
110
134
|
const updateConfig = [
|
|
111
135
|
{
|
|
112
136
|
fields: ['contactFormEmail'],
|
|
113
137
|
updater: updateContactEmail,
|
|
114
|
-
args: ([email]) => [
|
|
138
|
+
args: ([email]) => [wixContactId, email],
|
|
115
139
|
},
|
|
116
140
|
{
|
|
117
141
|
fields: ['firstName', 'lastName'],
|
|
118
|
-
updater:
|
|
119
|
-
args: ([firstName, lastName]) => [
|
|
142
|
+
updater: updateMemberAndContactNames,
|
|
143
|
+
args: ([firstName, lastName]) => [{ firstName, lastName, wixContactId, wixMemberId }],
|
|
120
144
|
},
|
|
121
145
|
];
|
|
122
146
|
|
|
@@ -128,11 +152,10 @@ const updateMemberContactInfo = async (data, existingMemberData) => {
|
|
|
128
152
|
})
|
|
129
153
|
.filter(Boolean);
|
|
130
154
|
|
|
131
|
-
|
|
132
|
-
console.log('updateMemberContactInfo updatePromises', resp);
|
|
133
|
-
return resp;
|
|
155
|
+
await Promise.all(updatePromises);
|
|
134
156
|
};
|
|
135
157
|
|
|
136
158
|
module.exports = {
|
|
137
159
|
updateMemberContactInfo,
|
|
160
|
+
createContact,
|
|
138
161
|
};
|
|
@@ -168,7 +168,7 @@ const bulkProcessAndSaveMemberData = async ({
|
|
|
168
168
|
const toChangeWixMembersEmails = [];
|
|
169
169
|
const toSaveMembersData = uniqueUrlsMembersData.map(member => {
|
|
170
170
|
const { isLoginEmailChanged, isNewToDb: _isNewToDb, ...restMemberData } = member;
|
|
171
|
-
if (member.
|
|
171
|
+
if (member.wixMemberId && isLoginEmailChanged) {
|
|
172
172
|
toChangeWixMembersEmails.push(member);
|
|
173
173
|
}
|
|
174
174
|
return restMemberData; //we don't want to store the isLoginEmailChanged in the database, it's just a flag to know if we need to change the login email in Members area
|
|
@@ -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,3 +1,5 @@
|
|
|
1
|
+
const { COLLECTIONS } = require('../public/consts');
|
|
2
|
+
|
|
1
3
|
const { ensureUniqueUrlsInBatch } = require('./daily-pull/bulk-process-methods');
|
|
2
4
|
const { wixData } = require('./elevated-modules');
|
|
3
5
|
const { bulkSaveMembers } = require('./members-data-methods');
|
|
@@ -15,4 +17,14 @@ async function deduplicateURls(collectionName, duplicateUrlsList) {
|
|
|
15
17
|
return await bulkSaveMembers(membersWithUniqueUrls, collectionName);
|
|
16
18
|
}
|
|
17
19
|
|
|
18
|
-
|
|
20
|
+
async function copyContactIdToWixMemberId() {
|
|
21
|
+
const query = wixData.query(COLLECTIONS.MEMBERS_DATA).isNotEmpty('contactId');
|
|
22
|
+
const members = await queryAllItems(query);
|
|
23
|
+
const updatedMembers = members.map(member => ({
|
|
24
|
+
...member,
|
|
25
|
+
wixMemberId: member.contactId,
|
|
26
|
+
}));
|
|
27
|
+
return await bulkSaveMembers(updatedMembers, COLLECTIONS.MEMBERS_DATA);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
module.exports = { deduplicateURls, copyContactIdToWixMemberId };
|
package/backend/forms-methods.js
CHANGED
|
@@ -16,7 +16,7 @@ const contactSubmission = async (data, memberDataId) => {
|
|
|
16
16
|
console.log('Member contact form is not enabled for user, skipping contact submission!');
|
|
17
17
|
return;
|
|
18
18
|
}
|
|
19
|
-
let memberContactId = memberData.
|
|
19
|
+
let memberContactId = memberData.wixContactId;
|
|
20
20
|
if (!memberContactId) {
|
|
21
21
|
/**
|
|
22
22
|
* Create a member contact here since some members may have never logged in
|
|
@@ -27,7 +27,7 @@ const contactSubmission = async (data, memberDataId) => {
|
|
|
27
27
|
*/
|
|
28
28
|
console.info('Member contact id not found for user, creating new contact!');
|
|
29
29
|
const member = await createContactAndMemberIfNew(memberData);
|
|
30
|
-
memberContactId = member.
|
|
30
|
+
memberContactId = member.wixContactId;
|
|
31
31
|
}
|
|
32
32
|
console.log('memberContactId', memberContactId);
|
|
33
33
|
const emailTriggered = await triggerAutomation(automationEmailTriggerId, {
|
|
@@ -40,7 +40,7 @@ const contactSubmission = async (data, memberDataId) => {
|
|
|
40
40
|
data = {
|
|
41
41
|
...data,
|
|
42
42
|
phone: Number(data.phone),
|
|
43
|
-
memberContactId
|
|
43
|
+
memberContactId,
|
|
44
44
|
memberEmail: memberData.contactFormEmail,
|
|
45
45
|
};
|
|
46
46
|
await wixData.insert(COLLECTIONS.CONTACT_US_SUBMISSIONS, data);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const {
|
|
1
|
+
const { prepareMemberForQALogin, getQAUsers } = require('../members-data-methods');
|
|
2
2
|
const { getSecret } = require('../utils');
|
|
3
3
|
|
|
4
4
|
const validateQAUser = async userEmail => {
|
|
@@ -20,27 +20,23 @@ const validateQAUser = async userEmail => {
|
|
|
20
20
|
*/
|
|
21
21
|
const loginQAMember = async ({ userEmail, secret }, generateSessionToken) => {
|
|
22
22
|
try {
|
|
23
|
-
const userValidation = await
|
|
23
|
+
const [userValidation, qaSecret] = await Promise.all([
|
|
24
|
+
validateQAUser(userEmail),
|
|
25
|
+
getSecret('ABMP_QA_SECRET'),
|
|
26
|
+
]);
|
|
24
27
|
if (userValidation.error) {
|
|
25
28
|
return { success: false, error: userValidation.error };
|
|
26
29
|
}
|
|
27
|
-
|
|
28
|
-
const qaSecret = await getSecret('ABMP_QA_SECRET');
|
|
29
30
|
if (secret !== qaSecret) {
|
|
30
31
|
return { success: false, error: 'Invalid secret' };
|
|
31
32
|
}
|
|
32
33
|
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
const result = await getMemberCMSId(userEmail);
|
|
36
|
-
if (!result.success) {
|
|
37
|
-
return { success: false, error: result.error };
|
|
38
|
-
}
|
|
39
|
-
|
|
34
|
+
const memberData = await prepareMemberForQALogin(userValidation.email);
|
|
35
|
+
const token = await generateSessionToken(memberData.email, qaSecret);
|
|
40
36
|
return {
|
|
41
37
|
success: true,
|
|
42
38
|
token,
|
|
43
|
-
memberCMSId:
|
|
39
|
+
memberCMSId: memberData._id,
|
|
44
40
|
};
|
|
45
41
|
} catch (error) {
|
|
46
42
|
console.error('QA login error:', error);
|
|
@@ -48,25 +44,6 @@ const loginQAMember = async ({ userEmail, secret }, generateSessionToken) => {
|
|
|
48
44
|
}
|
|
49
45
|
};
|
|
50
46
|
|
|
51
|
-
async function getMemberCMSId(userEmail) {
|
|
52
|
-
try {
|
|
53
|
-
const userValidation = await validateQAUser(userEmail);
|
|
54
|
-
if (userValidation.error) {
|
|
55
|
-
return { success: false, error: userValidation.error };
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
const member = await getMemberByEmail(userEmail);
|
|
59
|
-
|
|
60
|
-
if (!member) {
|
|
61
|
-
return { success: false, error: `No Member found in DB matching email: ${userEmail}` };
|
|
62
|
-
}
|
|
63
|
-
return { success: true, memberCMSId: member._id };
|
|
64
|
-
} catch (error) {
|
|
65
|
-
console.error('Error getting member CMS ID:', error);
|
|
66
|
-
return { success: false, error: 'Failed to retrieve member data' };
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
47
|
module.exports = {
|
|
71
48
|
loginQAMember,
|
|
72
49
|
};
|
|
@@ -5,7 +5,7 @@ const { decode } = require('jwt-js-decode');
|
|
|
5
5
|
const { CONFIG_KEYS, SSO_TOKEN_AUTH_API_URL } = require('../consts');
|
|
6
6
|
const { MEMBER_ACTIONS } = require('../daily-pull/consts');
|
|
7
7
|
const { getCurrentMember } = require('../members-area-methods');
|
|
8
|
-
const { getMemberByContactId,
|
|
8
|
+
const { getMemberByContactId, prepareMemberForSSOLogin } = require('../members-data-methods');
|
|
9
9
|
const {
|
|
10
10
|
formatDateToMonthYear,
|
|
11
11
|
getAddressDisplayOptions,
|
|
@@ -133,12 +133,12 @@ const authenticateSSOToken = async ({ token }, generateSessionToken) => {
|
|
|
133
133
|
if (isValidToken) {
|
|
134
134
|
const jwt = decode(responseToken);
|
|
135
135
|
const payload = jwt.payload;
|
|
136
|
-
const
|
|
137
|
-
console.log('
|
|
138
|
-
const sessionToken = await generateSessionToken(
|
|
136
|
+
const memberData = await prepareMemberForSSOLogin(payload);
|
|
137
|
+
console.log('memberDataCollectionId', memberData._id);
|
|
138
|
+
const sessionToken = await generateSessionToken(memberData.email);
|
|
139
139
|
const authObj = {
|
|
140
140
|
type: 'success',
|
|
141
|
-
memberId:
|
|
141
|
+
memberId: memberData._id,
|
|
142
142
|
sessionToken,
|
|
143
143
|
};
|
|
144
144
|
return authObj;
|
|
@@ -2,10 +2,11 @@ const { auth } = require('@wix/essentials');
|
|
|
2
2
|
const { members, authentication } = require('@wix/members');
|
|
3
3
|
const elevatedCreateMember = auth.elevate(members.createMember);
|
|
4
4
|
|
|
5
|
-
function
|
|
5
|
+
function prepareMemberData(partner) {
|
|
6
6
|
const phones = Array.isArray(partner.phones) ? partner.phones : []; //some users don't have phones
|
|
7
7
|
const options = {
|
|
8
8
|
member: {
|
|
9
|
+
//Keeping contact creation in member data for future purposes, in case we need to use it later
|
|
9
10
|
contact: {
|
|
10
11
|
...partner,
|
|
11
12
|
phones,
|
|
@@ -22,9 +23,8 @@ async function createMemberFunction(member) {
|
|
|
22
23
|
}
|
|
23
24
|
const createSiteMember = async memberDetails => {
|
|
24
25
|
try {
|
|
25
|
-
const options =
|
|
26
|
-
|
|
27
|
-
return contactId;
|
|
26
|
+
const options = prepareMemberData(memberDetails);
|
|
27
|
+
return await createMemberFunction(options);
|
|
28
28
|
} catch (error) {
|
|
29
29
|
console.error(`Error in createSiteMember ${error.message}`);
|
|
30
30
|
throw error;
|
|
@@ -37,22 +37,25 @@ const getCurrentMember = async () => {
|
|
|
37
37
|
};
|
|
38
38
|
|
|
39
39
|
/**
|
|
40
|
-
* Updates Wix member login email if the member has a
|
|
41
|
-
* @param {Object} member - Member object with
|
|
40
|
+
* Updates Wix member login email if the member has a wixMemberId (registered Wix member)
|
|
41
|
+
* @param {Object} member - Member object with wixMemberId and email
|
|
42
42
|
* @param {Object} result - Result object to track Wix member updates
|
|
43
43
|
*/
|
|
44
44
|
async function updateWixMemberLoginEmail(member, result = {}) {
|
|
45
|
-
if (!member.
|
|
46
|
-
console.log(`Member ${member.memberId} has no
|
|
45
|
+
if (!member.wixMemberId) {
|
|
46
|
+
console.log(`Member ${member.memberId} has no wixMemberId - skipping Wix login email update`);
|
|
47
47
|
return;
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
try {
|
|
51
51
|
console.log(
|
|
52
|
-
`Updating Wix login email for member ${member.memberId} (
|
|
52
|
+
`Updating Wix login email for member ${member.memberId} (wixMemberId: ${member.wixMemberId})`
|
|
53
53
|
);
|
|
54
54
|
|
|
55
|
-
const updatedWixMember = await authentication.changeLoginEmail(
|
|
55
|
+
const updatedWixMember = await authentication.changeLoginEmail(
|
|
56
|
+
member.wixMemberId,
|
|
57
|
+
member.email
|
|
58
|
+
);
|
|
56
59
|
|
|
57
60
|
console.log(
|
|
58
61
|
`✅ Successfully updated Wix login email for member ${member.memberId}: ${updatedWixMember.loginEmail}`
|
|
@@ -75,7 +78,7 @@ async function updateWixMemberLoginEmail(member, result = {}) {
|
|
|
75
78
|
}
|
|
76
79
|
result.wixMemberErrors.push({
|
|
77
80
|
memberId: member.memberId,
|
|
78
|
-
|
|
81
|
+
wixMemberId: member.wixMemberId,
|
|
79
82
|
email: member.email,
|
|
80
83
|
error: error.message,
|
|
81
84
|
});
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
const { COLLECTIONS } = require('../public/consts');
|
|
2
2
|
|
|
3
3
|
const { MEMBERSHIPS_TYPES } = require('./consts');
|
|
4
|
-
const { updateMemberContactInfo } = require('./contacts-methods');
|
|
4
|
+
const { updateMemberContactInfo, createContact } = require('./contacts-methods');
|
|
5
5
|
const { MEMBER_ACTIONS } = require('./daily-pull/consts');
|
|
6
6
|
const { wixData } = require('./elevated-modules');
|
|
7
|
-
const { createSiteMember } = require('./members-area-methods');
|
|
7
|
+
const { createSiteMember, getCurrentMember } = require('./members-area-methods');
|
|
8
8
|
const {
|
|
9
9
|
chunkArray,
|
|
10
10
|
normalizeUrlForComparison,
|
|
@@ -42,10 +42,14 @@ async function createContactAndMemberIfNew(memberData) {
|
|
|
42
42
|
phones: memberData.phones,
|
|
43
43
|
contactFormEmail: memberData.contactFormEmail || memberData.email,
|
|
44
44
|
};
|
|
45
|
-
const
|
|
45
|
+
const [wixMemberId, wixContactId] = await Promise.all([
|
|
46
|
+
createSiteMember(toCreateMemberData),
|
|
47
|
+
createContact(toCreateMemberData),
|
|
48
|
+
]);
|
|
46
49
|
let memberDataWithContactId = {
|
|
47
50
|
...memberData,
|
|
48
|
-
|
|
51
|
+
wixMemberId,
|
|
52
|
+
wixContactId,
|
|
49
53
|
};
|
|
50
54
|
const updatedResult = await updateMember(memberDataWithContactId);
|
|
51
55
|
memberDataWithContactId = {
|
|
@@ -93,10 +97,16 @@ async function findMemberById(memberId) {
|
|
|
93
97
|
const queryResult = await wixData
|
|
94
98
|
.query(COLLECTIONS.MEMBERS_DATA)
|
|
95
99
|
.eq('memberId', memberId)
|
|
100
|
+
.limit(2)
|
|
96
101
|
.find();
|
|
97
|
-
|
|
98
|
-
|
|
102
|
+
if (queryResult.items.length > 1) {
|
|
103
|
+
throw new Error(
|
|
104
|
+
`Multiple members found with memberId ${memberId} members _ids are : [${queryResult.items.map(member => member._id).join(', ')}]`
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
return queryResult.items.length === 1 ? queryResult.items[0] : null;
|
|
99
108
|
} catch (error) {
|
|
109
|
+
console.error('Error finding member by ID:', error);
|
|
100
110
|
throw new Error(`Failed to retrieve member data: ${error.message}`);
|
|
101
111
|
}
|
|
102
112
|
}
|
|
@@ -441,45 +451,111 @@ const getQAUsers = async () => {
|
|
|
441
451
|
throw new Error(`Failed to get QA users: ${error.message}`);
|
|
442
452
|
}
|
|
443
453
|
};
|
|
444
|
-
|
|
454
|
+
/**
|
|
455
|
+
* Ensures member has a contact - creates one if missing
|
|
456
|
+
* @param {Object} memberData - Member data from DB
|
|
457
|
+
* @returns {Promise<Object>} - Member data with contactId
|
|
458
|
+
*/
|
|
459
|
+
async function ensureMemberHasContact(memberData) {
|
|
460
|
+
if (!memberData) {
|
|
461
|
+
throw new Error('Member data is required');
|
|
462
|
+
}
|
|
463
|
+
if (!memberData.contactId) {
|
|
464
|
+
const memberDataWithContactId = await createContactAndMemberIfNew(memberData);
|
|
465
|
+
return memberDataWithContactId;
|
|
466
|
+
}
|
|
467
|
+
return memberData;
|
|
468
|
+
}
|
|
469
|
+
async function prepareMemberForSSOLogin(data) {
|
|
445
470
|
try {
|
|
446
471
|
console.log('data', data);
|
|
447
472
|
const memberId = data?.pac?.cst_recno;
|
|
448
473
|
if (!memberId) {
|
|
449
|
-
|
|
450
|
-
console.error(errorMessage);
|
|
451
|
-
throw new Error(errorMessage);
|
|
474
|
+
throw new Error(`Member ID is missing in passed data ${JSON.stringify(data)}`);
|
|
452
475
|
}
|
|
453
|
-
const
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
.find()
|
|
457
|
-
.then(res => res.items);
|
|
458
|
-
if (!queryMemberResult.length || queryMemberResult.length > 1) {
|
|
459
|
-
throw new Error(
|
|
460
|
-
`Invalid Members count found in DB for email ${data.email} members count is : [${
|
|
461
|
-
queryMemberResult.length
|
|
462
|
-
}] membersIds are : [${queryMemberResult.map(member => member.memberId).join(', ')}]`
|
|
463
|
-
);
|
|
476
|
+
const memberData = await findMemberById(Number(memberId));
|
|
477
|
+
if (!memberData) {
|
|
478
|
+
throw new Error(`Member data not found for memberId ${memberId}`);
|
|
464
479
|
}
|
|
465
|
-
let memberData = queryMemberResult[0];
|
|
466
480
|
console.log('memberData', memberData);
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
481
|
+
return await ensureMemberHasContact(memberData);
|
|
482
|
+
} catch (error) {
|
|
483
|
+
console.error('Error in prepareMemberForSSOLogin', error.message);
|
|
484
|
+
throw error;
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
async function prepareMemberForQALogin(email) {
|
|
488
|
+
try {
|
|
489
|
+
console.log('qa email:', email);
|
|
490
|
+
if (!email) {
|
|
491
|
+
throw new Error(`Email is missing in passed data ${email}`);
|
|
492
|
+
}
|
|
493
|
+
const memberData = await getMemberByEmail(email);
|
|
494
|
+
if (!memberData) {
|
|
495
|
+
throw new Error(`Member data not found for email ${email}`);
|
|
472
496
|
}
|
|
473
|
-
|
|
497
|
+
console.log('memberData', memberData);
|
|
498
|
+
return await ensureMemberHasContact(memberData);
|
|
499
|
+
} catch (error) {
|
|
500
|
+
console.error('Error in prepareMemberForQALogin', error.message);
|
|
501
|
+
throw error;
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
/**
|
|
506
|
+
* Tracks a button click with member and location info.
|
|
507
|
+
* @param {Object} params - Parameters
|
|
508
|
+
* @param {string} params.pageName - Name of the page/popup where button was clicked
|
|
509
|
+
* @param {string} params.buttonName - Name/ID of the button that was clicked
|
|
510
|
+
* @returns {Promise<Object>} - Saved record or null if member not found
|
|
511
|
+
*/
|
|
512
|
+
async function trackButtonClick({ pageName, buttonName }) {
|
|
513
|
+
const wixMember = await getCurrentMember();
|
|
514
|
+
|
|
515
|
+
if (!wixMember) {
|
|
516
|
+
console.warn('[trackButtonClick]: No logged in member found');
|
|
517
|
+
return null;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
const dbMember = await getMemberByContactId(wixMember._id);
|
|
521
|
+
|
|
522
|
+
if (!dbMember) {
|
|
523
|
+
console.warn(
|
|
524
|
+
`[trackButtonClick]: Member not found in MembersDataLatest for contactId: ${wixMember._id}`
|
|
525
|
+
);
|
|
526
|
+
return null;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
const memberName = dbMember.fullName || 'Unknown';
|
|
530
|
+
const memberId = dbMember.memberId;
|
|
531
|
+
|
|
532
|
+
const clickData = {
|
|
533
|
+
memberName,
|
|
534
|
+
memberId,
|
|
535
|
+
pageName,
|
|
536
|
+
buttonName,
|
|
537
|
+
clickedAt: new Date(),
|
|
538
|
+
};
|
|
539
|
+
|
|
540
|
+
try {
|
|
541
|
+
const result = await wixData.insert(COLLECTIONS.BUTTON_CLICKS, clickData);
|
|
542
|
+
console.log(`Tracked ${buttonName} click on ${pageName} for member ${memberId}`);
|
|
543
|
+
return result;
|
|
474
544
|
} catch (error) {
|
|
475
|
-
console.error(
|
|
545
|
+
console.error(`Error tracking ${buttonName} click:`, error);
|
|
476
546
|
throw error;
|
|
477
547
|
}
|
|
478
548
|
}
|
|
479
549
|
|
|
550
|
+
async function getAllMembersWithWixMemberId() {
|
|
551
|
+
const membersQuery = wixData.query(COLLECTIONS.MEMBERS_DATA).isNotEmpty('wixMemberId');
|
|
552
|
+
return await queryAllItems(membersQuery);
|
|
553
|
+
}
|
|
554
|
+
|
|
480
555
|
module.exports = {
|
|
481
556
|
findMemberByWixDataId,
|
|
482
557
|
createContactAndMemberIfNew,
|
|
558
|
+
getAllMembersWithWixMemberId,
|
|
483
559
|
saveRegistrationData,
|
|
484
560
|
bulkSaveMembers,
|
|
485
561
|
findMemberById,
|
|
@@ -494,6 +570,8 @@ module.exports = {
|
|
|
494
570
|
getMembersByIds,
|
|
495
571
|
getMemberByEmail,
|
|
496
572
|
getQAUsers,
|
|
497
|
-
|
|
573
|
+
prepareMemberForSSOLogin,
|
|
574
|
+
prepareMemberForQALogin,
|
|
498
575
|
checkUrlUniqueness,
|
|
576
|
+
trackButtonClick,
|
|
499
577
|
};
|
package/backend/tasks/consts.js
CHANGED
|
@@ -16,6 +16,8 @@ const TASKS_NAMES = {
|
|
|
16
16
|
migrateUrlsChunk: 'migrateUrlsChunk',
|
|
17
17
|
scheduleGenerateMissingUrls: 'scheduleGenerateMissingUrls',
|
|
18
18
|
generateUrlsChunk: 'generateUrlsChunk',
|
|
19
|
+
scheduleCreateContactsFromMembers: 'scheduleCreateContactsFromMembers',
|
|
20
|
+
createContactsFromMembers: 'createContactsFromMembers',
|
|
19
21
|
};
|
|
20
22
|
|
|
21
23
|
module.exports = {
|
|
@@ -16,6 +16,8 @@ const {
|
|
|
16
16
|
migrateContactFormEmails,
|
|
17
17
|
scheduleEmailSync,
|
|
18
18
|
syncMemberLoginEmails,
|
|
19
|
+
scheduleCreateContactsFromMembers,
|
|
20
|
+
createContactsFromMembers,
|
|
19
21
|
} = require('./tasks-process-methods');
|
|
20
22
|
const {
|
|
21
23
|
scheduleMigrateExistingUrls,
|
|
@@ -153,6 +155,20 @@ const TASKS = {
|
|
|
153
155
|
shouldSkipCheck: () => false,
|
|
154
156
|
estimatedDurationSec: 80,
|
|
155
157
|
},
|
|
158
|
+
[TASKS_NAMES.scheduleCreateContactsFromMembers]: {
|
|
159
|
+
name: TASKS_NAMES.scheduleCreateContactsFromMembers,
|
|
160
|
+
getIdentifier: () => 'SHOULD_NEVER_SKIP',
|
|
161
|
+
process: scheduleCreateContactsFromMembers,
|
|
162
|
+
shouldSkipCheck: () => false,
|
|
163
|
+
estimatedDurationSec: 80,
|
|
164
|
+
},
|
|
165
|
+
[TASKS_NAMES.createContactsFromMembers]: {
|
|
166
|
+
name: TASKS_NAMES.createContactsFromMembers,
|
|
167
|
+
getIdentifier: task => task.data,
|
|
168
|
+
process: createContactsFromMembers,
|
|
169
|
+
shouldSkipCheck: () => false,
|
|
170
|
+
estimatedDurationSec: 80,
|
|
171
|
+
},
|
|
156
172
|
};
|
|
157
173
|
|
|
158
174
|
module.exports = { TASKS };
|
|
@@ -13,6 +13,8 @@ const {
|
|
|
13
13
|
bulkSaveMembers,
|
|
14
14
|
getAllUpdatedLoginEmails,
|
|
15
15
|
getMembersByIds,
|
|
16
|
+
createContactAndMemberIfNew,
|
|
17
|
+
getAllMembersWithWixMemberId,
|
|
16
18
|
} = require('../members-data-methods');
|
|
17
19
|
const {
|
|
18
20
|
getCompleteStateList,
|
|
@@ -530,6 +532,46 @@ const syncMemberLoginEmails = async data => {
|
|
|
530
532
|
throw new Error(errorMessage);
|
|
531
533
|
}
|
|
532
534
|
};
|
|
535
|
+
/**
|
|
536
|
+
* Schedules tasks to create contacts from members
|
|
537
|
+
* dev-only task, run only once by the developers
|
|
538
|
+
*/
|
|
539
|
+
const scheduleCreateContactsFromMembers = async () => {
|
|
540
|
+
const members = await getAllMembersWithWixMemberId();
|
|
541
|
+
console.log(
|
|
542
|
+
`Starting to schedule create contacts from members tasks for ${members.length} members in chunks of 500 members`
|
|
543
|
+
);
|
|
544
|
+
const membersChunks = chunkArray(members, 500);
|
|
545
|
+
for (let chunkIndex = 0; chunkIndex < membersChunks.length; chunkIndex++) {
|
|
546
|
+
const chunk = membersChunks[chunkIndex];
|
|
547
|
+
const toScheduleTask = {
|
|
548
|
+
name: TASKS_NAMES.createContactsFromMembers,
|
|
549
|
+
data: { chunk, chunkIndex },
|
|
550
|
+
};
|
|
551
|
+
await taskManager().schedule(toScheduleTask);
|
|
552
|
+
console.log(`Scheduled task for chunk ${chunkIndex} with ${chunk.length} members`);
|
|
553
|
+
}
|
|
554
|
+
console.log(`Successfully scheduled ${membersChunks.length} tasks for ${members.length} members`);
|
|
555
|
+
};
|
|
556
|
+
|
|
557
|
+
/**
|
|
558
|
+
* Creates contacts from members
|
|
559
|
+
* dev-only task, run only once by the developers
|
|
560
|
+
*/
|
|
561
|
+
const createContactsFromMembers = async data => {
|
|
562
|
+
const { chunk, chunkIndex } = data;
|
|
563
|
+
console.log(`Creating contacts from ${chunk.length} members in chunk ${chunkIndex}`);
|
|
564
|
+
const createPromises = chunk.map(member => createContactAndMemberIfNew(member));
|
|
565
|
+
const createResults = await Promise.all(createPromises);
|
|
566
|
+
console.log(
|
|
567
|
+
`Created ${createResults.length} contacts from ${chunk.length} members in chunk ${chunkIndex}`
|
|
568
|
+
);
|
|
569
|
+
const saveResult = await bulkSaveMembers(createResults);
|
|
570
|
+
console.log(
|
|
571
|
+
`Successfully saved ${saveResult.totalSaved} contacts from ${chunk.length} members in chunk ${chunkIndex}`
|
|
572
|
+
);
|
|
573
|
+
return saveResult;
|
|
574
|
+
};
|
|
533
575
|
|
|
534
576
|
module.exports = {
|
|
535
577
|
scheduleTaskForEmptyAboutYouMembers,
|
|
@@ -542,4 +584,6 @@ module.exports = {
|
|
|
542
584
|
migrateContactFormEmails,
|
|
543
585
|
scheduleEmailSync,
|
|
544
586
|
syncMemberLoginEmails,
|
|
587
|
+
scheduleCreateContactsFromMembers, // run only once by the developers
|
|
588
|
+
createContactsFromMembers,
|
|
545
589
|
};
|
package/package.json
CHANGED
package/pages/Home.js
CHANGED
|
@@ -216,12 +216,19 @@ const homePageOnReady = async ({
|
|
|
216
216
|
$item('#milesAwayText').text = '';
|
|
217
217
|
}
|
|
218
218
|
|
|
219
|
-
// 7) "Show maps" button enabled only if there's
|
|
219
|
+
// 7) "Show maps" button enabled only if there's a full address with valid coordinates
|
|
220
220
|
const visible = checkAddressIsVisible(addresses);
|
|
221
|
-
|
|
221
|
+
const fullAddressWithValidCoords = visible.find(
|
|
222
|
+
addr =>
|
|
223
|
+
addr.addressStatus === ADDRESS_STATUS_TYPES.FULL_ADDRESS &&
|
|
224
|
+
addr.latitude &&
|
|
225
|
+
addr.longitude
|
|
226
|
+
);
|
|
227
|
+
|
|
228
|
+
if (fullAddressWithValidCoords) {
|
|
222
229
|
$item('#showMaps').enable();
|
|
223
230
|
$item('#showMaps').show();
|
|
224
|
-
const { latitude, longitude } =
|
|
231
|
+
const { latitude, longitude } = fullAddressWithValidCoords;
|
|
225
232
|
$item('#showMaps').link = `https://maps.google.com/?q=${latitude},${longitude}`;
|
|
226
233
|
$item('#showMaps').target = '_blank';
|
|
227
234
|
} 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/index.js
CHANGED