mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-08-20 22:53:49 +00:00
Feature: bootstrapping an app to show a modal for address details and showing it inside twig address's render box
Feature: showing map and link to external map, and address details inside address details modal Feature: AddressDetailsMap show a warning if the address is incomplete
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
import {getAddressById} from 'ChillMainAssets/lib/api/address';
|
||||
|
||||
/**
|
||||
* Endpoint chill_api_single_country__index
|
||||
* method GET, get Country Object
|
||||
@@ -188,13 +190,7 @@ const postPostalCode = (postalCode) => { //<--
|
||||
* @returns {Promise} a promise containing a Address object
|
||||
*/
|
||||
const getAddress = (id) => {
|
||||
//console.log('<< get address');
|
||||
const url = `/api/1.0/main/address/${id}.json`;
|
||||
return fetch(url)
|
||||
.then(response => {
|
||||
if (response.ok) { return response.json(); }
|
||||
throw Error('Error with request resource response');
|
||||
});
|
||||
return getAddressById(id);
|
||||
};
|
||||
|
||||
export {
|
||||
|
@@ -0,0 +1,45 @@
|
||||
<template>
|
||||
<a v-if="data.loading === false" @click.prevent="clickOrOpen"><span class="fa fa-map"></span></a>
|
||||
<span v-if="data.loading" class="fa fa-spin fa-spinner "></span>
|
||||
<AddressModal :address="data.working_address" ref="address_modal"></AddressModal>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import {Address} from "../../../types";
|
||||
import {reactive, ref} from "vue";
|
||||
import {getAddressById} from "../../../lib/api/address";
|
||||
import AddressModal from "./AddressModal.vue";
|
||||
|
||||
export interface AddressModalContentProps {
|
||||
//address?: Address|null,
|
||||
address_id: number,
|
||||
}
|
||||
|
||||
const data = reactive<{
|
||||
loading: boolean,
|
||||
working_address: Address | null,
|
||||
}>({
|
||||
loading: false,
|
||||
working_address: null,
|
||||
});
|
||||
|
||||
const props = defineProps<AddressModalContentProps>();
|
||||
|
||||
const address_modal = ref<InstanceType<typeof AddressModal> | null>(null)
|
||||
|
||||
async function clickOrOpen(): Promise<void> {
|
||||
if (data.working_address === null) {
|
||||
data.loading = true;
|
||||
data.working_address = await getAddressById(props.address_id);
|
||||
data.loading = false;
|
||||
}
|
||||
|
||||
// open the modal
|
||||
address_modal.value?.open();
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
@@ -0,0 +1,22 @@
|
||||
<template>
|
||||
<address-details-map :address="props.address"></address-details-map>
|
||||
<address-render-box :address="props.address"></address-render-box>
|
||||
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import {Address} from "../../../types";
|
||||
import AddressDetailsMap from "./Parts/AddressDetailsMap.vue";
|
||||
import AddressRenderBox from "../Entity/AddressRenderBox.vue";
|
||||
|
||||
interface AddressModalContentProps {
|
||||
address: Address,
|
||||
}
|
||||
|
||||
const props = defineProps<AddressModalContentProps>();
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
@@ -0,0 +1,49 @@
|
||||
<template>
|
||||
<teleport to="body">
|
||||
<modal v-if="state.show_modal" @close="close">
|
||||
<template v-slot:header>
|
||||
<h2>Détails d'une adresse</h2>
|
||||
</template>
|
||||
<template v-slot:body>
|
||||
<address-details-content :address="props.address"></address-details-content>
|
||||
</template>
|
||||
</modal>
|
||||
</teleport>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import {reactive, ref} from "vue";
|
||||
import Modal from 'ChillMainAssets/vuejs/_components/Modal.vue';
|
||||
import {Address} from "../../../types";
|
||||
import AddressDetailsContent from "./AddressDetailsContent.vue";
|
||||
|
||||
interface AddressModalProps {
|
||||
address: Address
|
||||
}
|
||||
|
||||
interface AddressModalState {
|
||||
show_modal: boolean,
|
||||
}
|
||||
|
||||
const props = defineProps<AddressModalProps>();
|
||||
const state: AddressModalState = reactive({show_modal: false});
|
||||
const dummy = ref(false);
|
||||
|
||||
const open = (): void => {
|
||||
state.show_modal = true;
|
||||
}
|
||||
|
||||
const close = (): void => {
|
||||
state.show_modal = false;
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
close,
|
||||
open,
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
@@ -0,0 +1,91 @@
|
||||
<template>
|
||||
<div v-if="props.address.isNoAddress" class="alert alert-info">
|
||||
Cette adresse est incomplète. La position géographique est approximative.
|
||||
</div>
|
||||
<div v-if="props.address.point !== null" class="address_details_map" ref="map_div"></div>
|
||||
<a :href="makeUrlGoogleMap(props.address)" target="_blank">Google Maps</a>
|
||||
<a :href="makeUrlOsm(props.address)" target="_blank">OSM</a>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import {onMounted, ref} from "vue";
|
||||
import 'leaflet/dist/leaflet.css';
|
||||
import markerIconPng from "leaflet/dist/images/marker-icon.png";
|
||||
import L, {LatLngExpression, LatLngTuple} from "leaflet";
|
||||
import {Address, Point} from "../../../../types";
|
||||
|
||||
const lonLatForLeaflet = (point: Point): LatLngTuple => {
|
||||
return [point.coordinates[1], point.coordinates[0]];
|
||||
}
|
||||
|
||||
export interface MapProps {
|
||||
address: Address,
|
||||
}
|
||||
|
||||
const props = defineProps<MapProps>();
|
||||
|
||||
const map_div = ref<HTMLDivElement | null>(null)
|
||||
let map: L.Map|null = null;
|
||||
let marker: L.Marker|null = null;
|
||||
|
||||
onMounted(() => {
|
||||
console.log(map_div.value);
|
||||
if (map_div.value === null) {
|
||||
throw new Error('map div not found');
|
||||
}
|
||||
|
||||
if (props.address.point !== null) {
|
||||
map = L.map(map_div.value);
|
||||
map.setView(lonLatForLeaflet(props.address.point), 15);
|
||||
|
||||
|
||||
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
||||
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
|
||||
}).addTo(map);
|
||||
|
||||
|
||||
const markerIcon = L.icon({
|
||||
iconUrl: markerIconPng,
|
||||
iconAnchor: [12, 41],
|
||||
});
|
||||
|
||||
marker = L.marker(lonLatForLeaflet(props.address.point), {icon: markerIcon});
|
||||
marker.addTo(map);
|
||||
}
|
||||
});
|
||||
|
||||
const makeUrlGoogleMap = (address: Address): string => {
|
||||
const params = new URLSearchParams();
|
||||
params.append('api', '1');
|
||||
if (address.point !== null) {
|
||||
params.append('query', `${address.point.coordinates[1]} ${address.point.coordinates[0]}`);
|
||||
} else {
|
||||
params.append('query', address.lines.join(', '));
|
||||
}
|
||||
|
||||
return `https://www.google.com/maps/search/?${params.toString()}`;
|
||||
}
|
||||
|
||||
const makeUrlOsm = (address: Address): string => {
|
||||
if (address.point !== null) {
|
||||
const params = new URLSearchParams();
|
||||
params.append('mlat', `${address.point.coordinates[1]}`);
|
||||
params.append('mlon', `${address.point.coordinates[0]}`);
|
||||
const hashParams = new URLSearchParams();
|
||||
hashParams.append('map', `18/${address.point.coordinates[1]}/${address.point.coordinates[0]}`);
|
||||
|
||||
return `https://www.openstreetmap.org/?${params.toString()}#${hashParams.toString()}`;
|
||||
}
|
||||
|
||||
const params = new URLSearchParams();
|
||||
params.append('query', address.lines.join(', '));
|
||||
|
||||
return `https://www.openstreetmap.org/search?${params.toString()}`;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
div.address_details_map {
|
||||
height: 250px;
|
||||
}
|
||||
</style>
|
Reference in New Issue
Block a user