@abcagency/hc-ui-components 1.5.1 → 1.5.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.
- package/dist/components/HireControlMap.js +34 -21
- package/dist/components/HireControlMap.js.map +1 -1
- package/dist/components/containers/accordions/filter-container.js +13 -5
- package/dist/components/containers/accordions/filter-container.js.map +1 -1
- package/dist/components/containers/accordions/filter-item-container.js +9 -9
- package/dist/components/containers/accordions/filter-item-container.js.map +1 -1
- package/dist/components/containers/accordions/map-accordion-item-container.js +10 -5
- package/dist/components/containers/accordions/map-accordion-item-container.js.map +1 -1
- package/dist/components/containers/filter/commute-container.js +3 -3
- package/dist/components/containers/filter/commute-container.js.map +1 -1
- package/dist/components/containers/filter/filter-container.js +6 -5
- package/dist/components/containers/filter/filter-container.js.map +1 -1
- package/dist/components/containers/filter/filter-item-container.js +12 -12
- package/dist/components/containers/filter/filter-item-container.js.map +1 -1
- package/dist/components/containers/filter/location-container.js +6 -5
- package/dist/components/containers/filter/location-container.js.map +1 -1
- package/dist/components/containers/filter/points-of-interest-container.js +5 -5
- package/dist/components/containers/filter/points-of-interest-container.js.map +1 -1
- package/dist/components/containers/filter/points-of-interest-radio-item-container.js +2 -2
- package/dist/components/containers/filter/points-of-interest-radio-item-container.js.map +1 -1
- package/dist/components/containers/filter/search-container.js +2 -2
- package/dist/components/containers/filter/search-container.js.map +1 -1
- package/dist/components/containers/jobListing/listing-details-container.js +2 -2
- package/dist/components/containers/jobListing/listing-details-container.js.map +1 -1
- package/dist/components/containers/list/item-list-container.js +8 -8
- package/dist/components/containers/list/item-list-container.js.map +1 -1
- package/dist/components/containers/list/list-item/list-item-container.js +2 -2
- package/dist/components/containers/list/list-item/list-item-container.js.map +1 -1
- package/dist/components/containers/maps/info-window-content-container.js +2 -2
- package/dist/components/containers/maps/info-window-content-container.js.map +1 -1
- package/dist/components/containers/maps/map-container.js +8 -9
- package/dist/components/containers/maps/map-container.js.map +1 -1
- package/dist/components/containers/maps/map-list-container.js +5 -5
- package/dist/components/containers/maps/map-list-container.js.map +1 -1
- package/dist/components/containers/maps/map-marker-container.js +6 -6
- package/dist/components/containers/maps/map-marker-container.js.map +1 -1
- package/dist/components/modules/accordions/MapAccordionItem.js +5 -5
- package/dist/components/modules/accordions/MapAccordionItem.js.map +1 -1
- package/dist/components/modules/accordions/default.js +15 -15
- package/dist/components/modules/accordions/default.js.map +1 -1
- package/dist/components/modules/accordions/filterItem.js +4 -4
- package/dist/components/modules/accordions/filterItem.js.map +1 -1
- package/dist/components/modules/accordions/filters.js +6 -6
- package/dist/components/modules/accordions/filters.js.map +1 -1
- package/dist/components/modules/buttons/button-group-apply.js +19 -19
- package/dist/components/modules/buttons/button-group-apply.js.map +1 -1
- package/dist/components/modules/buttons/default.js +9 -9
- package/dist/components/modules/buttons/default.js.map +1 -1
- package/dist/components/modules/buttons/items-pill.js +2 -2
- package/dist/components/modules/buttons/items-pill.js.map +1 -1
- package/dist/components/modules/buttons/pill-wrapper.js +2 -2
- package/dist/components/modules/buttons/pill-wrapper.js.map +1 -1
- package/dist/components/modules/buttons/show-all-button.js +3 -3
- package/dist/components/modules/buttons/show-all-button.js.map +1 -1
- package/dist/components/modules/cards/default.js +11 -11
- package/dist/components/modules/cards/default.js.map +1 -1
- package/dist/components/modules/cards/filter.js +5 -5
- package/dist/components/modules/cards/filter.js.map +1 -1
- package/dist/components/modules/dialogs/apply-dialog.js +19 -19
- package/dist/components/modules/dialogs/apply-dialog.js.map +1 -1
- package/dist/components/modules/filter/commute.js +18 -19
- package/dist/components/modules/filter/commute.js.map +1 -1
- package/dist/components/modules/filter/index.js +10 -10
- package/dist/components/modules/filter/index.js.map +1 -1
- package/dist/components/modules/filter/item.js +6 -6
- package/dist/components/modules/filter/item.js.map +1 -1
- package/dist/components/modules/filter/location.js +6 -6
- package/dist/components/modules/filter/location.js.map +1 -1
- package/dist/components/modules/filter/radio-item.js +6 -6
- package/dist/components/modules/filter/radio-item.js.map +1 -1
- package/dist/components/modules/filter/search.js +10 -10
- package/dist/components/modules/filter/search.js.map +1 -1
- package/dist/components/modules/filter/sort.js +28 -28
- package/dist/components/modules/filter/sort.js.map +1 -1
- package/dist/components/modules/grid.js +4 -4
- package/dist/components/modules/grid.js.map +1 -1
- package/dist/components/modules/icon.js +4 -4
- package/dist/components/modules/icon.js.map +1 -1
- package/dist/components/modules/jobListing/listing-details.js +4 -4
- package/dist/components/modules/jobListing/listing-details.js.map +1 -1
- package/dist/components/modules/list/field-mapper-desktop.js +8 -8
- package/dist/components/modules/list/field-mapper-desktop.js.map +1 -1
- package/dist/components/modules/list/field-mapper-mobile.js +18 -18
- package/dist/components/modules/list/field-mapper-mobile.js.map +1 -1
- package/dist/components/modules/list/header-item.js +7 -7
- package/dist/components/modules/list/header-item.js.map +1 -1
- package/dist/components/modules/list/header.js +5 -5
- package/dist/components/modules/list/header.js.map +1 -1
- package/dist/components/modules/list/item-expand-card/index.js +3 -3
- package/dist/components/modules/list/item-expand-card/index.js.map +1 -1
- package/dist/components/modules/list/item-list.js +15 -15
- package/dist/components/modules/list/item-list.js.map +1 -1
- package/dist/components/modules/list/list-item/list-item.js +13 -13
- package/dist/components/modules/list/list-item/list-item.js.map +1 -1
- package/dist/components/modules/maps/info-window-card.js +2 -2
- package/dist/components/modules/maps/info-window-card.js.map +1 -1
- package/dist/components/modules/maps/info-window-content.js +5 -5
- package/dist/components/modules/maps/info-window-content.js.map +1 -1
- package/dist/components/modules/maps/map-list.js +5 -5
- package/dist/components/modules/maps/map-list.js.map +1 -1
- package/dist/components/modules/maps/map-marker.js +3 -3
- package/dist/components/modules/maps/map-marker.js.map +1 -1
- package/dist/components/modules/maps/map.js +5 -5
- package/dist/components/modules/maps/map.js.map +1 -1
- package/dist/components/modules/maps/place-marker.js +5 -5
- package/dist/components/modules/maps/place-marker.js.map +1 -1
- package/dist/components/modules/maps/tabs.js +21 -21
- package/dist/components/modules/maps/tabs.js.map +1 -1
- package/dist/contexts/mapContext.js +18 -18
- package/dist/contexts/mapContext.js.map +1 -1
- package/dist/contexts/mapListContext.js +26 -22
- package/dist/contexts/mapListContext.js.map +1 -1
- package/dist/contexts/placesContext.js +2 -2
- package/dist/contexts/placesContext.js.map +1 -1
- package/dist/contexts/themeContext.js +2 -2
- package/dist/contexts/themeContext.js.map +1 -1
- package/dist/contexts/trackEventContext.js +2 -2
- package/dist/contexts/trackEventContext.js.map +1 -1
- package/dist/services/listingAggregatorService.js +19 -15
- package/dist/services/listingAggregatorService.js.map +1 -1
- package/dist/services/listingEntityService.js +3 -2
- package/dist/services/listingEntityService.js.map +1 -1
- package/dist/services/listingService.js +1 -16
- package/dist/services/listingService.js.map +1 -1
- package/dist/styles/index.css +1 -3
- package/dist/types/contexts/mapContext.d.ts +1 -0
- package/dist/types/services/listingAggregatorService.d.ts +2 -2
- package/dist/types/services/listingEntityService.d.ts +2 -3
- package/dist/types/types/GetListingParams.d.ts +1 -1
- package/dist/types/types/ListingEntity.d.ts +2 -1
- package/dist/types/types/ListingFields.d.ts +4 -2
- package/dist/types/types/Listings.d.ts +0 -1
- package/dist/types/util/mapUtil.d.ts +3 -3
- package/dist/util/filterUtil.js +6 -6
- package/dist/util/filterUtil.js.map +1 -1
- package/dist/util/loading.js +3 -3
- package/dist/util/loading.js.map +1 -1
- package/dist/util/mapUtil.js +37 -25
- package/dist/util/mapUtil.js.map +1 -1
- package/package.json +60 -17
- package/src/components/HireControlMap.js +19 -8
- package/src/components/containers/accordions/filter-container.js +6 -1
- package/src/components/containers/accordions/filter-item-container.js +2 -2
- package/src/components/containers/accordions/map-accordion-item-container.js +6 -2
- package/src/components/containers/filter/filter-container.js +3 -2
- package/src/components/containers/filter/filter-item-container.js +10 -10
- package/src/components/containers/filter/location-container.js +3 -3
- package/src/components/containers/list/item-list-container.tsx +3 -3
- package/src/components/containers/maps/info-window-content-container.js +1 -1
- package/src/components/containers/maps/map-container.js +2 -1
- package/src/components/modules/buttons/button-group-apply.js +8 -8
- package/src/components/modules/dialogs/apply-dialog.js +2 -2
- package/src/components/modules/list/field-mapper-desktop.jsx +2 -2
- package/src/components/modules/list/field-mapper-mobile.jsx +8 -8
- package/src/components/modules/list/header-item.js +1 -1
- package/src/components/modules/maps/map-list.js +1 -1
- package/src/contexts/mapContext.tsx +17 -16
- package/src/contexts/mapListContext.tsx +53 -47
- package/src/services/listingAggregatorService.ts +29 -21
- package/src/services/listingEntityService.ts +3 -3
- package/src/services/listingService.ts +1 -11
- package/src/styles/components.css +30 -0
- package/src/types/GetListingParams.ts +1 -1
- package/src/types/ListingEntity.ts +2 -1
- package/src/types/ListingFields.ts +4 -2
- package/src/types/Listings.ts +0 -1
- package/src/util/filterUtil.js +6 -6
- package/src/util/mapUtil.js +52 -41
|
@@ -57,7 +57,7 @@ const HeaderItem = ({
|
|
|
57
57
|
size="none"
|
|
58
58
|
className={`
|
|
59
59
|
hc-p-2 hc-rounded-none hc-text-left hc-normal-case hover:hc-bg-uiAccent/5 focus:hc-bg-uiAccent/5
|
|
60
|
-
${field.toLowerCase() === "
|
|
60
|
+
${field.toLowerCase() === "title" ? "hc-pl-7 hc-col-span-4" : (field.toLowerCase() === "state" || field.toLowerCase() == "favorite") ? "hc-col-span-1" : "hc-col-span-2"}
|
|
61
61
|
${className ?? ""}
|
|
62
62
|
`}
|
|
63
63
|
{...rest}
|
|
@@ -8,7 +8,7 @@ const MapList = ({ showMap, loading, list, map, filter, mapPosition, containerSt
|
|
|
8
8
|
style={containerStyle}
|
|
9
9
|
className={`
|
|
10
10
|
${showMap === false ? "md:hc-grid-rows-[100%]" : "md:hc-grid-rows-[50%_50%]"}
|
|
11
|
-
hc-hidden md:hc-grid
|
|
11
|
+
hc-hidden md:hc-grid hc-overflow-hidden hc-relative bg-gray-100
|
|
12
12
|
`}
|
|
13
13
|
>
|
|
14
14
|
{mapPosition && mapPosition === 'top' && showMap ? (
|
|
@@ -37,37 +37,38 @@ interface MapProviderProps {
|
|
|
37
37
|
children: ReactNode;
|
|
38
38
|
resetFilters: boolean;
|
|
39
39
|
defaultZoomOverride?: number | null;
|
|
40
|
+
localStorageKey?: string;
|
|
40
41
|
}
|
|
41
42
|
|
|
42
|
-
export const MapProvider: React.FC<MapProviderProps> = ({ children, resetFilters, defaultZoomOverride }) => {
|
|
43
|
-
const [selectedListItem, setSelectedListItem] = useState<Listing | null>(getStorageObject('selectedListItem'));
|
|
44
|
-
const [location, setLocation] = useState<any>(getStorageObject('location'));
|
|
45
|
-
const [center, setCenter] = useState<LatLng>(getStorageObject("center", { lat: 39.8283, lng: -98.5795 }) || { lat: 39.8283, lng: -98.5795 });
|
|
46
|
-
const [zoom, setZoom] = useState<number>(getStorageObject("zoom", 9) || 9);
|
|
43
|
+
export const MapProvider: React.FC<MapProviderProps> = ({ children, resetFilters, defaultZoomOverride, localStorageKey = '' }) => {
|
|
44
|
+
const [selectedListItem, setSelectedListItem] = useState<Listing | null>(getStorageObject(localStorageKey + 'selectedListItem'));
|
|
45
|
+
const [location, setLocation] = useState<any>(getStorageObject(localStorageKey + 'location'));
|
|
46
|
+
const [center, setCenter] = useState<LatLng>(getStorageObject(localStorageKey + "center", { lat: 39.8283, lng: -98.5795 }) || { lat: 39.8283, lng: -98.5795 });
|
|
47
|
+
const [zoom, setZoom] = useState<number>(getStorageObject(localStorageKey + "zoom", 9) || 9);
|
|
47
48
|
const [selectedPlaces, setSelectedPlaces] = useState<string[]>([]);
|
|
48
49
|
const [mapInteracted, setMapInteracted] = useState<boolean>(false);
|
|
49
|
-
const [firstLoadListItem] = useState<any>(getStorageObject('selectedListItem', { id: "defaultId" }));
|
|
50
|
+
const [firstLoadListItem] = useState<any>(getStorageObject(localStorageKey + 'selectedListItem', { id: "defaultId" }));
|
|
50
51
|
const userSetZoom = useRef<boolean>(true);
|
|
51
52
|
|
|
52
53
|
useEffect(() => {
|
|
53
|
-
setStorageObject("selectedListItem", selectedListItem);
|
|
54
|
-
}, [selectedListItem]);
|
|
54
|
+
setStorageObject(localStorageKey + "selectedListItem", selectedListItem);
|
|
55
|
+
}, [selectedListItem, localStorageKey]);
|
|
55
56
|
|
|
56
57
|
useEffect(() => {
|
|
57
|
-
localStorage.setItem("zoom", zoom.toString());
|
|
58
|
-
}, [zoom]);
|
|
58
|
+
localStorage.setItem(localStorageKey + "zoom", zoom.toString());
|
|
59
|
+
}, [zoom, localStorageKey]);
|
|
59
60
|
|
|
60
61
|
useEffect(() => {
|
|
61
62
|
if (location == null) {
|
|
62
|
-
localStorage.removeItem("location");
|
|
63
|
+
localStorage.removeItem(localStorageKey + "location");
|
|
63
64
|
} else {
|
|
64
|
-
setStorageObject("location", location);
|
|
65
|
+
setStorageObject(localStorageKey + "location", location);
|
|
65
66
|
}
|
|
66
|
-
}, [location]);
|
|
67
|
+
}, [location, localStorageKey]);
|
|
67
68
|
|
|
68
69
|
useEffect(() => {
|
|
69
|
-
setStorageObject("center", center);
|
|
70
|
-
}, [center]);
|
|
70
|
+
setStorageObject(localStorageKey + "center", center);
|
|
71
|
+
}, [center, localStorageKey]);
|
|
71
72
|
|
|
72
73
|
const selectItem = (item: Listing, itemLocation: LatLng | null, zoom: number, center: LatLng) => {
|
|
73
74
|
setSelectedListItem(item);
|
|
@@ -98,7 +99,7 @@ export const MapProvider: React.FC<MapProviderProps> = ({ children, resetFilters
|
|
|
98
99
|
}, [resetFilters]);
|
|
99
100
|
|
|
100
101
|
const selectLocationEntity = (location: LatLng) => {
|
|
101
|
-
localStorage.removeItem("selectedListItem");
|
|
102
|
+
localStorage.removeItem(localStorageKey + "selectedListItem");
|
|
102
103
|
setTimeout(() => setLocation(location), 200);
|
|
103
104
|
setSelectedListItem(null);
|
|
104
105
|
};
|
|
@@ -53,6 +53,7 @@ interface MapListContextProps {
|
|
|
53
53
|
hiddenFilters?: string[];
|
|
54
54
|
containerStyle?: any;
|
|
55
55
|
ExpandListComponent?: React.ComponentType<{ listing: any }> | ((listing: any) => JSX.Element) | null;
|
|
56
|
+
noEntities?: boolean;
|
|
56
57
|
}
|
|
57
58
|
|
|
58
59
|
const MapListContext = createContext<MapListContextProps | undefined>(undefined);
|
|
@@ -93,8 +94,11 @@ interface MapListProviderProps {
|
|
|
93
94
|
defaultFilters?: Record<string, any>;
|
|
94
95
|
containerStyle?: any;
|
|
95
96
|
localStorageKey: string;
|
|
96
|
-
getListingEntitiesCallback?: (
|
|
97
|
+
getListingEntitiesCallback?: (origin?: string) => Promise<any>;
|
|
97
98
|
ExpandListComponent?: React.ComponentType<{ listing: Listing }> | ((listing: Listing) => JSX.Element) | null;
|
|
99
|
+
hideMap?: boolean;
|
|
100
|
+
hideFilters?: boolean;
|
|
101
|
+
noEntities?: boolean;
|
|
98
102
|
}
|
|
99
103
|
|
|
100
104
|
export const MapListProvider: React.FC<MapListProviderProps> = ({
|
|
@@ -118,13 +122,16 @@ export const MapListProvider: React.FC<MapListProviderProps> = ({
|
|
|
118
122
|
containerStyle,
|
|
119
123
|
ExpandListComponent,
|
|
120
124
|
getListingEntitiesCallback,
|
|
121
|
-
localStorageKey
|
|
125
|
+
localStorageKey,
|
|
126
|
+
hideMap = false,
|
|
127
|
+
hideFilters = false,
|
|
128
|
+
noEntities = false
|
|
122
129
|
}) => {
|
|
123
130
|
const firstLoadFilters = () =>{
|
|
124
131
|
let urlFilters = filtersFromURL(window.location)?.filters;
|
|
125
132
|
return (setFiltersUrl === true && urlFilters && Object.keys(urlFilters).length > 0) ? urlFilters : getStorageObject(localStorageKey + 'selectedFilters', {}) || {}
|
|
126
133
|
}
|
|
127
|
-
|
|
134
|
+
|
|
128
135
|
const firstLoadQuery = (): string | null => {
|
|
129
136
|
if (resetFilters) return null;
|
|
130
137
|
// Check URL first
|
|
@@ -135,7 +142,7 @@ export const MapListProvider: React.FC<MapListProviderProps> = ({
|
|
|
135
142
|
// Fall back to localStorage
|
|
136
143
|
return getQuery(localStorageKey);
|
|
137
144
|
}
|
|
138
|
-
|
|
145
|
+
|
|
139
146
|
const [allListings, setAllListings] = useState<Listing[]>([]);
|
|
140
147
|
const [filteredListings, setFilteredListings] = useState<Listing[]>([]);
|
|
141
148
|
const [loading, setLoading] = useState<boolean>(false);
|
|
@@ -144,7 +151,7 @@ export const MapListProvider: React.FC<MapListProviderProps> = ({
|
|
|
144
151
|
const [sortSetting, setSortSetting] = useState<{ field: string; type: string }>(getStorageObject(localStorageKey + 'sortSetting', { field: 'position', type: 'asc' }) || { field: 'position', type: 'asc' });
|
|
145
152
|
const [listingEntities, setListingEntities] = useState<Record<number, ListingEntity> | null>({});
|
|
146
153
|
const [firstLoad, setFirstLoad] = useState<boolean>(true);
|
|
147
|
-
const [commuteLocation, setCommuteLocation] = useState<any | null>(getStorageObject('commuteLocation'));
|
|
154
|
+
const [commuteLocation, setCommuteLocation] = useState<any | null>(getStorageObject(localStorageKey + 'commuteLocation'));
|
|
148
155
|
const [selectedFilters, setSelectedFilters] = useState<Record<string, any>>(() => resetFilters ? {} : firstLoadFilters());
|
|
149
156
|
const [filterOptions, setFilterOptions] = useState<any>();
|
|
150
157
|
const [recruiters, setRecruiters] = useState<Record<number, Recruiter>>({});
|
|
@@ -161,7 +168,7 @@ export const MapListProvider: React.FC<MapListProviderProps> = ({
|
|
|
161
168
|
if (!sortSetting) return;
|
|
162
169
|
localStorage.setItem(localStorageKey + 'sortSetting', JSON.stringify(sortSetting));
|
|
163
170
|
setNewFilteredListings(filteredListings);
|
|
164
|
-
}, [sortSetting, localStorageKey]);
|
|
171
|
+
}, [sortSetting, localStorageKey, filteredListings]);
|
|
165
172
|
|
|
166
173
|
useEffect(() => {
|
|
167
174
|
const loadedFavorites = JSON.parse(localStorage.getItem(localStorageKey + 'favorites') || '[]');
|
|
@@ -172,34 +179,32 @@ export const MapListProvider: React.FC<MapListProviderProps> = ({
|
|
|
172
179
|
setStorageObject(localStorageKey + "commuteLocation", commuteLocation);
|
|
173
180
|
}, [commuteLocation, localStorageKey]);
|
|
174
181
|
|
|
182
|
+
|
|
175
183
|
useEffect(() => {
|
|
176
|
-
if (!commuteLocation) return;
|
|
184
|
+
if (!commuteLocation || noEntities) return;
|
|
177
185
|
|
|
178
186
|
async function fetchEntities() {
|
|
179
|
-
const distinctEntityIds = [
|
|
180
|
-
...new Set(allListings.map(listing => listing.entityId ?? -1))
|
|
181
|
-
];
|
|
182
187
|
try {
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
);
|
|
188
|
+
let fetchedEntities;
|
|
189
|
+
if (getListingEntitiesCallback) {
|
|
190
|
+
fetchedEntities = await getListingEntitiesCallback(`${commuteLocation.lat}, ${commuteLocation.lng}`);
|
|
191
|
+
} else {
|
|
192
|
+
fetchedEntities = await getListingEntities(`${commuteLocation.lat}, ${commuteLocation.lng}`);
|
|
193
|
+
}
|
|
190
194
|
setListingEntities(fetchedEntities);
|
|
191
|
-
|
|
195
|
+
// Update travelTime on listings
|
|
196
|
+
const newFilteredListings: Listing[] = [...filteredListings];
|
|
192
197
|
for (let i = 0; i < allListings.length; i++) {
|
|
193
198
|
const listing = newFilteredListings[i];
|
|
194
199
|
if (
|
|
195
200
|
listing &&
|
|
196
201
|
listing.fields &&
|
|
197
|
-
listing.
|
|
198
|
-
listing.
|
|
202
|
+
listing.fields.entityKey &&
|
|
203
|
+
listing.fields.entityKey !== ''
|
|
199
204
|
) {
|
|
200
|
-
const
|
|
201
|
-
|
|
202
|
-
|
|
205
|
+
const entityKey = listing.fields.entityKey;
|
|
206
|
+
// Try exact match first, then lowercase match for case-insensitive lookup
|
|
207
|
+
const travelTime = (fetchedEntities[entityKey] || fetchedEntities[entityKey.toLowerCase()])?.travelTime;
|
|
203
208
|
if (travelTime !== undefined && listing.fields) {
|
|
204
209
|
listing.fields.travelTime = travelTime;
|
|
205
210
|
}
|
|
@@ -211,35 +216,35 @@ export const MapListProvider: React.FC<MapListProviderProps> = ({
|
|
|
211
216
|
}
|
|
212
217
|
|
|
213
218
|
fetchEntities();
|
|
214
|
-
}, [commuteLocation, allListings, siteConfig.companyId]);
|
|
219
|
+
}, [commuteLocation, allListings, siteConfig.companyId, getListingEntitiesCallback, noEntities]);
|
|
215
220
|
|
|
216
221
|
useEffect(() => {
|
|
217
222
|
const handleFetchListings = async () => {
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
223
|
+
if (!(getStorageObject(localStorageKey + 'listings', []) || []).length) {
|
|
224
|
+
setLoading(true);
|
|
225
|
+
}
|
|
221
226
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
227
|
+
try {
|
|
228
|
+
const {
|
|
229
|
+
listingsResult,
|
|
230
|
+
entitiesByKey,
|
|
231
|
+
distinctItems
|
|
232
|
+
} = await fetchListings(commuteLocation, entities, listings, getListingEntitiesCallback, noEntities);
|
|
233
|
+
if (defaultFilters) {
|
|
234
|
+
const filteredListings = listingsResult.filter(listing => {
|
|
235
|
+
if (!listing.fields) return false;
|
|
231
236
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
});
|
|
237
|
+
return Object.keys(defaultFilters).every(filterKey => {
|
|
238
|
+
const filterValues = defaultFilters[filterKey as keyof typeof defaultFilters];
|
|
239
|
+
const listingValue = listing.fields ? listing.fields[filterKey as keyof typeof listing.fields] : null;
|
|
240
|
+
return filterValues.includes(listingValue);
|
|
237
241
|
});
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
242
|
+
});
|
|
243
|
+
setAllListings(filteredListings);
|
|
244
|
+
} else {
|
|
245
|
+
setAllListings(listingsResult);
|
|
246
|
+
}
|
|
247
|
+
setListingEntities(entitiesByKey);
|
|
243
248
|
setMapItems(distinctItems);
|
|
244
249
|
} catch (error) {
|
|
245
250
|
console.log(error);
|
|
@@ -369,7 +374,8 @@ export const MapListProvider: React.FC<MapListProviderProps> = ({
|
|
|
369
374
|
defaultFilters,
|
|
370
375
|
hiddenFilters,
|
|
371
376
|
containerStyle,
|
|
372
|
-
ExpandListComponent
|
|
377
|
+
ExpandListComponent,
|
|
378
|
+
noEntities
|
|
373
379
|
}}>
|
|
374
380
|
{children}
|
|
375
381
|
</MapListContext.Provider>
|
|
@@ -6,7 +6,8 @@ import { ListingEntity } from '~/types/ListingEntity';
|
|
|
6
6
|
|
|
7
7
|
interface FetchListingsResult {
|
|
8
8
|
listingsResult: Listing[];
|
|
9
|
-
|
|
9
|
+
entitiesByKey: Record<string, ListingEntity>;
|
|
10
|
+
|
|
10
11
|
distinctItems: any; // Update this type based on the return type of getDistinctItemsByProximity
|
|
11
12
|
}
|
|
12
13
|
|
|
@@ -14,39 +15,46 @@ const fetchListings = async (
|
|
|
14
15
|
commuteLocation: any | null = null,
|
|
15
16
|
entities: ListingEntity[] | null,
|
|
16
17
|
listings: Listing[] | null,
|
|
17
|
-
getListingEntitiesCallback?: (
|
|
18
|
+
getListingEntitiesCallback?: (origin?: string) => Promise<ListingEntity[]>,
|
|
19
|
+
noEntities: boolean = false
|
|
18
20
|
): Promise<FetchListingsResult> => {
|
|
19
21
|
try {
|
|
20
22
|
const listingsResult = listings && listings.length > 0 ? listings : await getListings();
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
const
|
|
36
|
-
if (
|
|
37
|
-
|
|
23
|
+
|
|
24
|
+
// Only fetch entities if noEntities is false
|
|
25
|
+
const fetchedEntities = noEntities ? {} : (
|
|
26
|
+
!commuteLocation
|
|
27
|
+
? entities && entities.length > 0 ? entities : !getListingEntitiesCallback ? await getListingEntities() : await getListingEntitiesCallback()
|
|
28
|
+
: !getListingEntitiesCallback ? await getListingEntities(
|
|
29
|
+
`${commuteLocation.lat}, ${commuteLocation.lng}`
|
|
30
|
+
) : await getListingEntitiesCallback(
|
|
31
|
+
`${commuteLocation.lat}, ${commuteLocation.lng}`)
|
|
32
|
+
);
|
|
33
|
+
const entitiesByKey = fetchedEntities;
|
|
34
|
+
// Update travel time only if entities were fetched
|
|
35
|
+
if (!noEntities && entitiesByKey) {
|
|
36
|
+
for (let i = 0; i < listingsResult.length; i++) {
|
|
37
|
+
const listing = listingsResult[i];
|
|
38
|
+
if (listing.fields && listing.fields.entityKey && listing.fields.entityKey !== '' && listing.fields) {
|
|
39
|
+
// Try exact match first, then lowercase match for case-insensitive lookup
|
|
40
|
+
const entity = entitiesByKey[listing.fields.entityKey] || entitiesByKey[listing.fields.entityKey.toLowerCase()];
|
|
41
|
+
console.log("Entity for listing with travel time", listing.fields.entityKey, entity);
|
|
42
|
+
|
|
43
|
+
if (entity) {
|
|
44
|
+
listing.fields.travelTime = entity.travelTime;
|
|
45
|
+
}
|
|
38
46
|
}
|
|
39
47
|
}
|
|
40
48
|
}
|
|
41
49
|
|
|
42
50
|
const distinctItems = getDistinctItemsByProximity(
|
|
43
51
|
listingsResult,
|
|
44
|
-
|
|
52
|
+
entitiesByKey || {}
|
|
45
53
|
);
|
|
46
54
|
|
|
47
55
|
return {
|
|
48
56
|
listingsResult,
|
|
49
|
-
|
|
57
|
+
entitiesByKey,
|
|
50
58
|
distinctItems
|
|
51
59
|
};
|
|
52
60
|
} catch (error) {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import api from '~/apis/hcApi';
|
|
2
|
-
import { ListingEntity } from '~/types/ListingEntity';
|
|
3
2
|
|
|
4
|
-
export const getListingEntities = async (
|
|
3
|
+
export const getListingEntities = async (origin = ''): Promise<any> => {
|
|
5
4
|
try {
|
|
6
|
-
|
|
5
|
+
//need to update / or add better endpoint fo this to match original functioanlity
|
|
6
|
+
const response = await api.get<any>(`/listingentities/MapEntities?origin=${origin}`);
|
|
7
7
|
return response;
|
|
8
8
|
} catch (error) {
|
|
9
9
|
console.error("Error fetching listing entities:", error);
|
|
@@ -5,18 +5,8 @@ import { Listing } from '../types/Listings';
|
|
|
5
5
|
|
|
6
6
|
export const getListings = async (params?: GetListingsParams): Promise<Listing[]> => {
|
|
7
7
|
try {
|
|
8
|
-
const
|
|
8
|
+
const response = await api.get(`/joblistings/maplistings`);
|
|
9
9
|
|
|
10
|
-
if (params) {
|
|
11
|
-
if (params.location) params.location.forEach(loc => query.append('location', loc));
|
|
12
|
-
if (params.category) params.category.forEach(cat => query.append('category', cat));
|
|
13
|
-
if (params.categoryClass) params.categoryClass.forEach(catClass => query.append('categoryClass', catClass));
|
|
14
|
-
if (params.education) params.education.forEach(edu => query.append('education', edu));
|
|
15
|
-
if (params.city) params.city.forEach(cty => query.append('city', cty));
|
|
16
|
-
if (params.state) params.state.forEach(st => query.append('state', st));
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const response = await api.get(`/Listings?${query.toString()}`);
|
|
20
10
|
return response as Listing[];
|
|
21
11
|
} catch (error) {
|
|
22
12
|
console.error(error);
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
@config "../../tailwind.config.js";
|
|
2
|
+
|
|
3
|
+
/* Only include components and utilities - no base styles */
|
|
4
|
+
@tailwind components;
|
|
5
|
+
@tailwind utilities;
|
|
6
|
+
|
|
7
|
+
@layer components {
|
|
8
|
+
.track * {
|
|
9
|
+
@apply hc-pointer-events-none;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.stretched-link::after {
|
|
13
|
+
@apply hc-content-[''] hc-absolute hc-inset-0 hc-z-[1] hc-pointer-events-auto hc-bg-transparent;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/* Component-specific utilities */
|
|
18
|
+
.fit-content {
|
|
19
|
+
height: fit-content;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/* CSS Variables for theming - these should be set by the consuming app */
|
|
23
|
+
:root {
|
|
24
|
+
--ui-text: #000000;
|
|
25
|
+
--ui-accent: #959595;
|
|
26
|
+
--primary: #959595;
|
|
27
|
+
--primary-dark: #959595;
|
|
28
|
+
--secondary: #959595;
|
|
29
|
+
--secondary-dark: #959595;
|
|
30
|
+
}
|
|
@@ -2,9 +2,10 @@ export type ListingFields = {
|
|
|
2
2
|
posted?: string;
|
|
3
3
|
subTitle?: string;
|
|
4
4
|
education?: string;
|
|
5
|
-
|
|
5
|
+
title?: string;
|
|
6
6
|
category?: string;
|
|
7
|
-
|
|
7
|
+
subCategory?: string;
|
|
8
|
+
applyUrl?: string;
|
|
8
9
|
shift?: string;
|
|
9
10
|
custom1?: string;
|
|
10
11
|
custom2?: string;
|
|
@@ -22,5 +23,6 @@ export type ListingFields = {
|
|
|
22
23
|
useClientJobUrl?: boolean;
|
|
23
24
|
dateCreated: Date;
|
|
24
25
|
dateLastEdited?: Date;
|
|
26
|
+
entityKey: string;
|
|
25
27
|
travelTime?: string;
|
|
26
28
|
}
|
package/src/types/Listings.ts
CHANGED
package/src/util/filterUtil.js
CHANGED
|
@@ -82,17 +82,17 @@ export const generateFilterOptions = (
|
|
|
82
82
|
if (fieldName === parentField && filterOptions?.filters) {
|
|
83
83
|
return filterOptions.filters.find(filter => filter.id === fieldName);
|
|
84
84
|
}
|
|
85
|
-
if(fieldName == '
|
|
85
|
+
if(fieldName == 'category'){
|
|
86
86
|
return {
|
|
87
87
|
id: fieldName,
|
|
88
88
|
title: siteConfig.fieldNames[fieldName],
|
|
89
89
|
items: getFilterOptions(allListings, allListings, fieldName)
|
|
90
90
|
};
|
|
91
91
|
}
|
|
92
|
-
if(fieldName == '
|
|
93
|
-
const
|
|
92
|
+
if(fieldName == 'subCategory' && selectedFilters.category){
|
|
93
|
+
const categoryKeys = Object.keys(selectedFilters.category);
|
|
94
94
|
const filteredListings = allListings.filter(
|
|
95
|
-
x =>
|
|
95
|
+
x => categoryKeys.includes(x.fields?.category)
|
|
96
96
|
);
|
|
97
97
|
return {
|
|
98
98
|
id: fieldName,
|
|
@@ -255,9 +255,9 @@ function searchResults(results, query) {
|
|
|
255
255
|
'fields.posted',
|
|
256
256
|
'fields.subtitle',
|
|
257
257
|
'fields.education',
|
|
258
|
-
'fields.
|
|
258
|
+
'fields.title',
|
|
259
259
|
'fields.category',
|
|
260
|
-
'fields.
|
|
260
|
+
'fields.subCategory',
|
|
261
261
|
'fields.shift',
|
|
262
262
|
'fields.citystate',
|
|
263
263
|
'fields.city',
|
package/src/util/mapUtil.js
CHANGED
|
@@ -1,54 +1,59 @@
|
|
|
1
|
-
export const getDistinctItemsByProximity = (items,
|
|
1
|
+
export const getDistinctItemsByProximity = (items, listingEntitiesDetailsInput) => {
|
|
2
2
|
const clusters = {};
|
|
3
3
|
|
|
4
|
-
if (!
|
|
4
|
+
if (!listingEntitiesDetailsInput) return [];
|
|
5
|
+
|
|
6
|
+
const listingEntitiesDetails = Array.isArray(listingEntitiesDetailsInput)
|
|
7
|
+
? listingEntitiesDetailsInput.reduce((acc, entity) => {
|
|
8
|
+
if (entity?.entityKey) acc[entity.entityKey.toLowerCase()] = entity;
|
|
9
|
+
return acc;
|
|
10
|
+
}, {})
|
|
11
|
+
: Object.keys(listingEntitiesDetailsInput).reduce((acc, key) => {
|
|
12
|
+
acc[key.toLowerCase()] = listingEntitiesDetailsInput[key];
|
|
13
|
+
return acc;
|
|
14
|
+
}, {});
|
|
5
15
|
|
|
6
16
|
const closeItemPairs = findCloseItems(listingEntitiesDetails);
|
|
7
17
|
if (closeItemPairs.length > 0) {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
closeItemPairs
|
|
11
|
-
);
|
|
18
|
+
const adjusted = adjustItemPositions(listingEntitiesDetails, closeItemPairs);
|
|
19
|
+
Object.assign(listingEntitiesDetails, adjusted);
|
|
12
20
|
}
|
|
13
21
|
|
|
14
22
|
items?.forEach(item => {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}
|
|
23
|
+
const entityKey = item?.fields?.entityKey;
|
|
24
|
+
if (!entityKey || entityKey === '-1') return;
|
|
25
|
+
const entityDetails = listingEntitiesDetails[entityKey.toLowerCase()];
|
|
26
|
+
if (!entityDetails) {
|
|
27
|
+
console.error(`Details not found for entityKey: ${entityKey}`);
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
23
30
|
|
|
24
|
-
|
|
31
|
+
item.mapDetails = entityDetails;
|
|
25
32
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
|
|
33
|
+
const normalizedEntityKey = entityKey.toLowerCase();
|
|
34
|
+
if (!clusters[normalizedEntityKey]) {
|
|
35
|
+
clusters[normalizedEntityKey] = {
|
|
36
|
+
...entityDetails,
|
|
37
|
+
items: { [item.id]: item }
|
|
38
|
+
};
|
|
39
|
+
} else {
|
|
40
|
+
clusters[normalizedEntityKey].items[item.id] = item;
|
|
41
|
+
}
|
|
34
42
|
});
|
|
35
43
|
|
|
36
44
|
return Object.values(clusters);
|
|
37
45
|
};
|
|
38
46
|
|
|
39
|
-
export const findCloseItems =
|
|
47
|
+
export const findCloseItems = entitiesByKey => {
|
|
40
48
|
const closeItems = [];
|
|
41
|
-
const items = Object.values(
|
|
49
|
+
const items = Object.values(entitiesByKey); // Convert object to array
|
|
42
50
|
const proximityThreshold = 0.0001;
|
|
43
51
|
|
|
44
52
|
for (let i = 0; i < items.length; i++) {
|
|
45
53
|
for (let j = i + 1; j < items.length; j++) {
|
|
46
54
|
const distanceLat = Math.abs(items[i].latitude - items[j].latitude);
|
|
47
55
|
const distanceLng = Math.abs(items[i].longitude - items[j].longitude);
|
|
48
|
-
if (
|
|
49
|
-
distanceLat < proximityThreshold &&
|
|
50
|
-
distanceLng < proximityThreshold
|
|
51
|
-
) {
|
|
56
|
+
if (distanceLat < proximityThreshold && distanceLng < proximityThreshold) {
|
|
52
57
|
closeItems.push({ item1: items[i], item2: items[j] });
|
|
53
58
|
}
|
|
54
59
|
}
|
|
@@ -57,14 +62,18 @@ export const findCloseItems = itemsObj => {
|
|
|
57
62
|
return closeItems;
|
|
58
63
|
};
|
|
59
64
|
|
|
60
|
-
export const adjustItemPositions = (
|
|
65
|
+
export const adjustItemPositions = (entitiesByKey, closeItemPairs) => {
|
|
61
66
|
const adjustmentValue = 0.0001;
|
|
62
|
-
const adjustedItems = { ...
|
|
67
|
+
const adjustedItems = { ...entitiesByKey };
|
|
63
68
|
|
|
64
69
|
closeItemPairs.forEach(pair => {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
adjustedItems[
|
|
70
|
+
const key2 = pair.item2.entityKey;
|
|
71
|
+
if (adjustedItems[key2]) {
|
|
72
|
+
adjustedItems[key2] = {
|
|
73
|
+
...adjustedItems[key2],
|
|
74
|
+
latitude: adjustedItems[key2].latitude + adjustmentValue,
|
|
75
|
+
longitude: adjustedItems[key2].longitude + adjustmentValue
|
|
76
|
+
};
|
|
68
77
|
}
|
|
69
78
|
});
|
|
70
79
|
|
|
@@ -74,13 +83,15 @@ export const adjustItemPositions = (itemsObj, closeItemPairs) => {
|
|
|
74
83
|
export const clusterOptions = (clusterGridSize, fillColor) => {
|
|
75
84
|
return {
|
|
76
85
|
gridSize: clusterGridSize,
|
|
77
|
-
maxZoom:15,
|
|
78
|
-
styles:[
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
86
|
+
maxZoom: 15,
|
|
87
|
+
styles: [
|
|
88
|
+
{
|
|
89
|
+
url: createSvgDataUri(fillColor),
|
|
90
|
+
textColor: 'white',
|
|
91
|
+
height: 40,
|
|
92
|
+
width: 40
|
|
93
|
+
}
|
|
94
|
+
]
|
|
84
95
|
};
|
|
85
96
|
};
|
|
86
97
|
|