sr-npm 3.0.0 → 3.0.2

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