Merge remote-tracking branch 'origin/master' into HEAD

This commit is contained in:
2021-09-24 12:32:19 +02:00
273 changed files with 8744 additions and 3656 deletions

View File

@@ -87,7 +87,6 @@ div.person-view {
}
}
/*
* ACCOMPANYING_COURSE CONTEXT
* Header custom for Accompanying Course
@@ -125,7 +124,6 @@ abbr.referrer {
align-self: center; // in flex context
}
/*
* HOUSEHOLD CONTEXT
* Header custom for Household
@@ -157,12 +155,19 @@ div.banner {
span.badge-member {
flex-shrink: 0; flex-grow: 0; flex-basis: auto;
color: $white;
border: 1px solid #ffffff3b;
border: 1px solid transparentize($white, 0.75);
border-bottom: 3px solid transparentize( shade-color( $chill-green, 20%), 0.3);
border-radius: 8px;
padding: 0.4em 0.8em;
padding: 0.2em 0.7em;
margin-bottom: 0.2em;
margin-right: 0.3em;
&.holder { order: -1; }
&.holder {
order: -1;
.fa-holder .text-success {
color: transparentize( shade-color( $chill-green, 20%), 0.3) !important;
}
}
&.child { order: 2; }
}
}
@@ -179,3 +184,66 @@ div.banner {
}
}
}
div.household-resume {
display: flex;
flex-direction: row;
align-items: center;
div.col-address {
font-size: 120%;
padding-left: 1em;
}
div.col-comment {
//padding: 0;
margin-bottom: 1rem;
display: flex;
flex-direction: column;
> * > * {
& > .chill-user-quote {
margin: 1.5em -1.67em 0;
}
}
}
}
/*
* BADGES, MARKS, PINS
* for chill person theme
*/
// chill person badges
span.badge-person,
span.badge-thirdparty {
display: inline-block;
padding: 0 0.5em !important;
background-color: $white;
color: $dark;
border: 1px solid $chill-ll-gray;
border-bottom-width: 2px;
border-bottom-style: solid;
border-radius: 6px;
a {
text-decoration: none;
}
}
span.badge-person {
border-bottom-color: $chill-green;
}
// todo: move in thirdparty
span.badge-thirdparty {
border-bottom-color: shade-color($chill-pink, 10%);
}
// household holder mark
span.fa-holder {
width: 1em;
margin: -10px 0.3em -8px 0;
i:last-child {
font-weight: 900;
color: white;
font-size: 70%;
font-family: "Open Sans Extrabold";
}
}

View File

@@ -26,26 +26,3 @@
}
}
}
// specific chill badges
span.badge-person,
span.badge-thirdparty {
display: inline-block;
padding: 0 0.5em !important;
background-color: $white;
color: $dark;
border: 1px solid $chill-ll-gray;
border-bottom-width: 2px;
border-bottom-style: solid;
border-radius: 6px;
a {
text-decoration: none;
}
}
span.badge-person {
border-bottom-color: $chill-green;
}
// todo: move in thirdparty
span.badge-thirdparty {
border-bottom-color: shade-color($chill-pink, 10%);
}

View File

@@ -10,6 +10,7 @@
<origin-demand></origin-demand>
<requestor></requestor>
<social-issue></social-issue>
<scopes></scopes>
<referrer></referrer>
<resources></resources>
<comment v-if="accompanyingCourse.step === 'DRAFT'"></comment>
@@ -32,6 +33,7 @@ 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 Scopes from './components/Scopes.vue';
import Referrer from './components/Referrer.vue';
import Resources from './components/Resources.vue';
import Comment from './components/Comment.vue';
@@ -47,6 +49,7 @@ export default {
Requestor,
SocialIssue,
CourseLocation,
Scopes,
Referrer,
Resources,
Comment,
@@ -77,7 +80,7 @@ export default {
left: -22px;
top: 4px;
}
a[name^="section"] {
a[id^="section"] {
position: absolute;
top: -2.5em; // reference for stickNav
}
@@ -93,7 +96,8 @@ export default {
}
& > div {
margin: 1em 3em 0;
&.flex-table {
&.flex-table,
&.flex-bloc {
margin: 1em 0 0;
}
}

View File

@@ -191,7 +191,49 @@ const getListOrigins = () => {
if (response.ok) { return response.json(); }
throw { msg: 'Error while retriving origin\'s list.', sta: response.status, txt: response.statusText, err: new Error(), body: response.body };
});
}
};
const addScope = (id, scope) => {
const url = `/api/1.0/person/accompanying-course/${id}/scope.json`;
console.log(url);
console.log(scope);
return fetch(url, {
method: 'POST',
body: JSON.stringify({
id: scope.id,
type: scope.type,
}),
headers: {
'Content-Type': 'application/json;charset=utf-8'
},
})
.then(response => {
if (response.ok) { return response.json(); }
throw { msg: 'Error while adding scope', sta: response.status, txt: response.statusText, err: new Error(), body: response.body };
});
};
const removeScope = (id, scope) => {
const url = `/api/1.0/person/accompanying-course/${id}/scope.json`;
console.log(url);
console.log(scope);
return fetch(url, {
method: 'DELETE',
body: JSON.stringify({
id: scope.id,
type: scope.type,
}),
headers: {
'Content-Type': 'application/json;charset=utf-8'
},
})
.then(response => {
if (response.ok) { return response.json(); }
throw { msg: 'Error while adding scope', sta: response.status, txt: response.statusText, err: new Error(), body: response.body };
});
};
export {
getAccompanyingCourse,
@@ -204,5 +246,7 @@ export {
getUsers,
whoami,
getListOrigins,
postSocialIssue
postSocialIssue,
addScope,
removeScope,
};

View File

@@ -13,7 +13,7 @@
<h2 class="modal-title">{{ $t('courselocation.sure') }}</h2>
</template>
<template v-slot:body>
<show-address :address="person.current_household_address"></show-address>
<address-render-box :address="person.current_household_address"></address-render-box>
<p>{{ $t('courselocation.sure_description') }}</p>
</template>
<template v-slot:footer>
@@ -28,12 +28,12 @@
<script>
import {mapState} from "vuex";
import Modal from 'ChillMainAssets/vuejs/_components/Modal';
import ShowAddress from "ChillMainAssets/vuejs/Address/components/ShowAddress";
import AddressRenderBox from "ChillMainAssets/vuejs/_components/Entity/AddressRenderBox.vue";
export default {
name: "ButtonLocation",
components: {
ShowAddress,
AddressRenderBox,
Modal,
},
props: ['person'],
@@ -54,8 +54,8 @@ export default {
assignAddress() {
//console.log('assignAddress id', this.person.current_household_address);
let payload = {
entity: this.context.entity.type,
entityId: this.context.entity.id,
target: this.context.target.name,
targetId: this.context.target.id,
locationStatusTo: 'person',
personId: this.person.id
};

View File

@@ -1,6 +1,6 @@
<template>
<div class="vue-component">
<h2><a name="section-80"></a>{{ $t('comment.title') }}</h2>
<h2><a id="section-90"></a>{{ $t('comment.title') }}</h2>
<!--div class="error flash_message" v-if="errors.length > 0">
{{ errors[0] }}

View File

@@ -1,6 +1,6 @@
<template>
<div class="vue-component">
<h2><a name="section-90"></a>
<h2><a id="section-100"></a>
{{ $t('confirm.title') }}
</h2>
<div>
@@ -88,6 +88,10 @@ export default {
socialIssue: {
msg: 'confirm.socialIssue_not_valid',
anchor: '#section-50'
},
scopes: {
msg: 'confirm.set_a_scope',
anchor: '#section-65'
}
}
}

View File

@@ -1,10 +1,9 @@
<template>
<div class="vue-component">
<h2><a name="section-20"></a>
<h2><a id="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>
@@ -17,9 +16,9 @@
<div class="flex-table" v-if="accompanyingCourse.location">
<div class="item-bloc">
<show-address
<address-render-box
:address="accompanyingCourse.location">
</show-address>
</address-render-box>
<div v-if="isPersonLocation" class="alert alert-secondary separator">
<label class="col-form-label">
@@ -41,8 +40,7 @@
:context="context"
:key="addAddress.type"
:options="addAddress.options"
:result="addAddress.result"
@submitAddress="submitTemporaryAddress"
:addressChangedCallback="submitTemporaryAddress"
ref="addAddress">
</add-address>
</li>
@@ -63,13 +61,13 @@
<script>
import { mapState } from "vuex";
import AddAddress from 'ChillMainAssets/vuejs/Address/components/AddAddress.vue';
import ShowAddress from 'ChillMainAssets/vuejs/Address/components/ShowAddress.vue';
import AddressRenderBox from 'ChillMainAssets/vuejs/_components/Entity/AddressRenderBox.vue';
export default {
name: "CourseLocation",
components: {
AddAddress,
ShowAddress
AddressRenderBox
},
data() {
return {
@@ -89,10 +87,12 @@ export default {
edit: 'courselocation.edit_temporary_address'
},
/// Display each step in page or Modal
bindModal: {
//step1: false, step2: false
},
hideDateFrom: true
openPanesInModal: true,
// Use Date fields
//useDate: {
// validFrom: true
//},
hideAddress: true
}
}
}
@@ -118,8 +118,8 @@ export default {
methods: {
initAddressContext() {
let context = {
entity: {
type: this.accompanyingCourse.type,
target: {
name: this.accompanyingCourse.type,
id: this.accompanyingCourse.id
},
edit: false,
@@ -132,31 +132,30 @@ export default {
this.$store.commit('setAddressContext', context);
},
removeAddress() {
//console.log('remove address');
let payload = {
entity: this.context.entity.type,
entityId: this.context.entity.id,
target: this.context.target.name,
targetId: this.context.target.id,
locationStatusTo: 'none'
};
//console.log('remove address');
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();
submitTemporaryAddress(payload) {
//console.log('@@@ click on Submit Temporary Address Button', payload);
payload['locationStatusTo'] = 'address'; // <== temporary, not none, not person
this.$store.dispatch('updateLocation', payload);
this.$store.commit('setEditContextTrue');
this.$store.commit('setEditContextTrue', payload);
}
},
mounted() {
created() {
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);
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,6 +1,6 @@
<template>
<div class="vue-component">
<h2><a name="section-30"></a>{{ $t('origin.title') }}</h2>
<h2><a id="section-30"></a>{{ $t('origin.title') }}</h2>
<div class="mb-4">
<label for="selectOrigin">

View File

@@ -1,17 +1,45 @@
<template>
<div class="vue-component">
<h2><a name="section-10"></a>{{ $t('persons_associated.title')}}</h2>
<h2><a id="section-10"></a>{{ $t('persons_associated.title')}}</h2>
<div v-if="participations.length > 0">
<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">
<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" for="hasNoHousehold">
{{ 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 participations"
v-for="participation in currentParticipations"
v-bind:participation="participation"
v-bind:key="participation.id"
@remove="removeParticipation"
@@ -56,10 +84,24 @@ export default {
}
}
},
computed: mapState({
participations: state => state.accompanyingCourse.participations,
counter: state => state.accompanyingCourse.participations.length
}),
computed: {
...mapState({
courseId: state => state.accompanyingCourse.id,
participations: state => state.accompanyingCourse.participations
}),
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) {
//console.log('@@ CLICK remove participation: item', item);
@@ -81,3 +123,30 @@ export default {
}
}
</script>
<style lang="scss" scoped>
div#accompanying-course {
div.vue-component {
& > div.alert {
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>

View File

@@ -1,15 +1,17 @@
<template>
<person-render-box
<person-render-box render="bloc"
:options="{
addInfo : true,
addId : false,
addEntity: false,
addLink: false,
addHouseholdLink: true,
addAltNames: true,
addAge : false,
addAge : true,
hLevel : 3,
}"
:person="participation.person">
:person="participation.person"
:returnPath="getAccompanyingCourseReturnPath">
<template v-slot:record-actions>
<ul class="record_actions">
@@ -40,34 +42,54 @@
<li>
<button v-if="!participation.endDate"
class="btn btn-sm btn-remove"
v-bind:title="$t('action.remove')"
@click.prevent="$emit('close', participation)">
v-bind:title="$t('persons_associated.leave_course')"
@click="modal.showModal = true">
</button>
<button v-else
class="btn btn-sm btn-remove disabled"></button>
</li>
</ul>
</template>
</person-render-box>
<teleport to="body">
<modal v-if="modal.showModal" :modalDialogClass="modal.modalDialogClass" @close="modal.showModal = false">
<template v-slot:header>
<h2 class="modal-title">{{ $t('persons_associated.sure') }}</h2>
</template>
<template v-slot:body>
<p>{{ $t('persons_associated.sure_description') }}</p>
</template>
<template v-slot:footer>
<button class="btn btn-danger" @click.prevent="$emit('close', participation)">
{{ $t('persons_associated.ok') }}
</button>
</template>
</modal>
</teleport>
</template>
<script>
import OnTheFly from 'ChillMainAssets/vuejs/_components/OnTheFly.vue';
import ButtonLocation from '../ButtonLocation.vue';
import PersonRenderBox from 'ChillPersonAssets/vuejs/_components/Entity/PersonRenderBox.vue';
import Modal from 'ChillMainAssets/vuejs/_components/Modal';
export default {
name: 'ParticipationItem',
components: {
OnTheFly,
ButtonLocation,
PersonRenderBox
PersonRenderBox,
Modal
},
props: ['participation'],
emits: ['remove', 'close'],
data() {
return {
modal: {
showModal: false,
modalDialogClass: "modal-dialog-centered modal-md"
},
PersonRenderBox: {
participation: 'participation',
options: {
@@ -86,6 +108,9 @@ export default {
return true;
}
return false;
},
getAccompanyingCourseReturnPath() {
return `fr/parcours/${this.$store.state.accompanyingCourse.id}/edit#section-10`;
}
}
}
@@ -93,10 +118,7 @@ export default {
/*
* dates of participation
*
* :title="$t('persons_associated.date_start_to_end', {
* start: $d(participation.startDate.datetime, 'short'),
* end: $d(participation.endDate.datetime, 'short')
* })"
*
*
* <tr>
* <td><span v-if="participation.startDate">

View File

@@ -1,6 +1,6 @@
<template>
<div class="vue-component">
<h2><a name="section-60"></a>{{ $t('referrer.title') }}</h2>
<h2><a id="section-70"></a>{{ $t('referrer.title') }}</h2>
<div>
<label class="col-form-label" for="selectReferrer">

View File

@@ -1,7 +1,7 @@
<template>
<div class="vue-component">
<h2><a name="section-40"></a>{{ $t('requestor.title') }}</h2>
<h2><a id="section-40"></a>{{ $t('requestor.title') }}</h2>
<div v-if="accompanyingCourse.requestor" class="flex-table">
@@ -16,7 +16,7 @@
addLink: false,
addId: false,
addEntity: true,
addInfo: true,
addInfo: false,
hLevel: 3,
isMultiline: true
}"
@@ -30,7 +30,7 @@
</template>
</third-party-render-box>
<person-render-box v-else-if="accompanyingCourse.requestor.type == 'person'"
<person-render-box render="bloc" v-else-if="accompanyingCourse.requestor.type == 'person'"
:person="accompanyingCourse.requestor"
:options="{
addLink: false,

View File

@@ -1,7 +1,7 @@
<template>
<div class="vue-component">
<h2><a name="section-70"></a>{{ $t('resources.title')}}</h2>
<h2><a id="section-80"></a>{{ $t('resources.title')}}</h2>
<div v-if="resources.length > 0">
<label class="col-form-label">{{ $tc('resources.counter', counter) }}</label>
@@ -10,7 +10,7 @@
<label class="chill-no-data-statement">{{ $tc('resources.counter', counter) }}</label>
</div>
<div class="flex-table mb-3">
<div class="flex-bloc mb-3">
<resource-item
v-for="resource in resources"
v-bind:resource="resource"
@@ -76,3 +76,11 @@ export default {
}
}
</script>
<style lang="scss">
div.flex-bloc {
div.item-bloc {
flex-basis: 50%;
}
}
</style>

View File

@@ -1,5 +1,5 @@
<template>
<person-render-box
<person-render-box render="bloc"
v-if="resource.resource.type === 'person'"
:person="resource.resource"
:options="{ addInfo : true, addId : false, addEntity: true, addLink: false, addAltNames: true, addAge : false, hLevel : 3 }"
@@ -17,7 +17,7 @@
<third-party-render-box
v-if="resource.resource.type === 'thirdparty'"
:thirdparty="resource.resource"
:options="{ addLink : false, addId : false, addEntity: true, addInfo: true, hLevel: 3 }"
:options="{ addLink : false, addId : false, addEntity: true, addInfo: false, hLevel: 3 }"
>
<template v-slot:record-actions>
<ul class="record_actions">

View File

@@ -0,0 +1,47 @@
<template>
<div class="vue-component">
<h2><a id="section-60"></a>{{ $t('scopes.title') }}</h2>
<ul>
<li v-for="s in scopes">
<input type="checkbox" v-model="checkedScopes" :value="s" />
{{ s.name.fr }}
</li>
</ul>
<div v-if="!isScopeValid" class="alert alert-warning separator">
{{ $t('scopes.add_at_least_one') }}
</div>
</div>
</template>
<script>
import { mapState, mapGetters } from 'vuex';
export default {
name: "Scopes",
computed: {
...mapState([
'scopes',
'scopesAtStart'
]),
...mapGetters([
'isScopeValid'
]),
checkedScopes: {
get: function() {
return this.$store.state.accompanyingCourse.scopes;
},
set: function(v) {
this.$store.dispatch('setScopes', v);
}
}
}
}
</script>
<style scoped>
</style>

View File

@@ -1,6 +1,6 @@
<template>
<div class="vue-component">
<h2><a name="section-50"></a>{{ $t('social_issue.title') }}</h2>
<h2><a id="section-50"></a>{{ $t('social_issue.title') }}</h2>
<div class="my-4">
<!--label for="field">{{ $t('social_issue.label') }}</label
@@ -78,6 +78,7 @@ export default {
@import 'ChillMainAssets/module/bootstrap/shared';
@import 'ChillPersonAssets/chill/scss/mixins';
div#accompanying-course {
span.multiselect__tag {
@include badge_social_issue;
background: $chill-l-gray;
@@ -93,6 +94,7 @@ export default {
}
}
}
}
</style>

View File

@@ -62,42 +62,42 @@ export default {
// load datas DOM when mounted ready
this.container = document.querySelector("#content");
this.stickyNav = document.querySelector('#navmap');
this.anchors = document.querySelectorAll("h2 a[name^='section']");
this.initItemsMap();
this.anchors = document.querySelectorAll("h2 a[id^='section']");
this.initItemsMap();
// TODO resizeObserver not supports IE !
// Listen when elements change size, then recalculate heightSum and initItemsMap
const resizeObserver = new ResizeObserver(entries => {
this.refreshPos();
});
resizeObserver.observe(this.header);
resizeObserver.observe(this.bannerName);
resizeObserver.observe(this.bannerDetails);
resizeObserver.observe(this.container);
},
initItemsMap() {
this.anchors.forEach(anchor => {
this.items.push({
pos: null,
active: false,
key: parseInt(anchor.name.slice(8).slice(0, -1)),
name: '#' + anchor.name
key: parseInt(anchor.id.slice(8).slice(0, -1)),
id: '#' + anchor.id
})
});
},
refreshPos() {
//console.log('refreshPos');
this.heightSum = this.header.offsetHeight + this.bannerName.offsetHeight + this.bannerDetails.offsetHeight;
this.anchors.forEach((anchor, i) => {
this.items[i].pos = this.findPos(anchor)['y'];
});
},
findPos(element) {
let posX = 0, posY = 0;
do {
posX += element.offsetLeft;
@@ -105,38 +105,38 @@ export default {
element = element.offsetParent;
}
while( element != null );
let pos = [];
pos['x'] = posX;
pos['y'] = posY;
return pos;
},
handleScroll(event) {
let pos = this.findPos(this.stickyNav);
let top = this.heightSum + this.top - window.scrollY;
//console.log(window.scrollY);
if (top > this.limit) {
//console.log(window.scrollY);
if (top > this.limit) {
this.stickyNav.style.position = 'absolute';
this.stickyNav.style.left = '10px';
} else {
this.stickyNav.style.position = 'fixed';
this.stickyNav.style.left = pos['x'] + 'px';
}
this.switchActive();
},
switchActive() {
this.items.forEach((item, i) => {
let next = (this.items[i+1]) ? this.items[i+1].pos : '100000';
item.active =
item.active =
(window.scrollY >= item.pos & window.scrollY < next) ? true : false;
}, this);
// last item never switch active because scroll reach bottom of page
// last item never switch active because scroll reach bottom of page
if (document.body.scrollHeight == window.scrollY + window.innerHeight) {
this.items[this.items.length-1].active = true;
this.items[this.items.length-2].active = false;
@@ -151,7 +151,7 @@ export default {
<style lang="scss">
div#content {
position: relative;
div#navmap {
position: absolute;
top: 30px;
@@ -170,7 +170,7 @@ div#content {
span {
display: none;
}
&:hover,
&:hover,
&.active {
span {
display: inline;

View File

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

View File

@@ -42,6 +42,14 @@ const appMessages = {
enddate: "Date de sortie",
add_persons: "Ajouter des usagers",
date_start_to_end: "Participation du {start} au {end}",
leave_course: "L'usager quitte le parcours",
sure: "Êtes-vous sûr ?",
sure_description: "Une fois confirmé, il ne sera pas possible de faire marche arrière ! La sortie reste cependant consignée dans l'historique du parcours.",
ok: "Oui, l'usager quitte le parcours",
show_household_number: "Voir le ménage (n° {id})",
show_household: "Voir le ménage",
person_without_household_warning: "Certaines personnes n'appartiennent à aucun ménage actuellement. Renseignez leur appartenance à un ménage dès que possible.",
update_household: "Modifier l'appartenance",
},
requestor: {
title: "Demandeur",
@@ -78,6 +86,10 @@ const appMessages = {
person_locator: "Parcours localisé auprès de {0}",
no_address: "Il n'y a pas d'adresse associée au parcours"
},
scopes: {
title: "Services",
add_at_least_one: "Indiquez au moins un service",
},
referrer: {
title: "Référent du parcours",
label: "Vous pouvez choisir un TMS ou vous assigner directement comme référent",
@@ -105,6 +117,7 @@ const appMessages = {
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",
set_a_scope: "indiquez au moins un service",
sure: "Êtes-vous sûr ?",
sure_description: "Une fois le changement confirmé, il ne sera plus possible de le remettre à l'état de brouillon !",
ok: "Confirmer le parcours"

View File

@@ -1,28 +1,41 @@
import 'es6-promise/auto';
import { createStore } from 'vuex';
import { fetchScopes } from 'ChillMainAssets/lib/api/scope.js';
import { getAccompanyingCourse,
patchAccompanyingCourse,
confirmAccompanyingCourse,
postParticipation,
postRequestor,
postResource,
postSocialIssue } from '../api';
postSocialIssue,
addScope,
removeScope,
} from '../api';
const debug = process.env.NODE_ENV !== 'production';
const id = window.accompanyingCourseId;
let initPromise = getAccompanyingCourse(id)
.then(accompanying_course => new Promise((resolve, reject) => {
let scopesPromise = fetchScopes();
let accompanyingCoursePromise = getAccompanyingCourse(id);
let initPromise = Promise.all([scopesPromise, accompanyingCoursePromise])
.then(([scopes, accompanyingCourse]) => new Promise((resolve, reject) => {
const store = createStore({
strict: debug,
modules: {
},
state: {
accompanyingCourse: accompanying_course,
accompanyingCourse: accompanyingCourse,
addressContext: {},
errorMsg: []
errorMsg: [],
// all the available scopes
scopes: scopes,
// the scopes at start. If the user remove all scopes, we re-add those scopes, by security
scopesAtStart: accompanyingCourse.scopes.map(scope => scope),
// the scope states at server side
scopesAtBackend: accompanyingCourse.scopes.map(scope => scope),
},
getters: {
isParticipationValid(state) {
@@ -34,11 +47,16 @@ let initPromise = getAccompanyingCourse(id)
isLocationValid(state) {
return state.accompanyingCourse.location !== null;
},
isScopeValid(state) {
console.log('is scope valid', state.accompanyingCourse.scopes.length > 0);
return state.accompanyingCourse.scopes.length > 0;
},
validationKeys(state, getters) {
let keys = [];
if (!getters.isParticipationValid) { keys.push('participation'); }
if (!getters.isLocationValid) { keys.push('location'); }
if (!getters.isSocialIssueValid) { keys.push('socialIssue'); }
if (!getters.isScopeValid) { keys.push('scopes'); }
//console.log('getter keys', keys);
return keys;
},
@@ -129,14 +147,34 @@ let initPromise = getAccompanyingCourse(id)
state.addressContext = context;
},
updateLocation(state, r) {
//console.log('### mutation: set location attributes', r);
state.accompanyingCourse.location = r.location;
//console.log('### mutation: set location attributes', r);
state.accompanyingCourse.locationStatus = r.locationStatus;
if (r.locationStatus !== 'person') {
state.addressContext.addressId = r.location.address_id;
//console.log('mutation: update context addressId', state.addressContext.addressId);
}
state.accompanyingCourse.location = r.location;
state.accompanyingCourse.personLocation = r.personLocation;
},
setEditContextTrue(state) {
//console.log('### mutation: set edit context = true');
setEditContextTrue(state, payload) {
//console.log('### mutation: set edit context true with addressId', payload.addressId);
state.addressContext.edit = true;
state.addressContext.addressId = payload.addressId;
},
setScopes(state, scopes) {
state.accompanyingCourse.scopes = scopes;
},
addScopeAtBackend(state, scope) {
let scopeIds = state.scopesAtBackend.map(s => s.id);
if (!scopeIds.includes(scope.id)) {
state.scopesAtBackend.push(scope);
}
},
removeScopeAtBackend(state, scope){
let scopeIds = state.scopesAtBackend.map(s => s.id);
if (scopeIds.includes(scope.id)) {
state.scopesAtBackend = state.scopesAtBackend.filter(s => s.id !== scope.id);
}
}
},
actions: {
@@ -223,6 +261,107 @@ let initPromise = getAccompanyingCourse(id)
resolve();
})).catch((error) => { commit('catchError', error) });
},
/**
* Handle the checked/unchecked scopes
*
* When the user set the scopes in a invalid situation (when no scopes are cheched), this
* method will internally re-add the scopes as they were originally when the page was loaded, but
* this does not appears for the user (they remains unchecked). When the user re-add a scope, the
* scope is back in a valid state, and the store synchronize with the new state (all the original scopes
* are removed if necessary, and the new checked scopes is backed).
*
* So, for instance:
*
* at load:
*
* [x] scope A (at backend: [x])
* [x] scope B (at backend: [x])
* [ ] scope C (at backend: [ ])
*
* The user uncheck scope A:
*
* [ ] scope A (at backend: [ ] as soon as the operation finish)
* [x] scope B (at backend: [x])
* [ ] scope C (at backend: [ ])
*
* The user uncheck scope B. The state is invalid (no scope checked), so we go back to initial state when
* the page loaded):
*
* [ ] scope A (at backend: [x] as soon as the operation finish)
* [ ] scope B (at backend: [x] as soon as the operation finish)
* [ ] scope C (at backend: [ ])
*
* The user check scope C. The scopes are back to valid state. So we go back to synchronization with UI and
* backend):
*
* [ ] scope A (at backend: [ ] as soon as the operation finish)
* [ ] scope B (at backend: [ ] as soon as the operation finish)
* [x] scope C (at backend: [x] as soon as the operation finish)
*
* **Warning** There is a problem if the user check/uncheck faster than the backend is synchronized.
*
* @param commit
* @param state
* @param dispatch
* @param scopes
* @returns Promise
*/
setScopes({ commit, state, dispatch }, scopes) {
let currentServerScopesIds = state.scopesAtBackend.map(scope => scope.id);
let checkedScopesIds = scopes.map(scope => scope.id);
let removedScopesIds = currentServerScopesIds.filter(id => !checkedScopesIds.includes(id));
let addedScopesIds = checkedScopesIds.filter(id => !currentServerScopesIds.includes(id));
let lengthAfterOperation = currentServerScopesIds.length + addedScopesIds.length
- removedScopesIds.length;
if (lengthAfterOperation > 0 || (lengthAfterOperation === 0 && state.scopesAtStart.length === 0) ) {
return dispatch('updateScopes', {
addedScopesIds, removedScopesIds
}).then(() => {
// warning: when the operation of dispatch are too slow, the user may check / uncheck before
// the end of the synchronisation with the server (done by dispatch operation). Then, it leads to
// check/uncheck in the UI. I do not know of to avoid it.
commit('setScopes', scopes);
return Promise.resolve();
});
} else {
return dispatch('setScopes', state.scopesAtStart).then(() => {
commit('setScopes', scopes);
return Promise.resolve();
});
}
},
/**
* Internal function for the store to effectively update scopes.
*
* Return a promise which resolves when all update operation are
* successful and finished.
*
* @param state
* @param commit
* @param addedScopesIds
* @param removedScopesIds
* @return Promise
*/
updateScopes({ state, commit }, { addedScopesIds, removedScopesIds }) {
let promises = [];
state.scopes.forEach(scope => {
if (addedScopesIds.includes(scope.id)) {
promises.push(addScope(state.accompanyingCourse.id, scope).then(() => {
commit('addScopeAtBackend', scope);
return Promise.resolve();
}));
}
if (removedScopesIds.includes(scope.id)) {
promises.push(removeScope(state.accompanyingCourse.id, scope).then(() => {
commit('removeScopeAtBackend', scope);
return Promise.resolve();
}));
}
});
return Promise.all(promises);
},
postFirstComment({ commit }, payload) {
//console.log('## action: postFirstComment: payload', payload);
patchAccompanyingCourse(id, { type: "accompanying_period", initialComment: payload })
@@ -260,8 +399,8 @@ let initPromise = getAccompanyingCourse(id)
})).catch((error) => { commit('catchError', error) });
},
updateLocation({ commit }, payload) {
//console.log('## action: updateLocation', payload.locationStatusTo);
let body = { 'type': payload.entity, 'id': payload.entityId };
//console.log('## action: updateLocation', payload.locationStatusTo);
let body = { 'type': payload.target, 'id': payload.targetId };
let location = {};
if (payload.locationStatusTo === 'person') { // patch for person address (don't remove addressLocation)
location = { 'personLocation': { 'type': 'person', 'id': payload.personId }};
@@ -273,7 +412,7 @@ let initPromise = getAccompanyingCourse(id)
location = { 'personLocation': null };
}
Object.assign(body, location);
patchAccompanyingCourse(payload.entityId, body)
patchAccompanyingCourse(payload.targetId, body)
.then(accompanyingCourse => new Promise((resolve, reject) => {
commit('updateLocation', {
location: accompanyingCourse.location,

View File

@@ -35,7 +35,7 @@
<ul>
<li v-for="p in personsReachables" :key="p.id">
<input type="checkbox" :value="p.id" v-model="personsPicked">
<person :person="p"></person>
<person-render-box render="badge" :options="{}" :person="p"></person-render-box>
</li>
</ul>
</div>
@@ -124,7 +124,7 @@
import { mapState, mapActions, mapGetters } from 'vuex';
import VueMultiselect from 'vue-multiselect';
import { dateToISO, ISOToDate } from 'ChillMainAssets/chill/js/date.js';
import Person from 'ChillPersonAssets/vuejs/_components/Person/Person.vue';
import PersonRenderBox from 'ChillPersonAssets/vuejs/_components/Entity/PersonRenderBox.vue';
const i18n = {
messages: {
@@ -145,7 +145,7 @@ export default {
name: 'App',
components: {
VueMultiselect,
Person,
PersonRenderBox,
},
methods: {
submit() {

View File

@@ -122,7 +122,7 @@
<ul>
<li v-for="p in personsReachables" :key="p.id">
<input v-model="personsPicked" :value="p.id" type="checkbox">
<person :person="p"></person>
<person-render-box render="badge" :options="{}" :person="p"></person-render-box>
</li>
</ul>
</div>
@@ -150,7 +150,7 @@
</div>
<div v-else>
<p>{{ handlingThirdParty.text }}</p>
<show-address :address="handlingThirdParty.address"></show-address>
<address-render-box :address="handlingThirdParty.address"></address-render-box>
<ul class="record_actions">
<li>
@@ -173,7 +173,7 @@
<ul>
<li v-for="t in thirdParties">
<p>{{ t.text }}</p>
<show-address :address="t.address"></show-address>
<address-render-box :address="t.address"></address-render-box>
<ul class="record_actions">
<button :title="$t('remove_thirdparty')" class="btn btn-remove"
@@ -229,9 +229,9 @@ import CKEditor from '@ckeditor/ckeditor5-vue';
import ClassicEditor from 'ChillMainAssets/module/ckeditor5/index.js';
import AddResult from './components/AddResult.vue';
import AddEvaluation from './components/AddEvaluation.vue';
import Person from 'ChillPersonAssets/vuejs/_components/Person/Person.vue';
import PersonRenderBox from 'ChillPersonAssets/vuejs/_components/Entity/PersonRenderBox.vue';
import AddPersons from 'ChillPersonAssets/vuejs/_components/AddPersons.vue';
import ShowAddress from 'ChillMainAssets/vuejs/Address/components/ShowAddress.vue';
import AddressRenderBox from 'ChillMainAssets/vuejs/_components/Entity/AddressRenderBox.vue';
const i18n = {
messages: {
@@ -274,8 +274,8 @@ export default {
AddResult,
AddEvaluation,
AddPersons,
Person,
ShowAddress,
PersonRenderBox,
AddressRenderBox,
},
i18n,
data() {

View File

@@ -1,21 +0,0 @@
import { addressMessages } from 'ChillMainAssets/vuejs/Address/i18n'
const appMessages = {
fr: {
select_a_existing_address: 'Sélectionner une adresse existante',
create_a_new_address: 'Créer une nouvelle adresse',
add_an_address_to_household: 'Enregistrer',
validFrom: 'Date du déménagement',
move_date: 'Date du déménagement',
back_to_the_list: 'Retour à la liste',
household_address_move_success: 'La nouvelle adresse du ménage est enregistrée',
household_address_edit_success: 'L\'adresse du ménage a été mise à jour',
loading: 'chargement en cours...'
}
};
Object.assign(appMessages.fr, addressMessages.fr);
export {
appMessages
};

View File

@@ -1,5 +1,5 @@
<template>
<h2>{{ $t('household_members_editor.concerned.title') }}</h2>
<h2 class="mt-4">{{ $t('household_members_editor.concerned.title') }}</h2>
<h3 v-if="needsPositionning">
{{ $t('household_members_editor.concerned.persons_to_positionnate') }}
@@ -25,7 +25,7 @@
<div class="item-row">
<div class="item-col">
<div>
<person :person="conc.person"></person>
<person-render-box render="badge" :options="{}" :person="conc.person"></person-render-box>
</div>
<div v-if="conc.person.birthdate !== null">
{{ $t('person.born', {'gender': conc.person.gender} ) }}
@@ -126,7 +126,7 @@ div.person {
<script>
import { mapGetters } from 'vuex';
import AddPersons from 'ChillPersonAssets/vuejs/_components/AddPersons.vue';
import Person from 'ChillPersonAssets/vuejs/_components/Person/Person.vue';
import PersonRenderBox from 'ChillPersonAssets/vuejs/_components/Entity/PersonRenderBox.vue';
import MemberDetails from './MemberDetails.vue';
import { ISOToDatetime } from 'ChillMainAssets/chill/js/date.js';
@@ -135,7 +135,7 @@ export default {
components: {
AddPersons,
MemberDetails,
Person,
PersonRenderBox,
},
computed: {
...mapGetters([

View File

@@ -1,24 +1,71 @@
<template>
<h2>{{ $t('household_members_editor.household_part') }}</h2>
<h2 class="mt-4">{{ $t('household_members_editor.household_part') }}</h2>
<div v-if="hasHousehold">
<div>
<household-viewer :household="household"></household-viewer>
<div class="flex-table">
<div class="item-bloc">
<household-render-box :household="household" :isAddressMultiline="true"></household-render-box>
</div>
</div>
<div v-if="isHouseholdNew && !hasHouseholdAddress">
<h3 >À quelle adresse habite ce ménage ?</h3>
<div v-if="filterAddressesSuggestion.length > 0" class="flex-table householdAddressSuggestionList">
<div v-for="a in filterAddressesSuggestion" class="item-bloc">
<show-address :address="a"></show-address>
<button class="btn btn-action" @click="setHouseholdAddress(a)">
Le ménage habite cette adresse
</button>
</div>
</div>
<div v-else>
<span class="chill-no-data-statement">Aucune adresse à suggérer</span>
<div v-if="hasAddressSuggestion" class="householdAddressSuggestion my-5">
<h4 class="mb-3">
{{ $t('household_members_editor.household.where_live_the_household') }}
</h4>
<div class="accordion" id="addressSuggestions">
<div class="accordion-item">
<h2 class="accordion-header" id="heading_address_suggestions">
<button v-if="!showAddressSuggestion"
class="accordion-button collapsed"
type="button"
data-bs-toggle="collapse"
aria-expanded="false"
@click="toggleAddressSuggestion">
{{ $tc('household_members_editor.show_household_suggestion', countAddressSuggestion) }}
</button>
<button v-if="showAddressSuggestion"
class="accordion-button"
type="button"
data-bs-toggle="collapse"
aria-expanded="true"
@click="toggleAddressSuggestion">
{{ $t('household_members_editor.hide_household_suggestion') }}
</button>
</h2>
<div class="accordion-collapse" id="collapse_address_suggestions"
aria-labelledby="heading_address_suggestions" data-bs-parent="#addressSuggestions">
<div v-if="showAddressSuggestion">
<div class="flex-table householdAddressSuggestionList">
<div v-for="a in filterAddressesSuggestion" class="item-bloc">
<div class="float-button bottom">
<div class="box">
<div class="action">
<ul class="record_actions">
<li>
<button class="btn btn-sm btn-choose" @click="setHouseholdAddress(a)">
{{ $t('household_members_editor.household.household_live_to_this_address') }}
</button>
</li>
</ul>
</div>
<ul class="list-content fa-ul">
<li>
<i class="fa fa-li fa-map-marker"></i>
<address-render-box :address="a"></address-render-box>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<ul class="record_actions">
@@ -28,49 +75,30 @@
:key="addAddress.key"
:options="addAddress.options"
:result="addAddress.result"
@submitAddress="setHouseholdCreatedAddress"
@addressChangedCallback="setHouseholdCreatedAddress"
ref="addAddress">
</add-address>
</li>
</ul>
</div>
<div v-if="isHouseholdNew && hasHouseholdAddress">
<ul class="record_actions">
<li >
<button class="btn btn-misc" @click="removeHouseholdAddress">
Supprimer cette adresse
{{ $t('household_members_editor.household.delete_this_address') }}
</button>
</li>
</ul>
</div>
</div>
<div v-else-if="isForceLeaveWithoutHousehold">
{{ $t('household_members_editor.household.will_leave_any_household') }}
</div>
<div v-else>
<div class="alert alert-info">{{ $t('household_members_editor.household.no_household_choose_one') }}</div>
</div>
<div v-else class="alert alert-info">{{ $t('household_members_editor.household.no_household_choose_one') }}</div>
<ul v-if="allowChangeHousehold" class="record_actions">
<li v-if="!showHouseholdSuggestion">
<button
class="btn btn-misc"
@click="toggleHouseholdSuggestion"
>
{{ $tc('household_members_editor.show_household_suggestion',
countHouseholdSuggestion) }}
</button>
</li>
<li v-if="showHouseholdSuggestion && hasHouseholdSuggestion">
<button
class="btn btn-misc"
@click="toggleHouseholdSuggestion"
>
{{ $t('household_members_editor.hide_household_suggestion') }}
</button>
</li>
<li v-if="allowHouseholdCreate">
<button class="btn btn-create" @click="createHousehold">
{{ $t('household_members_editor.household.create_household') }}
@@ -93,85 +121,73 @@
</li>
</ul>
<div class="householdSuggestions">
<div v-if="showHouseholdSuggestion && hasHouseholdSuggestion">
<p>{{ $t('household_members_editor.household_for_participants_accompanying_period') }}:</p>
<div class="householdSuggestionList">
<div
v-for="h in filterHouseholdSuggestionByAccompanyingPeriod"
class="item"
>
<household-viewer :household="h"></household-viewer>
<ul class="record_actions">
<li>
<button class="btn btn-misc" @click="selectHousehold(h)">
{{ $t('household_members_editor.select_household') }}
</button>
</li>
</ul>
</div >
<div v-if="hasHouseholdSuggestion" class="householdSuggestions my-5">
<h4 class="mb-3">
{{ $t('household_members_editor.household_for_participants_accompanying_period') }} :
</h4>
<div class="accordion" id="householdSuggestions">
<div class="accordion-item">
<h2 class="accordion-header" id="heading_household_suggestions">
<button v-if="!showHouseholdSuggestion"
class="accordion-button collapsed"
type="button"
data-bs-toggle="collapse"
aria-expanded="false"
@click="toggleHouseholdSuggestion">
{{ $tc('household_members_editor.show_household_suggestion', countHouseholdSuggestion) }}
</button>
<button v-if="showHouseholdSuggestion"
class="accordion-button"
type="button"
data-bs-toggle="collapse"
aria-expanded="true"
@click="toggleHouseholdSuggestion">
{{ $t('household_members_editor.hide_household_suggestion') }}
</button>
<!-- disabled bootstrap behaviour: data-bs-target="#collapse_household_suggestions" aria-controls="collapse_household_suggestions" -->
</h2>
<div class="accordion-collapse" id="collapse_household_suggestions"
aria-labelledby="heading_household_suggestions" data-bs-parent="#householdSuggestions">
<div v-if="showHouseholdSuggestion">
<div class="flex-table householdSuggestionList">
<div v-for="h in filterHouseholdSuggestionByAccompanyingPeriod" class="item-bloc">
<household-render-box :household="h"></household-render-box>
<ul class="record_actions">
<li>
<button class="btn btn-sm btn-choose" @click="selectHousehold(h)">
{{ $t('household_members_editor.select_household') }}
</button>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<style lang="scss">
div.householdAddressSuggestionList {
/*
display: flex;
list-style-type: none;
padding: 0;
*/
& > li {
}
}
.householdSuggestionList {
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: space-between;
& > .item {
margin-bottom: 0.8rem;
width: calc(50% - 1rem);
border: 1px solid var(--chill-light-gray);
padding: 0.5rem 0.5rem 0 0.5rem;
ul.record_actions {
margin-bottom: 0;
}
}
}
</style>
<script>
import { mapGetters, mapState } from 'vuex';
import HouseholdViewer from 'ChillPersonAssets/vuejs/_components/Household/Household.vue';
import ShowAddress from 'ChillMainAssets/vuejs/Address/components/ShowAddress.vue';
import HouseholdRenderBox from 'ChillPersonAssets/vuejs/_components/Entity/HouseholdRenderBox.vue';
import AddressRenderBox from 'ChillMainAssets/vuejs/_components/Entity/AddressRenderBox.vue';
import AddAddress from 'ChillMainAssets/vuejs/Address/components/AddAddress.vue';
export default {
name: 'Household',
components: {
HouseholdViewer,
ShowAddress,
HouseholdRenderBox,
AddressRenderBox,
AddAddress,
},
data() {
return {
addAddress: {
context: {
entity: {
type: 'household_create',
target: {
name: 'household_create',
id: 0
},
edit: false,
@@ -179,18 +195,17 @@ export default {
},
key: 'household_new',
options: {
hideDateFrom: true,
bindModal: {
useDate: {
validFrom: true
},
button: {
text: {
create: null,
create: 'household_members_editor.household.or_create_new_address',
edit: null,
}
},
title: {
create: null,
create: 'household_members_editor.household.create_new_address',
edit: null,
},
}
@@ -204,11 +219,14 @@ export default {
'hasHouseholdSuggestion',
'countHouseholdSuggestion',
'filterHouseholdSuggestionByAccompanyingPeriod',
'hasAddressSuggestion',
'countAddressSuggestion',
'filterAddressesSuggestion',
'hasHouseholdAddress',
]),
...mapState([
'showHouseholdSuggestion',
'showAddressSuggestion'
]),
household() {
return this.$store.state.household;
@@ -249,8 +267,12 @@ export default {
toggleHouseholdSuggestion() {
this.$store.commit('toggleHouseholdSuggestion');
},
toggleAddressSuggestion() {
this.$store.commit('toggleAddressSuggestion');
},
selectHousehold(h) {
this.$store.dispatch('selectHousehold', h);
this.toggleHouseholdSuggestion();
},
removeHousehold() {
this.$store.dispatch('removeHousehold');
@@ -260,15 +282,56 @@ export default {
console.log('setHouseholdAddress', a);
this.$store.commit('setHouseholdAddress', a);
},
setHouseholdCreatedAddress() {
let payload = this.$refs.addAddress.submitNewAddress();
setHouseholdCreatedAddress(payload) {
console.log('setHouseholdAddress', payload);
this.$store.dispatch('setHouseholdNewAddress', payload);
},
removeHouseholdAddress() {
this.$store.commit('removeHouseholdAddress');
}
},
},
};
</script>
<style lang="scss">
div#household_members_editor div,
div.householdSuggestionList {
&.flex-table {
margin: 0;
div.item-bloc div.item-row div.item-col {
&:first-child {
width: 25%;
}
&:last-child {
display: initial;
}
}
}
}
/*
div.householdAddressSuggestionList {
display: flex;
list-style-type: none;
padding: 0;
& > li {}
}
.householdSuggestionList {
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: space-between;
& > .item {
margin-bottom: 0.8rem;
width: calc(50% - 1rem);
border: 1px solid var(--chill-light-gray);
padding: 0.5rem 0.5rem 0 0.5rem;
ul.record_actions {
margin-bottom: 0;
}
}
}
*/
</style>

View File

@@ -3,7 +3,7 @@
<div class="item-row">
<div class="item-col">
<div>
<person :person="conc.person"></person>
<person-render-box render="badge" :options="{}" :person="conc.person"></person-render-box>
<span v-if="isHolder" class="badge bg-primary holder">
{{ $t('household_members_editor.holder') }}
</span>
@@ -73,14 +73,14 @@ div.participation-details {
<script>
import { mapGetters } from 'vuex';
import Person from 'ChillPersonAssets/vuejs/_components/Person/Person.vue';
import PersonRenderBox from 'ChillPersonAssets/vuejs/_components/Entity/PersonRenderBox.vue';
import CKEditor from '@ckeditor/ckeditor5-vue';
import ClassicEditor from 'ChillMainAssets/module/ckeditor5/index.js';
export default {
name: 'MemberDetails',
components: {
Person,
PersonRenderBox,
ckeditor: CKEditor.component,
},
props: [

View File

@@ -7,10 +7,16 @@ const appMessages = {
household: {
no_household_choose_one: "Aucun ménage de destination. Choisissez un ménage. Les usagers concernés par la modification apparaitront ensuite.",
new_household: "Nouveau ménage",
create_household: "Créer un ménage",
create_household: "Créer un nouveau ménage de destination",
search_household: "Chercher un ménage",
will_leave_any_household: "Ne rejoignent pas de ménage",
leave_without_household: "Sans nouveau ménage"
leave_without_household: "Sans nouveau ménage",
where_live_the_household: "À quelle adresse habite ce ménage ?",
household_live_to_this_address: "Sélectionner l'adresse",
no_suggestions: "Aucune adresse à suggérer",
delete_this_address: "Supprimer cette adresse",
create_new_address: "Créer une nouvelle adresse",
or_create_new_address: "Ou créer une nouvelle adresse",
},
concerned: {
title: "Nouveaux membres du ménage",
@@ -29,10 +35,11 @@ const appMessages = {
remove_position: "Retirer des {position}",
remove_concerned: "Ne plus transférer",
household_part: "Ménage de destination",
suggestions: "Suggestions",
hide_household_suggestion: "Masquer les suggestions",
show_household_suggestion: 'Aucune suggestion | Afficher une suggestion | Afficher {count} suggestions',
household_for_participants_accompanying_period: "Ces ménages partagent le même parcours",
select_household: "Choisir ce ménage",
household_for_participants_accompanying_period: "Des ménages partagent le même parcours",
select_household: "Sélectionner le ménage",
dates_title: "Période de validité",
dates: {
start_date: "Début de validité",

View File

@@ -36,6 +36,7 @@ const store = createStore({
householdSuggestionByAccompanyingPeriod: [],
showHouseholdSuggestion: window.household_members_editor_expand_suggestions === 1,
addressesSuggestion: [],
showAddressSuggestion: true,
warnings: [],
errors: []
},
@@ -73,6 +74,12 @@ const store = createStore({
.filter(h => h.id !== state.household.id)
;
},
hasAddressSuggestion(state, getters) {
return getters.filterAddressesSuggestion.length > 0;
},
countAddressSuggestion(state, getters) {
return getters.filterAddressesSuggestion.length;
},
filterAddressesSuggestion(state) {
if (state.household === null) {
return state.addressesSuggestion;
@@ -260,6 +267,9 @@ const store = createStore({
toggleHouseholdSuggestion(state) {
state.showHouseholdSuggestion = !state.showHouseholdSuggestion;
},
toggleAddressSuggestion(state) {
state.showAddressSuggestion = !state.showAddressSuggestion;
},
setWarnings(state, warnings) {
state.warnings = warnings;
// reset errors, which should come from servers
@@ -327,7 +337,7 @@ const store = createStore({
commit('forceLeaveWithoutHousehold');
dispatch('computeWarnings');
},
selectHousehold({ commit }, h) {
selectHousehold({ commit, dispatch }, h) {
commit('selectHousehold', h);
dispatch('computeWarnings');
},

View File

@@ -1,48 +0,0 @@
// CURRENTLY NOT IN USE
<template>
<li v-if="address" class="chill-entity entity-address">
<i v-if="options.with_picto == true" class="fa fa-fw fa-map-marker"></i>
<span v-if="options.render == 'list' || options.render == 'list'" :class="'address ' + {'multiline' : options.multiline === true}">
<!-- if address.street is not empty -->
<p v-if="address.street" class="street">{{ address.street }}
<!-- if address.streetNumber is not empty -->
<span v-if="address.streetNumber" class="streetnumber">{{ address.streetNumber }}</span>
</p>
<!-- if options['extended_infos'] -->
<div v-if="options.extended_infos == true">
<span v-if="address.floor" class="floor">{{ address.floor }}</span>
<span v-if="address.corridor" class="corridor">{{ address.corridor }}</span>
<span v-if="address.steps" class="steps">{{ address.steps }}</span>
<span v-if="address.buildingName" class="buildingName">{{ address.buildingName }}</span>
<span v-if="address.flat" class="flat">{{ address.flat }}</span>
<span v-if="address.distribution" class="distribution">{{ address.distribution }}</span>
<span v-if="address.extra" class="extra">{{ address.extra }}</span>
</div>
<!-- if address.postCode is not empty -->
<div v-if="address.postCode">
<p class="postcode">
<span class="code">{{ address.postCode.code }}</span>
<span class="name">{{ address.postCode.name }}</span>
</p>
<p class="country">{{ address.postCode.country.name }}</p>
</div>
</span>
</li>
</template>
<script>
export default{
name: "AddressRenderBox",
props: ['address', 'options']
}
</script>

View File

@@ -0,0 +1,126 @@
<template>
<section class="chill-entity entity-household">
<div class="item-row">
<div class="item-col">
<!-- identifier -->
<div v-if="isHouseholdNew()" class="h4">
<i class="fa fa-home"></i>
{{ $t('new_household') }}
</div>
<div v-else class="h4">
<i class="fa fa-home"></i>
{{ $t('household_number', { number: household.id } ) }}
</div>
</div>
<div class="item-col">
<ul class="list-content">
<!-- member part -->
<li v-if="hasCurrentMembers" class="members" :title="$t('current_members')">
<template v-for="m in currentMembers()" :key="m.id">
<person-render-box render="badge"
:person="m.person"
:options="{
isHolder: m.holder,
addLink: true
}">
</person-render-box>
</template>
</li>
<li v-else class="members" :title="$t('current_members')">
<p class="chill-no-data-statement">{{ $t('no_members_yet') }}</p>
</li>
<!-- address part -->
<li v-if="hasAddress()">
<address-render-box :address="household.current_address" :isMultiline="isMultiline"></address-render-box>
</li>
<li v-else>
<span class="chill-no-data-statement">{{ $t('no_current_address') }}</span>
</li>
</ul>
</div>
</div>
</section>
</template>
<script>
import PersonRenderBox from 'ChillPersonAssets/vuejs/_components/Entity/PersonRenderBox.vue';
import AddressRenderBox from 'ChillMainAssets/vuejs/_components/Entity/AddressRenderBox.vue';
const i18n = {
"messages": {
"fr": {
"household_number": "Ménage n°{number}",
"current_members": "Membres actuels",
"no_current_address": "Sans adresse actuellement",
"new_household": "Nouveau ménage",
"no_members_yet": "Aucun membre actuellement",
"holder": "titulaire",
}
}
};
export default {
name: 'HouseholdRenderBox',
props: ['household', 'isAddressMultiline'],
components: {
PersonRenderBox,
AddressRenderBox,
},
i18n,
computed: {
isMultiline() {
return (typeof this.isAddressMultiline !== 'undefined') ? this.isAddressMultiline : false;
}
},
methods: {
hasCurrentMembers() {
return this.household.current_members_id.length > 0;
},
currentMembers() {
return this.household.members.filter(m => this.household.current_members_id.includes(m.id))
.sort((a, b) => {
if (a.position.ordering < b.position.ordering) {
return -1;
}
if (a.position.ordering > b.position.ordering) {
return 1;
}
if (a.holder && !b.holder) {
return -1;
}
if (!a.holder && b.holder) {
return 1;
}
return 0;
});
},
currentMembersLength() {
return this.household.current_members_id.length;
},
isHouseholdNew() {
return !Number.isInteger(this.household.id);
},
hasAddress() {
return this.household.current_address !== null;
}
}
};
</script>
<style lang="scss">
section.chill-entity {
&.entity-household {
ul.list-content li::marker {
content: '';
}
}
}
</style>

View File

@@ -1,14 +1,14 @@
<template>
<div class="item-bloc">
<div v-if="render === 'bloc'" class="item-bloc">
<section class="chill-entity entity-person">
<div class="item-row entity-bloc">
<div class="item-row entity-bloc">
<div class="item-col">
<div class="entity-label">
<div :class="'denomination h' + options.hLevel">
<a v-if="this.options.addLink == true" href="#">
<a v-if="options.addLink === true" :href="getUrl">
<span class="firstname">{{ person.firstName }}</span>
<span class="lastname">{{ person.lastName }}</span>
<span v-if="person.altNames && options.addAltNames == true" class="altnames">
@@ -27,80 +27,121 @@
</div>
<p v-if="this.options.addInfo == true" class="moreinfo">
<p v-if="options.addInfo == true" class="moreinfo">
<i :class="'fa fa-fw ' + getGenderIcon" title="{{ getGender }}"></i>
<time v-if="person.birthdate" datetime="{{ person.birthdate }}" title="{{ birthdate }}">
{{ $t(getGender) + ' ' + $d(birthdate, 'text') }}
<time v-if="person.birthdate && !person.deathdate" datetime="{{ person.birthdate }}" title="{{ birthdate }}">
{{ $t(getGenderTranslation) + ' ' + $d(birthdate, 'text') }}
</time>
<time v-else-if="person.deathdate" datetime="{{ person.deathdate }}" title="{{ person.deathdate }}">
<time v-else-if="person.birthdate && person.deathdate" datetime="{{ person.deathdate }}" title="{{ person.deathdate }}">
{{ birthdate }} - {{ deathdate }}
</time>
<!-- <span class="age">{{ person.age }}</span> -->
<time v-else-if="person.deathdate" datetime="{{ person.deathdate }}" title="{{ person.deathdate }}">
{{ $t('renderbox.deathdate') + ' ' + deathdate }}
</time>
<span v-if="options.addAge && person.birthdate" class="age">{{ getAge }} {{ $t('renderbox.years_old')}}</span>
</p>
</div>
</div>
<div class="item-col">
<ul class="list-content fa-ul">
<div class="float-button bottom">
<div class="box">
<div class="action">
<slot name="record-actions"></slot>
</div>
<ul class="list-content fa-ul">
<li v-if="person.current_household_address">
<i class="fa fa-li fa-map-marker"></i>
<show-address :address="person.current_household_address" :isMultiline="isMultiline"></show-address>
</li>
<li v-else-if="options.addNoData">
<i class="fa fa-li fa-map-marker"></i>
<p class="chill-no-data-statement">{{ $t('renderbox.no_data') }}</p>
</li>
<li v-if="person.current_household_id">
<i class="fa fa-li fa-map-marker"></i>
<address-render-box v-if="person.current_household_address"
:address="person.current_household_address"
:isMultiline="isMultiline">
</address-render-box>
<p v-else class="chill-no-data-statement">
{{ $t('renderbox.household_without_address') }}
</p>
<a v-if="options.addHouseholdLink === true"
:href="getCurrentHouseholdUrl"
:title="$t('persons_associated.show_household_number', {id: person.current_household_id})">
<span class="badge rounded-pill bg-chill-beige">
<i class="fa fa-fw fa-home"></i><!--{{ $t('persons_associated.show_household') }}-->
</span>
</a>
</li>
<li v-else-if="options.addNoData">
<i class="fa fa-li fa-map-marker"></i>
<p class="chill-no-data-statement">
{{ $t('renderbox.no_data') }}
</p>
</li>
<li v-if="person.mobilenumber">
<i class="fa fa-li fa-mobile"></i>
<a :href="'tel: ' + person.mobilenumber">{{ person.mobilenumber }}</a>
</li>
<li v-else-if="options.addNoData">
<i class="fa fa-li fa-mobile"></i>
<p class="chill-no-data-statement">{{ $t('renderbox.no_data') }}</p>
</li>
<li v-if="person.phonenumber">
<i class="fa fa-li fa-phone"></i>
<a :href="'tel: ' + person.phonenumber">{{ person.phonenumber }}</a>
</li>
<li v-else-if="options.addNoData">
<i class="fa fa-li fa-phone"></i>
<p class="chill-no-data-statement">{{ $t('renderbox.no_data') }}</p>
</li>
<li v-if="person.mobilenumber">
<i class="fa fa-li fa-mobile"></i>
<a :href="'tel: ' + person.mobilenumber">{{ person.mobilenumber }}</a>
</li>
<li v-else-if="options.addNoData">
<i class="fa fa-li fa-mobile"></i>
<p class="chill-no-data-statement">{{ $t('renderbox.no_data') }}</p>
</li>
<li v-if="person.phonenumber">
<i class="fa fa-li fa-phone"></i>
<a :href="'tel: ' + person.phonenumber">{{ person.phonenumber }}</a>
</li>
<li v-else-if="options.addNoData">
<i class="fa fa-li fa-phone"></i>
<p class="chill-no-data-statement">{{ $t('renderbox.no_data') }}</p>
</li>
<li v-if="person.center && options.addCenter">
<i class="fa fa-li fa-long-arrow-right"></i>
{{ person.center.name }}
</li>
<li v-else-if="options.addNoData">
<i class="fa fa-li fa-long-arrow-right"></i>
<p class="chill-no-data-statement">{{ $t('renderbox.no_data') }}</p>
</li>
<slot name="custom-zone"></slot>
<li v-if="person.center && options.addCenter">
<i class="fa fa-li fa-long-arrow-right"></i>
{{ person.center.name }}
</li>
<li v-else-if="options.addNoData">
<i class="fa fa-li fa-long-arrow-right"></i>
<p class="chill-no-data-statement">{{ $t('renderbox.no_data') }}</p>
</li>
<slot name="custom-zone"></slot>
</ul>
<slot name="record-actions"></slot>
</ul>
</div>
</div>
</div>
</div>
</div>
</section>
</div>
</div>
<span v-if="render === 'badge'" class="chill-entity entity-person badge-person">
<a v-if="options.addLink === true" :href="getUrl">
<span v-if="options.isHolder" class="fa-stack fa-holder" :title="$t('renderbox.holder')">
<i class="fa fa-circle fa-stack-1x text-success"></i>
<i class="fa fa-stack-1x">T</i>
</span>
{{ person.text }}
</a>
<span v-else>
<span v-if="options.isHolder" class="fa-stack fa-holder" :title="$t('renderbox.holder')">
<i class="fa fa-circle fa-stack-1x text-success"></i>
<i class="fa fa-stack-1x">T</i>
</span>
{{ person.text }}
</span>
</span>
</template>
<script>
import {dateToISO} from 'ChillMainAssets/chill/js/date.js';
import ShowAddress from 'ChillMainAssets/vuejs/Address/components/ShowAddress.vue';
import AddressRenderBox from 'ChillMainAssets/vuejs/_components/Entity/AddressRenderBox.vue';
export default {
name: "PersonRenderBox",
components: {
ShowAddress
AddressRenderBox
},
props: ['person', 'options'],
props: ['person', 'options', 'render', 'returnPath'],
computed: {
getGender: function() {
getGenderTranslation: function() {
return this.person.gender == 'woman' ? 'renderbox.birthday.woman' : 'renderbox.birthday.man';
},
isMultiline: function() {
@@ -114,23 +155,60 @@ export default {
return this.person.gender == 'woman' ? 'fa-venus' : this.person.gender == 'man' ? 'fa-mars' : 'fa-neuter';
},
birthdate: function(){
var date = new Date(this.person.birthdate.datetime);
return dateToISO(date);
if(this.person.birthdate !== null){
const date = new Date(this.person.birthdate.datetime);
return dateToISO(date)
} else {
return "";
}
},
deathdate: function(){
var date = new Date(this.person.deathdate.datetime);
return dateToISO(date);
// TODO FIX edition conflict: if null or undefined ?
// if (typeof this.person.deathdate !== 'undefined') {
// var date = new Date(this.person.deathdate.datetime);
// return dateToISO(date);
//}
if(this.person.deathdate !== null){
const date = new Date(this.person.deathdate.datetime);
return date.toLocaleDateString("fr-FR");
} else {
return "";
}
},
altNameLabel: function(){
altNameLabel: function() {
for(let i = 0; i < this.person.altNames.length; i++){
return this.person.altNames[i].label
}
},
altNameKey: function(){
altNameKey: function() {
for(let i = 0; i < this.person.altNames.length; i++){
return this.person.altNames[i].key
}
},
getUrl: function() {
return `/fr/person/${this.person.id}/general`;
},
getAge: function() {
if(this.person.birthdate && !this.person.deathdate){
const birthday = new Date(this.person.birthdate.datetime)
const now = new Date()
return (now.getFullYear() - birthday.getFullYear())
} else if(this.person.birthdate && this.person.deathdate){
const birthday = new Date(this.person.birthdate.datetime)
const deathdate = new Date(this.person.deathdate.datetime)
return (deathdate.getFullYear() - birthday.getFullYear())
} else if(!this.person.birthdate && this.person.deathdate.datetime) {
// todo: change this
return "Age unknown"
} else {
// todo: change this
return "Age unknown"
}
},
getCurrentHouseholdUrl: function() {
let returnPath = this.returnPath ? `?returnPath=${this.returnPath}` : ``;
return `/fr/person/household/${this.person.current_household_id}/summary${returnPath}`
}
}
}
</script>
@@ -149,10 +227,17 @@ div.flex-table {
}
div.item-col:last-child {
justify-content: flex-start;
}
}
}
}
.age{
margin-left: 0.5em;
&:before { content: '('; }
&:after { content: ')'; }
}
</style>

View File

@@ -1,139 +0,0 @@
<template>
<div class="chill-entity chill-entity__household">
<!-- identifier -->
<div v-if="isHouseholdNew()" class="identifier">
<i class="fa fa-home"></i>
{{ $t('new_household') }}
</div>
<div v-else class="identifier">
<i class="fa fa-home"></i>
{{ $t('household_number', { number: household.id } ) }}
</div>
<!-- member part -->
<div v-if="hasCurrentMembers" class="members">
<span class="current-members">{{ $t('current_members') }}: </span>
<template v-for="(m, index) in currentMembers()" :key="m.id">
<person :person="m.person"></person>
<span v-if="m.holder">
&nbsp;<span class="badge bg-primary">{{ $t('holder') }}</span>
</span>
<span v-if="index != (currentMembersLength() - 1)">, </span>
</template>
</div>
<div v-else class="members">
<p class="chill-no-data-statement">{{ $t('no_members_yet') }}</p>
</div>
<!-- address part -->
<div v-if="hasAddress()" class="where">
<i class="fa fa-where"></i>
<show-address :address="household.current_address"></show-address>
</div>
<div v-else class="where">
<i class="fa fa-where"></i>
<p class="chill-no-data-statement">{{ $t('no_current_address') }}</p>
</div>
</div>
</template>
<style lang="scss">
.chill-entity__household {
display: grid;
grid-template-areas:
"identifier identifier where"
"who who where"
;
grid-template-columns:
auto auto 30%
;
.identifier {
grid-area: identifier;
font-size: 1.3em;
font-weight: 700;
color: var(--chill-blue);
}
.members {
grid-area: who;
.current-members {
font-weight: 700;
}
}
.where {
grid-area: where
}
}
</style>
<script>
import Person from 'ChillPersonAssets/vuejs/_components/Person/Person.vue';
import ShowAddress from 'ChillMainAssets/vuejs/Address/components/ShowAddress.vue';
const i18n = {
"messages":
{
"fr":
{
"household_number": "Ménage #{number}",
"current_members": "Membres actuels",
"no_current_address": "Sans adresse actuellement",
"new_household": "Nouveau ménage",
"no_members_yet": "Aucun membre actuellement",
"holder": "titulaire",
}
}
}
;
export default {
name: 'Household',
props: ['household'],
components: {
Person,
ShowAddress,
},
i18n,
methods: {
hasCurrentMembers() {
return this.household.current_members_id.length > 0;
},
currentMembers() {
return this.household.members.filter(m => this.household.current_members_id.includes(m.id))
.sort((a, b) => {
if (a.position.ordering < b.position.ordering) {
return -1;
}
if (a.position.ordering > b.position.ordering) {
return 1;
}
if (a.holder && !b.holder) {
return -1;
}
if (!a.holder && b.holder) {
return 1;
}
return 0;
});
},
currentMembersLength() {
return this.household.current_members_id.length;
},
isHouseholdNew() {
return !Number.isInteger(this.household.id);
},
hasAddress() {
return this.household.current_address !== null;
}
}
};
</script>

View File

@@ -1,12 +1,13 @@
<template>
<div v-if="action === 'show'">
<div class="flex-table">
<person-render-box
<person-render-box render="bloc"
:person="person"
:options="{
addInfo: true,
addEntity: false,
addAltNames: true,
addAge: true,
addId: true,
addLink: false,
hLevel: 3,

View File

@@ -1,16 +0,0 @@
<template>
<span class="chill-entity chill-entity__person">
<span class="chill-entity__person__text chill_denomination">
{{ person.text }}
</span>
</span>
</template>
<script>
export default {
name: 'Person',
props: ['person']
}
</script>

View File

@@ -1,7 +1,7 @@
{% extends '@ChillPerson/AccompanyingCourse/layout.html.twig' %}
{% block title %}
{{ 'Accompanying Course Details'|trans }}
{{ 'Accompanying Course History'|trans }}
{% endblock %}
{% block content %}
@@ -15,8 +15,8 @@
Il faudrait peut-être modifier son adresse comme ceci: `/fr/parcours/{id}/timeline`
</p>
{# start test flex-table
{# start test flex-table
<div class="flex-table">
{% for p in accompanyingCourse.participations %}
<div class="item-bloc">
@@ -52,16 +52,16 @@
<li><button type="button" class="btn btn-edit"></button></li>
</ul>
</div>
</div>
<div class="item-row">
Lorem ipsum dolor sit amet, incididunt ut labore et dolore magna aliqua.
Lorem ipsum dolor sit amet, incididunt ut labore et dolore magna aliqua.
</div>
<div class="item-row">
Rhoncus est pellentesque elit eu ultrices vitae auctor.
Rhoncus est pellentesque elit eu ultrices vitae auctor.
</div>
<div class="item-row">
Facilisis gravida neque convallis a cras semper auctor neque.
Facilisis gravida neque convallis a cras semper auctor neque.
</div>
</div>
{% endfor %}
@@ -70,5 +70,5 @@
{# end test flex-table #}
{# ==> insert accompanyingCourse vue component #}
<div id="accompanying-course"></div>
<div id="accompanying-course"></div>
{% endblock %}

View File

@@ -34,6 +34,9 @@
</div>
{% endif %}
<pre>WIP .. AccompanyingCourse Resume dashboard</pre>
{#
<h1>{{ 'Resume Accompanying Course'|trans }}</h1>
<div class="associated-persons mb-5">
@@ -50,11 +53,13 @@
{% endif %}
{% endfor %}
</div>
#}
{% if 'DRAFT' != accompanyingCourse.step %}
{% if withoutHousehold|length > 0 %}
{% include '@ChillPerson/AccompanyingCourse/_join_household.html.twig' with {} %}
{% endif %}
{% endif %}
{#
</div>
<div class="location mb-5">
@@ -75,12 +80,11 @@
</div>
</div>
{% endif %}
#}
{% if accompanyingCourse.locationStatus == 'address' or accompanyingCourse.locationStatus == 'none' %}
{% include '@ChillPerson/AccompanyingCourse/_warning_address.html.twig' with {} %}
{% endif %}
{#
</div>
<div class="requestor mb-5">
@@ -128,6 +132,8 @@
</div>
{% endif %}
</div>
#}
<div class="mt-5"></div>
<div class="social-actions mb-5">
<h2 class="mb-3">{{ 'Social actions'|trans }}</h2>

View File

@@ -1,72 +0,0 @@
{#
This Twig template include load vue_address component.
It push all variables from context in Address/App.vue.
OPTIONS
* mode string ['edit*'|'new'|'create']
* address_id integer
* backUrl twig route: path('route', {parameters})
* modalTitle twig translated chain
* buttonText twig translated chain
* buttonSize bootstrap class like 'btn-sm'
#}
<div id="address"></div>
<script type="text/javascript">
window.vueRootComponent = 'app';
{% if person is defined %}
window.entityType = 'person';
window.entityId = {{ person.id|e('js') }};
{% elseif household is defined %}
window.entityType = 'household';
window.entityId = {{ household.id|e('js') }};
{% endif %}
{% if 'edit' in app.request.get('_route') %}
window.addressId = {{ app.request.get('address_id')|e('js') }};
window.mode = 'edit';
{% elseif mode is defined and mode == 'edit' %}
window.addressId = {{ address_id|e('js') }};
window.mode = 'edit';
{% endif %}
{% if backUrl is not defined %}
{% if person is defined %}
window.backUrl = '{{ path('chill_person_address_list', { 'person_id': person.id })|e('js') }}';
{% elseif household is defined %}
window.backUrl = '{{ path('chill_person_household_addresses', { 'household_id': household.id })|e('js') }}';
{% endif %}
{% else %}
window.backUrl = '{{ backUrl|e('js') }}';
{% endif %}
{% if modalTitle is defined %}
window.modalTitle = '{{ modalTitle|trans|e('js') }}';
{% endif %}
{% if buttonText is defined %}
window.buttonText = '{{ buttonText|trans|e('js') }}';
{% endif %}
{% if buttonSize is defined %}
window.buttonSize = '{{ buttonSize|e('js') }}';
{% endif %}
{% if buttonDisplayText is defined and buttonDisplayText == false %}
window.buttonDisplayText = false;
{% endif %}
{% if binModalStep1 is defined and binModalStep1 == false %}
window.binModalStep1 = false;
{% endif %}
{% if binModalStep2 is defined and binModalStep2 == false %}
window.binModalStep2 = false;
{% endif %}
</script>
{{ encore_entry_script_tags('vue_address') }}
{{ encore_entry_link_tags('vue_address') }}

View File

@@ -27,10 +27,15 @@
<h1>{{ block('title') }}</h1>
{# include vue_address component #}
{% include '@ChillPerson/Address/_insert_vue_address.html.twig' with {
binModalStep1: false,
binModalStep2: false,
{% include '@ChillMain/Address/_insert_vue_address.html.twig' with {
targetEntity: { name: 'person', id: person.id },
backUrl: path('chill_person_address_list', { 'person_id': person.id }),
openPanesInModal: false,
stickyActions: true,
useValidFrom: true,
} %}
{#
#}
{% endblock %}

View File

@@ -29,7 +29,9 @@
<li style="margin: auto;">
{# include vue_address component #}
{% include '@ChillPerson/Address/_insert_vue_address.html.twig' with {
{% include '@ChillMain/Address/_insert_vue_address.html.twig' with {
targetEntity: { name: 'person', id: person.id },
backUrl: path('chill_person_address_list', { 'person_id': person.id }),
mode: 'new',
buttonSize: 'btn-lg',
buttonText: 'Add an address',
@@ -64,28 +66,30 @@
{% if address.validTo is not empty and address.validTo < previousRowFrom %}
<div class="{{ 'row' ~ row ~ ' ' }}col-a action">
{# include vue_address component #}
<a href="" class="btn btn-sm btn-create">{{ 'Insert an address'|trans }}</a></div>
{# include vue_address component #}
{#
{% include '@ChillPerson/Address/_insert_vue_address.html.twig' with {
address_id: address.id,
{% include '@ChillMain/Address/_insert_vue_address.html.twig' with {
targetEntity: { name: 'person', id: person.id },
backUrl: path('chill_person_address_list', { 'person_id': person.id }),
mode: 'edit',
binModalStep1: false,
binModalStep2: false,
addressId: address.id,
openPanesInModal: false,
} %}
#}
<div class="{{ 'row' ~ row ~ ' ' }}col-b"></div>
<div class="{{ 'row' ~ row ~ ' ' }}col-c action">
{# include vue_address component #}
<a href="" class="btn btn-sm btn-create">{{ 'Insert an address'|trans }}</a></div>
{# include vue_address component #}
{#
{% include '@ChillPerson/Address/_insert_vue_address.html.twig' with {
address_id: address.id,
{% include '@ChillMain/Address/_insert_vue_address.html.twig' with {
targetEntity: { name: 'person', id: person.id },
backUrl: path('chill_person_address_list', { 'person_id': person.id }),
mode: 'edit',
binModalStep1: false,
binModalStep2: false,
addressId: address.id,
openPanesInModal: false,
} %}
#}
@@ -109,7 +113,6 @@
}) }}
<ul class="record_actions">
{# include vue_address component #}
<li><a href="{{ path('chill_person_address_edit', { 'person_id': person.id, 'address_id' : address.id } ) }}" class="btn btn-edit"></a></li>
</ul>
@@ -160,7 +163,6 @@
</a>
</li>
<li>
{# include vue_address component #}
<a class="btn btn-create"
href="{{ path('chill_person_address_new', { 'person_id' : person.id } ) }}">
{{ 'Add an address'|trans }}

View File

@@ -27,10 +27,16 @@
<h1>{{ block('title') }}</h1>
{# include vue_address component #}
{% include '@ChillPerson/Address/_insert_vue_address.html.twig' with {
binModalStep1: false,
binModalStep2: false,
{% include '@ChillMain/Address/_insert_vue_address.html.twig' with {
targetEntity: { name: 'person', id: person.id },
backUrl: path('chill_person_address_list', { 'person_id': person.id }),
openPanesInModal: false,
stickyActions: true,
useValidFrom: true,
} %}
{#
useValidTo: true,
#}
{% endblock %}

View File

@@ -16,6 +16,10 @@
'replace' Twig\Markup,
'after' Twig\Markup
]
* customArea [
'beforeLabel' Twig\Markup,
'afterLabel' Twig\Markup,
]
#}
{% macro raw(person, options) %}
@@ -37,11 +41,22 @@
<div class="denomination {{ 'h' ~ options['hLevel'] }}">
{%- if options['addLink'] and is_granted('CHILL_PERSON_SEE', person) -%}
<a href="{{ chill_path_add_return_path('chill_person_view', { 'person_id': person.id }) }}">
{{ _self.raw(person, options) }}
</a>
{%- else -%}
{{ _self.raw(person, options) }}
{%- endif -%}
{% if options['customArea']['beforeLabel'] is defined %}
{{ options['customArea']['beforeLabel'] }}
{% endif %}
{{ _self.raw(person, options) }}
{% if options['customArea']['afterLabel'] is defined %}
{{ options['customArea']['afterLabel'] }}
{% endif %}
{%- if options['addLink'] and is_granted('CHILL_PERSON_SEE', person) -%}
</a>
{%- endif -%}
{%- if options['addEntity'] -%}
<span class="badge rounded-pill bg-secondary">{{ 'Person'|trans }}</span>
{%- endif -%}
@@ -131,10 +146,10 @@
{% endif %}
{% endif %}
</li>
{% if options['addCenter'] %}
{% if options['addCenter'] and person|chill_resolve_center is not null %}
<li>
<i class="fa fa-li fa-long-arrow-right"></i>
{{ person.center }}
{{ person|chill_resolve_center.name }}
</li>
{% endif %}
</ul>

View File

@@ -4,7 +4,8 @@
{% block content %}
<h1>{{ block('title') }}</h1>
<h1>{{ member.person|chill_entity_render_string }}</h1>
<h2 class="mb-5">{{ 'household.Edit his household'|trans }}</h2>
{{ form_start(form) }}
{{ form_widget(form) }}

View File

@@ -0,0 +1,65 @@
{% macro addHolder(holder) %}
{% if holder %}
<span class="fa-stack fa-holder" title="{{ 'household.holder'|trans }}">
<i class="fa fa-circle fa-stack-1x text-success"></i>
<i class="fa fa-stack-1x">T</i>
</span>
{% endif %}
{% endmacro %}
<div class="item-bloc">
<div class="item-row">
<div class="item-col" style="flex-basis: 30%;">
{{ member.person|chill_entity_render_box({
'render': 'label',
'addLink': true,
'addInfo': true,
'customArea': {
'afterLabel': _self.addHolder(member.holder)
}
}) }}
</div>
<div class="item-col">
<div class="float-button top"><div class="box">
<div class="action">
<ul class="record_actions">
{% if customButtons['before'] is defined %}
{{ customButtons['before'] }}
{% endif %}
<li>
<a class="btn btn-sm btn-edit"
title="{{ 'household.Edit member household'|trans }}"
href="{{ chill_path_add_return_path('chill_person_household_member_edit', { 'id': member.id }) }}"></a>
</li>
{% if customButtons['after'] is defined %}
{{ customButtons['after'] }}
{% endif %}
</ul>
</div>
<ul class="list-content fa-ul small ms-0">
{% if member.startDate is not empty %}
<li><i class="fa fa-long-arrow-right"></i>
{{ 'Since %date%'|trans({'%date%': member.startDate|format_date('short') }) }}</li>
{% endif %}
{% if member.endDate is not empty %}
<li><i class="fa fa-long-arrow-right"></i>
{{ 'Until %date%'|trans({'%date%': member.endDate|format_date('short') }) }}</li>
{% endif %}
</ul>
{% if member.comment is not empty %}
<blockquote class="chill-user-quote ms-0 mb-0" style="clear: right">
{{ member.comment|chill_markdown_to_html }}
</blockquote>
{% endif %}
</div></div>
</div>
</div>
</div>

View File

@@ -7,9 +7,12 @@
<div>
{# include vue_address component #}
{% include '@ChillPerson/Address/_insert_vue_address.html.twig' with {
binModalStep1: false,
binModalStep2: false,
{% include '@ChillMain/Address/_insert_vue_address.html.twig' with {
targetEntity: { name: 'household', id: household.id },
backUrl: path('chill_person_household_addresses', { 'household_id': household.id }),
openPanesInModal: false,
stickyActions: true,
useValidFrom: true,
} %}
</div>

View File

@@ -7,10 +7,15 @@
<div>
{# include vue_address component #}
{% include '@ChillPerson/Address/_insert_vue_address.html.twig' with {
binModalStep1: false,
binModalStep2: false,
{% include '@ChillMain/Address/_insert_vue_address.html.twig' with {
targetEntity: { name: 'household', id: household.id },
backUrl: path('chill_person_household_addresses', { 'household_id': household.id }),
openPanesInModal: false,
stickyActions: true,
useValidFrom: true,
} %}
{#
#}
</div>
{% endblock %}

View File

@@ -15,13 +15,17 @@
<li style="margin: auto;">
{# include vue_address component #}
{% include '@ChillPerson/Address/_insert_vue_address.html.twig' with {
{% include '@ChillMain/Address/_insert_vue_address.html.twig' with {
targetEntity: { name: 'household', id: household.id },
backUrl: path('chill_person_household_addresses', { 'household_id': household.id }),
mode: 'new',
backUrl: chill_path_add_return_path('chill_person_household_address_move', { 'household_id': household.id }),
buttonSize: 'btn-lg',
buttonText: 'Move household',
modalTitle: 'Move household',
} %}
{#
useValidFrom: true,
#}
</li>
</ul>
@@ -41,7 +45,6 @@
<div class="{{ 'row' ~ row ~ ' ' }}col-b"></div>
<div class="{{ 'row' ~ row ~ ' ' }}col-c action">
{# include vue_address component #}
<a href="" class="btn btn-sm btn-create">{{ 'Insert an address'|trans }}</a></div>
<div class="date">
@@ -63,8 +66,6 @@
}) }}
<ul class="record_actions">
<li>
{# include vue_address component #}
<a href="{{ path('chill_person_household_address_edit', { 'household_id': household.id, 'address_id' : address.id } ) }}"
class="btn btn-edit"></a>
@@ -91,7 +92,6 @@
</li>
<li>
{# include vue_address component #}
<a class="btn btn-create"
href="{{ chill_path_add_return_path('chill_person_household_address_move', { 'household_id': household.id }) }}">
{{ 'Move household'|trans }}

View File

@@ -20,24 +20,21 @@
<i class="fa fa-fw fa-users" title="{{- 'household.Current household members'|trans }}"></i>
</span>
{%- for m in members|slice(0, 5) -%}
{%- for m in members -%}
<span
class="badge-member{%- if m.holder %} holder{% endif -%}{%- if m.position.ordering >= 2 %} child{% endif -%}"
title="{{ m.position.label.fr }}">
{%- if m.holder %}
<span class="badge bg-chill-light-gray text-chill-gray">
{{ 'household.holder'|trans }}
</span>
{% endif -%}
{{- m.person|chill_entity_render_box({'addLink': false}) -}}
<a href="{{ path('chill_person_view', { person_id: m.person.id}) }}">
{%- if m.holder %}
<span class="fa-stack fa-holder" title="{{ 'household.holder'|trans }}">
<i class="fa fa-circle fa-stack-1x text-success"></i>
<i class="fa fa-stack-1x">T</i>
</span>
{% endif -%}
{{- m.person|chill_entity_render_box() -}}
</a>
</span>
{%- endfor -%}
{% if members|length > 5 %}
<span class="current-members-more">
{{ 'household.and x other persons'|trans({'x': members|length-5}) }}
</span>
{% endif %}
{%- endif -%}
</div>
</div>

View File

@@ -17,4 +17,8 @@
'layout': '@ChillPerson/menu.html.twig',
'args' : { 'household': household }
}) }}
{% block block_post_menu %}
{% endblock %}
{% endblock %}

View File

@@ -4,7 +4,7 @@
{% block title 'household.Edit household members'|trans %}
{% block content %}
<div class="col-md-10 col-xxl household-members">
<div class="household-members">
<h1>{{ block('title') }}</h1>
<div id="household_members_editor"></div>
@@ -22,5 +22,6 @@
{% endblock %}
{% block css %}
{{ encore_entry_link_tags('vue_household_members_editor') }}
{{ parent() }}
{{ encore_entry_link_tags('vue_household_members_editor') }}
{% endblock %}

View File

@@ -2,213 +2,196 @@
{% block title 'household.Household summary'|trans %}
{% block block_post_menu %}
<div class="block-post-menu"></div>
{% endblock %}
{% block content %}
<div class="household-summary">
<h1>{{ block('title') }}</h1>
{#
<h1>{{ block('title') }}</h1>
<h2>{{ 'household.Current address'|trans }}</h2>
#}
<h2>{{ 'household.Current address'|trans }}</h2>
{% set address = household.currentAddress %}
{% set address = household.currentAddress %}
<div class="row household-resume">
<div class="item-bloc col-5 col-address">
<h2>{{ 'Address'|trans }}</h2>
{% if address is empty %}
<p class="chill-no-data-statement">{{ 'household.Household does not have any address currently'|trans }}</p>
{% else %}
<div>
{{ address|chill_entity_render_box({'multiline': true}) }}
</div>
{% endif %}
<h2>{{ 'household.Household members'|trans }}</h2>
{% if form is not null %}
{{ form_start(form) }}
{{ form_row(form.commentMembers) }}
<div id="waitingForBirthContainer">
{{ form_row(form.waitingForBirth) }}
</div>
<div id="waitingForBirthDateContainer">
{{ form_row(form.waitingForBirthDate) }}
</div>
<ul class="record_actions">
<li>
<button type="submit" class="btn btn-save">
{{ 'Save'|trans }}
</button>
</li>
</ul>
{{ form_end(form) }}
{% else %}
{% if not household.commentMembers.isEmpty() %}
{{ household.commentMembers|chill_entity_render_box }}
{% endif %}
{% if household.waitingForBirth %}
{% if household.waitingForBirthDate is not null %}
{{ 'household.Expecting for birth on date'|trans({ 'date': household.waitingForBirthDate|format_date('long') }) }}
{% else %}
{{ 'household.Expecting for birth'|trans }}
{% endif %}
{% else %}
<p class="chill-no-data-statement">
{{ 'household.Any expecting birth'|trans }}
</p>
{% endif %}
<ul class="record_actions">
<li>
<a href="{{ chill_path_add_return_path('chill_person_household_summary', { 'household_id': household.id, 'edit': 1 }) }}"
class="btn btn-edit">
{{ 'household.Comment and expecting birth'|trans }}
</a>
</li>
</ul>
{% endif %}
{% for p in positions %}
<h3>{{ p.label|localize_translatable_string }}</h3>
{% if false == p.shareHousehold %}
<p>{{ 'household.Those members does not share address'|trans }}</p>
{% endif %}
{%- set members = household.currentMembersByPosition(p) %}
{% if members|length > 0 %}
<div class="flex-table list-household-members">
{% for m in members %}
<div class="item-bloc">
<div class="item-row">
<div class="item-col">
<div>
{{ m.person|chill_entity_render_box({'addLink': true}) }}
{% if m.holder %}
<span class="badge bg-primary">{{ 'household.holder'|trans }}</span>
{% endif %}
</div>
<div>
{{ 'Born the date'|trans({ 'gender': m.person.gender, 'birthdate': m.person.birthdate|format_date('long') }) }}
</div>
</div>
<div class="item-col">
<ul class="list-content fa-ul">
{% if m.startDate is not empty %}
<li>{{ 'Since %date%'|trans({'%date%': m.startDate|format_date('long') }) }}</li>
{% endif %}
{% if m.endDate is not empty %}
<li>{{ 'Until %date%'|trans({'%date%': m.endDate|format_date('long') }) }}</li>
{% endif %}
</ul>
<ul class="record_actions">
<li>
<a href="{{ chill_path_add_return_path('chill_person_household_member_edit', { 'id': m.id }) }}"
class="btn btn-edit" />
{{ 'household.Update membership'|trans }}
</a>
</li>
<li>
<a href="{{ chill_path_add_return_path('chill_person_household_members_editor', {'persons': [ m.person.id ], 'household': household.id} ) }}"
class="btn btn-misc" />
<i class="fa fa-arrows-h"></i>
{{ 'household.Change position'|trans }}
</a>
</li>
<li>
<a href="{{ chill_path_add_return_path('chill_person_household_members_editor', {'persons': [ m.person.id ], 'allow_leave_without_household': true } ) }}"
class="btn btn-misc" />
<i class="fa fa-sign-out"></i>
{{ 'household.Leave'|trans }}
</a>
</li>
</ul>
</div>
</div>
{% if m.comment is not empty %}
<div class="item-row comment">
<blockquote class="chill-user-quote">
{{ m.comment|chill_markdown_to_html }}
</blockquote>
</div>
{% endif %}
</div>
{% endfor %}
</div>
{% else %}
<p class="chill-no-data-statement">{{ 'household.Any persons into this position'|trans }}</p>
{% endif %}
{% set members = household.nonCurrentMembersByPosition(p) %}
{% if members|length > 0 %}
<p><!-- force a space after table --></p>
<button class="btn btn-green" type="button" data-bs-toggle="collapse" data-bs-target="#nonCurrent_{{ p.id }}" aria-expanded="false" aria-controls="collapse non current members">
{{ 'household.Show future or past memberships'|trans({'length': members|length}) }}
</button>
<div id="nonCurrent_{{ p.id }}" class="collapse">
<div class="flex-table list-household-members">
{% for m in members %}
<div class="item-bloc">
<div class="item-row">
<div class="item-col">
<div>
{{ m.person|chill_entity_render_box({'addLink': true}) }}
{% if m.holder %}
<span class="badge bg-primary">{{ 'household.holder'|trans }}</span>
{% endif %}
</div>
<div>
{{ 'Born the date'|trans({ 'gender': m.person.gender, 'birthdate': m.person.birthdate|format_date('long') }) }}
</div>
</div>
<div class="item-col">
<ul class="list-content fa-ul">
{% if m.startDate is not empty %}
<li>{{ 'Since %date%'|trans({'%date%': m.startDate|format_date('long') }) }}</li>
{% endif %}
{% if m.endDate is not empty %}
<li>{{ 'Until %date%'|trans({'%date%': m.endDate|format_date('long') }) }}</li>
{% endif %}
</ul>
<ul class="record_actions">
<li>
<a href="{{ chill_path_add_return_path('chill_person_household_member_edit', { 'id': m.id }) }}"
class="btn btn-edit">
{{ 'household.Update membership'|trans }}
</a>
</li>
</ul>
</div>
</div>
{% if m.comment is not empty %}
<div class="item-row comment">
<blockquote class="chill-user-quote">
{{ m.comment|chill_markdown_to_html }}
</blockquote>
</div>
{% if address is empty %}
<p class="chill-no-data-statement">{{ 'household.Household does not have any address currently'|trans }}</p>
{% else %}
{{ address|chill_entity_render_box({'multiline': true, 'extended_infos': true }) }}
{% endif %}
</div>
{% endfor %}
</div>
<ul class="list-inline text-right mt-2">
<li class="list-inline-item">
{# include vue_address component #}
{% include '@ChillMain/Address/_insert_vue_address.html.twig' with {
targetEntity: { name: 'household', id: household.id },
backUrl: path('chill_person_household_summary', { 'household_id': household.id }),
hideAddress: true,
mode: 'new',
buttonSize: 'btn-sm',
buttonText: 'Move household',
modalTitle: 'Move household',
buttonDisplayText: false,
} %}
</li>
<li class="list-inline-item">
<a class="btn btn-secondary btn-sm" title="{{ "Addresses history"|trans }}"
href="{{ path('chill_person_household_addresses', { 'household_id': household.id } ) }}">
<i class="fa fa-list fa-fw"></i>
</a>
</li>
</ul>
</div>
{% if address is not empty %}
<div class="item-bloc col-7 col-comment">
{% if form is null %}
{% if household.waitingForBirth or not household.commentMembers.isEmpty() %}
<div class="p-4 bg-light">
{% if household.waitingForBirth %}
<i class="fa fa-check-square-o pe-2"></i>
{% if household.waitingForBirthDate is not null %}
{{ 'household.Expecting for birth on date'|trans({ 'date': household.waitingForBirthDate|format_date('long') }) }}
{% else %}
{{ 'household.Expecting for birth'|trans }}
{% endif %}
{% endif %}
{% if not household.commentMembers.isEmpty() %}
{{ household.commentMembers|chill_entity_render_box }}
{% endif %}
</div>
{% endif %}
{% if not household.commentMembers.isEmpty() %}
<a href="{{ chill_path_add_return_path('chill_person_household_summary', { 'household_id': household.id, 'edit': 1 }) }}"
class="btn btn-edit btn-block">
{{ 'household.Edit comment and expecting birth'|trans }}
</a>
{% else %}
<a href="{{ chill_path_add_return_path('chill_person_household_summary', { 'household_id': household.id, 'edit': 1 }) }}"
class="btn btn-create btn-block">
{{ 'household.New comment and expecting birth'|trans }}
</a>
{% endif %}
{% else %}
{{ form_start(form) }}
<div id="waitingForBirthContainer">
{{ form_widget(form.waitingForBirth) }}
</div>
<div id="waitingForBirthDateContainer">
{{ form_widget(form.waitingForBirthDate) }}
</div>
<div class="mt-3">
{{ form_widget(form.commentMembers) }}
</div>
<ul class="record_actions">
<li>
<button type="submit" class="btn btn-save">
{{ 'Save'|trans }}
</button>
</li>
</ul>
{{ form_end(form) }}
{% endif %}
</div>
{% endif %}
</div>
{% endif %}
{% endfor %}
<h2 class="my-5">{{ 'household.Household members'|trans }}</h2>
<ul class="record_actions">
<li>
<a href="{{ chill_path_add_return_path('chill_person_household_members_editor', {'household': household.id }) }}"
class="btn btn-create">
{{ 'household.Add a member'|trans }}
</a>
</li>
</ul>
{% for p in positions %}
<div class="mb-5">
<h3>{{ p.label|localize_translatable_string }}
{% if false == p.shareHousehold %}
<i class="chill-help-tooltip" data-bs-toggle="tooltip" data-bs-placement="top" data-bs-html="true"
title="{{ 'household.Those members does not share address'|trans }}"></i>
{% endif %}
</h3>
{%- set members = household.currentMembersByPosition(p) %}
{% macro customButtons(member, household) %}
<li>
<a href="{{ chill_path_add_return_path('chill_person_household_members_editor', {'persons': [ member.person.id ], 'allow_leave_without_household': true } ) }}"
class="btn btn-sm btn-unlink" title="{{ 'household.person.leave'|trans }}"></a>
</li>
<li>
<a href="{{ chill_path_add_return_path('chill_person_household_members_editor', {'persons': [ member.person.id ], 'household': household.id} ) }}"
class="btn btn-sm btn-misc" title="{{ 'household.Change position'|trans }}"><i class="fa fa-arrows-h"></i></a>
</li>
{% endmacro %}
{% if members|length > 0 %}
<div class="flex-table list-household-members">
{% for m in members %}
{% include '@ChillPerson/Household/_render_member.html.twig' with {
'member': m,
'customButtons': { 'after': _self.customButtons(m, household) }
} %}
{% endfor %}
</div>
{% else %}
<p class="chill-no-data-statement">{{ 'household.Any persons into this position'|trans }}</p>
{% endif %}
{% set members = household.nonCurrentMembersByPosition(p) %}
{% if members|length > 0 %}
<style>
button[aria-expanded="true"] > span.folded,
button[aria-expanded="false"] > span.unfolded { display: none; }
button[aria-expanded="false"] > span.folded,
button[aria-expanded="true"] > span.unfolded { display: inline; }
</style>
<div class="accordion" id="nonCurrent">
<div class="accordion-item">
<h2 class="accordion-header" id="heading_{{ p.id }}">
<button
class="accordion-button collapsed"
type="button"
data-bs-toggle="collapse"
data-bs-target="#collapse_{{ p.id }}"
aria-expanded="false"
aria-controls="collapse_{{ p.id }}">
<span class="folded">{{ 'household.Show future or past memberships'|trans({'length': members|length}) }}</span>
<span class="unfolded text-secondary">{{ 'household.Hide memberships'|trans }}</span>
</button>
</h2>
<div id="collapse_{{ p.id }}"
class="accordion-collapse collapse"
aria-labelledby="heading_{{ p.id }}"
data-bs-parent="#nonCurrent">
<div class="flex-table my-0 list-household-members">
{% for m in members %}
{% include '@ChillPerson/Household/_render_member.html.twig' with { 'member': m } %}
{% endfor %}
</div>
</div>
</div>
</div>
{% endif %}
</div>
{% endfor %}
<ul class="record_actions">
<li>
<a href="{{ chill_path_add_return_path('chill_person_household_members_editor', {'household': household.id }) }}"
class="btn btn-create">
{{ 'household.Add a member'|trans }}
</a>
</li>
</ul>
</div>
{% endblock %}

View File

@@ -17,11 +17,11 @@
{%- endif -%}
</div>
<div class="text-md-end">
{%- if chill_person.fields.spoken_languages == 'visible' -%}
{% if person|chill_resolve_center is not null%}
<span class="open_sansbold">
{{ 'Center'|trans|upper}} :
</span>
{{ person.center.name|upper }}
{{ person|chill_resolve_center.name|upper }}
{%- endif -%}
</div>
</div>

View File

@@ -64,10 +64,10 @@
{{ form_start(form) }}
{{ form_row(form.firstName, { 'label' : 'First name'|trans }) }}
{{ form_row(form.lastName, { 'label' : 'Last name'|trans }) }}
{{ form_row(form.firstName, { 'label' : 'First name'|trans }) }}
{% if form.altNames is defined %}
{{ form_widget(form.altNames) }}
{% endif %}
@@ -76,12 +76,27 @@
{{ form_row(form.gender, { 'label' : 'Gender'|trans }) }}
{% if form.center is defined %}
{{ form_row(form.center) }}
{% endif %}
<ul class="record_actions sticky-form-buttons">
<li>
{{ form_widget(form.editPerson, { 'attr': { 'class': 'btn btn-create' }}) }}
</li>
<li>
{{ form_widget(form.createPeriod, { 'attr': { 'class': 'btn btn-create' }}) }}
<li class="dropdown">
<a class="btn btn-create dropdown-toggle"
href="#" role="button" id="newPersonMore" data-bs-toggle="dropdown" aria-expanded="false">
{{ 'Add the person'|trans }}
</a>
<ul class="dropdown-menu" aria-labelledby="newPersonMore">
<li>
{{ form_widget(form.editPerson, { 'attr': { 'class': 'dropdown-item' }}) }}
</li>
<li>
{{ form_widget(form.createPeriod, { 'attr': { 'class': 'dropdown-item' }}) }}
</li>
<li>
{{ form_widget(form.createHousehold, { 'attr': { 'class': 'dropdown-item' }}) }}
</li>
</ul>
</li>
</ul>