From c7c3e3fd6f221447a0c81459a45c090aa0714334 Mon Sep 17 00:00:00 2001 From: trisusilo48 Date: Mon, 28 Oct 2024 17:03:34 +0700 Subject: maps component --- src/lib/maps/components/PinPointMap.jsx | 163 ++++++++++++++++++++++++++++++++ src/lib/maps/stores/useMaps.js | 13 +++ 2 files changed, 176 insertions(+) create mode 100644 src/lib/maps/components/PinPointMap.jsx create mode 100644 src/lib/maps/stores/useMaps.js (limited to 'src/lib/maps') diff --git a/src/lib/maps/components/PinPointMap.jsx b/src/lib/maps/components/PinPointMap.jsx new file mode 100644 index 00000000..0781d8a8 --- /dev/null +++ b/src/lib/maps/components/PinPointMap.jsx @@ -0,0 +1,163 @@ +import React, { useState, useCallback, useRef } from 'react'; +import { + GoogleMap, + useJsApiLoader, + Marker, + Autocomplete, +} from '@react-google-maps/api'; +import { useMaps } from '../stores/useMaps'; +import { LocateFixed, MapPinIcon } from 'lucide-react'; +import { Button } from '@chakra-ui/react'; + +const containerStyle = { + width: '100%', + height: '400px', +}; + +const center = { + lat: -6.2, // Default latitude (Jakarta) + lng: 106.816666, // Default longitude (Jakarta) +}; + +const PinpointLocation = () => { + const { isLoaded } = useJsApiLoader({ + googleMapsApiKey: process.env.NEXT_PUBLIC_GOOGLE_API_KEY, // Pastikan API key ada di .env.local + libraries: ['places'], + }); + + const { addressMaps, setAddressMaps, selectedPosition, setSelectedPosition } = + useMaps(); + + const [tempAddress, setTempAddress] = useState(''); + const [tempPosition, setTempPosition] = useState(center); + + const autocompleteRef = useRef(null); + + const onMapClick = useCallback((event) => { + const lat = event.latLng.lat(); + const lng = event.latLng.lng(); + setTempPosition({ lat, lng }); + getAddress(lat, lng); + }, []); + + const handlePlaceSelect = () => { + const place = autocompleteRef.current.getPlace(); + if (place && place.geometry) { + const lat = place.geometry.location.lat(); + const lng = place.geometry.location.lng(); + setTempPosition({ lat, lng }); + setTempAddress(place.formatted_address); + } + }; + + const getAddress = async (lat, lng) => { + try { + const response = await fetch( + `https://maps.googleapis.com/maps/api/geocode/json?latlng=${lat},${lng}&key=${process.env.NEXT_PUBLIC_GOOGLE_API_KEY}` + ); + const data = await response.json(); + if (data.results[0]) { + setTempAddress(data.results[0].formatted_address); + } + } catch (error) { + console.error('Error fetching address:', error); + } + }; + + const handleUseCurrentLocation = () => { + if (navigator.geolocation) { + navigator.geolocation.getCurrentPosition( + (position) => { + const lat = position.coords.latitude; + const lng = position.coords.longitude; + setTempPosition({ lat, lng }); + getAddress(lat, lng); + }, + (error) => { + console.error('Error getting current location:', error); + } + ); + } + }; + + const handleSavePinpoint = (event) => { + event.preventDefault(); + if(tempAddress === '') { + alert('Silahkan pilih lokasi terlebih dahulu'); + return; + } + setSelectedPosition(tempPosition); + setAddressMaps(tempAddress); + }; + + return ( +
+

Tentukan Pinpoint Lokasi

+
+ {isLoaded ? ( + (autocompleteRef.current = ref)} + onPlaceChanged={handlePlaceSelect} + > + + + ) : ( +

Loading autocomplete...

+ )} +
+ +
+ {isLoaded ? ( + + onMapClick(e)} + icon={{ + url: 'https://maps.google.com/mapfiles/ms/icons/red-pushpin.png', + scaledSize: new window.google.maps.Size(40, 40), + }} + /> + + ) : ( +

Loading map...

+ )} +
+ +
+ +
+ +
+

PinPoint :

+
+ + +
+
+ +
+ +
+
+ ); +}; + +export default PinpointLocation; diff --git a/src/lib/maps/stores/useMaps.js b/src/lib/maps/stores/useMaps.js new file mode 100644 index 00000000..1720e663 --- /dev/null +++ b/src/lib/maps/stores/useMaps.js @@ -0,0 +1,13 @@ +import { create } from "zustand"; + +const center = { + lat: -6.200000, // Default latitude (Jakarta) + lng: 106.816666, // Default longitude (Jakarta) +}; + +export const useMaps = create((set) => ({ + selectedPosition: center, + addressMaps: '', + setSelectedPosition: (position) => set({ selectedPosition: position }), + setAddressMaps: (addressMaps) => set({ addressMaps }), + })); \ No newline at end of file -- cgit v1.2.3 From bc4fe87e012cc1b06572ca12f1a3b92f6d1757e0 Mon Sep 17 00:00:00 2001 From: trisusilo48 Date: Thu, 31 Oct 2024 09:09:05 +0700 Subject: detail adress --- src/lib/maps/components/PinPointMap.jsx | 43 +++++++++++++++++++++++++++------ 1 file changed, 36 insertions(+), 7 deletions(-) (limited to 'src/lib/maps') diff --git a/src/lib/maps/components/PinPointMap.jsx b/src/lib/maps/components/PinPointMap.jsx index 0781d8a8..1fa40036 100644 --- a/src/lib/maps/components/PinPointMap.jsx +++ b/src/lib/maps/components/PinPointMap.jsx @@ -8,6 +8,7 @@ import { import { useMaps } from '../stores/useMaps'; import { LocateFixed, MapPinIcon } from 'lucide-react'; import { Button } from '@chakra-ui/react'; +import { useForm } from 'react-hook-form'; const containerStyle = { width: '100%', @@ -30,6 +31,7 @@ const PinpointLocation = () => { const [tempAddress, setTempAddress] = useState(''); const [tempPosition, setTempPosition] = useState(center); + const { setValue } = useForm(); const autocompleteRef = useRef(null); @@ -50,6 +52,11 @@ const PinpointLocation = () => { } }; + const getAddressComponent = (components, type) => { + const component = components.find((comp) => comp.types.includes(type)); + return component ? component.long_name : ''; + }; + const getAddress = async (lat, lng) => { try { const response = await fetch( @@ -57,6 +64,28 @@ const PinpointLocation = () => { ); const data = await response.json(); if (data.results[0]) { + const addressComponents = data.results[0].address_components; + const details = { + province: getAddressComponent( + addressComponents, + 'administrative_area_level_1' + ), + district: getAddressComponent( + addressComponents, + 'administrative_area_level_2' + ), + subDistrict: getAddressComponent( + addressComponents, + 'administrative_area_level_3' + ), + village: getAddressComponent( + addressComponents, + 'administrative_area_level_4' + ), + postalCode: getAddressComponent(addressComponents, 'postal_code'), + }; + setValue('state', details?.province); + console.log(details); setTempAddress(data.results[0].formatted_address); } } catch (error) { @@ -82,7 +111,7 @@ const PinpointLocation = () => { const handleSavePinpoint = (event) => { event.preventDefault(); - if(tempAddress === '') { + if (tempAddress === '') { alert('Silahkan pilih lokasi terlebih dahulu'); return; } @@ -134,10 +163,7 @@ const PinpointLocation = () => {
- @@ -152,8 +178,11 @@ const PinpointLocation = () => {
-
-- cgit v1.2.3 From 053c801a8c43688c2c4eec6800368898a81bfc39 Mon Sep 17 00:00:00 2001 From: trisusilo48 Date: Thu, 31 Oct 2024 16:55:07 +0700 Subject: integrasi google maps service --- src/lib/maps/components/PinPointMap.jsx | 4 ++-- src/lib/maps/stores/useMaps.js | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'src/lib/maps') diff --git a/src/lib/maps/components/PinPointMap.jsx b/src/lib/maps/components/PinPointMap.jsx index 1fa40036..201fdeb4 100644 --- a/src/lib/maps/components/PinPointMap.jsx +++ b/src/lib/maps/components/PinPointMap.jsx @@ -26,7 +26,7 @@ const PinpointLocation = () => { libraries: ['places'], }); - const { addressMaps, setAddressMaps, selectedPosition, setSelectedPosition } = + const { addressMaps, setAddressMaps, selectedPosition, setSelectedPosition, setDetailAddress } = useMaps(); const [tempAddress, setTempAddress] = useState(''); @@ -84,7 +84,7 @@ const PinpointLocation = () => { ), postalCode: getAddressComponent(addressComponents, 'postal_code'), }; - setValue('state', details?.province); + setDetailAddress(details); console.log(details); setTempAddress(data.results[0].formatted_address); } diff --git a/src/lib/maps/stores/useMaps.js b/src/lib/maps/stores/useMaps.js index 1720e663..83f476bc 100644 --- a/src/lib/maps/stores/useMaps.js +++ b/src/lib/maps/stores/useMaps.js @@ -8,6 +8,8 @@ const center = { export const useMaps = create((set) => ({ selectedPosition: center, addressMaps: '', + detailAddress: {}, setSelectedPosition: (position) => set({ selectedPosition: position }), setAddressMaps: (addressMaps) => set({ addressMaps }), + setDetailAddress: (detailAddress) => set({ detailAddress }), })); \ No newline at end of file -- cgit v1.2.3 From d1592286eef165533c21d52aec70dbb703cdcfd3 Mon Sep 17 00:00:00 2001 From: trisusilo48 Date: Wed, 18 Dec 2024 15:03:52 +0700 Subject: feedback uat --- src/lib/maps/components/PinPointMap.jsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src/lib/maps') diff --git a/src/lib/maps/components/PinPointMap.jsx b/src/lib/maps/components/PinPointMap.jsx index 201fdeb4..acff5d67 100644 --- a/src/lib/maps/components/PinPointMap.jsx +++ b/src/lib/maps/components/PinPointMap.jsx @@ -66,6 +66,7 @@ const PinpointLocation = () => { if (data.results[0]) { const addressComponents = data.results[0].address_components; const details = { + route : getAddressComponent(addressComponents, 'route')+' '+getAddressComponent(addressComponents, 'street_number')+' '+getAddressComponent(addressComponents, 'administrative_area_level_7')+' '+getAddressComponent(addressComponents, 'administrative_area_level_6'), province: getAddressComponent( addressComponents, 'administrative_area_level_1' @@ -85,7 +86,6 @@ const PinpointLocation = () => { postalCode: getAddressComponent(addressComponents, 'postal_code'), }; setDetailAddress(details); - console.log(details); setTempAddress(data.results[0].formatted_address); } } catch (error) { @@ -115,10 +115,14 @@ const PinpointLocation = () => { alert('Silahkan pilih lokasi terlebih dahulu'); return; } + // console.log('tempPosition', tempPosition.lat); + getAddress(tempPosition.lat, tempPosition.lng); setSelectedPosition(tempPosition); setAddressMaps(tempAddress); }; + console.log('set selected position',selectedPosition); + return (

Tentukan Pinpoint Lokasi

-- cgit v1.2.3 From 0aa0d458e668520ef96ccf7ecb35bf84a585b279 Mon Sep 17 00:00:00 2001 From: trisusilo48 Date: Mon, 21 Apr 2025 13:05:57 +0700 Subject: fedback renca --- src/lib/maps/components/PinPointMap.jsx | 3 ++- src/lib/maps/stores/useMaps.js | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'src/lib/maps') diff --git a/src/lib/maps/components/PinPointMap.jsx b/src/lib/maps/components/PinPointMap.jsx index acff5d67..acd5ab92 100644 --- a/src/lib/maps/components/PinPointMap.jsx +++ b/src/lib/maps/components/PinPointMap.jsx @@ -26,7 +26,7 @@ const PinpointLocation = () => { libraries: ['places'], }); - const { addressMaps, setAddressMaps, selectedPosition, setSelectedPosition, setDetailAddress } = + const { addressMaps, setAddressMaps, selectedPosition, setSelectedPosition, setDetailAddress, setPinedMaps } = useMaps(); const [tempAddress, setTempAddress] = useState(''); @@ -119,6 +119,7 @@ const PinpointLocation = () => { getAddress(tempPosition.lat, tempPosition.lng); setSelectedPosition(tempPosition); setAddressMaps(tempAddress); + setPinedMaps(false) }; console.log('set selected position',selectedPosition); diff --git a/src/lib/maps/stores/useMaps.js b/src/lib/maps/stores/useMaps.js index 83f476bc..4daf7f62 100644 --- a/src/lib/maps/stores/useMaps.js +++ b/src/lib/maps/stores/useMaps.js @@ -9,7 +9,9 @@ export const useMaps = create((set) => ({ selectedPosition: center, addressMaps: '', detailAddress: {}, + pinedMaps : false, setSelectedPosition: (position) => set({ selectedPosition: position }), setAddressMaps: (addressMaps) => set({ addressMaps }), setDetailAddress: (detailAddress) => set({ detailAddress }), + setPinedMaps: (pinedMaps) => set({pinedMaps}) })); \ No newline at end of file -- cgit v1.2.3 From 2e507ccbc92f18a0d7f8ebc59112a0337a0bd678 Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Wed, 11 Jun 2025 13:40:45 +0700 Subject: Pinpoint done --- src/lib/maps/components/PinPointMap.jsx | 139 ++++++++++++++++++-------------- 1 file changed, 77 insertions(+), 62 deletions(-) (limited to 'src/lib/maps') diff --git a/src/lib/maps/components/PinPointMap.jsx b/src/lib/maps/components/PinPointMap.jsx index acd5ab92..fde1f36c 100644 --- a/src/lib/maps/components/PinPointMap.jsx +++ b/src/lib/maps/components/PinPointMap.jsx @@ -1,4 +1,4 @@ -import React, { useState, useCallback, useRef } from 'react'; +import React, { useState, useCallback, useRef, useEffect } from 'react'; import { GoogleMap, useJsApiLoader, @@ -8,49 +8,46 @@ import { import { useMaps } from '../stores/useMaps'; import { LocateFixed, MapPinIcon } from 'lucide-react'; import { Button } from '@chakra-ui/react'; -import { useForm } from 'react-hook-form'; const containerStyle = { width: '100%', height: '400px', }; -const center = { - lat: -6.2, // Default latitude (Jakarta) - lng: 106.816666, // Default longitude (Jakarta) +const defaultCenter = { + lat: -6.2, + lng: 106.816666, }; const PinpointLocation = () => { const { isLoaded } = useJsApiLoader({ - googleMapsApiKey: process.env.NEXT_PUBLIC_GOOGLE_API_KEY, // Pastikan API key ada di .env.local + googleMapsApiKey: process.env.NEXT_PUBLIC_GOOGLE_API_KEY, libraries: ['places'], }); - const { addressMaps, setAddressMaps, selectedPosition, setSelectedPosition, setDetailAddress, setPinedMaps } = - useMaps(); + const { + addressMaps, + setAddressMaps, + selectedPosition, + setSelectedPosition, + setDetailAddress, + setPinedMaps, + } = useMaps(); const [tempAddress, setTempAddress] = useState(''); - const [tempPosition, setTempPosition] = useState(center); - const { setValue } = useForm(); + const [tempPosition, setTempPosition] = useState(defaultCenter); + const [markerIcon, setMarkerIcon] = useState(null); const autocompleteRef = useRef(null); - const onMapClick = useCallback((event) => { - const lat = event.latLng.lat(); - const lng = event.latLng.lng(); - setTempPosition({ lat, lng }); - getAddress(lat, lng); - }, []); - - const handlePlaceSelect = () => { - const place = autocompleteRef.current.getPlace(); - if (place && place.geometry) { - const lat = place.geometry.location.lat(); - const lng = place.geometry.location.lng(); - setTempPosition({ lat, lng }); - setTempAddress(place.formatted_address); + useEffect(() => { + if (isLoaded && window.google) { + setMarkerIcon({ + url: 'https://cdn.pixabay.com/photo/2014/04/03/10/03/google-309740_1280.png', + scaledSize: new window.google.maps.Size(25, 40), + }); } - }; + }, [isLoaded]); const getAddressComponent = (components, type) => { const component = components.find((comp) => comp.types.includes(type)); @@ -63,43 +60,59 @@ const PinpointLocation = () => { `https://maps.googleapis.com/maps/api/geocode/json?latlng=${lat},${lng}&key=${process.env.NEXT_PUBLIC_GOOGLE_API_KEY}` ); const data = await response.json(); + if (data.results[0]) { const addressComponents = data.results[0].address_components; + const formattedAddress = data.results[0].formatted_address; + const details = { - route : getAddressComponent(addressComponents, 'route')+' '+getAddressComponent(addressComponents, 'street_number')+' '+getAddressComponent(addressComponents, 'administrative_area_level_7')+' '+getAddressComponent(addressComponents, 'administrative_area_level_6'), - province: getAddressComponent( - addressComponents, - 'administrative_area_level_1' - ), - district: getAddressComponent( - addressComponents, - 'administrative_area_level_2' - ), - subDistrict: getAddressComponent( - addressComponents, - 'administrative_area_level_3' - ), - village: getAddressComponent( - addressComponents, - 'administrative_area_level_4' - ), + street: + getAddressComponent(addressComponents, 'route') + + ' ' + + getAddressComponent(addressComponents, 'street_number'), + province: getAddressComponent(addressComponents, 'administrative_area_level_1'), + district: getAddressComponent(addressComponents, 'administrative_area_level_2'), + subDistrict: getAddressComponent(addressComponents, 'administrative_area_level_3'), + village: getAddressComponent(addressComponents, 'administrative_area_level_4'), postalCode: getAddressComponent(addressComponents, 'postal_code'), }; + setDetailAddress(details); - setTempAddress(data.results[0].formatted_address); + setTempAddress(formattedAddress); } } catch (error) { console.error('Error fetching address:', error); } }; + const onMapClick = useCallback((event) => { + const lat = event.latLng.lat(); + const lng = event.latLng.lng(); + const newPosition = { lat, lng }; + setTempPosition(newPosition); + getAddress(lat, lng); + }, []); + + const handlePlaceSelect = () => { + const place = autocompleteRef.current.getPlace(); + if (place && place.geometry) { + const lat = place.geometry.location.lat(); + const lng = place.geometry.location.lng(); + const newPosition = { lat, lng }; + setTempPosition(newPosition); + setTempAddress(place.formatted_address); + getAddress(lat, lng); + } + }; + const handleUseCurrentLocation = () => { if (navigator.geolocation) { navigator.geolocation.getCurrentPosition( (position) => { const lat = position.coords.latitude; const lng = position.coords.longitude; - setTempPosition({ lat, lng }); + const newPosition = { lat, lng }; + setTempPosition(newPosition); getAddress(lat, lng); }, (error) => { @@ -115,18 +128,16 @@ const PinpointLocation = () => { alert('Silahkan pilih lokasi terlebih dahulu'); return; } - // console.log('tempPosition', tempPosition.lat); - getAddress(tempPosition.lat, tempPosition.lng); + setSelectedPosition(tempPosition); setAddressMaps(tempAddress); - setPinedMaps(false) + setPinedMaps(false); }; - console.log('set selected position',selectedPosition); - return (

Tentukan Pinpoint Lokasi

+
{isLoaded ? ( { zoom={15} onClick={onMapClick} > - onMapClick(e)} - icon={{ - url: 'https://maps.google.com/mapfiles/ms/icons/red-pushpin.png', - scaledSize: new window.google.maps.Size(40, 40), - }} - /> + {markerIcon && ( + { + const lat = e.latLng.lat(); + const lng = e.latLng.lng(); + const newPosition = { lat, lng }; + setTempPosition(newPosition); + getAddress(lat, lng); + }} + icon={markerIcon} + /> + )} ) : (

Loading map...

@@ -169,16 +185,15 @@ const PinpointLocation = () => {

PinPoint :

- - + +
-- cgit v1.2.3 From e0e0729ee57d2f9b1188a0604e3cc4a51317b0ed Mon Sep 17 00:00:00 2001 From: it-fixcomart Date: Thu, 12 Jun 2025 11:00:00 +0700 Subject: fix pinpoint --- src/lib/maps/components/PinPointMap.jsx | 24 +++++++++++++++++++----- src/lib/maps/stores/useMaps.js | 33 ++++++++++++++++++++++++--------- 2 files changed, 43 insertions(+), 14 deletions(-) (limited to 'src/lib/maps') diff --git a/src/lib/maps/components/PinPointMap.jsx b/src/lib/maps/components/PinPointMap.jsx index fde1f36c..c46d838a 100644 --- a/src/lib/maps/components/PinPointMap.jsx +++ b/src/lib/maps/components/PinPointMap.jsx @@ -19,7 +19,7 @@ const defaultCenter = { lng: 106.816666, }; -const PinpointLocation = () => { +const PinpointLocation = ({ initialLatitude, initialLongitude, initialAddress }) => { const { isLoaded } = useJsApiLoader({ googleMapsApiKey: process.env.NEXT_PUBLIC_GOOGLE_API_KEY, libraries: ['places'], @@ -34,8 +34,15 @@ const PinpointLocation = () => { setPinedMaps, } = useMaps(); - const [tempAddress, setTempAddress] = useState(''); - const [tempPosition, setTempPosition] = useState(defaultCenter); + const [tempAddress, setTempAddress] = useState(initialAddress || ''); + const [tempPosition, setTempPosition] = useState( + initialLatitude && initialLongitude + ? { lat: parseFloat(initialLatitude), lng: parseFloat(initialLongitude) } + : selectedPosition.lat && selectedPosition.lng + ? selectedPosition + : defaultCenter + ); + const [markerIcon, setMarkerIcon] = useState(null); const autocompleteRef = useRef(null); @@ -47,7 +54,12 @@ const PinpointLocation = () => { scaledSize: new window.google.maps.Size(25, 40), }); } - }, [isLoaded]); + + // If we have initial coordinates but no address, fetch the address + if (initialLatitude && initialLongitude && !initialAddress) { + getAddress(parseFloat(initialLatitude), parseFloat(initialLongitude)); + } + }, [isLoaded, initialLatitude, initialLongitude, initialAddress]); const getAddressComponent = (components, type) => { const component = components.find((comp) => comp.types.includes(type)); @@ -147,6 +159,8 @@ const PinpointLocation = () => { setTempAddress(e.target.value)} style={{ width: '100%', padding: '8px' }} />
@@ -209,4 +223,4 @@ const PinpointLocation = () => { ); }; -export default PinpointLocation; +export default PinpointLocation; \ No newline at end of file diff --git a/src/lib/maps/stores/useMaps.js b/src/lib/maps/stores/useMaps.js index 4daf7f62..c57a05ad 100644 --- a/src/lib/maps/stores/useMaps.js +++ b/src/lib/maps/stores/useMaps.js @@ -6,12 +6,27 @@ const center = { }; export const useMaps = create((set) => ({ - selectedPosition: center, - addressMaps: '', - detailAddress: {}, - pinedMaps : false, - setSelectedPosition: (position) => set({ selectedPosition: position }), - setAddressMaps: (addressMaps) => set({ addressMaps }), - setDetailAddress: (detailAddress) => set({ detailAddress }), - setPinedMaps: (pinedMaps) => set({pinedMaps}) - })); \ No newline at end of file + // State existing + selectedPosition: center, + addressMaps: '', + detailAddress: {}, + pinedMaps: false, + + // State tambahan untuk penyimpanan posisi sementara + tempPositionCreate: null, + tempPositionEdit: null, + + // Setter existing + setSelectedPosition: (position) => set({ selectedPosition: position }), + setAddressMaps: (addressMaps) => set({ addressMaps }), + setDetailAddress: (detailAddress) => set({ detailAddress }), + setPinedMaps: (pinedMaps) => set({ pinedMaps }), + + // Setter tambahan untuk posisi sementara + setTempPositionCreate: (position) => set({ tempPositionCreate: position }), + setTempPositionEdit: (position) => set({ tempPositionEdit: position }), + + // Opsional: Reset jika ingin clear saat keluar halaman + resetTempPositionCreate: () => set({ tempPositionCreate: null }), + resetTempPositionEdit: () => set({ tempPositionEdit: null }), +})); -- cgit v1.2.3