@abcagency/hc-ui-components 1.3.18 → 1.3.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (191) hide show
  1. package/dist/_virtual/_rollupPluginBabelHelpers.js +1 -1
  2. package/dist/apis/hcApi.js +85 -183
  3. package/dist/apis/hcApi.js.map +1 -1
  4. package/dist/components/HireControlMap.js +10 -5
  5. package/dist/components/HireControlMap.js.map +1 -1
  6. package/dist/components/modules/accordions/MapAccordionItem.js +10 -67
  7. package/dist/components/modules/accordions/MapAccordionItem.js.map +1 -1
  8. package/dist/components/modules/filter/index.js.map +1 -1
  9. package/dist/components/modules/filter/radio-item.js +1 -2
  10. package/dist/components/modules/filter/radio-item.js.map +1 -1
  11. package/dist/components/modules/jobListing/listing-details-container.js +45 -0
  12. package/dist/components/modules/jobListing/listing-details-container.js.map +1 -0
  13. package/dist/components/modules/jobListing/listing-details.js +24 -24
  14. package/dist/components/modules/jobListing/listing-details.js.map +1 -1
  15. package/dist/components/modules/{maps/list → list}/field-mapper.js +8 -7
  16. package/dist/components/modules/list/field-mapper.js.map +1 -0
  17. package/dist/components/modules/{maps/list → list}/header-item.js +2 -2
  18. package/dist/components/modules/list/header-item.js.map +1 -0
  19. package/dist/components/modules/{maps/list → list}/header.js +6 -4
  20. package/dist/components/modules/list/header.js.map +1 -0
  21. package/dist/components/modules/list/index.js +36 -0
  22. package/dist/components/modules/list/index.js.map +1 -0
  23. package/dist/components/modules/{maps/list → list}/item-expand-card/index.js +3 -1
  24. package/dist/components/modules/list/item-expand-card/index.js.map +1 -0
  25. package/dist/components/modules/{maps/list → list}/item-expand-card/recruiter-contact-nav.js +2 -2
  26. package/dist/components/modules/list/item-expand-card/recruiter-contact-nav.js.map +1 -0
  27. package/dist/components/modules/{maps/list → list}/item-expand-card/recruiter-details.js +1 -1
  28. package/dist/components/modules/list/item-expand-card/recruiter-details.js.map +1 -0
  29. package/dist/components/modules/list/item-expand-card/recruiter-headshot.js.map +1 -0
  30. package/dist/components/modules/list/item-list.js +28 -0
  31. package/dist/components/modules/list/item-list.js.map +1 -0
  32. package/dist/components/modules/list/list-item/index.js +75 -0
  33. package/dist/components/modules/list/list-item/index.js.map +1 -0
  34. package/dist/components/modules/list/list-item/list-item-container.js +47 -0
  35. package/dist/components/modules/list/list-item/list-item-container.js.map +1 -0
  36. package/dist/components/modules/{maps/list/list-item/index.js → list/list-item/list-item.js} +29 -33
  37. package/dist/components/modules/list/list-item/list-item.js.map +1 -0
  38. package/dist/components/modules/maps/map-list.js +3 -3
  39. package/dist/components/modules/maps/map-list.js.map +1 -1
  40. package/dist/contexts/mapContext.js +84 -113
  41. package/dist/contexts/mapContext.js.map +1 -1
  42. package/dist/contexts/mapListContext.js +181 -293
  43. package/dist/contexts/mapListContext.js.map +1 -1
  44. package/dist/contexts/trackEventContext.js +1 -1
  45. package/dist/services/configService.js +10 -28
  46. package/dist/services/configService.js.map +1 -1
  47. package/dist/services/googlePlacesNearbyService.js +33 -58
  48. package/dist/services/googlePlacesNearbyService.js.map +1 -1
  49. package/dist/services/listingAggregatorService.js +35 -75
  50. package/dist/services/listingAggregatorService.js.map +1 -1
  51. package/dist/services/listingEntityService.js +10 -31
  52. package/dist/services/listingEntityService.js.map +1 -1
  53. package/dist/services/listingService.js +26 -60
  54. package/dist/services/listingService.js.map +1 -1
  55. package/dist/services/recruiterService.js +11 -31
  56. package/dist/services/recruiterService.js.map +1 -1
  57. package/dist/types/apis/hcApi.d.ts +5 -0
  58. package/dist/types/clientToken.d.ts +2 -0
  59. package/dist/types/components/modules/accordions/MapAccordionItem.d.ts +9 -0
  60. package/dist/types/components/modules/accordions/default.d.ts +19 -0
  61. package/dist/types/components/modules/buttons/button-group-apply.d.ts +24 -0
  62. package/dist/types/components/modules/buttons/commute-pill.d.ts +5 -0
  63. package/dist/types/components/modules/buttons/default.d.ts +48 -0
  64. package/dist/types/components/modules/buttons/pill-wrapper.d.ts +3 -0
  65. package/dist/types/components/modules/dialogs/apply-dialog.d.ts +8 -0
  66. package/dist/types/components/modules/filter/sort.d.ts +8 -0
  67. package/dist/types/components/modules/grid.d.ts +8 -0
  68. package/dist/types/components/modules/icon.d.ts +10 -0
  69. package/dist/types/components/modules/jobListing/listing-details-container.d.ts +6 -0
  70. package/dist/types/components/modules/jobListing/listing-details.d.ts +18 -0
  71. package/dist/types/components/modules/list/field-mapper.d.ts +10 -0
  72. package/dist/types/components/modules/list/header-item.d.ts +11 -0
  73. package/dist/types/components/modules/list/header.d.ts +11 -0
  74. package/dist/types/components/modules/list/index.d.ts +9 -0
  75. package/dist/types/components/modules/list/item-expand-card/index.d.ts +7 -0
  76. package/dist/types/components/modules/list/item-expand-card/recruiter-contact-nav.d.ts +17 -0
  77. package/dist/types/components/modules/list/item-expand-card/recruiter-details.d.ts +21 -0
  78. package/dist/types/components/modules/list/item-expand-card/recruiter-headshot.d.ts +8 -0
  79. package/dist/types/components/modules/list/item-list.d.ts +21 -0
  80. package/dist/types/components/modules/list/list-item/index.d.ts +12 -0
  81. package/dist/types/components/modules/list/list-item/list-item-container.d.ts +14 -0
  82. package/dist/types/components/modules/list/list-item/list-item.d.ts +3 -0
  83. package/dist/types/constants/eventTypes.d.ts +13 -0
  84. package/dist/types/contexts/mapContext.d.ts +29 -0
  85. package/dist/types/contexts/mapListContext.d.ts +58 -0
  86. package/dist/types/contexts/trackEventContext.d.ts +6 -0
  87. package/dist/types/enums/SectionType.d.ts +9 -0
  88. package/dist/types/hooks/useList.d.ts +13 -0
  89. package/dist/types/services/configService.d.ts +6 -0
  90. package/dist/types/services/googlePlacesNearbyService.d.ts +5 -0
  91. package/dist/types/services/listingAggregatorService.d.ts +12 -0
  92. package/dist/types/services/listingEntityService.d.ts +6 -0
  93. package/dist/types/services/listingService.d.ts +9 -0
  94. package/dist/types/services/recruiterService.d.ts +6 -0
  95. package/dist/types/types/Address.d.ts +7 -0
  96. package/dist/types/types/ContentSection.d.ts +8 -0
  97. package/dist/types/types/GetListingParams.d.ts +8 -0
  98. package/dist/types/types/LatLng.d.ts +4 -0
  99. package/dist/types/types/ListingEntity.d.ts +10 -0
  100. package/dist/types/types/ListingFields.d.ts +20 -0
  101. package/dist/types/types/Listings.d.ts +31 -0
  102. package/dist/types/types/Recruiter.d.ts +9 -0
  103. package/dist/types/types/SimilarListing.d.ts +24 -0
  104. package/dist/types/types/config/Colors.d.ts +8 -0
  105. package/dist/types/types/config/MapConfig.d.ts +29 -0
  106. package/dist/types/types/config/PointsOfInterestConfig.d.ts +13 -0
  107. package/dist/types/types/config/SearchConfig.d.ts +4 -0
  108. package/dist/types/util/filterUtil.d.ts +28 -0
  109. package/dist/types/util/loading.d.ts +3 -0
  110. package/dist/types/util/localStorageUtil.d.ts +3 -0
  111. package/dist/types/util/mapUtil.d.ts +15 -0
  112. package/dist/types/util/sortUtil.d.ts +1 -0
  113. package/dist/types/util/stringUtils.d.ts +1 -0
  114. package/dist/util/filterUtil.js +1 -3
  115. package/dist/util/filterUtil.js.map +1 -1
  116. package/dist/util/localStorageUtil.js +37 -28
  117. package/dist/util/localStorageUtil.js.map +1 -1
  118. package/dist/util/mapUtil.js.map +1 -1
  119. package/package.json +23 -17
  120. package/rollup.config.mjs +23 -19
  121. package/src/apis/{hcApi.js → hcApi.ts} +27 -11
  122. package/src/components/HireControlMap.js +132 -129
  123. package/src/components/modules/accordions/MapAccordionItem.js +32 -74
  124. package/src/components/modules/filter/index.js +89 -89
  125. package/src/components/modules/filter/radio-item.js +0 -1
  126. package/src/components/modules/jobListing/listing-details-container.js +40 -0
  127. package/src/components/modules/jobListing/listing-details.js +209 -99
  128. package/src/components/modules/{maps/list → list}/field-mapper.js +114 -112
  129. package/src/components/modules/{maps/list → list}/header.js +49 -47
  130. package/src/components/modules/list/index.tsx +83 -0
  131. package/src/components/modules/{maps/list → list}/item-expand-card/index.js +24 -22
  132. package/src/components/modules/list/item-list.tsx +198 -0
  133. package/src/components/modules/list/list-item/index.js +70 -0
  134. package/src/components/modules/list/list-item/list-item-container.js +43 -0
  135. package/src/components/modules/{maps/list/list-item/index.js → list/list-item/list-item.js} +32 -38
  136. package/src/components/modules/maps/map-list.js +74 -74
  137. package/src/contexts/mapContext.tsx +129 -0
  138. package/src/contexts/mapListContext.tsx +297 -0
  139. package/src/enums/SectionType.ts +9 -0
  140. package/src/services/{configService.js → configService.ts} +16 -16
  141. package/src/services/{googlePlacesNearbyService.js → googlePlacesNearbyService.ts} +11 -2
  142. package/src/services/listingAggregatorService.ts +76 -0
  143. package/src/services/listingEntityService.ts +16 -0
  144. package/src/services/listingService.ts +40 -0
  145. package/src/services/{recruiterService.js → recruiterService.ts} +18 -17
  146. package/src/types/Address.ts +7 -0
  147. package/src/types/ContentSection.ts +9 -0
  148. package/src/types/GetListingParams.ts +8 -0
  149. package/src/types/LatLng.ts +4 -0
  150. package/src/types/ListingEntity.ts +11 -0
  151. package/src/types/ListingFields.ts +20 -0
  152. package/src/types/Listings.ts +32 -0
  153. package/src/types/Recruiter.ts +9 -0
  154. package/src/types/SimilarListing.ts +24 -0
  155. package/src/types/config/Colors.ts +8 -0
  156. package/src/types/config/MapConfig.ts +30 -0
  157. package/src/types/config/PointsOfInterestConfig.ts +13 -0
  158. package/src/types/config/SearchConfig.ts +4 -0
  159. package/src/util/filterUtil.js +239 -239
  160. package/src/util/localStorageUtil.ts +34 -0
  161. package/src/util/mapUtil.js +91 -91
  162. package/tsconfig.json +23 -0
  163. package/dist/components/modules/maps/list/field-mapper.js.map +0 -1
  164. package/dist/components/modules/maps/list/header-item.js.map +0 -1
  165. package/dist/components/modules/maps/list/header.js.map +0 -1
  166. package/dist/components/modules/maps/list/index.js +0 -102
  167. package/dist/components/modules/maps/list/index.js.map +0 -1
  168. package/dist/components/modules/maps/list/item-expand-card/index.js.map +0 -1
  169. package/dist/components/modules/maps/list/item-expand-card/recruiter-contact-nav.js.map +0 -1
  170. package/dist/components/modules/maps/list/item-expand-card/recruiter-details.js.map +0 -1
  171. package/dist/components/modules/maps/list/item-expand-card/recruiter-headshot.js.map +0 -1
  172. package/dist/components/modules/maps/list/list-item/index.js.map +0 -1
  173. package/dist/services/_virtual/_rollupPluginBabelHelpers.js +0 -372
  174. package/dist/services/_virtual/_rollupPluginBabelHelpers.js.map +0 -1
  175. package/dist/services/apis/hcApi.js +0 -189
  176. package/dist/services/apis/hcApi.js.map +0 -1
  177. package/dist/services/clientToken.js +0 -7
  178. package/dist/services/clientToken.js.map +0 -1
  179. package/dist/services/styles/index.css +0 -3
  180. package/src/components/modules/maps/list/index.js +0 -112
  181. package/src/contexts/mapContext.js +0 -101
  182. package/src/contexts/mapListContext.js +0 -242
  183. package/src/services/listingAggregatorService.js +0 -50
  184. package/src/services/listingEntityService.js +0 -15
  185. package/src/services/listingService.js +0 -26
  186. package/src/util/localStorageUtil.js +0 -27
  187. /package/dist/components/modules/{maps/list → list}/item-expand-card/recruiter-headshot.js +0 -0
  188. /package/src/components/modules/{maps/list → list}/header-item.js +0 -0
  189. /package/src/components/modules/{maps/list → list}/item-expand-card/recruiter-contact-nav.js +0 -0
  190. /package/src/components/modules/{maps/list → list}/item-expand-card/recruiter-details.js +0 -0
  191. /package/src/components/modules/{maps/list → list}/item-expand-card/recruiter-headshot.js +0 -0
@@ -1,239 +1,239 @@
1
- import { getDistinctItemsByProximity } from '~/util/mapUtil';
2
-
3
- import Fuse from 'fuse.js';
4
-
5
- export const getFilterOptions = (listings, filteredListings, field, excludeZeroCount = null) => {
6
- const options = new Set();
7
- listings.forEach(listing => {
8
- if (listing.fields[field]) {
9
- options.add(listing.fields[field]);
10
- }
11
- });
12
-
13
- const optionCounts = {};
14
- options.forEach(option => {
15
- optionCounts[option] = 0;
16
- });
17
-
18
- filteredListings.forEach(listing => {
19
- const value = listing.fields[field];
20
- if (value && optionCounts.hasOwnProperty(value)) {
21
- optionCounts[value] += 1;
22
- }
23
- });
24
-
25
- return Array.from(options)
26
- .sort()
27
- .map(option => ({
28
- name: option,
29
- count: optionCounts[option] || 0
30
- }))
31
- .filter(option => !(excludeZeroCount === true && option.count === 0));
32
- };
33
-
34
- export const getSpecialFeatureOptions = (listings, filteredListings, siteConfig, favorites) => {
35
- const specialFeatures = siteConfig.specialFeatures;
36
- const featureCounts = Object.keys(specialFeatures).sort().reduce((acc, key) => {
37
- acc[specialFeatures[key]] = 0;
38
- return acc;
39
- }, {});
40
-
41
- filteredListings.forEach(listing => {
42
- Object.entries(specialFeatures).forEach(([featureKey, featureName]) => {
43
- if (listing.fields[featureKey] === 1) {
44
- featureCounts[featureName] += 1;
45
- }
46
- });
47
- });
48
-
49
- const specialFeatureOptions = Object.entries(featureCounts).map(([name, count]) => ({
50
- name,
51
- count
52
- }));
53
-
54
- for (let option of specialFeatureOptions) {
55
- if (option.name === 'Favorite') {
56
- option.count = filteredListings.filter(x => favorites.includes(x.id)).length;
57
- }
58
- }
59
-
60
- return specialFeatureOptions;
61
- };
62
-
63
- const getPointsOfInterestOptions = pointsOfInterestNames => {
64
- return Object.entries(pointsOfInterestNames).sort().map(([key, name]) => ({
65
- key,
66
- name
67
- }));
68
- };
69
-
70
- export const generateFilterOptions = (
71
- filteredListings,
72
- allListings,
73
- siteConfig,
74
- filterOptions,
75
- parentField = null,
76
- favorites
77
- ) => {
78
- if (allListings.length > 0) {
79
- const dynamicFilters = siteConfig.fieldFiltersShown.map(fieldName => {
80
- if (fieldName === parentField && filterOptions?.filters) {
81
- return filterOptions.filters.find(filter => filter.id === fieldName);
82
- }
83
- if (fieldName == "specialFeatures") {
84
- return {
85
- id: fieldName,
86
- title: siteConfig.fieldNames[fieldName],
87
- items: getSpecialFeatureOptions(allListings, filteredListings, siteConfig, favorites).sort()
88
- };
89
- }
90
- return {
91
- id: fieldName,
92
- title: siteConfig.fieldNames[fieldName],
93
- items: getFilterOptions(allListings, filteredListings, fieldName)
94
- };
95
- });
96
-
97
- const locations =
98
- siteConfig.locationFiltersShown.map((fieldName, index) => {
99
- if (index === 0 && filterOptions?.locations) {
100
- return filterOptions.locations.find(filter => filter.id === fieldName);
101
- }
102
- return {
103
- id: fieldName,
104
- title: siteConfig.fieldNames[fieldName],
105
- items: getFilterOptions(allListings, filteredListings, fieldName, true)
106
- };
107
- });
108
-
109
- const pointsOfInterest = {
110
- id: "pointsOfInterest",
111
- title: siteConfig.pointsOfInterestConfig.title,
112
- items: getPointsOfInterestOptions(
113
- siteConfig.pointsOfInterestConfig.pointsOfInterestNames
114
- )
115
- };
116
-
117
- return {
118
- filters: dynamicFilters,
119
- locations: locations,
120
- pointsOfInterest: pointsOfInterest
121
- };
122
- }
123
-
124
- return null;
125
- };
126
-
127
- export const applyFilters = (
128
- allListings,
129
- selectedFilters,
130
- query,
131
- listingEntities,
132
- favorites,
133
- siteConfig
134
- ) => {
135
- let results = allListings;
136
- let invertedSpecialFeaturesMap;
137
- if (siteConfig.specialFeatures) {
138
- invertedSpecialFeaturesMap = Object.entries(siteConfig.specialFeatures).reduce((acc, [key, value]) => {
139
- acc[value] = key;
140
- return acc;
141
- }, {});
142
-
143
- }
144
- const hasFavorite = !!selectedFilters.specialFeatures && !!selectedFilters.specialFeatures.Favorite;
145
-
146
- if (hasFavorite && selectedFilters.specialFeatures.Favorite == true) {
147
- results = results.filter(x => favorites.includes(x.id));
148
- }
149
- var favorite;
150
- if (hasFavorite) {
151
- favorite = selectedFilters.specialFeatures.Favorite;
152
- delete selectedFilters.specialFeatures.Favorite;
153
- }
154
- for (const [field, filterItems] of Object.entries(selectedFilters)) {
155
- const formattedField = field;
156
- if (field === "pointsOfInterest") continue;
157
- if (field === "specialFeatures" && invertedSpecialFeaturesMap && Object.keys(filterItems).length > 0) {
158
- results = results.filter(listing => {
159
- return Object.entries(filterItems).some(([filterName, filterValue]) => {
160
- const listingFieldName = invertedSpecialFeaturesMap[filterName];
161
- return filterValue && listing.fields[listingFieldName] === 1;
162
- });
163
- });
164
- } else if (Object.keys(filterItems).length > 0) {
165
- results = results.filter(listing =>
166
- filterItems.hasOwnProperty(listing.fields[formattedField])
167
- );
168
- }
169
- }
170
- if (query) {
171
- results = searchResults(results, query);
172
- }
173
- const distinctItems = getDistinctItemsByProximity(results, listingEntities);
174
- if (hasFavorite) {
175
- selectedFilters.specialFeatures.Favorite = favorite;
176
- }
177
- return { filteredListings: results, mapItems: distinctItems };
178
- };
179
-
180
- function searchResults(results, query) {
181
- const fields = [
182
- 'id',
183
- 'fields.posted',
184
- 'fields.subtitle',
185
- 'fields.education',
186
- 'fields.position',
187
- 'fields.category',
188
- 'fields.categoryclass',
189
- 'fields.shift',
190
- 'fields.citystate',
191
- 'fields.city',
192
- 'fields.state',
193
- 'fields.schedule',
194
- 'fields.customflag1',
195
- 'fields.bonus',
196
- 'fields.remote',
197
- 'fields.useclientjoburl',
198
- 'fields.datecreated',
199
- 'fields.datelastedited'
200
- ];
201
-
202
- const options = {
203
- includeScore: true,
204
- threshold: 0.3,
205
- keys: fields
206
- };
207
-
208
- const fuse = new Fuse(results, options);
209
- const lowerCaseQuery = query.toLowerCase();
210
- const queryTerms = lowerCaseQuery.split(' ');
211
-
212
- const exactIdMatch = results.find(result => result.id.toString() === query);
213
- if (exactIdMatch) {
214
- return [exactIdMatch];
215
- }
216
-
217
- const fuseQuery = queryTerms.map(term => ({
218
- $or: fields.map(field => ({ [field]: term }))
219
- }));
220
-
221
- const fuseResults = fuse.search({ $and: fuseQuery });
222
-
223
- return fuseResults.map(result => result.item);
224
- }
225
-
226
- export const filterListingsByLocation = (
227
- allListings,
228
- selectedLocation,
229
- listingEntities
230
- ) => {
231
- let results = allListings;
232
- if (selectedLocation !== null) {
233
- results = results.filter(item =>
234
- selectedLocation.items.hasOwnProperty(item.id)
235
- );
236
- }
237
- const mapItems = getDistinctItemsByProximity(results, listingEntities);
238
- return { filteredListings: results, mapItems: mapItems };
239
- };
1
+ import { getDistinctItemsByProximity } from '~/util/mapUtil';
2
+
3
+ import Fuse from 'fuse.js';
4
+
5
+ export const getFilterOptions = (listings, filteredListings, field, excludeZeroCount = null) => {
6
+ const options = new Set();
7
+ listings.forEach(listing => {
8
+ if (listing.fields[field]) {
9
+ options.add(listing.fields[field]);
10
+ }
11
+ });
12
+
13
+ const optionCounts = {};
14
+ options.forEach(option => {
15
+ optionCounts[option] = 0;
16
+ });
17
+
18
+ filteredListings.forEach(listing => {
19
+ const value = listing.fields[field];
20
+ if (value && optionCounts.hasOwnProperty(value)) {
21
+ optionCounts[value] += 1;
22
+ }
23
+ });
24
+
25
+ return Array.from(options)
26
+ .sort()
27
+ .map(option => ({
28
+ name: option,
29
+ count: optionCounts[option] || 0
30
+ }))
31
+ .filter(option => !(excludeZeroCount === true && option.count === 0));
32
+ };
33
+
34
+ export const getSpecialFeatureOptions = (listings, filteredListings, siteConfig, favorites) => {
35
+ const specialFeatures = siteConfig.specialFeatures;
36
+ const featureCounts = Object.keys(specialFeatures).sort().reduce((acc, key) => {
37
+ acc[specialFeatures[key]] = 0;
38
+ return acc;
39
+ }, {});
40
+
41
+ filteredListings.forEach(listing => {
42
+ Object.entries(specialFeatures).forEach(([featureKey, featureName]) => {
43
+ if (listing.fields[featureKey] === 1) {
44
+ featureCounts[featureName] += 1;
45
+ }
46
+ });
47
+ });
48
+
49
+ const specialFeatureOptions = Object.entries(featureCounts).map(([name, count]) => ({
50
+ name,
51
+ count
52
+ }));
53
+
54
+ for (let option of specialFeatureOptions) {
55
+ if (option.name === 'Favorite') {
56
+ option.count = filteredListings.filter(x => favorites.includes(x.id)).length;
57
+ }
58
+ }
59
+
60
+ return specialFeatureOptions;
61
+ };
62
+
63
+ const getPointsOfInterestOptions = pointsOfInterestNames => {
64
+ return Object.entries(pointsOfInterestNames).sort().map(([key, name]) => ({
65
+ key,
66
+ name
67
+ }));
68
+ };
69
+
70
+ export const generateFilterOptions = (
71
+ filteredListings,
72
+ allListings,
73
+ siteConfig,
74
+ filterOptions,
75
+ parentField,
76
+ favorites
77
+ ) => {
78
+ if (allListings.length > 0) {
79
+ const dynamicFilters = siteConfig.fieldFiltersShown.map(fieldName => {
80
+ if (fieldName === parentField && filterOptions?.filters) {
81
+ return filterOptions.filters.find(filter => filter.id === fieldName);
82
+ }
83
+ if (fieldName == "specialFeatures") {
84
+ return {
85
+ id: fieldName,
86
+ title: siteConfig.fieldNames[fieldName],
87
+ items: getSpecialFeatureOptions(allListings, filteredListings, siteConfig, favorites).sort()
88
+ };
89
+ }
90
+ return {
91
+ id: fieldName,
92
+ title: siteConfig.fieldNames[fieldName],
93
+ items: getFilterOptions(allListings, filteredListings, fieldName)
94
+ };
95
+ });
96
+
97
+ const locations =
98
+ siteConfig.locationFiltersShown.map((fieldName, index) => {
99
+ if (index === 0 && filterOptions?.locations) {
100
+ return filterOptions.locations.find(filter => filter.id === fieldName);
101
+ }
102
+ return {
103
+ id: fieldName,
104
+ title: siteConfig.fieldNames[fieldName],
105
+ items: getFilterOptions(allListings, filteredListings, fieldName, true)
106
+ };
107
+ });
108
+
109
+ const pointsOfInterest = {
110
+ id: "pointsOfInterest",
111
+ title: siteConfig.pointsOfInterestConfig.title,
112
+ items: getPointsOfInterestOptions(
113
+ siteConfig.pointsOfInterestConfig.pointsOfInterestNames
114
+ )
115
+ };
116
+
117
+ return {
118
+ filters: dynamicFilters,
119
+ locations: locations,
120
+ pointsOfInterest: pointsOfInterest
121
+ };
122
+ }
123
+
124
+ return null;
125
+ };
126
+
127
+ export const applyFilters = (
128
+ allListings,
129
+ selectedFilters,
130
+ query,
131
+ listingEntities,
132
+ favorites,
133
+ siteConfig
134
+ ) => {
135
+ let results = allListings;
136
+ let invertedSpecialFeaturesMap;
137
+ if (siteConfig.specialFeatures) {
138
+ invertedSpecialFeaturesMap = Object.entries(siteConfig.specialFeatures).reduce((acc, [key, value]) => {
139
+ acc[value] = key;
140
+ return acc;
141
+ }, {});
142
+
143
+ }
144
+ const hasFavorite = !!selectedFilters.specialFeatures && !!selectedFilters.specialFeatures.Favorite;
145
+
146
+ if (hasFavorite && selectedFilters.specialFeatures.Favorite == true) {
147
+ results = results.filter(x => favorites.includes(x.id));
148
+ }
149
+ var favorite;
150
+ if (hasFavorite) {
151
+ favorite = selectedFilters.specialFeatures.Favorite;
152
+ delete selectedFilters.specialFeatures.Favorite;
153
+ }
154
+ for (const [field, filterItems] of Object.entries(selectedFilters)) {
155
+ const formattedField = field;
156
+ if (field === "pointsOfInterest") continue;
157
+ if (field === "specialFeatures" && invertedSpecialFeaturesMap && Object.keys(filterItems).length > 0) {
158
+ results = results.filter(listing => {
159
+ return Object.entries(filterItems).some(([filterName, filterValue]) => {
160
+ const listingFieldName = invertedSpecialFeaturesMap[filterName];
161
+ return filterValue && listing.fields[listingFieldName] === 1;
162
+ });
163
+ });
164
+ } else if (Object.keys(filterItems).length > 0) {
165
+ results = results.filter(listing =>
166
+ filterItems.hasOwnProperty(listing.fields[formattedField])
167
+ );
168
+ }
169
+ }
170
+ if (query) {
171
+ results = searchResults(results, query);
172
+ }
173
+ const distinctItems = getDistinctItemsByProximity(results, listingEntities);
174
+ if (hasFavorite) {
175
+ selectedFilters.specialFeatures.Favorite = favorite;
176
+ }
177
+ return { filteredListings: results, mapItems: distinctItems };
178
+ };
179
+
180
+ function searchResults(results, query) {
181
+ const fields = [
182
+ 'id',
183
+ 'fields.posted',
184
+ 'fields.subtitle',
185
+ 'fields.education',
186
+ 'fields.position',
187
+ 'fields.category',
188
+ 'fields.categoryclass',
189
+ 'fields.shift',
190
+ 'fields.citystate',
191
+ 'fields.city',
192
+ 'fields.state',
193
+ 'fields.schedule',
194
+ 'fields.customflag1',
195
+ 'fields.bonus',
196
+ 'fields.remote',
197
+ 'fields.useclientjoburl',
198
+ 'fields.datecreated',
199
+ 'fields.datelastedited'
200
+ ];
201
+
202
+ const options = {
203
+ includeScore: true,
204
+ threshold: 0.3,
205
+ keys: fields
206
+ };
207
+
208
+ const fuse = new Fuse(results, options);
209
+ const lowerCaseQuery = query.toLowerCase();
210
+ const queryTerms = lowerCaseQuery.split(' ');
211
+
212
+ const exactIdMatch = results.find(result => result.id.toString() === query);
213
+ if (exactIdMatch) {
214
+ return [exactIdMatch];
215
+ }
216
+
217
+ const fuseQuery = queryTerms.map(term => ({
218
+ $or: fields.map(field => ({ [field]: term }))
219
+ }));
220
+
221
+ const fuseResults = fuse.search({ $and: fuseQuery });
222
+
223
+ return fuseResults.map(result => result.item);
224
+ }
225
+
226
+ export const filterListingsByLocation = (
227
+ allListings,
228
+ selectedLocation,
229
+ listingEntities
230
+ ) => {
231
+ let results = allListings;
232
+ if (selectedLocation !== null) {
233
+ results = results.filter(item =>
234
+ selectedLocation.items.hasOwnProperty(item.id)
235
+ );
236
+ }
237
+ const mapItems = getDistinctItemsByProximity(results, listingEntities);
238
+ return { filteredListings: results, mapItems: mapItems };
239
+ };
@@ -0,0 +1,34 @@
1
+ export const getStorageObject = <T>(item: string, defaultItem: T | null = null): T | null => {
2
+ if (typeof window === 'undefined') return defaultItem;
3
+ const storageItem = localStorage.getItem(item);
4
+ if (storageItem === null || storageItem === 'undefined') {
5
+ localStorage.removeItem(item);
6
+ return defaultItem;
7
+ }
8
+ try {
9
+ return JSON.parse(storageItem) ?? defaultItem;
10
+ } catch (error) {
11
+ console.error(`Error parsing JSON for ${item}:`, error);
12
+ return defaultItem;
13
+ }
14
+ };
15
+
16
+ export const getStorageItem = (item: string, defaultItem: string | null = null): string | null => {
17
+ if (typeof window === 'undefined') return defaultItem;
18
+ const storageItem = localStorage.getItem(item);
19
+ if (storageItem === null || storageItem === 'undefined') {
20
+ localStorage.removeItem(item);
21
+ return defaultItem;
22
+ }
23
+ return storageItem ?? defaultItem;
24
+ };
25
+
26
+ export const setStorageObject = (key: string, item: any): void => {
27
+ if (typeof window === 'undefined') return;
28
+ if (item === undefined) return;
29
+ try {
30
+ localStorage.setItem(key, JSON.stringify(item));
31
+ } catch (err) {
32
+ console.error(`Error setting item ${key} in localStorage:`, err);
33
+ }
34
+ };