mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-08-21 15:13:50 +00:00
Merge remote-tracking branch 'origin/master' into features/household-editor
This commit is contained in:
@@ -23,7 +23,7 @@
|
||||
// @import "bootstrap/scss/button-group";
|
||||
// @import "bootstrap/scss/input-group";
|
||||
// @import "bootstrap/scss/custom-forms";
|
||||
// @import "bootstrap/scss/nav";
|
||||
@import "bootstrap/scss/nav";
|
||||
// @import "bootstrap/scss/navbar";
|
||||
// @import "bootstrap/scss/card";
|
||||
// @import "bootstrap/scss/breadcrumb";
|
||||
|
@@ -50,7 +50,7 @@ div#header-accompanying_course-name {
|
||||
background: none repeat scroll 0 0 #718596;
|
||||
color: #FFF;
|
||||
h1 {
|
||||
margin: 0.4em 0;
|
||||
margin: 0.4em 0;
|
||||
}
|
||||
span {
|
||||
a {
|
||||
@@ -71,7 +71,7 @@ div#header-accompanying_course-details {
|
||||
/*
|
||||
* FLEX RESPONSIVE TABLE/BLOCK PRESENTATION
|
||||
*/
|
||||
div.flex-bloc,
|
||||
div.flex-bloc,
|
||||
div.flex-table {
|
||||
h2, h3, h4, dl, p {
|
||||
margin: 0;
|
||||
@@ -85,38 +85,38 @@ div.flex-table {
|
||||
* Bloc appearance
|
||||
*/
|
||||
div.flex-bloc {
|
||||
box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
align-items: stretch;
|
||||
align-content: stretch;
|
||||
|
||||
|
||||
div.item-bloc {
|
||||
flex-grow: 0; flex-shrink: 1; flex-basis: 50%;
|
||||
|
||||
|
||||
margin: 0;
|
||||
border: 1px solid #000;
|
||||
padding: 1em;
|
||||
|
||||
|
||||
border-top: 0;
|
||||
&:nth-child(1), &:nth-child(2) {
|
||||
&:nth-child(1), &:nth-child(2) {
|
||||
border-top: 1px solid #000;
|
||||
}
|
||||
border-left: 0;
|
||||
&:nth-child(odd) {
|
||||
border-left: 1px solid #000;
|
||||
}
|
||||
|
||||
|
||||
//background-color: #e6e6e6;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
|
||||
div.item-row {
|
||||
flex-grow: 1; flex-shrink: 1; flex-basis: auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
|
||||
div.item-col {
|
||||
&:first-child {
|
||||
flex-grow: 0; flex-shrink: 0; flex-basis: auto;
|
||||
@@ -124,7 +124,7 @@ div.flex-bloc {
|
||||
&:last-child {
|
||||
flex-grow: 1; flex-shrink: 1; flex-basis: auto;
|
||||
display: flex;
|
||||
|
||||
|
||||
.list-content { // ul, dl, or div
|
||||
}
|
||||
ul.record_actions {
|
||||
@@ -134,7 +134,7 @@ div.flex-bloc {
|
||||
li {
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -147,7 +147,7 @@ div.flex-bloc {
|
||||
margin: auto 0;
|
||||
div.item-bloc {
|
||||
border-left: 1px solid #000;
|
||||
&:nth-child(2) {
|
||||
&:nth-child(2) {
|
||||
border-top: 0;
|
||||
}
|
||||
}
|
||||
@@ -156,13 +156,13 @@ div.flex-bloc {
|
||||
|
||||
/*
|
||||
* Table appearance
|
||||
*/
|
||||
*/
|
||||
div.flex-table {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
align-content: stretch;
|
||||
|
||||
|
||||
div.item-bloc {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -173,7 +173,7 @@ div.flex-table {
|
||||
border-top: 1px solid #000;
|
||||
}
|
||||
&:nth-child(even) {
|
||||
background-color: #e6e6e6;
|
||||
background-color: #e6e6e6;
|
||||
}
|
||||
|
||||
div.item-row {
|
||||
@@ -185,7 +185,7 @@ div.flex-table {
|
||||
padding-top: 0.5em;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
|
||||
div.item-col {
|
||||
&:first-child {
|
||||
flex-grow: 0; flex-shrink: 0; flex-basis: 33%;
|
||||
@@ -194,7 +194,7 @@ div.flex-table {
|
||||
flex-grow: 1; flex-shrink: 1; flex-basis: auto;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
|
||||
|
||||
.list-content { // ul, dl, or div
|
||||
}
|
||||
ul.record_actions {
|
||||
@@ -204,7 +204,7 @@ div.flex-table {
|
||||
li {
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@media only screen and (max-width: 900px) {
|
||||
@@ -217,9 +217,47 @@ div.flex-table {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// neutralize
|
||||
|
||||
// neutralize
|
||||
div.chill_address div.chill_address_address p { text-indent: 0; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Address form
|
||||
*/
|
||||
div.address_form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
div.address_form__header {
|
||||
|
||||
}
|
||||
div.address_form__select {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
|
||||
div.address_form__select__body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
div.address_form__select__map {
|
||||
margin: 0px 20px;
|
||||
div#address_map {
|
||||
height:400px;
|
||||
width:400px;
|
||||
}
|
||||
}
|
||||
}
|
||||
div.address_form__more {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
|
||||
|
||||
<div v-if="address.address">
|
||||
{{ address.address.street }}, {{ address.address.streetNumber }}
|
||||
</div>
|
||||
@@ -9,7 +9,7 @@
|
||||
<div v-if="address.country">
|
||||
{{ address.country.name }}
|
||||
</div>
|
||||
|
||||
|
||||
<add-address
|
||||
@addNewAddress="addNewAddress">
|
||||
</add-address>
|
||||
@@ -33,7 +33,26 @@ export default {
|
||||
methods: {
|
||||
addNewAddress({ address, modal }) {
|
||||
console.log('@@@ CLICK button addNewAdress', address);
|
||||
this.$store.dispatch('addAddress', address.selected);
|
||||
|
||||
let newAddress = {
|
||||
'isNoAddress': address.isNoAddress,
|
||||
'street': address.selected.address.street,
|
||||
'streetNumber': address.selected.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){
|
||||
newAddress = Object.assign(newAddress, {'point': address.selected.address.point.coordinates});
|
||||
}
|
||||
|
||||
this.$store.dispatch('addAddress', newAddress);
|
||||
modal.showModal = false;
|
||||
}
|
||||
}
|
||||
|
@@ -1,12 +1,13 @@
|
||||
const addressMessages = {
|
||||
fr: {
|
||||
add_an_address: 'Ajouter une adresse',
|
||||
select_an_address: 'Sélectionner une adresse',
|
||||
add_an_address_title: 'Ajouter une adresse',
|
||||
select_an_address_title: 'Sélectionner une adresse',
|
||||
fill_an_address: 'Compléter l\'adresse',
|
||||
select_country: 'Choisir le pays',
|
||||
select_city: 'Choisir une localité',
|
||||
select_address: 'Choisir une adresse',
|
||||
isNoAddress: 'L\'adresse n\'est pas celle d\'un domicile fixe ?',
|
||||
create_address: 'Appuyer sur "Entrée" pour créer une nouvelle adresse',
|
||||
isNoAddress: 'Pas d\'adresse complète',
|
||||
floor: 'Étage',
|
||||
corridor: 'Couloir',
|
||||
steps: 'Escalier',
|
||||
|
@@ -1,8 +1,7 @@
|
||||
import 'es6-promise/auto';
|
||||
import { createStore } from 'vuex';
|
||||
|
||||
// le fetch POST serait rangé dans la logique du composant qui appelle AddAddress
|
||||
//import { postAddress } from '... api'
|
||||
import { postAddress } from '../../_api/AddAddress'
|
||||
|
||||
const debug = process.env.NODE_ENV !== 'production';
|
||||
|
||||
@@ -10,11 +9,14 @@ const store = createStore({
|
||||
strict: debug,
|
||||
state: {
|
||||
address: {},
|
||||
errorMsg: {}
|
||||
errorMsg: []
|
||||
},
|
||||
getters: {
|
||||
},
|
||||
mutations: {
|
||||
catchError(state, error) {
|
||||
state.errorMsg.push(error);
|
||||
},
|
||||
addAddress(state, address) {
|
||||
console.log('@M addAddress address', address);
|
||||
state.address = address;
|
||||
@@ -23,19 +25,19 @@ const store = createStore({
|
||||
actions: {
|
||||
addAddress({ commit }, payload) {
|
||||
console.log('@A addAddress payload', payload);
|
||||
commit('addAddress', payload); // à remplacer par
|
||||
|
||||
// fetch POST qui envoie l'adresse, et récupère la confirmation que c'est ok.
|
||||
// La confirmation est l'adresse elle-même.
|
||||
//
|
||||
// postAddress(payload)
|
||||
// .fetch(address => new Promise((resolve, reject) => {
|
||||
// commit('addAddress', address);
|
||||
// resolve();
|
||||
// }))
|
||||
// .catch((error) => {
|
||||
// state.errorMsg.push(error.message);
|
||||
// });
|
||||
//commit('addAddress', payload); // à remplacer par la suite
|
||||
|
||||
//fetch POST qui envoie l'adresse, et récupère la confirmation que c'est ok.
|
||||
//La confirmation est l'adresse elle-même.
|
||||
|
||||
postAddress(payload)
|
||||
.then(address => new Promise((resolve, reject) => {
|
||||
commit('addAddress', address);
|
||||
resolve();
|
||||
}))
|
||||
.catch((error) => {
|
||||
commit('catchError', error);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@@ -1,37 +1,43 @@
|
||||
/*
|
||||
* Endpoint countries GET
|
||||
* TODO
|
||||
* Endpoint chill_api_single_country__index
|
||||
* method GET, get Country Object
|
||||
* @returns {Promise} a promise containing all Country object
|
||||
*/
|
||||
const fetchCountries = () => {
|
||||
console.log('<<< fetching countries');
|
||||
return [
|
||||
{id: 1, name: 'France', countryCode: 'FR'},
|
||||
{id: 2, name: 'Belgium', countryCode: 'BE'}
|
||||
];
|
||||
|
||||
const url = `/api/1.0/main/country.json?item_per_page=1000`;
|
||||
return fetch(url)
|
||||
.then(response => {
|
||||
if (response.ok) { return response.json(); }
|
||||
throw Error('Error with request resource response');
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
* Endpoint cities GET
|
||||
* TODO
|
||||
* Endpoint chill_api_single_postal_code__index
|
||||
* method GET, get Country Object
|
||||
* @returns {Promise} a promise containing all Postal Code objects filtered with country
|
||||
*/
|
||||
const fetchCities = (country) => {
|
||||
const fetchCities = (country) => {
|
||||
console.log('<<< fetching cities for', country);
|
||||
return [
|
||||
{id: 1, name: 'Bruxelles', code: '1000', country: 'BE'},
|
||||
{id: 2, name: 'Aisne', code: '85045', country: 'FR'},
|
||||
{id: 3, name: 'Saint-Gervais', code: '85230', country: 'FR'}
|
||||
];
|
||||
const url = `/api/1.0/main/postal-code.json?item_per_page=1000&country=${country.id}`;
|
||||
return fetch(url)
|
||||
.then(response => {
|
||||
if (response.ok) { return response.json(); }
|
||||
throw Error('Error with request resource response');
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
* Endpoint chill_main_address_reference_api_show
|
||||
* Endpoint chill_api_single_address_reference__index
|
||||
* method GET, get AddressReference Object
|
||||
* @returns {Promise} a promise containing all AddressReference object
|
||||
* @returns {Promise} a promise containing all AddressReference objects filtered with postal code
|
||||
*/
|
||||
const fetchReferenceAddresses = (city) => {
|
||||
console.log('<<< fetching references addresses for', city); // city n'est pas utilisé pour le moment
|
||||
|
||||
const url = `/api/1.0/main/address-reference.json`;
|
||||
const fetchReferenceAddresses = (postalCode) => {
|
||||
console.log('<<< fetching references addresses for', postalCode);
|
||||
//TODO deal with huge number of addresses... we should do suggestion...
|
||||
const url = `/api/1.0/main/address-reference.json?item_per_page=1000&postal_code=${postalCode.id}`;
|
||||
return fetch(url)
|
||||
.then(response => {
|
||||
if (response.ok) { return response.json(); }
|
||||
@@ -39,8 +45,31 @@ const fetchReferenceAddresses = (city) => {
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
* Endpoint chill_api_single_address__entity__create
|
||||
* method POST, post Address Object
|
||||
* @returns {Promise}
|
||||
*/
|
||||
const postAddress = (address) => {
|
||||
console.log(address);
|
||||
const url = `/api/1.0/main/address.json?`;
|
||||
const body = address;
|
||||
|
||||
return fetch(url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json;charset=utf-8'
|
||||
},
|
||||
body: JSON.stringify(body)
|
||||
}).then(response => {
|
||||
if (response.ok) { return response.json(); }
|
||||
throw Error('Error with request resource response');
|
||||
});
|
||||
};
|
||||
|
||||
export {
|
||||
fetchCountries,
|
||||
fetchCities,
|
||||
fetchReferenceAddresses
|
||||
fetchReferenceAddresses,
|
||||
postAddress
|
||||
};
|
||||
|
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<button class="sc-button bt-create centered mt-4" @click="openModal">
|
||||
{{ $t('add_an_address') }}
|
||||
{{ $t('add_an_address_title') }}
|
||||
</button>
|
||||
|
||||
<teleport to="body">
|
||||
@@ -9,76 +9,64 @@
|
||||
@close="modal.showModal = false">
|
||||
|
||||
<template v-slot:header>
|
||||
<h3 class="modal-title">{{ $t('add_an_address') }}</h3>
|
||||
<h3 class="modal-title">{{ $t('add_an_address_title') }}</h3>
|
||||
</template>
|
||||
|
||||
<template v-slot:body>
|
||||
|
||||
<h4>{{ $t('select_an_address') }}</h4>
|
||||
|
||||
<label for="isNoAddress">
|
||||
<input type="checkbox"
|
||||
name="isNoAddress"
|
||||
v-bind:placeholder="$t('isNoAddress')"
|
||||
v-model="isNoAddress"
|
||||
v-bind:value="value"/>
|
||||
{{ $t('isNoAddress') }}
|
||||
</label>
|
||||
<div class="address_form">
|
||||
|
||||
<country-selection
|
||||
v-bind:address="address"
|
||||
v-bind:getCities="getCities">
|
||||
</country-selection>
|
||||
|
||||
<city-selection
|
||||
v-bind:address="address"
|
||||
v-bind:getReferenceAddresses="getReferenceAddresses">
|
||||
</city-selection>
|
||||
|
||||
<address-selection
|
||||
v-bind:address="address"
|
||||
v-bind:updateMapCenter="updateMapCenter">
|
||||
</address-selection>
|
||||
<div class="address_form__header">
|
||||
<h4>{{ $t('select_an_address_title') }}</h4>
|
||||
</div>
|
||||
|
||||
<address-map
|
||||
v-bind:address="address"
|
||||
ref="addressMap">
|
||||
</address-map>
|
||||
|
||||
<address-more
|
||||
v-if="!isNoAddress"
|
||||
v-bind:address="address">
|
||||
</address-more>
|
||||
|
||||
<!--
|
||||
<div class="address_form__fields__isNoAddress"></div>
|
||||
<div class="address_form__select">
|
||||
<div class="address_form__select__header"></div>
|
||||
<div class="address_form__select__left"></div>
|
||||
<div class="address_form__map"></div>
|
||||
<div class="address_form__select">
|
||||
|
||||
<div class="address_form__select__body">
|
||||
<label for="isNoAddress">
|
||||
<input type="checkbox"
|
||||
name="isNoAddress"
|
||||
v-bind:placeholder="$t('isNoAddress')"
|
||||
v-model="isNoAddress"
|
||||
v-bind:value="value"/>
|
||||
{{ $t('isNoAddress') }}
|
||||
</label>
|
||||
|
||||
<country-selection
|
||||
v-bind:address="address"
|
||||
v-bind:getCities="getCities">
|
||||
</country-selection>
|
||||
|
||||
<city-selection
|
||||
v-bind:address="address"
|
||||
v-bind:getReferenceAddresses="getReferenceAddresses">
|
||||
</city-selection>
|
||||
|
||||
<address-selection
|
||||
v-bind:address="address"
|
||||
v-bind:updateMapCenter="updateMapCenter">
|
||||
</address-selection>
|
||||
</div>
|
||||
|
||||
<div class="address_form__select__map">
|
||||
<address-map
|
||||
v-bind:address="address"
|
||||
ref="addressMap">
|
||||
</address-map>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="address_form__more">
|
||||
<address-more
|
||||
v-if="!isNoAddress"
|
||||
v-bind:address="address">
|
||||
</address-more>
|
||||
</div>
|
||||
</div>
|
||||
<div class="address_form__fields">
|
||||
<div class="address_form__fields__header"></div>
|
||||
<div class="address_form__fields__left"></div>
|
||||
<div class="address_form__fields__right"></div>
|
||||
</div>
|
||||
|
||||
à discuter,
|
||||
mais je pense qu'il est préférable de profiter de l'imbriquation des classes css
|
||||
|
||||
div.address_form {
|
||||
div.select {
|
||||
div.header {}
|
||||
div.left {}
|
||||
div.map {}
|
||||
}
|
||||
}
|
||||
|
||||
-->
|
||||
|
||||
</template>
|
||||
|
||||
<template v-slot:footer>
|
||||
<button class="sc-button green"
|
||||
<button class="sc-button green"
|
||||
@click.prevent="$emit('addNewAddress', { address, modal })">
|
||||
<i class="fa fa-plus fa-fw"></i>{{ $t('action.add')}}
|
||||
</button>
|
||||
@@ -155,49 +143,47 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getCountries();
|
||||
},
|
||||
methods: {
|
||||
openModal() {
|
||||
this.modal.showModal = true;
|
||||
this.resetAll();
|
||||
this.getCountries();
|
||||
|
||||
//this.$nextTick(function() {
|
||||
// this.$refs.search.focus(); // positionner le curseur à l'ouverture de la modale
|
||||
//})
|
||||
},
|
||||
getCountries() {
|
||||
console.log('getCountries');
|
||||
this.address.loaded.countries = fetchCountries(); // à remplacer par
|
||||
// fetchCountries().then(countries => new Promise((resolve, reject) => {
|
||||
// this.address.loaded.countries = countries;
|
||||
// resolve()
|
||||
// }))
|
||||
// .catch((error) => {
|
||||
// this.errorMsg.push(error.message);
|
||||
// });
|
||||
fetchCountries().then(countries => new Promise((resolve, reject) => {
|
||||
this.address.loaded.countries = countries.results;
|
||||
resolve()
|
||||
}))
|
||||
.catch((error) => {
|
||||
this.errorMsg.push(error.message);
|
||||
});
|
||||
},
|
||||
getCities(country) {
|
||||
console.log('getCities for', country.name);
|
||||
this.address.loaded.cities = fetchCities(); // à remplacer par
|
||||
// fetchCities(country).then(cities => new Promise((resolve, reject) => {
|
||||
// this.address.loaded.cities = cities;
|
||||
// resolve()
|
||||
// }))
|
||||
// .catch((error) => {
|
||||
// this.errorMsg.push(error.message);
|
||||
// });
|
||||
fetchCities(country).then(cities => new Promise((resolve, reject) => {
|
||||
this.address.loaded.cities = cities.results;
|
||||
resolve()
|
||||
}))
|
||||
.catch((error) => {
|
||||
this.errorMsg.push(error.message);
|
||||
});
|
||||
},
|
||||
getReferenceAddresses(city) {
|
||||
console.log('getReferenceAddresses for', city.name);
|
||||
fetchReferenceAddresses(city) // il me semble que le paramètre city va limiter le poids des adresses de références reçues
|
||||
.then(addresses => new Promise((resolve, reject) => {
|
||||
fetchReferenceAddresses(city).then(addresses => new Promise((resolve, reject) => {
|
||||
console.log('addresses', addresses);
|
||||
this.address.loaded.addresses = addresses.results;
|
||||
resolve();
|
||||
}))
|
||||
.catch((error) => {
|
||||
this.errorMsg.push(error.message);
|
||||
});
|
||||
.catch((error) => {
|
||||
this.errorMsg.push(error.message);
|
||||
});
|
||||
},
|
||||
updateMapCenter(point) {
|
||||
console.log('point', point);
|
||||
@@ -208,7 +194,7 @@ export default {
|
||||
resetAll() {
|
||||
console.log('reset all selected');
|
||||
this.address.loaded.addresses = [];
|
||||
this.address.selected.address = {};
|
||||
this.address.selected.address = {};
|
||||
this.address.loaded.cities = [];
|
||||
this.address.selected.city = {};
|
||||
this.address.selected.country = {};
|
||||
|
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="container">
|
||||
<div id='address_map' style='height:400px; width:400px;'></div>
|
||||
<div id='address_map'></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -11,6 +11,7 @@ import markerIconPng from 'leaflet/dist/images/marker-icon.png'
|
||||
import 'leaflet/dist/leaflet.css';
|
||||
|
||||
let map;
|
||||
let marker;
|
||||
|
||||
export default {
|
||||
name: 'AddressMap',
|
||||
@@ -30,13 +31,15 @@ export default {
|
||||
|
||||
const markerIcon = L.icon({
|
||||
iconUrl: markerIconPng,
|
||||
iconAnchor: [12, 41],
|
||||
});
|
||||
|
||||
L.marker([48.8589, 2.3469], {icon: markerIcon}).addTo(map);
|
||||
marker = L.marker([48.8589, 2.3469], {icon: markerIcon}).addTo(map);
|
||||
|
||||
},
|
||||
update() {
|
||||
console.log('update map with : ', this.address.addressMap.center)
|
||||
marker.setLatLng(this.address.addressMap.center);
|
||||
map.setView(this.address.addressMap.center, 12);
|
||||
}
|
||||
},
|
||||
|
@@ -1,38 +1,56 @@
|
||||
<template>
|
||||
<div class="container">
|
||||
<select
|
||||
v-model="selected">
|
||||
<option :value="{}" disabled selected>{{ $t('select_address') }}</option>
|
||||
<option
|
||||
v-for="item in this.addresses"
|
||||
v-bind:item="item"
|
||||
v-bind:key="item.id"
|
||||
v-bind:value="item">
|
||||
{{ item.street }}, {{ item.streetNumber }}
|
||||
</option>
|
||||
</select>
|
||||
<VueMultiselect
|
||||
v-model="value"
|
||||
@select="selectAddress"
|
||||
name="field"
|
||||
track-by="id"
|
||||
label="value"
|
||||
:custom-label="transName"
|
||||
:taggable="true"
|
||||
:multiple="false"
|
||||
@tag="addAddress"
|
||||
:placeholder="$t('select_address')"
|
||||
:tagPlaceholder="$t('create_address')"
|
||||
:options="addresses">
|
||||
</VueMultiselect>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import VueMultiselect from 'vue-multiselect';
|
||||
|
||||
export default {
|
||||
name: 'AddressSelection',
|
||||
components: { VueMultiselect },
|
||||
props: ['address', 'updateMapCenter'],
|
||||
data() {
|
||||
return {
|
||||
value: null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
addresses() {
|
||||
return this.address.loaded.addresses;
|
||||
addresses() {
|
||||
return this.address.loaded.addresses;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
transName(value) {
|
||||
return value.streetNumber === undefined ? value.street : `${value.street}, ${value.streetNumber}`
|
||||
},
|
||||
selected: {
|
||||
set(value) {
|
||||
console.log('selected value', value);
|
||||
this.address.selected.address = value;
|
||||
this.updateMapCenter(value.point);
|
||||
},
|
||||
get() {
|
||||
return this.address.selected.address;
|
||||
}
|
||||
selectAddress(value) {
|
||||
this.address.selected.address = value;
|
||||
this.updateMapCenter(value.point);
|
||||
},
|
||||
addAddress (newAddress) {
|
||||
const address = {
|
||||
street: newAddress
|
||||
};
|
||||
this.value = address;
|
||||
this.address.selected.address = address;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style src="vue-multiselect/dist/vue-multiselect.css"></style>
|
||||
|
@@ -1,38 +1,45 @@
|
||||
<template>
|
||||
<div class="container">
|
||||
<select
|
||||
v-model="selected">
|
||||
<option :value="{}" disabled selected>{{ $t('select_city') }}</option>
|
||||
<option
|
||||
v-for="item in this.cities"
|
||||
v-bind:item="item"
|
||||
v-bind:key="item.id"
|
||||
v-bind:value="item">
|
||||
{{ item.code }}-{{ item.name }}
|
||||
</option>
|
||||
</select>
|
||||
<VueMultiselect
|
||||
v-model="value"
|
||||
@select="selectCity"
|
||||
name="field"
|
||||
track-by="id"
|
||||
label="value"
|
||||
:custom-label="transName"
|
||||
:placeholder="$t('select_city')"
|
||||
:options="cities">
|
||||
</VueMultiselect>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import VueMultiselect from 'vue-multiselect';
|
||||
|
||||
export default {
|
||||
name: 'CitySelection',
|
||||
components: { VueMultiselect },
|
||||
props: ['address', 'getReferenceAddresses'],
|
||||
data() {
|
||||
return {
|
||||
value: null
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
transName(value) {
|
||||
return `${value.code}-${value.name}`
|
||||
},
|
||||
selectCity(value) {
|
||||
this.address.selected.city = value;
|
||||
this.getReferenceAddresses(value);
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
cities() {
|
||||
return this.address.loaded.cities;
|
||||
},
|
||||
selected: {
|
||||
set(value) {
|
||||
console.log('selected value', value.name);
|
||||
this.address.selected.city = value;
|
||||
this.getReferenceAddresses(value);
|
||||
},
|
||||
get() {
|
||||
return this.address.selected.city;
|
||||
}
|
||||
},
|
||||
cities() {
|
||||
return this.address.loaded.cities;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style src="vue-multiselect/dist/vue-multiselect.css"></style>
|
||||
|
@@ -1,38 +1,59 @@
|
||||
<template>
|
||||
<div class="container">
|
||||
<select
|
||||
v-model="selected">
|
||||
<option :value="{}" disabled selected>{{ $t('select_country') }}</option>
|
||||
<option
|
||||
v-for="item in this.countries"
|
||||
v-bind:item="item"
|
||||
v-bind:key="item.id"
|
||||
v-bind:value="item">
|
||||
{{ item.name }}
|
||||
</option>
|
||||
</select>
|
||||
<VueMultiselect
|
||||
v-model="value"
|
||||
name="field"
|
||||
track-by="id"
|
||||
label="name"
|
||||
:custom-label="transName"
|
||||
:placeholder="$t('select_country')"
|
||||
:options="countries"
|
||||
@select="selectCountry">
|
||||
</VueMultiselect>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import VueMultiselect from 'vue-multiselect';
|
||||
|
||||
export default {
|
||||
name: 'CountrySelection',
|
||||
components: { VueMultiselect },
|
||||
props: ['address', 'getCities'],
|
||||
computed: {
|
||||
countries() {
|
||||
return this.address.loaded.countries;
|
||||
},
|
||||
selected: {
|
||||
set(value) {
|
||||
console.log('selected value', value.name);
|
||||
this.address.selected.country = value;
|
||||
this.getCities(value);
|
||||
},
|
||||
get() {
|
||||
return this.address.selected.country;
|
||||
data() {
|
||||
return {
|
||||
value: this.address.loaded.countries.filter(c => c.countryCode === 'FR')[0]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
if (this.value !== undefined) {
|
||||
this.getCities(this.value);
|
||||
}
|
||||
},
|
||||
transName ({ name }) {
|
||||
return name.fr //TODO multilang
|
||||
},
|
||||
selectCountry(value) {
|
||||
console.log(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;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style src="vue-multiselect/dist/vue-multiselect.css"></style>
|
||||
|
@@ -0,0 +1,153 @@
|
||||
<template>
|
||||
|
||||
<a class="sc-button" target="_blank"
|
||||
:class="classAction"
|
||||
:title="$t(titleAction)"
|
||||
@click="openModal">
|
||||
{{ buttonText }}
|
||||
</a>
|
||||
|
||||
<teleport to="body">
|
||||
<modal v-if="modal.showModal"
|
||||
:modalDialogClass="modal.modalDialogClass"
|
||||
@close="modal.showModal = false">
|
||||
|
||||
<template v-slot:header>
|
||||
<h3 class="modal-title">{{ $t(titleModal) }}</h3>
|
||||
</template>
|
||||
|
||||
<template v-slot:body v-if="type === 'person'">
|
||||
<on-the-fly-person
|
||||
v-bind:id="id"
|
||||
v-bind:type="type"
|
||||
v-bind:action="action"
|
||||
ref="castPerson">
|
||||
</on-the-fly-person>
|
||||
</template>
|
||||
|
||||
<template v-slot:body v-else-if="type === 'thirdparty'">
|
||||
<on-the-fly-thirdparty
|
||||
v-bind:id="id"
|
||||
v-bind:type="type"
|
||||
v-bind:action="action"
|
||||
ref="castThirdparty">
|
||||
</on-the-fly-thirdparty>
|
||||
</template>
|
||||
|
||||
<template v-slot:body v-else>
|
||||
<on-the-fly-create
|
||||
v-bind:action="action"
|
||||
ref="castNew">
|
||||
</on-the-fly-create>
|
||||
</template>
|
||||
|
||||
<template v-slot:footer>
|
||||
<button v-if="action === 'show'"
|
||||
@click="changeActionTo('edit')"
|
||||
class="sc-button bt-update"> <!-- @click.prevent="$emit('..', ..)" -->
|
||||
</button>
|
||||
<button v-else
|
||||
class="sc-button bt-save"
|
||||
@click="saveAction"
|
||||
> <!--
|
||||
-->
|
||||
{{ $t('action.save')}}
|
||||
</button>
|
||||
</template>
|
||||
|
||||
</modal>
|
||||
</teleport>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Modal from 'ChillMainAssets/vuejs/_components/Modal.vue';
|
||||
import OnTheFlyPerson from 'ChillPersonAssets/vuejs/_components/OnTheFly/Person.vue';
|
||||
import OnTheFlyThirdparty from './OnTheFly/ThirdParty.vue';
|
||||
import OnTheFlyCreate from './OnTheFly/Create.vue';
|
||||
|
||||
export default {
|
||||
name: 'OnTheFly',
|
||||
components: {
|
||||
Modal,
|
||||
OnTheFlyPerson,
|
||||
OnTheFlyThirdparty,
|
||||
OnTheFlyCreate
|
||||
},
|
||||
props: ['type', 'id', 'action', 'buttonText'],
|
||||
data() {
|
||||
return {
|
||||
modal: {
|
||||
showModal: false,
|
||||
modalDialogClass: "modal-dialog-scrollable modal-xl"
|
||||
},
|
||||
action: this.action
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
action() {
|
||||
return this.$data.action;
|
||||
},
|
||||
classAction() {
|
||||
switch (this.action) {
|
||||
case 'show':
|
||||
return 'bt-show';
|
||||
case 'edit':
|
||||
return 'bt-update';
|
||||
case 'create':
|
||||
return 'bt-create';
|
||||
}
|
||||
},
|
||||
titleAction() {
|
||||
switch (this.action) {
|
||||
case 'show':
|
||||
return 'action.show';
|
||||
case 'edit':
|
||||
return 'action.edit';
|
||||
case 'create':
|
||||
return 'action.create';
|
||||
}
|
||||
},
|
||||
titleModal() {
|
||||
switch (this.action) {
|
||||
case 'show':
|
||||
return 'onthefly.show.' + this.type;
|
||||
case 'edit':
|
||||
return 'onthefly.edit.' + this.type;
|
||||
case 'create':
|
||||
return 'onthefly.create.title';
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
openModal() {
|
||||
this.modal.showModal = true;
|
||||
this.$nextTick(function() {
|
||||
//this.$refs.search.focus();
|
||||
})
|
||||
},
|
||||
changeActionTo(action) {
|
||||
// [BUG] clic first on show item button; in modal clic edit button; close modal; clic again on show item button
|
||||
this.$data.action = action;
|
||||
},
|
||||
saveAction() {
|
||||
console.log('saveAction');
|
||||
if (this.type === 'person') {
|
||||
this.$refs.castPerson.postData();
|
||||
} else if (this.type === 'thirdparty') {
|
||||
this.$refs.castThirdparty.postData();
|
||||
} else {
|
||||
// saveAction() ==cast=to==> child.castByType() ==cast=to==> grand-child.postData()
|
||||
this.$refs.castNew.castByType();
|
||||
}
|
||||
this.modal.showModal = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
a {
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
@@ -0,0 +1,84 @@
|
||||
<template>
|
||||
<ul class="nav nav-tabs">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" :class="{ active: isActive('person') }">
|
||||
<label for="person">
|
||||
<input type="radio" name="person" v-model="radioType" value="person">
|
||||
{{ $t('onthefly.create.person') }}
|
||||
</label>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" :class="{ active: isActive('thirdparty') }">
|
||||
<label for="thirdparty">
|
||||
<input type="radio" name="thirdparty" v-model="radioType" value="thirdparty">
|
||||
{{ $t('onthefly.create.thirdparty') }}
|
||||
</label>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div class="my-4">
|
||||
<on-the-fly-person
|
||||
v-if="type === 'person'"
|
||||
v-bind:action="action"
|
||||
ref="castPerson">
|
||||
</on-the-fly-person>
|
||||
|
||||
<on-the-fly-thirdparty
|
||||
v-if="type === 'thirdparty'"
|
||||
v-bind:action="action"
|
||||
ref="castThirdparty">
|
||||
</on-the-fly-thirdparty>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import OnTheFlyPerson from 'ChillPersonAssets/vuejs/_components/OnTheFly/Person.vue';
|
||||
import OnTheFlyThirdparty from './ThirdParty.vue'; // TODO move in ChillThirdpartyAssets
|
||||
|
||||
export default {
|
||||
name: "OnTheFlyCreate",
|
||||
props: ['action'],
|
||||
components: {
|
||||
OnTheFlyPerson,
|
||||
OnTheFlyThirdparty
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
type: 'person' //by default
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
radioType: {
|
||||
set(type) {
|
||||
this.type = type;
|
||||
},
|
||||
get() {
|
||||
return this.type;
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
isActive(tab) {
|
||||
return (this.type === tab) ? true : false;
|
||||
},
|
||||
castByType() {
|
||||
console.log('saveActionByType');
|
||||
if (this.type === 'person') {
|
||||
this.$refs.castPerson.postData();
|
||||
} else if (this.type === 'thirdparty') {
|
||||
this.$refs.castThirdparty.postData();
|
||||
} else {
|
||||
throw Error('Invalid type of entity');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
label {
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
@@ -0,0 +1,23 @@
|
||||
<template>
|
||||
<div v-if="action === 'show'">
|
||||
show
|
||||
thirdparty
|
||||
{{ id }}
|
||||
</div>
|
||||
<div v-else-if="action === 'edit' || action === 'create'">
|
||||
{{ action }}
|
||||
thirdparty
|
||||
{{ id }}
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "OnTheFlyThirdParty",
|
||||
props: ['id', 'type', 'action']
|
||||
}
|
||||
// TODO move in ChillThirdpartyAssets
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
</style>
|
@@ -46,6 +46,22 @@ const messages = {
|
||||
previous: "Précédent",
|
||||
top: "Haut",
|
||||
bottom: "Bas",
|
||||
},
|
||||
onthefly: {
|
||||
show: {
|
||||
person: "Détails de l'usager",
|
||||
thirdparty: "Détails du tiers"
|
||||
},
|
||||
edit: {
|
||||
person: "Modifier un usager",
|
||||
thirdparty: "Modifier un tiers"
|
||||
},
|
||||
create: {
|
||||
button: "Créer \"{q}\"",
|
||||
title: "Créer à la volée…",
|
||||
person: "un nouvel usager",
|
||||
thirdparty: "un nouveau tiers"
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
|
Reference in New Issue
Block a user