{"version":3,"file":"place-search-C4hEpuEp.js","sources":["../../../app/frontend/javascript/hooks/onClickOutside.jsx","../../../app/frontend/javascript/search/context/property-context.jsx","../../../app/frontend/javascript/hooks/retrievePlace.tsx","../../../app/frontend/javascript/components/icons/Pin.tsx","../../../app/frontend/javascript/place-search/components/suggestion.tsx","../../../app/frontend/javascript/place-search/place-search.tsx"],"sourcesContent":["import { useEffect } from \"react\";\n\nconst useOnClickOutside = (ref, handler) => {\n useEffect(\n () => {\n const listener = (event) => {\n // Do nothing if clicking ref's element or descendent elements\n if (!ref.current || ref.current.contains(event.target)) {\n return;\n }\n handler(event);\n };\n document.addEventListener(\"mousedown\", listener);\n document.addEventListener(\"touchstart\", listener);\n return () => {\n document.removeEventListener(\"mousedown\", listener);\n document.removeEventListener(\"touchstart\", listener);\n };\n },\n // Add ref and handler to effect dependencies\n // It's worth noting that because passed in handler is a new ...\n // ... function on every render that will cause this effect ...\n // ... callback/cleanup to run every render. It's not a big deal ...\n // ... but to optimize you can wrap handler in useCallback before ...\n // ... passing it into this hook.\n [ref, handler],\n );\n};\n\nexport default useOnClickOutside;\n","import React, { useState, createContext, useEffect } from \"react\";\n\nconst PropertyContext = createContext();\n\nconst PropertyContextProvider = ({ children }) => {\n const [properties, setProperties] = useState([]);\n const [filters, setFilters] = useState({});\n const [meta, setMeta] = useState({});\n\n const sendToListhub = (properties) => {\n const listhubProperties = properties.reduce((arr, prop) => {\n if (prop.listhub_key) {\n arr.push({ lkey: prop.listhub_key });\n }\n\n return arr;\n }, []);\n\n lh(\"submit\", \"SEARCH_DISPLAY\", listhubProperties);\n };\n\n useEffect(() => {\n getProperties();\n }, [filters]);\n\n useEffect(() => {\n sendToListhub(properties);\n }, [properties]);\n\n const buildUrl = () => {\n let url = `/map/properties?`;\n for (const key in filters) {\n const value = filters[key];\n if (Array.isArray(value)) {\n value.forEach((value) => {\n url += `&${key}[]=${value}`;\n });\n } else {\n url += `&${key}=${value}`;\n }\n }\n\n return url;\n };\n\n const getProperties = async () => {\n if (filters.zoom < 10) return;\n\n try {\n const response = await fetch(buildUrl(), {\n headers: {\n \"Content-Type\": \"application/json\",\n },\n });\n const json = await response.json();\n\n setProperties(json.properties);\n setMeta(json.meta_data);\n } catch (e) {\n console.log(e);\n }\n };\n return (\n \n {children}\n \n );\n};\n\nexport { PropertyContextProvider, PropertyContext };\n","const formatData = (result) => {\n const [lng, lat] = result.geometry.coordinates;\n let city = result.properties.context?.place?.name || result.properties.name;\n let state;\n\n if (result.properties.feature_type == \"region\") {\n state = result.properties.name;\n city = null;\n } else {\n state = result.properties.context?.region?.name;\n }\n\n return {\n lat,\n lng,\n city,\n state,\n featureType: result.properties.feature_type\n };\n};\n\nconst retrievePlaces = async (mapboxId) => {\n const result = await fetch(`/place_suggestions/${mapboxId}`);\n const json = await result.json();\n\n return formatData(json);\n};\n\nexport default retrievePlaces;\n","import React from 'react'\n\nconst Pin = () => (\n \n \n \n \n)\n\nexport default Pin\n","import React from 'react'\nimport { type PlaceSuggestion } from '../../types/types';\nimport Pin from '../../components/icons/Pin';\n\ninterface Props {\n suggestion: PlaceSuggestion\n onSelect: (mapboxId: string) => {}\n}\nconst Suggestion = ({ suggestion, onSelect }: Props) => {\n return (\n onSelect(suggestion.mapbox_id)}>\n
\n
\n \n

{suggestion.name}

\n
\n
\n \n

{suggestion.place_formatted}

\n
\n
\n \n )\n}\n\nexport default Suggestion;","import React, { useCallback, useEffect, useState, useRef, useMemo, useContext, createContext } from 'react'\nimport debounce from '../custom/debounce'\nimport useOnClickOutside from '../hooks/onClickOutside'\nimport { PropertyContext } from '../search/context/property-context'\nimport retrievePlaces from '../hooks/retrievePlace'\nimport Suggestion from './components/suggestion'\n\ninterface Props {\n label?: string\n redirect?: boolean\n place?: string | null\n baseUrl?: string \n onPlaceSelected?: ({lat, lng , city, state}: {lat: string, lng: string, city: string, state: string}) => void\n updateFilters?: boolean\n redirectParams?: string[]\n}\n\nconst PlaceSearch: React.FunctionComponent = ({ onPlaceSelected, label, redirect=true, place, baseUrl, updateFilters=false, redirectParams}) => {\n const placeHolderContext = createContext({\n setFilters: () => {},\n filters: {}\n })\n\n const formattedRedirectParams = useMemo(() => {\n if(redirectParams) {\n return redirectParams.join('&');\n } else {\n return ''\n }\n },[redirectParams])\n const [search, setSearch] = useState(place || '')\n const [places, setPlaces] = useState([])\n const { filters, setFilters } = useContext(updateFilters ? PropertyContext : placeHolderContext)\n\n const listRef = useRef(null)\n const outsideClickCallback = useCallback(() => {\n setPlaces([])\n }, [])\n const domain = useMemo(() =>{\n if (baseUrl) {\n return baseUrl\n } \n\n return ''\n }, [baseUrl])\n\n useOnClickOutside(listRef, outsideClickCallback)\n\n useEffect(() => {\n const params = new URLSearchParams(window.location.search)\n if(params.has('place')) {\n const place = params.get('place')!\n setSearch(place)\n } \n },[])\n\n useEffect(() => {\n if(search && document.activeElement?.id === 'place-search') {\n placesCallBack(search);\n } else { \n setPlaces([]);\n }\n }, [search])\n\n \n \n const getPlaces = async (searchTerm) => {\n const url = new URL(window.location.href.toLowerCase());\n const lat = url.searchParams.get(\"lat\");\n const lng = url.searchParams.get(\"lng\");\n let requestUrl = `${domain}/place_suggestions?query=${searchTerm}`\n if (lat && lng) {\n requestUrl += `&lat=${lat}&lng=${lng}`\n }\n \n try {\n const response = await fetch(requestUrl)\n const results = await response.json()\n setPlaces(results.suggestions)\n } catch(e) {\n // eventually a toast message\n }\n }\n const placesCallBack = useCallback(debounce(getPlaces, 500), [])\n\n const resetSearch = (e) => {\n setSearch('')\n const newFilters = {...filters }\n delete newFilters.city\n delete newFilters.state\n\n const url = new URL(location.href);\n url.searchParams.delete('city')\n url.searchParams.delete('state')\n window.history.replaceState({}, '', url.href) \n \n setFilters(newFilters)\n }\n\n const placeSelectedCallback = async(mapboxId) => {\n const place = await retrievePlaces(mapboxId)\n setZoom(place.featureType)\n setPlaces([])\n const search = place.city === null ? place.state : `${place.city}, ${place.state}`\n setSearch(search)\n logSearch(JSON.stringify(filters), name)\n if(redirect) {\n handleRedirect(place)\n } else {\n onPlaceSelected(place)\n }\n }\n\n const setZoom = (featureType: string) => {\n const newFilters = {...filters }\n\n switch (featureType) {\n case 'address':\n case 'street':\n setFilters({ ...newFilters, zoom: 14 })\n break;\n case 'neighborhood': \n setFilters({ ...newFilters, zoom: 12 })\n default:\n setFilters({ ...newFilters, zoom: 10 })\n break;\n }\n }\n\n const handleRedirect = ({lat, lng, state, city}) => {\n const url = `${domain}/search?lat=${lat}&lng=${lng}&state=${state}&city=${city}&${formattedRedirectParams}&zoom=${filters.zoom}`\n window.location.href = url;\n }\n\n\n const logSearch = async (query, name) => {\n const csrfToken = document.querySelector('meta[name=csrf-token]').content\n const csrfParam = document.querySelector('meta[name=csrf-param]').content\n const body = new FormData();\n body.append(csrfParam, csrfToken)\n body.append('query', query)\n body.append('name', name)\n\n try {\n const result = await fetch(`/log_search`, {\n method: 'POST',\n body\n })\n } catch(e) {\n alert('Something went wrong, please try again.')\n }\n }\n\n const renderPlaces = () => places.map((place)=> {\n return \n })\n\n\n return (\n
\n
\n { setSearch(event.target.value); }} />\n { label && \n \t\n }\n { updateFilters && } \n
\n
\n
    \n {renderPlaces()}\n
\n
\n
\n )\n}\n\nexport default PlaceSearch;\n"],"names":["useOnClickOutside","ref","handler","useEffect","listener","event","PropertyContext","createContext","PropertyContextProvider","children","properties","setProperties","useState","filters","setFilters","meta","setMeta","sendToListhub","listhubProperties","arr","prop","getProperties","buildUrl","url","key","value","json","e","React","formatData","result","lng","lat","city","_b","_a","state","_d","_c","retrievePlaces","mapboxId","Pin","Suggestion","suggestion","onSelect","PlaceSearch","onPlaceSelected","label","redirect","place","baseUrl","updateFilters","redirectParams","placeHolderContext","formattedRedirectParams","useMemo","search","setSearch","places","setPlaces","useContext","listRef","useRef","outsideClickCallback","useCallback","domain","params","placesCallBack","getPlaces","searchTerm","requestUrl","results","debounce","resetSearch","newFilters","placeSelectedCallback","setZoom","logSearch","handleRedirect","featureType","query","name","csrfToken","csrfParam","body","renderPlaces"],"mappings":"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"}