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,798 +0,0 @@
1
- const { location: wixLocation, queryParams: wixQueryParams } = require('@wix/site-location');
2
- const { window: wixWindow, rendering } = require('@wix/site-window');
3
-
4
- const { DEFAULT_FILTER } = require('../consts.js');
5
-
6
- const { debouncedFunction } = require('./sharedUtils.js');
7
-
8
- function isValidGeolocation(lat, lng) {
9
- return Number.isFinite(lat) && Number.isFinite(lng) && (lat !== 0 || lng !== 0);
10
- }
11
-
12
- function applyGeolocationToFilter(filter, lat, lng, isSearchingNearby) {
13
- return {
14
- ...filter,
15
- postalcode: isSearchingNearby ? null : filter.postalcode,
16
- state: isSearchingNearby ? [] : filter.state,
17
- city: isSearchingNearby ? [] : filter.city,
18
- stateSearch: isSearchingNearby ? '' : filter.stateSearch,
19
- citySearch: isSearchingNearby ? '' : filter.citySearch,
20
- latitude: lat,
21
- longitude: lng,
22
- };
23
- }
24
-
25
- const GEOLOCATION_TIMEOUT_MS = 10000;
26
-
27
- function getCurrentGeolocationWithTimeout(timeoutMs = GEOLOCATION_TIMEOUT_MS) {
28
- return new Promise((resolve, reject) => {
29
- const timer = setTimeout(() => {
30
- reject(new Error(`Geolocation timed out after ${timeoutMs}ms`));
31
- }, timeoutMs);
32
- wixWindow
33
- .getCurrentGeolocation()
34
- .then(location => {
35
- clearTimeout(timer);
36
- resolve(location);
37
- })
38
- .catch(error => {
39
- clearTimeout(timer);
40
- reject(error);
41
- });
42
- });
43
- }
44
-
45
- const createHomepageUtils = (_$w, filterProfiles) => {
46
- const getFiltersSelectors = filterName => ({
47
- checkBoxContainerSelector: _$w(`#${filterName}CheckBoxContainer`),
48
- searchTextInputSelector: _$w(`#${filterName}TextInput`),
49
- clearSearchButtonSelector: _$w(`#${filterName}ClearButton`),
50
- toggleOptionListButtonSelector: _$w(`#${filterName}ToggleButton`),
51
- multiCheckBoxSelector: _$w(`#${filterName}CheckBox`),
52
- });
53
-
54
- const getParamsMapping = (filter, pagination) => ({
55
- page: {
56
- getValue: () => pagination.currentPage + 1,
57
- setValue: ({ value }) => {
58
- pagination.currentPage = parseInt(value) - 1;
59
- },
60
- },
61
- searchText: {
62
- getValue: () => filter.searchText,
63
- setValue: ({ value }) => {
64
- filter.searchText = value;
65
- _$w('#searchDesktop,#searchTabletMobile').value = value;
66
- },
67
- },
68
- state: {
69
- getValue: () => (filter.state?.length ? filter.state.join(',') : null),
70
- setValue: ({ value }) => {
71
- const states = value.split(',');
72
- filter['state'] = states;
73
- },
74
- setUI: async ({
75
- value,
76
- dropDownOptions,
77
- stateNameCodeMap,
78
- sidePanelFilterData,
79
- stateCityMap,
80
- }) => {
81
- const states = value.split(',');
82
- await onChangeMultiCheckbox({
83
- filterName: 'state',
84
- selectedOptions: states,
85
- dropDownOptions,
86
- filter,
87
- pagination,
88
- stateNameCodeMap,
89
- sidePanelFilterData,
90
- stateCityMap,
91
- });
92
- },
93
- },
94
- city: {
95
- getValue: () => (filter.city?.length ? filter.city.join(',') : null),
96
- setValue: ({ value }) => {
97
- const cities = value.split(',');
98
- filter['city'] = cities;
99
- },
100
- setUI: async ({
101
- value,
102
- dropDownOptions,
103
- stateNameCodeMap,
104
- sidePanelFilterData,
105
- stateCityMap,
106
- }) => {
107
- const cities = value.split(',');
108
- await onChangeMultiCheckbox({
109
- filterName: 'city',
110
- selectedOptions: cities,
111
- dropDownOptions,
112
- filter,
113
- pagination,
114
- stateNameCodeMap,
115
- sidePanelFilterData,
116
- stateCityMap,
117
- });
118
- },
119
- },
120
- practiceAreas: {
121
- getValue: () => (filter.practiceAreas?.length ? filter.practiceAreas.join(',') : null),
122
- setValue: ({ value }) => {
123
- const practices = value.split(',');
124
- filter['practiceAreas'] = practices;
125
- },
126
- setUI: async ({
127
- value,
128
- dropDownOptions,
129
- stateNameCodeMap,
130
- sidePanelFilterData,
131
- stateCityMap,
132
- }) => {
133
- const practices = value.split(',');
134
- await onChangeMultiCheckbox({
135
- filterName: 'practiceAreas',
136
- selectedOptions: practices,
137
- dropDownOptions,
138
- filter,
139
- pagination,
140
- stateNameCodeMap,
141
- sidePanelFilterData,
142
- stateCityMap,
143
- });
144
- },
145
- },
146
- zip: {
147
- getValue: () => filter.postalcode,
148
- setValue: ({ value }) => {
149
- filter.postalcode = value;
150
- _$w('#zipcode').value = value;
151
- },
152
- },
153
- nearby: {
154
- getValue: () => (_$w('#nearBy').checked ? 'true' : 'false'),
155
- setValue: ({ value }) => (_$w('#nearBy').checked = value === 'true'),
156
- },
157
- });
158
- async function handlePagination({ delta, pagination, searchResults, filter }) {
159
- const newPage = pagination.currentPage + delta;
160
- const maxPage = pagination.totalPages ? pagination.totalPages - 1 : 0;
161
- if (newPage < 0 || newPage > maxPage) return;
162
-
163
- newPage === 0 ? _$w('#previousPage').disable() : _$w('#previousPage').enable();
164
- newPage === maxPage ? _$w('#nextPage').disable() : _$w('#nextPage').enable();
165
- pagination.currentPage = newPage;
166
-
167
- paginateSearchResults(searchResults, pagination);
168
- await updateUrlParams(filter, pagination);
169
-
170
- _$w('#resultsStateBox').scrollTo();
171
- }
172
-
173
- async function onChangeMultiCheckbox({
174
- filterName,
175
- selectedOptions,
176
- dropDownOptions,
177
- filter,
178
- pagination,
179
- stateNameCodeMap,
180
- sidePanelFilterData,
181
- stateCityMap,
182
- isMobile = false,
183
- }) {
184
- const { searchTextInputSelector, clearSearchButtonSelector } = getFiltersSelectors(filterName);
185
- dropDownOptions[filterName].selectedOptions = selectedOptions;
186
-
187
- // Update display text based on selection
188
- dropDownOptions[filterName].displayText = displayTextValue({
189
- type: filterName,
190
- selectedOptions,
191
- totalLength: selectedOptions.length,
192
- stateNameCodeMap,
193
- });
194
-
195
- // Update searchTextInput to show selection summary
196
- searchTextInputSelector.value = dropDownOptions[filterName].displayText;
197
- filter[`${filterName}Search`] = '';
198
- // Show/hide clear button based on selection
199
- if (selectedOptions.length > 0) {
200
- clearSearchButtonSelector.expand();
201
- } else {
202
- clearSearchButtonSelector.collapse();
203
- }
204
-
205
- // Update filter object with selected values
206
- filter[filterName] = selectedOptions;
207
- filter.skip = 0;
208
-
209
- // Enable/disable city dropdown based on state selection
210
- if (filterName === 'state') {
211
- // update city selections based on state selection
212
- const { multiCheckBoxSelector, searchTextInputSelector: citySearchTextInputSelector } =
213
- getFiltersSelectors('city');
214
-
215
- const citySelectedOptions = multiCheckBoxSelector.selectedIndices;
216
- if (citySelectedOptions && citySelectedOptions.length > 0) {
217
- // get all city options for the selected state
218
- const options = prepareOptionsFunction({
219
- filterName: 'city',
220
- sidePanelFilterData,
221
- stateCityMap,
222
- filter,
223
- });
224
- // filter out options that are not in the selected state
225
- const filteredOptions =
226
- multiCheckBoxSelector.selectedIndices.filter(index =>
227
- options.some(o => o.value == multiCheckBoxSelector.options[index].value)
228
- ) || [];
229
- const filteredOptionsTexts = filteredOptions.map(
230
- index => multiCheckBoxSelector.options[index].label
231
- );
232
- // update city dropdown with filtered options
233
- if (filteredOptions.length > 0) {
234
- multiCheckBoxSelector.selectedIndices = filteredOptions;
235
- citySearchTextInputSelector.value = displayTextValue({
236
- type: 'city',
237
- selectedOptions: filteredOptionsTexts,
238
- totalLength: filteredOptionsTexts.length,
239
- stateNameCodeMap,
240
- });
241
- } else {
242
- // if no city options are selected, set default city
243
- setDefaultCity({
244
- filter,
245
- dropDownOptions,
246
- sidePanelFilterData,
247
- stateCityMap,
248
- });
249
- }
250
- }
251
-
252
- if (selectedOptions && selectedOptions.length > 0 && !_$w('#nearBy').checked) {
253
- _$w('#cityTextInput').enable();
254
- } else {
255
- _$w('#cityTextInput').disable();
256
- setDefaultCity({
257
- filter,
258
- dropDownOptions,
259
- sidePanelFilterData,
260
- stateCityMap,
261
- });
262
- }
263
- }
264
-
265
- if (!isMobile) {
266
- await updateUrlParams(filter, pagination);
267
- }
268
- }
269
-
270
- function displayTextValue({ type, selectedOptions, totalLength, stateNameCodeMap }) {
271
- if (totalLength === 0) {
272
- return '';
273
- }
274
- let displayText = '';
275
- if (type === 'state') {
276
- displayText =
277
- totalLength === 1 ? stateNameCodeMap.get(selectedOptions[0]) : `${totalLength} selected`;
278
- } else {
279
- displayText = totalLength === 1 ? selectedOptions[0] : `${totalLength} selected`;
280
- }
281
- return displayText;
282
- }
283
-
284
- function setDefaultCity({ filter, dropDownOptions, sidePanelFilterData, stateCityMap }) {
285
- _$w('#cityTextInput').value = '';
286
- _$w('#cityTextInput').disable();
287
- setDefaultState({
288
- filterName: 'city',
289
- withSelectedOptions: false,
290
- filter,
291
- dropDownOptions,
292
- sidePanelFilterData,
293
- stateCityMap,
294
- });
295
- }
296
-
297
- function setDefaultState({
298
- filterName,
299
- withSelectedOptions,
300
- filter,
301
- dropDownOptions,
302
- sidePanelFilterData,
303
- stateCityMap,
304
- }) {
305
- const { checkBoxContainerSelector, clearSearchButtonSelector } =
306
- getFiltersSelectors(filterName);
307
- setDefaultFilterOption({
308
- filterName,
309
- withSelectedOptions,
310
- dropDownOptions,
311
- filter,
312
- sidePanelFilterData,
313
- stateCityMap,
314
- });
315
- if (!withSelectedOptions) {
316
- filter[filterName] = [];
317
- }
318
- filter[`${filterName}Search`] = '';
319
- clearSearchButtonSelector.collapse();
320
- checkBoxContainerSelector.collapse();
321
- }
322
-
323
- function setDefaultFilterOption({
324
- filterName,
325
- withSelectedOptions = false,
326
- dropDownOptions,
327
- filter,
328
- sidePanelFilterData,
329
- stateCityMap,
330
- }) {
331
- const { multiCheckBoxSelector } = getFiltersSelectors(filterName);
332
- multiCheckBoxSelector.options = prepareOptionsFunction({
333
- filterName,
334
- sidePanelFilterData,
335
- stateCityMap,
336
- filter,
337
- });
338
- if (withSelectedOptions) {
339
- multiCheckBoxSelector.value = dropDownOptions[filterName].selectedOptions;
340
- } else {
341
- multiCheckBoxSelector.value = [];
342
- dropDownOptions[filterName].selectedOptions = [];
343
- dropDownOptions[filterName].displayText = undefined;
344
- filter[filterName] = [];
345
- }
346
- }
347
-
348
- function prepareOptionsFunction({ filterName, sidePanelFilterData, stateCityMap, filter }) {
349
- let options = [];
350
-
351
- if (filterName === 'state' || filterName === 'practiceAreas') {
352
- options =
353
- sidePanelFilterData.has(filterName) && sidePanelFilterData.get(filterName).length > 0
354
- ? sidePanelFilterData.get(filterName)
355
- : [];
356
-
357
- options.sort((a, b) => a.label.localeCompare(b.label));
358
- return options;
359
- }
360
-
361
- if (filterName === 'city' && filter.state.length > 0) {
362
- filter.state.forEach(state => {
363
- const cityArr = stateCityMap.get(state);
364
- if (!cityArr || cityArr.length === 0) return;
365
- cityArr.forEach(city => options.push({ label: city, value: city }));
366
- });
367
-
368
- // Sort cities alphabetically
369
- options.sort((a, b) => a.label.localeCompare(b.label));
370
- }
371
-
372
- return options;
373
- }
374
-
375
- function handleNumberOfResults(pagination, totalCount) {
376
- const startResult = pagination.currentPage * pagination.pageSize + 1;
377
- const endResult = Math.min((pagination.currentPage + 1) * pagination.pageSize, totalCount);
378
- _$w('#numberOfResults').text = `Showing ${startResult} - ${endResult} of ${totalCount} results`;
379
- }
380
-
381
- /**
382
- * TOGGLES BETWEEN FILTERS BASED ON THE SCREEN SIZE
383
- */
384
-
385
- function showFiltersOnDesktop() {
386
- wixWindow
387
- .getBoundingRect()
388
- .then(windowRect => {
389
- if (windowRect.window.width > 1300) {
390
- // Expand the container if the screen is wider than 1300px
391
- _$w('#filtersContainer').expand();
392
- } else {
393
- // Collapse the container if the screen is 1300px or less
394
- _$w('#filtersContainer').collapse();
395
- }
396
- })
397
- .catch(err => {
398
- console.error('Error getting window dimensions:', err);
399
- });
400
- }
401
- async function getAndSetUserLocation(isSearchingNearby, filter) {
402
- const { latitude: existingLat, longitude: existingLng } = filter;
403
- if (isValidGeolocation(existingLat, existingLng)) {
404
- return {
405
- success: true,
406
- filter: applyGeolocationToFilter(filter, existingLat, existingLng, isSearchingNearby),
407
- };
408
- }
409
-
410
- try {
411
- const location = await getCurrentGeolocationWithTimeout();
412
-
413
- console.log('location inside getAndSetUserLocation', location);
414
- const userLat = location.coords?.latitude ?? 0;
415
- const userLong = location.coords?.longitude ?? 0;
416
- return {
417
- success: true,
418
- filter: applyGeolocationToFilter(filter, userLat, userLong, isSearchingNearby),
419
- };
420
- } catch (error) {
421
- console.warn('Failed to get user location in getAndSetUserLocation', error);
422
- return { success: false, filter };
423
- }
424
- }
425
- function setDefaultDropdownState(filterName, filter) {
426
- filter[filterName] = [];
427
-
428
- // Hide clear search button ("x")
429
-
430
- const clearSearchButtonSelector = _$w(`#${filterName}ClearButton`);
431
-
432
- clearSearchButtonSelector.collapse();
433
-
434
- // Clear the text present on text input bar
435
-
436
- const searchTextInputSelector = _$w(`#${filterName}TextInput`);
437
-
438
- searchTextInputSelector.value = undefined;
439
-
440
- // Make dropdown options and selected as empty
441
-
442
- const multiCheckBoxSelector = _$w(`#${filterName}CheckBox`);
443
-
444
- multiCheckBoxSelector.options = [];
445
-
446
- multiCheckBoxSelector.value = [];
447
-
448
- // If dropdown drawer is open close it
449
-
450
- const checkBoxContainerSelector = _$w(`#${filterName}CheckBoxContainer`);
451
-
452
- checkBoxContainerSelector.collapse();
453
- }
454
-
455
- function toggleDropdownFunctionality(filterName, enable) {
456
- // If disable then hide clear search button ("x")
457
-
458
- const clearSearchButtonSelector = _$w(`#${filterName}ClearButton`);
459
-
460
- !enable && clearSearchButtonSelector.collapse();
461
-
462
- enable && clearSearchButtonSelector.enable();
463
-
464
- // Toggle functionality based on the enable flag
465
-
466
- const searchTextInputSelector = _$w(`#${filterName}TextInput`);
467
-
468
- enable ? searchTextInputSelector.enable() : searchTextInputSelector.disable();
469
-
470
- // Toggle functionality of dropdown options based on the enable flag
471
-
472
- const multiCheckBoxSelector = _$w(`#${filterName}CheckBox`);
473
-
474
- enable ? multiCheckBoxSelector.enable() : multiCheckBoxSelector.disable();
475
-
476
- // If disable close dropdown drawer
477
-
478
- const checkBoxContainerSelector = _$w(`#${filterName}CheckBoxContainer`);
479
-
480
- !enable && checkBoxContainerSelector.collapse();
481
- }
482
-
483
- function updatePaginationUI(pagination) {
484
- const { currentPage, totalPages } = pagination;
485
- const noOfPages = totalPages <= 10 ? totalPages : 10;
486
- for (let i = 0; i < 10; i++) {
487
- const pageNumber = i + 1;
488
- const currentPageButtonIterator = _$w(`#pageButton${pageNumber}`);
489
- if (i < noOfPages) {
490
- currentPageButtonIterator.expand();
491
- currentPageButtonIterator.label = `${pageNumber}`;
492
-
493
- // Style the current page button
494
- if (pageNumber === currentPage + 1) {
495
- currentPageButtonIterator.disable();
496
- } else {
497
- currentPageButtonIterator.enable();
498
- }
499
- } else {
500
- currentPageButtonIterator.collapse();
501
- }
502
- }
503
- if (totalPages === 0 || totalPages === 1) {
504
- _$w('#previousPage').disable();
505
- _$w('#nextPage').disable();
506
- return;
507
- }
508
- if (currentPage === 0) {
509
- _$w('#previousPage').disable();
510
- } else {
511
- _$w('#previousPage').enable();
512
- }
513
- if (currentPage >= totalPages - 1) {
514
- _$w('#nextPage').disable();
515
- } else {
516
- _$w('#nextPage').enable();
517
- }
518
- }
519
- function paginateSearchResults(searchResults, pagination) {
520
- updatePaginationUI(pagination);
521
- handleNumberOfResults(pagination, searchResults.length);
522
- const currentPageData = searchResults.slice(
523
- pagination.currentPage * pagination.pageSize,
524
- (pagination.currentPage + 1) * pagination.pageSize
525
- );
526
- _$w('#profileRepeater').data = currentPageData;
527
- }
528
-
529
- // BASED ON DROPDOWN SEARCH TEXT FILTER DROPDOWN OPTIONS
530
-
531
- function filterOptionsFunction(filterName, cachedOptions, searchText) {
532
- return cachedOptions.filter(
533
- option =>
534
- option.label.toLowerCase().includes(searchText.toLowerCase()) ||
535
- (filterName === 'state' && option.value.includes(searchText))
536
- );
537
- }
538
- async function parseAndValidateQueryParams(filter, pagination) {
539
- const params = await wixLocation.query();
540
- const paramsMapping = getParamsMapping(filter, pagination);
541
- const {
542
- siteRevision: _siteRevision,
543
- branchId: _branchId,
544
- ssrOnly: _ssrOnly,
545
- ...withoutPreviewParams
546
- } = params || {};
547
- const isSearchingNearby = params.nearby === 'true';
548
- const isNoParams = !withoutPreviewParams || Object.keys(withoutPreviewParams).length === 0;
549
- const { success, filter: newFilter } = await getAndSetUserLocation(isSearchingNearby, filter);
550
-
551
- // Auto-enable nearby if GPS permission granted on fresh page load
552
- if (
553
- isNoParams &&
554
- success &&
555
- newFilter.latitude !== 0 &&
556
- newFilter.longitude !== 0 &&
557
- !isSearchingNearby
558
- ) {
559
- await wixQueryParams.add({ nearby: 'true', page: '1' });
560
- return { isDefaultStateParams: true, filter: newFilter };
561
- }
562
-
563
- if (isNoParams) {
564
- // search({
565
- // filter,
566
- // pagination,
567
- // debounceTimeout: 0,
568
- // timeoutType: 'search',
569
- // isSearchingNearby: false,
570
- // });
571
- // Don't search yet - let the caller decide what to do
572
- // The search will be handled in applyFilterToUI
573
- return { isDefaultStateParams: true, filter: newFilter };
574
- }
575
- let autoAdjustFilters = false;
576
- const validatePageValue = value => {
577
- if (!value || isNaN(Number(value)) || Number(value) < 1 || Number(value) > 10) {
578
- return { valid: false, value: '1' };
579
- } else {
580
- return { valid: true, value: value.toString() };
581
- }
582
- };
583
- const pageValidationResult = validatePageValue(params.page);
584
- if (!pageValidationResult.valid) {
585
- paramsMapping.page.setValue({ value: pageValidationResult.value });
586
- autoAdjustFilters = true;
587
- }
588
- if (isSearchingNearby) {
589
- //if nearby is true only city,state,zip should be reset, others should be preserved and taken from query params
590
- const paramsToPreserve = ['practiceAreas', 'searchText', 'page'];
591
- paramsToPreserve.forEach(paramName => {
592
- if (params[paramName]) {
593
- let value = params[paramName];
594
- if (paramName === 'page') {
595
- value = pageValidationResult.value;
596
- }
597
- paramsMapping[paramName].setValue({ value });
598
- }
599
- });
600
- paramsMapping.nearby.setValue({ value: 'true' });
601
- autoAdjustFilters = true;
602
- }
603
- if (autoAdjustFilters) {
604
- await updateUrlParams(filter, pagination);
605
- }
606
- const isNearbyFilter =
607
- (Object.keys(withoutPreviewParams).length === 2 &&
608
- withoutPreviewParams.nearby &&
609
- withoutPreviewParams.page) ||
610
- (Object.keys(withoutPreviewParams).length === 1 && withoutPreviewParams.nearby);
611
- const isDefaultStateParams = isNoParams || isNearbyFilter;
612
- return { isDefaultStateParams, filter: newFilter };
613
- }
614
-
615
- async function updateUrlQuery(filters, defaultFilters) {
616
- const queryParams = {};
617
-
618
- for (const key in filters) {
619
- const val = filters[key];
620
- const defaultVal = defaultFilters[key];
621
-
622
- // Only include non-default values in URL
623
- if (JSON.stringify(val) !== JSON.stringify(defaultVal)) {
624
- queryParams[key] = Array.isArray(val) ? JSON.stringify(val) : val;
625
- }
626
- }
627
-
628
- await wixQueryParams.add(queryParams);
629
- }
630
-
631
- async function updateUrlParams(filter, pagination) {
632
- const paramsMapping = getParamsMapping(filter, pagination);
633
- // Get current query parameters
634
- const currentParams = await wixLocation.query();
635
- // Remove all existing parameters that we manage
636
- Object.keys(paramsMapping).forEach(async param => {
637
- if (currentParams[param]) {
638
- await wixQueryParams.remove([param]);
639
- }
640
- });
641
-
642
- // Add new parameters only if they have values
643
- let addedParams = 0;
644
- Object.entries(paramsMapping).forEach(async ([param, { getValue }]) => {
645
- const value = getValue();
646
- if (param !== 'page') {
647
- if (value !== null && value !== undefined && value !== '') {
648
- addedParams++;
649
- await wixQueryParams.add({ [param]: value.toString() });
650
- }
651
- }
652
- });
653
- if (addedParams === 1) {
654
- // Only add page URL parameter, if nearby is true when there's exactly one filter
655
- if (paramsMapping.nearby.getValue() === 'true') {
656
- await wixQueryParams.add({
657
- page: paramsMapping.page.getValue().toString(),
658
- });
659
- }
660
- } else if (addedParams > 1) {
661
- // Always add page when there are multiple filters
662
- await wixQueryParams.add({
663
- page: paramsMapping.page.getValue().toString(),
664
- });
665
- }
666
- }
667
-
668
- async function noSearchCriteria() {
669
- const params = await wixLocation.query();
670
- const {
671
- siteRevision: _siteRevision,
672
- branchId: _branchId,
673
- ...withoutPreviewParams
674
- } = params || {};
675
- const isNoParams = !withoutPreviewParams || Object.keys(withoutPreviewParams).length === 0;
676
-
677
- // Also consider it as no search criteria if only nearby=false exists
678
- const onlyNearbyFalse =
679
- Object.keys(withoutPreviewParams).length === 1 && withoutPreviewParams.nearby === 'false';
680
-
681
- return isNoParams || onlyNearbyFalse;
682
- }
683
-
684
- /**
685
- * UPDATE PROFILES BASED ON APPLIED/DEFAULT FILTER
686
- */
687
- async function search({
688
- filter,
689
- pagination,
690
- debounceTimeout,
691
- timeoutType,
692
- isSearchingNearby,
693
- preservePagination = false,
694
- }) {
695
- const multiStateBoxSelector = _$w('#resultsStateBox');
696
- const renderingEnv = await rendering.env();
697
- const initSearchResultsUI = () => {
698
- JSON.stringify(filter) === JSON.stringify(DEFAULT_FILTER)
699
- ? _$w('#resetFilter').hide()
700
- : _$w('#resetFilter').show();
701
- _$w('#showingResult').hide();
702
- multiStateBoxSelector.changeState('loadingState');
703
- _$w('#showingResult').hide();
704
- _$w('#profileRepeater').data = [];
705
- console.log({ filter });
706
- };
707
- const runSearchAndUpdateUI = async (filter, isSearchingNearby) => {
708
- if (!isSearchingNearby) {
709
- if (
710
- JSON.stringify({
711
- ...filter,
712
- latitude: 0,
713
- longitude: 0,
714
- }) === JSON.stringify(DEFAULT_FILTER)
715
- ) {
716
- multiStateBoxSelector.changeState('noSearchCriteria');
717
- return [];
718
- }
719
- }
720
- const nonDebouncedFilterProfiles = async () => {
721
- try {
722
- const result = await filterProfiles({ filter, isSearchingNearby });
723
- return { success: true, response: result };
724
- } catch (error) {
725
- return { success: false, error };
726
- }
727
- };
728
- //Don't run setTimeout on SSR
729
- const funcPromise =
730
- renderingEnv === 'backend'
731
- ? () => nonDebouncedFilterProfiles()
732
- : () =>
733
- debouncedFunction({
734
- func: filterProfiles,
735
- debounceTimeout,
736
- timeoutType,
737
- args: { filter, isSearchingNearby },
738
- });
739
- const { success, response, error } = await funcPromise();
740
- if (!success) {
741
- _$w('#numberOfResults').text = '';
742
- console.error('[search] failed with error:', error);
743
- multiStateBoxSelector.changeState('errorState');
744
- return [];
745
- }
746
- const totalCount = response.items.length;
747
- if (!totalCount) {
748
- _$w('#numberOfResults').text = 'Showing 0 results';
749
- _$w('#noResultsMessage').text = `${
750
- filter.searchText && filter.searchText.length > 0
751
- ? `'${filter.searchText}' did not match any search. Please try again.`
752
- : 'No results found for the selected filters. Please adjust your filters and try again'
753
- }`;
754
- multiStateBoxSelector.changeState('noResultsState');
755
- return [];
756
- }
757
- console.log({ response });
758
- handleNumberOfResults(pagination, totalCount);
759
- _$w('#showingResult').show();
760
-
761
- if (!preservePagination || pagination.currentPage >= pagination.totalPages) {
762
- pagination.currentPage = 0;
763
- }
764
- pagination.totalPages = Math.ceil(totalCount / pagination.pageSize);
765
- paginateSearchResults(response.items, pagination);
766
- multiStateBoxSelector.changeState('resultsState');
767
- return response.items;
768
- };
769
- initSearchResultsUI();
770
- return await runSearchAndUpdateUI(filter, isSearchingNearby);
771
- }
772
-
773
- return {
774
- getFiltersSelectors,
775
- getParamsMapping,
776
- handlePagination,
777
- onChangeMultiCheckbox,
778
- setDefaultCity,
779
- setDefaultState,
780
- setDefaultFilterOption,
781
- prepareOptionsFunction,
782
- handleNumberOfResults,
783
- getAndSetUserLocation,
784
- setDefaultDropdownState,
785
- toggleDropdownFunctionality,
786
- paginateSearchResults,
787
- showFiltersOnDesktop,
788
- filterOptionsFunction,
789
- parseAndValidateQueryParams,
790
- updateUrlQuery,
791
- updateUrlParams,
792
- noSearchCriteria,
793
- search,
794
- };
795
- };
796
- module.exports = {
797
- createHomepageUtils,
798
- };