Merge remote-tracking branch 'origin/master' into features/docgen-widget-generate-template

This commit is contained in:
2021-11-30 16:38:36 +01:00
1055 changed files with 5050 additions and 2165 deletions

View File

@@ -95,7 +95,6 @@ div.person-view {
* Header custom for Accompanying Course
*/
div.banner {
div#header-accompanying_course-name {
background: none repeat scroll 0 0 $chill-accourse-context;
@@ -117,6 +116,37 @@ div.banner {
color: $white;
padding-top: 1em;
padding-bottom: 1em;
/// AccompanyingCourse: HeaderSlider Carousel
button.carousel-control-prev,
button.carousel-control-next {
width: 8%;
opacity: inherit;
}
button.carousel-control-prev {
left: unset;
right: 0;
}
span.to-social-issues,
span.to-persons-associated {
display: inline-block;
border-radius: 15px;
width: 24px;
height: 24px;
box-shadow: 0 0 3px 1px grey;
opacity: 0.8;
&:hover {
opacity: 1;
}
}
span.to-social-issues {
background-color: #4bafe8;
border-left: 12px solid #32749a;
}
span.to-persons-associated {
background-color: #16d9b4;
border-right: 12px solid #ffffff;
}
}
}
@@ -203,34 +233,11 @@ div.household-resume {
}
}
/// Horizontal list of persons (Accourse resume page)
div.accompanyingcourse-resume {
div.associated-persons {
font-size: 110%;
span.household {
display: inline-block;
border-radius: 8px;
border: 1px solid $white;
&:hover {
border: 1px solid $chill-beige;
i {
display: inline-block;
}
}
&.no-household:hover {
border: 1px solid $white;
}
i {
color: $chill-beige;
display: none;
}
padding: 0.3em;
margin-right: 2px;
}
}
}
/*
* GENERIC PERSON STYLES
* miscellaneous
*/
///
abbr.referrer { // still used ?
font-size: 70%;
padding-right: 0.4em;
@@ -246,4 +253,4 @@ abbr.referrer { // still used ?
.created-updated {
border: 1px solid black;
padding: 10px;
}
}

View File

@@ -87,26 +87,12 @@ div.accompanying_course_work-list {
&.result_list {
padding-left: 1em;
margin-bottom: 0;
li {
padding-left: 0.3em;
&::marker {
/*
content: '→';
font-weight: bold;
font-size: 120%;
*/
font-family: ForkAwesome;
content: '\f04b';
font-size: 75%;
transform: rotate(45deg);
}
}
}
&.goal_title li::marker {
color: $social-issue-color;
&.goal_title {
@include list_marker_triangle($social-issue-color);
}
&.result_list li::marker {
color: $pink;
&.result_list {
@include list_marker_triangle($pink);
}
}
}

View File

@@ -49,8 +49,6 @@ h2.badge-title {
width: 100%;
color: $dark;
a & { text-decoration: none; } // ?!? keep it ?
span.title_label {
border-radius: 0.35rem 0 0 0.35rem;
color: $white;
@@ -75,13 +73,43 @@ h2.badge-title {
flex-grow: 1;
margin: 0 0 0 auto;
border-radius: 0 0.35rem 0.35rem 0;
background-color: $light;
background-color: $chill-llight-gray;
padding: 0.2em 1em;
ul.small_in_title {
margin-top: 0.5em;
margin: 0;
//margin-top: 0.5em;
font-size: 70%;
padding-left: 1rem;
&.evaluations {
@include list_marker_triangle($orange);
}
}
ul.columns { // XS:1 SM:2 MD:1 LG:2 XL:2 XXL:2
@include media-breakpoint-only(sm) {
columns: 2; -webkit-columns: 2; -moz-columns: 2;
}
@include media-breakpoint-up(lg) {
columns: 2; -webkit-columns: 2; -moz-columns: 2;
}
}
}
}
/// Theses links apply on badge as parent tag.
/// They don't look like button, picto or simple text links
a.badge-link {
color: unset;
text-decoration: unset;
& > h2.badge-title {
&:hover {
//box-shadow: 0 0 7px 0 $chill-gray;
//opacity: 0.8;
}
span.title_action {
&:hover {
background-color: $chill-ll-gray;
}
}
}
}
@@ -128,35 +156,7 @@ div.activity-list {
}
}
/// AccompanyingCourse: HeaderSlider Carousel
div#header-accompanying_course-details {
button.carousel-control-prev,
button.carousel-control-next {
width: 8%;
opacity: inherit;
}
button.carousel-control-prev {
left: unset;
right: 0;
}
span.to-social-issues,
span.to-persons-associated {
display: inline-block;
border-radius: 15px;
width: 24px;
height: 24px;
box-shadow: 0 0 3px 1px grey;
opacity: 0.8;
&:hover {
opacity: 1;
}
}
span.to-social-issues {
background-color: #4bafe8;
border-left: 12px solid #32749a;
}
span.to-persons-associated {
background-color: #16d9b4;
border-right: 12px solid #ffffff;
}
}
/*
*/

View File

@@ -37,3 +37,20 @@
margin: 0 0.3em 0 -1.05em;
}
}
///
/// Make list with items marker like a colored triangle
///
@mixin list_marker_triangle($color) {
& > li {
padding-left: 0.3em;
&::marker {
font-family: ForkAwesome;
content: '\f04b';
font-size: 75%;
transform: rotate(45deg);
color: $color;
}
}
}

View File

@@ -0,0 +1,6 @@
import Masonry from 'masonry-layout/masonry';
let elem = document.querySelector('#dashboards');
let msnry = new Masonry( elem, {
// options
});

View File

@@ -48,9 +48,7 @@ export default {
persons: this.persons.filter(p => p.current_household_id === h)
})
})
console.log(personsByHousehold)
//console.log(personsByHousehold)
return personsByHousehold
},
householdExists(id) {

View File

@@ -21,6 +21,7 @@
<script>
import { mapState } from 'vuex';
export default {
name: "ToggleFlags",
computed: {
@@ -28,6 +29,7 @@ export default {
intensity: state => state.accompanyingCourse.intensity,
emergency: state => state.accompanyingCourse.emergency,
confidential: state => state.accompanyingCourse.confidential,
permissions: state => state.permissions,
}),
isRegular() {
return (this.intensity === 'regular') ? true : false;
@@ -37,7 +39,7 @@ export default {
},
isConfidential() {
return (this.confidential) ? true : false;
}
},
},
methods: {
toggleIntensity() {
@@ -73,16 +75,22 @@ export default {
});
},
toggleConfidential() {
this.$store.dispatch('toggleConfidential', (!this.isConfidential))
.catch(({name, violations}) => {
if (name === 'ValidationException' || name === 'AccessException') {
violations.forEach((violation) => this.$toast.open({message: violation}));
} else {
this.$toast.open({message: 'An error occurred'})
}
});
}
}
this.$store.dispatch('fetchPermissions').then(() => {
if (!this.$store.getters.canTogglePermission) {
this.$toast.open({message: "Seul le référent peut modifier la confidentialité"});
return Promise.resolve();
} else {
return this.$store.dispatch('toggleConfidential', (!this.isConfidential));
}
}).catch(({name, violations}) => {
if (name === 'ValidationException' || name === 'AccessException') {
violations.forEach((violation) => this.$toast.open({message: violation}));
} else {
this.$toast.open({message: 'An error occurred'})
}
});
},
},
}
</script>

View File

@@ -47,6 +47,14 @@
</participation-item>
</div>
<div v-if="suggestedPersons.length > 0">
<ul class="list-suggest add-items">
<li v-for="p in suggestedPersons" :key="p.id" @click="addSuggestedPerson(p)">
<span>{{ p.text }}</span>
</li>
</ul>
</div>
<div>
<add-persons
buttonTitle="persons_associated.add_persons"
@@ -90,7 +98,28 @@ export default {
computed: {
...mapState({
courseId: state => state.accompanyingCourse.id,
participations: state => state.accompanyingCourse.participations
participations: state => state.accompanyingCourse.participations,
suggestedPersons: state => [
state.accompanyingCourse.requestor,
...state.accompanyingCourse.resources.map(r => r.resource)
]
.filter((e) => e !== null)
.filter((e) => e.type === 'person')
.filter(
(p) => !state.accompanyingCourse.participations.filter(pa => pa.endDate === null).map((pa) => pa.person.id).includes(p.id)
)
// filter persons appearing twice in requestor and resources
.filter(
(e, index, suggested) => {
for (let i = 0; i < suggested.length; i = i+1) {
if (i < index && e.id === suggested[i].id) {
return false
}
}
return true;
}
)
}),
...mapGetters([
'isParticipationValid'
@@ -106,7 +135,7 @@ export default {
},
getReturnPath() {
return window.location.pathname + window.location.search + window.location.hash;
}
},
},
methods: {
removeParticipation(item) {
@@ -143,7 +172,17 @@ export default {
);
this.$refs.addPersons.resetSearch(); // to cast child method
modal.showModal = false;
}
},
addSuggestedPerson(person) {
this.$store.dispatch('addParticipation', { result: person, type: 'person' })
.catch(({name, violations}) => {
if (name === 'ValidationException' || name === 'AccessException') {
violations.forEach((violation) => this.$toast.open({message: violation}));
} else {
this.$toast.open({message: 'An error occurred'})
}
})
},
}
}
</script>

View File

@@ -20,10 +20,9 @@
</VueMultiselect>
<template v-if="referrersSuggested.length > 0">
<ul class="list-unstyled">
<ul class="list-suggest add-items">
<li v-for="u in referrersSuggested" @click="updateReferrer(u)">
<span class="badge bg-primary" style="cursor: pointer">
<i class="fa fa-plus fa-fw text-success"></i>
<span>
<user-render-box-badge :user="u"></user-render-box-badge>
</span>
</li>

View File

@@ -32,7 +32,7 @@
</third-party-render-box>
</template>
</confidential>
<confidential v-else-if="accompanyingCourse.requestor.type === 'person'">
<template v-slot:confidential-content>
<person-render-box render="bloc"
@@ -133,6 +133,14 @@
<label class="chill-no-data-statement">{{ $t('requestor.counter') }}</label>
</div>
<div v-if="accompanyingCourse.requestor === null && suggestedEntities.length > 0">
<ul class="list-suggest add-items">
<li v-for="p in suggestedEntities" :key="uniqueId(p)" @click="addSuggestedEntity(p)">
<span>{{ p.text }}</span>
</li>
</ul>
</div>
<div>
<add-persons v-if="accompanyingCourse.requestor === null"
buttonTitle="requestor.add_requestor"
@@ -153,6 +161,7 @@ import OnTheFly from 'ChillMainAssets/vuejs/OnTheFly/components/OnTheFly.vue';
import PersonRenderBox from '../../_components/Entity/PersonRenderBox.vue';
import ThirdPartyRenderBox from 'ChillThirdPartyAssets/vuejs/_components/Entity/ThirdPartyRenderBox.vue';
import Confidential from 'ChillMainAssets/vuejs/_components/Confidential.vue';
import { mapState } from 'vuex';
export default {
name: 'Requestor',
@@ -177,12 +186,30 @@ export default {
}
},
computed: {
...mapState({
suggestedEntities: state => {
return [
...state.accompanyingCourse.participations.map(p => p.person),
...state.accompanyingCourse.resources.map(r => r.resource)
]
.filter((e) => e !== null)
// filter for same entity appearing twice
.filter((e, index, suggested) => {
for (let i = 0; i < suggested.length; i = i+1) {
if (i < index && e.id === suggested[i].id && e.type === suggested[i].type) {
return false
}
}
return true;
})
}
}),
accompanyingCourse() {
return this.$store.state.accompanyingCourse
},
isAnonymous: {
set(value) {
//console.log('requestorIsAnonymous value',value);
this.$store.dispatch('requestorIsAnonymous', value);
},
get() {
@@ -227,6 +254,19 @@ export default {
this.$toast.open({message: 'An error occurred'})
}
});
},
addSuggestedEntity(e) {
this.$store.dispatch('addRequestor', { result: e, type: e.type })
.catch(({name, violations}) => {
if (name === 'ValidationException' || name === 'AccessException') {
violations.forEach((violation) => this.$toast.open({message: violation}));
} else {
this.$toast.open({message: 'An error occurred'})
}
})
},
uniqueId(e) {
return `${e.type}-${e.id}`;
}
}
}

View File

@@ -18,6 +18,15 @@
@remove="removeResource">
</resource-item>
</div>
<div v-if="suggestedEntities.length > 0">
<ul class="list-suggest add-items">
<li v-for="p in suggestedEntities" :key="uniqueId(p)" @click="addSuggestedEntity(p)">
<span>{{ p.text }}</span>
</li>
</ul>
</div>
<div>
<add-persons
buttonTitle="resources.add_resources"
@@ -57,7 +66,38 @@ export default {
},
computed: mapState({
resources: state => state.accompanyingCourse.resources,
counter: state => state.accompanyingCourse.resources.length
counter: state => state.accompanyingCourse.resources.length,
suggestedEntities: state => [
state.accompanyingCourse.requestor,
...state.accompanyingCourse.participations.map(p => p.person),
]
.filter((e) => e !== null)
.filter(
(e) => {
if (e.type === 'person') {
return !state.accompanyingCourse.resources
.filter((r) => r.resource.type === 'person')
.map((r) => r.resource.id).includes(e.id)
}
if (e.type === 'thirdparty') {
return !state.accompanyingCourse.resources
.filter((r) => r.resource.type === 'thirdparty')
.map((r) => r.resource.id).includes(e.id)
}
}
)
// filter persons appearing twice in requestor and resources
.filter(
(e, index, suggested) => {
for (let i = 0; i < suggested.length; i = i+1) {
if (i < index && e.id === suggested[i].id) {
return false
}
}
return true;
}
)
}),
methods: {
removeResource(item) {
@@ -86,6 +126,19 @@ export default {
);
this.$refs.addPersons.resetSearch(); // to cast child method
modal.showModal = false;
},
addSuggestedEntity(e) {
this.$store.dispatch('addResource', { result: e, type: e.type})
.catch(({name, violations}) => {
if (name === 'ValidationException' || name === 'AccessException') {
violations.forEach((violation) => this.$toast.open({message: violation}));
} else {
this.$toast.open({message: 'An error occurred'})
}
})
},
uniqueId(e) {
return `${e.type}-${e.id}`;
}
}
}

View File

@@ -35,7 +35,7 @@ const appMessages = {
title: "Origine de la demande",
label: "Origine de la demande",
placeholder: "Renseignez l'origine de la demande",
not_valid: "Indiquez une origine de la demande",
not_valid: "Indiquez une origine à la demande",
},
persons_associated: {
title: "Usagers concernés",
@@ -126,7 +126,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",
origin_not_valid: "indiquez une origine de la demande",
origin_not_valid: "Indiquez une origine à la demande",
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 !",

View File

@@ -37,6 +37,7 @@ let initPromise = Promise.all([scopesPromise, accompanyingCoursePromise])
referrersSuggested: [],
// all the users available
users: [],
permissions: {}
},
getters: {
isParticipationValid(state) {
@@ -70,7 +71,14 @@ let initPromise = Promise.all([scopesPromise, accompanyingCoursePromise])
return true;
}
return false;
}
},
canTogglePermission(state) {
if (state.permissions.roles) {
return state.permissions.roles['CHILL_PERSON_ACCOMPANYING_PERIOD_TOGGLE_CONFIDENTIAL'];
}
return false;
},
},
mutations: {
catchError(state, error) {
@@ -201,6 +209,10 @@ let initPromise = Promise.all([scopesPromise, accompanyingCoursePromise])
return u;
});
},
setPermissions(state, permissions) {
state.permissions = permissions;
// console.log('permissions', state.permissions);
},
updateLocation(state, r) {
//console.log('### mutation: set location attributes', r);
state.accompanyingCourse.locationStatus = r.locationStatus;
@@ -625,6 +637,33 @@ let initPromise = Promise.all([scopesPromise, accompanyingCoursePromise])
let users = await getUsers();
commit('setUsers', users);
},
/**
* By adding more roles to body['roles'], more permissions can be checked.
*/
fetchPermissions({commit}) {
const url = '/api/1.0/main/permissions/info.json';
const body = {
"object": {
"type": "accompanying_period",
"id": id
},
"class": "Chill\\PersonBundle\\Entity\\AccompanyingPeriod",
"roles": [
"CHILL_PERSON_ACCOMPANYING_PERIOD_TOGGLE_CONFIDENTIAL"
]
}
return makeFetch('POST', url, body)
.then((response) => {
commit('setPermissions', response);
return Promise.resolve();
})
.catch((error) => {
commit('catchError', error);
throw error;
})
},
updateLocation({ commit, dispatch }, payload) {
//console.log('## action: updateLocation', payload.locationStatusTo);
const url = `/api/1.0/person/accompanying-course/${payload.targetId}.json`;
@@ -642,12 +681,12 @@ let initPromise = Promise.all([scopesPromise, accompanyingCoursePromise])
Object.assign(body, location);
makeFetch('PATCH', url, body)
.then((response) => {
commit('updateLocation', {
location: response.location,
locationStatus: response.locationStatus,
personLocation: response.personLocation
});
dispatch('fetchReferrersSuggested');
commit('updateLocation', {
location: response.location,
locationStatus: response.locationStatus,
personLocation: response.personLocation
});
dispatch('fetchReferrersSuggested');
})
.catch((error) => {
commit('catchError', error);

View File

@@ -44,9 +44,9 @@
<!-- results which **are** attached to an objective -->
<div v-for="g in goalsPicked">
<div>
<div class="item-title" @click="removeGoal(g)">
<i class="fa fa-times"></i>
<div class="item-title">
{{ g.goal.title.fr }}
<a @click="removeGoal(g)"></a>
</div>
</div>
<div>
@@ -61,10 +61,9 @@
<p>{{ $t('available_goals_text') }}</p>
<ul class="list-objectives">
<li v-for="g in availableForCheckGoal" class="badge bg-primary" @click="addGoal(g)">
<i class="fa fa-plus"></i>
{{ g.title.fr }}
<ul class="list-suggest add-items">
<li v-for="g in availableForCheckGoal" @click="addGoal(g)">
<span>{{ g.title.fr }}</span>
</li>
</ul>
</div>
@@ -98,10 +97,9 @@
<div class="add_evaluation">
<div v-if="showAddEvaluation">
<p>{{ $t('available_evaluations_text') }}</p>
<ul class="list-evaluations">
<li v-for="e in evaluationsForAction" class="badge bg-primary" @click="addEvaluation(e)">
<i class="fa fa-plus"></i>
{{ e.title.fr }}
<ul class="list-suggest add-items">
<li v-for="e in evaluationsForAction" @click="addEvaluation(e)">
<span>{{ e.title.fr }}</span>
</li>
</ul>
</div>
@@ -512,8 +510,8 @@ div#workEditor {
& > div.results_without_objective {
background: repeating-linear-gradient(
45deg,
$gray-500,
$gray-500 10px,
$gray-200,
$gray-200 10px,
$gray-100 10px,
$gray-100 20px
);
@@ -552,31 +550,11 @@ div#workEditor {
font-size: 85%;
}
ul.list-evaluations,
ul.list-objectives,
ul.list-results {
list-style-type: none;
padding: 0;
li {
margin: 0.5rem;
&.badge {
padding-bottom: 0;
padding-top: 0;
padding-left: 0;
}
}
}
i.fa {
padding: 0.25rem;
color: $white;
&.fa-plus { background-color: $green; }
&.fa-times { background-color: $red; }
&.fa-pencil { background-color: $orange; }
&.fa-times { color: $red; }
}
}

View File

@@ -1,9 +1,10 @@
<template>
<div>
<div class="item-title" @click="removeEvaluation(evaluation)">
<i class="fa fa-fw fa-times"></i>
<div class="item-title">
{{ evaluation.evaluation.title.fr }}
<a @click="removeEvaluation(evaluation)"></a>
</div>
<div v-if="!evaluation.editEvaluation">
<dl class="item-details definition-inline">

View File

@@ -1,33 +1,57 @@
<template>
<div v-if="hasResult" class="addResult">
<p v-if="pickedResults.length ===0" class="chill-no-data-statement">
Aucun résultat associé
</p>
<ul class="list-results">
<li v-for="r in pickedResults" class="badge bg-primary" @click="removeResult(r)">
<i class="fa fa-times"></i>
{{ r.title.fr }}
</li>
<template v-if="isExpanded">
<li v-for="r in availableForCheckResults" class="badge bg-primary" @click="addResult(r)">
<i class="fa fa-plus"></i>
<ul class="list-suggest remove-items">
<li v-for="r in pickedResults">
<span>
{{ r.title.fr }}
</li>
</template>
</ul>
<ul class="record_actions">
<li v-if="isExpanded">
<button class="btn btn-hide" @click="toggleSelect">
<i class="fa fa-eye-slash"></i>
Masquer résultats et orientations disponibles
</button>
</li>
<li v-else>
<button class="btn btn-show" @click="toggleSelect">
Afficher résultats et orientations disponibles
</button>
<a @click="removeResult(r)"></a>
</span>
</li>
</ul>
<div class="accordion" id="expandedSuggestions">
<div class="accordion-item">
<h2 class="accordion-header" id="heading_expanded_suggestions">
<button v-if="isExpanded"
class="accordion-button"
type="button"
data-bs-toggle="collapse"
aria-expanded="true"
@click="toggleSelect">
Masquer résultats et orientations disponibles
</button>
<button v-else
class="accordion-button collapsed"
type="button"
data-bs-toggle="collapse"
aria-expanded="false"
@click="toggleSelect">
Afficher résultats et orientations disponibles
</button>
</h2>
<div class="accordion-collapse" id="collapse_expanded_suggestions"
aria-labelledby="heading_expanded_suggestions" data-bs-parent="#expandedSuggestions">
<template v-if="isExpanded">
<ul class="list-suggest add-items">
<li v-for="r in availableForCheckResults" @click="addResult(r)">
<span>{{ r.title.fr }}</span>
</li>
</ul>
</template>
</div>
</div>
</div>
</div>
<div v-if="!hasResult" class="noResult">
<div class="chill-no-data-statement">