#50 feat: mostrar dirección y mapa de la tienda en la página de inicio
This commit is contained in:
165
src/components/StoreLocation.vue
Normal file
165
src/components/StoreLocation.vue
Normal file
@@ -0,0 +1,165 @@
|
||||
<template>
|
||||
<v-container v-if="settings && settings.address">
|
||||
<v-sheet
|
||||
class="store-location-section rounded-xl pa-6 pa-md-8"
|
||||
elevation="2"
|
||||
>
|
||||
<div class="d-flex flex-column align-center text-center mb-4">
|
||||
<div class="d-flex align-center mb-1">
|
||||
<v-icon color="primary" size="36" class="mr-2">mdi-map-marker</v-icon>
|
||||
<h2 class="text-h4 font-weight-bold mb-0">Visítanos</h2>
|
||||
</div>
|
||||
<p class="text-body-1 text-medium-emphasis mb-0">
|
||||
Encuentra nuestra tienda física y adquiere nuestros productos
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="text-center mb-4">
|
||||
<div class="d-flex align-center justify-center">
|
||||
<v-icon color="red" class="mr-2">mdi-map-marker</v-icon>
|
||||
<span class="text-h6 font-weight-medium">
|
||||
{{ settings.address }}
|
||||
</span>
|
||||
</div>
|
||||
<v-btn
|
||||
v-if="hasCoordinates"
|
||||
:href="directionsLink"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
color="primary"
|
||||
variant="tonal"
|
||||
size="small"
|
||||
prepend-icon="mdi-directions"
|
||||
class="mt-2"
|
||||
>
|
||||
Cómo llegar
|
||||
</v-btn>
|
||||
<v-btn
|
||||
v-else
|
||||
:href="searchLink"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
color="primary"
|
||||
variant="tonal"
|
||||
size="small"
|
||||
prepend-icon="mdi-map-search"
|
||||
class="mt-2"
|
||||
>
|
||||
Ver en el mapa
|
||||
</v-btn>
|
||||
</div>
|
||||
|
||||
<div v-if="hasCoordinates" ref="mapEl" class="map-wrapper"></div>
|
||||
<v-alert v-else type="info" variant="tonal" class="ma-0">
|
||||
La ubicación en el mapa aún no está configurada.
|
||||
</v-alert>
|
||||
</v-sheet>
|
||||
</v-container>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, inject, onMounted, onBeforeUnmount, nextTick } from 'vue';
|
||||
import L from 'leaflet';
|
||||
import 'leaflet/dist/leaflet.css';
|
||||
|
||||
const api = inject('api');
|
||||
|
||||
const settings = ref(null);
|
||||
const mapEl = ref(null);
|
||||
|
||||
let map = null;
|
||||
let marker = null;
|
||||
|
||||
const hasCoordinates = computed(
|
||||
() =>
|
||||
settings.value &&
|
||||
settings.value.latitude != null &&
|
||||
settings.value.longitude != null
|
||||
);
|
||||
|
||||
const redPinIcon = L.divIcon({
|
||||
className: 'store-map-pin',
|
||||
html: '<i class="mdi mdi-map-marker" style="font-size:48px;line-height:1;color:#f44336;"></i>',
|
||||
iconSize: [48, 48],
|
||||
iconAnchor: [24, 48],
|
||||
});
|
||||
|
||||
const directionsLink = computed(() => {
|
||||
const lat = settings.value.latitude;
|
||||
const lng = settings.value.longitude;
|
||||
return `https://www.openstreetmap.org/?mlat=${lat}&mlon=${lng}#map=16/${lat}/${lng}`;
|
||||
});
|
||||
|
||||
const searchLink = computed(
|
||||
() =>
|
||||
`https://www.openstreetmap.org/search?query=${encodeURIComponent(
|
||||
settings.value.address
|
||||
)}`
|
||||
);
|
||||
|
||||
function initMap() {
|
||||
if (!hasCoordinates.value || !mapEl.value || map) return;
|
||||
|
||||
const lat = settings.value.latitude;
|
||||
const lng = settings.value.longitude;
|
||||
|
||||
map = L.map(mapEl.value, {
|
||||
scrollWheelZoom: false,
|
||||
}).setView([lat, lng], 16);
|
||||
|
||||
L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
||||
maxZoom: 19,
|
||||
attribution:
|
||||
'© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
|
||||
}).addTo(map);
|
||||
|
||||
marker = L.marker([lat, lng], { icon: redPinIcon }).addTo(map);
|
||||
marker.bindPopup(settings.value.address);
|
||||
}
|
||||
|
||||
function handleResize() {
|
||||
if (map) {
|
||||
map.invalidateSize();
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
try {
|
||||
settings.value = await api.getStoreSettings();
|
||||
await nextTick();
|
||||
initMap();
|
||||
} catch (error) {
|
||||
console.error('Error al cargar la información de la tienda:', error);
|
||||
}
|
||||
window.addEventListener('resize', handleResize);
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
window.removeEventListener('resize', handleResize);
|
||||
if (map) {
|
||||
map.remove();
|
||||
map = null;
|
||||
marker = null;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.store-location-section {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.map-wrapper {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 400px;
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.map-wrapper :deep(.leaflet-control-attribution) {
|
||||
font-size: 10px;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user