@abcagency/hc-ui-components 1.0.0
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/globals.css +3 -0
- package/dist/index.js +4644 -0
- package/dist/output.css +784 -0
- package/dist/services/globals.css +3 -0
- package/dist/services/listingService.js +606 -0
- package/package.json +38 -0
- package/postcss.config.js +15 -0
- package/rollup.config.js +67 -0
- package/src/apis/hcApi.js +68 -0
- package/src/clientToken.js +9 -0
- package/src/components/layout/footer.js +34 -0
- package/src/components/layout/header.js +23 -0
- package/src/components/layout/layout.js +36 -0
- package/src/components/modules/accordions/MapAccordionItem.js +69 -0
- package/src/components/modules/accordions/default.js +173 -0
- package/src/components/modules/accordions/filterItem.js +53 -0
- package/src/components/modules/accordions/filters.js +44 -0
- package/src/components/modules/animations/slidein.js +41 -0
- package/src/components/modules/buttons/button-group-apply.js +75 -0
- package/src/components/modules/buttons/commute-pill.js +21 -0
- package/src/components/modules/buttons/default.js +196 -0
- package/src/components/modules/buttons/items-pill.js +31 -0
- package/src/components/modules/buttons/pill-wrapper.js +26 -0
- package/src/components/modules/buttons/show-all-button.js +20 -0
- package/src/components/modules/cards/default.js +168 -0
- package/src/components/modules/cards/filter.js +55 -0
- package/src/components/modules/dialogs/apply-dialog.js +47 -0
- package/src/components/modules/filter/commute.js +149 -0
- package/src/components/modules/filter/index.js +86 -0
- package/src/components/modules/filter/item.js +77 -0
- package/src/components/modules/filter/location.js +69 -0
- package/src/components/modules/filter/points-of-interest.js +43 -0
- package/src/components/modules/filter/radio-item.js +51 -0
- package/src/components/modules/filter/search.js +89 -0
- package/src/components/modules/filter/search.js.rej +9 -0
- package/src/components/modules/filter/sort.js +83 -0
- package/src/components/modules/form.js +362 -0
- package/src/components/modules/grid.js +75 -0
- package/src/components/modules/icon.js +33 -0
- package/src/components/modules/jobListing/listing-details.js +87 -0
- package/src/components/modules/jumbotron.js +81 -0
- package/src/components/modules/maps/info-window-card.js +17 -0
- package/src/components/modules/maps/info-window-content.js +60 -0
- package/src/components/modules/maps/list/field-mapper.js +113 -0
- package/src/components/modules/maps/list/header-item.js +90 -0
- package/src/components/modules/maps/list/header.js +46 -0
- package/src/components/modules/maps/list/index.js +104 -0
- package/src/components/modules/maps/list/item-expand-card/index.js +21 -0
- package/src/components/modules/maps/list/item-expand-card/recruiter-contact-nav.js +48 -0
- package/src/components/modules/maps/list/item-expand-card/recruiter-details.js +67 -0
- package/src/components/modules/maps/list/item-expand-card/recruiter-headshot.js +22 -0
- package/src/components/modules/maps/list/list-item/index.js +133 -0
- package/src/components/modules/maps/map-list.js +73 -0
- package/src/components/modules/maps/map-marker.js +84 -0
- package/src/components/modules/maps/map.js +218 -0
- package/src/components/modules/maps/place-marker.js +41 -0
- package/src/components/modules/maps/tabs.js +79 -0
- package/src/components/modules/navigation/nav-link.js +65 -0
- package/src/components/modules/navigation/navbar.js +109 -0
- package/src/components/modules/navigation/skip-link.js +21 -0
- package/src/components/modules/navigation/social.js +29 -0
- package/src/components/modules/sections/default.js +59 -0
- package/src/components/modules/sections/sectionContext.js +4 -0
- package/src/components/modules/video-player.js +126 -0
- package/src/constants/placeTypes.js +8 -0
- package/src/contexts/mapContext.js +116 -0
- package/src/contexts/mapListContext.js +212 -0
- package/src/contexts/placesContext.js +98 -0
- package/src/hooks/useClickOutside.js +16 -0
- package/src/hooks/useEventListener.js +25 -0
- package/src/hooks/useEventTracker.js +19 -0
- package/src/hooks/useList.js +102 -0
- package/src/hooks/useRefScrollProgress.js +24 -0
- package/src/hooks/useScript.js +63 -0
- package/src/hooks/useScrollDirection.js +39 -0
- package/src/hooks/useSectionTracker.js +95 -0
- package/src/hooks/useUserAgent.js +43 -0
- package/src/hooks/useWindowSize.js +28 -0
- package/src/index.css +25 -0
- package/src/index.js +116 -0
- package/src/services/configService.js +16 -0
- package/src/services/googlePlacesNearbyService.js +33 -0
- package/src/services/listingAggregatorService.js +42 -0
- package/src/services/listingEntityService.js +14 -0
- package/src/services/listingService.js +28 -0
- package/src/services/recruiterService.js +17 -0
- package/src/styles/fonts.js +0 -0
- package/src/styles/globals.css +25 -0
- package/src/tailwind/preset.default.js +15 -0
- package/src/tailwind/tailwind.config.js +126 -0
- package/src/util/arrayUtil.js +3 -0
- package/src/util/fieldMapper.js +19 -0
- package/src/util/filterUtil.js +195 -0
- package/src/util/loading.js +17 -0
- package/src/util/localStorageUtil.js +27 -0
- package/src/util/mapIconUtil.js +179 -0
- package/src/util/mapUtil.js +91 -0
- package/src/util/page-head.js +62 -0
- package/src/util/provider.js +12 -0
- package/src/util/sortUtil.js +33 -0
- package/src/util/stringUtils.js +6 -0
- package/src/util/urlFilterUtil.js +91 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export const getStorageObject = (item, defaultItem = null) =>{
|
|
2
|
+
if(typeof window == 'undefined') return defaultItem;
|
|
3
|
+
if(localStorage.getItem(item) == null) return defaultItem;
|
|
4
|
+
if(localStorage.getItem(item) == 'undefined'){
|
|
5
|
+
localStorage.removeItem(item);
|
|
6
|
+
}
|
|
7
|
+
return JSON.parse(localStorage.getItem(item)) ?? defaultItem;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export const getStorageItem = (item, defaultItem = null) =>{
|
|
11
|
+
if(typeof window == 'undefined') return defaultItem;
|
|
12
|
+
if(localStorage.getItem(item) == null) return defaultItem;
|
|
13
|
+
if(localStorage.getItem(item) == 'undefined'){
|
|
14
|
+
localStorage.removeItem(item);
|
|
15
|
+
}
|
|
16
|
+
return localStorage.getItem(item) ?? defaultItem;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const setStorageObject = (key, item) =>{
|
|
20
|
+
if(typeof window == 'undefined') return;
|
|
21
|
+
if(item == undefined)return;
|
|
22
|
+
try{
|
|
23
|
+
localStorage.setItem(key, JSON.stringify(item));
|
|
24
|
+
}catch(err){
|
|
25
|
+
console.log(err);
|
|
26
|
+
}
|
|
27
|
+
};
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { placeTypes } from "../constants/placeTypes";
|
|
2
|
+
import { useLoadScript } from "@react-google-maps/api";
|
|
3
|
+
|
|
4
|
+
const customSVGIcon = (
|
|
5
|
+
type,
|
|
6
|
+
fillColor = "#FFFFFF",
|
|
7
|
+
strokeColor = "#000000",
|
|
8
|
+
backgroundFill = "#000000",
|
|
9
|
+
backgroundStroke = "#000000",
|
|
10
|
+
) => {
|
|
11
|
+
let svg = "";
|
|
12
|
+
switch (type) {
|
|
13
|
+
case placeTypes.FOOD:
|
|
14
|
+
svg = `
|
|
15
|
+
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
|
16
|
+
viewBox="0 0 60.8 89.6" preserveAspectRatio="xMidYMid meet" style="enable-background:new 0 0 60.8 89.6;" xml:space="preserve">
|
|
17
|
+
<style type="text/css">
|
|
18
|
+
.st0{fill:${fillColor}; stroke:${strokeColor};}
|
|
19
|
+
.svg-background{fill:${backgroundFill}; stroke:${backgroundStroke};}
|
|
20
|
+
</style>
|
|
21
|
+
<path class="svg-background" d="M30.4,3.9C14.3,3.9,1.3,16.8,1.3,33c0,21,18.6,29.1,29.1,56.6C40.9,62.1,59.5,54.9,59.5,33C60.3,16.8,46.6,3.9,30.4,3.9z"/>
|
|
22
|
+
<path class="st0" d="M25.7,36.6l0.6,15.8c0.1,2.4-2.3,2.4-2.3,2.4s-2.4,0-2.3-2.4l0.6-15.8c0.1-2-4.3-2.9-4-4.9l2.3-13.3h1.1
|
|
23
|
+
l-0.6,9.7l1.7,1.2l0.6-10.9h1.1l0.6,10.9l1.7-1.2l-0.6-9.7h1.1l2.3,13.3C29.7,33.7,25.6,34.6,25.7,36.6z"/>
|
|
24
|
+
<path class="st0" d="M40,52.4c0,2.4-2.3,2.4-2.3,2.4s-2.5,0-2.3-2.4L36.6,39c-0.9,0-3.4-0.4-3.4-2.4v-6.1c0-2.4,0.3-6.4,1.2-8.2
|
|
25
|
+
c1.1-2.4,3.9-4,5.6-4C40,18.3,40,52.4,40,52.4z"/>
|
|
26
|
+
</svg>
|
|
27
|
+
`;
|
|
28
|
+
break;
|
|
29
|
+
case placeTypes.TOURIST_ATTRACTION:
|
|
30
|
+
svg = `<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
|
31
|
+
viewBox="0 0 60.8 89.6" preserveAspectRatio="xMidYMid meet" style="enable-background:new 0 0 60.8 89.6;" xml:space="preserve">
|
|
32
|
+
<style type="text/css">
|
|
33
|
+
.st0{fill:${fillColor}; stroke:${strokeColor};}
|
|
34
|
+
.svg-background{fill:${backgroundFill}; stroke:${backgroundStroke};}
|
|
35
|
+
</style>
|
|
36
|
+
<path class="svg-background" d="M30.4,3.9C14.3,3.9,1.3,16.8,1.3,33c0,21,18.6,29.1,29.1,56.6C40.9,62.1,59.5,54.9,59.5,33C60.3,16.8,46.6,3.9,30.4,3.9z"/>
|
|
37
|
+
<path class="st0" d="M27,18.5c-1.2,0-1.7,1.1-2.2,2.2L23.7,23h-4.5c-1.9,0-3.4,1.5-3.4,3.4v11.2c0,1.9,1.5,3.4,3.4,3.4h22.5
|
|
38
|
+
c1.9,0,3.4-1.5,3.4-3.4V26.4c0-1.9-1.5-3.4-3.4-3.4h-4.5L36,20.8c-0.6-1.1-1-2.2-2.2-2.2H27z M19.2,25.3c0.6,0,1.1,0.5,1.1,1.1
|
|
39
|
+
c0,0.6-0.5,1.1-1.1,1.1c-0.6,0-1.1-0.5-1.1-1.1C18,25.8,18.5,25.3,19.2,25.3z M30.4,25.3c3.7,0,6.7,3,6.7,6.7s-3,6.7-6.7,6.7
|
|
40
|
+
s-6.7-3-6.7-6.7S26.7,25.3,30.4,25.3z M30.4,28.7c-1.9,0-3.4,1.5-3.4,3.4s1.5,3.4,3.4,3.4c1.9,0,3.4-1.5,3.4-3.4
|
|
41
|
+
S32.3,28.7,30.4,28.7z"/>
|
|
42
|
+
</svg>
|
|
43
|
+
`;
|
|
44
|
+
break;
|
|
45
|
+
case placeTypes.SCHOOL:
|
|
46
|
+
svg = `
|
|
47
|
+
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
|
48
|
+
viewBox="0 0 60.8 89.6" preserveAspectRatio="xMidYMid meet" style="enable-background:new 0 0 60.8 89.6;" xml:space="preserve">
|
|
49
|
+
<style type="text/css">
|
|
50
|
+
.st0{fill:${fillColor}; stroke:${strokeColor};}
|
|
51
|
+
.svg-background{fill:${backgroundFill}; stroke:${backgroundStroke};}
|
|
52
|
+
</style>
|
|
53
|
+
<path class="svg-background" d="M30.4,3.9C14.3,3.9,1.3,16.8,1.3,33c0,21,18.6,29.1,29.1,56.6C40.9,62.1,59.5,54.9,59.5,33C60.3,16.8,46.6,3.9,30.4,3.9z"/>
|
|
54
|
+
<path class="st0" d="M39.2,40.6c0,0-4.1,4.6-9.1,4.6S21,40.6,21,40.6v-5.2l9.1,5l9.1-5V40.6z"/>
|
|
55
|
+
<polygon class="st0" points="44.4,40.4 41.8,40.4 41.8,31.4 30.1,37.8 15.8,30 30.1,22.2 44.4,30 "/>
|
|
56
|
+
</svg>
|
|
57
|
+
`;
|
|
58
|
+
break;
|
|
59
|
+
case placeTypes.STORE:
|
|
60
|
+
svg = `<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
|
61
|
+
viewBox="0 0 60.8 89.6" preserveAspectRatio="xMidYMid meet" style="enable-background:new 0 0 60.8 89.6;" xml:space="preserve">
|
|
62
|
+
<style type="text/css">
|
|
63
|
+
.st0{fill:${fillColor}; stroke:${strokeColor};}
|
|
64
|
+
.svg-background{fill:${backgroundFill}; stroke:${backgroundStroke};}
|
|
65
|
+
</style>
|
|
66
|
+
<g>
|
|
67
|
+
<path class="svg-background" d="M30.4,3.9C14.3,3.9,1.3,16.8,1.3,33c0,21,18.6,29.1,29.1,56.6C40.9,62.1,59.5,54.9,59.5,33C60.3,16.8,46.6,3.9,30.4,3.9z"
|
|
68
|
+
/>
|
|
69
|
+
</g>
|
|
70
|
+
<path class="st0" d="M45.4,27.7L42,41.1c-0.1,0.6-0.7,1-1.3,1c1.8,0,3.3,1.5,3.3,3.3s-1.5,3.3-3.3,3.3s-3.3-1.5-3.3-3.3
|
|
71
|
+
s1.5-3.3,3.3-3.3H23.3c1.8,0,3.3,1.5,3.3,3.3s-1.5,3.3-3.3,3.3S20,47.2,20,45.4s1.5-3.3,3.3-3.3c-0.6,0-1.2-0.4-1.3-1l-4.1-16.4
|
|
72
|
+
h-1.3c-0.7,0-1.3-0.6-1.3-1.3s0.6-1.3,1.3-1.3h2.3c0.6,0,1.2,0.4,1.3,1l0.8,3h23.1c0.4,0,0.8,0.2,1.1,0.5
|
|
73
|
+
C45.4,26.9,45.5,27.3,45.4,27.7z"/>
|
|
74
|
+
<path d="M41.4,45.5c0-0.4-0.3-0.7-0.7-0.7S40,45.1,40,45.5C40.1,46.2,41.4,46.2,41.4,45.5z"/>
|
|
75
|
+
<path d="M24,45.5c0-0.4-0.3-0.7-0.7-0.7s-0.7,0.3-0.7,0.7C22.6,46.2,24,46.2,24,45.5z"/>
|
|
76
|
+
</svg>
|
|
77
|
+
`;
|
|
78
|
+
break;
|
|
79
|
+
case placeTypes.TRANSIT_STATION:
|
|
80
|
+
svg = `<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
|
81
|
+
viewBox="0 0 60.8 89.6" preserveAspectRatio="xMidYMid meet" style="enable-background:new 0 0 60.8 89.6;" xml:space="preserve">
|
|
82
|
+
<style type="text/css">
|
|
83
|
+
.st0{fill:${fillColor}; stroke:${strokeColor};}
|
|
84
|
+
.svg-background{fill:${backgroundFill}; stroke:${backgroundStroke};}
|
|
85
|
+
</style>
|
|
86
|
+
<g>
|
|
87
|
+
<path class="svg-background" d="M30.4,3.9C14.3,3.9,1.3,16.8,1.3,33c0,21,18.6,29.1,29.1,56.6C40.9,62.1,59.5,54.9,59.5,33C60.3,16.8,46.6,3.9,30.4,3.9z"
|
|
88
|
+
/>
|
|
89
|
+
</g>
|
|
90
|
+
<path class="st0" d="M26.3,41.3h-2.8L20.7,44h-1.4v-1.4l1.4-1.4c-2.3,0-4.2-1.9-4.2-4.2V26c0-2.3,1.9-4.2,4.2-4.2h9.7
|
|
91
|
+
c2.3,0,4.2,1.9,4.2,4.2v1.4h-2.8v-2.8H19.3v9.7h6.9v7H26.3z"/>
|
|
92
|
+
<path class="st0" d="M44.3,43c0,0.5-0.4,1-1,1h-0.8c-0.5,0-1-0.5-1-1.1v-1.7H30.4V43c0,0.5-0.4,1.1-0.9,1.1h-0.9c-0.5,0-1-0.5-1-1
|
|
93
|
+
v-7.6l2-5.7c0.2-0.6,0.7-0.9,1.4-0.9h10c0.6,0,1.1,0.4,1.3,0.9l2,5.7V43z"/>
|
|
94
|
+
<circle cx="20.7" cy="37.1" r="1.4"/>
|
|
95
|
+
<circle cx="41.5" cy="37.1" r="1.4"/>
|
|
96
|
+
<circle cx="30.4" cy="37.1" r="1.4"/>
|
|
97
|
+
<polygon points="31,30.2 29.6,34.4 42.4,34.4 40.9,30.2 "/>
|
|
98
|
+
</svg>
|
|
99
|
+
`;
|
|
100
|
+
break;
|
|
101
|
+
case placeTypes.PLACE_OF_WORSHIP:
|
|
102
|
+
svg = `<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
|
103
|
+
viewBox="0 0 60.8 89.6" style="enable-background:new 0 0 60.8 89.6;" xml:space="preserve">
|
|
104
|
+
<style type="text/css">
|
|
105
|
+
.st0{fill:${fillColor}; stroke:${strokeColor};}
|
|
106
|
+
.svg-background{fill:${backgroundFill}; stroke:${backgroundStroke};}
|
|
107
|
+
</style>
|
|
108
|
+
<path class="svg-background" d="M30.4,3.9C14.3,3.9,1.3,16.8,1.3,33c0,21,18.6,29.1,29.1,56.6C40.9,62.1,59.5,54.9,59.5,33C60.3,16.8,46.6,3.9,30.4,3.9z"/>
|
|
109
|
+
<path class="st0" d="M21.3,40.8h-3.8c-1.3,0-2.3-1-2.3-2.3v-4.3c0-0.8,0.5-1.6,1.2-2l4.9-2.7V40.8z"/>
|
|
110
|
+
<path class="st0" d="M38,40.8h-4.6v-4.6c0-1.7-1.4-3-3-3c-1.7,0-3,1.4-3,3v4.6h-4.6V30c0-0.8,0.4-1.5,1.1-2l1.9-1.2v-5.1l0,0
|
|
111
|
+
c0-0.4,0.2-0.8,0.4-1.1l3.6-3.6c0.3-0.3,0.8-0.3,1.1,0l3.6,3.6c0.3,0.3,0.4,0.7,0.4,1.1v5.1l1.9,1.2c0.7,0.4,1.1,1.2,1.1,2L38,40.8
|
|
112
|
+
L38,40.8z"/>
|
|
113
|
+
<path class="st0" d="M45.6,38.5c0,1.3-1,2.3-2.3,2.3h-3.8V29.5l4.9,2.7c0.7,0.4,1.2,1.2,1.2,2C45.6,34.2,45.6,38.5,45.6,38.5z"/>
|
|
114
|
+
</svg>
|
|
115
|
+
`;
|
|
116
|
+
break;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const iconUrl = `data:image/svg+xml;utf8,${encodeURIComponent(svg)}`;
|
|
120
|
+
return iconUrl;
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
export const iconPath = "M5.5 0A5.27 5.27 0 0 0 0 5.01v.49c0 1.73 1.38 3.43 2.07 4.12s3.43 4.12 3.43 4.12 2.75-3.43 3.43-4.12 2.06-2.39 2.06-4.12c.14-2.9-2.1-5.36-5-5.5H5.5Zm-.04 5.71c-.32 0-.57-.27-.56-.58 0-.32.27-.57.58-.56.32 0 .57.27.56.58 0 .31-.25.55-.56.56h-.02Z";
|
|
124
|
+
|
|
125
|
+
export const markerIconProps = (placeMarkerConfigs, type) => {
|
|
126
|
+
|
|
127
|
+
const scaledWidth = placeMarkerConfigs.size;
|
|
128
|
+
const scaledHeight = (scaledWidth * 3) / 2;
|
|
129
|
+
const iconUrl = customSVGIcon(
|
|
130
|
+
type,
|
|
131
|
+
placeMarkerConfigs.colors.innerFillColor,
|
|
132
|
+
placeMarkerConfigs.colors.innerStrokeColor,
|
|
133
|
+
placeMarkerConfigs.colors.outerFillColor,
|
|
134
|
+
placeMarkerConfigs.colors.outerStrokeColor,
|
|
135
|
+
);
|
|
136
|
+
return {
|
|
137
|
+
url: iconUrl,
|
|
138
|
+
scaledSize: new google.maps.Size(scaledWidth, scaledHeight),
|
|
139
|
+
anchor: new google.maps.Point(scaledWidth / 2, scaledHeight)
|
|
140
|
+
};
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
export const iconProps = () => {
|
|
144
|
+
return {
|
|
145
|
+
path: iconPath,
|
|
146
|
+
fillOpacity: 1,
|
|
147
|
+
strokeWeight: 1.75,
|
|
148
|
+
scale: 1.6,
|
|
149
|
+
anchor: new google.maps.Point(12, 17)
|
|
150
|
+
};
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
export const markerIcon = markerConfigs => {
|
|
154
|
+
return {
|
|
155
|
+
...iconProps(),
|
|
156
|
+
fillColor: markerConfigs.fillColor,
|
|
157
|
+
strokeColor: markerConfigs.strokeColor
|
|
158
|
+
};
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
export const markerIconSelected = markerConfigs => {
|
|
162
|
+
return { ...iconProps(),
|
|
163
|
+
fillColor: markerConfigs.selectedFillColor,
|
|
164
|
+
strokeColor: markerConfigs.selectedStrokeColor
|
|
165
|
+
};
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
export const pinIcon = markerConfigs => {
|
|
169
|
+
const { fillColor, strokeColor } = markerConfigs;
|
|
170
|
+
|
|
171
|
+
const svg = `
|
|
172
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="30" height="30" viewBox="-6 -4 24 24">
|
|
173
|
+
<path d="${iconPath}" fill="${fillColor}" stroke="${strokeColor}" stroke-width="2"/>
|
|
174
|
+
</svg>
|
|
175
|
+
`;
|
|
176
|
+
|
|
177
|
+
return `data:image/svg+xml;utf8,${encodeURIComponent(svg)}`;
|
|
178
|
+
};
|
|
179
|
+
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
export const getDistinctItemsByProximity = (items, listingEntitiesDetails) => {
|
|
2
|
+
const clusters = {};
|
|
3
|
+
|
|
4
|
+
if (!listingEntitiesDetails) return [];
|
|
5
|
+
|
|
6
|
+
const closeItemPairs = findCloseItems(listingEntitiesDetails);
|
|
7
|
+
if (closeItemPairs.length > 0) {
|
|
8
|
+
listingEntitiesDetails = adjustItemPositions(
|
|
9
|
+
listingEntitiesDetails,
|
|
10
|
+
closeItemPairs,
|
|
11
|
+
);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
items?.forEach(item => {
|
|
15
|
+
if(item.entityId !== -1){
|
|
16
|
+
|
|
17
|
+
const entityDetails = listingEntitiesDetails[item.entityId];
|
|
18
|
+
|
|
19
|
+
if (!entityDetails) {
|
|
20
|
+
console.error(`Details not found for entityId: ${item.entityId}`);
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
item.mapDetails = entityDetails;
|
|
25
|
+
|
|
26
|
+
if (!clusters[item.entityId]) {
|
|
27
|
+
clusters[item.entityId] = {
|
|
28
|
+
...item.mapDetails,
|
|
29
|
+
items: { [item.id]: item }
|
|
30
|
+
};
|
|
31
|
+
} else {
|
|
32
|
+
clusters[item.entityId].items[item.id] = item;
|
|
33
|
+
}}
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
return Object.values(clusters);
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export const findCloseItems = itemsObj => {
|
|
40
|
+
const closeItems = [];
|
|
41
|
+
const items = Object.values(itemsObj); // Convert object to array for iteration
|
|
42
|
+
const proximityThreshold = 0.0001;
|
|
43
|
+
|
|
44
|
+
for (let i = 0; i < items.length; i++) {
|
|
45
|
+
for (let j = i + 1; j < items.length; j++) {
|
|
46
|
+
const distanceLat = Math.abs(items[i].latitude - items[j].latitude);
|
|
47
|
+
const distanceLng = Math.abs(items[i].longitude - items[j].longitude);
|
|
48
|
+
if (
|
|
49
|
+
distanceLat < proximityThreshold &&
|
|
50
|
+
distanceLng < proximityThreshold
|
|
51
|
+
) {
|
|
52
|
+
closeItems.push({ item1: items[i], item2: items[j] });
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return closeItems;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export const adjustItemPositions = (itemsObj, closeItemPairs) => {
|
|
61
|
+
const adjustmentValue = 0.0001;
|
|
62
|
+
const adjustedItems = { ...itemsObj }; // Create a shallow copy of the object
|
|
63
|
+
|
|
64
|
+
closeItemPairs.forEach(pair => {
|
|
65
|
+
if (adjustedItems[pair.item1.id] && adjustedItems[pair.item2.id]) {
|
|
66
|
+
adjustedItems[pair.item2.id].latitude += adjustmentValue;
|
|
67
|
+
adjustedItems[pair.item2.id].longitude += adjustmentValue;
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
return adjustedItems;
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
export const clusterOptions = (clusterGridSize, fillColor) => {
|
|
75
|
+
return {
|
|
76
|
+
gridSize: clusterGridSize,
|
|
77
|
+
styles:[{
|
|
78
|
+
url: createSvgDataUri(fillColor),
|
|
79
|
+
textColor:'white',
|
|
80
|
+
height: 40,
|
|
81
|
+
width: 40
|
|
82
|
+
}]
|
|
83
|
+
};
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
function createSvgDataUri(fillColor) {
|
|
87
|
+
const svg = `<svg width="50" height="50" xmlns="http://www.w3.org/2000/svg">
|
|
88
|
+
<circle cx="25" cy="25" r="20" fill="${fillColor}" />
|
|
89
|
+
</svg>`;
|
|
90
|
+
return `data:image/svg+xml;base64,${btoa(svg)}`;
|
|
91
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { useMapList } from "~/contexts/mapListContext";
|
|
2
|
+
import React from 'react';
|
|
3
|
+
const PageHead = ({
|
|
4
|
+
description,
|
|
5
|
+
keywords,
|
|
6
|
+
title
|
|
7
|
+
}) => {
|
|
8
|
+
const {siteConfig} = useMapList();
|
|
9
|
+
//const router = useRouter();
|
|
10
|
+
const defaultTitle = siteConfig.title;
|
|
11
|
+
const pageTitle = title || defaultTitle;
|
|
12
|
+
const metaDescription = description || siteConfig.description;
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
<div>
|
|
16
|
+
<title>{title ? `${title} | ${defaultTitle}` : defaultTitle}</title>
|
|
17
|
+
<meta name="description" content={metaDescription} />
|
|
18
|
+
{keywords?.length > 0
|
|
19
|
+
? (
|
|
20
|
+
<meta name="keywords" content={`${keywords.join(', ')}`} />
|
|
21
|
+
) : null
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
<meta property="og:title" content={pageTitle} />
|
|
25
|
+
<meta property="og:description" content={metaDescription} />
|
|
26
|
+
{siteConfig?.shareImage &&
|
|
27
|
+
<meta property="og:image" content={`/${siteConfig.shareImage}`} />
|
|
28
|
+
}
|
|
29
|
+
<meta property="og:type" content="website" />
|
|
30
|
+
|
|
31
|
+
<meta name="twitter:card" content="summary" />
|
|
32
|
+
<meta name="twitter:creator" content={siteConfig?.author} />
|
|
33
|
+
<meta name="twitter:title" content={pageTitle} />
|
|
34
|
+
<meta name="twitter:description" content={metaDescription} />
|
|
35
|
+
<script type="application/ld+json">
|
|
36
|
+
{`
|
|
37
|
+
{
|
|
38
|
+
"@context": "https://schema.org",
|
|
39
|
+
"@type": "WebPage",
|
|
40
|
+
"url": "pathame",
|
|
41
|
+
"legalName": "${defaultTitle}",
|
|
42
|
+
"name": "${pageTitle}",
|
|
43
|
+
"about": "${metaDescription}",
|
|
44
|
+
"brand": "${defaultTitle}"
|
|
45
|
+
}
|
|
46
|
+
`}
|
|
47
|
+
</script>
|
|
48
|
+
|
|
49
|
+
<link rel="icon" href="/favicon.svg" type="image/svg+xml" />
|
|
50
|
+
|
|
51
|
+
{/* Only show these in Production */}
|
|
52
|
+
{'' !== 'development' && <>
|
|
53
|
+
<link rel="icon" href="/favicon.ico" sizes="any" />
|
|
54
|
+
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
|
|
55
|
+
<link rel="manifest" href="/manifest.webmanifest" />
|
|
56
|
+
<meta name="msapplication-TileColor" content={siteConfig?.colors?.manifest?.tileColor ?? '#000'} />
|
|
57
|
+
</>}
|
|
58
|
+
</div>
|
|
59
|
+
);
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export default PageHead;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export const dynamicSort = (items, fieldName, order = "asc") => {
|
|
2
|
+
if (!items || !items.length) {
|
|
3
|
+
return [];
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
const inferType = value => {
|
|
7
|
+
if (!isNaN(Date.parse(value)) && isNaN(value)) {
|
|
8
|
+
return "date";
|
|
9
|
+
} else if (!isNaN(parseFloat(value)) && isFinite(value)) {
|
|
10
|
+
return "number";
|
|
11
|
+
} else {
|
|
12
|
+
return "string";
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const dataType = inferType(items[0].fields[fieldName]);
|
|
17
|
+
|
|
18
|
+
return items.sort((a, b) => {
|
|
19
|
+
let valA = a.fields[fieldName];
|
|
20
|
+
let valB = b.fields[fieldName];
|
|
21
|
+
if (!valA || !valB) return;
|
|
22
|
+
let comparison = 0;
|
|
23
|
+
|
|
24
|
+
if (dataType === "string") {
|
|
25
|
+
comparison = valA.localeCompare(valB);
|
|
26
|
+
} else if (dataType === "number") {
|
|
27
|
+
comparison = valA - valB;
|
|
28
|
+
} else if (dataType === "date") {
|
|
29
|
+
comparison = new Date(valA) - new Date(valB);
|
|
30
|
+
}
|
|
31
|
+
return order === "desc" ? comparison * -1 : comparison;
|
|
32
|
+
});
|
|
33
|
+
};
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
export const updateURLWithFilters = (filters, location, navigate, query) => {
|
|
2
|
+
console.log("attempting to update url");
|
|
3
|
+
console.log(filters);
|
|
4
|
+
console.log(location);
|
|
5
|
+
console.log(navigate);
|
|
6
|
+
console.log(query);
|
|
7
|
+
|
|
8
|
+
const searchParams = new URLSearchParams();
|
|
9
|
+
|
|
10
|
+
// Add the new filters to search params
|
|
11
|
+
Object.keys(filters).forEach(category => {
|
|
12
|
+
Object.keys(filters[category]).forEach(filter => {
|
|
13
|
+
if (filters[category][filter]) {
|
|
14
|
+
const key = `${category}.${filter}`;
|
|
15
|
+
searchParams.set(key, 'true');
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
// Add the query to search params if it exists
|
|
21
|
+
if (query) {
|
|
22
|
+
searchParams.set('query', query);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
navigate({
|
|
26
|
+
search: searchParams.toString(),
|
|
27
|
+
}, { replace: true });
|
|
28
|
+
|
|
29
|
+
notifyParentOfUrlChange();
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
function notifyParentOfUrlChange() {
|
|
33
|
+
setTimeout(() => {
|
|
34
|
+
var message = {
|
|
35
|
+
type: 'URL_CHANGE',
|
|
36
|
+
url: window.location.href
|
|
37
|
+
};
|
|
38
|
+
window.parent.postMessage(message, "*");
|
|
39
|
+
}, 500);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export const parseQueryParams = search => {
|
|
43
|
+
const queryParams = {};
|
|
44
|
+
if (!search) return queryParams;
|
|
45
|
+
let queryString = search.split('?')[1];
|
|
46
|
+
if (!queryString) {
|
|
47
|
+
return queryParams;
|
|
48
|
+
}
|
|
49
|
+
queryString = queryString.replaceAll('+', ' ');
|
|
50
|
+
queryString.split('&').forEach(param => {
|
|
51
|
+
const [key, value] = param.split('=');
|
|
52
|
+
queryParams[decodeURIComponent(key)] = decodeURIComponent(value);
|
|
53
|
+
});
|
|
54
|
+
return queryParams;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export const filtersFromURL = location => {
|
|
58
|
+
if (!location || !location.search) return;
|
|
59
|
+
const filters = {};
|
|
60
|
+
let queryParam = null;
|
|
61
|
+
const queryParams = parseQueryParams(location.search);
|
|
62
|
+
if (!queryParams) return;
|
|
63
|
+
Object.keys(queryParams).forEach(key => {
|
|
64
|
+
if (key && key.includes('.')) {
|
|
65
|
+
const [category, filter] = key.split('.');
|
|
66
|
+
if (!filters[category]) {
|
|
67
|
+
filters[category] = {};
|
|
68
|
+
}
|
|
69
|
+
filters[category][filter] = queryParams[key] === 'true';
|
|
70
|
+
} else if (key === 'query') {
|
|
71
|
+
queryParam = queryParams[key];
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
return { filters, query: queryParam };
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
export const hasFiltersInURL = location => {
|
|
79
|
+
if (!location || !location.search) return;
|
|
80
|
+
const queryParams = parseQueryParams(location.search);
|
|
81
|
+
if (!queryParams) return;
|
|
82
|
+
return Object.keys(queryParams).some(key => key.includes('.'));
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
export const hasQueryInUrl = location => {
|
|
86
|
+
console.log(location);
|
|
87
|
+
if (!location || !location.search) return;
|
|
88
|
+
const queryParams = parseQueryParams(location.search);
|
|
89
|
+
if (!queryParams) return;
|
|
90
|
+
return Object.keys(queryParams).includes('query');
|
|
91
|
+
};
|