633 lines
21 KiB
Vue

<template>
<!-- step0 -->
<show-pane 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"
@openEditPane="openEditPane"
ref="showAddress">
</show-pane>
<!-- step 1 -->
<teleport to="body" v-if="inModal">
<modal v-if="flag.suggestPane"
modalDialogClass="modal-dialog-scrollable modal-xl"
@close="resetPane">
<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">{{ $t('loading') }}</span>
</span>
</h2>
</template>
<template v-slot:body>
<suggest-pane
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="suggestAddress">
</suggest-pane>
</template>
<template v-slot:footer>
<button @click="openEditPane"
class="btn btn-update">
{{ $t('action.edit')}}
</button>
<!--
<button class="btn btn-save">
{{ $t('action.save')}}
</button>
-->
</template>
</modal>
</teleport>
<div class="mt-4" v-else>
<suggest-pane v-if="flag.suggestPane"
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"
ref="suggestAddress">
</suggest-pane>
</div>
<!-- step 2 -->
<teleport to="body" v-if="inModal">
<modal v-if="flag.editPane"
modalDialogClass="modal-dialog-scrollable modal-xl"
@close="resetPane">
<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">{{ $t('loading') }}</span>
</span>
</h2>
</template>
<template v-slot:body>
<edit-pane
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-pane>
</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-pane 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-pane>
</div>
<!-- step 3 -->
<teleport to="body" v-if="inModal">
<modal v-if="flag.datePane"
modalDialogClass="modal-dialog-scrollable modal-xl"
@close="resetPane">
<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">{{ $t('loading') }}</span>
</span>
</h2>
</template>
<template v-slot:body>
<date-pane
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="dateAddress">
</date-pane>
</template>
<template v-slot:footer>
<button @click="openEditPane"
class="btn btn-update">
{{ $t('action.edit')}}
</button>
<button class="btn btn-save">
{{ $t('action.save')}}
</button>
</template>
</modal>
</teleport>
<div class="mt-4" v-else>
<date-pane v-if="flag.datePane"
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"
ref="dateAddress">
</date-pane>
</div>
</template>
<script>
import Modal from 'ChillMainAssets/vuejs/_components/Modal';
import { getAddress, fetchCountries, fetchCities, fetchReferenceAddresses, patchAddress, postAddress, postPostalCode } from '../api';
import { postAddressToPerson, postAddressToHousehold } from "ChillPersonAssets/vuejs/_api/AddAddress.js";
import ShowPane from './ShowPane.vue';
import SuggestPane from './SuggestPane.vue';
import EditPane from './EditPane.vue';
import DatePane from './DatePane.vue';
export default {
name: "AddAddress",
props: ['context', 'options', 'addressChangedCallback'],
components: {
Modal,
ShowPane,
SuggestPane,
EditPane,
DatePane
},
data() {
return {
flag: {
showPane: true, // begin with showPane
suggestPane: false,
editPane: false,
datePane: false,
loading: false,
success: false
},
default: {
button: {
text: { create: 'add_an_address_title', edit: 'edit_address' },
type: { create: 'btn-create', edit: 'btn-update'},
displayText: true
},
title: { create: 'add_an_address_title', edit: 'edit_address' },
openPanesInModal: true,
stickyActions: false,
useDate: {
validFrom: false,
validTo: false
}
},
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
},
valid: {
from: new Date(),
to: new Date()
}
},
addressMap: {
// Note: LeafletJs demands [lat, lon]
// cfr https://macwright.com/lonlat/
center : [48.8589, 2.3469],
zoom: 12
},
},
errorMsg: []
}
},
computed: {
inModal() {
return (typeof this.options.openPanesInModal !== 'undefined') ?
this.options.openPanesInModal : this.default.openPanesInModal;
},
useDatePane() {
let vFrom = (typeof this.options.useDate !== 'undefined'
&& typeof this.options.useDate.validFrom !== 'undefined') ?
this.options.useDate.validFrom : this.default.useDate.validFrom ;
let vTo = (typeof this.options.useDate !== 'undefined'
&& typeof this.options.useDate.validTo !== 'undefined') ?
this.options.useDate.validTo : this.default.useDate.validTo ;
return (vFrom || vTo) ? true : false;
},
hasSuggestions() {
// TODO
//return addressSuggestions.length > 0
return true;
},
getTextTitle() {
if ( typeof this.options.title !== 'undefined'
&& ( this.options.title.edit !== null
|| this.options.title.create !== null
)) {
return (this.context.edit) ? this.options.title.edit : this.options.title.create;
}
return (this.context.edit) ? this.default.title.edit : this.default.title.create;
},
bypassFirstStep() {
// exception: passing step0 if new address and pane are not in modal
return !this.context.edit && !this.inModal && this.flag.editPane === false
}
},
mounted() {
//console.log('options displayText', this.options.button.displayText);
//console.log('options bindModal.step1', this.options.bindModal.step1);
//console.log('options bindModal.step2', this.options.bindModal.step2);
//console.log('options useDate.validFrom', this.options.useDate.validFrom);
//console.log('options useDate.validTo', this.options.useDate.validTo);
console.log('useDatePane', this.useDatePane);
//console.log('Mounted now !');
this.openShowPane();
},
methods: {
/*
* Opening and closing Panes when interacting with buttons
*/
openShowPane() {
if (this.context.edit) {
console.log('getInitialAddress');
this.getInitialAddress(this.context.addressId);
}
if (this.bypassFirstStep) {
this.closeShowPane();
this.openEditPane();
} else {
this.flag.showPane = true;
console.log('step0: open the Show Panel');
}
},
closeShowPane() {
// Show pane can be closed only when openPanesInModal is false
if (!this.inModal) {
this.flag.showPane = false;
console.log('step0: close the Show Panel');
}
},
openSuggestPane() {
this.flag.suggestPane = true;
console.log('step1: open the Suggestion Panel');
},
closeSuggestPane() {
this.flag.suggestPane = false;
console.log('step1: close the Suggestion Panel');
},
openEditPane() {
/*
if (!this.context.edit && this.hasSuggestions) {
this.openSuggestPane();
} else {
}
*/
this.initForm();
this.getCountries();
this.flag.editPane = true;
console.log('step2: open the Edit panel');
},
closeEditPane() {
this.applyChanges();
this.flag.editPane = false;
console.log('step2: close the Edit Panel');
/*
if (!this.context.edit && this.useDatePane) {
this.openDatePane();
} else {
}
*/
this.openShowPane()
},
openDatePane() {
this.flag.datePane = true;
console.log('step3: open the Date Panel');
},
closeDatePane() {
this.flag.datePane = false;
console.log('step3: close the Date Panel');
},
resetPane() {
this.flag.suggestPane = false;
this.flag.editPane = false;
this.flag.datePane = false;
this.flag.showPane = true;
},
/*
* 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 (get out step2 edit pane, button valid),
* 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
})
.then(payload => {
console.log('payload', payload);
this.closePaneAndCallbackSubmit(payload);
}
);
} else {
this.addNewAddress(newAddress)
.then(payload => this.closePaneAndCallbackSubmit(payload));
}
},
/*
* Async POST transactions,
* creating new address, and receive backend datas when promise is resolved
*/
addNewAddress(payload)
{
//console.log('addNewAddress', payload);
this.flag.loading = true;
if ('newPostcode' in payload) {
let postcodeBody = payload.newPostcode;
if (this.context.entity.name === 'person') {
postcodeBody = Object.assign(postcodeBody, {'origin': 3});
}
return postPostalCode(postcodeBody)
.then(postalCode => {
payload.postcode = {'id': postalCode.id };
return this.postNewAddress(payload);
});
} else {
return this.postNewAddress(payload);
}
},
postNewAddress(payload) {
//console.log('postNewAddress', payload);
return postAddress(payload)
.then(address => new Promise((resolve, reject) => {
this.entity.address = address;
this.flag.loading = false;
this.flag.success = true;
resolve({
entity: this.context.entity.name,
entityId: this.context.entity.id,
addressId: this.entity.address.address_id
}
);
}))
.catch((error) => {
this.errorMsg.push(error);
this.flag.loading = false;
});
},
/*
* Async PATCH transactions,
* then update existing address with backend datas when promise is resolved
*/
updateAddress(payload)
{
this.flag.loading = true;
// TODO change the condition because it writes new postal code in edit mode now: !writeNewPostalCode
if ('newPostcode' in payload.newAddress) {
let postcodeBody = payload.newAddress.newPostcode;
postcodeBody = Object.assign(postcodeBody, {'origin': 3});
return postPostalCode(postcodeBody)
.then(postalCode => {
console.log('create new postcode', postalCode.id);
payload.newAddress.postcode = {'id': postalCode.id };
return this.patchExistingAddress(payload);
});
} else {
return this.patchExistingAddress(payload);
}
},
patchExistingAddress(payload) {
console.log('patchExistingAddress', payload);
return patchAddress(payload.addressId, payload.newAddress)
.then(address => new Promise((resolve, reject) => {
this.entity.address = address;
this.flag.loading = false;
this.flag.success = true;
return resolve({
entity: this.context.entity.name,
entityId: this.context.entity.id,
addressId: this.entity.address.address_id
});
})
)
.catch((error) => {
this.errorMsg.push(error);
this.flag.loading = false;
});
},
/*
* Method just add closing pane to the callback method
* (get out step1 show pane, submit button)
*/
closePaneAndCallbackSubmit(payload)
{
console.log('close pane and call parent callback method', payload);
//this.initForm();
this.flag.showPane = false;
// callback props method from parent
this.addressChangedCallback(payload);
}
}
}
</script>
<style lang="scss">
div.entity-address {
position: relative;
div.loading {
position: absolute;
right: 0; top: -55px;
}
}
</style>