fix "impossible to confirm a course"

In some case, the "confirm" button for the form AccompanyingCourse was
disable, due to wrong condition.

This commit also fixes the filtering for users, and allow to remove a
user associated with an accompanyingCourse.
This commit is contained in:
Julien Fastré 2022-02-07 17:44:03 +01:00
parent f9b514c869
commit 03007370bc
5 changed files with 189 additions and 160 deletions

View File

@ -91,11 +91,11 @@ export const multiSelectMessages = {
multiselect: { multiselect: {
placeholder: 'Choisir', placeholder: 'Choisir',
tag_placeholder: 'Créer un nouvel élément', tag_placeholder: 'Créer un nouvel élément',
select_label: 'Appuyer sur "Entrée" pour sélectionner', select_label: '"Entrée" ou cliquez pour sélectionner',
deselect_label: 'Appuyer sur "Entrée" pour désélectionner', deselect_label: '"Entrée" ou cliquez pour désélectionner',
select_group_label: 'Appuyer sur "Entrée" pour sélectionner ce groupe', select_group_label: 'Appuyer sur "Entrée" pour sélectionner ce groupe',
deselect_group_label: 'Appuyer sur "Entrée" pour désélectionner ce groupe', deselect_group_label: 'Appuyer sur "Entrée" pour désélectionner ce groupe',
selected_label: 'Sélectionné' selected_label: 'Sélectionné'
} }
} }
}; };

View File

@ -60,14 +60,14 @@
<template v-slot:body> <template v-slot:body>
<p>{{ $t('confirm.sure_description') }}</p> <p>{{ $t('confirm.sure_description') }}</p>
<div v-if="accompanyingCourse.user === null"> <div v-if="accompanyingCourse.user === null">
<div v-if="filteredReferrersSuggested.length === 0"> <div v-if="usersSuggestedFilteredByJob.length === 0">
<p class="alert alert-warning">{{ $t('confirm.no_suggested_referrer') }}</p> <p class="alert alert-warning">{{ $t('confirm.no_suggested_referrer') }}</p>
</div> </div>
<div v-if="filteredReferrersSuggested.length === 1" class="alert alert-info"> <div v-if="usersSuggestedFilteredByJob.length === 1" class="alert alert-info">
<p>{{ $t('confirm.one_suggested_referrer') }}:</p> <p>{{ $t('confirm.one_suggested_referrer') }}:</p>
<ul class="list-suggest add-items inline"> <ul class="list-suggest add-items inline">
<li> <li>
<user-render-box-badge :user="filteredReferrersSuggested[0]"></user-render-box-badge> <user-render-box-badge :user="usersSuggestedFilteredByJob[0]"></user-render-box-badge>
</li> </li>
</ul> </ul>
<p>{{ $t('confirm.choose_suggested_referrer') }}</p> <p>{{ $t('confirm.choose_suggested_referrer') }}</p>
@ -150,7 +150,6 @@ export default {
computed: { computed: {
...mapState({ ...mapState({
accompanyingCourse: state => state.accompanyingCourse, accompanyingCourse: state => state.accompanyingCourse,
filteredReferrersSuggested: state => state.filteredReferrersSuggested
}), }),
...mapGetters([ ...mapGetters([
'isParticipationValid', 'isParticipationValid',
@ -160,15 +159,16 @@ export default {
'isLocationValid', 'isLocationValid',
'isJobValid', 'isJobValid',
'validationKeys', 'validationKeys',
'isValidToBeConfirmed' 'isValidToBeConfirmed',
'usersSuggestedFilteredByJob',
]), ]),
deleteLink() { deleteLink() {
return `/fr/parcours/${this.accompanyingCourse.id}/delete`; //TODO locale return `/fr/parcours/${this.accompanyingCourse.id}/delete`; //TODO locale
}, },
disableConfirm() { disableConfirm() {
return this.clickedDoNotChooseReferrer return (this.accompanyingCourse.user === null
? (this.accompanyingCourse.user === null && this.filteredReferrersSuggested.length === 0) && this.usersSuggestedFilteredByJob.length === 1
: (this.accompanyingCourse.user === null && this.filteredReferrersSuggested.length === 0) || (this.filteredReferrersSuggested.length === 1); && this.clickedDoNotChooseReferrer === false);
} }
}, },
methods: { methods: {
@ -183,7 +183,7 @@ export default {
}); });
}, },
chooseSuggestedReferrer() { chooseSuggestedReferrer() {
this.$store.dispatch('updateReferrer', this.filteredReferrersSuggested[0]) this.$store.dispatch('updateReferrer', this.usersSuggestedFilteredByJob[0])
.catch(({name, violations}) => { .catch(({name, violations}) => {
if (name === 'ValidationException' || name === 'AccessException') { if (name === 'ValidationException' || name === 'AccessException') {
violations.forEach((violation) => this.$toast.open({message: violation})); violations.forEach((violation) => this.$toast.open({message: violation}));

View File

@ -1,164 +1,178 @@
<template> <template>
<div class="vue-component"> <div class="vue-component">
<h2><a id="section-80"></a>{{ $t('referrer.title') }}</h2> <h2><a id="section-80"></a>{{ $t('referrer.title') }}</h2>
<div> <div>
<label class="col-form-label" for="selectJob"> <label class="col-form-label" for="selectJob">
{{ $t('job.label') }} {{ $t('job.label') }}
</label> </label>
<VueMultiselect <VueMultiselect
name="selectJob" name="selectJob"
label="text" label="text"
:custom-label="customJobLabel" :custom-label="customJobLabel"
track-by="id" track-by="id"
:multiple="false" :multiple="false"
:searchable="true" :searchable="true"
:placeholder="$t('job.placeholder')" :placeholder="$t('job.placeholder')"
v-model="valueJob" v-model="valueJob"
:options="jobs" :options="jobs"
:select-label="$t('multiselect.select_label')" :select-label="$t('multiselect.select_label')"
:deselect-label="$t('multiselect.deselect_label')" :deselect-label="$t('multiselect.deselect_label')"
:selected-label="$t('multiselect.selected_label')" :selected-label="$t('multiselect.selected_label')"
@select="updateJob"> ></VueMultiselect>
</VueMultiselect>
<label class="col-form-label" for="selectReferrer"> <label class="col-form-label" for="selectReferrer">
{{ $t('referrer.label') }} {{ $t('referrer.label') }}
</label> </label>
<VueMultiselect <VueMultiselect
name="selectReferrer" name="selectReferrer"
label="text" label="text"
track-by="id" track-by="id"
:multiple="false" :multiple="false"
:searchable="true" :searchable="true"
:placeholder="$t('referrer.placeholder')" :placeholder="$t('referrer.placeholder')"
v-model="value" v-model="value"
:options="users" :options="users"
:select-label="$t('multiselect.select_label')" :select-label="$t('multiselect.select_label')"
:deselect-label="$t('multiselect.deselect_label')" :deselect-label="$t('multiselect.deselect_label')"
:selected-label="$t('multiselect.selected_label')" :selected-label="$t('multiselect.selected_label')"
@select="updateReferrer"> ></VueMultiselect>
</VueMultiselect>
<template v-if="filteredReferrersSuggested.length > 0"> <template v-if="usersSuggestedFilteredByJob.length > 0">
<ul class="list-suggest add-items inline"> <ul class="list-suggest add-items inline">
<li v-for="(u, i) in filteredReferrersSuggested" @click="updateReferrer(u)" :key="`referrer-${i}`"> <li v-for="(u, i) in usersSuggestedFilteredByJob" @click="updateReferrer(u)" :key="`referrer-${i}`">
<span> <span>
<user-render-box-badge :user="u"></user-render-box-badge> <user-render-box-badge :user="u"></user-render-box-badge>
</span> </span>
</li> </li>
</ul> </ul>
</template> </template>
</div> </div>
<div> <div>
<ul class="record_actions"> <ul class="record_actions">
<li> <li>
<button <button
class="btn btn-create" class="btn btn-create"
type="button" type="button"
name="button" name="button"
@click="assignMe"> @click="assignMe">
{{ $t('referrer.assign_me') }} {{ $t('referrer.assign_me') }}
</button> </button>
</li> </li>
</ul> </ul>
</div> </div>
<div v-if="!isJobValid" class="alert alert-warning to-confirm"> <div v-if="!isJobValid" class="alert alert-warning to-confirm">
{{ $t('job.not_valid') }} {{ $t('job.not_valid') }}
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import VueMultiselect from 'vue-multiselect'; import VueMultiselect from 'vue-multiselect';
import { makeFetch } from 'ChillMainAssets/lib/api/apiMethods'; import {makeFetch} from 'ChillMainAssets/lib/api/apiMethods';
import { mapState, mapGetters } from 'vuex'; import {mapState, mapGetters} from 'vuex';
import UserRenderBoxBadge from "ChillMainAssets/vuejs/_components/Entity/UserRenderBoxBadge"; import UserRenderBoxBadge from "ChillMainAssets/vuejs/_components/Entity/UserRenderBoxBadge";
export default { export default {
name: "Referrer", name: "Referrer",
components: { components: {
UserRenderBoxBadge, UserRenderBoxBadge,
VueMultiselect, VueMultiselect,
}, },
data() { data() {
return { return {
jobs: [] jobs: []
}
},
computed: {
...mapState({
valueJob: state => state.accompanyingCourse.job,
}),
...mapGetters(['isJobValid', 'usersSuggestedFilteredByJob']),
users: function () {
let users = this.$store.getters.usersFilteredByJob;
console.log('users filtered by job', users);
// ensure that the selected user is in the list. add it if necessary
if (this.$store.state.accompanyingCourse.user !== null && users.find(u => this.$store.state.accompanyingCourse.user.id === u.id) === undefined) {
console.log('add user to users');
users.push(this.$store.state.accompanyingCourse.user);
} }
},
computed: { console.log('users to return', users);
...mapState({ return users;
value: state => state.accompanyingCourse.user, },
valueJob: state => state.accompanyingCourse.job, valueJob: {
users: state => state.users.filter(u => { get() {
if (u.user_job && state.accompanyingCourse.job) { return this.$store.state.accompanyingCourse.job;
return u.user_job.id === state.accompanyingCourse.job.id; },
} else { set(value) {
return false; this.$store.dispatch('updateJob', value)
}
}),
filteredReferrersSuggested: state => state.filteredReferrersSuggested,
}),
...mapGetters([
'isJobValid'
])
},
mounted() {
this.getJobs();
},
methods: {
updateReferrer(value) {
this.$store.dispatch('updateReferrer', value)
.catch(({name, violations}) => { .catch(({name, violations}) => {
if (name === 'ValidationException' || name === 'AccessException') { if (name === 'ValidationException' || name === 'AccessException') {
violations.forEach((violation) => this.$toast.open({message: violation})); violations.forEach((violation) => this.$toast.open({message: violation}));
} else { } else {
this.$toast.open({message: 'An error occurred'}) this.$toast.open({message: 'An error occurred'})
} }
}); });
},
getJobs() {
const url = '/api/1.0/main/user-job.json';
makeFetch('GET', url)
.then(response => {
this.jobs = response.results;
})
.catch((error) => {
this.$toast.open({message: error.txt})
})
},
updateJob(value) {
this.$store.dispatch('updateJob', value)
.catch(({name, violations}) => {
if (name === 'ValidationException' || name === 'AccessException') {
violations.forEach((violation) => this.$toast.open({message: violation}));
} else {
this.$toast.open({message: 'An error occurred'})
}
});
},
customJobLabel(value) {
return value.label.fr;
},
assignMe() {
const url = `/api/1.0/main/whoami.json`;
makeFetch('GET', url)
.then(response => {
this.$store.dispatch('updateReferrer', response);
return response;
})
.catch((error) => {
commit('catchError', error);
this.$toast.open({message: error.body})
})
} }
} },
value: {
get() {
return this.$store.state.accompanyingCourse.user;
},
set(value) {
console.log('set referrer', value);
this.$store.dispatch('updateReferrer', value)
.catch(({name, violations}) => {
if (name === 'ValidationException' || name === 'AccessException') {
violations.forEach((violation) => this.$toast.open({message: violation}));
} else {
this.$toast.open({message: 'An error occurred'})
}
});
}
},
},
mounted() {
this.getJobs();
},
methods: {
updateReferrer(value) {
this.value = value;
},
getJobs() {
const url = '/api/1.0/main/user-job.json';
makeFetch('GET', url)
.then(response => {
this.jobs = response.results;
})
.catch((error) => {
this.$toast.open({message: error.txt})
})
},
customJobLabel(value) {
return value.label.fr;
},
assignMe() {
const url = `/api/1.0/main/whoami.json`;
makeFetch('GET', url)
.then(user => {
this.value = user
})
/*.catch((error) => {
commit('catchError', error);
this.$toast.open({message: error.body})
})*/
}
}
} }
</script> </script>

View File

@ -140,7 +140,7 @@ const appMessages = {
sure_description: "Une fois le changement confirmé, il ne sera 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", ok: "Confirmer le parcours",
delete: "Supprimer le parcours", delete: "Supprimer le parcours",
no_suggested_referrer: "Il n'y a aucun référent qui puisse être désigné pour ce parcours. Vérifiez la localisation du parcours, les métiers et service indiqués. Si le problème persiste, contactez l'administrateur du logiciel.", no_suggested_referrer: "Il n'y a aucun référent qui puisse être suggéré pour ce parcours. Vérifiez la localisation du parcours, les métiers et service indiqués. Si les données sont correctes, vous pouvez confirmer ce parcours.",
one_suggested_referrer: "Un unique référent peut être suggéré pour ce parcours", one_suggested_referrer: "Un unique référent peut être suggéré pour ce parcours",
choose_suggested_referrer: "Voulez-vous le désigner directement ?", choose_suggested_referrer: "Voulez-vous le désigner directement ?",
choose_button: "Désigner", choose_button: "Désigner",

View File

@ -40,7 +40,6 @@ let initPromise = (root) => Promise.all([getScopesPromise(root), accompanyingCou
scopesAtBackend: accompanyingCourse.scopes.map(scope => scope), scopesAtBackend: accompanyingCourse.scopes.map(scope => scope),
// the users which are available for referrer // the users which are available for referrer
referrersSuggested: [], referrersSuggested: [],
filteredReferrersSuggested: [],
// all the users available // all the users available
users: [], users: [],
permissions: {} permissions: {}
@ -93,6 +92,30 @@ let initPromise = (root) => Promise.all([getScopesPromise(root), accompanyingCou
return false; return false;
}, },
usersFilteredByJob(state) {
return state.users.filter(u => {
if (null !== state.accompanyingCourse.job) {
return (u.user_job === null ? null : u.user_job.id) === state.accompanyingCourse.job.id;
} else {
return true;
}
});
},
usersSuggestedFilteredByJob(state) {
return state.referrersSuggested.filter(u => {
if (null !== state.accompanyingCourse.job) {
return (u.user_job === null ? null : u.user_job.id) === state.accompanyingCourse.job.id;
} else {
return true;
}
}).filter(u => {
if (null !== state.accompanyingCourse.user) {
return u.id !== state.accompanyingCourse.user.id;
}
return true;
});
},
}, },
mutations: { mutations: {
catchError(state, error) { catchError(state, error) {
@ -216,22 +239,6 @@ let initPromise = (root) => Promise.all([getScopesPromise(root), accompanyingCou
return u; return u;
}); });
}, },
setFilteredReferrersSuggested(state) {
state.filteredReferrersSuggested = state.referrersSuggested.filter(u => {
if (u.user_job && state.accompanyingCourse.job && state.accompanyingCourse.user) {
return u.user_job.id === state.accompanyingCourse.job.id && state.accompanyingCourse.user.id !== u.id
} else {
if (null === state.accompanyingCourse.user) {
if (u.user_job && state.accompanyingCourse.job) {
return u.user_job.id === state.accompanyingCourse.job.id
} else {
return true;
}
}
return state.accompanyingCourse.user.id !== u.id;
}
})
},
confirmAccompanyingCourse(state, response) { confirmAccompanyingCourse(state, response) {
//console.log('### mutation: confirmAccompanyingCourse: response', response); //console.log('### mutation: confirmAccompanyingCourse: response', response);
state.accompanyingCourse.step = response.step; state.accompanyingCourse.step = response.step;
@ -689,8 +696,14 @@ let initPromise = (root) => Promise.all([getScopesPromise(root), accompanyingCou
}) })
}, },
updateReferrer({ commit }, payload) { updateReferrer({ commit }, payload) {
console.log('update referrer', payload);
console.log('payload !== null', payload !== null);
const url = `/api/1.0/person/accompanying-course/${id}.json`; const url = `/api/1.0/person/accompanying-course/${id}.json`;
const body = { type: "accompanying_period", user: { id: payload.id, type: payload.type }}; let body = { type: "accompanying_period", user: null };
if (payload !== null) {
body = { type: "accompanying_period", user: { id: payload.id, type: payload.type } };
}
return makeFetch('PATCH', url, body) return makeFetch('PATCH', url, body)
.then((response) => { .then((response) => {
@ -704,12 +717,15 @@ let initPromise = (root) => Promise.all([getScopesPromise(root), accompanyingCou
}, },
updateJob({ commit }, payload) { updateJob({ commit }, payload) {
const url = `/api/1.0/person/accompanying-course/${id}.json`; const url = `/api/1.0/person/accompanying-course/${id}.json`;
const body = { type: "accompanying_period", job: { id: payload.id, type: payload.type }}; let body = { type: "accompanying_period", job: null };
if (payload !== null) {
body = { type: "accompanying_period", job: { id: payload.id, type: payload.type } };
}
return makeFetch('PATCH', url, body) return makeFetch('PATCH', url, body)
.then((response) => { .then((response) => {
commit('updateJob', response.job); commit('updateJob', response.job);
commit('setFilteredReferrersSuggested');
}) })
.catch((error) => { .catch((error) => {
commit('catchError', error); commit('catchError', error);
@ -734,7 +750,6 @@ let initPromise = (root) => Promise.all([getScopesPromise(root), accompanyingCou
async fetchReferrersSuggested({ state, commit}) { async fetchReferrersSuggested({ state, commit}) {
let users = await getReferrersSuggested(state.accompanyingCourse); let users = await getReferrersSuggested(state.accompanyingCourse);
commit('setReferrersSuggested', users); commit('setReferrersSuggested', users);
commit('setFilteredReferrersSuggested');
if ( if (
null === state.accompanyingCourse.user null === state.accompanyingCourse.user
&& !state.accompanyingCourse.confidential && !state.accompanyingCourse.confidential