160 lines
4.1 KiB
TypeScript
160 lines
4.1 KiB
TypeScript
import { GoogleMap, Marker, useLoadScript } from "@react-google-maps/api";
|
|
import Cookies from "js-cookie";
|
|
import { useEffect, useState } from "react";
|
|
import usePlacesAutocomplete, {
|
|
getGeocode,
|
|
getLatLng,
|
|
} from "use-places-autocomplete";
|
|
import { GoogleMapsAPI } from "./client-config";
|
|
import Geocode from "react-geocode";
|
|
import { PlacesCombobox } from "@/components/ui/combobox";
|
|
|
|
Geocode.setApiKey(GoogleMapsAPI);
|
|
|
|
export default function Places(props: {
|
|
center: { lat: number; lng: number };
|
|
draggable?: boolean;
|
|
onLocationChange?: (location: string) => void; // Tambahkan onLocationChange
|
|
}) {
|
|
const { isLoaded } = useLoadScript({
|
|
googleMapsApiKey: GoogleMapsAPI,
|
|
libraries: ["places"],
|
|
language: "id",
|
|
});
|
|
|
|
const { center, draggable, onLocationChange } = props;
|
|
|
|
if (!isLoaded) return <div>Loading...</div>;
|
|
|
|
return (
|
|
<Map
|
|
lat={center.lat}
|
|
lng={center.lng}
|
|
draggable={draggable}
|
|
onLocationChange={onLocationChange} // Kirimkan properti onLocationChange
|
|
/>
|
|
);
|
|
}
|
|
|
|
interface MapProps {
|
|
lat: number;
|
|
lng: number;
|
|
draggable?: boolean;
|
|
onLocationChange?: (location: string) => void; // Tambahkan properti ini
|
|
}
|
|
|
|
function Map(props: MapProps) {
|
|
const containerStyle = {
|
|
width: "100%",
|
|
height: "400px",
|
|
};
|
|
|
|
const center = {
|
|
lat: -6.1754,
|
|
lng: 106.8272,
|
|
};
|
|
|
|
const [selected, setSelected] = useState<{ lat: number; lng: number } | null>(
|
|
null
|
|
);
|
|
|
|
const { lat, lng, draggable, onLocationChange } = props;
|
|
|
|
useEffect(() => {
|
|
if (lat !== undefined && lng !== undefined) {
|
|
setSelected({ lat, lng });
|
|
getAddressFromLatLong(lat, lng);
|
|
}
|
|
}, [lat, lng]);
|
|
|
|
const onMarkerDragEnd = (e: google.maps.MapMouseEvent) => {
|
|
const lat = e.latLng?.lat() ?? 0;
|
|
const lng = e.latLng?.lng() ?? 0;
|
|
console.log(lat, lng);
|
|
getAddressFromLatLong(lat, lng);
|
|
if (onLocationChange) {
|
|
onLocationChange(`Latitude: ${lat}, Longitude: ${lng}`); // Kirimkan lokasi ke parent melalui onLocationChange
|
|
}
|
|
};
|
|
|
|
async function getAddressFromLatLong(lat: number, lng: number) {
|
|
try {
|
|
const response = await Geocode.fromLatLng(lat.toString(), lng.toString());
|
|
const address = response.results[0].formatted_address;
|
|
Cookies.set("map_lat", `${lat}`, { expires: 1 });
|
|
Cookies.set("map_long", `${lng}`, { expires: 1 });
|
|
console.log("Address:", address);
|
|
if (onLocationChange) {
|
|
onLocationChange(address); // Kirimkan alamat jika berhasil
|
|
}
|
|
} catch (error) {
|
|
console.error(error);
|
|
}
|
|
}
|
|
|
|
return (
|
|
<>
|
|
<div>
|
|
<PlacesAutocomplete setSelected={setSelected} />
|
|
</div>
|
|
<GoogleMap
|
|
zoom={selected == null ? 10 : 15}
|
|
center={selected == null ? center : selected}
|
|
mapContainerStyle={containerStyle}
|
|
>
|
|
{selected && (
|
|
<Marker
|
|
draggable={draggable}
|
|
position={selected}
|
|
onDragEnd={onMarkerDragEnd}
|
|
/>
|
|
)}
|
|
</GoogleMap>
|
|
</>
|
|
);
|
|
}
|
|
|
|
interface PlacesAutocompleteProps {
|
|
setSelected: (coords: { lat: number; lng: number }) => void;
|
|
}
|
|
|
|
function PlacesAutocomplete({ setSelected }: PlacesAutocompleteProps) {
|
|
const {
|
|
ready,
|
|
value,
|
|
setValue,
|
|
suggestions: { status, data },
|
|
clearSuggestions,
|
|
} = usePlacesAutocomplete();
|
|
|
|
const handleSelect = async (address: string) => {
|
|
setValue(address, false);
|
|
clearSuggestions();
|
|
|
|
try {
|
|
const results = await getGeocode({ address });
|
|
const { lat, lng } = await getLatLng(results[0]);
|
|
|
|
setSelected({ lat, lng });
|
|
console.log("Selected Lat/Lng:", { lat, lng });
|
|
Cookies.set("map_lat", `${lat}`, { expires: 1 });
|
|
Cookies.set("map_long", `${lng}`, { expires: 1 });
|
|
} catch (error) {
|
|
console.error("Error fetching coordinates:", error);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<PlacesCombobox
|
|
value={value}
|
|
onValueChange={(newValue) => setValue(newValue)}
|
|
onSelect={handleSelect}
|
|
suggestions={data}
|
|
status={status}
|
|
disabled={!ready}
|
|
placeholder="Cari Alamat"
|
|
className="border"
|
|
/>
|
|
);
|
|
}
|