515 lines
17 KiB
Vue

<template>
<button v-if="step1WithModal"
@click="openShowPane"
class="btn btn-create mt-4" type="button" name="button">
{{ $t(getTextButton) }}
</button>
<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>
<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>
<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"
ref="showAddress">
</show-address>
</template>
<template v-slot:footer>
<button @click="openEditPane"
class="btn btn-update">
{{ $t('action.edit')}}
</button>
<button class="btn btn-save"
@click="submitAddress">
{{ $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"
ref="showAddress"
v-bind:insideModal="false" @openEditPane="openEditPane"
@submitAddress="submitAddress">
</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 ShowAddress from './ShowAddress.vue';
import EditAddress from './EditAddress.vue';
import {
getAddress,
fetchCountries, fetchCities, fetchReferenceAddresses,
patchAddress, postAddress, postPostalCode, postAddressToPerson
} from '../api'
export default {
name: "AddAddress",
props: ['context', 'options', 'result'],
components: {
Modal,
ShowAddress,
EditAddress,
},
data() {
return {
flag: {
showPane: false,
editPane: false,
loading: false,
success: 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: { // <== make temporary changes
isNoAddress: false,
country: {},
city: {},
postcode: {
code: null,
name: null
},
address: {},
writeNew: {
address: false,
postcode: false
}
},
addressMap: {
// Note: LeafletJs demands [lat, lon]
// cfr https://macwright.com/lonlat/
center : [48.8589, 2.3469],
zoom: 12
},
},
valid: {
from: null,
to: null
},
errorMsg: []
}
},
computed: {
// 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;
}
},
mounted() {
if (!this.step1WithModal) {
console.log('Mounted now !');
this.openShowPane();
}
},
methods: {
/*
* 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;
},
openEditPane() {
console.log('open the Edit panel');
this.initForm();
this.getCountries();
},
closeEditPane() {
console.log('close the Edit Panel (with validation)');
this.applyChanges();
this.flag.showPane = true;
this.flag.editPane = 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.flag.loading = false;
});
},
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();
}))
.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);
}
},
/*
* Async PATCH transactions,
* then update existing address with backend datas when promise is resolved
*/
updateAddress(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) => {
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) => {
this.entity.address = address;
this.flag.loading = false;
resolve();
}))
.catch((error) => {
this.errorMsg.push(error);
this.flag.loading = false;
});
}
},
/*
* Async POST transactions,
* creating new address, and receive backend datas when promise is resolved
*/
addAddress(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) => {
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) => {
this.entity.address = address;
resolve();
this.flag.loading = false;
}))
.catch((error) => {
this.errorMsg.push(error);
this.flag.loading = false;
});
}
},
/*
* When submited
*/
submitAddress() {
console.log('@@@ CLICK button submitAddress');
this.addDateToAddressAndAddressToPerson({
personId: this.context.personId,
addressId: this.entity.address.address_id,
body: { validFrom: { datetime: `${this.$refs.showAddress.validFrom}T00:00:00+0100`}},
backUrl: this.context.backUrl
});
this.initForm();
this.flag.showPane = false;
},
addDateToAddressAndAddressToPerson(payload) {
console.log('addDateToAddressAndAddressToPerson payload', payload);
this.flag.loading = true;
patchAddress(payload.addressId, payload.body)
.then(address => new Promise((resolve, reject) => {
this.valid.from = address.validFrom;
resolve();
}).then(
postAddressToPerson(payload.personId, payload.addressId)
.then(person => new Promise((resolve, reject) => {
console.log('commit addAddressToPerson !!!', person);
this.result = person;
this.flag.loading = false;
this.flag.success = true;
window.location.assign(payload.backUrl);
resolve();
}))
.catch((error) => {
this.errorMsg.push(error);
this.flag.loading = false;
})
))
.catch((error) => {
this.errorMsg.push(error);
this.flag.loading = false;
});
}
}
}
</script>
<style lang="scss">
div.entity-address {
position: relative;
div.loading {
position: absolute;
right: 0; top: -55px;
}
}
</style>