abmp-npm 2.0.76 → 2.0.78

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.
Files changed (99) hide show
  1. package/package.json +8 -1
  2. package/pages/Home.js +27 -55
  3. package/pages/index.js +0 -1
  4. package/public/Utils/personalDetailsUtils.js +5 -1
  5. package/public/Utils/sharedUtils.js +32 -0
  6. package/public/consts.js +0 -1
  7. package/.claude/worktrees/fix-save-button-disable/.husky/pre-commit +0 -19
  8. package/.claude/worktrees/fix-save-button-disable/.prettierignore +0 -7
  9. package/.claude/worktrees/fix-save-button-disable/.prettierrc.json +0 -16
  10. package/.claude/worktrees/fix-save-button-disable/README.md +0 -1
  11. package/.claude/worktrees/fix-save-button-disable/backend/README-member-contact-flows.md +0 -136
  12. package/.claude/worktrees/fix-save-button-disable/backend/__tests__/daily-pull-execution-check.test.js +0 -124
  13. package/.claude/worktrees/fix-save-button-disable/backend/__tests__/ensure-unique-urls-in-batch.test.js +0 -129
  14. package/.claude/worktrees/fix-save-button-disable/backend/__tests__/login-email-sync.test.js +0 -49
  15. package/.claude/worktrees/fix-save-button-disable/backend/__tests__/transient-retry-and-bulk-lookup.test.js +0 -129
  16. package/.claude/worktrees/fix-save-button-disable/backend/__tests__/url-uniqueness.test.js +0 -194
  17. package/.claude/worktrees/fix-save-button-disable/backend/automations-methods.js +0 -13
  18. package/.claude/worktrees/fix-save-button-disable/backend/cms-data-methods.js +0 -251
  19. package/.claude/worktrees/fix-save-button-disable/backend/consts.js +0 -58
  20. package/.claude/worktrees/fix-save-button-disable/backend/contacts-methods.js +0 -67
  21. package/.claude/worktrees/fix-save-button-disable/backend/daily-pull/bulk-process-methods.js +0 -222
  22. package/.claude/worktrees/fix-save-button-disable/backend/daily-pull/consts.js +0 -39
  23. package/.claude/worktrees/fix-save-button-disable/backend/daily-pull/index.js +0 -5
  24. package/.claude/worktrees/fix-save-button-disable/backend/daily-pull/process-member-methods.js +0 -213
  25. package/.claude/worktrees/fix-save-button-disable/backend/daily-pull/schedule-methods.js +0 -41
  26. package/.claude/worktrees/fix-save-button-disable/backend/daily-pull/sync-to-cms-methods.js +0 -161
  27. package/.claude/worktrees/fix-save-button-disable/backend/daily-pull/utils.js +0 -151
  28. package/.claude/worktrees/fix-save-button-disable/backend/data-hooks.js +0 -29
  29. package/.claude/worktrees/fix-save-button-disable/backend/dev-only-methods.js +0 -58
  30. package/.claude/worktrees/fix-save-button-disable/backend/elevated-modules.js +0 -18
  31. package/.claude/worktrees/fix-save-button-disable/backend/forms-methods.js +0 -52
  32. package/.claude/worktrees/fix-save-button-disable/backend/http-functions/httpFunctions.js +0 -86
  33. package/.claude/worktrees/fix-save-button-disable/backend/http-functions/index.js +0 -3
  34. package/.claude/worktrees/fix-save-button-disable/backend/http-functions/interests.js +0 -35
  35. package/.claude/worktrees/fix-save-button-disable/backend/index.js +0 -19
  36. package/.claude/worktrees/fix-save-button-disable/backend/jobs.js +0 -158
  37. package/.claude/worktrees/fix-save-button-disable/backend/login/generate-member-session-token.js +0 -27
  38. package/.claude/worktrees/fix-save-button-disable/backend/login/index.js +0 -8
  39. package/.claude/worktrees/fix-save-button-disable/backend/login/qa-login-methods.js +0 -54
  40. package/.claude/worktrees/fix-save-button-disable/backend/login/sso-methods.js +0 -159
  41. package/.claude/worktrees/fix-save-button-disable/backend/member-contact-orchestration.js +0 -111
  42. package/.claude/worktrees/fix-save-button-disable/backend/members-area-methods.js +0 -88
  43. package/.claude/worktrees/fix-save-button-disable/backend/members-data-methods.js +0 -789
  44. package/.claude/worktrees/fix-save-button-disable/backend/pac-api-methods.js +0 -54
  45. package/.claude/worktrees/fix-save-button-disable/backend/routers/index.js +0 -3
  46. package/.claude/worktrees/fix-save-button-disable/backend/routers/methods.js +0 -191
  47. package/.claude/worktrees/fix-save-button-disable/backend/routers/utils.js +0 -128
  48. package/.claude/worktrees/fix-save-button-disable/backend/search-filters-methods.js +0 -124
  49. package/.claude/worktrees/fix-save-button-disable/backend/tasks/address-primary-methods.js +0 -256
  50. package/.claude/worktrees/fix-save-button-disable/backend/tasks/address-visibility-methods.js +0 -160
  51. package/.claude/worktrees/fix-save-button-disable/backend/tasks/consts.js +0 -34
  52. package/.claude/worktrees/fix-save-button-disable/backend/tasks/daily-pull-check-methods.js +0 -78
  53. package/.claude/worktrees/fix-save-button-disable/backend/tasks/email-normalize-methods.js +0 -134
  54. package/.claude/worktrees/fix-save-button-disable/backend/tasks/index.js +0 -10
  55. package/.claude/worktrees/fix-save-button-disable/backend/tasks/migration-methods.js +0 -46
  56. package/.claude/worktrees/fix-save-button-disable/backend/tasks/tasks-configs.js +0 -251
  57. package/.claude/worktrees/fix-save-button-disable/backend/tasks/tasks-helpers-methods.js +0 -433
  58. package/.claude/worktrees/fix-save-button-disable/backend/tasks/tasks-process-methods.js +0 -606
  59. package/.claude/worktrees/fix-save-button-disable/backend/tasks/url-migration-methods.js +0 -378
  60. package/.claude/worktrees/fix-save-button-disable/backend/tasks/url-space-fix-methods.js +0 -174
  61. package/.claude/worktrees/fix-save-button-disable/backend/utils.js +0 -277
  62. package/.claude/worktrees/fix-save-button-disable/dev-only-scripts/extract-duplicate-url-groups.js +0 -201
  63. package/.claude/worktrees/fix-save-button-disable/dev-only-scripts/find-duplicate-ids.js +0 -159
  64. package/.claude/worktrees/fix-save-button-disable/dev-only-scripts/find-duplicate-urls.js +0 -201
  65. package/.claude/worktrees/fix-save-button-disable/eslint.config.js +0 -120
  66. package/.claude/worktrees/fix-save-button-disable/index.js +0 -5
  67. package/.claude/worktrees/fix-save-button-disable/package-lock.json +0 -12160
  68. package/.claude/worktrees/fix-save-button-disable/package.json +0 -60
  69. package/.claude/worktrees/fix-save-button-disable/pages/ContactUs.js +0 -129
  70. package/.claude/worktrees/fix-save-button-disable/pages/Home.js +0 -779
  71. package/.claude/worktrees/fix-save-button-disable/pages/LearnMore.js +0 -27
  72. package/.claude/worktrees/fix-save-button-disable/pages/LoadingPage.js +0 -29
  73. package/.claude/worktrees/fix-save-button-disable/pages/Profile.js +0 -354
  74. package/.claude/worktrees/fix-save-button-disable/pages/QAPage.js +0 -39
  75. package/.claude/worktrees/fix-save-button-disable/pages/SaveAlerts.js +0 -13
  76. package/.claude/worktrees/fix-save-button-disable/pages/SelectBannerImages.js +0 -46
  77. package/.claude/worktrees/fix-save-button-disable/pages/deleteConfirm.js +0 -19
  78. package/.claude/worktrees/fix-save-button-disable/pages/index.js +0 -12
  79. package/.claude/worktrees/fix-save-button-disable/pages/personalDetails.js +0 -2486
  80. package/.claude/worktrees/fix-save-button-disable/public/Utils/homePage.js +0 -798
  81. package/.claude/worktrees/fix-save-button-disable/public/Utils/personalDetailsUtils.js +0 -25
  82. package/.claude/worktrees/fix-save-button-disable/public/Utils/sharedUtils.js +0 -235
  83. package/.claude/worktrees/fix-save-button-disable/public/consts.js +0 -113
  84. package/.claude/worktrees/fix-save-button-disable/public/index.js +0 -5
  85. package/.claude/worktrees/fix-save-button-disable/public/messages.js +0 -16
  86. package/.claude/worktrees/fix-save-button-disable/public/sso-auth-methods.js +0 -43
  87. package/.husky/pre-commit +0 -19
  88. package/.prettierignore +0 -7
  89. package/.prettierrc.json +0 -16
  90. package/backend/__tests__/daily-pull-execution-check.test.js +0 -124
  91. package/backend/__tests__/ensure-unique-urls-in-batch.test.js +0 -129
  92. package/backend/__tests__/login-email-sync.test.js +0 -49
  93. package/backend/__tests__/transient-retry-and-bulk-lookup.test.js +0 -129
  94. package/backend/__tests__/url-uniqueness.test.js +0 -194
  95. package/dev-only-scripts/extract-duplicate-url-groups.js +0 -201
  96. package/dev-only-scripts/find-duplicate-ids.js +0 -159
  97. package/dev-only-scripts/find-duplicate-urls.js +0 -201
  98. package/eslint.config.js +0 -120
  99. package/pages/contactForLocation.js +0 -28
@@ -1,606 +0,0 @@
1
- const { taskManager } = require('psdev-task-manager');
2
-
3
- const { COLLECTIONS } = require('../../public/consts');
4
- const { COMPILED_FILTERS_FIELDS, CONFIG_KEYS, LOGIN_EMAIL_SYNC_STATUS } = require('../consts');
5
- const { changeWixMembersEmails, summarizeLoginEmailOutcomes } = require('../daily-pull/utils');
6
- const { wixData } = require('../elevated-modules');
7
- const {
8
- getAllEmptyAboutYouMembers,
9
- getAllMembersWithExternalImages,
10
- getMembersWithWixUrl,
11
- getAllMembersWithoutContactFormEmail,
12
- findMemberByWixDataId,
13
- bulkSaveMembers,
14
- getAllUpdatedLoginEmails,
15
- getMembersByIds,
16
- createContactAndMemberIfNew,
17
- getAllMembersWithWixMemberId,
18
- } = require('../members-data-methods');
19
- const {
20
- getCompleteStateList,
21
- getAreasOfPracticeList,
22
- getStateCityMap,
23
- getCompiledFiltersOptions,
24
- } = require('../search-filters-methods');
25
- const { chunkArray, getSiteConfigs } = require('../utils');
26
-
27
- const { TASKS_NAMES } = require('./consts');
28
- const {
29
- updateMemberRichContent,
30
- updateMemberProfileImage,
31
- getAWSTokens,
32
- uploadMembersSitemap,
33
- } = require('./tasks-helpers-methods');
34
-
35
- const scheduleTaskForEmptyAboutYouMembers = async () => {
36
- const createTasksFromMembers = members => {
37
- const memberIds = members.map(member => member._id);
38
- return {
39
- name: TASKS_NAMES.convertHtmlToRichContent,
40
- data: { memberIds },
41
- type: 'scheduled',
42
- };
43
- };
44
- const members = await getAllEmptyAboutYouMembers();
45
- console.log('starting to schedule tasks for empty about you members');
46
- const membersChunks = chunkArray(members, 1000);
47
- for (const chunk of membersChunks) {
48
- const toScheduleTask = createTasksFromMembers(chunk);
49
- await taskManager().schedule(toScheduleTask);
50
- }
51
- };
52
-
53
- //this funciton takes ~0.5 seconds per member
54
- const convertAboutYouHtmlToRichContent = async membersIds => {
55
- const result = {};
56
-
57
- // Process members in chunks of 30
58
- const chunks = chunkArray(membersIds, 30);
59
-
60
- for (const chunk of chunks) {
61
- console.log(`Processing chunk of ${chunk.length} members`);
62
-
63
- // Process each chunk concurrently using Promise.all
64
- const chunkPromises = chunk.map(async memberId => {
65
- console.log('memberId ======', memberId);
66
- try {
67
- await updateMemberRichContent(memberId);
68
- return { memberId, success: true };
69
- } catch (error) {
70
- console.error('error in updating member', error);
71
- return { memberId, success: false };
72
- }
73
- });
74
-
75
- // Wait for all promises in the chunk to complete
76
- const chunkResults = await Promise.all(chunkPromises);
77
-
78
- // Update result object with chunk results
79
- chunkResults.forEach(({ memberId, success }) => {
80
- result[memberId] = success;
81
- });
82
- }
83
-
84
- return result;
85
- };
86
-
87
- async function compileFiltersOptions(field) {
88
- const getNonCompiledFilter = field => {
89
- const filterMap = {
90
- [COMPILED_FILTERS_FIELDS.COMPILED_STATE_LIST]: getCompleteStateList,
91
- [COMPILED_FILTERS_FIELDS.COMPILED_AREAS_OF_PRACTICES]: getAreasOfPracticeList,
92
- [COMPILED_FILTERS_FIELDS.COMPILED_STATE_CITY_MAP]: getStateCityMap,
93
- };
94
- const filterFunction = filterMap[field];
95
- if (!filterFunction) {
96
- throw new Error(`Unknown filter field: ${field}`);
97
- }
98
- return filterFunction();
99
- };
100
- const [nonCompiledFilterData, compiledFiltersOptions] = await Promise.all([
101
- getNonCompiledFilter(field),
102
- getCompiledFiltersOptions(),
103
- ]);
104
- compiledFiltersOptions[field] = nonCompiledFilterData;
105
- await wixData.save(COLLECTIONS.COMPILED_STATE_CITY_MAP, compiledFiltersOptions);
106
- }
107
-
108
- const scheduleTaskForExternalProfileImages = async () => {
109
- const createImageMigrationTasksFromMembers = members => {
110
- const memberIds = members.map(member => member._id);
111
-
112
- return {
113
- name: TASKS_NAMES.convertExternalProfilesToWixImages,
114
- data: { memberIds },
115
- type: 'scheduled',
116
- };
117
- };
118
- const members = await getAllMembersWithExternalImages();
119
- console.log('Starting to schedule tasks for external profile image migration');
120
- const membersChunks = chunkArray(members, 300);
121
- for (const chunk of membersChunks) {
122
- const toScheduleTask = createImageMigrationTasksFromMembers(chunk);
123
- await taskManager().schedule(toScheduleTask);
124
- }
125
- console.log(`Scheduled ${members.length} members for profile image migration`);
126
- };
127
-
128
- const convertExternalProfilesToWixImages = async membersIds => {
129
- const result = {};
130
-
131
- // Process members in chunks of 30 (optimal concurrent processing)
132
- const chunks = chunkArray(membersIds, 30);
133
-
134
- for (const chunk of chunks) {
135
- console.log(`Processing profile image chunk of ${chunk.length} members`);
136
-
137
- // Process each chunk concurrently using Promise.all
138
- const chunkPromises = chunk.map(async memberId => {
139
- console.log('Processing profile image for member:', memberId);
140
- try {
141
- const updateResult = await updateMemberProfileImage(memberId);
142
- return {
143
- memberId,
144
- success: updateResult.success,
145
- message: updateResult.message,
146
- };
147
- } catch (error) {
148
- console.error('Error updating member profile image:', error);
149
- return { memberId, success: false, error: error.message };
150
- }
151
- });
152
-
153
- const chunkResults = await Promise.all(chunkPromises);
154
-
155
- // Log results for this chunk
156
- chunkResults.forEach(result => {
157
- if (result.success) {
158
- console.log(`✅ Successfully processed profile image for member ${result.memberId}`);
159
- } else {
160
- console.error(
161
- `❌ Failed to process profile image for member ${result.memberId}: ${result.error}`
162
- );
163
- }
164
- });
165
-
166
- // Add small delay between chunks to avoid overwhelming the media manager
167
- await new Promise(resolve => setTimeout(resolve, 2000));
168
- }
169
-
170
- return result;
171
- };
172
- const updateSiteMapS3 = async () => {
173
- const relevantMembers = await getMembersWithWixUrl();
174
- console.log('number of profiles to upload', relevantMembers.length);
175
- const [tokens, siteAssociation] = await Promise.all([
176
- getAWSTokens(),
177
- getSiteConfigs(CONFIG_KEYS.SITE_ASSOCIATION),
178
- ]);
179
- // const creds = await getNewStsSessionToken(tokens.AWS_ACCESS_KEY_ID, tokens.AWS_SECRET_ACCESS_KEY, 3600);
180
- // console.log("creds",creds); // verify it’s fresh
181
- try {
182
- const chunkSize = 10000;
183
- console.log('Total items will be split into', relevantMembers.length / chunkSize);
184
- const chunks = chunkArray(relevantMembers, chunkSize);
185
- console.log(`Uploading ${chunks.length} sitemap files...`);
186
- for (let i = 0; i < chunks.length; i++) {
187
- const index = i + 1;
188
- const fileName = `profiles-sitemap-${index}.xml`;
189
- console.log(
190
- `Uploading chunk ${index}/${chunks.length} -> ${fileName} (${chunks[i].length} items)`
191
- );
192
- await uploadMembersSitemap({
193
- members: chunks[i],
194
- tokens,
195
- destinationFileName: fileName,
196
- siteAssociation,
197
- });
198
- console.log(`Uploaded ${fileName}`);
199
- }
200
- console.log('All sitemap files uploaded successfully');
201
- } catch (e) {
202
- console.error('Sitemap upload failed:', e?.message || e);
203
- }
204
- };
205
-
206
- /**
207
- * Schedules tasks to migrate contactFormEmail for all members who don't have it set
208
- * This function gets all members missing contactFormEmail and schedules batch processing tasks
209
- */
210
- const scheduleContactFormEmailMigration = async () => {
211
- try {
212
- console.log('Starting to schedule contactFormEmail migration tasks');
213
- const createContactFormEmailMigrationTask = (members, chunkIndex) => {
214
- const memberIds = members.map(member => member._id);
215
- return {
216
- name: TASKS_NAMES.migrateContactFormEmails,
217
- data: { memberIds, chunkIndex },
218
- type: 'scheduled',
219
- };
220
- };
221
- const membersToMigrate = await getAllMembersWithoutContactFormEmail();
222
- console.log(`Found ${membersToMigrate.length} members needing contactFormEmail migration`);
223
- if (membersToMigrate.length === 0) {
224
- console.log('No members need contactFormEmail migration');
225
- return {
226
- success: true,
227
- message: 'No members need migration',
228
- totalMembers: 0,
229
- tasksScheduled: 0,
230
- };
231
- }
232
-
233
- // Process in chunks of 500 members per task (smaller chunks for reliability)
234
- const membersChunks = chunkArray(membersToMigrate, 500);
235
- console.log(`Creating ${membersChunks.length} migration tasks`);
236
-
237
- for (let chunkIndex = 0; chunkIndex < membersChunks.length; chunkIndex++) {
238
- const chunk = membersChunks[chunkIndex];
239
- const migrationTask = createContactFormEmailMigrationTask(chunk, chunkIndex);
240
- await taskManager().schedule(migrationTask);
241
- console.log(`Scheduled task for chunk ${chunkIndex} with ${chunk.length} members`);
242
- }
243
-
244
- console.log(
245
- `Successfully scheduled ${membersChunks.length} tasks for ${membersToMigrate.length} members`
246
- );
247
-
248
- return {
249
- success: true,
250
- message: `Scheduled ${membersChunks.length} tasks for ${membersToMigrate.length} members`,
251
- totalMembers: membersToMigrate.length,
252
- tasksScheduled: membersChunks.length,
253
- };
254
- } catch (error) {
255
- const errorMessage = `Failed to schedule contactFormEmail migration: ${error.message}`;
256
- console.error(errorMessage);
257
- throw new Error(errorMessage);
258
- }
259
- };
260
-
261
- /**
262
- * Migrates contactFormEmail for a batch of members
263
- * Sets contactFormEmail to the same value as the member's current email
264
- * @param {Object} data - Data object with memberIds and chunkIndex
265
- * @param {Array} data.memberIds - Array of member IDs to process
266
- * @param {number} data.chunkIndex - Index of the chunk
267
- * @returns {Promise<Object>} - Result object with success/failure counts
268
- */
269
- const migrateContactFormEmails = async data => {
270
- const { memberIds, chunkIndex } = data;
271
- const result = {
272
- successful: 0,
273
- failed: 0,
274
- errors: [],
275
- skipped: 0,
276
- skippedIds: [],
277
- };
278
-
279
- console.log(
280
- `Starting contactFormEmail migration for ${memberIds.length} members in chunk ${chunkIndex}`
281
- );
282
-
283
- try {
284
- // Get all members for this batch
285
- const memberPromises = memberIds.map(async memberId => {
286
- try {
287
- const member = await findMemberByWixDataId(memberId);
288
-
289
- // Skip if member already has contactFormEmail set
290
- if (member.contactFormEmail) {
291
- console.log(`Member ${memberId} already has contactFormEmail set`);
292
- result.skipped++;
293
- result.skippedIds.push(memberId);
294
- return null;
295
- }
296
-
297
- // Skip if member doesn't have email
298
- if (!member.email) {
299
- console.log(`Member ${memberId} doesn't have email - skipping`);
300
- result.skipped++;
301
- result.skippedIds.push(memberId);
302
- return null;
303
- }
304
-
305
- return {
306
- ...member,
307
- contactFormEmail: member.email,
308
- };
309
- } catch (error) {
310
- console.error(`Error preparing member ${memberId}:`, error);
311
- result.failed++;
312
- result.errors.push({ memberId, error: error.message });
313
- return null;
314
- }
315
- });
316
-
317
- const membersToUpdate = (await Promise.all(memberPromises)).filter(Boolean);
318
-
319
- if (membersToUpdate.length === 0) {
320
- console.log('No members need updating in this batch');
321
- return result;
322
- }
323
-
324
- console.log(
325
- `Started Updating ${membersToUpdate.length} members with contactFormEmail in chunk ${chunkIndex}`
326
- );
327
-
328
- // Process in smaller chunks for bulk update (1000 is Wix limit)
329
- const updateChunks = chunkArray(membersToUpdate, 1000);
330
-
331
- for (let chunkIndex = 0; chunkIndex < updateChunks.length; chunkIndex++) {
332
- const chunk = updateChunks[chunkIndex];
333
- try {
334
- await bulkSaveMembers(chunk);
335
- result.successful += chunk.length;
336
- console.log(`✅ Successfully updated ${chunk.length} members in chunk ${chunkIndex}`);
337
- } catch (error) {
338
- console.error(`❌ Error updating chunk ${chunkIndex}:`, error);
339
- result.failed += chunk.length;
340
- result.errors.push({
341
- chunk: chunkIndex,
342
- error: error.message,
343
- memberCount: chunk.length,
344
- });
345
- }
346
- }
347
- } catch (error) {
348
- const errorMessage = `Failed to migrate contactFormEmail for chunk ${chunkIndex}: ${error.message}`;
349
- console.error(errorMessage);
350
- throw new Error(errorMessage);
351
- }
352
-
353
- console.log(
354
- `ContactFormEmail migration task completed: ${result.successful} successful, ${result.failed} failed, ${result.skipped} skipped, in chunk ${chunkIndex}`
355
- );
356
- return result;
357
- };
358
-
359
- /**
360
- Schedules tasks to sync updated emails from the updated login emails database
361
- * This function gets all updated emails and schedules batch processing tasks
362
- */
363
- const scheduleEmailSync = async () => {
364
- try {
365
- console.log('Starting to schedule email sync tasks');
366
- const createEmailSyncTask = (chunk, chunkIndex) => {
367
- //To reduce stored Items size inside task data
368
- const emailUpdates = chunk.map(emailUpdate => ({
369
- memberId: emailUpdate.memberId,
370
- loginEmail: emailUpdate.loginEmail,
371
- }));
372
- return {
373
- name: TASKS_NAMES.syncMemberLoginEmails,
374
- data: { emailUpdates, chunkIndex },
375
- type: 'scheduled',
376
- };
377
- };
378
- const updatedEmails = await getAllUpdatedLoginEmails();
379
- console.log(`Found ${updatedEmails.length} updated email records`);
380
-
381
- if (updatedEmails.length === 0) {
382
- console.log('No updated emails found');
383
- return {
384
- success: true,
385
- message: 'No updated emails to sync',
386
- totalEmails: 0,
387
- tasksScheduled: 0,
388
- };
389
- }
390
-
391
- const emailChunks = chunkArray(updatedEmails, 500);
392
- console.log(`Creating ${emailChunks.length} email sync tasks`);
393
-
394
- for (let chunkIndex = 0; chunkIndex < emailChunks.length; chunkIndex++) {
395
- const chunk = emailChunks[chunkIndex];
396
- const syncTask = createEmailSyncTask(chunk, chunkIndex);
397
- await taskManager().schedule(syncTask);
398
- console.log(`Scheduled task for chunk ${chunkIndex} with ${chunk.length} email updates`);
399
- }
400
-
401
- console.log(
402
- `Successfully scheduled ${emailChunks.length} tasks for ${updatedEmails.length} email updates`
403
- );
404
-
405
- return {
406
- success: true,
407
- message: `Scheduled ${emailChunks.length} tasks for ${updatedEmails.length} email updates`,
408
- totalEmails: updatedEmails.length,
409
- tasksScheduled: emailChunks.length,
410
- };
411
- } catch (error) {
412
- const errorMessage = `Failed to schedule email sync: ${error.message}`;
413
- console.error(errorMessage);
414
- throw new Error(errorMessage);
415
- }
416
- };
417
-
418
- /**
419
- * Syncs member emails with updated login emails
420
- * @param {Object} data - Data object with emailUpdates and chunkIndex
421
- * @param {Array} data.emailUpdates - Array of email update objects with memberId and loginEmail
422
- * @param {number} data.chunkIndex - Index of the chunk
423
- * @returns {Object} - Result object with success/failure counts
424
- */
425
- const syncMemberLoginEmails = async data => {
426
- const { emailUpdates, chunkIndex } = data;
427
- const result = {
428
- successful: 0,
429
- failed: 0,
430
- skipped: 0,
431
- skippedIds: [],
432
- missingMemberIds: [],
433
- errors: [],
434
- };
435
-
436
- console.log(
437
- `Starting email sync for ${emailUpdates.length} email updates in chunk ${chunkIndex}`
438
- );
439
-
440
- try {
441
- const memberIds = emailUpdates.map(update => update.memberId);
442
-
443
- const existingMembers = await getMembersByIds(memberIds);
444
- console.log(`Found ${existingMembers.length} existing members to update`);
445
- const existingMemberIds = new Set(existingMembers.map(member => member.memberId));
446
- const missingMemberIds = memberIds.filter(memberId => !existingMemberIds.has(memberId));
447
-
448
- // Add missing member IDs to skipped count and log them
449
- if (missingMemberIds.length > 0) {
450
- console.log(
451
- `Found ${missingMemberIds.length} members in emailUpdates but not in database:`,
452
- missingMemberIds
453
- );
454
- result.missingMemberIds = result.missingMemberIds || [];
455
- result.missingMemberIds.push(...missingMemberIds);
456
- }
457
- const emailUpdateMap = new Map();
458
- emailUpdates.forEach(update => {
459
- emailUpdateMap.set(update.memberId, update.loginEmail);
460
- });
461
-
462
- const membersToUpdate = [];
463
-
464
- for (const member of existingMembers) {
465
- const newEmail = emailUpdateMap.get(member.memberId);
466
-
467
- if (!newEmail) {
468
- console.log(`No email update found for member ${member.memberId}`);
469
- result.skipped++;
470
- result.skippedIds.push(member.memberId);
471
- continue;
472
- }
473
-
474
- if (member.email === newEmail) {
475
- console.log(`Email already up to date for member ${member.memberId}`);
476
- result.skipped++;
477
- result.skippedIds.push(member.memberId);
478
- continue;
479
- }
480
-
481
- membersToUpdate.push({
482
- ...member,
483
- email: newEmail,
484
- previousLoginEmail: member.email,
485
- });
486
- }
487
-
488
- if (membersToUpdate.length === 0) {
489
- console.log('No members need email updates in this batch', chunkIndex);
490
- return result;
491
- }
492
-
493
- console.log(
494
- `Updating ${membersToUpdate.length} members with new emails in chunk ${chunkIndex}`
495
- );
496
-
497
- const updateChunks = chunkArray(membersToUpdate, 1000);
498
-
499
- for (const chunk of updateChunks) {
500
- try {
501
- // Change Wix login emails first; only advance the CMS login email for the ones that
502
- // succeeded. Failures keep their previous email (CMS stays consistent with Wix) and are
503
- // reported in result.errors for manual handling.
504
- const outcomes = await changeWixMembersEmails(chunk);
505
- const { failedMemberIds } = summarizeLoginEmailOutcomes(outcomes);
506
- const toSave = chunk.map(member => {
507
- const { previousLoginEmail, ...restMember } = member;
508
- if (failedMemberIds.has(member.memberId) && previousLoginEmail !== undefined) {
509
- return { ...restMember, email: previousLoginEmail };
510
- }
511
- return restMember;
512
- });
513
- await bulkSaveMembers(toSave);
514
-
515
- outcomes.forEach(outcome => {
516
- if (outcome.status === LOGIN_EMAIL_SYNC_STATUS.UPDATED) {
517
- result.successful++;
518
- } else if (outcome.status === LOGIN_EMAIL_SYNC_STATUS.FAILED) {
519
- result.failed++;
520
- result.errors.push({
521
- memberId: outcome.memberId,
522
- wixMemberId: outcome.wixMemberId,
523
- desiredEmail: outcome.desiredEmail,
524
- error: outcome.error,
525
- });
526
- } else {
527
- result.skipped++;
528
- }
529
- });
530
- } catch (error) {
531
- console.error(`❌ Error updating chunk ${chunkIndex}:`, error);
532
- result.failed += chunk.length;
533
- result.errors.push({
534
- chunk: chunkIndex,
535
- error: error.message,
536
- memberCount: chunk.length,
537
- });
538
- }
539
- }
540
- console.log(
541
- `Login Emails sync task completed: ${result.successful} synced, ${result.failed} failed, ${result.skipped} skipped`
542
- );
543
-
544
- return result;
545
- } catch (error) {
546
- const errorMessage = `Failed to syncMemberLoginEmails for chunk ${chunkIndex} of length ${emailUpdates.length} with error: ${error.message}`;
547
- console.error(errorMessage);
548
- throw new Error(errorMessage);
549
- }
550
- };
551
- /**
552
- * Schedules tasks to create contacts from members
553
- * dev-only task, run only once by the developers
554
- */
555
- const scheduleCreateContactsFromMembers = async () => {
556
- const members = await getAllMembersWithWixMemberId();
557
- console.log(
558
- `Starting to schedule create contacts from members tasks for ${members.length} members in chunks of 500 members`
559
- );
560
- const membersChunks = chunkArray(members, 500);
561
- for (let chunkIndex = 0; chunkIndex < membersChunks.length; chunkIndex++) {
562
- const chunk = membersChunks[chunkIndex];
563
- const toScheduleTask = {
564
- name: TASKS_NAMES.createContactsFromMembers,
565
- data: { chunk, chunkIndex },
566
- type: 'scheduled',
567
- };
568
- await taskManager().schedule(toScheduleTask);
569
- console.log(`Scheduled task for chunk ${chunkIndex} with ${chunk.length} members`);
570
- }
571
- console.log(`Successfully scheduled ${membersChunks.length} tasks for ${members.length} members`);
572
- };
573
-
574
- /**
575
- * Creates contacts from members
576
- * dev-only task, run only once by the developers
577
- */
578
- const createContactsFromMembers = async data => {
579
- const { chunk, chunkIndex } = data;
580
- console.log(`Creating contacts from ${chunk.length} members in chunk ${chunkIndex}`);
581
- const createPromises = chunk.map(member => createContactAndMemberIfNew(member, true));
582
- const createResults = await Promise.all(createPromises);
583
- console.log(
584
- `Created ${createResults.length} contacts from ${chunk.length} members in chunk ${chunkIndex}`
585
- );
586
- const saveResult = await bulkSaveMembers(createResults);
587
- console.log(
588
- `Successfully saved ${saveResult.totalSaved} contacts from ${chunk.length} members in chunk ${chunkIndex}`
589
- );
590
- return saveResult;
591
- };
592
-
593
- module.exports = {
594
- scheduleTaskForEmptyAboutYouMembers,
595
- convertAboutYouHtmlToRichContent,
596
- compileFiltersOptions,
597
- scheduleTaskForExternalProfileImages,
598
- convertExternalProfilesToWixImages,
599
- updateSiteMapS3,
600
- scheduleContactFormEmailMigration,
601
- migrateContactFormEmails,
602
- scheduleEmailSync,
603
- syncMemberLoginEmails,
604
- scheduleCreateContactsFromMembers, // run only once by the developers
605
- createContactsFromMembers,
606
- };