-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(pickup): support dragging map to load more locations
Note: only supported for PostNL
- Loading branch information
1 parent
e2ac4c7
commit 4d5c938
Showing
34 changed files
with
580 additions
and
200 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
108 changes: 22 additions & 86 deletions
108
apps/delivery-options/src/components/map/LeafletMapInner/LeafletMapInner.vue
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,112 +1,48 @@ | ||
<template> | ||
<div | ||
ref="container" | ||
:style="{height}"> | ||
style="height: 100%"> | ||
<LeafletMapLoadMoreButton /> | ||
|
||
<slot /> | ||
</div> | ||
</template> | ||
|
||
<script lang="ts" setup> | ||
/* eslint-disable new-cap */ | ||
import {computed, onActivated, onMounted, onUnmounted, provide, ref, toRefs, watch} from 'vue'; | ||
import {isString} from 'radash'; | ||
import {type Control, type Map, type Marker, type TileLayer, type LatLng, type FeatureGroup} from 'leaflet'; | ||
import {isDef, useScriptTag, useStyleTag, useDebounceFn} from '@vueuse/core'; | ||
import {type MapTileLayerData} from '@myparcel-do/shared'; | ||
import {type LeafletMapProps} from '../../../types'; | ||
import {useConfigStore} from '../../../stores'; | ||
import {MAP_MARKER_CLASS_ACTIVE} from '../../../data'; | ||
// eslint-disable-next-line vue/no-unused-properties | ||
const props = withDefaults(defineProps<LeafletMapProps>(), { | ||
zoom: 14, | ||
height: '100%', | ||
center: () => [0, 0], | ||
}); | ||
const propRefs = toRefs(props); | ||
import {ref, onMounted, toValue, onUnmounted, onActivated} from 'vue'; | ||
import {asyncComputed, useStyleTag, useScriptTag} from '@vueuse/core'; | ||
import {usePickupLocationsMap} from '../../../composables'; | ||
import LeafletMapLoadMoreButton from './LeafletMapLoadMoreButton.vue'; | ||
const unmountHooks = []; | ||
const container = ref<HTMLElement>(); | ||
const map = ref<Map>(); | ||
const tileLayer = ref<TileLayer>(); | ||
const scale = ref<Control.Scale>(); | ||
const markers = ref<Marker[]>([]); | ||
provide('map', map); | ||
provide('tileLayer', tileLayer); | ||
provide('scale', scale); | ||
provide('markers', markers); | ||
const css = await (await fetch('https://cdn.jsdelivr.net/npm/leaflet@1/dist/leaflet.min.css')).text(); | ||
useStyleTag(css); | ||
const tag = useScriptTag('https://cdn.jsdelivr.net/npm/leaflet@1/dist/leaflet.js'); | ||
await tag.load(); | ||
const config = useConfigStore(); | ||
const tileLayerData = computed<MapTileLayerData>(() => { | ||
if (isString(config.pickupLocationsMapTileLayerData)) { | ||
return JSON.parse(config.pickupLocationsMapTileLayerData); | ||
} | ||
return config.pickupLocationsMapTileLayerData; | ||
const css = asyncComputed(async () => { | ||
return (await fetch('https://cdn.jsdelivr.net/npm/leaflet@1/dist/leaflet.min.css')).text(); | ||
}); | ||
const getActiveMarkerLatLng = (): undefined | LatLng => { | ||
const activeMarker = markers.value.find((marker) => marker.getElement()?.classList.contains(MAP_MARKER_CLASS_ACTIVE)); | ||
return activeMarker?.getLatLng(); | ||
}; | ||
const styleTag = useStyleTag(css); | ||
const scriptTag = useScriptTag('https://cdn.jsdelivr.net/npm/leaflet@1/dist/leaflet.js'); | ||
const fitBounds = useDebounceFn(() => { | ||
if (!container.value) { | ||
return; | ||
} | ||
const {initializeMap, activeMarker, center, map} = usePickupLocationsMap(); | ||
const group: FeatureGroup = new L.featureGroup(markers.value as Marker[]); | ||
onMounted(async () => { | ||
styleTag.load(); | ||
await scriptTag.load(); | ||
map.value?.setView(getActiveMarkerLatLng() ?? props.center, props.zoom); | ||
const teardownMap = initializeMap(container); | ||
const bounds = group.getBounds(); | ||
if (bounds.isValid()) { | ||
map.value?.fitBounds(bounds); | ||
} | ||
}, 50); | ||
onMounted(() => { | ||
if (!isDef(container.value)) { | ||
return; | ||
} | ||
const {center, scroll, zoom} = propRefs; | ||
const {attribution, maxZoom, url, token} = tileLayerData.value; | ||
map.value = new L.Map(container.value, {preferCanvas: true, scrollWheelZoom: scroll.value}); | ||
if (!isDef(map.value)) { | ||
return; | ||
} | ||
map.value.setView(center.value, zoom.value); | ||
tileLayer.value = new L.TileLayer(url, {attribution, maxZoom, accessToken: token}); | ||
scale.value = new L.Control.Scale(); | ||
tileLayer.value?.addTo(map.value); | ||
scale.value?.addTo(map.value); | ||
map.value.on('layeradd', fitBounds); | ||
map.value.on('layerremove', fitBounds); | ||
unmountHooks.push(teardownMap); | ||
}); | ||
onUnmounted(() => { | ||
map.value?.remove(); | ||
scriptTag.unload(); | ||
styleTag.unload(); | ||
unmountHooks.forEach((hook) => hook()); | ||
}); | ||
onUnmounted(watch(propRefs.zoom, () => map.value?.setZoom(propRefs.zoom.value))); | ||
onActivated(() => { | ||
map.value?.panTo(getActiveMarkerLatLng() ?? propRefs.center.value); | ||
map.value?.panTo(toValue(activeMarker)?.getLatLng() ?? toValue(center)); | ||
}); | ||
</script> |
39 changes: 39 additions & 0 deletions
39
apps/delivery-options/src/components/map/LeafletMapInner/LeafletMapLoadMoreButton.vue
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
<template> | ||
<div class="mp-absolute mp-bottom-10 mp-text-center mp-w-full mp-z-[99999]"> | ||
<DoButton | ||
v-show="showLoadMoreButton" | ||
:class="{ | ||
'mp-cursor-not-allowed mp-bg-gray-100 mp-opacity-50': loading, | ||
}" | ||
class="mp-inline-flex mp-px-2 mp-py-0.5 mp-transition-colors" | ||
no-spacing | ||
@click="loadMore"> | ||
{{ translate(SHOW_MORE_LOCATIONS) }} | ||
</DoButton> | ||
</div> | ||
</template> | ||
|
||
<script lang="ts" setup> | ||
import {computed} from 'vue'; | ||
import {SHOW_MORE_LOCATIONS} from '@myparcel-do/shared'; | ||
import {DoButton} from '../../common'; | ||
import {useLanguage, usePickupLocationsMap, useResolvedPickupLocations} from '../../../composables'; | ||
const {translate} = useLanguage(); | ||
const {locations, loadMoreLocations} = useResolvedPickupLocations(); | ||
const {showLoadMoreButton, map} = usePickupLocationsMap(); | ||
const loading = computed(() => locations.loading.value); | ||
const loadMore = async () => { | ||
const center = map.value?.getCenter(); | ||
if (!center) { | ||
return; | ||
} | ||
await loadMoreLocations(center.lat, center.lng); | ||
showLoadMoreButton.value = false; | ||
}; | ||
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
20 changes: 8 additions & 12 deletions
20
apps/delivery-options/src/composables/usePickupLocation.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.