sr-npm 2.0.18 → 2.0.19

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.
@@ -0,0 +1,560 @@
1
+ const { COLLECTIONS,CUSTOM_VALUES_COLLECTION_FIELDS,JOBS_COLLECTION_FIELDS } = require('../backend/collectionConsts');
2
+ const { queryParams} = require('wix-location-frontend');
3
+ const { location } = require("@wix/site-location");
4
+ const {CAREERS_MULTI_BOXES_PAGE_CONSTS,FiltersIds,fieldTitlesInCMS} = require('../backend/careersMultiBoxesPageIds');
5
+ const { groupValuesByField, debounce, getAllRecords, getFieldById, getFieldByTitle,getCorrectOption,getOptionIndexFromCheckBox,loadPrimarySearchRepeater,bindPrimarySearch,primarySearch } = require('./pagesUtils');
6
+
7
+ let dontUpdateThisCheckBox;
8
+ const selectedByField = new Map(); // fieldId -> array of selected value IDs
9
+ const optionsByFieldId = new Map(); // fieldId -> [{label, value}] array of objects with label which is the valueLabel and value which is the valueId
10
+ const countsByFieldId = new Map(); // fieldId -> {valueId: count} map of counts for each valueId
11
+ let allfields=[] // all fields in the database
12
+ let alljobs=[] // all jobs in the database
13
+ let allvaluesobjects=[] // all values in the database
14
+ let valueToJobs={} // valueId -> array of jobIds
15
+ let currentJobs=[] // current jobs that are displayed in the jobs repeater
16
+ let allsecondarySearchJobs=[] // secondary search results that are displayed in the jobs repeater
17
+ let currentSecondarySearchJobs=[] // current secondary search results that are displayed in the jobs repeater
18
+ let secondarySearchIsFilled=false // whether the secondary search is filled with results
19
+ let keywordAllJobs; // all jobs that are displayed in the jobs repeater when the keyword is filled
20
+ const pagination = {
21
+ pageSize: 10,
22
+ currentPage: 1,
23
+ };
24
+ async function careersMultiBoxesPageOnReady(_$w,urlParams) {
25
+ await loadData(_$w);
26
+ loadJobsRepeater(_$w);
27
+ loadPrimarySearchRepeater(_$w);
28
+ await loadFilters(_$w);
29
+ loadSelectedValuesRepeater(_$w);
30
+ bindSearchInput(_$w);
31
+ loadPaginationButtons(_$w);
32
+
33
+ if (await window.formFactor() === "Mobile") {
34
+ handleFilterInMobile(_$w);
35
+ }
36
+
37
+ await handleUrlParams(_$w, urlParams);
38
+ _$w(CAREERS_MULTI_BOXES_PAGE_CONSTS.CLEAR_ALL_BUTTON_ID).onClick(async () => {
39
+ await clearAll(_$w);
40
+ });
41
+
42
+ }
43
+
44
+ async function clearAll(_$w) {
45
+ if(selectedByField.size>0 || _$w(CAREERS_MULTI_BOXES_PAGE_CONSTS.SECONDARY_SEARCH_INPUT).value || _$w(CAREERS_MULTI_BOXES_PAGE_CONSTS.PRIMARY_SEARCH_INPUT).value) {
46
+ for(const field of allfields) {
47
+ _$w(`#${FiltersIds[field.title]}CheckBox`).selectedIndices = [];
48
+ }
49
+ selectedByField.clear();
50
+ _$w(CAREERS_MULTI_BOXES_PAGE_CONSTS.SECONDARY_SEARCH_INPUT).value='';
51
+ _$w(CAREERS_MULTI_BOXES_PAGE_CONSTS.PRIMARY_SEARCH_INPUT).value='';
52
+ secondarySearchIsFilled=false;
53
+ currentJobs=alljobs;
54
+ keywordAllJobs=undefined;
55
+ await updateJobsAndNumbersAndFilters(_$w,true);
56
+ }
57
+ }
58
+
59
+ function handleFilterInMobile(_$w) {
60
+ const searchResultsSelectors = [
61
+ CAREERS_PAGE_SELECTORS.RESULT_BOX,
62
+ CAREERS_PAGE_SELECTORS.PAGINATION_BTN,
63
+ CAREERS_PAGE_SELECTORS.HEAD_BTNS,
64
+ CAREERS_PAGE_SELECTORS.SELECTED_VALUES_REPEATER,
65
+ CAREERS_PAGE_SELECTORS.BUTTOM_TXT,
66
+ CAREERS_PAGE_SELECTORS.SECTION_24,
67
+ CAREERS_PAGE_SELECTORS.SECTION_3,
68
+ CAREERS_PAGE_SELECTORS.LINE_3,
69
+ CAREERS_PAGE_SELECTORS.FILTER_ICON];
70
+
71
+ _$w(CAREERS_PAGE_SELECTORS.FILTER_ICON).onClick(()=>{
72
+ _$w(CAREERS_PAGE_SELECTORS.FILTER_BOX).expand();
73
+ searchResultsSelectors.forEach(selector => {
74
+ _$w(selector).collapse();
75
+ });
76
+ });
77
+
78
+ const exitFilterBox = () => {
79
+ _$w(CAREERS_PAGE_SELECTORS.FILTER_BOX).collapse();
80
+ searchResultsSelectors.forEach(selector => {
81
+ _$w(selector).expand();
82
+ });
83
+ }
84
+
85
+ _$w(CAREERS_PAGE_SELECTORS.EXIT_BUTTON).onClick(()=>{
86
+ exitFilterBox();
87
+ });
88
+
89
+ _$w(CAREERS_PAGE_SELECTORS.REFINE_SEARCH_BUTTON).onClick(()=>{
90
+ exitFilterBox();
91
+ });
92
+ }
93
+
94
+
95
+ async function handleUrlParams(_$w,urlParams) {
96
+ try {
97
+ let applyFiltering=false;
98
+
99
+ if(urlParams.keyword) {
100
+ applyFiltering=await primarySearch(_$w, decodeURIComponent(urlParams.keyword), alljobs);
101
+ _$w(CAREERS_MULTI_BOXES_PAGE_CONSTS.PRIMARY_SEARCH_INPUT).value=decodeURIComponent(urlParams.keyword);
102
+ currentJobs=_$w(CAREERS_MULTI_BOXES_PAGE_CONSTS.JOB_RESULTS_REPEATER).data;
103
+ keywordAllJobs=_$w(CAREERS_MULTI_BOXES_PAGE_CONSTS.JOB_RESULTS_REPEATER).data;
104
+ }
105
+ if(urlParams.brand) {
106
+ applyFiltering=await handleParams(_$w,"brand",urlParams.brand)
107
+ }
108
+ if(urlParams.visibility) {
109
+ applyFiltering=await handleParams(_$w,"visibility",urlParams.visibility)
110
+ }
111
+ if(urlParams.category) {
112
+ applyFiltering=await handleParams(_$w,"category",urlParams.category)
113
+ }
114
+
115
+ if(applyFiltering || keywordAllJobs) {
116
+ await updateJobsAndNumbersAndFilters(_$w);
117
+ }
118
+ if(urlParams.page) {
119
+ if(Number.isNaN(Number(urlParams.page)) || Number(urlParams.page)<=1 || Number(urlParams.page)>Math.ceil(currentJobs.length/pagination.pageSize)) {
120
+ console.warn("page number is invalid, removing page from url");
121
+ queryParams.remove(["page"]);
122
+ return;
123
+ }
124
+ pagination.currentPage=Number(urlParams.page);
125
+ let paginationCurrentText=Number(urlParams.page)*pagination.pageSize
126
+ let startSlicIndex=pagination.pageSize*(pagination.currentPage-1);
127
+ let endSlicIndex=(pagination.pageSize)*(pagination.currentPage);
128
+ if(Number(urlParams.page)==Math.ceil(currentJobs.length/pagination.pageSize)) {
129
+ paginationCurrentText=paginationCurrentText-(pagination.pageSize-(currentJobs.length%pagination.pageSize));
130
+ endSlicIndex=currentJobs.length;
131
+ }
132
+ _$w(CAREERS_MULTI_BOXES_PAGE_CONSTS.paginationCurrentText).text = paginationCurrentText.toString();
133
+ const jobsFirstPage=currentJobs.slice(startSlicIndex,endSlicIndex);
134
+ _$w(CAREERS_MULTI_BOXES_PAGE_CONSTS.JOBS_REPEATER).data = jobsFirstPage;
135
+ handlePaginationButtons(_$w);
136
+ }
137
+ } catch (error) {
138
+ console.error('Failed to handle url params:', error);
139
+ }
140
+ }
141
+
142
+ async function handleParams(_$w,param,value) {
143
+ let applyFiltering=false;
144
+ const decodedValue = decodeURIComponent(value);
145
+ const field=getFieldByTitle(fieldTitlesInCMS[param],allfields);
146
+ const options=optionsByFieldId.get(field._id);
147
+ const option=getCorrectOption(decodedValue,options);
148
+ if(option) {
149
+ const optionIndex=getOptionIndexFromCheckBox(_$w(`#${FiltersIds[field.title]}CheckBox`).options,option.value);
150
+ _$w(`#${FiltersIds[field.title]}CheckBox`).selectedIndices = [optionIndex];
151
+ selectedByField.set(field._id, [option.value]);
152
+ applyFiltering=true;
153
+ dontUpdateThisCheckBox=field._id;
154
+ }
155
+ else {
156
+ console.warn(`${param} value not found in dropdown options`);
157
+ }
158
+ return applyFiltering;
159
+ }
160
+
161
+ function loadPaginationButtons(_$w) {
162
+ try {
163
+ _$w(CAREERS_MULTI_BOXES_PAGE_CONSTS.PAGE_BUTTON_NEXT).onClick(async () => {
164
+ let nextPageJobs=currentJobs.slice(pagination.pageSize*pagination.currentPage,pagination.pageSize*(pagination.currentPage+1));
165
+ _$w(CAREERS_MULTI_BOXES_PAGE_CONSTS.paginationCurrentText).text = (nextPageJobs.length+pagination.pageSize*pagination.currentPage).toString();
166
+ pagination.currentPage++;
167
+ _$w(CAREERS_MULTI_BOXES_PAGE_CONSTS.JOBS_REPEATER).data = nextPageJobs;
168
+ handlePaginationButtons(_$w);
169
+ });
170
+
171
+ _$w(CAREERS_MULTI_BOXES_PAGE_CONSTS.PAGE_BUTTON_PREVIOUS).onClick(async () => {
172
+ let previousPageJobs=currentJobs.slice(pagination.pageSize*(pagination.currentPage-2),pagination.pageSize*(pagination.currentPage-1));
173
+ pagination.currentPage--;
174
+ _$w(CAREERS_MULTI_BOXES_PAGE_CONSTS.paginationCurrentText).text = (pagination.pageSize*pagination.currentPage).toString();
175
+ _$w(CAREERS_MULTI_BOXES_PAGE_CONSTS.JOBS_REPEATER).data = previousPageJobs;
176
+ handlePaginationButtons(_$w);
177
+ });
178
+ } catch (error) {
179
+ console.error('Failed to load pagination buttons:', error);
180
+ }
181
+ }
182
+
183
+ function loadSelectedValuesRepeater(_$w) {
184
+ try {
185
+ _$w(CAREERS_MULTI_BOXES_PAGE_CONSTS.SELECTED_VALUES_REPEATER).onItemReady(($item, itemData) => {
186
+ $item(CAREERS_MULTI_BOXES_PAGE_CONSTS.SELECTED_VALUES_REPEATER_ITEM_LABEL).text = itemData.label || '';
187
+ // Deselect this value from both the selected map and the multibox
188
+ $item(CAREERS_MULTI_BOXES_PAGE_CONSTS.DESELECT_BUTTON_ID).onClick(async () => {
189
+
190
+ const fieldId = itemData.fieldId;
191
+ const valueId = itemData.valueId;
192
+ dontUpdateThisCheckBox=fieldId;
193
+ if (!fieldId || !valueId) return;
194
+
195
+ const existing = selectedByField.get(fieldId) || [];
196
+ const updated = existing.filter(v => v !== valueId);
197
+ if (updated.length) {
198
+ selectedByField.set(fieldId, updated);
199
+ } else {
200
+ selectedByField.delete(fieldId);
201
+ }
202
+
203
+ const field=getFieldById(fieldId,allfields);
204
+ const currentVals = _$w(`#${FiltersIds[field.title]}CheckBox`).value || [];
205
+ const nextVals = currentVals.filter(v => v !== valueId);
206
+ _$w(`#${FiltersIds[field.title]}CheckBox`).value = nextVals;
207
+ await updateJobsAndNumbersAndFilters(_$w);
208
+ });
209
+ });
210
+ updateSelectedValuesRepeater(_$w);
211
+ } catch (error) {
212
+ console.error('Failed to load selected values repeater:', error);
213
+ }
214
+ }
215
+
216
+ async function loadData() {
217
+ try {
218
+ if(alljobs.length===0) {
219
+ alljobs=await getAllRecords(COLLECTIONS.JOBS);
220
+ currentJobs=alljobs;
221
+ }
222
+ if(Object.keys(valueToJobs).length === 0){
223
+ allvaluesobjects=await getAllRecords(COLLECTIONS.CUSTOM_VALUES);
224
+ for (const value of allvaluesobjects) {
225
+ valueToJobs[value._id]= value.jobIds;
226
+ }
227
+ }
228
+ if(allfields.length===0) {
229
+ allfields=await getAllRecords(COLLECTIONS.CUSTOM_FIELDS);
230
+ allfields.push({_id:"Location",title:"Location"});
231
+ }
232
+ } catch (error) {
233
+ console.error('Failed to load data:', error);
234
+ }
235
+ }
236
+ async function loadJobsRepeater(_$w) {
237
+ try {
238
+ _$w(CAREERS_MULTI_BOXES_PAGE_CONSTS.JOBS_REPEATER).onItemReady(($item, itemData) => {
239
+ $item(CAREERS_MULTI_BOXES_PAGE_CONSTS.JOBS_REPEATER_ITEM_TITLE).text = itemData.title;
240
+ $item(CAREERS_MULTI_BOXES_PAGE_CONSTS.JOBS_REPEATER_ITEM_TITLE).onClick(() => {
241
+ location.to(itemData["link-jobs-title"]);
242
+ });
243
+ $item(CAREERS_MULTI_BOXES_PAGE_CONSTS.JOBS_REPEATER_ITEM_LOCATION).text=itemData.location.fullLocation
244
+ $item(CAREERS_MULTI_BOXES_PAGE_CONSTS.JOBS_REPEATER_ITEM_EMPLOYMENT_TYPE).text=itemData.employmentType
245
+
246
+ });
247
+
248
+ const jobsFirstPage=alljobs.slice(0,pagination.pageSize);
249
+ _$w(CAREERS_MULTI_BOXES_PAGE_CONSTS.JOBS_REPEATER).data = jobsFirstPage;
250
+ _$w(CAREERS_MULTI_BOXES_PAGE_CONSTS.paginationCurrentText).text = jobsFirstPage.length.toString();
251
+ _$w(CAREERS_MULTI_BOXES_PAGE_CONSTS.paginationTotalCountText).text = currentJobs.length.toString();
252
+ updateTotalJobsCountText(_$w);
253
+ handlePaginationButtons(_$w);
254
+ } catch (error) {
255
+ console.error('Failed to load jobs repeater:', error);
256
+ }
257
+ }
258
+
259
+ function updateTotalJobsCountText(_$w) {
260
+ secondarySearchIsFilled? _$w(CAREERS_MULTI_BOXES_PAGE_CONSTS.TotalJobsCountText).text = `${currentSecondarySearchJobs.length} Jobs`:
261
+ _$w(CAREERS_MULTI_BOXES_PAGE_CONSTS.TotalJobsCountText).text = `${currentJobs.length} Jobs`;
262
+ }
263
+
264
+ async function loadFilters(_$w) {
265
+ try {
266
+ // 1) Load all categories (fields)
267
+ const cities=await getAllRecords(COLLECTIONS.CITIES);
268
+ for(const city of cities) {
269
+ valueToJobs[city._id]=city.jobIds;
270
+ }
271
+ // 2) Load all values once and group them by referenced field
272
+ let valuesByFieldId = groupValuesByField(allvaluesobjects, CUSTOM_VALUES_COLLECTION_FIELDS.CUSTOM_FIELD);
273
+ valuesByFieldId.set("Location",cities)
274
+ // Build CheckboxGroup options for this field
275
+
276
+ const counter={}
277
+ for(const city of cities) {
278
+ counter[city.city]=city.count
279
+ }
280
+ for(const [key, value] of valuesByFieldId) {
281
+ const field=getFieldById(key,allfields);
282
+ let originalOptions=[];
283
+ if(key==="Location") {
284
+ originalOptions=value.map(city=>({
285
+ label: city.city,
286
+ value: city._id
287
+ }));
288
+ }
289
+ else{
290
+ originalOptions=value
291
+ }
292
+
293
+ optionsByFieldId.set(key, originalOptions);
294
+ for (const val of allvaluesobjects) {
295
+ counter[val.title]=val.count
296
+ }
297
+
298
+ countsByFieldId.set(key, new Map(originalOptions.map(o => [o.value, counter[o.label]])));
299
+ updateOptionsUI(_$w,field.title, field._id, ''); // no search query
300
+ _$w(`#${FiltersIds[field.title]}CheckBox`).selectedIndices = []; // start empty
301
+ _$w(`#${FiltersIds[field.title]}CheckBox`).onChange(async (ev) => {
302
+ console.log("i am here !!!!!")
303
+ console.log("field.title: ",field.title)
304
+ console.log("value: ",value)
305
+ dontUpdateThisCheckBox=field._id;
306
+ const selected = ev.target.value; // array of selected value IDs
307
+ console.log("ev: ",ev)
308
+ console.log("ev.target: ",ev.target)
309
+ if (selected && selected.length) {
310
+ selectedByField.set(field._id, selected);
311
+ } else {
312
+ selectedByField.delete(field._id);
313
+ }
314
+ await updateJobsAndNumbersAndFilters(_$w);
315
+
316
+ });
317
+ const runFilter = debounce(() => {
318
+ const query = (_$w(`#${FiltersIds[field.title]}input`).value || '').toLowerCase().trim();
319
+ updateOptionsUI(_$w, field.title, field._id, query);
320
+ }, 150);
321
+ _$w(`#${FiltersIds[field.title]}input`).onInput(runFilter);
322
+
323
+ }
324
+ await refreshFacetCounts(_$w);
325
+
326
+ } catch (err) {
327
+ console.error('Failed to load filters:', err);
328
+ }
329
+ }
330
+
331
+
332
+
333
+ async function updateJobsAndNumbersAndFilters(_$w,clearAll=false) {
334
+ await applyJobFilters(_$w); // re-query jobs
335
+ await refreshFacetCounts(_$w,clearAll); // recompute and update counts in all lists
336
+ await updateSelectedValuesRepeater(_$w);
337
+ updateTotalJobsCountText(_$w);
338
+ }
339
+
340
+ function updateOptionsUI(_$w,fieldTitle, fieldId, searchQuery,clearAll=false) {
341
+ let base = optionsByFieldId.get(fieldId) || [];
342
+ const countsMap = countsByFieldId.get(fieldId) || new Map();
343
+
344
+ if(dontUpdateThisCheckBox===fieldId && !clearAll)
345
+ {
346
+ dontUpdateThisCheckBox=null;
347
+ return;
348
+ }
349
+ let filteredbase=[]
350
+ for (const element of base)
351
+ {
352
+ if(countsMap.get(element.value))
353
+ {
354
+ filteredbase.push(element)
355
+ }
356
+ }
357
+ // Build display options with counts
358
+ const withCounts = filteredbase.map(o => {
359
+ const count = countsMap.get(o.value)
360
+ return {
361
+ label: `${o.label} (${count})`,
362
+ value: o.value
363
+ };
364
+ });
365
+ // Apply search
366
+ const filtered = searchQuery
367
+ ? withCounts.filter(o => (o.label || '').toLowerCase().includes(searchQuery))
368
+ : withCounts;
369
+
370
+ // Preserve currently selected values that are still visible
371
+ let prevSelected=[]
372
+ clearAll? prevSelected=[]:prevSelected= _$w(`#${FiltersIds[fieldTitle]}CheckBox`).value;
373
+ const visibleSet = new Set(filtered.map(o => o.value));
374
+ const preserved = prevSelected.filter(v => visibleSet.has(v));
375
+ if(filtered.length===0) {
376
+ _$w(`#${FiltersIds[fieldTitle]}MultiBox`).changeState(`${FiltersIds[fieldTitle]}NoResults`);
377
+ }
378
+ else{
379
+ _$w(`#${FiltersIds[fieldTitle]}MultiBox`).changeState(`${FiltersIds[fieldTitle]}Results`);
380
+ _$w(`#${FiltersIds[fieldTitle]}CheckBox`).options = filtered;
381
+ _$w(`#${FiltersIds[fieldTitle]}CheckBox`).value = preserved;
382
+ }
383
+ }
384
+
385
+ async function applyJobFilters(_$w) {
386
+ let tempFilteredJobs=[];
387
+ let finalFilteredJobs=[];
388
+ secondarySearchIsFilled? finalFilteredJobs=allsecondarySearchJobs:finalFilteredJobs=alljobs;
389
+ if(keywordAllJobs) {
390
+ finalFilteredJobs=keywordAllJobs
391
+ }
392
+ let addedJobsIds=new Set();
393
+ // AND across categories, OR within each category
394
+ for (const [key, values] of selectedByField.entries()) {
395
+ for(const job of finalFilteredJobs) {
396
+ if(key==="Location"){
397
+ //if it is location then we check if selecred values (which is an array) have job city text
398
+ if(values.includes(job[JOBS_COLLECTION_FIELDS.CITY_TEXT])) {
399
+ if(!addedJobsIds.has(job._id)) {
400
+ tempFilteredJobs.push(job);
401
+ addedJobsIds.add(job._id);
402
+ }
403
+ }
404
+ }
405
+ else{
406
+ //if it is not location then we check if selecred values (which is an array) have one of the job values (whcih is also an array)
407
+ if(job[JOBS_COLLECTION_FIELDS.MULTI_REF_JOBS_CUSTOM_VALUES].some(value=>values.includes(value._id))) {
408
+ if(!addedJobsIds.has(job._id)) {
409
+ tempFilteredJobs.push(job);
410
+ addedJobsIds.add(job._id);
411
+ }
412
+ }
413
+ }
414
+ }
415
+ addedJobsIds.clear();
416
+ finalFilteredJobs=tempFilteredJobs;
417
+ tempFilteredJobs=[];
418
+ }
419
+ secondarySearchIsFilled? currentSecondarySearchJobs=finalFilteredJobs:currentJobs=finalFilteredJobs;
420
+ let jobsFirstPage=[];
421
+ secondarySearchIsFilled? jobsFirstPage=currentSecondarySearchJobs.slice(0,pagination.pageSize):jobsFirstPage=currentJobs.slice(0,pagination.pageSize);
422
+ _$w(CAREERS_MULTI_BOXES_PAGE_CONSTS.JOBS_REPEATER).data = jobsFirstPage;
423
+ _$w(CAREERS_MULTI_BOXES_PAGE_CONSTS.paginationCurrentText).text = jobsFirstPage.length.toString();
424
+ _$w(CAREERS_MULTI_BOXES_PAGE_CONSTS.paginationTotalCountText).text = secondarySearchIsFilled? currentSecondarySearchJobs.length.toString():currentJobs.length.toString();
425
+ if(jobsFirstPage.length===0) {
426
+ await _$w(CAREERS_MULTI_BOXES_PAGE_CONSTS.JOBS_MULTI_STATE_BOX).changeState("noJobs");
427
+ }
428
+ else{
429
+ await _$w(CAREERS_MULTI_BOXES_PAGE_CONSTS.JOBS_MULTI_STATE_BOX).changeState("searchResult");
430
+ }
431
+ pagination.currentPage=1;
432
+ handlePaginationButtons(_$w);
433
+ }
434
+
435
+ function handlePaginationButtons(_$w)
436
+ {
437
+ handlePageUrlParam();
438
+
439
+ pagination.currentPage===1? _$w(CAREERS_MULTI_BOXES_PAGE_CONSTS.PAGE_BUTTON_PREVIOUS).disable():_$w(CAREERS_MULTI_BOXES_PAGE_CONSTS.PAGE_BUTTON_PREVIOUS).enable();
440
+ if(secondarySearchIsFilled) {
441
+ if(currentSecondarySearchJobs.length===0) {
442
+ _$w(CAREERS_MULTI_BOXES_PAGE_CONSTS.PAGE_BUTTON_NEXT).disable();
443
+ return;
444
+ }
445
+ pagination.currentPage>=Math.ceil(currentSecondarySearchJobs.length/pagination.pageSize)? _$w(CAREERS_MULTI_BOXES_PAGE_CONSTS.PAGE_BUTTON_NEXT).disable():_$w(CAREERS_MULTI_BOXES_PAGE_CONSTS.PAGE_BUTTON_NEXT).enable();
446
+ }
447
+ else {
448
+ if(currentJobs.length===0) {
449
+ _$w(CAREERS_MULTI_BOXES_PAGE_CONSTS.PAGE_BUTTON_NEXT).disable();
450
+ return;
451
+ }
452
+ pagination.currentPage>=Math.ceil(currentJobs.length/pagination.pageSize)? _$w(CAREERS_MULTI_BOXES_PAGE_CONSTS.PAGE_BUTTON_NEXT).disable():_$w(CAREERS_MULTI_BOXES_PAGE_CONSTS.PAGE_BUTTON_NEXT).enable();
453
+ }
454
+ }
455
+
456
+ function handlePageUrlParam() {
457
+ if(pagination.currentPage==1)
458
+ {
459
+ queryParams.remove(["page"]);
460
+ }
461
+ else{
462
+ queryParams.add({ page: pagination.currentPage });
463
+ }
464
+
465
+ }
466
+ async function refreshFacetCounts(_$w,clearAll=false) {
467
+
468
+ secondarySearchIsFilled? countJobsPerField(currentSecondarySearchJobs):countJobsPerField(currentJobs);
469
+ for(const field of allfields) {
470
+ const query = (_$w(`#${FiltersIds[field.title]}input`).value || '').toLowerCase().trim();
471
+ clearAll? updateOptionsUI(_$w,field.title, field._id, '',true):updateOptionsUI(_$w,field.title, field._id, query);
472
+ // no search query
473
+ }
474
+ }
475
+
476
+
477
+ function countJobsPerField(jobs) {
478
+ const fieldIds = Array.from(optionsByFieldId.keys());
479
+ const currentJobsIds=jobs.map(job=>job._id);
480
+
481
+ for (const fieldId of fieldIds) {
482
+ let currentoptions=optionsByFieldId.get(fieldId)
483
+ let counter=new Map();
484
+ for(const option of currentoptions) {
485
+ for (const jobId of currentJobsIds) {
486
+ if (valueToJobs[option.value].includes(jobId)) {
487
+ counter.set(option.value, (counter.get(option.value) || 0) + 1);
488
+ }
489
+ }
490
+ }
491
+ countsByFieldId.set(fieldId, counter);
492
+ }
493
+ }
494
+
495
+
496
+ function updateSelectedValuesRepeater(_$w) {
497
+ const selectedItems = [];
498
+ for (const [fieldId, valueIds] of selectedByField.entries()) {
499
+ const opts = optionsByFieldId.get(fieldId) || [];
500
+ for (const id of valueIds) {
501
+ const found = opts.find((option) => option.value === id);
502
+ const label = found.label;
503
+ selectedItems.push({ _id: `${fieldId}:${id}`, label, fieldId, valueId: id });
504
+ }
505
+ }
506
+ _$w(CAREERS_MULTI_BOXES_PAGE_CONSTS.SELECTED_VALUES_REPEATER).data = selectedItems;
507
+ }
508
+
509
+
510
+
511
+ async function secondarySearch(_$w,query) {
512
+ if(query.length===0 || query===undefined || query==='') {
513
+ secondarySearchIsFilled=false;
514
+ await updateJobsAndNumbersAndFilters(_$w); // we do this here because of the case when searching the list and adding filters from the side, and we delete the search query, so we need to refresh the counts and the jobs
515
+ return;
516
+ }
517
+ else {
518
+ allsecondarySearchJobs=currentJobs.filter(job=>job.title.toLowerCase().includes(query));
519
+ currentSecondarySearchJobs=allsecondarySearchJobs;
520
+ const jobsFirstPage=allsecondarySearchJobs.slice(0,pagination.pageSize);
521
+ _$w(CAREERS_MULTI_BOXES_PAGE_CONSTS.JOBS_REPEATER).data = jobsFirstPage;
522
+ _$w(CAREERS_MULTI_BOXES_PAGE_CONSTS.paginationCurrentText).text = jobsFirstPage.length.toString();
523
+ _$w(CAREERS_MULTI_BOXES_PAGE_CONSTS.paginationTotalCountText).text = allsecondarySearchJobs.length.toString();
524
+ pagination.currentPage=1;
525
+ if(jobsFirstPage.length===0) {
526
+ await _$w(CAREERS_MULTI_BOXES_PAGE_CONSTS.JOBS_MULTI_STATE_BOX).changeState("noJobs");
527
+ }
528
+ else{
529
+ await _$w(CAREERS_MULTI_BOXES_PAGE_CONSTS.JOBS_MULTI_STATE_BOX).changeState("searchResult");
530
+ }
531
+ secondarySearchIsFilled=true
532
+ }
533
+
534
+ handlePaginationButtons(_$w);
535
+ updateTotalJobsCountText(_$w);
536
+ await refreshFacetCounts(_$w);
537
+ return allsecondarySearchJobs;
538
+ }
539
+ function bindSearchInput(_$w) {
540
+ try {
541
+ bindPrimarySearch(_$w,allvaluesobjects,alljobs);
542
+
543
+ const secondarySearchDebounced = debounce(async () => {
544
+ const query = (_$w(CAREERS_MULTI_BOXES_PAGE_CONSTS.SECONDARY_SEARCH_INPUT).value || '').toLowerCase().trim();
545
+ await secondarySearch(_$w, query);
546
+ }, 150);
547
+
548
+
549
+ _$w(CAREERS_MULTI_BOXES_PAGE_CONSTS.SECONDARY_SEARCH_INPUT).onInput(secondarySearchDebounced);
550
+
551
+ } catch (error) {
552
+ console.error('Failed to bind search input:', error);
553
+ }
554
+ }
555
+
556
+
557
+ module.exports = {
558
+ careersMultiBoxesPageOnReady,
559
+ secondarySearch
560
+ };