abmp-npm 2.0.77 → 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/.claude/skills/wix-data-query/SKILL.md +0 -167
  3. package/.claude/skills/wix-data-query/references/backup-archive.md +0 -136
  4. package/.claude/skills/wix-data-query/references/members-data-latest.md +0 -125
  5. package/.claude/skills/wix-data-query/references/recipes.md +0 -264
  6. package/.claude/worktrees/fix-save-button-disable/.husky/pre-commit +0 -19
  7. package/.claude/worktrees/fix-save-button-disable/.prettierignore +0 -7
  8. package/.claude/worktrees/fix-save-button-disable/.prettierrc.json +0 -16
  9. package/.claude/worktrees/fix-save-button-disable/README.md +0 -1
  10. package/.claude/worktrees/fix-save-button-disable/backend/README-member-contact-flows.md +0 -136
  11. package/.claude/worktrees/fix-save-button-disable/backend/__tests__/daily-pull-execution-check.test.js +0 -124
  12. package/.claude/worktrees/fix-save-button-disable/backend/__tests__/ensure-unique-urls-in-batch.test.js +0 -129
  13. package/.claude/worktrees/fix-save-button-disable/backend/__tests__/login-email-sync.test.js +0 -49
  14. package/.claude/worktrees/fix-save-button-disable/backend/__tests__/transient-retry-and-bulk-lookup.test.js +0 -129
  15. package/.claude/worktrees/fix-save-button-disable/backend/__tests__/url-uniqueness.test.js +0 -194
  16. package/.claude/worktrees/fix-save-button-disable/backend/automations-methods.js +0 -13
  17. package/.claude/worktrees/fix-save-button-disable/backend/cms-data-methods.js +0 -251
  18. package/.claude/worktrees/fix-save-button-disable/backend/consts.js +0 -58
  19. package/.claude/worktrees/fix-save-button-disable/backend/contacts-methods.js +0 -67
  20. package/.claude/worktrees/fix-save-button-disable/backend/daily-pull/bulk-process-methods.js +0 -222
  21. package/.claude/worktrees/fix-save-button-disable/backend/daily-pull/consts.js +0 -39
  22. package/.claude/worktrees/fix-save-button-disable/backend/daily-pull/index.js +0 -5
  23. package/.claude/worktrees/fix-save-button-disable/backend/daily-pull/process-member-methods.js +0 -213
  24. package/.claude/worktrees/fix-save-button-disable/backend/daily-pull/schedule-methods.js +0 -41
  25. package/.claude/worktrees/fix-save-button-disable/backend/daily-pull/sync-to-cms-methods.js +0 -161
  26. package/.claude/worktrees/fix-save-button-disable/backend/daily-pull/utils.js +0 -151
  27. package/.claude/worktrees/fix-save-button-disable/backend/data-hooks.js +0 -29
  28. package/.claude/worktrees/fix-save-button-disable/backend/dev-only-methods.js +0 -58
  29. package/.claude/worktrees/fix-save-button-disable/backend/elevated-modules.js +0 -18
  30. package/.claude/worktrees/fix-save-button-disable/backend/forms-methods.js +0 -52
  31. package/.claude/worktrees/fix-save-button-disable/backend/http-functions/httpFunctions.js +0 -86
  32. package/.claude/worktrees/fix-save-button-disable/backend/http-functions/index.js +0 -3
  33. package/.claude/worktrees/fix-save-button-disable/backend/http-functions/interests.js +0 -35
  34. package/.claude/worktrees/fix-save-button-disable/backend/index.js +0 -19
  35. package/.claude/worktrees/fix-save-button-disable/backend/jobs.js +0 -158
  36. package/.claude/worktrees/fix-save-button-disable/backend/login/generate-member-session-token.js +0 -27
  37. package/.claude/worktrees/fix-save-button-disable/backend/login/index.js +0 -8
  38. package/.claude/worktrees/fix-save-button-disable/backend/login/qa-login-methods.js +0 -54
  39. package/.claude/worktrees/fix-save-button-disable/backend/login/sso-methods.js +0 -159
  40. package/.claude/worktrees/fix-save-button-disable/backend/member-contact-orchestration.js +0 -111
  41. package/.claude/worktrees/fix-save-button-disable/backend/members-area-methods.js +0 -88
  42. package/.claude/worktrees/fix-save-button-disable/backend/members-data-methods.js +0 -789
  43. package/.claude/worktrees/fix-save-button-disable/backend/pac-api-methods.js +0 -54
  44. package/.claude/worktrees/fix-save-button-disable/backend/routers/index.js +0 -3
  45. package/.claude/worktrees/fix-save-button-disable/backend/routers/methods.js +0 -191
  46. package/.claude/worktrees/fix-save-button-disable/backend/routers/utils.js +0 -128
  47. package/.claude/worktrees/fix-save-button-disable/backend/search-filters-methods.js +0 -124
  48. package/.claude/worktrees/fix-save-button-disable/backend/tasks/address-primary-methods.js +0 -256
  49. package/.claude/worktrees/fix-save-button-disable/backend/tasks/address-visibility-methods.js +0 -160
  50. package/.claude/worktrees/fix-save-button-disable/backend/tasks/consts.js +0 -34
  51. package/.claude/worktrees/fix-save-button-disable/backend/tasks/daily-pull-check-methods.js +0 -78
  52. package/.claude/worktrees/fix-save-button-disable/backend/tasks/email-normalize-methods.js +0 -134
  53. package/.claude/worktrees/fix-save-button-disable/backend/tasks/index.js +0 -10
  54. package/.claude/worktrees/fix-save-button-disable/backend/tasks/migration-methods.js +0 -46
  55. package/.claude/worktrees/fix-save-button-disable/backend/tasks/tasks-configs.js +0 -251
  56. package/.claude/worktrees/fix-save-button-disable/backend/tasks/tasks-helpers-methods.js +0 -433
  57. package/.claude/worktrees/fix-save-button-disable/backend/tasks/tasks-process-methods.js +0 -606
  58. package/.claude/worktrees/fix-save-button-disable/backend/tasks/url-migration-methods.js +0 -378
  59. package/.claude/worktrees/fix-save-button-disable/backend/tasks/url-space-fix-methods.js +0 -174
  60. package/.claude/worktrees/fix-save-button-disable/backend/utils.js +0 -277
  61. package/.claude/worktrees/fix-save-button-disable/dev-only-scripts/extract-duplicate-url-groups.js +0 -201
  62. package/.claude/worktrees/fix-save-button-disable/dev-only-scripts/find-duplicate-ids.js +0 -159
  63. package/.claude/worktrees/fix-save-button-disable/dev-only-scripts/find-duplicate-urls.js +0 -201
  64. package/.claude/worktrees/fix-save-button-disable/eslint.config.js +0 -120
  65. package/.claude/worktrees/fix-save-button-disable/index.js +0 -5
  66. package/.claude/worktrees/fix-save-button-disable/package-lock.json +0 -12160
  67. package/.claude/worktrees/fix-save-button-disable/package.json +0 -60
  68. package/.claude/worktrees/fix-save-button-disable/pages/ContactUs.js +0 -129
  69. package/.claude/worktrees/fix-save-button-disable/pages/Home.js +0 -779
  70. package/.claude/worktrees/fix-save-button-disable/pages/LearnMore.js +0 -27
  71. package/.claude/worktrees/fix-save-button-disable/pages/LoadingPage.js +0 -29
  72. package/.claude/worktrees/fix-save-button-disable/pages/Profile.js +0 -354
  73. package/.claude/worktrees/fix-save-button-disable/pages/QAPage.js +0 -39
  74. package/.claude/worktrees/fix-save-button-disable/pages/SaveAlerts.js +0 -13
  75. package/.claude/worktrees/fix-save-button-disable/pages/SelectBannerImages.js +0 -46
  76. package/.claude/worktrees/fix-save-button-disable/pages/deleteConfirm.js +0 -19
  77. package/.claude/worktrees/fix-save-button-disable/pages/index.js +0 -12
  78. package/.claude/worktrees/fix-save-button-disable/pages/personalDetails.js +0 -2486
  79. package/.claude/worktrees/fix-save-button-disable/public/Utils/homePage.js +0 -798
  80. package/.claude/worktrees/fix-save-button-disable/public/Utils/personalDetailsUtils.js +0 -25
  81. package/.claude/worktrees/fix-save-button-disable/public/Utils/sharedUtils.js +0 -235
  82. package/.claude/worktrees/fix-save-button-disable/public/consts.js +0 -113
  83. package/.claude/worktrees/fix-save-button-disable/public/index.js +0 -5
  84. package/.claude/worktrees/fix-save-button-disable/public/messages.js +0 -16
  85. package/.claude/worktrees/fix-save-button-disable/public/sso-auth-methods.js +0 -43
  86. package/.husky/pre-commit +0 -19
  87. package/.prettierignore +0 -7
  88. package/.prettierrc.json +0 -16
  89. package/backend/__tests__/daily-pull-execution-check.test.js +0 -124
  90. package/backend/__tests__/ensure-unique-urls-in-batch.test.js +0 -129
  91. package/backend/__tests__/login-email-sync.test.js +0 -49
  92. package/backend/__tests__/map-link.test.js +0 -115
  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/backend/__tests__/url-validation.test.js +0 -69
  96. package/dev-only-scripts/extract-duplicate-url-groups.js +0 -201
  97. package/dev-only-scripts/find-duplicate-ids.js +0 -159
  98. package/dev-only-scripts/find-duplicate-urls.js +0 -201
  99. package/eslint.config.js +0 -120
@@ -1,378 +0,0 @@
1
- const { taskManager } = require('psdev-task-manager');
2
-
3
- const { COLLECTIONS } = require('../../public/consts');
4
- const { ensureUniqueUrl } = require('../daily-pull/process-member-methods');
5
- const { wixData } = require('../elevated-modules');
6
- const { bulkSaveMembers } = require('../members-data-methods');
7
- const { queryAllItems, chunkArray } = require('../utils');
8
-
9
- const { TASKS_NAMES } = require('./consts');
10
-
11
- const COLLECTION_WITH_URLS = 'MembersDataWithUrls';
12
- const CHUNK_SIZE = 5000; // 5k members per task for migration
13
- const GENERATION_CHUNK_SIZE = 1000; // 1k members per task for URL generation
14
-
15
- /**
16
- * Step 1: Migrate existing URLs from backup collection
17
- * Queries backup collection and schedules tasks with memberIds and URLs
18
- */
19
- async function scheduleMigrateExistingUrls() {
20
- console.log('=== Scheduling Step 1: Migrate Existing URLs ===');
21
-
22
- try {
23
- const membersQuery = await wixData.query(COLLECTION_WITH_URLS);
24
- const startTime = Date.now();
25
- const membersWithUrls = await queryAllItems(membersQuery);
26
- const endTime = Date.now();
27
- console.log(`QueryAllItems time: ${endTime - startTime}ms`);
28
-
29
- const validMembers = membersWithUrls.filter(member => member.memberId && member.url);
30
- console.log(`${validMembers.length} members have valid memberId and URL`);
31
-
32
- if (validMembers.length === 0) {
33
- console.log('No members to migrate URLs for');
34
- return {
35
- success: true,
36
- message: 'No members need URL migration',
37
- totalMembers: 0,
38
- tasksScheduled: 0,
39
- };
40
- }
41
-
42
- const migrationData = validMembers.map(member => ({
43
- memberId: member.memberId,
44
- url: member.url,
45
- }));
46
-
47
- const chunks = chunkArray(migrationData, CHUNK_SIZE);
48
-
49
- for (let i = 0; i < chunks.length; i++) {
50
- const chunk = chunks[i];
51
- const task = {
52
- name: TASKS_NAMES.migrateUrlsChunk,
53
- data: {
54
- urlData: chunk,
55
- chunkIndex: i,
56
- totalChunks: chunks.length,
57
- },
58
- type: 'scheduled',
59
- };
60
- await taskManager().schedule(task);
61
- console.log(`Scheduled migration task ${i + 1}/${chunks.length} (${chunk.length} members)`);
62
- }
63
-
64
- const result = {
65
- success: true,
66
- message: `Scheduled ${chunks.length} tasks for ${validMembers.length} members`,
67
- totalMembers: validMembers.length,
68
- tasksScheduled: chunks.length,
69
- };
70
-
71
- console.log('=== Migration Scheduling Complete ===');
72
- console.log(JSON.stringify(result, null, 2));
73
-
74
- return result;
75
- } catch (error) {
76
- console.error('Error scheduling URL migration:', error);
77
- throw error;
78
- }
79
- }
80
-
81
- /**
82
- * Process a chunk of URL migrations (called by task manager)
83
- * Fetches members by memberId and updates with URLs using bulkSave
84
- */
85
- async function migrateUrlsChunk(data) {
86
- const { urlData, chunkIndex, totalChunks } = data;
87
- console.log(
88
- `Processing migration chunk ${chunkIndex + 1}/${totalChunks} (${urlData.length} members)`
89
- );
90
-
91
- const result = {
92
- successful: 0,
93
- failed: 0,
94
- skipped: 0,
95
- errors: [],
96
- skippedIds: [],
97
- failedIds: [],
98
- };
99
-
100
- try {
101
- const memberIds = urlData.map(({ memberId }) => memberId);
102
-
103
- console.log(`Fetching ${memberIds.length} members from database...`);
104
- const query = await wixData.query(COLLECTIONS.MEMBERS_DATA).hasSome('memberId', memberIds);
105
- const members = await queryAllItems(query);
106
- console.log(`Found ${members.length} members in database`);
107
-
108
- const memberMap = new Map();
109
- members.forEach(member => {
110
- if (member.memberId) {
111
- memberMap.set(member.memberId, member);
112
- }
113
- });
114
-
115
- const membersToUpdate = [];
116
- for (const { memberId, url } of urlData) {
117
- const member = memberMap.get(memberId);
118
-
119
- if (!member) {
120
- console.log(`Member with memberId ${memberId} not found - skipping`);
121
- result.skipped++;
122
- result.skippedIds.push(memberId);
123
- continue;
124
- }
125
-
126
- if (member.url === url) {
127
- console.log(`Member ${member._id} already has URL ${url} - skipping`);
128
- result.skipped++;
129
- result.skippedIds.push(memberId);
130
- continue;
131
- }
132
-
133
- membersToUpdate.push({
134
- ...member,
135
- url: url,
136
- });
137
- }
138
-
139
- if (membersToUpdate.length === 0) {
140
- console.log('No members need updating in this batch');
141
- return result;
142
- }
143
-
144
- console.log(
145
- `Started updating ${membersToUpdate.length} members with URLs in chunk ${chunkIndex}`
146
- );
147
-
148
- try {
149
- await bulkSaveMembers(membersToUpdate);
150
- result.successful += membersToUpdate.length;
151
- console.log(`✅ Successfully updated ${membersToUpdate.length} members`);
152
- } catch (error) {
153
- console.error(`❌ Error bulk saving members:`, error);
154
- result.failed += membersToUpdate.length;
155
- // Add all member IDs to failedIds
156
- result.failedIds.push(...membersToUpdate.map(m => m.memberId));
157
- result.errors.push({
158
- error: error.message,
159
- memberCount: membersToUpdate.length,
160
- });
161
- }
162
-
163
- console.log(
164
- `Chunk ${chunkIndex + 1} complete: ${result.successful} success, ${result.failed} failed, ${result.skipped} skipped`
165
- );
166
-
167
- // Log failed and skipped IDs if any
168
- if (result.failedIds.length > 0) {
169
- console.log(`❌ Failed memberIds (${result.failedIds.length}):`, result.failedIds);
170
- }
171
- if (result.skippedIds.length > 0) {
172
- console.log(`⏭️ Skipped memberIds (${result.skippedIds.length}):`, result.skippedIds);
173
- }
174
-
175
- return result;
176
- } catch (error) {
177
- console.error(`Error processing migration chunk ${chunkIndex}:`, error);
178
- throw error;
179
- }
180
- }
181
-
182
- /**
183
- * Step 2: Generate URLs for members without URLs
184
- * Queries members without URLs and schedules generation tasks
185
- */
186
- async function scheduleGenerateMissingUrls() {
187
- console.log('=== Scheduling Step 2: Generate Missing URLs ===');
188
-
189
- try {
190
- const membersQuery = await wixData.query(COLLECTIONS.MEMBERS_DATA).isEmpty('url');
191
- const membersToUpdate = await queryAllItems(membersQuery);
192
-
193
- console.log(`Found ${membersToUpdate.length} members without URLs`);
194
-
195
- if (membersToUpdate.length === 0) {
196
- console.log('No members need URL generation');
197
- return {
198
- success: true,
199
- message: 'No members need URL generation',
200
- totalMembers: 0,
201
- tasksScheduled: 0,
202
- };
203
- }
204
-
205
- const chunks = chunkArray(membersToUpdate, GENERATION_CHUNK_SIZE);
206
-
207
- for (let i = 0; i < chunks.length; i++) {
208
- const chunk = chunks[i];
209
- const task = {
210
- name: TASKS_NAMES.generateUrlsChunk,
211
- data: {
212
- memberIds: chunk.map(m => m._id),
213
- chunkIndex: i,
214
- totalChunks: chunks.length,
215
- },
216
- type: 'scheduled',
217
- };
218
- await taskManager().schedule(task);
219
- console.log(`Scheduled generation task ${i + 1}/${chunks.length} (${chunk.length} members)`);
220
- }
221
-
222
- const result = {
223
- success: true,
224
- message: `Scheduled ${chunks.length} tasks for ${membersToUpdate.length} members`,
225
- totalMembers: membersToUpdate.length,
226
- tasksScheduled: chunks.length,
227
- };
228
-
229
- console.log('=== Generation Scheduling Complete ===');
230
- console.log(JSON.stringify(result, null, 2));
231
-
232
- return result;
233
- } catch (error) {
234
- console.error('Error scheduling URL generation:', error);
235
- throw error;
236
- }
237
- }
238
-
239
- /**
240
- * Process a chunk of URL generation (called by task manager)
241
- * Fetches members, generates URLs, and bulk saves
242
- */
243
- async function generateUrlsChunk(data) {
244
- const { memberIds, chunkIndex, totalChunks } = data;
245
- console.log(
246
- `Processing generation chunk ${chunkIndex + 1}/${totalChunks} (${memberIds.length} members)`
247
- );
248
-
249
- const result = {
250
- successful: 0,
251
- failed: 0,
252
- skipped: 0,
253
- errors: [],
254
- skippedIds: [],
255
- failedIds: [],
256
- };
257
-
258
- try {
259
- // Fetch members in smaller batches to avoid cursor size limits
260
- // hasSome with too many IDs creates cursors that exceed Wix's 150KB limit
261
- const FETCH_BATCH_SIZE = 200;
262
- console.log(
263
- `Fetching ${memberIds.length} members from database in batches of ${FETCH_BATCH_SIZE}...`
264
- );
265
-
266
- const members = [];
267
- const idBatches = chunkArray(memberIds, FETCH_BATCH_SIZE);
268
-
269
- for (let i = 0; i < idBatches.length; i++) {
270
- const idBatch = idBatches[i];
271
- const batchMembers = await queryAllItems(
272
- wixData.query(COLLECTIONS.MEMBERS_DATA).hasSome('_id', idBatch)
273
- );
274
- members.push(...batchMembers);
275
- console.log(`Fetched batch ${i + 1}/${idBatches.length}: ${batchMembers.length} members`);
276
- }
277
-
278
- console.log(`Found ${members.length} members in database`);
279
-
280
- // Create a map of _id -> member for quick lookup
281
- const memberMap = new Map();
282
- members.forEach(member => {
283
- memberMap.set(member._id, member);
284
- });
285
-
286
- // Process each member and generate URLs
287
- const membersToUpdate = [];
288
- for (const memberId of memberIds) {
289
- const member = memberMap.get(memberId);
290
-
291
- if (!member) {
292
- console.log(`Member ${memberId} not found - skipping`);
293
- result.skipped++;
294
- result.skippedIds.push(memberId);
295
- continue;
296
- }
297
-
298
- if (member.url) {
299
- console.log(`Member ${memberId} already has URL - skipping`);
300
- result.skipped++;
301
- result.skippedIds.push(memberId);
302
- continue;
303
- }
304
-
305
- const name = member.fullName || `${member.firstName || ''} ${member.lastName || ''}`.trim();
306
-
307
- try {
308
- const uniqueUrl = await ensureUniqueUrl({
309
- url: '',
310
- memberId: member.memberId,
311
- fullName: name || '', // Let ensureUniqueUrl handle fallback for empty names
312
- });
313
-
314
- console.log(`✅ Generated URL for member ${memberId}: ${uniqueUrl}`);
315
- membersToUpdate.push({
316
- ...member,
317
- url: uniqueUrl,
318
- });
319
- } catch (error) {
320
- console.error(`❌ Failed to generate URL for member ${memberId}:`, error);
321
- result.failed++;
322
- result.failedIds.push(memberId);
323
- result.errors.push({
324
- memberId,
325
- error: error.message || 'Unknown error',
326
- });
327
- }
328
- }
329
-
330
- if (membersToUpdate.length === 0) {
331
- console.log('No members need updating in this batch');
332
- return result;
333
- }
334
-
335
- console.log(
336
- `Started updating ${membersToUpdate.length} members with generated URLs in chunk ${chunkIndex}`
337
- );
338
-
339
- try {
340
- await bulkSaveMembers(membersToUpdate);
341
- result.successful += membersToUpdate.length;
342
- console.log(`✅ Successfully updated ${membersToUpdate.length} members`);
343
- } catch (error) {
344
- console.error(`❌ Error bulk saving members:`, error);
345
- result.failed += membersToUpdate.length;
346
- // Add all member _ids to failedIds
347
- result.failedIds.push(...membersToUpdate.map(m => m._id));
348
- result.errors.push({
349
- error: error.message,
350
- memberCount: membersToUpdate.length,
351
- });
352
- }
353
-
354
- console.log(
355
- `Chunk ${chunkIndex + 1} complete: ${result.successful} success, ${result.failed} failed, ${result.skipped} skipped`
356
- );
357
-
358
- // Log failed and skipped IDs if any
359
- if (result.failedIds.length > 0) {
360
- console.log(`❌ Failed memberIds (${result.failedIds.length}):`, result.failedIds);
361
- }
362
- if (result.skippedIds.length > 0) {
363
- console.log(`⏭️ Skipped memberIds (${result.skippedIds.length}):`, result.skippedIds);
364
- }
365
-
366
- return result;
367
- } catch (error) {
368
- console.error(`Error processing generation chunk ${chunkIndex}:`, error);
369
- throw error;
370
- }
371
- }
372
-
373
- module.exports = {
374
- scheduleMigrateExistingUrls,
375
- migrateUrlsChunk,
376
- scheduleGenerateMissingUrls,
377
- generateUrlsChunk,
378
- };
@@ -1,174 +0,0 @@
1
- const { taskManager } = require('psdev-task-manager');
2
-
3
- const { COLLECTIONS } = require('../../public/consts');
4
- const { ensureUniqueUrlsInBatch } = require('../daily-pull/bulk-process-methods');
5
- const { ensureUniqueUrl } = require('../daily-pull/process-member-methods');
6
- const { wixData } = require('../elevated-modules');
7
- const { bulkSaveMembers, getMembersByIds } = require('../members-data-methods');
8
- const { queryAllItems, chunkArray } = require('../utils');
9
-
10
- const { TASKS_NAMES } = require('./consts');
11
-
12
- const CHUNK_SIZE = 1000;
13
-
14
- const hasSpace = value => typeof value === 'string' && /\s/.test(value);
15
-
16
- const normalizeSlug = value => (value || '').replace(/\s+/g, '').trim();
17
-
18
- /**
19
- * Schedules tasks to fix member URLs that contain spaces.
20
- */
21
- async function scheduleFixUrlsWithSpaces() {
22
- console.log('=== Scheduling Fix URLs With Spaces ===');
23
-
24
- try {
25
- const membersQuery = await wixData
26
- .query(COLLECTIONS.MEMBERS_DATA)
27
- .contains('url', ' ')
28
- .limit(1000);
29
- const members = await queryAllItems(membersQuery);
30
- console.log(`Fetched ${members.length} members with spaces in url`);
31
-
32
- const memberIds = [
33
- ...new Set(
34
- members
35
- .map(member => Number(member.memberId))
36
- .filter(memberId => Number.isFinite(memberId) && memberId > 0)
37
- ),
38
- ];
39
- console.log(`Members to fix: ${memberIds.length}`);
40
-
41
- if (memberIds.length === 0) {
42
- console.log('No members need URL space fixes');
43
- return {
44
- success: true,
45
- message: 'No members need URL space fixes',
46
- totalMembers: 0,
47
- tasksScheduled: 0,
48
- };
49
- }
50
-
51
- const chunks = chunkArray(memberIds, CHUNK_SIZE);
52
- for (let i = 0; i < chunks.length; i++) {
53
- const chunk = chunks[i];
54
- const task = {
55
- name: TASKS_NAMES.fixUrlsWithSpacesChunk,
56
- data: {
57
- memberIds: chunk,
58
- chunkIndex: i,
59
- totalChunks: chunks.length,
60
- },
61
- type: 'scheduled',
62
- };
63
- await taskManager().schedule(task);
64
- console.log(`Scheduled task ${i + 1}/${chunks.length} (${chunk.length} members)`);
65
- }
66
-
67
- const result = {
68
- success: true,
69
- message: `Scheduled ${chunks.length} tasks for ${memberIds.length} members`,
70
- totalMembers: memberIds.length,
71
- tasksScheduled: chunks.length,
72
- };
73
-
74
- console.log('=== Scheduling Complete ===');
75
- console.log(`Sample memberIds: ${memberIds.slice(0, 10).join(', ')}`);
76
- console.log(JSON.stringify(result, null, 2));
77
-
78
- return result;
79
- } catch (error) {
80
- console.error('Error scheduling URL space fixes:', error);
81
- throw error;
82
- }
83
- }
84
-
85
- /**
86
- * Processes a chunk of members and fixes URLs with spaces.
87
- */
88
- async function fixUrlsWithSpacesChunk(data) {
89
- const { memberIds, chunkIndex, totalChunks } = data;
90
- console.log(
91
- `Processing URL space fix chunk ${chunkIndex + 1}/${totalChunks} (${memberIds.length} members)`
92
- );
93
-
94
- const result = {
95
- successful: 0,
96
- failed: 0,
97
- skipped: 0,
98
- errors: [],
99
- skippedIds: [],
100
- failedIds: [],
101
- };
102
- const updatedIds = [];
103
-
104
- try {
105
- const members = await getMembersByIds(memberIds);
106
- console.log(`Loaded ${members.length} members for this chunk`);
107
-
108
- const membersToUpdate = [];
109
- for (const member of members) {
110
- if (!hasSpace(member.url)) {
111
- result.skipped++;
112
- result.skippedIds.push(member.memberId);
113
- continue;
114
- }
115
-
116
- const normalized = normalizeSlug(member.url);
117
- const ensuredUrl = await ensureUniqueUrl({
118
- url: normalized,
119
- memberId: member.memberId,
120
- fullName: member.fullName,
121
- });
122
-
123
- if (!ensuredUrl || ensuredUrl === member.url) {
124
- result.skipped++;
125
- result.skippedIds.push(member.memberId);
126
- continue;
127
- }
128
-
129
- membersToUpdate.push({
130
- ...member,
131
- url: ensuredUrl,
132
- });
133
- }
134
-
135
- if (membersToUpdate.length === 0) {
136
- console.log('No members need updating in this batch');
137
- return result;
138
- }
139
-
140
- const uniqueUpdates = await ensureUniqueUrlsInBatch(membersToUpdate);
141
- uniqueUpdates.forEach(member => {
142
- if (updatedIds.length < 20) {
143
- updatedIds.push(member.memberId);
144
- }
145
- });
146
-
147
- try {
148
- await bulkSaveMembers(uniqueUpdates);
149
- result.successful += uniqueUpdates.length;
150
- console.log(`✅ Successfully updated ${uniqueUpdates.length} members`);
151
- if (updatedIds.length > 0) {
152
- console.log(`Updated memberIds (sample): ${updatedIds.join(', ')}`);
153
- }
154
- } catch (error) {
155
- console.error('❌ Error bulk saving members:', error);
156
- result.failed += uniqueUpdates.length;
157
- result.failedIds.push(...uniqueUpdates.map(member => member.memberId));
158
- result.errors.push({
159
- error: error.message,
160
- memberCount: uniqueUpdates.length,
161
- });
162
- }
163
-
164
- return result;
165
- } catch (error) {
166
- console.error(`Error processing URL space fix chunk ${chunkIndex}:`, error);
167
- throw error;
168
- }
169
- }
170
-
171
- module.exports = {
172
- scheduleFixUrlsWithSpaces,
173
- fixUrlsWithSpacesChunk,
174
- };