Merge branch 'ameliorations_composants_vue' of gitlab.com:Chill-Projet/chill-bundles into ameliorations_composants_vue

This commit is contained in:
2021-08-19 16:21:11 +02:00
290 changed files with 14212 additions and 4797 deletions

View File

@@ -6,6 +6,7 @@
<h1 v-else>{{ $t('course.title.active') }}</h1>
<persons-associated></persons-associated>
<course-location></course-location>
<origin-demand></origin-demand>
<requestor></requestor>
<social-issue></social-issue>
@@ -14,6 +15,12 @@
<comment v-if="accompanyingCourse.step === 'DRAFT'"></comment>
<confirm v-if="accompanyingCourse.step === 'DRAFT'"></confirm>
<div v-for="error in errorMsg" class="vue-component errors alert alert-danger">
<p>
<span>{{ error.sta }} {{ error.txt }}</span><br>
<span>{{ $t(error.msg) }}</span>
</p>
</div>
</template>
<script>
@@ -24,6 +31,7 @@ import OriginDemand from './components/OriginDemand.vue';
import PersonsAssociated from './components/PersonsAssociated.vue';
import Requestor from './components/Requestor.vue';
import SocialIssue from './components/SocialIssue.vue';
import CourseLocation from './components/CourseLocation.vue';
import Referrer from './components/Referrer.vue';
import Resources from './components/Resources.vue';
import Comment from './components/Comment.vue';
@@ -38,18 +46,24 @@ export default {
PersonsAssociated,
Requestor,
SocialIssue,
CourseLocation,
Referrer,
Resources,
Comment,
Confirm,
},
computed: mapState([
'accompanyingCourse'
'accompanyingCourse',
'addressContext',
'errorMsg'
])
};
</script>
<style lang="scss">
@import 'ChillMainAssets/module/bootstrap/shared';
$chill-accourse-context: #718596;
div#accompanying-course {
div.vue-component {
h2 {
@@ -59,7 +73,7 @@ export default {
position: absolute;
content: "\f142"; //ellipsis-v
font-family: "ForkAwesome";
color: #718596ab;
color: tint-color($chill-accourse-context, 10%);
left: -22px;
top: 4px;
}
@@ -70,10 +84,10 @@ export default {
}
padding: 0em 0em;
margin: 1em 0;
border: 1px dotted #718596ab;
border: 1px dotted tint-color($chill-accourse-context, 10%);
border-radius: 5px;
border-left: 1px dotted #718596ab;
border-right: 1px dotted #718596ab;
border-left: 1px dotted tint-color($chill-accourse-context, 10%);
border-right: 1px dotted tint-color($chill-accourse-context, 10%);
dd {
margin-left: 1em;
}
@@ -83,7 +97,16 @@ export default {
margin: 1em 0 0;
}
}
}
}
&.errors {
//display: flex;
//position: sticky;
//bottom: 0.3em;
//z-index: 1000;
margin: 1em 0;
padding: 1em;
border-radius: 0;
}
}
}
</style>

View File

@@ -4,12 +4,12 @@
*
* @id integer - id of accompanyingCourse
*/
const getAccompanyingCourse = (id) => {
const getAccompanyingCourse = (id) => {
const url = `/api/1.0/person/accompanying-course/${id}.json`;
return fetch(url)
.then(response => {
if (response.ok) { return response.json(); }
throw Error('Error with request resource response');
throw { msg: 'Error while retriving AccompanyingPeriod Course.', sta: response.status, txt: response.statusText, err: new Error(), body: response.body };
});
};
@@ -20,8 +20,8 @@ const getAccompanyingCourse = (id) => {
* @id integer - id of accompanyingCourse
* @body Object - dictionary with changes to post
*/
const patchAccompanyingCourse = (id, body) => {
console.log('body', body);
const patchAccompanyingCourse = (id, body) => {
//console.log('body', body);
const url = `/api/1.0/person/accompanying-course/${id}.json`;
return fetch(url, {
method: 'PATCH',
@@ -32,7 +32,8 @@ const patchAccompanyingCourse = (id, body) => {
})
.then(response => {
if (response.ok) { return response.json(); }
throw Error('Error with request resource response');
console.log(response);
throw { msg: 'Error while updating AccompanyingPeriod Course.', sta: response.status, txt: response.statusText, err: new Error(), body: response.body };
});
};
@@ -47,24 +48,24 @@ const confirmAccompanyingCourse = (id) => {
})
.then(response => {
if (response.ok) { return response.json(); }
throw Error('Error with request resource response');
throw { msg: 'Error while confirming AccompanyingPeriod Course.', sta: response.status, txt: response.statusText, err: new Error(), body: response.body };
});
};
/*
* Endpoint
* Endpoint
*/
const getSocialIssues = () => {
const url = `/api/1.0/person/social-work/social-issue.json`;
return fetch(url)
.then(response => {
if (response.ok) { return response.json(); }
throw Error('Error with request resource response');
throw { msg: 'Error while retriving Social Issues.', sta: response.status, txt: response.statusText, err: new Error(), body: response.body };
});
};
/*
* Endpoint v.2 chill_api_single_accompanying_course_participation,
* Endpoint v.2 chill_api_single_accompanying_course_participation,
* method POST/DELETE, add/close a participation to the accompanyingCourse
*
* @id integer - id of accompanyingCourse
@@ -83,12 +84,12 @@ const postParticipation = (id, payload, method) => {
})
.then(response => {
if (response.ok) { return response.json(); }
throw Error('Error with request resource response');
throw { msg: 'Error while sending AccompanyingPeriod Course participation.', sta: response.status, txt: response.statusText, err: new Error(), body: response.body };
});
};
/*
* Endpoint v.2 chill_api_single_accompanying_course_requestor,
* Endpoint v.2 chill_api_single_accompanying_course_requestor,
* method POST/DELETE, add/close a requestor to the accompanyingCourse
*
* @id integer - id of accompanyingCourse
@@ -109,12 +110,12 @@ const postRequestor = (id, payload, method) => {
})
.then(response => {
if (response.ok) { return response.json(); }
throw Error('Error with request resource response');
throw { msg: 'Error while sending AccompanyingPeriod Course requestor', sta: response.status, txt: response.statusText, err: new Error(), body: response.body };
});
};
/*
* Endpoint v.2 chill_api_single_accompanying_course_resource,
* Endpoint v.2 chill_api_single_accompanying_course_resource,
* method POST/DELETE, add/remove a resource to the accompanyingCourse
*
* @id integer - id of accompanyingCourse
@@ -126,11 +127,11 @@ const postResource = (id, payload, method) => {
const body = { type: "accompanying_period_resource" };
switch (method) {
case 'DELETE':
body['id'] = payload.id;
body['id'] = payload.id;
break;
default:
body['resource'] = { type: payload.type, id: payload.id };
}
}
//console.log('body', body);
const url = `/api/1.0/person/accompanying-course/${id}/resource.json`;
return fetch(url, {
@@ -142,7 +143,7 @@ const postResource = (id, payload, method) => {
})
.then(response => {
if (response.ok) { return response.json(); }
throw Error('Error with request resource response');
throw { msg: 'Error while sending AccompanyingPeriod Course resource.', sta: response.status, txt: response.statusText, err: new Error(), body: response.body };
});
};
@@ -150,7 +151,7 @@ const postResource = (id, payload, method) => {
* Endpoint to Add/remove SocialIssue
*/
const postSocialIssue = (id, body, method) => {
//console.log('api body and method', body, method);
//console.log('api body and method', body, method);
const url = `/api/1.0/person/accompanying-course/${id}/socialissue.json`;
return fetch(url, {
method: method,
@@ -161,7 +162,7 @@ const postSocialIssue = (id, body, method) => {
})
.then(response => {
if (response.ok) { return response.json(); }
throw Error('Error with request resource response');
throw { msg: 'Error while updating SocialIssue.', sta: response.status, txt: response.statusText, err: new Error(), body: response.body };
});
};
@@ -170,7 +171,7 @@ const getUsers = () => {
return fetch(url)
.then(response => {
if (response.ok) { return response.json(); }
throw Error('Error with request resource response');
throw { msg: 'Error while retriving users.', sta: response.status, txt: response.statusText, err: new Error(), body: response.body };
});
};
@@ -179,7 +180,7 @@ const whoami = () => {
return fetch(url)
.then(response => {
if (response.ok) { return response.json(); }
throw Error('Error with request resource response');
throw { msg: 'Error while getting whoami.', sta: response.status, txt: response.statusText, err: new Error(), body: response.body };
});
};
@@ -188,11 +189,11 @@ const getListOrigins = () => {
return fetch(url)
.then(response => {
if (response.ok) { return response.json(); }
throw Error('Error with request resource response');
throw { msg: 'Error while retriving origin\'s list.', sta: response.status, txt: response.statusText, err: new Error(), body: response.body };
});
}
export {
export {
getAccompanyingCourse,
patchAccompanyingCourse,
confirmAccompanyingCourse,

View File

@@ -5,7 +5,8 @@
</teleport>
<teleport to="#header-accompanying_course-name #banner-status">
<span v-if="accompanyingCourse.step === 'DRAFT'" class="d-md-block">
<span v-if="accompanyingCourse.step === 'DRAFT'"
class="text-md-end d-md-block">
<span class="badge bg-secondary">
{{ $t('course.step.draft') }}
</span>

View File

@@ -0,0 +1,68 @@
<template>
<li>
<button class="btn btn-sm btn-secondary"
@click="modal.showModal = true"
:title="$t('courselocation.assign_course_address')">
<i class="fa fa-map-marker"></i>
</button>
</li>
<teleport to="body">
<modal v-if="modal.showModal" :modalDialogClass="modal.modalDialogClass" @close="modal.showModal = false">
<template v-slot:header>
<h2 class="modal-title">{{ $t('courselocation.sure') }}</h2>
</template>
<template v-slot:body>
<show-address :address="person.current_household_address"></show-address>
<p>{{ $t('courselocation.sure_description') }}</p>
</template>
<template v-slot:footer>
<button class="btn btn-danger" @click="assignAddress">
{{ $t('courselocation.ok') }}
</button>
</template>
</modal>
</teleport>
</template>
<script>
import {mapState} from "vuex";
import Modal from 'ChillMainAssets/vuejs/_components/Modal';
import ShowAddress from "ChillMainAssets/vuejs/Address/components/ShowAddress";
export default {
name: "ButtonLocation",
components: {
ShowAddress,
Modal,
},
props: ['person'],
data() {
return {
modal: {
showModal: false,
modalDialogClass: "modal-dialog-centered modal-md"
}
}
},
computed: {
...mapState({
context: state => state.addressContext
}),
},
methods: {
assignAddress() {
//console.log('assignAddress id', this.person.current_household_address);
let payload = {
entity: this.context.entity.type,
entityId: this.context.entity.id,
locationStatusTo: 'person',
personId: this.person.id
};
this.$store.dispatch('updateLocation', payload);
window.location.assign('#section-20');
this.modal.showModal = false;
}
}
}
</script>

View File

@@ -1,57 +1,65 @@
<template>
<div class="vue-component">
<h2><a name="section-60"></a>{{ $t('comment.title') }}</h2>
<h2><a name="section-80"></a>{{ $t('comment.title') }}</h2>
<!--div class="error flash_message" v-if="errors.length > 0">
{{ errors[0] }}
TODO fix errors flashbag for app component
</div-->
<div>
<form @submit.prevent="submitform">
<label for="content">{{ $t('comment.label') }}</label>
<div v-if="initialComment">
{{ $t('comment.created_by', [
initialComment.creator.text,
$d(initialComment.createdAt.datetime, 'long')
]) }}
</div>
<textarea
name="content"
<label class="col-form-label" for="content">{{ $t('comment.label') }}</label>
<ckeditor
name="content"
v-bind:placeholder="$t('comment.content')"
rows="8"
cols="80"
ckeditor="ckeditor"
v-model="content">
</textarea>
<ul class="record_actions">
<li>
<button type="submit" class="btn btn-save">{{ $t('action.save') }}</button>
</li>
<li v-if="initialComment !== null">
<a class="btn btn-delete"
@click="removeComment">
{{ $t('action.delete') }}
</a>
</li>
</ul>
:editor="editor"
v-model="content"
tag-name="textarea">
</ckeditor>
<div v-if="initialComment" class="metadata">
{{ $t('comment.created_by', [
initialComment.creator.text,
$d(initialComment.createdAt.datetime, 'long')
]) }}
</div>
<div>
<ul class="record_actions">
<li>
<button type="submit" class="btn btn-save">{{ $t('action.save') }}</button>
</li>
<li v-if="initialComment !== null">
<a class="btn btn-delete"
@click="removeComment">
{{ $t('action.delete') }}
</a>
</li>
</ul>
</div>
</form>
</div>
</div>
</template>
<script>
import CKEditor from '@ckeditor/ckeditor5-vue';
import ClassicEditor from "ChillMainAssets/module/ckeditor5";
export default {
name: "Comment",
components: {
ckeditor: CKEditor.component,
},
data() {
return {
formdata: {
editor: ClassicEditor,
formdata: {
type: "accompanying_period_comment",
content: ''
}
@@ -66,7 +74,7 @@ export default {
this.formdata.content = value;
},
get() {
return (this.initialComment)? this.initialComment.content : null;
return (this.initialComment)? this.initialComment.content : {};
}
},
errors() {
@@ -75,12 +83,12 @@ export default {
},
methods: {
submitform() {
console.log('submit');
//console.log('submit');
this.$store.dispatch('postFirstComment', this.formdata);
},
removeComment() {
console.log('remove');
this.$store.dispatch('postFirstComment', null);
//console.log('remove');
this.$store.dispatch('postFirstComment', {});
}
}
}
@@ -88,12 +96,11 @@ export default {
* TODO
* - [x] delete button in ul record_actions, but not in form
* - [ ] display updatedAt => initialComment fetch PATCH content changes MUST NOT change object id !!
* - [ ] ckeditor integration
*/
</script>
<style lang="scss" scoped>
div.vue-component > div {
//margin: 1em;
}
<style lang="scss">
div.ck-editor.ck-reset {
margin: 0.6em 0;
}
</style>

View File

@@ -1,26 +1,45 @@
<template>
<div class="vue-component">
<h2><a name="section-70"></a>
<h2><a name="section-90"></a>
{{ $t('confirm.title') }}
</h2>
<div>
<p>
{{ $t('confirm.text_draft') }}
<span class="badge bg-secondary">{{ $t('course.step.draft') }}</span>
</p>
<p>
{{ $t('confirm.text_active') }}
<span class="badge bg-primary">{{ $t('course.step.active') }}</span>
</p>
<ul class="record_actions">
<li>
<button class="btn btn-save" @click="modal.showModal = true">
{{ $t('confirm.ok') }}
</button>
</li>
</ul>
<p v-html="$t('confirm.text_draft', [$t('course.step.draft')])"></p>
<div v-if="!isValidToBeConfirmed">
<div class="alert alert-warning">
{{ $t('confirm.alert_validation') }}
<ul class="mt-2">
<li v-for="k in validationKeys">
{{ $t(notValidMessages[k].msg) }}
<a :href="notValidMessages[k].anchor">
<i class="fa fa-level-up fa-fw"></i>
</a>
</li>
</ul>
</div>
<ul class="record_actions">
<li>
<button class="btn btn-save" disabled>
{{ $t('confirm.ok') }}
</button>
</li>
</ul>
</div>
<div v-else>
<p v-html="$t('confirm.text_active', [$t('course.step.active')])"></p>
<ul class="record_actions">
<li>
<button
class="btn btn-save"
@click="modal.showModal = true">
{{ $t('confirm.ok') }}
</button>
</li>
</ul>
</div>
</div>
<teleport to="body">
@@ -43,6 +62,7 @@
</template>
<script>
import {mapGetters, mapState} from "vuex";
import Modal from 'ChillMainAssets/vuejs/_components/Modal';
export default {
@@ -55,26 +75,41 @@ export default {
modal: {
showModal: false,
modalDialogClass: "modal-dialog-centered modal-md"
},
notValidMessages: {
participation: {
msg: 'confirm.participation_not_valid',
anchor: '#section-10'
},
location: {
msg: 'confirm.location_not_valid',
anchor: '#section-20' //
},
socialIssue: {
msg: 'confirm.socialIssue_not_valid',
anchor: '#section-50'
}
}
}
},
computed: {
accompanyingCourse() {
return this.$store.state.accompanyingCourse
}
...mapState([
'accompanyingCourse'
]),
...mapGetters([
'isParticipationValid',
'isSocialIssueValid',
'isLocationValid',
'validationKeys',
'isValidToBeConfirmed'
])
},
methods: {
confirmCourse() {
console.log('@@ CLICK confirmCourse');
//console.log('@@ CLICK confirmCourse');
this.$store.dispatch('confirmAccompanyingCourse');
console.log('confirm last');
//console.log('confirm last');
}
}
}
</script>
<style lang="scss" scoped>
div.vue-component > div {
//margin: 1em;
}
</style>

View File

@@ -0,0 +1,158 @@
<template>
<div class="vue-component">
<h2><a name="section-20"></a>
{{ $t('courselocation.title') }}
</h2>
<!-- {# include vue_address component #} -->
<div v-for="error in displayErrors" class="alert alert-danger my-2">
{{ error }}
</div>
<div v-if="hasNoLocation">
<label class="chill-no-data-statement">
{{ $t('courselocation.no_address') }}
</label>
</div>
<div v-if="isPersonLocation">
<label class="col-form-label">
{{ $t('courselocation.person_locator', [ accompanyingCourse.personLocation.text ]) }}
</label>
</div>
<show-address
v-if="accompanyingCourse.location"
:address="accompanyingCourse.location">
</show-address>
<div v-if="isTemporaryAddress" class="alert alert-warning">
<p>{{ $t('courselocation.temporary_address_must_be_changed') }}</p>
</div>
<div>
<ul class="record_actions">
<li>
<add-address
v-if="!isPersonLocation"
:context="context"
:key="addAddress.type"
:options="addAddress.options"
:result="addAddress.result"
@submitAddress="submitTemporaryAddress"
ref="addAddress">
</add-address>
</li>
<li v-if="isPersonLocation">
<button
class="btn btn-remove"
@click="removeAddress"
:title="$t('courselocation.remove_button')">
</button>
</li>
</ul>
</div>
</div>
</template>
<script>
import { mapState } from "vuex";
import AddAddress from 'ChillMainAssets/vuejs/Address/components/AddAddress.vue';
import ShowAddress from 'ChillMainAssets/vuejs/Address/components/ShowAddress.vue';
export default {
name: "CourseLocation",
components: {
AddAddress,
ShowAddress
},
data() {
return {
addAddress: {
type: 'accompanying_course_location',
options: {
/// Options override default.
/// null value take default component value
button: {
text: {
create: 'courselocation.add_temporary_address',
edit: 'courselocation.edit_temporary_address'
}
},
title: {
create: 'courselocation.add_temporary_address',
edit: 'courselocation.edit_temporary_address'
},
/// Display each step in page or Modal
bindModal: {
//step1: false, step2: false
},
hideDateFrom: true
}
}
}
},
computed: {
...mapState({
accompanyingCourse: state => state.accompanyingCourse,
context: state => state.addressContext
}),
isTemporaryAddress() {
return this.accompanyingCourse.locationStatus === 'address';
},
isPersonLocation() {
return this.accompanyingCourse.locationStatus === 'person';
},
hasNoLocation() {
return this.accompanyingCourse.locationStatus === 'none';
},
isContextEdit() {
return this.context.edit;
}
},
methods: {
initAddressContext() {
let context = {
entity: {
type: this.accompanyingCourse.type,
id: this.accompanyingCourse.id
},
edit: false,
addressId: null
}
if (this.accompanyingCourse.location) {
context['edit'] = true;
context['addressId'] = this.accompanyingCourse.location.address_id
}
this.$store.commit('setAddressContext', context);
},
removeAddress() {
//console.log('remove address');
let payload = {
entity: this.context.entity.type,
entityId: this.context.entity.id,
locationStatusTo: 'none'
};
this.$store.dispatch('updateLocation', payload);
},
displayErrors() {
return this.$refs.addAddress.errorMsg;
},
submitTemporaryAddress() {
//console.log('@@@ click on Submit Temporary Address Button');
let payload = this.$refs.addAddress.submitNewAddress();
payload['locationStatusTo'] = 'address'; // <== temporary, not none, not person
this.$store.dispatch('updateLocation', payload);
this.$store.commit('setEditContextTrue');
}
},
mounted() {
this.initAddressContext();
//console.log('ac.locationStatus', this.accompanyingCourse.locationStatus);
//console.log('ac.location (temporary location)', this.accompanyingCourse.location);
//console.log('ac.personLocation', this.accompanyingCourse.personLocation);
}
}
</script>

View File

@@ -1,8 +1,8 @@
<template>
<div class="vue-component">
<h2><a name="section-15"></a>{{ $t('origin.title') }}</h2>
<div class="my-4">
<h2><a name="section-30"></a>{{ $t('origin.title') }}</h2>
<div class="mb-4">
<label for="selectOrigin">
{{ $t('origin.label') }}
</label>

View File

@@ -1,41 +1,26 @@
<template>
<div class="vue-component">
<h2><a name="section-10"></a>{{ $t('persons_associated.title')}}</h2>
<div>
<div v-if="participations.length > 0">
<label class="col-form-label">{{ $tc('persons_associated.counter', counter) }}</label>
</div>
<div class="flex-table mb-3">
<participation-item
v-for="participation in participations"
v-bind:participation="participation"
v-bind:key="participation.id"
@remove="removeParticipation"
@close="closeParticipation">
</participation-item>
</div>
<!-- <table class="table table-bordered table-striped border-dark align-middle" v-if="participations.length > 0">
<thead>
<tr>
<th class="chill-orange">{{ $t('persons_associated.name') }}</th>
<th class="chill-orange">{{ $t('persons_associated.startdate') }}</th>
<th class="chill-orange">{{ $t('persons_associated.enddate') }}</th>
<th class="chill-orange">{{ $t('action.actions') }}</th>
</tr>
</thead>
<tbody>
<participation-item
v-for="participation in participations"
v-bind:participation="participation"
v-bind:key="participation.id"
@remove="removeParticipation"
@close="closeParticipation">
</participation-item>
</tbody>
</table> -->
<div v-else>
<label class="chill-no-data-statement">{{ $tc('persons_associated.counter', counter) }}</label>
</div>
<div class="flex-table mb-3">
<participation-item
v-for="participation in participations"
v-bind:participation="participation"
v-bind:key="participation.id"
@remove="removeParticipation"
@close="closeParticipation">
</participation-item>
</div>
<div>
<add-persons
<add-persons
buttonTitle="persons_associated.add_persons"
modalTitle="add_persons.title"
v-bind:key="addPersons.key"
@@ -77,15 +62,15 @@ export default {
}),
methods: {
removeParticipation(item) {
console.log('@@ CLICK remove participation: item', item);
//console.log('@@ CLICK remove participation: item', item);
this.$store.dispatch('removeParticipation', item);
},
closeParticipation(item) {
console.log('@@ CLICK close participation: item', item);
//console.log('@@ CLICK close participation: item', item);
this.$store.dispatch('closeParticipation', item);
},
addNewPersons({ selected, modal }) {
console.log('@@@ CLICK button addNewPersons', selected);
//console.log('@@@ CLICK button addNewPersons', selected);
selected.forEach(function(item) {
this.$store.dispatch('addParticipation', item);
}, this

View File

@@ -1,5 +1,4 @@
<template>
<person-render-box
:options="{
addInfo : true,
@@ -10,9 +9,8 @@
addAge : false,
hLevel : 1
}"
:person="participation.person"
>
:person="participation.person">
<template v-slot:record-actions>
<ul class="record_actions">
<li>
@@ -31,46 +29,70 @@
</li>
<!-- <li>
<button class="btn btn-delete"
:title="$t('action.delete')"
:title="$t('action.delete')"
@click.prevent="$emit('remove', participation)">
</button>
</li> -->
<li>
<button v-if="!participation.endDate"
class="btn btn-remove"
v-bind:title="$t('action.remove')"
class="btn btn-sm btn-remove"
v-bind:title="$t('action.remove')"
@click.prevent="$emit('close', participation)">
</button>
<button v-else class="btn btn-remove disabled"></button>
<button v-else class="btn btn-sm btn-remove disabled"></button>
</li>
</ul>
</template>
</template>
</person-render-box>
<!-- dates of participation
<tr>
<td><span v-if="participation.startDate">
{{ $d(participation.startDate.datetime, 'short') }}</span>
</td>
<td><span v-if="participation.endDate">
{{ $d(participation.endDate.datetime, 'short') }}</span>
</td>
</tr>
-->
</template>
<!-- <tr>
<td><span v-if="participation.startDate">
{{ $d(participation.startDate.datetime, 'short') }}</span>
</td>
<td><span v-if="participation.endDate">
{{ $d(participation.endDate.datetime, 'short') }}</span>
</td>
</tr> -->
<script>
import OnTheFly from 'ChillMainAssets/vuejs/_components/OnTheFly.vue';
import PersonRenderBox from '../../../_components/Entity/PersonRenderBox.vue';
import ButtonLocation from '../ButtonLocation.vue';
import PersonRenderBox from 'ChillPersonAssets/vuejs/_components/Entity/PersonRenderBox.vue';
export default {
name: 'ParticipationItem',
components: {
OnTheFly,
ButtonLocation,
PersonRenderBox
},
props: ['participation'],
emits: ['remove', 'close'],
data() {
return {
PersonRenderBox: {
participation: 'participation',
options: {
addInfo: false,
addId: true,
addAge: false,
hLevel: 1
}
}
}
},
computed: {
hasCurrentHouseholdAddress() {
if ( !this.participation.endDate
&& this.participation.person.current_household_address !== null ) {
return true;
}
return false;
}
}
}
</script>

View File

@@ -1,8 +1,8 @@
<template>
<div class="vue-component">
<h2><a name="section-40"></a>{{ $t('referrer.title') }}</h2>
<h2><a name="section-60"></a>{{ $t('referrer.title') }}</h2>
<div class="my-4">
<div>
<label class="col-form-label" for="selectReferrer">
{{ $t('referrer.label') }}
</label>
@@ -18,10 +18,12 @@
v-bind:options="options"
@select="updateReferrer">
</VueMultiselect>
</div>
<div>
<ul class="record_actions">
<li>
<button
<button
class="btn btn-create"
type="button"
name="button"
@@ -30,8 +32,8 @@
</button>
</li>
</ul>
</div>
</div>
</template>

View File

@@ -1,12 +1,12 @@
<template>
<div class="vue-component">
<h2><a name="section-20"></a>{{ $t('requestor.title') }}</h2>
<h2><a name="section-40"></a>{{ $t('requestor.title') }}</h2>
<div v-if="accompanyingCourse.requestor" class="flex-table">
<label>
<input type="checkbox" v-model="isAnonymous" class="me-2" /><!-- :value="value" -->
<input type="checkbox" v-model="isAnonymous" class="me-2" />
{{ $t('requestor.is_anonymous') }}
</label>
@@ -30,31 +30,32 @@
addInfo: true
}"
></person-render-box>
<!-- </div> -->
<!-- <h4>
<span class="badge rounded-pill bg-secondary">{{ accompanyingCourse.requestor.type }}</span>
{{ accompanyingCourse.requestor.text }}
</h4>
</h4>
<dl class="content-bloc" v-if="accompanyingCourse.requestor.type === 'person'">
<dt>{{ $t('requestor.birthdate') }}</dt>
<dt>{{ $t('requestor.birthdate') }}</dt>
<dd>{{ $d(accompanyingCourse.requestor.birthdate.datetime, 'short') }}</dd>
<dt>{{ $t('requestor.center') }}</dt>
<dt>{{ $t('requestor.center') }}</dt>
<dd>{{ accompanyingCourse.requestor.center.name }}</dd>
<dt>{{ $t('requestor.phonenumber') }}</dt>
<dt>{{ $t('requestor.phonenumber') }}</dt>
<dd>{{ accompanyingCourse.requestor.phonenumber }}</dd>
<dt>{{ $t('requestor.mobilenumber') }}</dt>
<dt>{{ $t('requestor.mobilenumber') }}</dt>
<dd>{{ accompanyingCourse.requestor.mobilenumber }}</dd>
</dl>
<dl class="content-bloc" v-if="accompanyingCourse.requestor.type === 'thirdparty'">
<dt>{{ $t('requestor.address') }}</dt>
<dd>{{ accompanyingCourse.requestor.address.text }}</dd>
<dt>{{ $t('requestor.location') }}</dt>
<dd>{{ accompanyingCourse.requestor.address.postcode.name }}</dd>
</dl>
@@ -79,17 +80,17 @@
<ul class="record_actions">
<li>
<button class="btn btn-remove"
:title="$t('action.remove')"
:title="$t('action.remove')"
@click="removeRequestor">
{{ $t('action.remove') }}
</button>
</li>
</ul>
</div>
</div>
<div v-else>
<label>{{ $t('requestor.counter') }}</label>
</div>
<label class="chill-no-data-statement">{{ $t('requestor.counter') }}</label>
</div>
<div>
<add-persons v-if="accompanyingCourse.requestor === null"
buttonTitle="requestor.add_requestor"
@@ -163,7 +164,7 @@ export default {
div.flex-table {
margin: 1em 0 0 !important;
& > label,
& > label,
& > ul.record_actions {
margin: 1em 3em 0 !important;
}

View File

@@ -1,21 +1,15 @@
<template>
<div class="vue-component">
<h2><a name="section-50"></a>{{ $t('resources.title')}}</h2>
<div>
<h2><a name="section-70"></a>{{ $t('resources.title')}}</h2>
<div v-if="resources.length > 0">
<label class="col-form-label">{{ $tc('resources.counter', counter) }}</label>
</div>
<table class="table table-bordered table-striped border-dark align-middle" v-if="resources.length > 0">
<thead>
<tr>
<th class="chill-orange">{{ $t('resources.text') }}</th>
<th class="chill-orange">{{ $t('resources.description') }}</th>
<th class="chill-orange">{{ $t('action.actions') }}</th>
</tr>
</thead>
</table>
<div v-else>
<label class="chill-no-data-statement">{{ $tc('resources.counter', counter) }}</label>
</div>
<div class="flex-table mb-3">
<resource-item
v-for="resource in resources"
@@ -25,7 +19,7 @@
</resource-item>
</div>
<div>
<add-persons
<add-persons
buttonTitle="resources.add_resources"
modalTitle="resources.add_resources"
v-bind:key="addPersons.key"
@@ -67,11 +61,11 @@ export default {
}),
methods: {
removeResource(item) {
console.log('@@ CLICK remove resource: item', item);
//console.log('@@ CLICK remove resource: item', item);
this.$store.dispatch('removeResource', item);
},
addNewPersons({ selected, modal }) {
console.log('@@@ CLICK button addNewPersons', selected);
//console.log('@@@ CLICK button addNewPersons', selected);
selected.forEach(function(item) {
this.$store.dispatch('addResource', item);
}, this

View File

@@ -1,24 +1,4 @@
<template>
<!-- <tr> -->
<!-- <td>
<span class="badge rounded-pill bg-secondary"
v-bind:title="resource.resource.id">
<span v-if="resource.resource.type === 'person'" >{{ $t('item.type_person') }}</span>
<span v-if="resource.resource.type === 'thirdparty'" >{{ $t('item.type_thirdparty') }}</span>
</span>
{{ resource.resource.text }}
</td>
<td v-if="resource.resource.type === 'person'">
{{ $tc('person.born') }}{{ $d(resource.resource.birthdate.datetime, 'short') }}
</td>
<td v-else-if="resource.resource.type === 'thirdparty'">
{{ resource.resource.address.text }}<br>
{{ resource.resource.address.postcode.name }}
</td>
<td> -->
<third-party-render-box
:options="{
addLink : false,
@@ -46,32 +26,38 @@
</li>
<li>
<button
class="btn btn-remove"
v-bind:title="$t('action.remove')"
class="btn btn-sm btn-remove"
v-bind:title="$t('action.remove')"
@click.prevent="$emit('remove', resource)">
</button>
</li>
</ul>
</template>
</third-party-render-box>
<!-- </td>
</tr> -->
</template>
<script>
import OnTheFly from 'ChillMainAssets/vuejs/_components/OnTheFly.vue';
import ThirdPartyRenderBox from '../../../../../../../ChillThirdPartyBundle/Resources/public/vuejs/_components/ThirdPartyRenderbox.vue'
import ButtonLocation from '../ButtonLocation.vue';
import ThirdPartyRenderBox from 'ChillThirdPartyAssets/vuejs/_components/Entity/ThirdPartyRenderBox.vue'
export default {
name: 'ResourceItem',
components: {
OnTheFly,
ButtonLocation,
ThirdPartyRenderBox
},
props: ['resource'],
emits: ['remove']
emits: ['remove'],
computed: {
hasCurrentHouseholdAddress() {
if ( this.resource.resource.type === 'person'
&& this.resource.resource.current_household_address !== null ) {
return true;
}
return false;
}
}
}
</script>

View File

@@ -1,15 +1,15 @@
<template>
<div class="vue-component">
<h2><a name="section-30"></a>{{ $t('social_issue.title') }}</h2>
<h2><a name="section-50"></a>{{ $t('social_issue.title') }}</h2>
<div class="my-4">
<!--label for="field">{{ $t('social_issue.label') }}</label
-->
<VueMultiselect
name="field"
:close-on-select="false"
:allow-empty="true"
:show-labels="false"
:allow-empty="true"
:show-labels="false"
track-by="id"
label="text"
:multiple="true"
@@ -20,7 +20,7 @@
:options="options">
</VueMultiselect>
</div>
</div>
</template>
@@ -51,7 +51,7 @@ export default {
//console.log('get socialIssues', response.results);
this.options = response.results;
resolve();
})).catch(error => this.$store.commit('catchError', error));
})).catch(error => this.$store.commit('catchError', error));
},
updateSocialIssues(value) {
this.$store.dispatch('updateSocialIssues', this.transformValue(value));
@@ -60,7 +60,7 @@ export default {
let stored = this.value;
let added = updated.filter(x => stored.indexOf(x) === -1).shift();
let removed = stored.filter(x => updated.indexOf(x) === -1).shift();
let method = (typeof removed === 'undefined') ? 'POST' : 'DELETE';
let method = (typeof removed === 'undefined') ? 'POST' : 'DELETE';
let changed = (typeof removed === 'undefined') ? added : removed;
let body = { type: "social_issue", id: changed.id };
//console.log('body', body);

View File

@@ -1,15 +1,15 @@
<template>
<a
v-if="item.key <= 5"
:href="item.name"
<a
v-if="item.key <= 7"
:href="item.name"
:class="{ 'active': isActive }"
>
<i class="fa fa-fw fa-square"></i>
<span>{{ item.key }}</span>
</a>
<a
<a
v-else-if="step === 'DRAFT'"
:href="item.name"
:href="item.name"
:class="{ 'active': isActive }"
>
<i class="fa fa-fw fa-square"></i>

View File

@@ -0,0 +1,14 @@
{
"name": "vendor_name/AccompanyingCourse",
"description": "description",
"minimum-stability": "stable",
"license": "proprietary",
"authors": [
{
"name": "mat",
"email": "email@example.com"
}
],
"require": {
}
}

View File

@@ -12,11 +12,10 @@ const root = window.vueRootComponent;
* Load all App component, for AccompanyingCourse edition page
*/
if (root === 'app') {
initPromise.then(store => {
const i18n = _createI18n(appMessages);
const app = createApp({
template: `<app></app>`,
})
@@ -31,11 +30,10 @@ if (root === 'app') {
* Load only Banner sub-component, for all others AccompanyingCourse page
*/
if (root === 'banner') {
initPromise.then(store => {
const i18n = _createI18n(appMessages);
const app = createApp({
template: `<banner></banner>`,
})
@@ -44,5 +42,5 @@ if (root === 'banner') {
.component('banner', Banner)
.mount('#banner-accompanying-course');
});
}

View File

@@ -1,4 +1,5 @@
import { personMessages } from 'ChillPersonAssets/vuejs/_js/i18n'
import { addressMessages } from 'ChillMainAssets/vuejs/Address/i18n';
const appMessages = {
fr: {
@@ -20,7 +21,7 @@ const appMessages = {
active: "En file active"
},
open_at: "ouvert le ",
by: "par ",
by: "par ",
emergency: "urgent",
confidential: "confidentiel",
regular: "régulier",
@@ -33,7 +34,7 @@ const appMessages = {
},
persons_associated: {
title: "Usagers concernés",
counter: "Il n'y a pas encore d'usager | 1 usager | {count} usagers",
counter: "Il n'y a pas encore d'usagers | 1 usager | {count} usagers",
firstname: "Prénom",
lastname: "Nom",
name: "Nom",
@@ -63,6 +64,19 @@ const appMessages = {
title: "Problématiques sociales",
label: "Choisir les problématiques sociales",
},
courselocation: {
title: "Localisation du parcours",
add_temporary_address: "Ajouter une adresse temporaire",
edit_temporary_address: "Modifier l'adresse temporaire",
assign_course_address: "Désigner comme l'adresse du parcours",
remove_button: "Enlever l'adresse",
temporary_address_must_be_changed: "Cette addresse est temporaire et devrait être remplacée par celle d'un usager de référence.",
sure: "Êtes-vous sûr ?",
sure_description: "Voulez-vous faire de cette adresse l'adresse du parcours ?",
ok: "Désigner comme adresse du parcours",
person_locator: "Parcours localisé auprès de {0}",
no_address: "Il n'y a pas d'adresse associée au parcours"
},
referrer: {
title: "Référent du parcours",
label: "Vous pouvez choisir un TMS ou vous assigner directement comme référent",
@@ -80,21 +94,36 @@ const appMessages = {
title: "Observations",
label: "Ajout d'une note",
content: "Rédigez une première note…",
created_by: "créé par {0}, le {1}"
created_by: "créé par {0}, le {1}"
},
confirm: {
title: "Confirmation",
text_draft: "Le parcours est actuellement à l'état de ",
text_active: "En validant cette étape, vous lui donnez le statut ",
text_draft: "Le parcours est actuellement à l'état de <b>{0}</b>.",
text_active: "En validant cette étape, vous lui donnez le statut <b>{0}</b>.",
alert_validation: "Certaines conditions ne sont pas remplies pour pouvoir confirmer le parcours :",
participation_not_valid: "sélectionnez au minimum 1 usager",
socialIssue_not_valid: "sélectionnez au minimum une problématique sociale",
location_not_valid: "indiquez au minimum une localisation temporaire du parcours",
sure: "Êtes-vous sûr ?",
sure_description: "Une fois le changement confirmé, il n'est plus possible de le remettre à l'état de brouillon !",
sure_description: "Une fois le changement confirmé, il ne sera plus possible de le remettre à l'état de brouillon !",
ok: "Confirmer le parcours"
},
// catch errors
'Error while updating AccompanyingPeriod Course.': "Erreur du serveur lors de la mise à jour du parcours d'accompagnement.",
'Error while retriving AccompanyingPeriod Course.': "Erreur du serveur lors du chargement du parcours d'accompagnement.",
'Error while confirming AccompanyingPeriod Course.': "Erreur du serveur lors de la confirmation du parcours d'accompagnement.",
'Error while retriving Social Issues.': "Erreur du serveur lors du chargement des problématique sociales.",
'Error while sending AccompanyingPeriod Course participation.': "Erreur du serveur lors de l'envoi des infos d'un usager.",
'Error while sending AccompanyingPeriod Course requestor': "Erreur du serveur lors de l'envoi des infos du demandeur.",
'Error while sending AccompanyingPeriod Course resource.': "Erreur du serveur lors de l'envoi des infos d'un interlocuteur privilégié.",
'Error while updating SocialIssue.': "Erreur du serveur lors de la mise à jour d'une problématique sociale.",
'Error while retriving users.': "Erreur du serveur lors du chargement de la liste des travailleurs.",
'Error while getting whoami.': "Erreur du serveur lors de la requête 'qui suis-je ?'",
'Error while retriving origin\'s list.': "Erreur du serveur lors du chargement de la liste des origines de la demande.",
}
};
Object.assign(appMessages.fr, personMessages.fr);
Object.assign(appMessages.fr, personMessages.fr, addressMessages.fr);
export {
appMessages

View File

@@ -1,32 +1,58 @@
import 'es6-promise/auto';
import { createStore } from 'vuex';
import { getAccompanyingCourse,
import { getAccompanyingCourse,
patchAccompanyingCourse,
confirmAccompanyingCourse,
postParticipation,
postParticipation,
postRequestor,
postResource,
postSocialIssue } from '../api';
const debug = process.env.NODE_ENV !== 'production';
const id = window.accompanyingCourseId;
let initPromise = getAccompanyingCourse(id)
.then(accompanying_course => new Promise((resolve, reject) => {
const store = createStore({
strict: debug,
modules: {
},
state: {
accompanyingCourse: accompanying_course,
addressContext: {},
errorMsg: []
},
getters: {
isParticipationValid(state) {
return state.accompanyingCourse.participations.length > 0;
},
isSocialIssueValid(state) {
return state.accompanyingCourse.socialIssues.length > 0;
},
isLocationValid(state) {
return state.accompanyingCourse.location !== null;
},
validationKeys(state, getters) {
let keys = [];
if (!getters.isParticipationValid) { keys.push('participation'); }
if (!getters.isLocationValid) { keys.push('location'); }
if (!getters.isSocialIssueValid) { keys.push('socialIssue'); }
//console.log('getter keys', keys);
return keys;
},
isValidToBeConfirmed(state, getters) {
if (getters.validationKeys.length === 0) {
return true;
}
return false;
}
},
mutations: {
catchError(state, error) {
state.errorMsg.push(error);
console.log('### mutation: a new error have been catched and pushed in store !', error);
state.errorMsg.push(error);
},
removeParticipation(state, participation) {
//console.log('### mutation: remove participation', participation.id);
@@ -77,7 +103,7 @@ let initPromise = getAccompanyingCourse(id)
postFirstComment(state, comment) {
//console.log('### mutation: postFirstComment', comment);
state.accompanyingCourse.initialComment = comment;
},
},
updateSocialIssues(state, value) {
state.accompanyingCourse.socialIssues = value;
},
@@ -92,6 +118,20 @@ let initPromise = getAccompanyingCourse(id)
confirmAccompanyingCourse(state, response) {
//console.log('### mutation: confirmAccompanyingCourse: response', response);
state.accompanyingCourse.step = response.step;
},
setAddressContext(state, context) {
//console.log('define location context');
state.addressContext = context;
},
updateLocation(state, r) {
//console.log('### mutation: set location attributes', r);
state.accompanyingCourse.location = r.location;
state.accompanyingCourse.locationStatus = r.locationStatus;
state.accompanyingCourse.personLocation = r.personLocation;
},
setEditContextTrue(state) {
//console.log('### mutation: set edit context = true');
state.addressContext.edit = true;
}
},
actions: {
@@ -105,7 +145,7 @@ let initPromise = getAccompanyingCourse(id)
.then(participation => new Promise((resolve, reject) => {
commit('closeParticipation', { participation, payload });
resolve();
})).catch((error) => { commit('catchError', error) });
})).catch((error) => { commit('catchError', error) });
},
addParticipation({ commit }, payload) {
//console.log('## action: fetch post participation (select item): payload', payload);
@@ -113,7 +153,7 @@ let initPromise = getAccompanyingCourse(id)
.then(participation => new Promise((resolve, reject) => {
commit('addParticipation', participation);
resolve();
})).catch((error) => { commit('catchError', error) });
})).catch((error) => { commit('catchError', error) });
},
removeRequestor({ commit, dispatch }) {
//console.log('## action: fetch delete requestor');
@@ -122,7 +162,7 @@ let initPromise = getAccompanyingCourse(id)
commit('removeRequestor');
dispatch('requestorIsAnonymous', false);
resolve();
})).catch((error) => { commit('catchError', error) });
})).catch((error) => { commit('catchError', error) });
},
addRequestor({ commit }, payload) {
//console.log('## action: fetch post requestor: payload', payload);
@@ -130,7 +170,7 @@ let initPromise = getAccompanyingCourse(id)
.then(requestor => new Promise((resolve, reject) => {
commit('addRequestor', requestor);
resolve();
})).catch((error) => { commit('catchError', error) });
})).catch((error) => { commit('catchError', error) });
},
requestorIsAnonymous({ commit }, payload) {
//console.log('## action: fetch patch AccompanyingCourse: payload', payload);
@@ -209,6 +249,30 @@ let initPromise = getAccompanyingCourse(id)
resolve();
})).catch((error) => { commit('catchError', error) });
},
updateLocation({ commit }, payload) {
//console.log('## action: updateLocation', payload.locationStatusTo);
let body = { 'type': payload.entity, 'id': payload.entityId };
let location = {};
if (payload.locationStatusTo === 'person') { // patch for person address (don't remove addressLocation)
location = { 'personLocation': { 'type': 'person', 'id': payload.personId }};
}
else if (payload.locationStatusTo === 'address') { // patch for temporary address
location = { 'personLocation': null, 'addressLocation': { 'id': payload.addressId }};
}
else { // patch to remove person address
location = { 'personLocation': null };
}
Object.assign(body, location);
patchAccompanyingCourse(payload.entityId, body)
.then(accompanyingCourse => new Promise((resolve, reject) => {
commit('updateLocation', {
location: accompanyingCourse.location,
locationStatus: accompanyingCourse.locationStatus,
personLocation: accompanyingCourse.personLocation
});
resolve();
})).catch((error) => { commit('catchError', error) });
},
confirmAccompanyingCourse({ commit }) {
//console.log('## action: confirmAccompanyingCourse');
confirmAccompanyingCourse(id)