207 lines
7.1 KiB
Vue

<template>
<div class="vue-component">
<h2><a id="section-10"></a>{{ $t('persons_associated.title')}}</h2>
<div v-if="currentParticipations.length > 0">
<label class="col-form-label">{{ $tc('persons_associated.counter', counter) }}</label>
</div>
<div v-else>
<label class="chill-no-data-statement">{{ $tc('persons_associated.counter', counter) }}</label>
</div>
<div v-if="participationWithoutHousehold.length > 0" class="alert alert-warning no-household">
<i class="fa fa-warning fa-2x"></i>
<form method="GET" action="/fr/person/household/members/editor">
<div class="float-button bottom"><div class="box">
<div class="action">
<button class="btn btn-update" type="submit">{{ $t('persons_associated.update_household') }}</button>
</div>
<p class="mb-3">{{ $t('persons_associated.person_without_household_warning') }}</p>
<div class="form-check" v-for="p in participationWithoutHousehold" :key="p.id">
<input type="checkbox"
class="form-check-input"
v-model="hasNoHousehold"
name="persons[]"
checked="checked"
:id="p.person.id"
:value="p.person.id"
/>
<label class="form-check-label">
{{ p.person.text }}
</label>
</div>
<input type="hidden" name="expand_suggestions" value="true">
<input type="hidden" name="returnPath" :value="getReturnPath">
<input type="hidden" name="accompanying_period_id" :value="courseId">
</div></div>
</form>
</div>
<div class="flex-table mb-3">
<participation-item
v-for="participation in currentParticipations"
v-bind:participation="participation"
v-bind:key="participation.id"
@remove="removeParticipation"
@close="closeParticipation">
</participation-item>
</div>
<div v-if="suggestedPersons.length > 0">
<ul class="list-unstyled">
<li v-for="p in suggestedPersons" :key="p.id" @click="addSuggestedPerson(p)">
<span class="badge bg-primary" style="cursor: pointer;">
<i class="fa fa-plus fa-fw text-success"></i>
{{ p.text }}
</span>
</li>
</ul>
</div>
<div>
<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>
<div v-if="!isParticipationValid" class="alert alert-warning to-confirm">
{{ $t('persons_associated.participation_not_valid') }}
</div>
</div>
</template>
<script>
import {mapGetters, mapState} from 'vuex';
import ParticipationItem from "./PersonsAssociated/ParticipationItem.vue";
import AddPersons from 'ChillPersonAssets/vuejs/_components/AddPersons.vue';
export default {
name: 'PersonsAssociated',
components: {
ParticipationItem,
AddPersons
},
data() {
return {
addPersons: {
key: 'persons_associated',
options: {
type: ['person'],
priority: null,
uniq: false,
}
}
}
},
computed: {
...mapState({
courseId: state => state.accompanyingCourse.id,
participations: state => state.accompanyingCourse.participations,
suggestedPersons: state => [
state.accompanyingCourse.requestor,
...state.accompanyingCourse.resources.map(r => r.resource)
]
.filter((e) => e !== null)
.filter((e) => e.type === 'person')
.filter(
(p) => !state.accompanyingCourse.participations.map((pa) => pa.person.id).includes(p.id)
)
}),
...mapGetters([
'isParticipationValid'
]),
currentParticipations() {
return this.participations.filter(p => p.endDate === null)
},
counter() {
return this.currentParticipations.length;
},
participationWithoutHousehold() {
return this.currentParticipations.filter(p => p.person.current_household_id === null);
},
getReturnPath() {
return window.location.pathname + window.location.search + window.location.hash;
},
},
methods: {
removeParticipation(item) {
this.$store.dispatch('removeParticipation', item)
.catch(({name, violations}) => {
if (name === 'ValidationException' || name === 'AccessException') {
violations.forEach((violation) => this.$toast.open({message: violation}));
} else {
this.$toast.open({message: 'An error occurred'})
}
});
},
closeParticipation(item) {
this.$store.dispatch('closeParticipation', item)
.catch(({name, violations}) => {
if (name === 'ValidationException' || name === 'AccessException') {
violations.forEach((violation) => this.$toast.open({message: violation}));
} else {
this.$toast.open({message: 'An error occurred'})
}
});
},
addNewPersons({ selected, modal }) {
selected.forEach(function(item) {
this.$store.dispatch('addParticipation', item)
.catch(({name, violations}) => {
if (name === 'ValidationException' || name === 'AccessException') {
violations.forEach((violation) => this.$toast.open({message: violation}));
} else {
this.$toast.open({message: 'An error occurred'})
}
});
}, this
);
this.$refs.addPersons.resetSearch(); // to cast child method
modal.showModal = false;
},
addSuggestedPerson(person) {
this.$store.dispatch('addParticipation', { result: person, type: 'person' })
.catch(({name, violations}) => {
if (name === 'ValidationException' || name === 'AccessException') {
violations.forEach((violation) => this.$toast.open({message: violation}));
} else {
this.$toast.open({message: 'An error occurred'})
}
})
},
}
}
</script>
<style lang="scss" scoped>
div#accompanying-course {
div.vue-component {
& > div.alert.no-household {
margin: 0 0 -1em;
}
div.no-household {
padding-bottom: 1.5em;
display: flex;
flex-direction: row;
& > i {
flex-basis: 1.5em; flex-grow: 0; flex-shrink: 0;
padding-top: 0.2em;
opacity: 0.75;
}
& > form {
flex-basis: auto;
div.action {
button.btn-update {
margin-right: 2em;
}
}
}
}
}
}
</style>