Merge branch '139_demandeur' into _23_addresses_form_2

This commit is contained in:
2021-05-11 15:51:06 +02:00
51 changed files with 1732 additions and 375 deletions

View File

@@ -2,6 +2,8 @@
<accompanying-course></accompanying-course>
<persons-associated></persons-associated>
<requestor></requestor>
<interlocutors></interlocutors>
<!--test></test-->
</template>
<script>
@@ -10,13 +12,17 @@ import { mapState } from 'vuex'
import AccompanyingCourse from './components/AccompanyingCourse.vue';
import PersonsAssociated from './components/PersonsAssociated.vue';
import Requestor from './components/Requestor.vue';
import Interlocutors from './components/Interlocutors.vue';
//import Test from './components/Test.vue';
export default {
name: 'App',
components: {
AccompanyingCourse,
PersonsAssociated,
Requestor
Requestor,
Interlocutors,
//Test
},
computed: mapState([
'accompanyingCourse'

View File

@@ -1,18 +1,11 @@
const
locale = 'fr',
format = 'json'
, accompanying_period_id = window.accompanyingCourseId //tmp
;
/*
* Endpoint chill_person_accompanying_course_api_show
* method GET, get AccompanyingCourse Object
* Endpoint v.2 chill_api_single_accompanying_course__entity
* method GET/HEAD, get AccompanyingCourse Instance
*
* @accompanying_period_id___ integer
* @TODO var is not used but necessary in method signature
* @id integer - id of accompanyingCourse
*/
let getAccompanyingCourse = (accompanying_period_id___) => { //tmp
const url = `/${locale}/person/api/1.0/accompanying-course/${accompanying_period_id}/show.${format}`;
const getAccompanyingCourse = (id) => {
const url = `/api/1.0/person/accompanying-course/${id}.json`;
return fetch(url)
.then(response => {
if (response.ok) { return response.json(); }
@@ -21,21 +14,50 @@ let getAccompanyingCourse = (accompanying_period_id___) => { //tmp
};
/*
* Endpoint chill_person_accompanying_course_api_add_participation,
* Endpoint v.2 chill_api_single_accompanying_course_participation,
* method POST/DELETE, add/close a participation to the accompanyingCourse
*
* @accompanying_period_id integer - id of accompanyingCourse
* @person_id integer - id of person
* @method string - POST or DELETE
* @id integer - id of accompanyingCourse
* @person_id integer - id of person
* @method string - POST or DELETE
*/
let postParticipation = (accompanying_period_id, person_id, method) => {
const url = `/${locale}/person/api/1.0/accompanying-course/${accompanying_period_id}/participation.${format}`
const postParticipation = (id, person_id, method) => {
const url = `/api/1.0/person/accompanying-course/${id}/participation.json`;
return fetch(url, {
method: method,
headers: {
'Content-Type': 'application/json;charset=utf-8'
},
body: JSON.stringify({id: person_id})
body: JSON.stringify({person_id: person_id})
})
.then(response => {
if (response.ok) { return response.json(); }
throw Error('Error with request resource response');
});
};
/*
* Endpoint v.2 chill_api_single_accompanying_course_requestor,
* method POST/DELETE, add/close a requestor to the accompanyingCourse
*
* @id integer - id of accompanyingCourse
* @payload object of type person|thirdparty
* @method string - POST or DELETE
*/
const postRequestor = (id, payload, method) => {
const body = {};
if (payload !== null) {
const typeId = `${payload.result.type}_id`;
body[typeId] = payload.result[typeId];
};
console.log(body);
const url = `/api/1.0/person/accompanying-course/${id}/requestor.json`;
return fetch(url, {
method: method,
headers: {
'Content-Type': 'application/json;charset=utf-8'
},
body: JSON.stringify(body)
})
.then(response => {
if (response.ok) { return response.json(); }
@@ -45,5 +67,6 @@ let postParticipation = (accompanying_period_id, person_id, method) => {
export {
getAccompanyingCourse,
postParticipation
postParticipation,
postRequestor
};

View File

@@ -4,14 +4,46 @@
<dl>
<dt>{{ $t('course.id') }}</dt>
<dd>{{ accompanyingCourse.id }}</dd>
<dt>{{ $t('course.user') }}</dt>
<dd v-if="accompanyingCourse.user">{{ accompanyingCourse.user.username }}</dd>
<dt>{{ $t('course.status') }}</dt>
<dd>
<div v-if="accompanyingCourse.step !== 'DRAFT'"
class="badge badge-pill badge-primary">
{{ $t('course.step.active') }}</div>
<div v-else class="badge badge-pill badge-secondary">
{{ $t('course.step.draft') }}</div>
</dd>
<dt>{{ $t('course.flags') }}</dt>
<dd>
<div v-if="accompanyingCourse.emergency === true"
class="badge badge-pill badge-primary">
{{ $t('course.emergency') }}</div>
<div v-else class="badge badge-pill badge-secondary">
{{ $t('course.emergency') }}</div>
<div v-if="accompanyingCourse.confidential === true"
class="badge badge-pill badge-primary">
{{ $t('course.confidential') }}</div>
<div v-else class="badge badge-pill badge-secondary">
{{ $t('course.confidential') }}</div>
</dd>
<dt>{{ $t('course.opening_date') }}</dt>
<dd>{{ $d(accompanyingCourse.openingDate.datetime, 'short') }}</dd>
<dt>{{ $t('course.closing_date') }}</dt>
<dd>{{ $d(accompanyingCourse.closingDate.datetime, 'short') }}</dd>
<dd v-if="accompanyingCourse.closingDate">{{ $d(accompanyingCourse.closingDate.datetime, 'short') }}</dd>
<dt>{{ $t('course.closing_motive') }}</dt>
<dd v-if="accompanyingCourse.closingMotive">{{ accompanyingCourse.closingMotive.name.fr }}</dd>
<dt>{{ $t('course.remark') }}</dt>
<dd>{{ accompanyingCourse.remark }}</dd>
<dt>{{ $t('course.closing_motive') }}</dt>
<dd>{{ accompanyingCourse.closing_motive }}</dd>
</dl>
</div>
</template>

View File

@@ -0,0 +1,54 @@
<template>
<tr>
<td>{{ interlocutor.key }}</td>
<td>{{ interlocutor.result.text }}</td>
<td><span >
</span>
</td>
<td><span >
</span>
</td>
<td>
<ul class="record_actions">
<li>
<a class="sc-button bt-show" target="_blank"
:href="url.show"
:title="$t('action.show')">
</a>
</li>
<li>
<a class="sc-button bt-update" target="_blank"
:href="url.edit"
:title="$t('action.edit')">
</a>
</li>
<li>
<button
class="sc-button bt-remove"
:title="$t('action.remove')"
@click.prevent="$emit('remove', interlocutor)">
</button>
</li>
</ul>
</td>
</tr>
</template>
<script>
export default {
name: 'InterlocutorItem',
props: ['interlocutor'],
data() {
return {
url: {
show: 'show', //'/fr/person/' + this.interlocutor.person.id + '/general',
edit: 'edit' //'/fr/person/' + this.interlocutor.person.id + '/general/edit'
}
}
},
emits: ['remove']
}
</script>

View File

@@ -0,0 +1,82 @@
<template>
<div class="vue-component">
<h3>{{ $t('interlocutors.title')}}</h3>
<label>{{ $tc('interlocutors.counter', counter) }}</label>
<table class="rounded">
<thead>
<tr>
<th class="chill-orange">{{ $t('interlocutors.firstname') }}</th>
<th class="chill-orange">{{ $t('interlocutors.lastname') }}</th>
<th>3</th>
<th>4</th>
<th class="chill-orange">{{ $t('action.actions') }}</th>
</tr>
</thead>
<tbody>
<interlocutor-item
v-for="interlocutor in interlocutors"
v-bind:interlocutor="interlocutor"
v-bind:key="interlocutor.id"
@remove="removeInterlocutor">
</interlocutor-item>
</tbody>
</table>
<add-persons
buttonTitle="interlocutors.add_interlocutors"
modalTitle="interlocutors.add_interlocutors"
v-bind:key="addPersons.key"
v-bind:options="addPersons.options"
@addNewPersons="addNewPersons"
ref="addPersons"> <!-- to cast child method -->
</add-persons>
</div>
</template>
<script>
import AddPersons from 'ChillPersonAssets/vuejs/_components/AddPersons.vue'
import InterlocutorItem from './InterlocutorItem.vue'
export default {
name: 'Interlocutors',
components: {
AddPersons,
InterlocutorItem
},
data() {
return {
addPersons: {
key: 'interlocutors',
options: {
type: ['person', 'thirdparty'],
priority: null,
uniq: false,
}
}
}
},
computed: {
accompanyingCourse() {
return this.$store.state.accompanyingCourse
}
},
methods: {
removeInterlocutor() {
console.log('@@ CLICK remove interlocutor: item');
this.$store.dispatch('removeInterlocutor');
},
addNewPersons({ selected, modal }) {
console.log('@@@ CLICK button addNewPersons', selected);
selected.forEach(function(item) {
this.$store.dispatch('addInterlocutor', item);
}, this
);
this.$refs.addPersons.resetSearch(); // to cast child method
modal.showModal = false;
}
}
}
</script>

View File

@@ -29,10 +29,12 @@
</button>
</li-->
<li>
<button class="sc-button bt-remove"
<button v-if="!participation.endDate"
class="sc-button bt-remove"
:title="$t('action.remove')"
@click.prevent="$emit('close', participation)">
</button>
<button v-else class="sc-button bt-remove disabled"></button>
</li>
</ul>
</td>

View File

@@ -2,7 +2,7 @@
<div class="vue-component">
<h3>{{ $t('persons_associated.title')}}</h3>
<label>{{ $tc('persons_associated.counter', counter) }}</label>
<table class="rounded">
<table class="rounded">
<thead>
<tr>
<th class="chill-orange">{{ $t('persons_associated.firstname') }}</th>
@@ -12,24 +12,26 @@
<th class="chill-orange">{{ $t('action.actions') }}</th>
</tr>
</thead>
<tbody>
<person-item
v-for="participation in participations"
v-bind:participation="participation"
v-bind:key="participation.id"
<tbody>
<person-item
v-for="participation in participations"
v-bind:participation="participation"
v-bind:key="participation.id"
@remove="removeParticipation"
@close="closeParticipation">
</person-item>
</tbody>
</table>
<add-persons></add-persons>
<ul class="record_actions">
<!--li>
<button class="sc-button orange" @click="savePersons">
{{ $t('action.save') }}
</button>
</li-->
</ul>
<add-persons
buttonTitle="persons_associated.add_persons"
modalTitle="add_persons.title"
v-bind:key="addPersons.key"
v-bind:options="addPersons.options"
@addNewPersons="addNewPersons"
ref="addPersons"> <!-- to cast child method -->
</add-persons>
</div>
</template>
@@ -40,27 +42,44 @@ import AddPersons from 'ChillPersonAssets/vuejs/_components/AddPersons.vue'
export default {
name: 'PersonsAssociated',
components: {
components: {
PersonItem,
AddPersons
},
data() {
return {
addPersons: {
key: 'persons_associated',
options: {
type: ['person'],
priority: null,
uniq: false,
}
}
}
},
computed: mapState({
participations: state => state.accompanyingCourse.participations,
counter: state => state.accompanyingCourse.participations.length
}),
methods: {
removeParticipation(item) {
this.$store.dispatch('removeParticipation', item)
console.log('@@ CLICK remove participation: item', item);
this.$store.dispatch('removeParticipation', item);
},
closeParticipation(item) {
console.log('@@ CLICK close participation: item', item);
this.$store.dispatch('closeParticipation', item)
this.$store.dispatch('closeParticipation', item);
},
/*
savePersons() {
console.log('[wip] saving persons');
addNewPersons({ selected, modal }) {
console.log('@@@ CLICK button addNewPersons', selected);
selected.forEach(function(item) {
this.$store.dispatch('addParticipation', item);
}, this
);
this.$refs.addPersons.resetSearch(); // to cast child method
modal.showModal = false;
}
*/
}
}
</script>

View File

@@ -1,85 +1,116 @@
<template>
<div class="vue-component">
<h3>{{ $t('requestor.title') }}</h3>
{{ accompanyingCourse.id }}
{{ accompanyingCourse.remark }}<br><br>
<!-- TESTS AREA -->
<ul class="record_actions">
<li>
<button class="sc-button bt-create" @click="modal1.showModal = true">
{{ $t('action.show_modal') }}
</button>
</li>
<li>
<button class="sc-button bt-create" @click="modal2.showModal = true">
Ouvrir une seconde modale
</button>
</li>
</ul>
<div v-if="accompanyingCourse.requestor">
<dt>{{ $t('requestor.type') }}</dt>
<dd>{{ accompanyingCourse.requestor.type }}</dd>
<dt>{{ $t('requestor.text') }}</dt>
<dd>{{ accompanyingCourse.requestor.text }}</dd>
<dt>{{ $t('requestor.anonymous') }}</dt>
<dd>{{ accompanyingCourse.requestorAnonymous }}</dd>
<div v-if="accompanyingCourse.requestor.type === 'person'">
<dt>{{ $t('requestor.person_id') }}</dt>
<dd>{{ accompanyingCourse.requestor.person_id }}</dd>
<dt>{{ $t('requestor.birthdate') }}</dt>
<dd>{{ $d(accompanyingCourse.requestor.birthdate.datetime, 'short') }}</dd>
<dt>{{ $t('requestor.center') }}</dt>
<dd>{{ accompanyingCourse.requestor.center.name }}</dd>
<dt>{{ $t('requestor.firstName') }}</dt>
<dd>{{ accompanyingCourse.requestor.firstName }}</dd>
<dt>{{ $t('requestor.lastName') }}</dt>
<dd>{{ accompanyingCourse.requestor.lastName }}</dd>
<dt>{{ $t('requestor.phonenumber') }}</dt>
<dd>{{ accompanyingCourse.requestor.phonenumber }}</dd>
<dt>{{ $t('requestor.mobilenumber') }}</dt>
<dd>{{ accompanyingCourse.requestor.mobilenumber }}</dd>
<dt>{{ $t('requestor.altNames') }}</dt>
<dd>{{ accompanyingCourse.requestor.altNames }}</dd>
</div>
<div v-if="accompanyingCourse.requestor.type === 'thirdparty'">
<dt>{{ $t('requestor.person_id') }}</dt>
<dd>{{ accompanyingCourse.requestor.thirdparty_id }}</dd>
<dt>{{ $t('requestor.address') }}</dt>
<dd>{{ accompanyingCourse.requestor.address.text }}</dd>
<dt>{{ $t('requestor.location') }}</dt>
<dd>{{ accompanyingCourse.requestor.address.postcode.name }}</dd>
</div>
</div>
<teleport to="body">
<modal v-if="modal1.showModal" :modalDialogClass="modal1.modalDialogClass" @close="modal1.showModal = false">
<template v-slot:header>
<h3 class="modal-title">Le titre de ma modale</h3>
</template>
<template v-slot:body>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus luctus facilisis suscipit. Cras pulvinar, purus sagittis pulvinar porta, enim ex posuere lacus, in pulvinar lectus magna in odio. Nullam iaculis congue lorem ac suscipit. Proin ut rutrum augue. Ut vehicula risus nec hendrerit ullamcorper. Ut volutpat eu mi eget viverra. Morbi dictum placerat suscipit. </p>
<p>Quisque non erat tincidunt, lacinia justo ut, pulvinar nisl. Nunc id enim ut sem pretium interdum consectetur eu quam. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Etiam posuere erat eget augue finibus luctus. Maecenas auctor, tortor non luctus ultrices, neque neque porttitor ex, nec lacinia lorem ligula et elit. Sed tempor nulla vitae lorem sollicitudin dictum. Vestibulum nec arcu eget elit pulvinar pretium. Phasellus facilisis metus sed diam luctus, feugiat scelerisque velit dignissim.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus luctus facilisis suscipit. Cras pulvinar, purus sagittis pulvinar porta, enim ex posuere lacus, in pulvinar lectus magna in odio. Nullam iaculis congue lorem ac suscipit. Proin ut rutrum augue. Ut vehicula risus nec hendrerit ullamcorper. Ut volutpat eu mi eget viverra. Morbi dictum placerat suscipit. </p>
<p>Quisque non erat tincidunt, lacinia justo ut, pulvinar nisl. Nunc id enim ut sem pretium interdum consectetur eu quam. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Etiam posuere erat eget augue finibus luctus. Maecenas auctor, tortor non luctus ultrices, neque neque porttitor ex, nec lacinia lorem ligula et elit. Sed tempor nulla vitae lorem sollicitudin dictum. Vestibulum nec arcu eget elit pulvinar pretium. Phasellus facilisis metus sed diam luctus, feugiat scelerisque velit dignissim.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus luctus facilisis suscipit. Cras pulvinar, purus sagittis pulvinar porta, enim ex posuere lacus, in pulvinar lectus magna in odio. Nullam iaculis congue lorem ac suscipit. Proin ut rutrum augue. Ut vehicula risus nec hendrerit ullamcorper. Ut volutpat eu mi eget viverra. Morbi dictum placerat suscipit. </p>
<p>Quisque non erat tincidunt, lacinia justo ut, pulvinar nisl. Nunc id enim ut sem pretium interdum consectetur eu quam. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Etiam posuere erat eget augue finibus luctus. Maecenas auctor, tortor non luctus ultrices, neque neque porttitor ex, nec lacinia lorem ligula et elit. Sed tempor nulla vitae lorem sollicitudin dictum. Vestibulum nec arcu eget elit pulvinar pretium. Phasellus facilisis metus sed diam luctus, feugiat scelerisque velit dignissim.</p>
</template>
<template v-slot:footer>
<button class="sc-button green" @click="modal1.showModal = false; modal2.showModal = true">
{{ $t('action.next')}}</button>
</template>
</modal>
</teleport>
<label>
<input type="checkbox" v-model="isAnonymous" :value="value" />
{{ $t('requestor.is_anonymous') }}
</label>
<teleport to="body">
<modal v-if="modal2.showModal" :modalDialogClass="modal2.modalDialogClass" @close="modal2.showModal = false">
<template v-slot:header>
<h3 class="modal-title">Une autre modale</h3>
</template>
<template v-slot:body>
<p>modal 2</p>
</template>
<template v-slot:footer>
<button class="sc-button green" @click="modal2.showModal = false">
{{ $t('action.save')}}</button>
</template>
</modal>
</teleport>
<!-- END TESTS -->
<button v-if="accompanyingCourse.requestor !== null"
class="sc-button bt-remove"
:title="$t('action.remove')"
@click="removeRequestor">
</button>
<add-persons v-if="accompanyingCourse.requestor === null"
buttonTitle="requestor.add_requestor"
modalTitle="requestor.add_requestor"
v-bind:key="addPersons.key"
v-bind:options="addPersons.options"
@addNewPersons="addNewPersons"
ref="addPersons"> <!-- to cast child method -->
</add-persons>
</div>
</template>
<script>
import Modal from 'ChillMainAssets/vuejs/_components/Modal'
import AddPersons from 'ChillPersonAssets/vuejs/_components/AddPersons.vue'
export default {
name: 'Requestor',
components: {
Modal,
AddPersons,
},
data() {
return {
modal1: {
showModal: false,
modalDialogClass: "modal-dialog-scrollable modal-xl" // modal-lg modal-md modal-sm
},
modal2: {
showModal: false,
modalDialogClass: "modal-dialog-centered modal-sm" // modal-lg modal-md modal-sm
addPersons: {
key: 'requestor',
options: {
type: ['person', 'thirdparty'],
priority: null,
uniq: true,
}
}
}
},
computed: {
accompanyingCourse() {
return this.$store.state.accompanyingCourse
},
isAnonymous: {
set(value) {
console.log('requestorIsAnonymous value',value);
this.$store.dispatch('requestorIsAnonymous', value);
},
get() {
return this.$store.state.accompanyingCourse.requestorAnonymous;
}
}
},
methods: {
removeRequestor() {
console.log('@@ CLICK remove requestor: item');
this.$store.dispatch('removeRequestor');
},
addNewPersons({ selected, modal }) {
console.log('@@@ CLICK button addNewPersons', selected);
selected.forEach(function(item) {
this.$store.dispatch('addRequestor', item);
}, this
);
this.$refs.addPersons.resetSearch(); // to cast child method
modal.showModal = false;
}
}
}

View File

@@ -0,0 +1,81 @@
<template>
<div class="vue-component">
<h3>Tests</h3>
<!-- Modal -->
<ul class="record_actions">
<li>
<button class="sc-button bt-create" @click="modal1.showModal = true">
{{ $t('action.show_modal') }}
</button>
</li>
<li>
<button class="sc-button bt-create" @click="modal2.showModal = true">
Ouvrir une seconde modale
</button>
</li>
</ul>
<teleport to="body">
<modal v-if="modal1.showModal" :modalDialogClass="modal1.modalDialogClass" @close="modal1.showModal = false">
<template v-slot:header>
<h3 class="modal-title">Le titre de ma modale</h3>
</template>
<template v-slot:body>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus luctus facilisis suscipit. Cras pulvinar, purus sagittis pulvinar porta, enim ex posuere lacus, in pulvinar lectus magna in odio. Nullam iaculis congue lorem ac suscipit. Proin ut rutrum augue. Ut vehicula risus nec hendrerit ullamcorper. Ut volutpat eu mi eget viverra. Morbi dictum placerat suscipit. </p>
<p>Quisque non erat tincidunt, lacinia justo ut, pulvinar nisl. Nunc id enim ut sem pretium interdum consectetur eu quam. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Etiam posuere erat eget augue finibus luctus. Maecenas auctor, tortor non luctus ultrices, neque neque porttitor ex, nec lacinia lorem ligula et elit. Sed tempor nulla vitae lorem sollicitudin dictum. Vestibulum nec arcu eget elit pulvinar pretium. Phasellus facilisis metus sed diam luctus, feugiat scelerisque velit dignissim.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus luctus facilisis suscipit. Cras pulvinar, purus sagittis pulvinar porta, enim ex posuere lacus, in pulvinar lectus magna in odio. Nullam iaculis congue lorem ac suscipit. Proin ut rutrum augue. Ut vehicula risus nec hendrerit ullamcorper. Ut volutpat eu mi eget viverra. Morbi dictum placerat suscipit. </p>
<p>Quisque non erat tincidunt, lacinia justo ut, pulvinar nisl. Nunc id enim ut sem pretium interdum consectetur eu quam. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Etiam posuere erat eget augue finibus luctus. Maecenas auctor, tortor non luctus ultrices, neque neque porttitor ex, nec lacinia lorem ligula et elit. Sed tempor nulla vitae lorem sollicitudin dictum. Vestibulum nec arcu eget elit pulvinar pretium. Phasellus facilisis metus sed diam luctus, feugiat scelerisque velit dignissim.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus luctus facilisis suscipit. Cras pulvinar, purus sagittis pulvinar porta, enim ex posuere lacus, in pulvinar lectus magna in odio. Nullam iaculis congue lorem ac suscipit. Proin ut rutrum augue. Ut vehicula risus nec hendrerit ullamcorper. Ut volutpat eu mi eget viverra. Morbi dictum placerat suscipit. </p>
<p>Quisque non erat tincidunt, lacinia justo ut, pulvinar nisl. Nunc id enim ut sem pretium interdum consectetur eu quam. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Etiam posuere erat eget augue finibus luctus. Maecenas auctor, tortor non luctus ultrices, neque neque porttitor ex, nec lacinia lorem ligula et elit. Sed tempor nulla vitae lorem sollicitudin dictum. Vestibulum nec arcu eget elit pulvinar pretium. Phasellus facilisis metus sed diam luctus, feugiat scelerisque velit dignissim.</p>
</template>
<template v-slot:footer>
<button class="sc-button green" @click="modal1.showModal = false; modal2.showModal = true">
{{ $t('action.next')}}</button>
</template>
</modal>
</teleport>
<teleport to="body">
<modal v-if="modal2.showModal" :modalDialogClass="modal2.modalDialogClass" @close="modal2.showModal = false">
<template v-slot:header>
<h3 class="modal-title">Une autre modale</h3>
</template>
<template v-slot:body>
<p>modal 2</p>
</template>
<template v-slot:footer>
<button class="sc-button green" @click="modal2.showModal = false">
{{ $t('action.save')}}</button>
</template>
</modal>
</teleport>
<!-- END Modal -->
</div>
</template>
<script>
import Modal from 'ChillMainAssets/vuejs/_components/Modal'
export default {
name: 'Test',
components: {
Modal,
},
data() {
return {
modal1: {
showModal: false,
modalDialogClass: "modal-dialog-scrollable modal-xl" // modal-lg modal-md modal-sm
},
modal2: {
showModal: false,
modalDialogClass: "modal-dialog-centered modal-sm" // modal-lg modal-md modal-sm
}
}
},
computed: {
}
}
</script>

View File

@@ -9,19 +9,50 @@ const appMessages = {
closing_date: "Date de clôture",
remark: "Commentaire",
closing_motive: "Motif de clôture",
user: "TMS",
flags: "Indicateurs",
status: "État",
step: {
draft: "Brouillon",
open: "Ouvert",
active: "En file active"
},
emergency: "urgent",
confidential: "confidentiel",
},
persons_associated: {
title: "Usagers concernés",
counter: "Pas d'usager | 1 usager | {count} usagers",
firstname: "Prénom",
lastname: "Nom",
startdate: "Date d'entrée",
firstname: "Prénom",
lastname: "Nom",
startdate: "Date d'entrée",
enddate: "Date de sortie",
addPerson: "Ajouter un usager",
add_persons: "Ajouter des usagers",
},
requestor: {
title: "Demandeur",
add_requestor: "Ajouter un demandeur",
is_anonymous: "Le demandeur est anonyme",
type: "Type",
person_id: "id",
text: "Dénomination",
firstName: "Prénom",
lastName: "Nom",
birthdate: "Date de naissance",
center: "Centre",
phonenumber: "Téléphone",
mobilenumber: "Mobile",
altNames: "Autres noms",
address: "Adresse",
location: "Localité",
},
interlocutors: {
title: "Interlocuteurs privilégiés",
counter: "Pas d'interlocuteur | 1 interlocuteur | {count} interlocuteurs",
firstname: "Prénom",
lastname: "Nom",
add_interlocutors: "Ajouter des interlocuteurs",
}
}
};

View File

@@ -1,11 +1,9 @@
import 'es6-promise/auto';
import { createStore } from 'vuex';
import addPersons from './modules/addPersons'
import { getAccompanyingCourse, postParticipation } from '../api';
import { getAccompanyingCourse, postParticipation, postRequestor } from '../api';
const debug = process.env.NODE_ENV !== 'production';
const id = window.accompanyingCourseId; //tmp
const id = window.accompanyingCourseId;
let initPromise = getAccompanyingCourse(id)
.then(accompanying_course => new Promise((resolve, reject) => {
@@ -13,7 +11,6 @@ let initPromise = getAccompanyingCourse(id)
const store = createStore({
strict: debug,
modules: {
addPersons
},
state: {
accompanyingCourse: accompanying_course,
@@ -23,30 +20,36 @@ let initPromise = getAccompanyingCourse(id)
},
mutations: {
removeParticipation(state, item) {
//console.log('mutation: remove item', item.id);
//console.log('### mutation: remove item', item.id);
state.accompanyingCourse.participations = state.accompanyingCourse.participations.filter(participation => participation !== item);
},
closeParticipation(state, { participation, payload }) {
console.log('### mutation: close item', { participation, payload });
// trouve dans le state le payload et le supprime du state
state.accompanyingCourse.participations = state.accompanyingCourse.participations.filter(participation => participation !== payload);
// pousse la participation
state.accompanyingCourse.participations.push(participation);
//console.log('### mutation: close item', { participation, payload });
// find row position and replace by closed participation
state.accompanyingCourse.participations.splice(
state.accompanyingCourse.participations.findIndex(element => element === payload), 1, participation
);
},
addParticipation(state, participation) {
//console.log('### mutation: add participation', participation);
state.accompanyingCourse.participations.push(participation);
},
removeRequestor(state) {
state.accompanyingCourse.requestor = null;
},
addRequestor(state, requestor) {
console.log(requestor);
state.accompanyingCourse.requestor = requestor;
}
},
actions: {
removeParticipation({ commit }, payload) {
commit('removeParticipation', payload);
},
closeParticipation({ commit }, payload) {
//console.log('## action: fetch delete participation: payload', payload.person.id);
postParticipation(id, payload.person.id, 'DELETE')
console.log('## action: fetch delete participation: payload', payload);
postParticipation(id, payload.person.person_id, 'DELETE')
.then(participation => new Promise((resolve, reject) => {
//console.log('payload', payload);
commit('closeParticipation', { participation, payload });
resolve();
}))
@@ -54,22 +57,43 @@ let initPromise = getAccompanyingCourse(id)
state.errorMsg.push(error.message);
});
},
addParticipation(addPersons, payload) {
//console.log('## action: fetch post participation: payload', payload.id);
postParticipation(id, payload.id, 'POST')
addParticipation({ commit }, payload) {
console.log('## action: fetch post participation (select item): payload', payload);
postParticipation(id, payload.result.person_id, 'POST')
.then(participation => new Promise((resolve, reject) => {
//console.log(participation, payload);
addPersons.commit('addParticipation', participation);
addPersons.commit('resetState', payload);
commit('addParticipation', participation);
resolve();
}))
.catch((error) => {
state.errorMsg.push(error.message);
});
},
removeRequestor({ commit }) {
postRequestor(id, null, 'DELETE')
.then(requestor => new Promise((resolve, reject) => {
commit('removeRequestor');
resolve();
}))
.catch((error) => {
state.errorMsg.push(error.message);
});
},
addRequestor({ commit }, payload) {
console.log(payload);
postRequestor(id, payload, 'POST')
.then(requestor => new Promise((resolve, reject) => {
commit('addRequestor', requestor);
resolve();
}))
.catch((error) => {
state.errorMsg.push(error.message);
});
},
requestorIsAnonymous({ commit }, payload) {
console.log('payload', payload);
}
}
});
//console.log('store object', store.state.accompanyingCourse.id);
resolve(store);
}));

View File

@@ -1,76 +0,0 @@
import { searchPersons } from 'ChillPersonAssets/vuejs/_api/AddPersons'
import { postParticipation } from '../../api';
// initial state
const state = {
query: "",
suggested: [],
selected: []
}
// getters
const getters = {
selectedAndSuggested: state => {
const uniqBy = (a, key) => [
...new Map(
a.map(x => [key(x), x])
).values()
];
let union = [...new Set([
...state.suggested.slice().reverse(),
...state.selected.slice().reverse(),
])];
return uniqBy(union, k => k.id);
}
}
// mutations
const mutations = {
setQuery(state, query) {
//console.log('q=', query);
state.query = query;
},
loadSuggestions(state, suggested) {
state.suggested = suggested;
},
updateSelected(state, value) {
state.selected = value;
},
resetState(state, selected) {
//console.log('avant', state.selected);
state.selected = state.selected.filter(value => value !== selected);
//console.log('après', state.selected);
state.query = "";
state.suggested = [];
}
}
// actions
const actions = {
setQuery({ commit }, payload) {
//console.log('## action: setquery: payload', payload);
commit('setQuery', payload.query);
if (payload.query.length >= 3) {
searchPersons(payload.query)
.then(suggested => new Promise((resolve, reject) => {
commit('loadSuggestions', suggested.results);
resolve();
}));
} else {
commit('loadSuggestions', []);
}
},
updateSelected({ commit }, payload) {
//console.log('## action: update selected values: payload', payload);
commit('updateSelected', payload);
}
}
export default {
//namespaced: true,
state,
getters,
actions,
mutations
}

View File

@@ -1,15 +1,23 @@
const
locale = 'fr',
format = 'json'
;
/*
* Build query string with query and options
*/
const parametersToString = ({ query, options }) => {
let types ='';
options.type.forEach(function(type) {
types += '&type[]=' + type;
});
return 'q=' + query + types;
};
/*
* Endpoint chill_person_search, method GET, get a list of persons
* Endpoint chill_person_search
* method GET, get a list of persons
*
* @query string - the query to search for
*/
let searchPersons = (query) => {
let url = `/${locale}/search.${format}?name=person_regular&q=${query}`;
const searchPersons = ({ query, options }) => {
let queryStr = parametersToString({ query, options });
let url = `/fr/search.json?name=person_regular&${queryStr}`;
return fetch(url)
.then(response => {
if (response.ok) { return response.json(); }
@@ -17,4 +25,22 @@ let searchPersons = (query) => {
});
};
export { searchPersons };
/*
* Endpoint v.2 chill_main_search_global
* method GET, get a list of persons and thirdparty
*
* NOTE: this is a temporary WIP endpoint, return inconsistent random results
* @query string - the query to search for
*/
const searchPersons_2 = ({ query, options }) => {
let queryStr = parametersToString({ query, options });
let url = `/api/1.0/search.json?${queryStr}`;
return fetch(url)
.then(response => {
if (response.ok) { return response.json(); }
throw Error('Error with request resource response');
});
};
export { searchPersons, searchPersons_2 };

View File

@@ -1,73 +1,87 @@
<template>
<button class="sc-button bt-create centered mt-4" @click="openModal">
{{ $t('add_persons.search_add_others_persons') }}
{{ $t(buttonTitle) }}
</button>
<teleport to="body">
<modal v-if="modal.showModal"
:modalDialogClass="modal.modalDialogClass"
@close="modal.showModal = false">
<modal v-if="modal.showModal"
:modalDialogClass="modal.modalDialogClass"
@close="modal.showModal = false">
<template v-slot:header>
<h3 class="modal-title">{{ $t('add_persons.title') }}</h3>
<h3 class="modal-title">{{ $t(modalTitle) }}</h3>
</template>
<template v-slot:body-fixed>
<div class="search">
<label style="float: right;">
{{ $tc('add_persons.suggested_counter', suggestedCounter) }}
</label>
<input id="search-persons"
name="query"
v-model="query"
:placeholder="$t('add_persons.search_some_persons')"
ref="search" />
<i class="fa fa-search fa-lg"></i>
<template v-slot:body-head>
<div class="modal-body">
<div class="search">
<label style="float: right;">
{{ $tc('add_persons.suggested_counter', suggestedCounter) }}
</label>
<input id="search-persons"
name="query"
v-model="query"
:placeholder="$t('add_persons.search_some_persons')"
ref="search" />
<i class="fa fa-search fa-lg"></i>
<i class="fa fa-times" v-if="queryLength >= 3" @click="resetSuggestion"></i>
</div>
</div>
</template>
<template v-slot:body>
<!--span class="discret">Selection: {{ selected }}</span-->
<div class="results">
<div class="modal-body">
<div class="count">
<span>
<a v-if="suggestedCounter > 0" href="#">
{{ $t('action.check_all')}}</a>
<a v-if="selectedCounter > 0" href="#">
{{ $t('action.reset')}}</a>
<a v-if="suggestedCounter > 2" @click="selectAll">
{{ $t('action.check_all')}}
</a>
<a v-if="selectedCounter > 0" @click="resetSelection">
<i v-if="suggestedCounter > 2"> </i>
{{ $t('action.reset')}}
</a>
</span>
<span v-if="selectedCounter > 0">
{{ $tc('add_persons.selected_counter', selectedCounter) }}
</span>
</div>
<person-suggestion
</div>
</template>
<template v-slot:body>
<!--span class="discret">Selection: {{ selected }}</span-->
<div class="results">
<person-suggestion
v-for="item in this.selectedAndSuggested.slice().reverse()"
v-bind:item="item"
v-bind:key="item.id">
v-bind:key="itemKey(item)"
v-bind:item="item"
v-bind:search="search"
@updateSelected="updateSelected">
</person-suggestion>
<button v-if="query.length >= 3" class="sc-button bt-create ml-5 mt-2" name="createPerson">
{{ $t('action.create') }} "{{ query }}"
</button>
</div>
</template>
<template v-slot:footer>
<button class="sc-button green" @click="addNewPersons">
<button class="sc-button green"
@click.prevent="$emit('addNewPersons', { selected, modal })">
<i class="fa fa-plus fa-fw"></i>{{ $t('action.add')}}
</button>
{{ $t(checkUniq) }}
</template>
</modal>
</teleport>
</template>
<script>
import { mapState } from 'vuex';
import Modal from 'ChillMainAssets/vuejs/_components/Modal';
import PersonSuggestion from 'ChillPersonAssets/vuejs/_components/PersonSuggestion';
import { searchPersons, searchPersons_2 } from 'ChillPersonAssets/vuejs/_api/AddPersons';
export default {
name: 'AddPersons',
@@ -75,40 +89,69 @@ export default {
Modal,
PersonSuggestion,
},
props: [
'buttonTitle',
'modalTitle',
'options'
],
emits: ['addNewPersons'],
data() {
return {
modal: {
showModal: false,
modalDialogClass: "modal-dialog-scrollable modal-xl"
},
search: {
query: "",
suggested: [],
selected: []
}
}
},
computed: {
...mapState({
addPersons: state => state.addPersons
}),
query: {
set(query) {
this.$store.dispatch('setQuery', { query });
return this.setQuery(query);
},
get() {
return this.addPersons.query;
return this.search.query;
}
},
queryLength() {
return this.search.query.length;
},
suggested() {
return this.addPersons.suggested;
return this.search.suggested;
},
suggestedCounter() {
return this.addPersons.suggested.length;
},
return this.search.suggested.length;
},
selected() {
return this.addPersons.selected;
},
return this.search.selected;
},
selectedCounter() {
return this.addPersons.selected.length;
return this.search.selected.length;
},
selectedAndSuggested() {
return this.$store.getters.selectedAndSuggested;
const uniqBy = (a, key) => [
...new Map(
a.map(x => [key(x), x])
).values()
];
let union = [...new Set([
...this.suggested.slice().reverse(),
...this.selected.slice().reverse(),
])];
return uniqBy(union, k => k.key);
},
options() {
return this.options;
},
checkUniq() {
if (this.options.uniq === true && this.selectedCounter > 1) {
return "error_only_one_person";
}
return '';
}
},
methods: {
@@ -118,15 +161,47 @@ export default {
this.$refs.search.focus();
})
},
addNewPersons() {
console.log('@@@ CLICK button addPersons')
this.selected.forEach(function(item) {
//console.log('# dispatch action for each item', item);
this.$store.dispatch('addParticipation', item);
}, this
);
this.modal.showModal = false;
setQuery(query) {
this.search.query = query;
if (query.length >= 3) {
searchPersons_2({ query, options: this.options })
.then(suggested => new Promise((resolve, reject) => {
this.loadSuggestions(suggested.results);
resolve();
}));
} else {
this.loadSuggestions([]);
}
},
loadSuggestions(suggested) {
this.search.suggested = suggested;
this.search.suggested.forEach(function(item) {
item.key = this.itemKey(item);
}, this);
},
updateSelected(value) {
this.search.selected = value;
},
resetSearch() {
this.resetSelection();
this.resetSuggestion();
},
resetSuggestion() {
this.search.query = "";
this.search.suggested = [];
},
resetSelection() {
this.search.selected = [];
},
selectAll() {
this.search.suggested.forEach(function(item) {
this.search.selected.push(item);
}, this);
},
itemKey(item) {
let type = item.result.type;
return type + item.result[type + '_id'];
}
}
},
}
</script>

View File

@@ -1,53 +1,52 @@
<template>
<div class="list-item" :class="{ checked: isChecked }">
<div class="container">
<!--a class="discret" target="_blank" :href="url.show">{{ item.id }}</a-->
<input class=""
type="checkbox"
v-model="selected"
:value="item" />
<div class="container">
<input type="checkbox"
v-model="selected"
:value="item" />
</div>
{{ item.text }}
<suggestion-person
v-if="item.result.type === 'person'"
v-bind:item="item">
</suggestion-person>
</div>
<div class="right_actions">
<span class="badge badge-pill badge-secondary" :title="item.id">
{{ $t('item.type_person') }}
</span>
<a class="sc-button bt-show" target="_blank" :title="item.id" :href="url.show"></a>
</div>
<suggestion-third-party
v-if="item.result.type === 'thirdparty'"
v-bind:item="item">
</suggestion-third-party>
</div>
</template>
<script>
import { mapState } from 'vuex';
import SuggestionPerson from './PersonSuggestion/Person';
import SuggestionThirdParty from './PersonSuggestion/ThirdParty';
export default {
name: 'PersonSuggestion',
props: ['item'],
data() {
return {
url: {
show: '/fr/person/' + this.item.id + '/general',
edit: '/fr/person/' + this.item.id + '/general/edit'
}
}
components: {
SuggestionPerson,
SuggestionThirdParty,
},
props: [
'item',
'search'
],
emits: ['updateSelected'],
computed: {
selected: {
set(value) {
this.$store.dispatch('updateSelected', value);
this.$emit('updateSelected', value);
},
get() {
return this.$store.state.addPersons.selected;
return this.search.selected;
}
},
isChecked() {
return (this.selected.indexOf(this.item) === -1) ? false : true;
return (this.search.selected.indexOf(this.item) === -1) ? false : true;
}
}
},
};
</script>

View File

@@ -0,0 +1,35 @@
<template>
<div class="container">
<span class="name">
{{ item.result.text }}
</span>
<span class="birthday">
{{ $d(item.result.birthdate.datetime, 'short') }}
</span>
</div>
<div class="right_actions">
<span class="badge badge-pill badge-secondary" :title="item.key">
{{ $t('item.type_person') }}
</span>
<a class="sc-button bt-show" target="_blank" :title="item.key" :href="url.show"></a>
</div>
</template>
<script>
export default {
name: 'SuggestionPerson',
props: ['item'],
data() {
return {
url: {
show: '/fr/person/' + this.item.result.person_id + '/general',
edit: '/fr/person/' + this.item.result.person_id + '/general/edit'
},
}
},
}
</script>

View File

@@ -0,0 +1,36 @@
<template>
<div class="container">
<span class="name">
{{ item.result.text }}
</span>
<span class="location">
{{ item.result.address.text }} -
{{ item.result.address.postcode.name }}
</span>
</div>
<div class="right_actions">
<span class="badge badge-pill badge-secondary" :title="item.key">
{{ $t('item.type_thirdparty') }}
</span>
<a class="sc-button bt-show" target="_blank" :title="item.key" :href="url.show"></a>
</div>
</template>
<script>
export default {
name: 'SuggestionThirdParty',
props: ['item'],
data() {
return {
url: {
show: '/fr/thirdparty/thirdparty/' + this.item.result.thirdparty_id + '/show',
edit: '/fr/thirdparty/thirdparty/' + this.item.result.thirdparty_id + '/edit'
},
}
},
}
</script>

View File

@@ -1,7 +1,6 @@
const personMessages = {
fr: {
add_persons: {
search_add_others_persons: "Rechercher et ajouter d'autres usagers",
title: "Ajouter des usagers",
suggested_counter: "Pas de résultats | 1 résultat | {count} résultats",
selected_counter: " 1 sélectionné | {count} sélectionnés",
@@ -9,10 +8,11 @@ const personMessages = {
},
item: {
type_person: "Usager",
type_tms: "TMS",
type_3rdparty: "Tiers",
type_menage: "Ménage"
}
type_user: "TMS",
type_thirdparty: "Tiers",
type_household: "Ménage"
},
error_only_one_person: "Une seule personne peut être sélectionnée !"
}
};