{"id":13344365,"url":"https://github.com/yujhenchen/nearby-places-react-leaflet-overpass-api","last_synced_at":"2026-04-18T04:35:44.458Z","repository":{"id":192231176,"uuid":"686294659","full_name":"yujhenchen/nearby-places-react-leaflet-overpass-api","owner":"yujhenchen","description":"A finding nearby places app built with React, Vite, Flowbite, Tailwind CSS, leafletjs, React Leaflet, Overpass API, zustand, and TypeScript","archived":false,"fork":false,"pushed_at":"2024-06-06T15:19:55.000Z","size":8711,"stargazers_count":5,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-07-30T21:09:55.519Z","etag":null,"topics":["flowbite","front-end","frontend","leafletjs","netlify","openstreetmap","overpass-api","react","react-leaflet","tailwind-css","typescript","vite","zustand"],"latest_commit_sha":null,"homepage":"https://jen-nearby-places-react-vite.netlify.app/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/yujhenchen.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-09-02T10:14:07.000Z","updated_at":"2024-06-07T18:07:03.000Z","dependencies_parsed_at":"2023-09-10T03:24:41.823Z","dependency_job_id":"d8f42124-8c62-4c03-b68b-f61e5427fd57","html_url":"https://github.com/yujhenchen/nearby-places-react-leaflet-overpass-api","commit_stats":null,"previous_names":["yujhenchen/restaurant-map-react-vite","yujhenchen/nearby-places-react-leaflet-overpass-api"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yujhenchen%2Fnearby-places-react-leaflet-overpass-api","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yujhenchen%2Fnearby-places-react-leaflet-overpass-api/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yujhenchen%2Fnearby-places-react-leaflet-overpass-api/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yujhenchen%2Fnearby-places-react-leaflet-overpass-api/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/yujhenchen","download_url":"https://codeload.github.com/yujhenchen/nearby-places-react-leaflet-overpass-api/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":221279958,"owners_count":16790562,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["flowbite","front-end","frontend","leafletjs","netlify","openstreetmap","overpass-api","react","react-leaflet","tailwind-css","typescript","vite","zustand"],"created_at":"2024-07-29T19:33:04.713Z","updated_at":"2026-04-18T04:35:44.391Z","avatar_url":"https://github.com/yujhenchen.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ca name=\"top\"\u003e\u003c/a\u003e\n\n\u003c!-- PROJECT SHIELDS --\u003e\n\n\u003c!-- [![Contributors][contributors-shield]][contributors-url]\n[![Forks][forks-shield]][forks-url]\n[![Stargazers][stars-shield]][stars-url]\n[![Issues][issues-shield]][issues-url]\n[![MIT License][license-shield]][license-url]\n[![LinkedIn][linkedin-shield]][linkedin-url] --\u003e\n\n\n\n\u003c!-- PROJECT LOGO --\u003e\n\u003cbr /\u003e\n\u003cdiv align=\"center\"\u003e\n  \u003ch3 align=\"center\"\u003eProject Features and Issues\u003c/h3\u003e\n\n  \u003cp align=\"center\"\u003e\n    A finding nearby places app built with React, Vite, Flowbite, Tailwind CSS, leafletjs, React Leaflet, Overpass API, zustand, and TypeScript.\n  \u003c/p\u003e\n\u003c/div\u003e\n\n\n\n\u003c!-- TABLE OF CONTENTS --\u003e\n\u003cdetails\u003e\n  \u003csummary\u003eTable of Contents\u003c/summary\u003e\n  \u003col\u003e\n    \u003cli\u003e\u003ca href=\"#completed-features\"\u003eCompleted Features\u003c/a\u003e\u003c/li\u003e\n    \u003cli\u003e\u003ca href=\"#to-do-tasks\"\u003eTo-Do Tasks\u003c/a\u003e\u003c/li\u003e\n    \u003cli\u003e\u003ca href=\"#packages-used\"\u003ePackages Used\u003c/a\u003e\u003c/li\u003e\n    \u003cli\u003e\u003ca href=\"#issues-encountered-and-solutions\"\u003eIssues Encountered and Solutions\u003c/a\u003e\u003c/li\u003e\n    \u003cli\u003e\u003ca href=\"#extra-features\"\u003eExtra Features\u003c/a\u003e\u003c/li\u003e\n    \u003cli\u003e\u003ca href=\"#reference\"\u003eReference\u003c/a\u003e\u003c/li\u003e\n  \u003c/ol\u003e\n\u003c/details\u003e\n\n\n\n\u003c!-- COMPLETED FEATURES --\u003e\n## Completed Features:\n\n1. Utilized React Query for efficient data fetching and caching, enhancing performance.\n2. Expanded categories of places for more comprehensive search options.\n3. Implemented storage of the user's current position for enhanced user experience.\n4. Added loading UI during data queries for better visual feedback.\n5. Enabled single click navigation to any location worldwide directly on the map.\n6. Incorporated onScroll events to dynamically adjust card container styles.\n7. Implemented functionality to scroll into the corresponding card after clicking on a marker.\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#top\"\u003eback to top\u003c/a\u003e)\u003c/p\u003e\n\n\n\n\u003c!-- TO-DO TASKS --\u003e\n## To-Do Tasks:\n\n- Pass Refs to Child Components using forwardRef.\n- Implement deep refs forwarding for complex component structures.\n- Utilize useRef to store a list of elements efficiently.\n- Add custom attributes to div elements for enhanced styling flexibility.\n- Create custom hooks for map-related functionalities.\n- Explore testing React components using Vitest.\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#top\"\u003eback to top\u003c/a\u003e)\u003c/p\u003e\n\n\n\n\u003c!-- PACKAGES USED --\u003e\n## Packages Used:\n\n- Flowbite\n- Tailwind CSS\n- Leafletjs\n- React Leaflet\n- Overpass API\n- Zustand\n- React Query\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#top\"\u003eback to top\u003c/a\u003e)\u003c/p\u003e\n\n\n## Issues Encountered and Solutions\n\n### 'require' is not defined\n\nIn tailwind.config.js on `plugins: [require(\"flowbite/plugin\")],`\n\n**Solution** \u003cbr\u003e\nignore eslint\n\n```\n// eslint-disable-next-line no-undef\n  plugins: [require(\"flowbite/plugin\")],\n```\n\n### Flex col auto wrap child element\n\n**Solution** \u003cbr\u003e\nChange the parent layout to `lg:inline-block` instead of `lg:flex-col`\n\n### Overflow scroll does not work when flex row\n\n**Solution** \u003cbr\u003e\nAdd missing width: 100vw; `w-screen` to the flex container\n\n### Flex nowrap does not work when flex row\n\n**Solution** \u003cbr\u003e\nAdd missing height `h-full` to the flex element\n\n### Default scroll looks ugly\n\n**Solution** \u003cbr\u003e\nhttps://www.npmjs.com/package/tailwind-scrollbar\n\n### react-leaflet does not show correctly on the page\n\n**Solution** \u003cbr\u003e\nhttps://leafletjs.com/examples/quick-start/  \ndoes not work\n\nhttps://www.npmjs.com/package/react-leaflet?activeTab=dependencies\ndoes not work\n\nhttps://stackoverflow.com/questions/40365440/react-leaflet-map-not-correctly-displayed\n\nhttps://leafletjs.com/examples/quick-start/\nit works\n\n### Add link and script and width and height\n\nAdd the below codes into **index.html**\n\n```\n\u003clink\n      rel=\"stylesheet\"\n      href=\"https://unpkg.com/leaflet@1.9.4/dist/leaflet.css\"\n      integrity=\"sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY=\"\n      crossorigin=\"\"\n    /\u003e\n```\n\n```\n \u003cscript\n  src=\"https://unpkg.com/leaflet@1.9.4/dist/leaflet.js\"\n  integrity=\"sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo=\"\n  crossorigin=\"\"\n\u003e\u003c/script\u003e\n```\n\nAdd below codes into **src\\App.css**\n\n```\n.leaflet-container {\n  width: 100wh;\n  height: 100vh;\n}\n```\n\n### Default map is on the top of every component\n\n**Solution** \u003cbr\u003e\nhttps://wordpress.org/support/topic/leaflet-map-z-index-and-css/\n\nAdd the style `z-index: 0 !important;` to the leaflet container class `.leaflet-container` in **src\\App.css**\n\nChange the order of components, make leaflet container component to be the first render component. For example, in **src\\App.tsx**, where `\u003cMapLayout /\u003e` is the component that includes leaflet container:\n\n```\nimport \"./App.css\";\nimport MapLayout from \"./MapLayout\";\nimport Navigation from \"./Navigation\";\nimport ResultContainer from \"./ResultContainer\";\n\nfunction App() {\n  return (\n    \u003cmain className=\"min-h-screen min-w-screen flex\"\u003e\n      \u003cMapLayout /\u003e\n      \u003cNavigation /\u003e\n      \u003cResultContainer /\u003e\n    \u003c/main\u003e\n  );\n}\n\nexport default App;\n```\n\nIn **src\\MapLayout.tsx**\n\n```\nimport React from \"react\";\nimport CurrentLocationButton from \"./CurrentLocationButton\";\nimport { MapContainer, Marker, Popup, TileLayer } from \"react-leaflet\";\n\nexport default function MapLayout() {\n  return (\n    \u003cdiv className=\"w-screen h-screen \"\u003e\n      \u003cMapContainer center={[51.505, -0.09]} zoom={13} scrollWheelZoom={false}\u003e\n        \u003cTileLayer\n          attribution='\u0026copy; \u003ca href=\"https://www.openstreetmap.org/copyright\"\u003eOpenStreetMap\u003c/a\u003e contributors'\n          url=\"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png\"\n        /\u003e\n        \u003cMarker position={[51.505, -0.09]}\u003e\n          \u003cPopup\u003e\n            A pretty CSS3 popup. \u003cbr /\u003e Easily customizable.\n          \u003c/Popup\u003e\n        \u003c/Marker\u003e\n      \u003c/MapContainer\u003e\n\n      \u003cdiv className=\"fixed w-10 aspect-square flex items-center place-content-center bottom-64 right-8 lg:bottom-24 lg:right-24\"\u003e\n        \u003cCurrentLocationButton /\u003e\n      \u003c/div\u003e\n    \u003c/div\u003e\n  );\n}\n```\n\n### Error: `Argument of type 'LatLng' is not assignable to parameter of type 'SetStateAction\u003cnull\u003e'. Type 'LatLng' provides no match for the signature '(prevState: null): null'.`\n\n**Solution** \u003cbr\u003e\nChange `useState(null);` to `useState\u003cLatLng | null\u003e(null);`\n\n## Tasks\n\n### Get the user's current location and mark it on the map\n\nhttps://react-leaflet.js.org/docs/example-events/\n\nhttps://stackoverflow.com/questions/66500181/how-to-locate-react-leaflet-map-to-users-current-position-and-get-the-borders-f\n\nAdd onClick event to the custom go to current location button `onClick={() =\u003e setGoToCurrentPosition(true)}`, to change the state `const [goToCurrentPosition, setGoToCurrentPosition] = useState(false);`\n\nMonitor the state change in the `LocationMarker` component. And add the condition in the `useEffect`, only go to the current location when the state variable `goToCurrent` is true.\n\nFull codes:\n\n```\nimport { LatLng } from \"leaflet\";\nimport { useEffect, useState } from \"react\";\nimport {\n  MapContainer,\n  Marker,\n  Popup,\n  TileLayer,\n  useMap,\n} from \"react-leaflet\";\nimport CurrentLocationIcon from \"./CurrentLocationIcon\";\n\ntype Props = {\n  goToCurrentPosition: boolean;\n};\n\nfunction LocationMarker({ goToCurrentPosition }: Props) {\n  const [position, setPosition] = useState\u003cLatLng | null\u003e(null);\n\n  const [goToCurrent, setGoToCurrent] = useState(false);\n\n  const map = useMap();\n\n  useEffect(() =\u003e {\n    setGoToCurrent(goToCurrentPosition);\n  }, [goToCurrentPosition]);\n\n  useEffect(() =\u003e {\n    if (goToCurrent) {\n      map.locate().on(\"locationfound\", function (e) {\n        setPosition(e.latlng);\n        map.flyTo(e.latlng, map.getZoom());\n      });\n    }\n  }, [goToCurrent]);\n\n  return position === null ? null : (\n    \u003cMarker position={position}\u003e\n      \u003cPopup\u003eYou are here\u003c/Popup\u003e\n    \u003c/Marker\u003e\n  );\n}\n\nexport default function MapLayout() {\n  const [goToCurrentPosition, setGoToCurrentPosition] = useState(false);\n\n  return (\n    \u003cdiv className=\"w-screen h-screen \"\u003e\n      \u003cMapContainer center={[51.505, -0.09]} zoom={13} scrollWheelZoom={false}\u003e\n        \u003cTileLayer\n          attribution='\u0026copy; \u003ca href=\"https://www.openstreetmap.org/copyright\"\u003eOpenStreetMap\u003c/a\u003e contributors'\n          url=\"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png\"\n        /\u003e\n        \u003cMarker position={[51.505, -0.09]}\u003e\n          \u003cPopup\u003e\n            A pretty CSS3 popup. \u003cbr /\u003e Easily customizable.\n          \u003c/Popup\u003e\n        \u003c/Marker\u003e\n\n        \u003cLocationMarker goToCurrentPosition={goToCurrentPosition} /\u003e\n      \u003c/MapContainer\u003e\n\n      \u003cbutton\n        className=\"fixed w-14 aspect-square flex items-center place-content-center bottom-64 right-8 lg:bottom-24 lg:right-24 backdrop-blur shadow-lg p-2 rounded-full\"\n        onClick={() =\u003e setGoToCurrentPosition(true)}\n      \u003e\n        \u003cCurrentLocationIcon /\u003e\n      \u003c/button\u003e\n    \u003c/div\u003e\n  );\n}\n```\n\n### List 10 restaurants near the current location\n\nhttps://opensource.com/article/18/5/how-build-your-first-gis-app\n\nhttps://www.npmjs.com/package/query-overpass\n\nhttps://codesandbox.io/s/b7olo?file=/src/service/overpass.ts\n\n### Try out overpass api on Postman\n\n#### Url\n\nhttps://overpass-api.de/api/interpreter\n\n#### Method\n\nPOST\n\n#### Header\n\n`Content-Type: application/x-www-form-urlencoded;charset=UTF-8`\n\n#### Request body\n\nQuery Castles\n\n```\n[out:json];(way[historic=castle](around:10000, 50.0874654,14.4212535);\nrelation[historic=castle](around:10000, 50.0874654,14.4212535););\nout body;\u003e;out skel qt;\n```\n\nQuery schools\n\n```\n[out:json];\n(node[amenity=school](around:10000, 50.0874654,14.4212535););\nout body;\u003e;out skel qt;\n```\n\n### Save the current position for sharable use\n\nUse zustand\n\n### Show restaurants on the map\n\nChange the icons\nhttps://codesandbox.io/s/react-leaflet-icon-material-mx1iu?file=/src/index.js\n\n### Get distance information from the current position in km\n\nhttps://www.geodatasource.com/developers/javascript\n\n### Change the corresponding restaurant card style after clicking the marker\n\nAdd `eventHandlers` in `Marker`\n\n```\n...\n\n\u003cMarker\n      position={[position.lat, position.lon]}\n      icon={customMarkerIcon}\n      eventHandlers={{\n        click: (e) =\u003e {\n          onClickMarker(e);\n        },\n      }}\n    \u003e\n      \u003cPopup\u003e{text}\u003c/Popup\u003e\n    \u003c/Marker\u003e\n\n...\n\n```\n\nIn the handler function, set the state variable using the selected position from the event object\n\n```\n...\n\n  const [selectedPosition, setSelectedPosition] = useState\u003cGeoPosition | null\u003e(\n    null\n  );\n\n  ...\n\n  function onClickCustomMapMarker(event: LeafletMouseEvent): void {\n    setSelectedPosition({ lat: event.latlng.lat, lon: event.latlng.lng });\n  }\n\n...\n\n```\n\nRender the selected card component if the position matches the position of the selected marker\n\n```\n...\n\nexport default function PlaceContainer({\n  currentPosition,\n  places,\n  selectedPosition,\n}: Props) {\n  if (places.length \u003e 0) {\n    return (\n      \u003csection\u003e\n        {places.map((place) =\u003e\n          selectedPosition !== null \u0026\u0026\n          selectedPosition.lat === place.lat \u0026\u0026\n          selectedPosition.lon === place.lon ? (\n            \u003cPlaceCardSelected\n\n              ...\n\n            /\u003e\n          ) : (\n            \u003cPlaceCard\n\n              ...\n\n            /\u003e\n          )\n        )}\n      \u003c/section\u003e\n    );\n  } else {\n    return null;\n  }\n}\n```\n\n## Extra Features\n\n### Use React Query for efficient data fetching and caching to increase performance\n\n#### Update and pass queryKey for query\n\nhttps://github.com/TanStack/query/discussions/3200\n\n...\nzustand\n\n### Edit data after calling API\n\nhttps://github.com/TanStack/query/discussions/530\n\n...\nuseMemo\n\n### Single chick on the map go to anywhere in the world\n\nhttps://stackoverflow.com/questions/66288089/how-to-display-a-list-of-points-using-dbclick-in-react-leaflet-v-3-x\n\n### onScroll events for changing card container styles\n\n...\n\n### Scroll into the card after clicking on the corresponding marker\n\n#### Pass Refs to Child Components using forwardRef\n\nhttps://dmitripavlutin.com/react-forwardref/\n\nhttps://react-typescript-cheatsheet.netlify.app/docs/basic/getting-started/forward_and_create_ref/\n\n#### Deep refs forwarding\n\nhttps://dmitripavlutin.com/react-forwardref/#4-deep-refs-forwarding\n\n...\n\n#### Storing an list of elements using useRef\n\nPossible solution: passing ref as props\nhttps://stackoverflow.com/questions/66764686/how-to-pass-a-ref-down-more-than-one-level-in-react\n\nhttps://eliaslog.pw/how-to-add-multiple-refs-to-one-useref-hook/\n\nGrand child component:\n\n```\n  ...\n\n\u003cPlaceCard\n  ref={(element) =\u003e {\n  if (element) cardRefs.current[index] = element;\n  }}\n  key={place.id}\n\n  ...\n```\n\n...\n\n### Add custom attribute to div\n\n#### XXX does not exist on type 'DetailedHTMLProps\u003cHTMLAttributes\u003cHTMLDivElement\u003e, HTMLDivElement\u003e'\n\nSolution\nhttps://stackoverflow.com/questions/46215614/property-does-not-exist-on-type-detailedhtmlprops-htmldivelement-with-react\n\n...\n\n### Create custom hooks\n\nhttps://www.freecodecamp.org/news/how-to-create-react-hooks/\n\n```\nconst [showStart, setShowStart] = useState(false);\n\nconst [showEnd, setShowEnd] = useState(true);\n```\n\n...\n\n### TypeScript: define the return type of the custom hook to be an array with multiple types\n\nhttps://stackoverflow.com/questions/29382389/defining-array-with-multiple-types-in-typescript\n\n...\n\n## Reference\n\nhttps://github.com/othneildrew/Best-README-Template\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyujhenchen%2Fnearby-places-react-leaflet-overpass-api","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fyujhenchen%2Fnearby-places-react-leaflet-overpass-api","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyujhenchen%2Fnearby-places-react-leaflet-overpass-api/lists"}