@abcagency/hc-ui-components 1.3.57 → 1.3.59

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (158) hide show
  1. package/dist/apis/hcApi.js +85 -85
  2. package/dist/apis/hcApi.js.map +1 -1
  3. package/dist/clientToken.js.map +1 -1
  4. package/dist/components/containers/accordions/filter-container.js.map +1 -1
  5. package/dist/components/containers/accordions/filter-item-container.js +4 -2
  6. package/dist/components/containers/accordions/filter-item-container.js.map +1 -1
  7. package/dist/components/containers/accordions/map-accordion-item-container.js.map +1 -1
  8. package/dist/components/containers/filter/filter-item-container.js +4 -2
  9. package/dist/components/containers/filter/filter-item-container.js.map +1 -1
  10. package/dist/components/containers/jobListing/listing-details-container.js.map +1 -1
  11. package/dist/components/containers/list/item-list-container.js +21 -21
  12. package/dist/components/containers/list/list-item/list-item-container.js.map +1 -1
  13. package/dist/components/containers/maps/map-container.js.map +1 -1
  14. package/dist/components/modules/accordions/MapAccordionItem.js.map +1 -1
  15. package/dist/components/modules/accordions/default.js.map +1 -1
  16. package/dist/components/modules/buttons/commute-pill.js.map +1 -1
  17. package/dist/components/modules/buttons/default.js.map +1 -1
  18. package/dist/components/modules/buttons/items-pill.js.map +1 -1
  19. package/dist/components/modules/buttons/pill-wrapper.js.map +1 -1
  20. package/dist/components/modules/buttons/show-all-button.js.map +1 -1
  21. package/dist/components/modules/cards/default.js.map +1 -1
  22. package/dist/components/modules/cards/filter.js.map +1 -1
  23. package/dist/components/modules/filter/item.js.map +1 -1
  24. package/dist/components/modules/filter/sort.js.map +1 -1
  25. package/dist/components/modules/grid.js.map +1 -1
  26. package/dist/components/modules/icon.js.map +1 -1
  27. package/dist/components/modules/list/header.js.map +1 -1
  28. package/dist/components/modules/list/item-list.js +40 -40
  29. package/dist/components/modules/maps/info-window-card.js.map +1 -1
  30. package/dist/components/modules/maps/map.js.map +1 -1
  31. package/dist/components/modules/maps/place-marker.js.map +1 -1
  32. package/dist/components/modules/maps/tabs.js.map +1 -1
  33. package/dist/constants/placeTypes.js.map +1 -1
  34. package/dist/contexts/mapContext.js +83 -83
  35. package/dist/contexts/mapListContext.js +190 -190
  36. package/dist/contexts/trackEventContext.js.map +1 -1
  37. package/dist/hooks/useList.js.map +1 -1
  38. package/dist/services/configService.js +9 -9
  39. package/dist/services/googlePlacesNearbyService.js +32 -32
  40. package/dist/services/googlePlacesNearbyService.js.map +1 -1
  41. package/dist/services/listingAggregatorService.js +34 -34
  42. package/dist/services/listingAggregatorService.js.map +1 -1
  43. package/dist/services/listingEntityService.js +9 -9
  44. package/dist/services/listingService.js +24 -24
  45. package/dist/services/recruiterService.js +10 -10
  46. package/dist/types/apis/hcApi.d.ts +5 -5
  47. package/dist/types/clientToken.d.ts +2 -2
  48. package/dist/types/components/containers/accordions/map-accordion-item-container.d.ts +12 -12
  49. package/dist/types/components/containers/jobListing/listing-details-container.d.ts +6 -6
  50. package/dist/types/components/containers/list/item-list-container.d.ts +9 -9
  51. package/dist/types/components/containers/list/list-item/list-item-container.d.ts +14 -14
  52. package/dist/types/components/modules/accordions/MapAccordionItem.d.ts +10 -10
  53. package/dist/types/components/modules/accordions/default.d.ts +19 -19
  54. package/dist/types/components/modules/buttons/button-group-apply.d.ts +24 -24
  55. package/dist/types/components/modules/buttons/commute-pill.d.ts +5 -5
  56. package/dist/types/components/modules/buttons/default.d.ts +48 -48
  57. package/dist/types/components/modules/buttons/pill-wrapper.d.ts +3 -3
  58. package/dist/types/components/modules/dialogs/apply-dialog.d.ts +8 -8
  59. package/dist/types/components/modules/filter/sort.d.ts +8 -8
  60. package/dist/types/components/modules/grid.d.ts +8 -8
  61. package/dist/types/components/modules/icon.d.ts +10 -10
  62. package/dist/types/components/modules/jobListing/listing-details.d.ts +18 -18
  63. package/dist/types/components/modules/list/field-mapper.d.ts +10 -10
  64. package/dist/types/components/modules/list/header-item.d.ts +11 -11
  65. package/dist/types/components/modules/list/header.d.ts +12 -12
  66. package/dist/types/components/modules/list/item-expand-card/index.d.ts +7 -7
  67. package/dist/types/components/modules/list/item-expand-card/recruiter-contact-nav.d.ts +17 -17
  68. package/dist/types/components/modules/list/item-expand-card/recruiter-details.d.ts +21 -21
  69. package/dist/types/components/modules/list/item-expand-card/recruiter-headshot.d.ts +8 -8
  70. package/dist/types/components/modules/list/item-list.d.ts +20 -20
  71. package/dist/types/components/modules/list/list-item/list-item.d.ts +3 -3
  72. package/dist/types/constants/eventTypes.d.ts +14 -14
  73. package/dist/types/contexts/mapContext.d.ts +29 -29
  74. package/dist/types/contexts/mapListContext.d.ts +61 -61
  75. package/dist/types/contexts/trackEventContext.d.ts +6 -6
  76. package/dist/types/enums/SectionType.d.ts +9 -9
  77. package/dist/types/hooks/useList.d.ts +13 -13
  78. package/dist/types/services/configService.d.ts +6 -6
  79. package/dist/types/services/googlePlacesNearbyService.d.ts +5 -5
  80. package/dist/types/services/listingAggregatorService.d.ts +12 -12
  81. package/dist/types/services/listingEntityService.d.ts +6 -6
  82. package/dist/types/services/listingService.d.ts +9 -9
  83. package/dist/types/services/recruiterService.d.ts +6 -6
  84. package/dist/types/types/Address.d.ts +7 -7
  85. package/dist/types/types/ContentSection.d.ts +8 -8
  86. package/dist/types/types/GetListingParams.d.ts +8 -8
  87. package/dist/types/types/LatLng.d.ts +4 -4
  88. package/dist/types/types/ListingEntity.d.ts +10 -10
  89. package/dist/types/types/ListingFields.d.ts +25 -25
  90. package/dist/types/types/Listings.d.ts +31 -31
  91. package/dist/types/types/Recruiter.d.ts +9 -9
  92. package/dist/types/types/SimilarListing.d.ts +24 -24
  93. package/dist/types/types/config/Colors.d.ts +8 -8
  94. package/dist/types/types/config/MapConfig.d.ts +30 -30
  95. package/dist/types/types/config/PointsOfInterestConfig.d.ts +13 -13
  96. package/dist/types/types/config/SearchConfig.d.ts +4 -4
  97. package/dist/types/util/filterUtil.d.ts +28 -28
  98. package/dist/types/util/loading.d.ts +3 -3
  99. package/dist/types/util/localStorageUtil.d.ts +3 -3
  100. package/dist/types/util/mapUtil.d.ts +16 -16
  101. package/dist/types/util/sortUtil.d.ts +1 -1
  102. package/dist/types/util/stringUtils.d.ts +1 -1
  103. package/dist/types/util/urlFilterUtil.d.ts +8 -8
  104. package/dist/util/filterUtil.js +2 -2
  105. package/dist/util/filterUtil.js.map +1 -1
  106. package/dist/util/loading.js.map +1 -1
  107. package/dist/util/localStorageUtil.js +37 -37
  108. package/dist/util/localStorageUtil.js.map +1 -1
  109. package/dist/util/sortUtil.js.map +1 -1
  110. package/dist/util/stringUtils.js.map +1 -1
  111. package/dist/util/urlFilterUtil.js.map +1 -1
  112. package/package.json +1 -1
  113. package/src/apis/hcApi.ts +109 -109
  114. package/src/clientToken.js +9 -9
  115. package/src/components/containers/accordions/filter-container.js +48 -48
  116. package/src/components/containers/accordions/filter-item-container.js +2 -0
  117. package/src/components/containers/accordions/map-accordion-item-container.js +70 -70
  118. package/src/components/containers/filter/filter-item-container.js +2 -1
  119. package/src/components/containers/jobListing/listing-details-container.js +40 -40
  120. package/src/components/containers/list/list-item/list-item-container.js +43 -43
  121. package/src/components/containers/maps/map-container.js +249 -249
  122. package/src/components/modules/accordions/MapAccordionItem.js +30 -30
  123. package/src/components/modules/accordions/default.js +171 -171
  124. package/src/components/modules/buttons/commute-pill.js +22 -22
  125. package/src/components/modules/buttons/default.js +194 -194
  126. package/src/components/modules/buttons/items-pill.js +35 -35
  127. package/src/components/modules/buttons/pill-wrapper.js +27 -27
  128. package/src/components/modules/buttons/show-all-button.js +19 -19
  129. package/src/components/modules/cards/default.js +167 -167
  130. package/src/components/modules/cards/filter.js +56 -56
  131. package/src/components/modules/filter/item.js +69 -69
  132. package/src/components/modules/filter/sort.js +83 -83
  133. package/src/components/modules/grid.js +54 -54
  134. package/src/components/modules/icon.js +33 -33
  135. package/src/components/modules/list/header.js +51 -51
  136. package/src/components/modules/list/item-expand-card/recruiter-contact-nav.js +50 -50
  137. package/src/components/modules/list/item-expand-card/recruiter-details.js +68 -68
  138. package/src/components/modules/list/item-expand-card/recruiter-headshot.js +22 -22
  139. package/src/components/modules/maps/info-window-card.js +17 -17
  140. package/src/components/modules/maps/map.js +64 -64
  141. package/src/components/modules/maps/place-marker.js +41 -41
  142. package/src/components/modules/maps/tabs.js +81 -81
  143. package/src/constants/placeTypes.js +8 -8
  144. package/src/contexts/trackEventContext.js +14 -14
  145. package/src/enums/SectionType.ts +9 -9
  146. package/src/hooks/useList.js +89 -89
  147. package/src/index.js +3 -3
  148. package/src/services/googlePlacesNearbyService.ts +42 -42
  149. package/src/services/listingAggregatorService.ts +76 -76
  150. package/src/util/arrayUtil.js +3 -3
  151. package/src/util/fieldMapper.js +22 -22
  152. package/src/util/filterUtil.js +311 -310
  153. package/src/util/loading.js +17 -17
  154. package/src/util/localStorageUtil.ts +34 -34
  155. package/src/util/sortUtil.js +32 -32
  156. package/src/util/stringUtils.js +6 -6
  157. package/src/util/urlFilterUtil.js +85 -85
  158. package/dist/types/contexts/themeContext.d.ts +0 -11
@@ -1,310 +1,311 @@
1
- /* eslint-disable no-undef */
2
- import { getDistinctItemsByProximity } from '~/util/mapUtil';
3
-
4
- import Fuse from 'fuse.js';
5
-
6
- export const getFilterOptions = (listings, filteredListings, field, excludeZeroCount = null) => {
7
- const options = new Set();
8
- listings.forEach(listing => {
9
- if (listing.fields[field]) {
10
- options.add(listing.fields[field]);
11
- }
12
- });
13
-
14
- const optionCounts = {};
15
- options.forEach(option => {
16
- optionCounts[option] = 0;
17
- });
18
-
19
- filteredListings.forEach(listing => {
20
- const value = listing.fields[field];
21
- if (value && optionCounts.hasOwnProperty(value)) {
22
- optionCounts[value] += 1;
23
- }
24
- });
25
-
26
- return Array.from(options)
27
- .sort()
28
- .map(option => ({
29
- name: option,
30
- count: optionCounts[option] || 0
31
- }))
32
- .filter(option => !(excludeZeroCount === true && option.count === 0));
33
- };
34
-
35
- export const getSpecialFeatureOptions = (listings, filteredListings, siteConfig, favorites) => {
36
- const specialFeatures = siteConfig.specialFeatures;
37
- const featureCounts = Object.keys(specialFeatures).sort().reduce((acc, key) => {
38
- acc[specialFeatures[key]] = 0;
39
- return acc;
40
- }, {});
41
-
42
- filteredListings.forEach(listing => {
43
- Object.entries(specialFeatures).forEach(([featureKey, featureName]) => {
44
- if (listing.fields[featureKey] == 1) {
45
- featureCounts[featureName] += 1;
46
- }
47
- });
48
- });
49
-
50
- const specialFeatureOptions = Object.entries(featureCounts).map(([name, count]) => ({
51
- name,
52
- count
53
- }));
54
-
55
- for (let option of specialFeatureOptions) {
56
- if (option.name === 'Favorite') {
57
- option.count = filteredListings.filter(x => favorites.includes(x.id)).length;
58
- }
59
- }
60
-
61
- return specialFeatureOptions;
62
- };
63
-
64
- const getPointsOfInterestOptions = pointsOfInterestNames => {
65
- return Object.entries(pointsOfInterestNames).sort().map(([key, name]) => ({
66
- key,
67
- name
68
- }));
69
- };
70
-
71
- export const generateFilterOptions = (
72
- filteredListings,
73
- allListings,
74
- siteConfig,
75
- filterOptions,
76
- parentField,
77
- favorites,
78
- selectedFilters
79
- ) => {
80
- if (allListings.length > 0) {
81
- const dynamicFilters = siteConfig.fieldFiltersShown.map(fieldName => {
82
- if (fieldName === parentField && filterOptions?.filters) {
83
- return filterOptions.filters.find(filter => filter.id === fieldName);
84
- }
85
- if(fieldName == 'categoryClass'){
86
- return {
87
- id: fieldName,
88
- title: siteConfig.fieldNames[fieldName],
89
- items: getFilterOptions(allListings, allListings, fieldName)
90
- };
91
- }
92
- if(fieldName == 'category' && selectedFilters.categoryClass){
93
- const categoryClassKeys = Object.keys(selectedFilters.categoryClass);
94
- const filteredListings = allListings.filter(
95
- x => categoryClassKeys.includes(x.fields?.categoryClass)
96
- );
97
- return {
98
- id: fieldName,
99
- title: siteConfig.fieldNames[fieldName],
100
- items: getFilterOptions(allListings, filteredListings, fieldName, false)
101
- };
102
- }
103
- if (fieldName == "specialFeatures") {
104
- return {
105
- id: fieldName,
106
- title: siteConfig.fieldNames[fieldName],
107
- items: getSpecialFeatureOptions(allListings, filteredListings, siteConfig, favorites).sort()
108
- };
109
- }
110
- return {
111
- id: fieldName,
112
- title: siteConfig.fieldNames[fieldName],
113
- items: getFilterOptions(allListings, filteredListings, fieldName)
114
- };
115
- });
116
-
117
- const locations =
118
- siteConfig.locationFiltersShown.map((fieldName, index) => {
119
- let locationFilteredListings = allListings;
120
- locationFilteredListings = allListings.filter(listing => {
121
- return Object.entries(selectedFilters).every(([key, value]) => {
122
- if (siteConfig.locationFiltersShown.includes(key)) return true;
123
- if (value && typeof value === 'object' && value[listing.fields[key]] === true) {
124
- return true;
125
- }
126
- return false;
127
- });
128
- });
129
- if (index === 0) {
130
- return {
131
- id: fieldName,
132
- title: siteConfig.fieldNames[fieldName],
133
- items: getFilterOptions(allListings, locationFilteredListings, fieldName, true)
134
- };
135
- }
136
- if (fieldName === 'entityName' && filterOptions?.locations) {
137
- const cityIncluded = siteConfig.locationFiltersShown.includes('city');
138
- const stateIncluded = siteConfig.locationFiltersShown.includes('state');
139
- const cityStateIncluded = siteConfig.locationFiltersShown.includes('cityState');
140
- const uniqueCities = cityIncluded ? [...new Set(filteredListings.map(listing => listing.fields.city))] : [];
141
- const uniqueStates = stateIncluded ? [...new Set(filteredListings.map(listing => listing.fields.state))] : [];
142
- const uniqueCityStates = cityStateIncluded ? [...new Set(filteredListings.map(listing => listing.fields.cityState))] : [];
143
- const filteredByLocation = locationFilteredListings.filter(listing => {
144
- const cityMatches = cityIncluded ? uniqueCities.includes(listing.fields.city) : true;
145
- const stateMatches = stateIncluded ? uniqueStates.includes(listing.fields.state) : true;
146
- const cityStateMatches = cityStateIncluded ? uniqueCityStates.includes(listing.fields.cityState) : true;
147
- return cityMatches && stateMatches && cityStateMatches;
148
- });
149
- return {
150
- id: fieldName,
151
- title: siteConfig.fieldNames[fieldName],
152
- items: getFilterOptions(allListings, filteredByLocation, fieldName, true)
153
- };
154
- }
155
- if (fieldName === 'city') {
156
- if (siteConfig.locationFiltersShown.includes('state') && selectedFilters.state) {
157
- const selectedStates = Object.keys(selectedFilters.state).filter(
158
- state => selectedFilters.state[state] === true
159
- );
160
-
161
- const filteredByLocation = locationFilteredListings.filter(listing =>
162
- selectedStates.includes(listing.fields.state)
163
- );
164
-
165
- return {
166
- id: fieldName,
167
- title: siteConfig.fieldNames[fieldName],
168
- items: getFilterOptions(allListings, filteredByLocation, fieldName, true)
169
- };
170
- }
171
- }
172
-
173
- return {
174
- id: fieldName,
175
- title: siteConfig.fieldNames[fieldName],
176
- items: getFilterOptions(allListings, filteredListings, fieldName, true)
177
- };
178
- });
179
-
180
- const pointsOfInterest = {
181
- id: "pointsOfInterest",
182
- title: siteConfig.pointsOfInterestConfig.title,
183
- items: getPointsOfInterestOptions(
184
- siteConfig.pointsOfInterestConfig.pointsOfInterestNames
185
- )
186
- };
187
-
188
- return {
189
- filters: dynamicFilters,
190
- locations: locations,
191
- pointsOfInterest: pointsOfInterest
192
- };
193
- }
194
-
195
- return null;
196
- };
197
-
198
- export const applyFilters = (
199
- allListings,
200
- selectedFilters,
201
- query,
202
- listingEntities,
203
- favorites,
204
- siteConfig
205
- ) => {
206
- let results = allListings;
207
- let invertedSpecialFeaturesMap;
208
- if (siteConfig.specialFeatures) {
209
- invertedSpecialFeaturesMap = Object.entries(siteConfig.specialFeatures).reduce((acc, [key, value]) => {
210
- acc[value] = key;
211
- return acc;
212
- }, {});
213
-
214
- }
215
- const hasFavorite = !!selectedFilters.specialFeatures && !!selectedFilters.specialFeatures.Favorite;
216
-
217
- if (hasFavorite && selectedFilters.specialFeatures.Favorite == true) {
218
- results = results.filter(x => favorites.includes(x.id));
219
- }
220
- var favorite;
221
- if (hasFavorite) {
222
- favorite = selectedFilters.specialFeatures.Favorite;
223
- delete selectedFilters.specialFeatures.Favorite;
224
- }
225
- for (const [field, filterItems] of Object.entries(selectedFilters)) {
226
- const formattedField = field;
227
- if (field === "pointsOfInterest") continue;
228
- if (field === "specialFeatures" && invertedSpecialFeaturesMap && Object.keys(filterItems).length > 0) {
229
- results = results.filter(listing => {
230
- return Object.entries(filterItems).some(([filterName, filterValue]) => {
231
- const listingFieldName = invertedSpecialFeaturesMap[filterName];
232
- return filterValue && listing.fields[listingFieldName] == 1;
233
- });
234
- });
235
- } else if (Object.keys(filterItems).length > 0) {
236
- results = results.filter(listing =>
237
- filterItems.hasOwnProperty(listing.fields[formattedField])
238
- );
239
- }
240
- }
241
- if (query) {
242
- results = searchResults(results, query);
243
- }
244
- const distinctItems = getDistinctItemsByProximity(results, listingEntities);
245
- if (hasFavorite) {
246
- selectedFilters.specialFeatures.Favorite = favorite;
247
- }
248
- return { filteredListings: results, mapItems: distinctItems };
249
- };
250
-
251
- function searchResults(results, query) {
252
- const fields = [
253
- 'id',
254
- 'fields.posted',
255
- 'fields.subtitle',
256
- 'fields.education',
257
- 'fields.position',
258
- 'fields.category',
259
- 'fields.categoryclass',
260
- 'fields.shift',
261
- 'fields.citystate',
262
- 'fields.city',
263
- 'fields.state',
264
- 'fields.schedule',
265
- 'fields.customflag1',
266
- 'fields.bonus',
267
- 'fields.remote',
268
- 'fields.useclientjoburl',
269
- 'fields.datecreated',
270
- 'fields.datelastedited'
271
- ];
272
-
273
- const options = {
274
- includeScore: true,
275
- threshold: 0.3,
276
- keys: fields
277
- };
278
-
279
- const fuse = new Fuse(results, options);
280
- const lowerCaseQuery = query.toLowerCase();
281
- const queryTerms = lowerCaseQuery.split(' ');
282
-
283
- const exactIdMatch = results.find(result => result.id.toString() === query);
284
- if (exactIdMatch) {
285
- return [exactIdMatch];
286
- }
287
-
288
- const fuseQuery = queryTerms.map(term => ({
289
- $or: fields.map(field => ({ [field]: term }))
290
- }));
291
-
292
- const fuseResults = fuse.search({ $and: fuseQuery });
293
-
294
- return fuseResults.map(result => result.item);
295
- }
296
-
297
- export const filterListingsByLocation = (
298
- allListings,
299
- selectedLocation,
300
- listingEntities
301
- ) => {
302
- let results = allListings;
303
- if (selectedLocation !== null) {
304
- results = results.filter(item =>
305
- selectedLocation.items.hasOwnProperty(item.id)
306
- );
307
- }
308
- const mapItems = getDistinctItemsByProximity(results, listingEntities);
309
- return { filteredListings: results, mapItems: mapItems };
310
- };
1
+ /* eslint-disable no-undef */
2
+ import { getDistinctItemsByProximity } from '~/util/mapUtil';
3
+
4
+ import Fuse from 'fuse.js';
5
+
6
+ export const getFilterOptions = (listings, filteredListings, field, excludeZeroCount = null) => {
7
+ const options = new Set();
8
+ listings.forEach(listing => {
9
+ if (listing.fields[field]) {
10
+ options.add(listing.fields[field]);
11
+ }
12
+ });
13
+
14
+ const optionCounts = {};
15
+ options.forEach(option => {
16
+ optionCounts[option] = 0;
17
+ });
18
+
19
+ filteredListings.forEach(listing => {
20
+ const value = listing.fields[field];
21
+ if (value && optionCounts.hasOwnProperty(value)) {
22
+ optionCounts[value] += 1;
23
+ }
24
+ });
25
+
26
+ return Array.from(options)
27
+ .sort()
28
+ .map(option => ({
29
+ name: option,
30
+ count: optionCounts[option] || 0
31
+ }))
32
+ .filter(option => !(excludeZeroCount === true && option.count === 0));
33
+ };
34
+
35
+ export const getSpecialFeatureOptions = (listings, filteredListings, siteConfig, favorites) => {
36
+ const specialFeatures = siteConfig.specialFeatures;
37
+ const featureCounts = Object.keys(specialFeatures).sort().reduce((acc, key) => {
38
+ acc[specialFeatures[key]] = 0;
39
+ return acc;
40
+ }, {});
41
+
42
+ filteredListings.forEach(listing => {
43
+ Object.entries(specialFeatures).forEach(([featureKey, featureName]) => {
44
+ if (listing.fields[featureKey] == 1) {
45
+ featureCounts[featureName] += 1;
46
+ }
47
+ });
48
+ });
49
+
50
+ const specialFeatureOptions = Object.entries(featureCounts).map(([name, count]) => ({
51
+ name,
52
+ count
53
+ }));
54
+
55
+ for (let option of specialFeatureOptions) {
56
+ if (option.name === 'Favorite') {
57
+ option.count = filteredListings.filter(x => favorites.includes(x.id)).length;
58
+ }
59
+ }
60
+
61
+ return specialFeatureOptions;
62
+ };
63
+
64
+ const getPointsOfInterestOptions = pointsOfInterestNames => {
65
+ return Object.entries(pointsOfInterestNames).sort().map(([key, name]) => ({
66
+ key,
67
+ name
68
+ }));
69
+ };
70
+
71
+ export const generateFilterOptions = (
72
+ filteredListings,
73
+ allListings,
74
+ siteConfig,
75
+ filterOptions,
76
+ parentField,
77
+ favorites,
78
+ selectedFilters
79
+ ) => {
80
+ if (allListings.length > 0) {
81
+ const dynamicFilters = siteConfig.fieldFiltersShown.map(fieldName => {
82
+ if (fieldName === parentField && filterOptions?.filters) {
83
+ return filterOptions.filters.find(filter => filter.id === fieldName);
84
+ }
85
+ if(fieldName == 'categoryClass'){
86
+ return {
87
+ id: fieldName,
88
+ title: siteConfig.fieldNames[fieldName],
89
+ items: getFilterOptions(allListings, allListings, fieldName)
90
+ };
91
+ }
92
+ if(fieldName == 'category' && selectedFilters.categoryClass){
93
+ const categoryClassKeys = Object.keys(selectedFilters.categoryClass);
94
+ const filteredListings = allListings.filter(
95
+ x => categoryClassKeys.includes(x.fields?.categoryClass)
96
+ );
97
+ return {
98
+ id: fieldName,
99
+ title: siteConfig.fieldNames[fieldName],
100
+ items: getFilterOptions(allListings, filteredListings, fieldName, false)
101
+ };
102
+ }
103
+ if (fieldName == "specialFeatures") {
104
+ return {
105
+ id: fieldName,
106
+ title: siteConfig.fieldNames[fieldName],
107
+ items: getSpecialFeatureOptions(allListings, filteredListings, siteConfig, favorites).sort()
108
+ };
109
+ }
110
+ return {
111
+ id: fieldName,
112
+ title: siteConfig.fieldNames[fieldName],
113
+ items: getFilterOptions(allListings, filteredListings, fieldName)
114
+ };
115
+ });
116
+
117
+ const locations =
118
+ siteConfig.locationFiltersShown.map((fieldName, index) => {
119
+ let locationFilteredListings = allListings;
120
+ locationFilteredListings = allListings.filter(listing => {
121
+ return Object.entries(selectedFilters).every(([key, value]) => {
122
+ if (siteConfig.locationFiltersShown.includes(key)) return true;
123
+ if (value && typeof value === 'object' && value[listing.fields[key]] === true) {
124
+ return true;
125
+ }
126
+ return false;
127
+ });
128
+ });
129
+ if (index === 0) {
130
+ return {
131
+ id: fieldName,
132
+ title: siteConfig.fieldNames[fieldName],
133
+ items: getFilterOptions(allListings, locationFilteredListings, fieldName, true)
134
+ };
135
+ }
136
+ if (fieldName === 'entityName' && filterOptions?.locations) {
137
+ const cityIncluded = siteConfig.locationFiltersShown.includes('city');
138
+ const stateIncluded = siteConfig.locationFiltersShown.includes('state');
139
+ const cityStateIncluded = siteConfig.locationFiltersShown.includes('cityState');
140
+ const uniqueCities = cityIncluded ? [...new Set(filteredListings.map(listing => listing.fields.city))] : [];
141
+ const uniqueStates = stateIncluded ? [...new Set(filteredListings.map(listing => listing.fields.state))] : [];
142
+ const uniqueCityStates = cityStateIncluded ? [...new Set(filteredListings.map(listing => listing.fields.cityState))] : [];
143
+ const filteredByLocation = locationFilteredListings.filter(listing => {
144
+ const cityMatches = cityIncluded ? uniqueCities.includes(listing.fields.city) : true;
145
+ const stateMatches = stateIncluded ? uniqueStates.includes(listing.fields.state) : true;
146
+ const cityStateMatches = cityStateIncluded ? uniqueCityStates.includes(listing.fields.cityState) : true;
147
+ return cityMatches && stateMatches && cityStateMatches;
148
+ });
149
+ return {
150
+ id: fieldName,
151
+ title: siteConfig.fieldNames[fieldName],
152
+ items: getFilterOptions(allListings, filteredByLocation, fieldName, true)
153
+ };
154
+ }
155
+ if (fieldName === 'city') {
156
+ if (siteConfig.locationFiltersShown.includes('state') && selectedFilters.state) {
157
+ const selectedStates = Object.keys(selectedFilters.state).filter(
158
+ state => selectedFilters.state[state] === true
159
+ );
160
+
161
+ const filteredByLocation = locationFilteredListings.filter(listing =>
162
+ selectedStates.includes(listing.fields.state)
163
+ );
164
+
165
+ return {
166
+ id: fieldName,
167
+ title: siteConfig.fieldNames[fieldName],
168
+ items: getFilterOptions(allListings, filteredByLocation, fieldName, true)
169
+ };
170
+ }
171
+ }
172
+
173
+ return {
174
+ id: fieldName,
175
+ title: siteConfig.fieldNames[fieldName],
176
+ items: getFilterOptions(allListings, filteredListings, fieldName, true)
177
+ };
178
+ });
179
+
180
+ const pointsOfInterest = {
181
+ id: "pointsOfInterest",
182
+ title: siteConfig.pointsOfInterestConfig.title,
183
+ items: getPointsOfInterestOptions(
184
+ siteConfig.pointsOfInterestConfig.pointsOfInterestNames
185
+ )
186
+ };
187
+
188
+ return {
189
+ filters: dynamicFilters,
190
+ locations: locations,
191
+ pointsOfInterest: pointsOfInterest
192
+ };
193
+ }
194
+
195
+ return null;
196
+ };
197
+
198
+ export const applyFilters = (
199
+ allListings,
200
+ selectedFilters,
201
+ query,
202
+ listingEntities,
203
+ favorites,
204
+ siteConfig
205
+ ) => {
206
+ let results = allListings;
207
+ let invertedSpecialFeaturesMap;
208
+ if (siteConfig.specialFeatures) {
209
+ invertedSpecialFeaturesMap = Object.entries(siteConfig.specialFeatures).reduce((acc, [key, value]) => {
210
+ acc[value] = key;
211
+ return acc;
212
+ }, {});
213
+
214
+ }
215
+ const hasFavorite = !!selectedFilters.specialFeatures && !!selectedFilters.specialFeatures.Favorite;
216
+
217
+ if (hasFavorite && selectedFilters.specialFeatures.Favorite == true) {
218
+ results = results.filter(x => favorites.includes(x.id));
219
+ }
220
+ var favorite;
221
+ if (hasFavorite) {
222
+ favorite = selectedFilters.specialFeatures.Favorite;
223
+ delete selectedFilters.specialFeatures.Favorite;
224
+ }
225
+ for (const [field, filterItems] of Object.entries(selectedFilters)) {
226
+ const formattedField = field;
227
+ if (field === "pointsOfInterest") continue;
228
+ if (field === "specialFeatures" && invertedSpecialFeaturesMap && Object.keys(filterItems).length > 0) {
229
+ results = results.filter(listing => {
230
+ return Object.entries(filterItems).some(([filterName, filterValue]) => {
231
+ const listingFieldName = invertedSpecialFeaturesMap[filterName];
232
+ return filterValue && listing.fields[listingFieldName] == 1;
233
+ });
234
+ });
235
+ } else if (Object.keys(filterItems).length > 0) {
236
+ results = results.filter(listing =>
237
+ filterItems.hasOwnProperty(listing.fields[formattedField])
238
+ );
239
+ }
240
+ }
241
+ if (query) {
242
+ results = searchResults(results, query);
243
+ }
244
+ const distinctItems = getDistinctItemsByProximity(results, listingEntities);
245
+ if (hasFavorite) {
246
+ selectedFilters.specialFeatures.Favorite = favorite;
247
+ }
248
+ return { filteredListings: results, mapItems: distinctItems };
249
+ };
250
+
251
+ function searchResults(results, query) {
252
+ const fields = [
253
+ 'id',
254
+ 'uniqueId',
255
+ 'fields.posted',
256
+ 'fields.subtitle',
257
+ 'fields.education',
258
+ 'fields.position',
259
+ 'fields.category',
260
+ 'fields.categoryclass',
261
+ 'fields.shift',
262
+ 'fields.citystate',
263
+ 'fields.city',
264
+ 'fields.state',
265
+ 'fields.schedule',
266
+ 'fields.customflag1',
267
+ 'fields.bonus',
268
+ 'fields.remote',
269
+ 'fields.useclientjoburl',
270
+ 'fields.datecreated',
271
+ 'fields.datelastedited'
272
+ ];
273
+
274
+ const options = {
275
+ includeScore: true,
276
+ threshold: 0.3,
277
+ keys: fields
278
+ };
279
+
280
+ const fuse = new Fuse(results, options);
281
+ const lowerCaseQuery = query.toLowerCase();
282
+ const queryTerms = lowerCaseQuery.split(' ');
283
+
284
+ const exactIdMatch = results.find(result => result.id.toString() === query || result.uniqueId === query);
285
+ if (exactIdMatch) {
286
+ return [exactIdMatch];
287
+ }
288
+
289
+ const fuseQuery = queryTerms.map(term => ({
290
+ $or: fields.map(field => ({ [field]: term }))
291
+ }));
292
+
293
+ const fuseResults = fuse.search({ $and: fuseQuery });
294
+
295
+ return fuseResults.map(result => result.item);
296
+ }
297
+
298
+ export const filterListingsByLocation = (
299
+ allListings,
300
+ selectedLocation,
301
+ listingEntities
302
+ ) => {
303
+ let results = allListings;
304
+ if (selectedLocation !== null) {
305
+ results = results.filter(item =>
306
+ selectedLocation.items.hasOwnProperty(item.id)
307
+ );
308
+ }
309
+ const mapItems = getDistinctItemsByProximity(results, listingEntities);
310
+ return { filteredListings: results, mapItems: mapItems };
311
+ };
@@ -1,17 +1,17 @@
1
- import React from 'react';
2
- import Icon from '~/components/modules/icon';
3
-
4
- const Loading = () => {
5
- return (
6
- <div className="hc-flex hc-items-center hc-justify-center hc-w-full hc-h-full">
7
- <Icon
8
- icon="ph:spinner"
9
- className="hc-animate-spin hc-text-gray-300"
10
- width="40"
11
- height="40"
12
- />
13
- </div>
14
- );
15
- };
16
-
17
- export default Loading;
1
+ import React from 'react';
2
+ import Icon from '~/components/modules/icon';
3
+
4
+ const Loading = () => {
5
+ return (
6
+ <div className="hc-flex hc-items-center hc-justify-center hc-w-full hc-h-full">
7
+ <Icon
8
+ icon="ph:spinner"
9
+ className="hc-animate-spin hc-text-gray-300"
10
+ width="40"
11
+ height="40"
12
+ />
13
+ </div>
14
+ );
15
+ };
16
+
17
+ export default Loading;