Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions web/src/components/LeafletMap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ const LocationMarker = (props: MarkerProps) => {

useEffect(() => {
map.attributionControl.setPrefix("");
map.attributionControl.addAttribution("<a href='https://www.openstreetmap.org/copyright'>OpenStreetMap</a>");
map.locate();
}, []);

Expand Down
34 changes: 31 additions & 3 deletions web/src/components/MemoEditor/ActionButton/LocationSelector.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { LatLng } from "leaflet";
import { MapPinIcon, XIcon } from "lucide-react";
import { useEffect, useState } from "react";
import { useEffect, useState, useRef } from "react";
import toast from "react-hot-toast";
import LeafletMap from "@/components/LeafletMap";
import { Button } from "@/components/ui/button";
Expand All @@ -25,6 +25,12 @@ interface State {
lngInput: string;
}

interface NominatimRateLimit {
lastNominatimFetch: Date;
nominatimTimeoutId: number | undefined;
timeBetweenFetch: number;
}

const LocationSelector = (props: Props) => {
const t = useTranslate();
const [state, setState] = useState<State>({
Expand All @@ -34,6 +40,12 @@ const LocationSelector = (props: Props) => {
latInput: props.location ? String(props.location.latitude) : "",
lngInput: props.location ? String(props.location.longitude) : "",
});
const rateLimit = useRef<NominatimRateLimit>({
lastNominatimFetch: new Date(0),
nominatimTimeoutId: undefined,
timeBetweenFetch: 1300,
});

const [popoverOpen, setPopoverOpen] = useState<boolean>(false);

useEffect(() => {
Expand Down Expand Up @@ -77,7 +89,7 @@ const LocationSelector = (props: Props) => {
}
}, [popoverOpen, props.location]);

useEffect(() => {
const updateReverseGeocoding = () => {
if (!state.position) {
setState((prev) => ({ ...prev, placeholder: "" }));
return;
Expand All @@ -91,7 +103,10 @@ const LocationSelector = (props: Props) => {
}

// Fetch reverse geocoding data.
fetch(`https://nominatim.openstreetmap.org/reverse?lat=${state.position.lat}&lon=${state.position.lng}&format=json`)
fetch(`https://nominatim.openstreetmap.org/reverse?lat=${state.position.lat}&lon=${state.position.lng}&format=json`, {
cache: "default",
headers: new Headers({ "Cache-Control": "max-age=86400" }),
})
.then((response) => response.json())
.then((data) => {
if (data && data.display_name) {
Expand All @@ -102,6 +117,19 @@ const LocationSelector = (props: Props) => {
toast.error("Failed to fetch reverse geocoding data");
console.error("Failed to fetch reverse geocoding data:", error);
});
};

useEffect(() => {
// Fetch reverse geocoding with rate limits
clearTimeout(rateLimit.current.nominatimTimeoutId);
const timeLeft = rateLimit.current.timeBetweenFetch - (new Date().getTime() - rateLimit.current.lastNominatimFetch.getTime());
rateLimit.current.nominatimTimeoutId = setTimeout(
() => {
updateReverseGeocoding();
rateLimit.current.lastNominatimFetch = new Date();
},
Math.max(0, timeLeft),
);
}, [state.position]);

// Update position when lat/lng inputs change (if valid numbers)
Expand Down