address refactoring: resolve lack of flexibility for many implementations (modal/not, overriding, options, etc. )

address creation/edition is unchanged
many variables are renamed to improve logic and readability
This commit is contained in:
2021-08-02 16:27:11 +02:00
parent 7665181d44
commit 884de5c19e
24 changed files with 894 additions and 713 deletions

View File

@@ -1,282 +1,473 @@
<template>
<button v-if="!edit"
class="btn btn-create mt-4"
type="button"
name="button"
@click="openModal">
{{ $t(modalAddTitle) }}
</button>
<button v-else
class="btn btn-create mt-4"
type="button"
name="button"
@click="openModal">
{{ $t(modalEditTitle) }}
<button v-if="step1WithModal"
@click="openShowPane"
class="btn btn-create mt-4" type="button" name="button">
{{ $t(getTextButton) }}
</button>
<teleport to="body">
<modal v-if="modal.showModal"
v-bind:modalDialogClass="modal.modalDialogClass"
@close="modal.showModal = false">
<teleport to="body" v-if="step1WithModal">
<modal v-if="flag.showPane"
modalDialogClass="modal-dialog-scrollable modal-xl"
@close="flag.showPane = false">
<template v-slot:header>
<h3 v-if="!edit" class="modal-title">{{ $t(modalAddTitle) }}</h3>
<h3 v-if="edit" class="modal-title">{{ $t(modalEditTitle) }}</h3>
<h2 class="modal-title">{{ $t(getTextTitle) }}
<span v-if="flag.loading" class="loading">
<i class="fa fa-circle-o-notch fa-spin fa-fw"></i>
<span class="sr-only">Loading...</span>
</span>
</h2>
</template>
<template v-slot:body>
<div class="address-form">
<h4 class="h3">{{ $t('select_an_address_title') }}
<span v-if="loading">
<i class="fa fa-circle-o-notch fa-spin fa-lg"></i>
</span>
</h4>
<div class="row my-3">
<div class="col-lg-6">
<div class="form-check">
<input type="checkbox"
class="form-check-input"
id="isNoAddress"
v-model="isNoAddress"
v-bind:value="value" />
<label class="form-check-label" for="isNoAddress">
{{ $t('isNoAddress') }}
</label>
</div>
<country-selection
v-bind:address="address"
v-bind:getCities="getCities">
</country-selection>
<city-selection
v-bind:address="address"
v-bind:focusOnAddress="focusOnAddress"
v-bind:getReferenceAddresses="getReferenceAddresses">
</city-selection>
<address-selection
v-if="!isNoAddress"
v-bind:address="address"
v-bind:updateMapCenter="updateMapCenter">
</address-selection>
</div>
<div class="col-lg-6 mt-3 mt-lg-0">
<address-map
v-bind:address="address"
ref="addressMap">
</address-map>
</div>
</div>
<address-more
v-if="!isNoAddress"
v-bind:address="address">
</address-more>
</div>
<show-address
v-bind:context="this.context"
v-bind:options="this.options"
v-bind:default="this.default"
v-bind:entity="this.entity"
v-bind:flag="this.flag">
</show-address>
</template>
<template v-slot:footer>
<button class="btn btn-create"
@click.prevent="$emit('addNewAddress', { address, modal })">
{{ $t('action.add')}}
<button @click="openEditPane"
class="btn btn-update">
{{ $t('action.edit')}}
</button>
<button class="btn btn-save"
@click.prevent="$emit('submitAddress', { getSubmited , flag })">
{{ $t('action.save')}}
</button>
</template>
</modal>
</teleport>
<div class="mt-4" v-else>
<show-address v-if="flag.showPane"
v-bind:context="this.context"
v-bind:options="this.options"
v-bind:default="this.default"
v-bind:entity="this.entity"
v-bind:flag="this.flag"
v-bind:insideModal="false" @openEditPane="openEditPane"
@submitAddress="$emit('submitAddress', { getSubmited , flag })">
</show-address>
</div>
<teleport to="body" v-if="step2WithModal">
<modal v-if="flag.editPane"
modalDialogClass="modal-dialog-scrollable modal-xl"
@close="flag.editPane = false">
<template v-slot:header>
<h2 class="modal-title">{{ $t(getTextTitle) }}
<span v-if="flag.loading" class="loading">
<i class="fa fa-circle-o-notch fa-spin fa-fw"></i>
<span class="sr-only">Loading...</span>
</span>
</h2>
</template>
<template v-slot:body>
<edit-address
v-bind:context="this.context"
v-bind:options="this.options"
v-bind:default="this.default"
v-bind:entity="this.entity"
v-bind:flag="this.flag"
@getCities="getCities"
@getReferenceAddresses="getReferenceAddresses">
</edit-address>
</template>
<template v-slot:footer>
<button class="btn btn-cancel change-icon" @click="flag.showPane = true; flag.editPane = false;">
{{ $t('action.cancel') }}
</button>
<button class="btn btn-update"
@click="closeEditPane">
{{ $t('action.valid')}}
</button>
</template>
</modal>
</teleport>
<div class="mt-4" v-else>
<edit-address v-if="flag.editPane"
v-bind:context="this.context"
v-bind:options="this.options"
v-bind:default="this.default"
v-bind:entity="this.entity"
v-bind:flag="this.flag"
v-bind:insideModal="false" @closeEditPane="closeEditPane"
@getCities="getCities"
@getReferenceAddresses="getReferenceAddresses">
</edit-address>
</div>
</template>
<script>
import Modal from 'ChillMainAssets/vuejs/_components/Modal';
import { fetchCountries, fetchCities, fetchReferenceAddresses } from '../api'
import CountrySelection from './AddAddress/CountrySelection';
import CitySelection from './AddAddress/CitySelection';
import AddressSelection from './AddAddress/AddressSelection';
import AddressMap from './AddAddress/AddressMap';
import AddressMore from './AddAddress/AddressMore'
import ShowAddress from './ShowAddress.vue';
import EditAddress from './EditAddress.vue';
import {
getAddress,
fetchCountries, fetchCities, fetchReferenceAddresses,
patchAddress, postAddress, postPostalCode, postAddressToPerson
} from '../api'
export default {
name: 'AddAddresses',
name: "AddAddress",
props: ['context', 'options'],
emits: ['submitAddress'],
components: {
Modal,
CountrySelection,
CitySelection,
AddressSelection,
AddressMap,
AddressMore
ShowAddress,
EditAddress,
},
props: [
'modalAddTitle',
'modalEditTitle'
],
emits: ['addNewAddress'],
data() {
return {
edit: window.mode === 'edit',
modal: {
showModal: false,
modalDialogClass: "modal-dialog-scrollable modal-xl"
flag: {
showPane: false,
editPane: false,
loading: false,
success: false
},
loading: false,
address: {
writeNewAddress: false,
writeNewPostalCode: false,
default: {
textButton: { create: 'add_an_address_title', edit: 'edit_address' },
title: { create: 'add_an_address_title', edit: 'edit_address' },
bindModal: {
step1: true,
step2: true,
},
},
entity: {
address: {}, // <== loaded and returned
loaded: {
countries: [],
cities: [],
addresses: [],
},
selected: {
selected: { // <== make temporary changes
isNoAddress: false,
country: {},
city: {},
postcode: {
code: null,
name: null
},
address: {},
},
newPostalCode: {
code: null,
name: null
writeNew: {
address: false,
postcode: false
}
},
addressMap: {
center : [48.8589, 2.3469], // Note: LeafletJs demands [lat, lon] cfr https://macwright.com/lonlat/
// Note: LeafletJs demands [lat, lon]
// cfr https://macwright.com/lonlat/
center : [48.8589, 2.3469],
zoom: 12
},
isNoAddress: false,
street: null,
streetNumber: null,
corridor: null,
steps: null,
floor: null,
flat: null,
buildingName: null,
extra: null,
distribution: null,
},
errorMsg: {},
errorMsg: []
}
},
computed: {
isNoAddress: {
set(value) {
console.log('value', value);
this.address.isNoAddress = value;
},
get() {
return this.address.isNoAddress;
// TODO improve: props options must override data default
step1WithModal() {
return (this.options.bindModal) ? this.options.bindModal.step1 : this.default.bindModal.step1;
},
step2WithModal() {
return (this.options.bindModal) ? this.options.bindModal.step2 : this.default.bindModal.step2;
},
getTextButton() {
if (this.options.textButton) {
return (this.context.edit) ? this.options.textButton.edit : this.options.textButton.create;
}
return (this.context.edit) ? this.default.textButton.edit : this.default.textButton.create;
},
getTextTitle() {
if (this.options.title) {
return (this.context.edit) ? this.options.title.edit : this.options.title.create;
}
return (this.context.edit) ? this.default.title.edit : this.default.title.create;
},
getSubmited() {
return this.entity.address;
}
},
mounted() {
this.getCountries();
if (!this.step1WithModal) {
console.log('Mounted now !');
this.openShowPane();
}
},
methods: {
openModal() {
this.modal.showModal = true;
this.resetAll();
//this.$nextTick(function() {
// this.$refs.search.focus(); // positionner le curseur à l'ouverture de la modale
//})
/*
* Opening and closing Panes when interacting with buttons
*/
openShowPane() {
console.log('open the Show Panel');
if (this.context.addressId) {
this.getInitialAddress(this.context.addressId);
}
this.flag.showPane = true;
},
focusOnCity() {
const citySelector = document.getElementById('citySelector');
citySelector.focus();
openEditPane() {
console.log('open the Edit panel');
this.initForm();
this.getCountries();
},
focusOnAddress() {
const addressSelector = document.getElementById('addressSelector');
addressSelector.focus();
closeEditPane() {
console.log('close the Edit Panel (with validation)');
this.applyChanges();
this.flag.showPane = true;
this.flag.editPane = false;
},
getCountries() {
console.log('getCountries');
this.loading = true;
fetchCountries().then(countries => new Promise((resolve, reject) => {
this.address.loaded.countries = countries.results;
resolve()
this.loading = false;
}))
.catch((error) => {
this.errorMsg.push(error.message);
this.loading = false;
});
},
getCities(country) {
console.log('getCities for', country.name);
this.loading = true;
fetchCities(country).then(cities => new Promise((resolve, reject) => {
this.address.loaded.cities = cities.results.filter(c => c.origin !== 3); // filter out user-defined cities
resolve();
this.loading = false;
/*
* Async Fetch datas
*/
getInitialAddress(id) {
this.flag.loading = true;
getAddress(id).then(
address => new Promise((resolve, reject) => {
this.entity.address = address;
this.flag.loading = false;
resolve();
}))
.catch((error) => {
this.errorMsg.push(error.message);
this.loading = false;
this.flag.loading = false;
});
},
getReferenceAddresses(city) {
this.loading = true;
console.log('getReferenceAddresses for', city.name);
fetchReferenceAddresses(city).then(addresses => new Promise((resolve, reject) => {
console.log('addresses', addresses);
this.address.loaded.addresses = addresses.results;
getCountries() {
this.flag.loading = true;
fetchCountries().then(
countries => new Promise((resolve, reject) => {
this.entity.loaded.countries = countries.results;
this.flag.showPane = false;
this.flag.editPane = true;
this.flag.loading = false;
resolve()
}))
.catch((error) => {
this.errorMsg.push(error.message);
this.flag.loading = false;
});
},
getCities(country) {
this.flag.loading = true;
fetchCities(country).then(
cities => new Promise((resolve, reject) => {
this.entity.loaded.cities = cities.results.filter(c => c.origin !== 3); // filter out user-defined cities
this.flag.loading = false;
resolve();
this.loading = false;
}))
.catch((error) => {
this.errorMsg.push(error.message);
this.loading = false;
}))
.catch((error) => {
this.errorMsg.push(error.message);
this.flag.loading = false;
});
},
getReferenceAddresses(city) {
this.flag.loading = true;
fetchReferenceAddresses(city).then(
addresses => new Promise((resolve, reject) => {
this.entity.loaded.addresses = addresses.results;
this.flag.loading = false;
resolve();
}))
.catch((error) => {
this.errorMsg.push(error.message);
this.flag.loading = false;
});
},
/*
* Make form ready for new changes
*/
initForm() {
console.log('init form');
this.entity.loaded.addresses = [];
this.entity.loaded.cities = [];
this.entity.loaded.countries = [];
this.entity.selected.isNoAddress = (this.context.edit && this.entity.address.text === '') ? true : false;
this.entity.selected.country = this.context.edit ? this.entity.address.country : {};
this.entity.selected.postcode = this.context.edit ? this.entity.address.postcode : {};
this.entity.selected.city = {};
this.entity.selected.address = {};
this.entity.selected.address.street = this.context.edit ? this.entity.address.street: null;
this.entity.selected.address.streetNumber = this.context.edit ? this.entity.address.streetNumber: null;
this.entity.selected.address.floor = this.context.edit ? this.entity.address.floor: null;
this.entity.selected.address.corridor = this.context.edit ? this.entity.address.corridor: null;
this.entity.selected.address.steps = this.context.edit ? this.entity.address.steps: null;
this.entity.selected.address.flat = this.context.edit ? this.entity.address.flat: null;
this.entity.selected.address.buildingName = this.context.edit ? this.entity.address.buildingName: null;
this.entity.selected.address.distribution = this.context.edit ? this.entity.address.distribution: null;
this.entity.selected.address.extra = this.context.edit ? this.entity.address.extra: null;
this.entity.selected.writeNew.address = this.context.edit;
this.entity.selected.writeNew.postcode = this.context.edit;
},
/*
* When changes are validated,
* apply some transformations before asyncing with backend
* from entity.selected to entity.address
*/
applyChanges() {
let newAddress = {
'isNoAddress': this.entity.selected.isNoAddress,
'street': this.entity.selected.isNoAddress ? '' : this.entity.selected.address.street,
'streetNumber': this.entity.selected.isNoAddress ? '' : this.entity.selected.address.streetNumber,
'postcode': {'id': this.entity.selected.city.id },
'floor': this.entity.selected.address.floor,
'corridor': this.entity.selected.address.corridor,
'steps': this.entity.selected.address.steps,
'flat': this.entity.selected.address.flat,
'buildingName': this.entity.selected.address.buildingName,
'distribution': this.entity.selected.address.distribution,
'extra': this.entity.selected.address.extra
};
if (this.entity.selected.address.point !== undefined) {
newAddress = Object.assign(newAddress, {
'point': this.entity.selected.address.point.coordinates
});
}
if (this.entity.selected.writeNew.postcode) {
let newPostcode = this.entity.selected.postcode;
newPostcode = Object.assign(newPostcode, {
'country': {'id': this.entity.selected.country.id },
});
newAddress = Object.assign(newAddress, {
'newPostcode': newPostcode
});
}
if (this.context.edit) {
this.updateAddress({ addressId: this.context.addressId, newAddress: newAddress });
} else {
this.addAddress(newAddress);
}
},
updateMapCenter(point) {
console.log('point', point);
this.address.addressMap.center[0] = point.coordinates[1]; // TODO use reverse()
this.address.addressMap.center[1] = point.coordinates[0];
this.$refs.addressMap.update(); // cast child methods
/*
* Async PATCH transactions,
* then update existing address with backend datas when promise is resolved
*/
updateAddress(payload) {
console.log('updateAddress payload', payload);
// TODO change the condition because it writes new postal code in edit mode now: !writeNewPostalCode
this.flag.loading = true;
if ('newPostcode' in payload.newAddress) {
let postcodeBody = payload.newAddress.newPostcode;
postcodeBody = Object.assign(postcodeBody, {'origin': 3});
postPostalCode(postcodeBody)
.then(postalCode => {
let body = payload.newAddress;
body.postcode = {'id': postalCode.id },
patchAddress(payload.addressId, body)
.then(address => new Promise((resolve, reject) => {
console.log('update address');
this.entity.address = address;
this.flag.loading = false;
resolve();
}))
.catch((error) => {
this.errorMsg.push(error);
this.flag.loading = false;
});
})
} else {
patchAddress(payload.addressId, payload.newAddress)
.then(address => new Promise((resolve, reject) => {
console.log('update address');
this.entity.address = address;
this.flag.loading = false;
resolve();
}))
.catch((error) => {
this.errorMsg.push(error);
this.flag.loading = false;
});
}
},
resetAll() {
console.log('reset all selected');
this.address.loaded.addresses = [];
this.address.selected.address = {};
this.address.loaded.cities = [];
this.address.selected.city = {};
this.address.selected.country = {};
this.address.isNoAddress = this.edit ? this.$store.state.editAddress.isNoAddress: false;;
this.address.street = this.edit ? this.$store.state.editAddress.street: null;
this.address.streetNumber = this.edit ? this.$store.state.editAddress.streetNumber: null;
this.address.floor = this.edit ? this.$store.state.editAddress.floor: null;
this.address.corridor = this.edit ? this.$store.state.editAddress.corridor: null;
this.address.steps = this.edit ? this.$store.state.editAddress.steps: null;
this.address.flat = this.edit ? this.$store.state.editAddress.flat: null;
this.address.buildingName = this.edit ? this.$store.state.editAddress.buildingName: null;
this.address.distribution = this.edit ? this.$store.state.editAddress.distribution: null;
this.address.extra = this.edit ? this.$store.state.editAddress.extra: null;
this.address.writeNewAddress = this.edit;
this.address.writeNewPostalCode = this.edit;
this.address.newPostalCode = this.edit ?
{
code: this.$store.state.editAddress.postcode !== undefined ? this.$store.state.editAddress.postcode.code : null,
name: this.$store.state.editAddress.postcode !== undefined ? this.$store.state.editAddress.postcode.name : null
} : {};
console.log('cities and addresses', this.address.loaded.cities, this.address.loaded.addresses);
/*
* Async POST transactions,
* creating new address, and receive backend datas when promise is resolved
*/
addAddress(payload) {
console.log('addAddress payload', payload);
this.flag.loading = true;
if('newPostcode' in payload){
let postcodeBody = payload.newPostcode;
postcodeBody = Object.assign(postcodeBody, {'origin': 3});
postPostalCode(postcodeBody)
.then(postalCode => {
let body = payload;
body.postcode = {'id': postalCode.id},
postAddress(body)
.then(address => new Promise((resolve, reject) => {
console.log('add address');
this.entity.address = address;
resolve();
this.flag.loading = false;
}))
.catch((error) => {
this.errorMsg.push(error);
this.flag.loading = false;
});
})
} else {
postAddress(payload)
.then(address => new Promise((resolve, reject) => {
console.log('add address');
this.entity.address = address;
resolve();
this.flag.loading = false;
}))
.catch((error) => {
this.errorMsg.push(error);
this.flag.loading = false;
});
}
}
}
}
</script>
<style lang="scss">
div.address-form {
h4.h3 {
font-weight: bold;
}
div#address_map {
height: 400px;
width: 100%;
div.entity-address {
position: relative;
div.loading {
position: absolute;
right: 0; top: -55px;
}
}
</style>

View File

@@ -13,16 +13,18 @@ let marker;
export default {
name: 'AddressMap',
props: ['address'],
props: ['entity'],
computed: {
center() {
return this.address.addressMap.center;
return this.entity.selected.addressMap.center;
},
},
methods:{
init() {
map = L.map('address_map').setView([46.67059, -1.42683], 12);
map.scrollWheelZoom.disable();
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map);
@@ -36,9 +38,9 @@ export default {
},
update() {
console.log('update map with : ', this.address.addressMap.center)
marker.setLatLng(this.address.addressMap.center);
map.setView(this.address.addressMap.center, 15);
//console.log('update map with : ', this.address.addressMap.center)
marker.setLatLng(this.entity.addressMap.center);
map.setView(this.entity.addressMap.center, 15);
}
},
mounted(){

View File

@@ -74,69 +74,62 @@
<script>
export default {
name: "AddressMore",
props: ['address'],
props: ['entity'],
computed: {
floor: {
set(value) {
console.log('value', value);
this.address.floor = value;
this.entity.selected.address.floor = value;
},
get() {
return this.address.floor;
return this.entity.selected.address.floor;
}
},
corridor: {
set(value) {
console.log('value', value);
this.address.corridor = value;
this.entity.selected.address.corridor = value;
},
get() {
return this.address.corridor;
return this.entity.selected.address.corridor;
}
},
steps: {
set(value) {
console.log('value', value);
this.address.steps = value;
this.entity.selected.address.steps = value;
},
get() {
return this.address.steps;
return this.entity.selected.address.steps;
}
},
flat: {
set(value) {
console.log('value', value);
this.address.flat = value;
this.entity.selected.address.flat = value;
},
get() {
return this.address.flat;
return this.entity.selected.address.flat;
}
},
buildingName: {
set(value) {
console.log('value', value);
this.address.buildingName = value;
this.entity.selected.address.buildingName = value;
},
get() {
return this.address.buildingName;
return this.entity.selected.address.buildingName;
}
},
extra: {
set(value) {
console.log('value', value);
this.address.extra = value;
this.entity.selected.address.extra = value;
},
get() {
return this.address.extra;
return this.entity.selected.address.extra;
}
},
distribution: {
set(value) {
console.log('value', value);
this.address.distribution = value;
this.entity.selected.address.distribution = value;
},
get() {
return this.address.distribution;
return this.entity.selected.address.distribution;
}
}
}

View File

@@ -47,7 +47,7 @@ import VueMultiselect from 'vue-multiselect';
export default {
name: 'AddressSelection',
components: { VueMultiselect },
props: ['address', 'updateMapCenter'],
props: ['entity', 'updateMapCenter'],
data() {
return {
value: null
@@ -55,28 +55,28 @@ export default {
},
computed: {
writeNewAddress() {
return this.address.writeNewAddress;
return this.entity.selected.writeNew.address;
},
writeNewPostalCode() {
return this.address.writeNewPostalCode;
return this.entity.selected.writeNew.postCode;
},
addresses() {
return this.address.loaded.addresses;
return this.entity.loaded.addresses;
},
street: {
set(value) {
this.address.street = value;
this.entity.selected.address.street = value;
},
get() {
return this.address.street;
return this.entity.selected.address.street;
}
},
streetNumber: {
set(value) {
this.address.streetNumber = value;
this.entity.selected.address.streetNumber = value;
},
get() {
return this.address.streetNumber;
return this.entity.selected.address.streetNumber;
}
},
},
@@ -85,13 +85,13 @@ export default {
return value.streetNumber === undefined ? value.street : `${value.streetNumber}, ${value.street}`
},
selectAddress(value) {
this.address.selected.address = value;
this.address.street = value.street;
this.address.streetNumber = value.streetNumber;
this.entity.selected.address = value;
this.entity.selected.address.street = value.street;
this.entity.selected.address.streetNumber = value.streetNumber;
this.updateMapCenter(value.point);
},
addAddress() {
this.address.writeNewAddress = true;
this.entity.selected.writeNew.address = true;
}
}
};

View File

@@ -12,13 +12,13 @@
:placeholder="$t('select_city')"
:taggable="true"
:multiple="false"
@tag="addPostalCode"
@tag="addPostcode"
:tagPlaceholder="$t('create_postal_code')"
:options="cities">
</VueMultiselect>
</div>
<div class="custom-postcode row g-1" v-if="writeNewPostalCode">
<div class="custom-postcode row g-1" v-if="writeNewPostcode">
<div class="col-4">
<div class="form-floating">
<input class="form-control"
@@ -28,7 +28,7 @@
v-model="code"/>
<label for="code">{{ $t('postalCode_code') }}</label>
</div>
</div>
</div>
<div class="col-8">
<div class="form-floating">
<input class="form-control"
@@ -48,33 +48,34 @@ import VueMultiselect from 'vue-multiselect';
export default {
name: 'CitySelection',
components: { VueMultiselect },
props: ['address', 'getReferenceAddresses', 'focusOnAddress'],
props: ['entity', 'focusOnAddress'],
emits: ['getReferenceAddresses'],
data() {
return {
value: null
}
},
computed: {
writeNewPostalCode() {
return this.address.writeNewPostalCode;
writeNewPostcode() {
return this.entity.selected.writeNew.postcode;
},
cities() {
return this.address.loaded.cities;
return this.entity.loaded.cities;
},
name: {
set(value) {
this.address.newPostalCode.name = value;
this.entity.selected.postcode.name = value;
},
get() {
return this.address.newPostalCode.name;
return this.entity.selected.postcode.name;
}
},
code: {
set(value) {
this.address.newPostalCode.code= value;
this.entity.selected.postcode.code= value;
},
get() {
return this.address.newPostalCode.code;
return this.entity.selected.postcode.code;
}
},
},
@@ -83,14 +84,14 @@ export default {
return `${value.code}-${value.name}`
},
selectCity(value) {
this.address.selected.city = value;
this.address.newPostalCode.name = value.name;
this.address.newPostalCode.code = value.code;
this.getReferenceAddresses(value);
this.entity.selected.city = value;
this.entity.selected.postcode.name = value.name;
this.entity.selected.postcode.code = value.code;
this.$emit('getReferenceAddresses', value);
this.focusOnAddress();
},
addPostalCode() {
this.address.writeNewPostalCode = true;
addPostcode() {
this.entity.selected.writeNew.postcode = true;
}
}
};

View File

@@ -2,13 +2,13 @@
<div class="my-1">
<label class="col-form-label" for="countrySelect">{{ $t('country') }}</label>
<VueMultiselect
v-model="value"
id="countrySelect"
track-by="id"
label="name"
:custom-label="transName"
:placeholder="$t('select_country')"
:options="countries"
track-by="id"
v-bind:custom-label="transName"
v-bind:placeholder="$t('select_country')"
v-bind:options="sortedCountries"
v-model="value"
@select="selectCountry">
</VueMultiselect>
</div>
@@ -20,43 +20,47 @@ import VueMultiselect from 'vue-multiselect';
export default {
name: 'CountrySelection',
components: { VueMultiselect },
props: ['address', 'getCities'],
props: ['context', 'entity'],
emits: ['getCities'],
data() {
return {
edit: window.mode === 'edit',
defaultCountry: this.edit ? this.$store.state.editAddress.country.code : 'FR',
value: this.address.loaded.countries.filter(c => c.countryCode === this.defaultCountry)[0]
value: this.selectCountryByCode(
this.context.edit ? this.entity.selected.country.code : 'FR'
)
}
},
computed: {
sortedCountries() {
console.log('sorted countries');
const countries = this.entity.loaded.countries;
let sortedCountries = [];
sortedCountries.push(...countries.filter(c => c.countryCode === 'FR'))
sortedCountries.push(...countries.filter(c => c.countryCode === 'BE'))
sortedCountries.push(...countries.filter(c => c.countryCode !== 'FR').filter(c => c.countryCode !== 'BE'))
return sortedCountries;
}
},
mounted() {
this.init();
},
methods: {
init() {
this.value = this.edit ?
this.address.loaded.countries.filter(c => c.countryCode === this.$store.state.editAddress.country.code)[0]:
this.address.loaded.countries.filter(c => c.countryCode === 'FR')[0]
if (this.value !== undefined) {
this.selectCountry(this.value);
}
},
selectCountryByCode(countryCode) {
return this.entity.loaded.countries.filter(c => c.countryCode === countryCode)[0];
},
transName ({ name }) {
return name.fr //TODO multilang
},
selectCountry(value) {
this.address.selected.country = value;
this.getCities(value);
},
},
mounted(){
this.init()
},
computed: {
countries() {
const countries = this.address.loaded.countries;
let orderedCountries = [];
orderedCountries.push(...countries.filter(c => c.countryCode === 'FR'))
orderedCountries.push(...countries.filter(c => c.countryCode === 'BE'))
orderedCountries.push(...countries.filter(c => c.countryCode !== 'FR').filter(c => c.countryCode !== 'BE'))
return orderedCountries;
console.log('select country', value);
this.entity.selected.country = value;
this.$emit('getCities', value);
}
}
};
</script>

View File

@@ -0,0 +1,160 @@
<template>
<div class="address-form">
<!-- Not display in modal -->
<div v-if="insideModal == false" class="loading">
<i v-if="flag.loading" class="fa fa-circle-o-notch fa-spin fa-2x fa-fw"></i>
<span class="sr-only">Loading...</span>
</div>
<h4 class="h3">{{ $t('select_an_address_title') }}</h4>
<div class="row my-3">
<div class="col-lg-6">
<div class="form-check">
<input type="checkbox"
class="form-check-input"
id="isNoAddress"
v-model="isNoAddress"
v-bind:value="value" />
<label class="form-check-label" for="isNoAddress">
{{ $t('isNoAddress') }}
</label>
</div>
<country-selection
v-bind:context="context"
v-bind:entity="entity"
@getCities="$emit('getCities', selected.country)">
</country-selection>
<city-selection
v-bind:entity="entity"
v-bind:focusOnAddress="focusOnAddress"
@getReferenceAddresses="$emit('getReferenceAddresses', selected.city)">
</city-selection>
<address-selection v-if="!isNoAddress"
v-bind:entity="entity"
v-bind:updateMapCenter="updateMapCenter">
</address-selection>
</div>
<div class="col-lg-6 mt-3 mt-lg-0">
<address-map
v-bind:entity="entity"
ref="addressMap">
</address-map>
</div>
</div>
<address-more v-if="!isNoAddress"
v-bind:entity="entity">
</address-more>
<!-- Not display in modal -->
<ul v-if="insideModal == false"
class="record_actions sticky-form-buttons">
<li class="cancel">
<a class="btn btn-cancel" v-bind:href="context.backUrl">
{{ $t('back_to_the_list') }}
</a>
</li>
<li>
<a class="btn btn-cancel change-icon" @click="flag.showPane = true; flag.editPane = false;">
{{ $t('action.cancel') }}
</a>
</li>
<li>
<a class="btn btn-update" @click.prevent="$emit('closeEditPane')">
{{ $t('action.valid_and_see')}}
</a>
</li>
</ul>
</div>
</template>
<script>
import CountrySelection from './AddAddress/CountrySelection';
import CitySelection from './AddAddress/CitySelection';
import AddressSelection from './AddAddress/AddressSelection';
import AddressMap from './AddAddress/AddressMap';
import AddressMore from './AddAddress/AddressMore'
export default {
name: "EditAddress",
components: {
CountrySelection,
CitySelection,
AddressSelection,
AddressMap,
AddressMore
},
props: [
'context',
'options',
'default',
'flag',
'entity',
'errorMsg',
'insideModal'
],
emits: ['closeEditPane', 'getCities', 'getReferenceAddresses'],
data() {
return {
value: false
}
},
computed: {
address() {
return this.entity.address;
},
loaded() {
return this.entity.loaded;
},
selected() {
return this.entity.selected;
},
addressMap() {
return this.entity.addressMap;
},
isNoAddress: {
set(value) {
console.log('isNoAddress value', value);
this.entity.selected.isNoAddress = value;
},
get() {
return this.entity.selected.isNoAddress;
}
}
},
methods: {
focusOnAddress() {
const addressSelector = document.getElementById('addressSelector');
addressSelector.focus();
},
updateMapCenter(point) {
//console.log('point', point);
this.addressMap.center[0] = point.coordinates[1]; // TODO use reverse()
this.addressMap.center[1] = point.coordinates[0];
this.$refs.addressMap.update(); // cast child methods
}
}
};
</script>
<style lang="scss">
div.address-form {
h4.h3 {
font-weight: bold;
}
div#address_map {
height: 400px;
width: 100%;
}
}
</style>

View File

@@ -1,17 +1,25 @@
<template>
<div class="address multiline">
<p v-if="address.text"
class="street">
{{ address.text }}
</p>
<p v-if="address.postcode"
class="postcode">
{{ address.postcode.name }}
</p>
<p v-if="address.country"
class="country">
{{ address.country.name.fr }}
</p>
<div class="chill-entity entity-address">
<div v-if="insideModal == false" class="loading">
<i v-if="flag.loading" class="fa fa-circle-o-notch fa-spin fa-2x fa-fw"></i>
<span class="sr-only">Loading...</span>
</div>
<div class="address multiline">
<p v-if="address.text"
class="street">
{{ address.text }}
</p>
<p v-if="address.postcode"
class="postcode">
{{ address.postcode.code }} {{ address.postcode.name }}
</p>
<p v-if="address.country"
class="country">
{{ address.country.name.fr }}
</p>
</div>
<div v-if="address.floor">
<span class="floor">
@@ -48,17 +56,60 @@
<b>{{ $t('distribution') }}</b>: {{ address.distribution }}
</span>
</div>
</div>
<ul v-if="insideModal == false"
class="record_actions sticky-form-buttons">
<li class="cancel">
<a class="btn btn-cancel" v-bind:href="context.backUrl">
{{ $t('back_to_the_list') }}</a>
</li>
<li>
<a @click.prevent="$emit('openEditPane')"
class="btn btn-update">
{{ $t('action.edit')}}
</a>
</li>
<li>
<a class="btn btn-save"
@click.prevent="$emit('submitAddress', { getSubmited , flag })">
{{ $t('action.save')}}
</a>
</li>
</ul>
</template>
<script>
export default {
name: 'ShowAddress',
props: ['address'],
data() {
return {
props: [
'context',
'options',
'default',
'flag',
'entity',
'errorMsg',
'insideModal'
],
emits: ['openEditPane', 'submitAddress'],
computed: {
address() {
return this.entity.address;
},
loaded() {
return this.entity.loaded;
},
selected() {
return this.entity.selected;
},
addressMap() {
return this.entity.addressMap;
},
getSubmited() {
return this.entity.address;
}
},
}
};
</script>