sr-npm 2.0.18 → 2.0.20

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