abmp-npm 10.0.50 → 10.0.52

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/jobs.js CHANGED
@@ -82,20 +82,6 @@ async function scheduleFixPrimaryAddressForMembersTask() {
82
82
  }
83
83
  }
84
84
 
85
- async function scheduleFixPrimaryAddressVisibilityForMembersTask() {
86
- try {
87
- console.log('scheduleFixPrimaryAddressVisibilityForMembers started!');
88
- return await taskManager().schedule({
89
- name: TASKS_NAMES.scheduleFixPrimaryAddressVisibilityForMembers,
90
- data: {},
91
- type: 'scheduled',
92
- });
93
- } catch (error) {
94
- console.error(`Failed to scheduleFixPrimaryAddressVisibilityForMembers: ${error.message}`);
95
- throw new Error(`Failed to scheduleFixPrimaryAddressVisibilityForMembers: ${error.message}`);
96
- }
97
- }
98
-
99
85
  async function updateSiteMapS3() {
100
86
  try {
101
87
  return await taskManager().schedule({
@@ -114,5 +100,4 @@ module.exports = {
114
100
  updateSiteMapS3,
115
101
  scheduleCreateContactsFromMembersTask,
116
102
  scheduleFixPrimaryAddressForMembersTask,
117
- scheduleFixPrimaryAddressVisibilityForMembersTask,
118
103
  };
@@ -1,6 +1,6 @@
1
1
  const { taskManager } = require('psdev-task-manager');
2
2
 
3
- const { COLLECTIONS, ADDRESS_STATUS_TYPES } = require('../../public/consts');
3
+ const { COLLECTIONS } = require('../../public/consts');
4
4
  const { wixData } = require('../elevated-modules');
5
5
  const { bulkSaveMembers, getMembersByIds } = require('../members-data-methods');
6
6
  const { chunkArray, queryAllItems } = require('../utils');
@@ -16,22 +16,6 @@ const hasPrimaryAddress = addressDisplayOption =>
16
16
  Array.isArray(addressDisplayOption) &&
17
17
  addressDisplayOption.some(option => option?.isMain === true);
18
18
 
19
- const getPrimaryAddressKey = addressDisplayOption =>
20
- Array.isArray(addressDisplayOption)
21
- ? addressDisplayOption.find(option => option?.isMain === true)?.key
22
- : null;
23
-
24
- const needsPrimaryAddressVisibilityFix = (address, index) => {
25
- if (!address) {
26
- return false;
27
- }
28
- const status = address?.addressStatus;
29
- if (index === 0 && status === ADDRESS_STATUS_TYPES.DONT_SHOW) {
30
- return true;
31
- }
32
- return !status || status === ADDRESS_STATUS_TYPES.DONT_SHOW;
33
- };
34
-
35
19
  /**
36
20
  * Schedules tasks to fix members with multiple addresses and no primary address.
37
21
  */
@@ -221,204 +205,7 @@ async function fixPrimaryAddressChunk(data) {
221
205
  }
222
206
  }
223
207
 
224
- /**
225
- * Schedules tasks to fix primary address visibility when missing or DONT_SHOW.
226
- */
227
- async function scheduleFixPrimaryAddressVisibilityForMembers() {
228
- console.log('=== Scheduling Fix Primary Address Visibility Tasks ===');
229
-
230
- try {
231
- const membersQuery = await wixData
232
- .query(COLLECTIONS.MEMBERS_DATA)
233
- .isNotEmpty('addresses')
234
- .limit(1000);
235
- const members = await queryAllItems(membersQuery);
236
- console.log(`Fetched ${members.length} members with addresses`);
237
-
238
- const membersToFix = members.filter(member => {
239
- const addresses = Array.isArray(member.addresses) ? member.addresses : [];
240
- if (addresses.length === 0) {
241
- return false;
242
- }
243
- const primaryKey = getPrimaryAddressKey(member.addressDisplayOption);
244
- if (!primaryKey) {
245
- return false;
246
- }
247
- const addressIndex = addresses.findIndex(address => getAddressKey(address, 0) === primaryKey);
248
- if (addressIndex === -1) {
249
- return false;
250
- }
251
- return needsPrimaryAddressVisibilityFix(addresses[addressIndex], addressIndex);
252
- });
253
-
254
- const memberIds = [
255
- ...new Set(
256
- membersToFix
257
- .map(member => Number(member.memberId))
258
- .filter(memberId => Number.isFinite(memberId) && memberId > 0)
259
- ),
260
- ];
261
- console.log(`Members with primary address visibility issues: ${memberIds.length}`);
262
-
263
- if (memberIds.length === 0) {
264
- console.log('No members need primary address visibility fixes');
265
- return {
266
- success: true,
267
- message: 'No members need primary address visibility fixes',
268
- totalMembers: 0,
269
- tasksScheduled: 0,
270
- };
271
- }
272
-
273
- const chunks = chunkArray(memberIds, CHUNK_SIZE);
274
- for (let i = 0; i < chunks.length; i++) {
275
- const chunk = chunks[i];
276
- const task = {
277
- name: TASKS_NAMES.fixPrimaryAddressVisibilityChunk,
278
- data: {
279
- memberIds: chunk,
280
- chunkIndex: i,
281
- totalChunks: chunks.length,
282
- },
283
- type: 'scheduled',
284
- };
285
- await taskManager().schedule(task);
286
- console.log(`Scheduled task ${i + 1}/${chunks.length} (${chunk.length} members)`);
287
- }
288
-
289
- const result = {
290
- success: true,
291
- message: `Scheduled ${chunks.length} tasks for ${memberIds.length} members`,
292
- totalMembers: memberIds.length,
293
- tasksScheduled: chunks.length,
294
- };
295
-
296
- console.log('=== Scheduling Complete ===');
297
- console.log(`Sample memberIds: ${memberIds.slice(0, 10).join(', ')}`);
298
- console.log(JSON.stringify(result, null, 2));
299
-
300
- return result;
301
- } catch (error) {
302
- console.error('Error scheduling primary address visibility fix:', error);
303
- throw error;
304
- }
305
- }
306
-
307
- /**
308
- * Processes a chunk of members and fixes primary address visibility when missing or DONT_SHOW.
309
- */
310
- async function fixPrimaryAddressVisibilityChunk(data) {
311
- const { memberIds, chunkIndex, totalChunks } = data;
312
- console.log(
313
- `Processing primary address visibility chunk ${chunkIndex + 1}/${totalChunks} (${memberIds.length} members)`
314
- );
315
-
316
- const result = {
317
- successful: 0,
318
- failed: 0,
319
- skipped: 0,
320
- errors: [],
321
- skippedIds: [],
322
- failedIds: [],
323
- };
324
- const skippedNoPrimary = [];
325
- const skippedNoAddressMatch = [];
326
- const updatedIds = [];
327
-
328
- try {
329
- const members = await getMembersByIds(memberIds);
330
- console.log(`Loaded ${members.length} members for this chunk`);
331
- const membersToUpdate = [];
332
-
333
- members.forEach(member => {
334
- const addresses = Array.isArray(member.addresses) ? member.addresses : [];
335
- const primaryKey = getPrimaryAddressKey(member.addressDisplayOption);
336
- if (!primaryKey) {
337
- result.skipped++;
338
- result.skippedIds.push(member.memberId);
339
- if (skippedNoPrimary.length < 20) {
340
- skippedNoPrimary.push(member.memberId);
341
- }
342
- return;
343
- }
344
-
345
- const addressIndex = addresses.findIndex(address => getAddressKey(address, 0) === primaryKey);
346
- if (addressIndex === -1) {
347
- result.skipped++;
348
- result.skippedIds.push(member.memberId);
349
- if (skippedNoAddressMatch.length < 20) {
350
- skippedNoAddressMatch.push(member.memberId);
351
- }
352
- return;
353
- }
354
-
355
- const targetAddress = addresses[addressIndex];
356
- if (!needsPrimaryAddressVisibilityFix(targetAddress, addressIndex)) {
357
- result.skipped++;
358
- result.skippedIds.push(member.memberId);
359
- return;
360
- }
361
-
362
- const updatedAddresses = addresses.map((address, index) => {
363
- if (index !== addressIndex) {
364
- return address;
365
- }
366
- return {
367
- ...address,
368
- addressStatus: ADDRESS_STATUS_TYPES.STATE_CITY_ZIP,
369
- };
370
- });
371
-
372
- membersToUpdate.push({
373
- ...member,
374
- addresses: updatedAddresses,
375
- });
376
- if (updatedIds.length < 20) {
377
- updatedIds.push(member.memberId);
378
- }
379
- });
380
-
381
- if (membersToUpdate.length === 0) {
382
- console.log('No members need updating in this batch');
383
- return result;
384
- }
385
-
386
- try {
387
- await bulkSaveMembers(membersToUpdate);
388
- result.successful += membersToUpdate.length;
389
- console.log(`✅ Successfully updated ${membersToUpdate.length} members`);
390
- if (updatedIds.length > 0) {
391
- console.log(`Updated memberIds (sample): ${updatedIds.join(', ')}`);
392
- }
393
- } catch (error) {
394
- console.error('❌ Error bulk saving members:', error);
395
- result.failed += membersToUpdate.length;
396
- result.failedIds.push(...membersToUpdate.map(member => member.memberId));
397
- result.errors.push({
398
- error: error.message,
399
- memberCount: membersToUpdate.length,
400
- });
401
- }
402
-
403
- if (skippedNoPrimary.length > 0) {
404
- console.log(`Skipped (no primary address) sample: ${skippedNoPrimary.join(', ')}`);
405
- }
406
- if (skippedNoAddressMatch.length > 0) {
407
- console.log(
408
- `Skipped (primary address not found) sample: ${skippedNoAddressMatch.join(', ')}`
409
- );
410
- }
411
-
412
- return result;
413
- } catch (error) {
414
- console.error(`Error processing primary address visibility chunk ${chunkIndex}:`, error);
415
- throw error;
416
- }
417
- }
418
-
419
208
  module.exports = {
420
209
  scheduleFixPrimaryAddressForMembers,
421
210
  fixPrimaryAddressChunk,
422
- scheduleFixPrimaryAddressVisibilityForMembers,
423
- fixPrimaryAddressVisibilityChunk,
424
211
  };
@@ -20,8 +20,6 @@ const TASKS_NAMES = {
20
20
  createContactsFromMembers: 'createContactsFromMembers',
21
21
  scheduleFixPrimaryAddressForMembers: 'scheduleFixPrimaryAddressForMembers',
22
22
  fixPrimaryAddressChunk: 'fixPrimaryAddressChunk',
23
- scheduleFixPrimaryAddressVisibilityForMembers: 'scheduleFixPrimaryAddressVisibilityForMembers',
24
- fixPrimaryAddressVisibilityChunk: 'fixPrimaryAddressVisibilityChunk',
25
23
  };
26
24
 
27
25
  module.exports = {
@@ -7,8 +7,6 @@ const {
7
7
  const {
8
8
  scheduleFixPrimaryAddressForMembers,
9
9
  fixPrimaryAddressChunk,
10
- scheduleFixPrimaryAddressVisibilityForMembers,
11
- fixPrimaryAddressVisibilityChunk,
12
10
  } = require('./address-primary-methods');
13
11
  const { TASKS_NAMES } = require('./consts');
14
12
  const {
@@ -189,20 +187,6 @@ const TASKS = {
189
187
  shouldSkipCheck: () => false,
190
188
  estimatedDurationSec: 80,
191
189
  },
192
- [TASKS_NAMES.scheduleFixPrimaryAddressVisibilityForMembers]: {
193
- name: TASKS_NAMES.scheduleFixPrimaryAddressVisibilityForMembers,
194
- getIdentifier: () => 'SHOULD_NEVER_SKIP',
195
- process: scheduleFixPrimaryAddressVisibilityForMembers,
196
- shouldSkipCheck: () => false,
197
- estimatedDurationSec: 80,
198
- },
199
- [TASKS_NAMES.fixPrimaryAddressVisibilityChunk]: {
200
- name: TASKS_NAMES.fixPrimaryAddressVisibilityChunk,
201
- getIdentifier: task => task.data,
202
- process: fixPrimaryAddressVisibilityChunk,
203
- shouldSkipCheck: () => false,
204
- estimatedDurationSec: 80,
205
- },
206
190
  };
207
191
 
208
192
  module.exports = { TASKS };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "abmp-npm",
3
- "version": "10.0.50",
3
+ "version": "10.0.52",
4
4
  "main": "index.js",
5
5
  "scripts": {
6
6
  "check-cycles": "madge --circular .",
@@ -1,11 +1,24 @@
1
1
  const { location: wixLocation, queryParams: wixQueryParams } = require('@wix/site-location');
2
2
  const { window: wixWindow, rendering } = require('@wix/site-window');
3
3
 
4
- const { DEFAULT_FILTER } = require('../consts.js');
4
+ const { DEFAULT_FILTER, DEBOUNCE_DELAY } = require('../consts.js');
5
5
 
6
- const { debouncedFunction } = require('./sharedUtils.js');
6
+ function generateSearchId() {
7
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
8
+ const r = (Math.random() * 16) | 0;
9
+ const v = c === 'x' ? r : (r & 0x3) | 0x8;
10
+ return v.toString(16);
11
+ });
12
+ }
7
13
 
8
14
  const createHomepageUtils = (_$w, filterProfiles) => {
15
+ let currentSearchId = null;
16
+ let searchDebounceTimer = null;
17
+ let lastSearchFilter = null;
18
+ let lastSearchIsSearchingNearby = false;
19
+ let lastSearchPreservePagination = false;
20
+ let pendingSearchResolve = null;
21
+
9
22
  const getFiltersSelectors = filterName => ({
10
23
  checkBoxContainerSelector: _$w(`#${filterName}CheckBoxContainer`),
11
24
  searchTextInputSelector: _$w(`#${filterName}TextInput`),
@@ -662,6 +675,7 @@ const createHomepageUtils = (_$w, filterProfiles) => {
662
675
  }) {
663
676
  const multiStateBoxSelector = _$w('#resultsStateBox');
664
677
  const renderingEnv = await rendering.env();
678
+
665
679
  const initSearchResultsUI = () => {
666
680
  JSON.stringify(filter) === JSON.stringify(DEFAULT_FILTER)
667
681
  ? _$w('#resetFilter').hide()
@@ -672,11 +686,12 @@ const createHomepageUtils = (_$w, filterProfiles) => {
672
686
  _$w('#profileRepeater').data = [];
673
687
  console.log({ filter });
674
688
  };
675
- const runSearchAndUpdateUI = async (filter, isSearchingNearby) => {
676
- if (!isSearchingNearby) {
689
+
690
+ const runSearchAndUpdateUI = async (filterToUse, isSearchingNearbyToUse, preservePaginationToUse) => {
691
+ if (!isSearchingNearbyToUse) {
677
692
  if (
678
693
  JSON.stringify({
679
- ...filter,
694
+ ...filterToUse,
680
695
  latitude: 0,
681
696
  longitude: 0,
682
697
  }) === JSON.stringify(DEFAULT_FILTER)
@@ -685,38 +700,29 @@ const createHomepageUtils = (_$w, filterProfiles) => {
685
700
  return [];
686
701
  }
687
702
  }
688
- const nonDebouncedFilterProfiles = async () => {
689
- try {
690
- const result = await filterProfiles({ filter, isSearchingNearby });
691
- return { success: true, response: result };
692
- } catch (error) {
693
- return { success: false, error };
694
- }
695
- };
696
- //Don't run setTimeout on SSR
697
- const funcPromise =
698
- renderingEnv === 'backend'
699
- ? () => nonDebouncedFilterProfiles()
700
- : () =>
701
- debouncedFunction({
702
- func: filterProfiles,
703
- debounceTimeout,
704
- timeoutType,
705
- args: { filter, isSearchingNearby },
706
- });
707
- const { success, response, error } = await funcPromise();
708
- if (!success) {
703
+ const thisSearchId = generateSearchId();
704
+ currentSearchId = thisSearchId;
705
+
706
+ let result;
707
+ try {
708
+ result = await filterProfiles({ filter: filterToUse, isSearchingNearby: isSearchingNearbyToUse });
709
+ } catch (error) {
710
+ if (thisSearchId !== currentSearchId) return [];
709
711
  _$w('#numberOfResults').text = '';
710
712
  console.error('[search] failed with error:', error);
711
713
  multiStateBoxSelector.changeState('errorState');
712
714
  return [];
713
715
  }
716
+
717
+ if (thisSearchId !== currentSearchId) return [];
718
+
719
+ const response = result;
714
720
  const totalCount = response.items.length;
715
721
  if (!totalCount) {
716
722
  _$w('#numberOfResults').text = 'Showing 0 results';
717
723
  _$w('#noResultsMessage').text = `${
718
- filter.searchText && filter.searchText.length > 0
719
- ? `'${filter.searchText}' did not match any search. Please try again.`
724
+ filterToUse.searchText && filterToUse.searchText.length > 0
725
+ ? `'${filterToUse.searchText}' did not match any search. Please try again.`
720
726
  : 'No results found for the selected filters. Please adjust your filters and try again'
721
727
  }`;
722
728
  multiStateBoxSelector.changeState('noResultsState');
@@ -726,7 +732,7 @@ const createHomepageUtils = (_$w, filterProfiles) => {
726
732
  handleNumberOfResults(pagination, totalCount);
727
733
  _$w('#showingResult').show();
728
734
 
729
- if (!preservePagination || pagination.currentPage >= pagination.totalPages) {
735
+ if (!preservePaginationToUse || pagination.currentPage >= pagination.totalPages) {
730
736
  pagination.currentPage = 0;
731
737
  }
732
738
  pagination.totalPages = Math.ceil(totalCount / pagination.pageSize);
@@ -734,8 +740,46 @@ const createHomepageUtils = (_$w, filterProfiles) => {
734
740
  multiStateBoxSelector.changeState('resultsState');
735
741
  return response.items;
736
742
  };
743
+
744
+ // Always show loading as soon as user changes input
737
745
  initSearchResultsUI();
738
- return await runSearchAndUpdateUI(filter, isSearchingNearby);
746
+
747
+ // SSR: run immediately, no debounce
748
+ if (renderingEnv === 'backend') {
749
+ return await runSearchAndUpdateUI(filter, isSearchingNearby, preservePagination);
750
+ }
751
+
752
+ // Client: debounce the API call; loading is already shown above.
753
+ // Snapshot the filter so rapid clicks / URL sync can't mutate it before the debounced run.
754
+ lastSearchFilter = JSON.parse(JSON.stringify(filter));
755
+ lastSearchIsSearchingNearby = isSearchingNearby;
756
+ lastSearchPreservePagination = preservePagination;
757
+
758
+ if (pendingSearchResolve) {
759
+ pendingSearchResolve([]);
760
+ pendingSearchResolve = null;
761
+ }
762
+
763
+ if (searchDebounceTimer) {
764
+ clearTimeout(searchDebounceTimer);
765
+ searchDebounceTimer = null;
766
+ }
767
+
768
+ const delay = DEBOUNCE_DELAY[timeoutType] ?? 300;
769
+ return new Promise(resolve => {
770
+ pendingSearchResolve = resolve;
771
+ searchDebounceTimer = setTimeout(async () => {
772
+ searchDebounceTimer = null;
773
+ const filterToUse = lastSearchFilter;
774
+ const isSearchingNearbyToUse = lastSearchIsSearchingNearby;
775
+ const preservePaginationToUse = lastSearchPreservePagination;
776
+ const items = await runSearchAndUpdateUI(filterToUse, isSearchingNearbyToUse, preservePaginationToUse);
777
+ if (pendingSearchResolve) {
778
+ pendingSearchResolve(items);
779
+ pendingSearchResolve = null;
780
+ }
781
+ }, delay);
782
+ });
739
783
  }
740
784
 
741
785
  return {