sr-npm 1.0.21 → 1.2.0

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