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:
Mathieu Jaumotte 2021-08-02 16:27:11 +02:00
parent 7665181d44
commit 884de5c19e
24 changed files with 894 additions and 713 deletions

View File

@ -43,6 +43,7 @@ ul.record_actions {
display: flex; display: flex;
padding: 0.8em 1.6em; padding: 0.8em 1.6em;
border-radius: 0; border-radius: 0;
z-index: 1000;
} }
/// EXCEPTIONS /// EXCEPTIONS

View File

@ -1,149 +1,58 @@
<template> <template>
<div class="chill-entity entity-address">
<h2 v-if="!edit">{{ $t('create_a_new_address') }}</h2> <add-address
<h2 v-else>{{ $t('edit_address') }}</h2> v-bind:context="context"
v-bind:key="addAddress.key"
<show-address v-bind:options="addAddress.options"
v-if="address" @submitAddress="submitAddress"
v-bind:address="address"> ref="addAddress">
</show-address> </add-address>
<add-address
modalAddTitle="add_an_address_title"
modalEditTitle="edit_an_address_title"
@addNewAddress="addNewAddress">
</add-address>
</div>
<div v-if="!edit" class='person-address__valid'>
<h2>{{ $t('date') }}</h2>
<div class="input-group mb-3">
<span class="input-group-text" id="validFrom"><i class="fa fa-fw fa-calendar"></i></span>
<input type="date" class="form-control form-control-lg" name="validFrom"
v-bind:placeholder="$t('validFrom')"
v-model="validFrom"
aria-describedby="validFrom" />
</div>
<div v-if="errors.length > 0">
{{ errors }}
</div>
<div v-if="loading">
{{ $t('loading') }}
</div>
<div v-if="success">
{{ $t('person_address_creation_success') }}
</div>
</div>
<ul class="record_actions sticky-form-buttons">
<li class="cancel">
<a :href="backUrl" class="btn btn-cancel">{{ $t('back_to_the_list') }}</a>
</li>
<li v-if="!edit">
<button type="submit" class="btn btn-update" @click="addToPerson">
{{ $t('add_an_address_to_person') }}
</button>
</li>
</ul>
</template> </template>
<script> <script>
import AddAddress from './components/AddAddress.vue'; import AddAddress from './components/AddAddress.vue';
import ShowAddress from './components/ShowAddress.vue';
export default { export default {
name: 'App', name: "App",
components: { components: {
AddAddress, AddAddress
ShowAddress
}, },
data() { data() {
return { return {
edit: window.mode === 'edit', context: {
personId: window.personId, edit: window.mode === 'edit',
addressId: window.addressId, personId: window.personId,
backUrl: `/fr/person/${window.personId}/address/list`, //TODO better way to pass this addressId: window.addressId,
validFrom: new Date().toISOString().split('T')[0] backUrl: `/fr/person/${window.personId}/address/list`, //TODO better way to pass this
} validFrom: new Date().toISOString().split('T')[0]
}, },
computed: { addAddress: {
address() { key: 'person',
return this.$store.state.address; options: {
}, /// Options override default
errors() {
return this.$store.state.errorMsg; /// First button text if create or edit address (trans chain, see i18n)
}, //textButton: { create: 'bim', edit: 'bam' },
loading() {
return this.$store.state.loading; /// Modal title text if create or edit address (trans chain, see i18n)
}, //title: { create: 'boum', edit: 'pan' },
success() {
return this.$store.state.success; /// Display each step in page or Modal
//bindModal: { step1: false, step2: false } //TODO true-false must not be possible
}
}
} }
}, },
methods: { methods: {
addNewAddress({ address, modal }) { submitAddress({ submited, flag }) {
console.log('@@@ CLICK button addNewAdress', address); console.log('@@@ CLICK button submitAddress');
let newAddress = { console.log('address to post:', submited);
'isNoAddress': address.isNoAddress, console.log('datas by refs: ', this.$refs.addAddress.entity.address.text);
'street': address.isNoAddress ? '' : address.street,
'streetNumber': address.isNoAddress ? '' : address.streetNumber,
'postcode': {'id': address.selected.city.id},
'floor': address.floor,
'corridor': address.corridor,
'steps': address.steps,
'flat': address.flat,
'buildingName': address.buildingName,
'distribution': address.distribution,
'extra': address.extra
};
if (address.selected.address.point !== undefined){ this.$refs.addAddress.initForm(); // to cast child method
newAddress = Object.assign(newAddress, { flag.showPane = false;
'point': address.selected.address.point.coordinates
});
}
if (address.writeNewPostalCode){
let newPostalCode = address.newPostalCode;
newPostalCode = Object.assign(newPostalCode, {
'country': {'id': address.selected.country.id },
});
newAddress = Object.assign(newAddress, {
'newPostalCode': newPostalCode
});
}
if (this.edit){
this.$store.dispatch('updateAddress', {
addressId: this.addressId,
newAddress: newAddress
});
} else {
this.$store.dispatch('addAddress', newAddress);
}
modal.showModal = false;
},
addToPerson() {
this.$store.dispatch('addDateToAddressAndAddressToPerson', {
personId: this.personId,
addressId: this.$store.state.address.address_id,
body: { validFrom: {datetime: `${this.validFrom}T00:00:00+0100`}},
backUrl: this.backUrl
})
},
getEditAddress() {
this.$store.dispatch('getEditAddress', this.addressId);
} }
}, }
mounted() { }
if (this.edit) {
this.getEditAddress();
}
},
};
</script> </script>

View File

@ -4,7 +4,7 @@
* @returns {Promise} a promise containing all Country object * @returns {Promise} a promise containing all Country object
*/ */
const fetchCountries = () => { const fetchCountries = () => {
console.log('<<< fetching countries'); //console.log('<<< fetching countries');
const url = `/api/1.0/main/country.json?item_per_page=1000`; const url = `/api/1.0/main/country.json?item_per_page=1000`;
return fetch(url) return fetch(url)
@ -20,7 +20,7 @@ const fetchCountries = () => {
* @returns {Promise} a promise containing all Postal Code objects filtered with country * @returns {Promise} a promise containing all Postal Code objects filtered with country
*/ */
const fetchCities = (country) => { const fetchCities = (country) => {
console.log('<<< fetching cities for', country); //console.log('<<< fetching cities for', country);
const url = `/api/1.0/main/postal-code.json?item_per_page=1000&country=${country.id}`; const url = `/api/1.0/main/postal-code.json?item_per_page=1000&country=${country.id}`;
return fetch(url) return fetch(url)
.then(response => { .then(response => {
@ -35,7 +35,7 @@ const fetchCities = (country) => {
* @returns {Promise} a promise containing all AddressReference objects filtered with postal code * @returns {Promise} a promise containing all AddressReference objects filtered with postal code
*/ */
const fetchReferenceAddresses = (postalCode) => { const fetchReferenceAddresses = (postalCode) => {
console.log('<<< fetching references addresses for', postalCode); //console.log('<<< fetching references addresses for', postalCode);
const url = `/api/1.0/main/address-reference.json?item_per_page=1000&postal_code=${postalCode.id}`; const url = `/api/1.0/main/address-reference.json?item_per_page=1000&postal_code=${postalCode.id}`;
return fetch(url) return fetch(url)
.then(response => { .then(response => {
@ -50,7 +50,7 @@ const fetchReferenceAddresses = (postalCode) => {
* @returns {Promise} a promise containing all AddressReference objects filtered with postal code * @returns {Promise} a promise containing all AddressReference objects filtered with postal code
*/ */
const fetchAddresses = () => { const fetchAddresses = () => {
console.log('<<< fetching addresses'); //console.log('<<< fetching addresses');
//TODO deal with huge number of addresses... we should do suggestion... //TODO deal with huge number of addresses... we should do suggestion...
const url = `/api/1.0/main/address.json?item_per_page=1000`; const url = `/api/1.0/main/address.json?item_per_page=1000`;
return fetch(url) return fetch(url)
@ -133,8 +133,8 @@ const postPostalCode = (postalCode) => {
* @body Object - dictionary with changes to post * @body Object - dictionary with changes to post
*/ */
const postAddressToPerson = (personId, addressId) => { const postAddressToPerson = (personId, addressId) => {
console.log(personId); //console.log(personId);
console.log(addressId); //console.log(addressId);
const body = { const body = {
'id': addressId 'id': addressId
}; };
@ -157,7 +157,7 @@ const postAddressToPerson = (personId, addressId) => {
* @returns {Promise} a promise containing a Address object * @returns {Promise} a promise containing a Address object
*/ */
const getAddress = (id) => { const getAddress = (id) => {
console.log('<<< get address'); //console.log('<< get address');
const url = `/api/1.0/main/address/${id}.json`; const url = `/api/1.0/main/address/${id}.json`;
return fetch(url) return fetch(url)
.then(response => { .then(response => {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -2,13 +2,13 @@
<div class="my-1"> <div class="my-1">
<label class="col-form-label" for="countrySelect">{{ $t('country') }}</label> <label class="col-form-label" for="countrySelect">{{ $t('country') }}</label>
<VueMultiselect <VueMultiselect
v-model="value"
id="countrySelect" id="countrySelect"
track-by="id"
label="name" label="name"
:custom-label="transName" track-by="id"
:placeholder="$t('select_country')" v-bind:custom-label="transName"
:options="countries" v-bind:placeholder="$t('select_country')"
v-bind:options="sortedCountries"
v-model="value"
@select="selectCountry"> @select="selectCountry">
</VueMultiselect> </VueMultiselect>
</div> </div>
@ -20,43 +20,47 @@ import VueMultiselect from 'vue-multiselect';
export default { export default {
name: 'CountrySelection', name: 'CountrySelection',
components: { VueMultiselect }, components: { VueMultiselect },
props: ['address', 'getCities'], props: ['context', 'entity'],
emits: ['getCities'],
data() { data() {
return { return {
edit: window.mode === 'edit', value: this.selectCountryByCode(
defaultCountry: this.edit ? this.$store.state.editAddress.country.code : 'FR', this.context.edit ? this.entity.selected.country.code : 'FR'
value: this.address.loaded.countries.filter(c => c.countryCode === this.defaultCountry)[0] )
} }
}, },
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: { methods: {
init() { 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) { if (this.value !== undefined) {
this.selectCountry(this.value); this.selectCountry(this.value);
} }
}, },
selectCountryByCode(countryCode) {
return this.entity.loaded.countries.filter(c => c.countryCode === countryCode)[0];
},
transName ({ name }) { transName ({ name }) {
return name.fr //TODO multilang return name.fr //TODO multilang
}, },
selectCountry(value) { selectCountry(value) {
this.address.selected.country = value; console.log('select country', value);
this.getCities(value); this.entity.selected.country = value;
}, this.$emit('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;
} }
} }
}; };
</script> </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> <template>
<div class="address multiline"> <div class="chill-entity entity-address">
<p v-if="address.text"
class="street"> <div v-if="insideModal == false" class="loading">
{{ address.text }} <i v-if="flag.loading" class="fa fa-circle-o-notch fa-spin fa-2x fa-fw"></i>
</p> <span class="sr-only">Loading...</span>
<p v-if="address.postcode" </div>
class="postcode">
{{ address.postcode.name }} <div class="address multiline">
</p> <p v-if="address.text"
<p v-if="address.country" class="street">
class="country"> {{ address.text }}
{{ address.country.name.fr }} </p>
</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"> <div v-if="address.floor">
<span class="floor"> <span class="floor">
@ -48,17 +56,60 @@
<b>{{ $t('distribution') }}</b>: {{ address.distribution }} <b>{{ $t('distribution') }}</b>: {{ address.distribution }}
</span> </span>
</div> </div>
</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> </template>
<script> <script>
export default { export default {
name: 'ShowAddress', name: 'ShowAddress',
props: ['address'], props: [
data() { 'context',
return { '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> </script>

View File

@ -0,0 +1,42 @@
const addressMessages = {
fr: {
add_an_address_title: 'Créer une adresse',
edit_an_address_title: 'Modifier une adresse',
create_a_new_address: 'Créer une nouvelle adresse',
edit_address: 'Modifier l\'adresse',
select_an_address_title: 'Sélectionner une adresse',
fill_an_address: 'Compléter l\'adresse',
select_country: 'Choisir le pays',
country: 'Pays',
select_city: 'Choisir une localité',
city: 'Localité',
other_city: 'Autre localité',
select_address: 'Choisir une adresse',
address: 'Adresse',
other_address: 'Autre adresse',
create_address: 'Adresse inconnue. Cliquez ici pour créer une nouvelle adresse',
isNoAddress: 'Pas d\'adresse complète',
street: 'Nom de rue',
streetNumber: 'Numéro',
floor: 'Étage',
corridor: 'Couloir',
steps: 'Escalier',
flat: 'Appartement',
buildingName: 'Nom du bâtiment',
extra: 'Complément d\'adresse',
distribution: 'Service particulier de distribution',
create_postal_code: 'Localité inconnue. Cliquez ici pour créer une nouvelle localité',
postalCode_name: 'Nom',
postalCode_code: 'Code postal',
date: 'Date de la nouvelle adresse',
add_an_address_to_person: 'Ajouter l\'adresse à la personne',
validFrom: 'Date de la nouvelle adresse',
back_to_the_list: 'Retour à la liste',
person_address_creation_success: 'La nouvelle adresse de la personne est enregistrée',
loading: 'chargement en cours...'
}
};
export {
addressMessages
};

View File

@ -1,14 +1,13 @@
import { createApp } from 'vue' import { createApp } from 'vue'
import { _createI18n } from 'ChillMainAssets/vuejs/_js/i18n'
import { addressMessages } from './js/i18n'
import { store } from './store' import { store } from './store'
import App from './App.vue'; import App from './App.vue';
import { _createI18n } from 'ChillMainAssets/vuejs/_js/i18n'
import { addressMessages } from './i18n'
const i18n = _createI18n(addressMessages); const i18n = _createI18n(addressMessages);
const app = createApp({ const app = createApp({
template: `<app></app>`, template: `<app></app>`,
}) })
.use(store) .use(store)
.use(i18n) .use(i18n)

View File

@ -1,42 +0,0 @@
const addressMessages = {
fr: {
add_an_address_title: 'Créer une adresse',
edit_an_address_title: 'Modifier une adresse',
create_a_new_address: 'Créer une nouvelle adresse',
edit_address: 'Modifier l\'adresse',
select_an_address_title: 'Sélectionner une adresse',
fill_an_address: 'Compléter l\'adresse',
select_country: 'Choisir le pays',
country: 'Pays',
select_city: 'Choisir une localité',
city: 'Localité',
other_city: 'Autre localité',
select_address: 'Choisir une adresse',
address: 'Adresse',
other_address: 'Autre adresse',
create_address: 'Adresse inconnue. Cliquez ici pour créer une nouvelle adresse',
isNoAddress: 'Pas d\'adresse complète',
street: 'Nom de rue',
streetNumber: 'Numéro',
floor: 'Étage',
corridor: 'Couloir',
steps: 'Escalier',
flat: 'Appartement',
buildingName: 'Nom du bâtiment',
extra: 'Complément d\'adresse',
distribution: 'Service particulier de distribution',
create_postal_code: 'Localité inconnue. Cliquez ici pour créer une nouvelle localité',
postalCode_name: 'Nom',
postalCode_code: 'Code postal',
date: 'Date de la nouvelle adresse',
add_an_address_to_person: 'Ajouter l\'adresse à la personne',
validFrom: 'Date de la nouvelle adresse',
back_to_the_list: 'Retour à la liste',
person_address_creation_success: 'La nouvelle adresse de la personne est enregistrée',
loading: 'chargement en cours...'
}
};
export {
addressMessages
};

View File

@ -0,0 +1,14 @@
import 'es6-promise/auto';
import { createStore } from 'vuex';
const debug = process.env.NODE_ENV !== 'production';
const store = createStore({
strict: debug,
state: {},
getters: {},
mutations: {},
actions: {},
});
export { store };

View File

@ -1,158 +0,0 @@
import 'es6-promise/auto';
import { createStore } from 'vuex';
import { patchAddress, postAddress, postPostalCode, postAddressToPerson, getAddress } from '../api'
const debug = process.env.NODE_ENV !== 'production';
const store = createStore({
strict: debug,
state: {
address: {},
editAddress: {}, //TODO or should be address?
person: {},
errorMsg: [],
loading: false,
success: false
},
getters: {
},
mutations: {
catchError(state, error) {
state.errorMsg.push(error);
},
addAddress(state, address) {
console.log('@M addAddress address', address);
state.address = address;
},
updateAddress(state, address) {
console.log('@M updateAddress address', address);
state.address = address;
},
addAddressToPerson(state, person) {
console.log('@M addAddressToPerson person', person);
state.person = person;
},
addDateToAddress(state, validFrom) {
console.log('@M addDateToAddress address.validFrom', validFrom);
state.validFrom = validFrom;
},
getEditAddress(state, address) {
console.log('@M getEditAddress address', address);
state.editAddress = address;
},
setLoading(state, b) {
state.loading = b;
},
setSuccess(state, b) {
state.success = b;
}
},
actions: {
addAddress({ commit }, payload) {
console.log('@A addAddress payload', payload);
commit('setLoading', true);
if('newPostalCode' in payload){
let postalCodeBody = payload.newPostalCode;
postalCodeBody = Object.assign(postalCodeBody, {'origin': 3});
postPostalCode(postalCodeBody)
.then(postalCode => {
let body = payload;
body.postcode = {'id': postalCode.id},
postAddress(body)
.then(address => new Promise((resolve, reject) => {
commit('addAddress', address);
resolve();
commit('setLoading', false);
}))
.catch((error) => {
commit('catchError', error);
commit('setLoading', false);
});
})
} else {
postAddress(payload)
.then(address => new Promise((resolve, reject) => {
commit('addAddress', address);
resolve();
commit('setLoading', false);
}))
.catch((error) => {
commit('catchError', error);
commit('setLoading', false);
});
}
},
addDateToAddressAndAddressToPerson({ commit }, payload) {
console.log('@A addDateToAddressAndAddressToPerson payload', payload);
commit('setLoading', true);
patchAddress(payload.addressId, payload.body)
.then(address => new Promise((resolve, reject) => {
commit('addDateToAddress', address.validFrom);
resolve();
}).then(
postAddressToPerson(payload.personId, payload.addressId)
.then(person => new Promise((resolve, reject) => {
commit('addAddressToPerson', person);
commit('setLoading', false);
commit('setSuccess', true);
window.location.assign(payload.backUrl);
resolve();
}))
.catch((error) => {
commit('catchError', error);
commit('setLoading', false);
})
))
.catch((error) => {
commit('catchError', error);
commit('setLoading', false);
});
},
updateAddress({ commit }, payload) {
console.log('@A updateAddress payload', payload);
if('newPostalCode' in payload.newAddress){ // TODO change the condition because it writes new postal code in edit mode now: !writeNewPostalCode
let postalCodeBody = payload.newAddress.newPostalCode;
postalCodeBody = Object.assign(postalCodeBody, {'origin': 3});
postPostalCode(postalCodeBody)
.then(postalCode => {
let body = payload.newAddress;
body.postcode = {'id': postalCode.id },
patchAddress(payload.addressId, body)
.then(address => new Promise((resolve, reject) => {
commit('updateAddress', address);
resolve();
}))
.catch((error) => {
commit('catchError', error);
});
})
} else {
patchAddress(payload.addressId, payload.newAddress)
.then(address => new Promise((resolve, reject) => {
commit('updateAddress', address);
resolve();
}))
.catch((error) => {
commit('catchError', error);
});
}
},
getEditAddress({ commit }, payload) {
console.log('@A getEditAddress payload', payload);
getAddress(payload).then(address => new Promise((resolve, reject) => {
commit('getEditAddress', address);
resolve();
}))
.catch((error) => {
commit('catchError', error);
});
},
}
});
export { store };

View File

@ -24,16 +24,16 @@
<!-- :: end styles bootstrap :: --> <!-- :: end styles bootstrap :: -->
</div> </div>
</transition> </transition>
</template> </template>
<script> <script>
/* /*
* This Modal component is a mix between Vue3 modal implementation * This Modal component is a mix between Vue3 modal implementation
* [+] with 'v-if:showModal' directive:parameter, html scope is added/removed not just shown/hidden * [+] with 'v-if:showModal' directive:parameter, html scope is added/removed not just shown/hidden
* [+] with slot we can pass content from parent component * [+] with slot we can pass content from parent component
* [+] some classes are passed from parent component * [+] some classes are passed from parent component
* and Bootstrap 4.6 _modal.scss module * and Bootstrap 4.6 _modal.scss module
* [+] using bootstrap css classes, the modal have a responsive behaviour, * [+] using bootstrap css classes, the modal have a responsive behaviour,
* [+] modal design can be configured using css classes (size, scroll) * [+] modal design can be configured using css classes (size, scroll)
*/ */
export default { export default {
@ -54,7 +54,7 @@ export default {
background-color: rgba(0, 0, 0, 0.75); background-color: rgba(0, 0, 0, 0.75);
transition: opacity 0.3s ease; transition: opacity 0.3s ease;
} }
.modal-header .close { .modal-header .close {
border-top-right-radius: 0.3rem; border-top-right-radius: 0.3rem;
} }
/* /*
@ -71,7 +71,8 @@ export default {
.modal-leave-active { .modal-leave-active {
opacity: 0; opacity: 0;
} }
.modal-enter .modal-container, .modal-enter
.modal-container,
.modal-leave-active .modal-container { .modal-leave-active .modal-container {
-webkit-transform: scale(1.1); -webkit-transform: scale(1.1);
transform: scale(1.1); transform: scale(1.1);
@ -80,4 +81,9 @@ export default {
font-size: 1.5rem; font-size: 1.5rem;
font-weight: bold; font-weight: bold;
} }
div.modal-footer {
button:first-child {
margin-right: auto;
}
}
</style> </style>

View File

@ -32,6 +32,8 @@ const messages = {
remove: "Enlever", remove: "Enlever",
delete: "Supprimer", delete: "Supprimer",
save: "Enregistrer", save: "Enregistrer",
valid: "Valider",
valid_and_see: "Valider et voir",
add: "Ajouter", add: "Ajouter",
show_modal: "Ouvrir une modale", show_modal: "Ouvrir une modale",
ok: "OK", ok: "OK",
@ -61,7 +63,7 @@ const messages = {
title: "Création d'un nouvel usager ou d'un tiers professionnel", title: "Création d'un nouvel usager ou d'un tiers professionnel",
person: "un nouvel usager", person: "un nouvel usager",
thirdparty: "un nouveau tiers professionnel" thirdparty: "un nouveau tiers professionnel"
}, },
}, },
} }
}; };

View File

@ -9,6 +9,7 @@
<origin-demand></origin-demand> <origin-demand></origin-demand>
<requestor></requestor> <requestor></requestor>
<social-issue></social-issue> <social-issue></social-issue>
<!--course-location></course-location-->
<referrer></referrer> <referrer></referrer>
<resources></resources> <resources></resources>
<comment v-if="accompanyingCourse.step === 'DRAFT'"></comment> <comment v-if="accompanyingCourse.step === 'DRAFT'"></comment>
@ -24,7 +25,7 @@ import OriginDemand from './components/OriginDemand.vue';
import PersonsAssociated from './components/PersonsAssociated.vue'; import PersonsAssociated from './components/PersonsAssociated.vue';
import Requestor from './components/Requestor.vue'; import Requestor from './components/Requestor.vue';
import SocialIssue from './components/SocialIssue.vue'; import SocialIssue from './components/SocialIssue.vue';
import CourseLocation from './components/CourseLocation.vue'; //import CourseLocation from './components/CourseLocation.vue';
import Referrer from './components/Referrer.vue'; import Referrer from './components/Referrer.vue';
import Resources from './components/Resources.vue'; import Resources from './components/Resources.vue';
import Comment from './components/Comment.vue'; import Comment from './components/Comment.vue';
@ -39,7 +40,7 @@ export default {
PersonsAssociated, PersonsAssociated,
Requestor, Requestor,
SocialIssue, SocialIssue,
CourseLocation, //CourseLocation,
Referrer, Referrer,
Resources, Resources,
Comment, Comment,

View File

@ -1,25 +1,24 @@
<template> <template>
<div class='household__address-move'> <div class='chill-entity entity-address'>
<div class='household__address-move__create'>
<div>
<h2 v-if="!edit">{{ $t('create_a_new_address') }}</h2>
<h2 v-else>{{ $t('edit_a_new_address') }}</h2>
<add-address
modalAddTitle="add_an_address_title"
modalEditTitle="edit_an_address_title"
@addNewAddress="addNewAddress">
</add-address>
</div>
<div>
<show-address
v-if="newAddress"
v-bind:address="newAddress">
</show-address>
</div>
</div>
<div v-if="!edit" class='household__address-move__valid'>
<h2>{{ $t('move_date') }}</h2>
<div class="my-3">
<h2 v-if="!edit">{{ $t('create_a_new_address') }}</h2>
<h2 v-else>{{ $t('edit_address') }}</h2>
<show-address
v-if="newAddress"
v-bind:address="newAddress">
</show-address>
<add-address
modalAddTitle="add_an_address_title"
modalEditTitle="edit_address"
@addNewAddress="addNewAddress">
</add-address>
</div>
<div v-if="!edit" class='address-valid'>
<h2>{{ $t('move_date') }}</h2>
<div class="input-group mb-3"> <div class="input-group mb-3">
<span class="input-group-text" id="validFrom"><i class="fa fa-fw fa-calendar"></i></span> <span class="input-group-text" id="validFrom"><i class="fa fa-fw fa-calendar"></i></span>
<input type="date" class="form-control form-control-lg" name="validFrom" <input type="date" class="form-control form-control-lg" name="validFrom"
@ -27,7 +26,6 @@
v-model="validFrom" v-model="validFrom"
aria-describedby="validFrom" /> aria-describedby="validFrom" />
</div> </div>
<div v-if="errors.length > 0"> <div v-if="errors.length > 0">
{{ errors }} {{ errors }}
</div> </div>
@ -38,26 +36,26 @@
{{ $t('household_address_move_success') }} {{ $t('household_address_move_success') }}
</div> </div>
</div> </div>
<div v-if="success && edit"> <div v-if="success && edit">
{{ $t('household_address_edit_success') }} {{ $t('household_address_edit_success') }}
</div> </div>
<div>
<ul class="record_actions sticky-form-buttons"> <ul class="record_actions sticky-form-buttons">
<li class="cancel"> <li class="cancel">
<a :href="backUrl" class="btn btn-cancel">{{ $t('back_to_the_list') }}</a> <a :href="backUrl" class="btn btn-cancel">{{ $t('back_to_the_list') }}</a>
</li> </li>
<li v-if="!edit"> <li v-if="!edit">
<button type="submit" class="btn btn-update" @click="addToHousehold"> <button type="submit" class="btn btn-update" @click="addToHousehold">
{{ $t('add_an_address_to_household') }} {{ $t('add_an_address_to_household') }}
</button> </button>
</li> </li>
</ul> </ul>
</div>
</div> </div>
</template> </template>
<script> <script>
import AddAddress from 'ChillMainAssets/vuejs/Address/components/AddAddress.vue'; import AddAddress from 'ChillMainAssets/vuejs/Address/components/AddAddress.vue';
import ShowAddress from 'ChillMainAssets/vuejs/Address/components/ShowAddress.vue'; import ShowAddress from 'ChillMainAssets/vuejs/Address/components/ShowAddress.vue';
@ -153,5 +151,10 @@ export default {
} }
}, },
}; };
</script> </script>
<style lang="scss">
div.entity-address {
border: 1px dashed grey;
}
</style>

View File

@ -18,15 +18,15 @@
{% set activeRouteKey = '' %} {% set activeRouteKey = '' %}
{% block title 'Modify address for %name%'|trans({ '%name%': person.firstName ~ ' ' ~ person.lastName } ) %} {% block title 'Edit an address'|trans %}
{% block personcontent %} {% block personcontent %}
<div class="address-new"> <div class="address-edit">
{% block content %} {% block content %}
<h1>{{ block('title') }}</h1> <h1>{{ block('title') }}</h1>
<div id="address"></div> <div id="address"></div>
{% endblock %} {% endblock %}
</div> </div>
{% endblock %} {% endblock %}

View File

@ -18,16 +18,16 @@
{% set activeRouteKey = '' %} {% set activeRouteKey = '' %}
{% block title %}{{ 'New address for %name%'|trans({ '%name%': person.firstName|capitalize ~ ' ' ~ person.lastName } )|capitalize }}{% endblock %} {% block title %}{{ 'New address'|trans }}{% endblock %}
{% block personcontent %} {% block personcontent %}
<div class="address-new"> <div class="address-new">
{% block content %} {% block content %}
<h1>{{ block('title') }}</h1> <h1>{{ block('title') }}</h1>
<div id="address"></div> <div id="address"></div>
{% endblock %} {% endblock %}
</div> </div>
{% endblock %} {% endblock %}

View File

@ -8,11 +8,11 @@ module.exports = function(encore, entries)
ChillPersonAssets: __dirname + '/Resources/public' ChillPersonAssets: __dirname + '/Resources/public'
}); });
encore.addEntry('vue_household_address', __dirname + '/Resources/public/vuejs/HouseholdAddress/index.js'); //encore.addEntry('vue_household_address', __dirname + '/Resources/public/vuejs/HouseholdAddress/index.js');
encore.addEntry('vue_household_members_editor', __dirname + '/Resources/public/vuejs/HouseholdMembersEditor/index.js'); //encore.addEntry('vue_household_members_editor', __dirname + '/Resources/public/vuejs/HouseholdMembersEditor/index.js');
encore.addEntry('vue_accourse', __dirname + '/Resources/public/vuejs/AccompanyingCourse/index.js'); encore.addEntry('vue_accourse', __dirname + '/Resources/public/vuejs/AccompanyingCourse/index.js');
encore.addEntry('vue_accourse_work_create', __dirname + '/Resources/public/vuejs/AccompanyingCourseWorkCreate/index.js'); //encore.addEntry('vue_accourse_work_create', __dirname + '/Resources/public/vuejs/AccompanyingCourseWorkCreate/index.js');
encore.addEntry('vue_accourse_work_edit', __dirname + '/Resources/public/vuejs/AccompanyingCourseWorkEdit/index.js'); //encore.addEntry('vue_accourse_work_edit', __dirname + '/Resources/public/vuejs/AccompanyingCourseWorkEdit/index.js');
encore.addEntry('page_household_edit_metadata', __dirname + '/Resources/public/page/household_edit_metadata/index.js'); encore.addEntry('page_household_edit_metadata', __dirname + '/Resources/public/page/household_edit_metadata/index.js');
encore.addEntry('page_person', __dirname + '/Resources/public/page/person/index.js'); encore.addEntry('page_person', __dirname + '/Resources/public/page/person/index.js');

View File

@ -207,8 +207,10 @@ No address given: Pas d'adresse renseignée
The address has been successfully updated: L'adresse a été mise à jour avec succès The address has been successfully updated: L'adresse a été mise à jour avec succès
Update address for %name%: Mettre à jour une adresse pour %name% Update address for %name%: Mettre à jour une adresse pour %name%
Modify address for %name%: Modifier une adresse pour %name% Modify address for %name%: Modifier une adresse pour %name%
Edit an address: Modifier une adresse
Addresses history for %name%: Historique des adresses de %name% Addresses history for %name%: Historique des adresses de %name%
Addresses history: Historique des adresses Addresses history: Historique des adresses
New address : Nouvelle adresse
New address for %name% : Nouvelle adresse pour %name% New address for %name% : Nouvelle adresse pour %name%
The new address was created successfully: La nouvelle adresse a été créée The new address was created successfully: La nouvelle adresse a été créée
Add an address: Ajouter une adresse Add an address: Ajouter une adresse