eslint fixes

This commit is contained in:
2025-07-09 17:46:36 +02:00
parent 0204bdd38d
commit dcdfba5ccd
208 changed files with 20402 additions and 21424 deletions

View File

@@ -1,28 +1,28 @@
<template>
<banner />
<sticky-nav />
<banner />
<sticky-nav />
<h1 v-if="accompanyingCourse.step === 'DRAFT'">
{{ $t("course.title.draft") }}
</h1>
<h1 v-else>
{{ $t("course.title.active") }}
</h1>
<h1 v-if="accompanyingCourse.step === 'DRAFT'">
{{ $t("course.title.draft") }}
</h1>
<h1 v-else>
{{ $t("course.title.active") }}
</h1>
<persons-associated />
<course-location />
<origin-demand />
<admin-location />
<requestor :is-anonymous="accompanyingCourse.requestorAnonymous" />
<social-issue />
<scopes />
<referrer />
<resources />
<start-date v-if="accompanyingCourse.step.startsWith('CONFIRMED')" />
<comment v-if="accompanyingCourse.step === 'DRAFT'" />
<confirm v-if="accompanyingCourse.step === 'DRAFT'" />
<persons-associated />
<course-location />
<origin-demand />
<admin-location />
<requestor :is-anonymous="accompanyingCourse.requestorAnonymous" />
<social-issue />
<scopes />
<referrer />
<resources />
<start-date v-if="accompanyingCourse.step.startsWith('CONFIRMED')" />
<comment v-if="accompanyingCourse.step === 'DRAFT'" />
<confirm v-if="accompanyingCourse.step === 'DRAFT'" />
<!-- <div v-for="error in errorMsg" v-bind:key="error.id" class="vue-component errors alert alert-danger">
<!-- <div v-for="error in errorMsg" v-bind:key="error.id" class="vue-component errors alert alert-danger">
<p>
<span>{{ error.sta }} {{ error.txt }}</span><br>
<span>{{ $t(error.msg) }}</span>
@@ -47,26 +47,26 @@ import Confirm from "./components/Confirm.vue";
import StartDate from "./components/StartDate.vue";
export default {
name: "App",
components: {
Banner,
StickyNav,
OriginDemand,
AdminLocation,
PersonsAssociated,
Requestor,
SocialIssue,
CourseLocation,
Scopes,
Referrer,
Resources,
Comment,
Confirm,
StartDate,
},
computed: {
...mapState(["accompanyingCourse", "addressContext"]),
},
name: "App",
components: {
Banner,
StickyNav,
OriginDemand,
AdminLocation,
PersonsAssociated,
Requestor,
SocialIssue,
CourseLocation,
Scopes,
Referrer,
Resources,
Comment,
Confirm,
StartDate,
},
computed: {
...mapState(["accompanyingCourse", "addressContext"]),
},
};
</script>
@@ -75,62 +75,62 @@ export default {
$chill-accourse-context: #718596;
div#accompanying-course {
div.vue-component {
h2 {
margin: 1em 0.7em;
position: relative;
&:before {
position: absolute;
content: "\f142"; //ellipsis-v
font-family: "ForkAwesome";
color: tint-color($chill-accourse-context, 10%);
left: -22px;
top: 4px;
}
a[id^="section"] {
position: absolute;
top: -2.5em; // reference for stickNav
}
}
padding: 0em 0em;
margin: 1em 0;
border-radius: 5px;
border: 1px dotted tint-color($chill-accourse-context, 10%);
border-left: 1px dotted tint-color($chill-accourse-context, 10%);
border-right: 1px dotted tint-color($chill-accourse-context, 10%);
dd {
margin-left: 1em;
}
& > div {
margin: 1em 3em 0;
&.flex-table,
&.flex-bloc {
margin: 1em 0 0;
}
&.alert.to-confirm {
margin: 1em 0 0;
padding: 1em 3em;
}
}
div.flex-table {
div.item-row {
div.item-col:first-child {
flex-basis: 33%;
}
}
}
&.errors {
//display: flex;
//position: sticky;
//bottom: 0.3em;
//z-index: 1000;
margin: 1em 0;
padding: 1em;
border-radius: 0;
}
div.vue-component {
h2 {
margin: 1em 0.7em;
position: relative;
&:before {
position: absolute;
content: "\f142"; //ellipsis-v
font-family: "ForkAwesome";
color: tint-color($chill-accourse-context, 10%);
left: -22px;
top: 4px;
}
a[id^="section"] {
position: absolute;
top: -2.5em; // reference for stickNav
}
}
padding: 0em 0em;
margin: 1em 0;
border-radius: 5px;
border: 1px dotted tint-color($chill-accourse-context, 10%);
border-left: 1px dotted tint-color($chill-accourse-context, 10%);
border-right: 1px dotted tint-color($chill-accourse-context, 10%);
dd {
margin-left: 1em;
}
& > div {
margin: 1em 3em 0;
&.flex-table,
&.flex-bloc {
margin: 1em 0 0;
}
&.alert.to-confirm {
margin: 1em 0 0;
padding: 1em 3em;
}
}
div.flex-table {
div.item-row {
div.item-col:first-child {
flex-basis: 33%;
}
}
}
&.errors {
//display: flex;
//position: sticky;
//bottom: 0.3em;
//z-index: 1000;
margin: 1em 0;
padding: 1em;
border-radius: 0;
}
}
}
</style>

View File

@@ -1,38 +1,35 @@
<template>
<div class="vue-component">
<h2><a id="section-40" />{{ $t("admin_location.title") }}</h2>
<div class="vue-component">
<h2><a id="section-40" />{{ $t("admin_location.title") }}</h2>
<div class="mb-4">
<label for="selectAdminLocation">
{{ $t("admin_location.title") }}
</label>
<div class="mb-4">
<label for="selectAdminLocation">
{{ $t("admin_location.title") }}
</label>
<VueMultiselect
name="selectAdminLocation"
label="text"
:custom-label="customLabel"
track-by="id"
:multiple="false"
:searchable="true"
:placeholder="$t('admin_location.placeholder')"
v-model="value"
:options="options"
group-values="locations"
group-label="locationCategories"
:select-label="$t('multiselect.select_label')"
:deselect-label="$t('multiselect.deselect_label')"
:selected-label="$t('multiselect.selected_label')"
@select="updateAdminLocation"
/>
</div>
<div
v-if="!isAdminLocationValid"
class="alert alert-warning to-confirm"
>
{{ $t("admin_location.not_valid") }}
</div>
<VueMultiselect
name="selectAdminLocation"
label="text"
:custom-label="customLabel"
track-by="id"
:multiple="false"
:searchable="true"
:placeholder="$t('admin_location.placeholder')"
v-model="value"
:options="options"
group-values="locations"
group-label="locationCategories"
:select-label="$t('multiselect.select_label')"
:deselect-label="$t('multiselect.deselect_label')"
:selected-label="$t('multiselect.selected_label')"
@select="updateAdminLocation"
/>
</div>
<div v-if="!isAdminLocationValid" class="alert alert-warning to-confirm">
{{ $t("admin_location.not_valid") }}
</div>
</div>
</template>
<script>
@@ -41,72 +38,67 @@ import { fetchResults } from "ChillMainAssets/lib/api/apiMethods";
import { mapState, mapGetters } from "vuex";
export default {
name: "AdminLocation",
components: { VueMultiselect },
data() {
return {
options: [],
};
name: "AdminLocation",
components: { VueMultiselect },
data() {
return {
options: [],
};
},
computed: {
...mapState({
value: (state) => state.accompanyingCourse.administrativeLocation,
}),
...mapGetters(["isAdminLocationValid"]),
},
mounted() {
this.getOptions();
},
methods: {
getOptions() {
fetchResults(`/api/1.0/main/location.json`).then((response) => {
let uniqueLocationTypeId = [
...new Set(response.map((o) => o.locationType.id)),
];
let results = [];
for (let id of uniqueLocationTypeId) {
results.push({
locationCategories: response.filter(
(o) => o.locationType.id === id,
)[0].locationType.title.fr,
locations: response.filter((o) => o.locationType.id === id),
});
}
this.options = results;
});
},
computed: {
...mapState({
value: (state) => state.accompanyingCourse.administrativeLocation,
}),
...mapGetters(["isAdminLocationValid"]),
updateAdminLocation(value) {
this.$store
.dispatch("updateAdminLocation", value)
.catch(({ name, violations }) => {
if (name === "ValidationException" || name === "AccessException") {
violations.forEach((violation) =>
this.$toast.open({ message: violation }),
);
} else {
this.$toast.open({ message: "An error occurred" });
}
});
},
mounted() {
this.getOptions();
},
methods: {
getOptions() {
fetchResults(`/api/1.0/main/location.json`).then((response) => {
let uniqueLocationTypeId = [
...new Set(response.map((o) => o.locationType.id)),
];
let results = [];
for (let id of uniqueLocationTypeId) {
results.push({
locationCategories: response.filter(
(o) => o.locationType.id === id,
)[0].locationType.title.fr,
locations: response.filter(
(o) => o.locationType.id === id,
),
});
}
this.options = results;
});
},
updateAdminLocation(value) {
this.$store
.dispatch("updateAdminLocation", value)
.catch(({ name, violations }) => {
if (
name === "ValidationException" ||
name === "AccessException"
) {
violations.forEach((violation) =>
this.$toast.open({ message: violation }),
);
} else {
this.$toast.open({ message: "An error occurred" });
}
});
},
customLabel(value) {
return value.locationType
? value.name
? `${value.name} (${value.locationType.title.fr})`
: value.locationType.title.fr
: "";
},
customLabel(value) {
return value.locationType
? value.name
? `${value.name} (${value.locationType.title.fr})`
: value.locationType.title.fr
: "";
},
},
};
</script>
<style src="vue-multiselect/dist/vue-multiselect.css"></style>
<style lang="css" scoped>
label {
display: none;
display: none;
}
</style>

View File

@@ -1,132 +1,107 @@
<template>
<teleport to="#header-accompanying_course-name #banner-flags">
<toggle-flags />
</teleport>
<teleport to="#header-accompanying_course-name #banner-flags">
<toggle-flags />
</teleport>
<teleport to="#header-accompanying_course-name #banner-status">
<span
v-if="accompanyingCourse.step === 'DRAFT'"
class="text-md-end d-md-block"
>
<span class="badge bg-secondary">
{{ $t("course.step.draft") }}
</span>
</span>
<span
v-else-if="
accompanyingCourse.step === 'CONFIRMED' ||
accompanyingCourse.step === 'CONFIRMED_INACTIVE_SHORT' ||
accompanyingCourse.step === 'CONFIRMED_INACTIVE_LONG'
"
class="text-md-end"
>
<span
v-if="accompanyingCourse.step === 'CONFIRMED'"
class="d-md-block mb-md-3"
>
<span class="badge bg-primary">
{{ $t("course.step.active") }}
</span>
</span>
<span
v-else-if="
accompanyingCourse.step === 'CONFIRMED_INACTIVE_SHORT'
"
class="d-md-block mb-md-3"
>
<span class="badge bg-chill-yellow text-primary">
{{ $t("course.step.inactive_short") }}
</span>
</span>
<span
v-else-if="
accompanyingCourse.step === 'CONFIRMED_INACTIVE_LONG'
"
class="d-md-block mb-md-3"
>
<span class="badge bg-chill-pink">
{{ $t("course.step.inactive_long") }}
</span>
</span>
<span class="d-md-block">
<span class="d-md-block ms-3 ms-md-0">
<i
>{{ $t("course.open_at")
}}{{
$d(accompanyingCourse.openingDate.datetime, "text")
}}</i
>
</span>
<span
v-if="accompanyingCourse.user"
class="d-md-block ms-3 ms-md-0"
>
<span class="item-key">{{ $t("course.referrer") }}:</span
>&nbsp;
<b>{{ accompanyingCourse.user.text }}</b>
<template v-if="accompanyingCourse.user.isAbsent">
&nbsp;
<span
class="badge bg-danger rounded-pill"
title="Absent"
>A</span
>
</template>
</span>
</span>
</span>
<span v-else class="text-md-end d-md-block">
<span class="badge bg-danger">
{{ $t("course.step.closed") }}
</span>
<span class="d-md-block">
<span class="d-md-block ms-3 ms-md-0">
<i
>{{
$d(accompanyingCourse.openingDate.datetime, "text")
}}
-
{{
$d(accompanyingCourse.closingDate.datetime, "text")
}}</i
>
</span>
<span
v-if="accompanyingCourse.user"
class="d-md-block ms-3 ms-md-0"
>
<span class="item-key">{{ $t("course.referrer") }}:</span>
<b>{{ accompanyingCourse.user.text }}</b>
</span>
</span>
</span>
</teleport>
<teleport
to="#header-accompanying_course-name #persons-associated-shortlist"
<teleport to="#header-accompanying_course-name #banner-status">
<span
v-if="accompanyingCourse.step === 'DRAFT'"
class="text-md-end d-md-block"
>
<persons-associated
:accompanyingCourse="accompanyingCourse"
:shortlist="true"
></persons-associated>
</teleport>
<teleport to="#header-accompanying_course-details #banner-social-issues">
<social-issue
v-for="issue in accompanyingCourse.socialIssues"
:key="issue.id"
:issue="issue"
/>
</teleport>
<teleport
to="#header-accompanying_course-details #banner-persons-associated"
<span class="badge bg-secondary">
{{ $t("course.step.draft") }}
</span>
</span>
<span
v-else-if="
accompanyingCourse.step === 'CONFIRMED' ||
accompanyingCourse.step === 'CONFIRMED_INACTIVE_SHORT' ||
accompanyingCourse.step === 'CONFIRMED_INACTIVE_LONG'
"
class="text-md-end"
>
<persons-associated
:accompanying-course="accompanyingCourse"
:shortlist="false"
/>
</teleport>
<span
v-if="accompanyingCourse.step === 'CONFIRMED'"
class="d-md-block mb-md-3"
>
<span class="badge bg-primary">
{{ $t("course.step.active") }}
</span>
</span>
<span
v-else-if="accompanyingCourse.step === 'CONFIRMED_INACTIVE_SHORT'"
class="d-md-block mb-md-3"
>
<span class="badge bg-chill-yellow text-primary">
{{ $t("course.step.inactive_short") }}
</span>
</span>
<span
v-else-if="accompanyingCourse.step === 'CONFIRMED_INACTIVE_LONG'"
class="d-md-block mb-md-3"
>
<span class="badge bg-chill-pink">
{{ $t("course.step.inactive_long") }}
</span>
</span>
<span class="d-md-block">
<span class="d-md-block ms-3 ms-md-0">
<i
>{{ $t("course.open_at")
}}{{ $d(accompanyingCourse.openingDate.datetime, "text") }}</i
>
</span>
<span v-if="accompanyingCourse.user" class="d-md-block ms-3 ms-md-0">
<span class="item-key">{{ $t("course.referrer") }}:</span>&nbsp;
<b>{{ accompanyingCourse.user.text }}</b>
<template v-if="accompanyingCourse.user.isAbsent">
&nbsp;
<span class="badge bg-danger rounded-pill" title="Absent">A</span>
</template>
</span>
</span>
</span>
<span v-else class="text-md-end d-md-block">
<span class="badge bg-danger">
{{ $t("course.step.closed") }}
</span>
<span class="d-md-block">
<span class="d-md-block ms-3 ms-md-0">
<i
>{{ $d(accompanyingCourse.openingDate.datetime, "text") }}
-
{{ $d(accompanyingCourse.closingDate.datetime, "text") }}</i
>
</span>
<span v-if="accompanyingCourse.user" class="d-md-block ms-3 ms-md-0">
<span class="item-key">{{ $t("course.referrer") }}:</span>
<b>{{ accompanyingCourse.user.text }}</b>
</span>
</span>
</span>
</teleport>
<teleport to="#header-accompanying_course-name #persons-associated-shortlist">
<persons-associated
:accompanyingCourse="accompanyingCourse"
:shortlist="true"
></persons-associated>
</teleport>
<teleport to="#header-accompanying_course-details #banner-social-issues">
<social-issue
v-for="issue in accompanyingCourse.socialIssues"
:key="issue.id"
:issue="issue"
/>
</teleport>
<teleport to="#header-accompanying_course-details #banner-persons-associated">
<persons-associated
:accompanying-course="accompanyingCourse"
:shortlist="false"
/>
</teleport>
</template>
<script>
@@ -135,30 +110,30 @@ import SocialIssue from "./Banner/SocialIssue.vue";
import PersonsAssociated from "./Banner/PersonsAssociated.vue";
export default {
name: "Banner",
components: {
ToggleFlags,
SocialIssue,
PersonsAssociated,
},
computed: {
accompanyingCourse() {
return this.$store.state.accompanyingCourse;
},
name: "Banner",
components: {
ToggleFlags,
SocialIssue,
PersonsAssociated,
},
computed: {
accompanyingCourse() {
return this.$store.state.accompanyingCourse;
},
},
};
</script>
<style lang="scss">
div#banner-flags,
div#banner-status {
.badge {
text-transform: uppercase;
}
.badge {
text-transform: uppercase;
}
}
div#banner-status {
span.badge {
font-size: 90%;
}
span.badge {
font-size: 90%;
}
}
</style>

View File

@@ -1,129 +1,127 @@
<template>
<span v-if="shortlist">
<span v-for="person in firstPersons" class="me-1" :key="person.id">
<on-the-fly
:type="person.type"
:id="person.id"
:buttonText="person.textAge"
:displayBadge="'true' === 'true'"
action="show"
></on-the-fly>
</span>
<span v-if="hasMoreThanShortListPerson">
<a
class="showMore carousel-control"
role="button"
data-bs-target="#ACHeaderSlider"
data-bs-slide="next"
>{{ $t("more_x", { x: countMoreThanShortListPerson }) }}</a
>
</span>
<span v-if="shortlist">
<span v-for="person in firstPersons" class="me-1" :key="person.id">
<on-the-fly
:type="person.type"
:id="person.id"
:buttonText="person.textAge"
:displayBadge="'true' === 'true'"
action="show"
></on-the-fly>
</span>
<span v-else>
<span
v-for="([pk, persons], h) in personsByHousehold"
:class="{ household: pk > -1, 'no-household': pk === -1 }"
:key="h.id"
>
<a v-if="pk !== -1" :href="householdLink(pk)">
<i
class="fa fa-home fa-fw text-light"
:title="
$t('persons_associated.show_household_number', {
id: pk,
})
"
></i>
</a>
<span v-for="person in persons" class="me-1" :key="person.id">
<on-the-fly
:type="person.type"
:id="person.id"
:buttonText="person.textAge"
:displayBadge="true"
action="show"
></on-the-fly>
</span>
</span>
<span v-if="hasMoreThanShortListPerson">
<a
class="showMore carousel-control"
role="button"
data-bs-target="#ACHeaderSlider"
data-bs-slide="next"
>{{ $t("more_x", { x: countMoreThanShortListPerson }) }}</a
>
</span>
</span>
<span v-else>
<span
v-for="([pk, persons], h) in personsByHousehold"
:class="{ household: pk > -1, 'no-household': pk === -1 }"
:key="h.id"
>
<a v-if="pk !== -1" :href="householdLink(pk)">
<i
class="fa fa-home fa-fw text-light"
:title="
$t('persons_associated.show_household_number', {
id: pk,
})
"
></i>
</a>
<span v-for="person in persons" class="me-1" :key="person.id">
<on-the-fly
:type="person.type"
:id="person.id"
:buttonText="person.textAge"
:displayBadge="true"
action="show"
></on-the-fly>
</span>
</span>
</span>
</template>
<script>
import OnTheFly from "ChillMainAssets/vuejs/OnTheFly/components/OnTheFly";
export default {
name: "PersonsAssociated",
components: {
OnTheFly,
name: "PersonsAssociated",
components: {
OnTheFly,
},
props: ["accompanyingCourse", "shortlist"],
data() {
return {
showAllPersons: false,
maxTotalPersons: 2,
nbShortList: 3,
};
},
computed: {
participations() {
return this.accompanyingCourse.participations.filter(
(p) => p.endDate === null,
);
},
props: ["accompanyingCourse", "shortlist"],
data() {
return {
showAllPersons: false,
maxTotalPersons: 2,
nbShortList: 3,
};
persons() {
return this.participations.map((p) => p.person);
},
computed: {
participations() {
return this.accompanyingCourse.participations.filter(
(p) => p.endDate === null,
);
},
persons() {
return this.participations.map((p) => p.person);
},
firstPersons() {
return this.participations.slice(0, 3).map((p) => p.person);
},
hasMoreThanShortListPerson() {
return this.participations.length > 3;
},
countMoreThanShortListPerson() {
return this.participations.length - 3;
},
resources() {
return this.accompanyingCourse.resources;
},
requestor() {
return this.accompanyingCourse.requestor;
},
personsByHousehold() {
const households = new Map();
this.accompanyingCourse.participations
.filter((part) => part.endDate === null)
.map((part) => part.person)
.forEach((person) => {
if (!households.has(person.current_household_id || -1)) {
households.set(person.current_household_id || -1, []);
}
households
.get(person.current_household_id || -1)
.push(person);
});
firstPersons() {
return this.participations.slice(0, 3).map((p) => p.person);
},
hasMoreThanShortListPerson() {
return this.participations.length > 3;
},
countMoreThanShortListPerson() {
return this.participations.length - 3;
},
resources() {
return this.accompanyingCourse.resources;
},
requestor() {
return this.accompanyingCourse.requestor;
},
personsByHousehold() {
const households = new Map();
this.accompanyingCourse.participations
.filter((part) => part.endDate === null)
.map((part) => part.person)
.forEach((person) => {
if (!households.has(person.current_household_id || -1)) {
households.set(person.current_household_id || -1, []);
}
households.get(person.current_household_id || -1).push(person);
});
return households;
},
return households;
},
methods: {
householdLink(id) {
return `/fr/person/household/${id}/summary`;
},
},
methods: {
householdLink(id) {
return `/fr/person/household/${id}/summary`;
},
},
};
</script>
<style lang="scss" scoped>
.showMore {
cursor: pointer;
color: white;
cursor: pointer;
color: white;
}
span.household {
display: inline-block;
border-top: 1px solid rgba(255, 255, 255, 0.3);
background-color: rgba(255, 255, 255, 0.1);
border-radius: 10px;
margin-right: 0.3em;
padding: 5px;
display: inline-block;
border-top: 1px solid rgba(255, 255, 255, 0.3);
background-color: rgba(255, 255, 255, 0.1);
border-radius: 10px;
margin-right: 0.3em;
padding: 5px;
}
</style>

View File

@@ -1,11 +1,11 @@
<template>
<span class="badge bg-chill-l-gray text-dark">{{ issue.text }}</span>
<span class="badge bg-chill-l-gray text-dark">{{ issue.text }}</span>
</template>
<script>
export default {
name: "SocialIssues",
props: ["issue"],
name: "SocialIssues",
props: ["issue"],
};
</script>
@@ -14,9 +14,9 @@ export default {
@import "ChillPersonAssets/chill/scss/mixins";
@import "ChillMainAssets/chill/scss/chill_variables";
span.badge {
@include badge_social($social-issue-color);
font-size: 95%;
margin-bottom: 5px;
margin-right: 1em;
@include badge_social($social-issue-color);
font-size: 95%;
margin-bottom: 5px;
margin-right: 1em;
}
</style>

View File

@@ -1,158 +1,145 @@
<template>
<div class="text-md-end">
<span class="d-block d-sm-inline-block mb-md-2">
<a @click="toggleIntensity" class="flag-toggle">
<span :class="{ on: !isRegular }">{{
$t("course.occasional")
}}</span>
<i
class="fa"
:class="{
'fa-toggle-on': isRegular,
'fa-toggle-on fa-flip-horizontal': !isRegular,
}"
/>
<span :class="{ on: isRegular }">{{
$t("course.regular")
}}</span>
</a>
</span>
<div class="text-md-end">
<span class="d-block d-sm-inline-block mb-md-2">
<a @click="toggleIntensity" class="flag-toggle">
<span :class="{ on: !isRegular }">{{ $t("course.occasional") }}</span>
<i
class="fa"
:class="{
'fa-toggle-on': isRegular,
'fa-toggle-on fa-flip-horizontal': !isRegular,
}"
/>
<span :class="{ on: isRegular }">{{ $t("course.regular") }}</span>
</a>
</span>
<span class="d-block d-sm-inline-block ms-sm-3 ms-md-0">
<button
class="badge rounded-pill me-1"
:class="{
'bg-danger': isEmergency,
'bg-secondary': !isEmergency,
}"
@click="toggleEmergency"
>
{{ $t("course.emergency") }}
</button>
<button
class="badge rounded-pill"
:class="{
'bg-danger': isConfidential,
'bg-secondary': !isConfidential,
}"
@click="toggleConfidential"
>
{{ $t("course.confidential") }}
</button>
</span>
</div>
<span class="d-block d-sm-inline-block ms-sm-3 ms-md-0">
<button
class="badge rounded-pill me-1"
:class="{
'bg-danger': isEmergency,
'bg-secondary': !isEmergency,
}"
@click="toggleEmergency"
>
{{ $t("course.emergency") }}
</button>
<button
class="badge rounded-pill"
:class="{
'bg-danger': isConfidential,
'bg-secondary': !isConfidential,
}"
@click="toggleConfidential"
>
{{ $t("course.confidential") }}
</button>
</span>
</div>
</template>
<script>
import { mapState } from "vuex";
export default {
name: "ToggleFlags",
computed: {
...mapState({
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;
},
isEmergency() {
return this.emergency ? true : false;
},
isConfidential() {
return this.confidential ? true : false;
},
name: "ToggleFlags",
computed: {
...mapState({
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;
},
methods: {
toggleIntensity() {
let value;
switch (this.intensity) {
case "occasional":
value = "regular";
break;
case "regular":
value = "occasional";
break;
default:
//temporaire (modif backend)
value = "occasional";
}
this.$store.dispatch("toggleIntensity", value).catch(({ name }) => {
if (
name === "ValidationException" ||
name === "AccessException"
) {
this.$toast.open({
message: this.$t(
"Only the referrer can toggle the intensity of an accompanying course",
),
});
} else {
this.$toast.open({ message: "An error occurred" });
}
});
},
toggleEmergency() {
this.$store
.dispatch("toggleEmergency", !this.isEmergency)
.catch(({ name, violations }) => {
if (
name === "ValidationException" ||
name === "AccessException"
) {
violations.forEach((violation) =>
this.$toast.open({ message: violation }),
);
} else {
this.$toast.open({ message: "An error occurred" });
}
});
},
toggleConfidential() {
this.$store.dispatch("toggleConfidential").catch(({ name }) => {
console.log(name);
if (
name === "ValidationException" ||
name === "AccessException"
) {
this.$toast.open({
message: this.$t(
"Only the referrer can toggle the confidentiality of an accompanying course",
),
});
} else {
this.$toast.open({ message: "An error occurred" });
}
});
},
isEmergency() {
return this.emergency ? true : false;
},
isConfidential() {
return this.confidential ? true : false;
},
},
methods: {
toggleIntensity() {
let value;
switch (this.intensity) {
case "occasional":
value = "regular";
break;
case "regular":
value = "occasional";
break;
default:
//temporaire (modif backend)
value = "occasional";
}
this.$store.dispatch("toggleIntensity", value).catch(({ name }) => {
if (name === "ValidationException" || name === "AccessException") {
this.$toast.open({
message: this.$t(
"Only the referrer can toggle the intensity of an accompanying course",
),
});
} else {
this.$toast.open({ message: "An error occurred" });
}
});
},
toggleEmergency() {
this.$store
.dispatch("toggleEmergency", !this.isEmergency)
.catch(({ name, violations }) => {
if (name === "ValidationException" || name === "AccessException") {
violations.forEach((violation) =>
this.$toast.open({ message: violation }),
);
} else {
this.$toast.open({ message: "An error occurred" });
}
});
},
toggleConfidential() {
this.$store.dispatch("toggleConfidential").catch(({ name }) => {
console.log(name);
if (name === "ValidationException" || name === "AccessException") {
this.$toast.open({
message: this.$t(
"Only the referrer can toggle the confidentiality of an accompanying course",
),
});
} else {
this.$toast.open({ message: "An error occurred" });
}
});
},
},
};
</script>
<style lang="scss" scoped>
a.flag-toggle {
color: white;
cursor: pointer;
&:hover {
color: white;
cursor: pointer;
&:hover {
color: white;
text-decoration: underline;
border-radius: 20px;
}
i {
margin: auto 0.4em;
}
span.on {
font-weight: bolder;
}
text-decoration: underline;
border-radius: 20px;
}
i {
margin: auto 0.4em;
}
span.on {
font-weight: bolder;
}
}
button.badge {
&.bg-secondary {
opacity: 0.5;
&:hover {
opacity: 0.7;
}
&.bg-secondary {
opacity: 0.5;
&:hover {
opacity: 0.7;
}
}
}
</style>

View File

@@ -1,38 +1,36 @@
<template>
<li>
<button
class="btn btn-sm btn-secondary"
@click="modal.showModal = true"
:title="$t('courselocation.assign_course_address')"
>
<i class="fa fa-map-marker" />
</button>
</li>
<li>
<button
class="btn btn-sm btn-secondary"
@click="modal.showModal = true"
:title="$t('courselocation.assign_course_address')"
>
<i class="fa fa-map-marker" />
</button>
</li>
<teleport to="body">
<modal
v-if="modal.showModal"
:modal-dialog-class="modal.modalDialogClass"
@close="modal.showModal = false"
>
<template #header>
<h2 class="modal-title">
{{ $t("courselocation.sure") }}
</h2>
</template>
<template #body>
<address-render-box
:address="person.current_household_address"
/>
<p>{{ $t("courselocation.sure_description") }}</p>
</template>
<template #footer>
<button class="btn btn-danger" @click="assignAddress">
{{ $t("courselocation.ok") }}
</button>
</template>
</modal>
</teleport>
<teleport to="body">
<modal
v-if="modal.showModal"
:modal-dialog-class="modal.modalDialogClass"
@close="modal.showModal = false"
>
<template #header>
<h2 class="modal-title">
{{ $t("courselocation.sure") }}
</h2>
</template>
<template #body>
<address-render-box :address="person.current_household_address" />
<p>{{ $t("courselocation.sure_description") }}</p>
</template>
<template #footer>
<button class="btn btn-danger" @click="assignAddress">
{{ $t("courselocation.ok") }}
</button>
</template>
</modal>
</teleport>
</template>
<script>
@@ -41,52 +39,49 @@ import Modal from "ChillMainAssets/vuejs/_components/Modal";
import AddressRenderBox from "ChillMainAssets/vuejs/_components/Entity/AddressRenderBox.vue";
export default {
name: "ButtonLocation",
components: {
AddressRenderBox,
Modal,
},
props: ["person"],
data() {
return {
modal: {
showModal: false,
modalDialogClass: "modal-dialog-centered modal-md",
},
};
},
computed: {
...mapState({
context: (state) => state.addressContext,
}),
},
methods: {
assignAddress() {
//console.log('assignAddress id', this.person.current_household_address);
let payload = {
target: this.context.target.name,
targetId: this.context.target.id,
locationStatusTo: "person",
personId: this.person.id,
};
this.$store
.dispatch("updateLocation", payload)
.catch(({ name, violations }) => {
if (
name === "ValidationException" ||
name === "AccessException"
) {
violations.forEach((violation) =>
this.$toast.open({ message: violation }),
);
} else {
this.$toast.open({ message: "An error occurred" });
}
});
name: "ButtonLocation",
components: {
AddressRenderBox,
Modal,
},
props: ["person"],
data() {
return {
modal: {
showModal: false,
modalDialogClass: "modal-dialog-centered modal-md",
},
};
},
computed: {
...mapState({
context: (state) => state.addressContext,
}),
},
methods: {
assignAddress() {
//console.log('assignAddress id', this.person.current_household_address);
let payload = {
target: this.context.target.name,
targetId: this.context.target.id,
locationStatusTo: "person",
personId: this.person.id,
};
this.$store
.dispatch("updateLocation", payload)
.catch(({ name, violations }) => {
if (name === "ValidationException" || name === "AccessException") {
violations.forEach((violation) =>
this.$toast.open({ message: violation }),
);
} else {
this.$toast.open({ message: "An error occurred" });
}
});
window.location.assign("#section-20");
this.modal.showModal = false;
},
window.location.assign("#section-20");
this.modal.showModal = false;
},
},
};
</script>

View File

@@ -1,56 +1,56 @@
<template>
<div class="vue-component">
<h2><a id="section-100" />{{ $t("comment.title") }}</h2>
<div class="vue-component">
<h2><a id="section-100" />{{ $t("comment.title") }}</h2>
<!--div class="error flash_message" v-if="errors.length > 0">
<!--div class="error flash_message" v-if="errors.length > 0">
{{ errors[0] }}
TODO fix errors flashbag for app component
</div-->
<div>
<form @submit.prevent="submitform">
<label class="col-form-label" for="content">{{
$t("comment.label")
}}</label>
<div>
<form @submit.prevent="submitform">
<label class="col-form-label" for="content">{{
$t("comment.label")
}}</label>
<comment-editor v-model="content" />
<comment-editor v-model="content" />
<div class="sub-comment">
<div
v-if="
pinnedComment !== null &&
typeof pinnedComment.creator !== 'undefined'
"
class="metadata"
>
{{
$t("comment.created_by", [
pinnedComment.creator.text,
$d(pinnedComment.updatedAt.datetime, "long"),
])
}}
</div>
<div class="loading">
<i
v-if="loading"
class="fa fa-circle-o-notch fa-spin"
:title="$t('loading')"
/>
</div>
</div>
<div>
<ul class="record_actions">
<li v-if="pinnedComment !== null">
<a class="btn btn-delete" @click="removeComment">
{{ $t("action.delete") }}
</a>
</li>
</ul>
</div>
</form>
<div class="sub-comment">
<div
v-if="
pinnedComment !== null &&
typeof pinnedComment.creator !== 'undefined'
"
class="metadata"
>
{{
$t("comment.created_by", [
pinnedComment.creator.text,
$d(pinnedComment.updatedAt.datetime, "long"),
])
}}
</div>
<div class="loading">
<i
v-if="loading"
class="fa fa-circle-o-notch fa-spin"
:title="$t('loading')"
/>
</div>
</div>
<div>
<ul class="record_actions">
<li v-if="pinnedComment !== null">
<a class="btn btn-delete" @click="removeComment">
{{ $t("action.delete") }}
</a>
</li>
</ul>
</div>
</form>
</div>
</div>
</template>
<script>
@@ -58,127 +58,121 @@ import CommentEditor from "ChillMainAssets/vuejs/_components/CommentEditor/Comme
import { mapState } from "vuex";
export default {
name: "Comment",
components: {
CommentEditor,
},
data() {
return {
loading: false,
lastRecordedContent: null,
};
},
computed: {
...mapState({
pinnedComment: (state) => state.accompanyingCourse.pinnedComment,
}),
classicEditor: () => ClassicEditor,
editorConfig: () => classicEditorConfig,
content: {
set(value) {
console.log("new comment value", value);
console.log("previous value", this.lastRecordedContent);
this.lastRecordedContent = value;
name: "Comment",
components: {
CommentEditor,
},
data() {
return {
loading: false,
lastRecordedContent: null,
};
},
computed: {
...mapState({
pinnedComment: (state) => state.accompanyingCourse.pinnedComment,
}),
classicEditor: () => ClassicEditor,
editorConfig: () => classicEditorConfig,
content: {
set(value) {
console.log("new comment value", value);
console.log("previous value", this.lastRecordedContent);
this.lastRecordedContent = value;
setTimeout(() => {
console.log("performing test on ", value);
if (this.lastRecordedContent === value) {
this.loading = true;
if (value !== "") {
this.$store
.dispatch("updatePinnedComment", value)
.then(() => {
this.loading = false;
})
.catch(({ name, violations }) => {
if (
name === "ValidationException" ||
name === "AccessException"
) {
violations.forEach((violation) =>
this.$toast.open({
message: violation,
}),
);
} else {
this.$toast.open({
message: "An error occurred",
});
}
});
} else {
if (
this.$store.state.accompanyingCourse
.pinnedComment !== null
) {
this.$store
.dispatch("removePinnedComment", {
id: this.pinnedComment.id,
})
.then(() => {
this.loading = false;
this.lastRecoredContent = null;
})
.catch(({ name, violations }) => {
if (
name === "ValidationException" ||
name === "AccessException"
) {
violations.forEach((violation) =>
this.$toast.open({
message: violation,
}),
);
} else {
this.$toast.open({
message: "An error occurred",
});
}
});
}
}
}
}, 3000);
},
get() {
return this.pinnedComment ? this.pinnedComment.content : "";
},
},
errors() {
return this.$store.state.errorMsg;
},
},
methods: {
removeComment() {
this.$store
.dispatch("removePinnedComment", { id: this.pinnedComment.id })
setTimeout(() => {
console.log("performing test on ", value);
if (this.lastRecordedContent === value) {
this.loading = true;
if (value !== "") {
this.$store
.dispatch("updatePinnedComment", value)
.then(() => {
this.loading = false;
})
.catch(({ name, violations }) => {
if (
name === "ValidationException" ||
name === "AccessException"
) {
violations.forEach((violation) =>
this.$toast.open({ message: violation }),
);
} else {
this.$toast.open({ message: "An error occurred" });
}
if (
name === "ValidationException" ||
name === "AccessException"
) {
violations.forEach((violation) =>
this.$toast.open({
message: violation,
}),
);
} else {
this.$toast.open({
message: "An error occurred",
});
}
});
},
} else {
if (this.$store.state.accompanyingCourse.pinnedComment !== null) {
this.$store
.dispatch("removePinnedComment", {
id: this.pinnedComment.id,
})
.then(() => {
this.loading = false;
this.lastRecoredContent = null;
})
.catch(({ name, violations }) => {
if (
name === "ValidationException" ||
name === "AccessException"
) {
violations.forEach((violation) =>
this.$toast.open({
message: violation,
}),
);
} else {
this.$toast.open({
message: "An error occurred",
});
}
});
}
}
}
}, 3000);
},
get() {
return this.pinnedComment ? this.pinnedComment.content : "";
},
},
errors() {
return this.$store.state.errorMsg;
},
},
methods: {
removeComment() {
this.$store
.dispatch("removePinnedComment", { id: this.pinnedComment.id })
.catch(({ name, violations }) => {
if (name === "ValidationException" || name === "AccessException") {
violations.forEach((violation) =>
this.$toast.open({ message: violation }),
);
} else {
this.$toast.open({ message: "An error occurred" });
}
});
},
},
};
</script>
<style lang="scss">
div.ck-editor.ck-reset {
margin: 0.6em 0;
margin: 0.6em 0;
}
div.sub-comment {
display: flex;
justify-content: space-between;
div.loading {
margin-right: 6px;
margin-left: 6px;
}
display: flex;
justify-content: space-between;
div.loading {
margin-right: 6px;
margin-left: 6px;
}
}
</style>

View File

@@ -1,127 +1,120 @@
<template>
<div class="vue-component">
<h2>
<a id="section-110" />
{{ $t("confirm.title") }}
</h2>
<div>
<p v-html="$t('confirm.text_draft', [$t('course.step.draft')])" />
<div class="vue-component">
<h2>
<a id="section-110" />
{{ $t("confirm.title") }}
</h2>
<div>
<p v-html="$t('confirm.text_draft', [$t('course.step.draft')])" />
<div v-if="!isValidToBeConfirmed">
<div class="alert alert-warning">
{{ $t("confirm.alert_validation") }}
<ul class="mt-2">
<li v-for="k in validationKeys" :key="k">
{{ $t(notValidMessages[k].msg) }}
<a :href="notValidMessages[k].anchor">
<i class="fa fa-level-up fa-fw" />
</a>
</li>
</ul>
</div>
<ul class="record_actions">
<li>
<button class="btn btn-save" disabled>
{{ $t("confirm.ok") }}
</button>
</li>
<li>
<a class="btn btn-delete" :href="deleteLink">
{{ $t("confirm.delete") }}
</a>
</li>
</ul>
</div>
<div v-else>
<p
v-html="
$t('confirm.text_active', [$t('course.step.active')])
"
/>
<ul class="record_actions">
<li>
<button
class="btn btn-save"
@click="modal.showModal = true"
>
{{ $t("confirm.ok") }}
</button>
</li>
<li>
<a class="btn btn-delete" :href="deleteLink">
{{ $t("confirm.delete") }}
</a>
</li>
</ul>
</div>
<div v-if="!isValidToBeConfirmed">
<div class="alert alert-warning">
{{ $t("confirm.alert_validation") }}
<ul class="mt-2">
<li v-for="k in validationKeys" :key="k">
{{ $t(notValidMessages[k].msg) }}
<a :href="notValidMessages[k].anchor">
<i class="fa fa-level-up fa-fw" />
</a>
</li>
</ul>
</div>
<ul class="record_actions">
<li>
<button class="btn btn-save" disabled>
{{ $t("confirm.ok") }}
</button>
</li>
<li>
<a class="btn btn-delete" :href="deleteLink">
{{ $t("confirm.delete") }}
</a>
</li>
</ul>
</div>
<teleport to="body">
<modal
v-if="modal.showModal"
:modal-dialog-class="modal.modalDialogClass"
@close="modal.showModal = false"
>
<template #header>
<h2 class="modal-title">
{{ $t("confirm.sure") }}
</h2>
</template>
<template #body>
<p>{{ $t("confirm.sure_description") }}</p>
<div v-if="accompanyingCourse.user === null">
<div v-if="usersSuggestedFilteredByJob.length === 0">
<p class="alert alert-warning">
{{ $t("confirm.no_suggested_referrer") }}
</p>
</div>
<div
v-if="usersSuggestedFilteredByJob.length === 1"
class="alert alert-info"
>
<p>{{ $t("confirm.one_suggested_referrer") }}:</p>
<ul class="list-suggest add-items inline">
<li>
<user-render-box-badge
:user="usersSuggestedFilteredByJob[0]"
/>
</li>
</ul>
<p>{{ $t("confirm.choose_suggested_referrer") }}</p>
<ul class="record_actions">
<li>
<button
class="btn btn-save mr-5"
@click="chooseSuggestedReferrer"
>
{{ $t("confirm.choose_button") }}
</button>
</li>
<li>
<button
class="btn btn-secondary"
@click="doNotChooseSuggestedReferrer"
>
{{ $t("confirm.do_not_choose_button") }}
</button>
</li>
</ul>
</div>
</div>
</template>
<template #footer>
<button
class="btn btn-danger"
:disabled="disableConfirm"
@click="confirmCourse"
>
{{ $t("confirm.ok") }}
</button>
</template>
</modal>
</teleport>
<div v-else>
<p v-html="$t('confirm.text_active', [$t('course.step.active')])" />
<ul class="record_actions">
<li>
<button class="btn btn-save" @click="modal.showModal = true">
{{ $t("confirm.ok") }}
</button>
</li>
<li>
<a class="btn btn-delete" :href="deleteLink">
{{ $t("confirm.delete") }}
</a>
</li>
</ul>
</div>
</div>
<teleport to="body">
<modal
v-if="modal.showModal"
:modal-dialog-class="modal.modalDialogClass"
@close="modal.showModal = false"
>
<template #header>
<h2 class="modal-title">
{{ $t("confirm.sure") }}
</h2>
</template>
<template #body>
<p>{{ $t("confirm.sure_description") }}</p>
<div v-if="accompanyingCourse.user === null">
<div v-if="usersSuggestedFilteredByJob.length === 0">
<p class="alert alert-warning">
{{ $t("confirm.no_suggested_referrer") }}
</p>
</div>
<div
v-if="usersSuggestedFilteredByJob.length === 1"
class="alert alert-info"
>
<p>{{ $t("confirm.one_suggested_referrer") }}:</p>
<ul class="list-suggest add-items inline">
<li>
<user-render-box-badge
:user="usersSuggestedFilteredByJob[0]"
/>
</li>
</ul>
<p>{{ $t("confirm.choose_suggested_referrer") }}</p>
<ul class="record_actions">
<li>
<button
class="btn btn-save mr-5"
@click="chooseSuggestedReferrer"
>
{{ $t("confirm.choose_button") }}
</button>
</li>
<li>
<button
class="btn btn-secondary"
@click="doNotChooseSuggestedReferrer"
>
{{ $t("confirm.do_not_choose_button") }}
</button>
</li>
</ul>
</div>
</div>
</template>
<template #footer>
<button
class="btn btn-danger"
:disabled="disableConfirm"
@click="confirmCourse"
>
{{ $t("confirm.ok") }}
</button>
</template>
</modal>
</teleport>
</div>
</template>
<script>
@@ -130,112 +123,106 @@ import Modal from "ChillMainAssets/vuejs/_components/Modal";
import UserRenderBoxBadge from "ChillMainAssets/vuejs/_components/Entity/UserRenderBoxBadge";
export default {
name: "Confirm",
components: {
Modal,
UserRenderBoxBadge,
},
data() {
return {
modal: {
showModal: false,
modalDialogClass: "modal-dialog-centered modal-md",
},
notValidMessages: {
participation: {
msg: "confirm.participation_not_valid",
anchor: "#section-10",
},
location: {
msg: "confirm.location_not_valid",
anchor: "#section-20",
},
origin: {
msg: "confirm.origin_not_valid",
anchor: "#section-30",
},
adminLocation: {
msg: "confirm.adminLocation_not_valid",
anchor: "#section-40",
},
socialIssue: {
msg: "confirm.socialIssue_not_valid",
anchor: "#section-60",
},
scopes: {
msg: "confirm.set_a_scope",
anchor: "#section-70",
},
job: {
msg: "confirm.job_not_valid",
anchor: "#section-80",
},
},
clickedDoNotChooseReferrer: false,
};
},
computed: {
...mapState({
accompanyingCourse: (state) => state.accompanyingCourse,
}),
...mapGetters([
"isParticipationValid",
"isSocialIssueValid",
"isOriginValid",
"isAdminLocationValid",
"isLocationValid",
"isJobValid",
"validationKeys",
"isValidToBeConfirmed",
"usersSuggestedFilteredByJob",
]),
deleteLink() {
return `/fr/parcours/${this.accompanyingCourse.id}/delete`; //TODO locale
name: "Confirm",
components: {
Modal,
UserRenderBoxBadge,
},
data() {
return {
modal: {
showModal: false,
modalDialogClass: "modal-dialog-centered modal-md",
},
notValidMessages: {
participation: {
msg: "confirm.participation_not_valid",
anchor: "#section-10",
},
disableConfirm() {
return (
this.accompanyingCourse.user === null &&
this.usersSuggestedFilteredByJob.length === 1 &&
this.clickedDoNotChooseReferrer === false
location: {
msg: "confirm.location_not_valid",
anchor: "#section-20",
},
origin: {
msg: "confirm.origin_not_valid",
anchor: "#section-30",
},
adminLocation: {
msg: "confirm.adminLocation_not_valid",
anchor: "#section-40",
},
socialIssue: {
msg: "confirm.socialIssue_not_valid",
anchor: "#section-60",
},
scopes: {
msg: "confirm.set_a_scope",
anchor: "#section-70",
},
job: {
msg: "confirm.job_not_valid",
anchor: "#section-80",
},
},
clickedDoNotChooseReferrer: false,
};
},
computed: {
...mapState({
accompanyingCourse: (state) => state.accompanyingCourse,
}),
...mapGetters([
"isParticipationValid",
"isSocialIssueValid",
"isOriginValid",
"isAdminLocationValid",
"isLocationValid",
"isJobValid",
"validationKeys",
"isValidToBeConfirmed",
"usersSuggestedFilteredByJob",
]),
deleteLink() {
return `/fr/parcours/${this.accompanyingCourse.id}/delete`; //TODO locale
},
disableConfirm() {
return (
this.accompanyingCourse.user === null &&
this.usersSuggestedFilteredByJob.length === 1 &&
this.clickedDoNotChooseReferrer === false
);
},
},
methods: {
confirmCourse() {
this.$store
.dispatch("confirmAccompanyingCourse")
.catch(({ name, violations }) => {
if (name === "ValidationException" || name === "AccessException") {
violations.forEach((violation) =>
this.$toast.open({ message: violation }),
);
},
} else {
this.$toast.open({ message: "An error occurred" });
}
});
},
methods: {
confirmCourse() {
this.$store
.dispatch("confirmAccompanyingCourse")
.catch(({ name, violations }) => {
if (
name === "ValidationException" ||
name === "AccessException"
) {
violations.forEach((violation) =>
this.$toast.open({ message: violation }),
);
} else {
this.$toast.open({ message: "An error occurred" });
}
});
},
chooseSuggestedReferrer() {
this.$store
.dispatch("updateReferrer", this.usersSuggestedFilteredByJob[0])
.catch(({ name, violations }) => {
if (
name === "ValidationException" ||
name === "AccessException"
) {
violations.forEach((violation) =>
this.$toast.open({ message: violation }),
);
} else {
this.$toast.open({ message: "An error occurred" });
}
});
},
doNotChooseSuggestedReferrer() {
this.clickedDoNotChooseReferrer = true;
},
chooseSuggestedReferrer() {
this.$store
.dispatch("updateReferrer", this.usersSuggestedFilteredByJob[0])
.catch(({ name, violations }) => {
if (name === "ValidationException" || name === "AccessException") {
violations.forEach((violation) =>
this.$toast.open({ message: violation }),
);
} else {
this.$toast.open({ message: "An error occurred" });
}
});
},
doNotChooseSuggestedReferrer() {
this.clickedDoNotChooseReferrer = true;
},
},
};
</script>

View File

@@ -1,95 +1,85 @@
<template>
<div class="vue-component">
<h2>
<a id="section-20" />
{{ $t("courselocation.title") }}
</h2>
<div class="vue-component">
<h2>
<a id="section-20" />
{{ $t("courselocation.title") }}
</h2>
<div
v-for="error in displayErrors"
class="alert alert-danger my-2"
:key="error"
>
{{ error }}
</div>
<div v-if="hasNoLocation">
<label class="chill-no-data-statement">
{{ $t("courselocation.no_address") }}
</label>
</div>
<div class="flex-table" v-if="accompanyingCourse.location">
<div class="item-bloc">
<address-render-box :address="accompanyingCourse.location" />
<div
v-if="isPersonLocation"
class="alert alert-secondary separator"
>
<label class="col-form-label">
{{
$t("courselocation.person_locator", [
accompanyingCourse.personLocation.text,
])
}}
</label>
</div>
<div
v-if="isTemporaryAddress"
class="alert alert-warning separator"
>
<p>
{{
$t(
"courselocation.temporary_address_must_be_changed",
)
}}
<i class="fa fa-fw fa-map-marker" />
</p>
</div>
</div>
</div>
<div
v-if="hasNoPersonLocation"
class="alert alert-danger no-person-location"
>
<i class="fa fa-warning fa-2x" />
<div>
<p>
{{
$t(
"courselocation.associate_at_least_one_person_with_one_household_with_address",
)
}}
<a href="#section-10">
<i class="fa fa-level-up fa-fw" />
</a>
</p>
</div>
</div>
<div>
<ul class="record_actions">
<li>
<add-address
v-if="!isPersonLocation"
:key="key"
:context="context"
:options="options"
:address-changed-callback="submitTemporaryAddress"
ref="addAddress"
/>
</li>
</ul>
</div>
<div v-if="!isLocationValid" class="alert alert-warning to-confirm">
{{ $t("courselocation.not_valid") }}
</div>
<div
v-for="error in displayErrors"
class="alert alert-danger my-2"
:key="error"
>
{{ error }}
</div>
<div v-if="hasNoLocation">
<label class="chill-no-data-statement">
{{ $t("courselocation.no_address") }}
</label>
</div>
<div class="flex-table" v-if="accompanyingCourse.location">
<div class="item-bloc">
<address-render-box :address="accompanyingCourse.location" />
<div v-if="isPersonLocation" class="alert alert-secondary separator">
<label class="col-form-label">
{{
$t("courselocation.person_locator", [
accompanyingCourse.personLocation.text,
])
}}
</label>
</div>
<div v-if="isTemporaryAddress" class="alert alert-warning separator">
<p>
{{ $t("courselocation.temporary_address_must_be_changed") }}
<i class="fa fa-fw fa-map-marker" />
</p>
</div>
</div>
</div>
<div
v-if="hasNoPersonLocation"
class="alert alert-danger no-person-location"
>
<i class="fa fa-warning fa-2x" />
<div>
<p>
{{
$t(
"courselocation.associate_at_least_one_person_with_one_household_with_address",
)
}}
<a href="#section-10">
<i class="fa fa-level-up fa-fw" />
</a>
</p>
</div>
</div>
<div>
<ul class="record_actions">
<li>
<add-address
v-if="!isPersonLocation"
:key="key"
:context="context"
:options="options"
:address-changed-callback="submitTemporaryAddress"
ref="addAddress"
/>
</li>
</ul>
</div>
<div v-if="!isLocationValid" class="alert alert-warning to-confirm">
{{ $t("courselocation.not_valid") }}
</div>
</div>
</template>
<script>
@@ -98,177 +88,171 @@ import AddAddress from "ChillMainAssets/vuejs/Address/components/AddAddress.vue"
import AddressRenderBox from "ChillMainAssets/vuejs/_components/Entity/AddressRenderBox.vue";
export default {
name: "CourseLocation",
components: {
AddAddress,
AddressRenderBox,
},
data() {
return {
addAddress: {
options: {
button: {
text: {
create: "courselocation.add_temporary_address",
edit: "courselocation.edit_temporary_address",
},
},
title: {
create: "courselocation.add_temporary_address",
edit: "courselocation.edit_temporary_address",
},
onlyButton: true,
},
name: "CourseLocation",
components: {
AddAddress,
AddressRenderBox,
},
data() {
return {
addAddress: {
options: {
button: {
text: {
create: "courselocation.add_temporary_address",
edit: "courselocation.edit_temporary_address",
},
};
},
title: {
create: "courselocation.add_temporary_address",
edit: "courselocation.edit_temporary_address",
},
onlyButton: true,
},
},
};
},
computed: {
...mapState({
accompanyingCourse: (state) => state.accompanyingCourse,
context: (state) => state.addressContext,
}),
...mapGetters(["isLocationValid"]),
options() {
return this.addAddress.options;
},
computed: {
...mapState({
accompanyingCourse: (state) => state.accompanyingCourse,
context: (state) => state.addressContext,
}),
...mapGetters(["isLocationValid"]),
options() {
return this.addAddress.options;
key() {
return this.context.edit
? "address_" + this.context.addressId
: this.accompanyingCourse.type + "_" + this.accompanyingCourse.id;
},
isTemporaryAddress() {
return this.accompanyingCourse.locationStatus === "address";
},
isPersonLocation() {
return this.accompanyingCourse.locationStatus === "person";
},
hasNoLocation() {
return this.accompanyingCourse.locationStatus === "none";
},
currentParticipations() {
return this.accompanyingCourse.participations.filter(
(p) => p.enddate !== null,
);
},
hasNoPersonLocation() {
let addressInParticipations_ = [];
this.currentParticipations.forEach((p) => {
addressInParticipations_.push(
this.checkHouseholdAddressForParticipation(p),
);
});
const booleanReducer = (previousValue, currentValue) =>
previousValue || currentValue;
let addressInParticipations =
addressInParticipations_.length > 0
? addressInParticipations_.reduce(booleanReducer)
: false;
//console.log(addressInParticipations_, addressInParticipations);
return (
this.accompanyingCourse.step !== "DRAFT" &&
this.isTemporaryAddress &&
!addressInParticipations
);
},
isContextEdit() {
return this.context.edit;
},
},
methods: {
checkHouseholdAddressForParticipation(participation) {
if (participation.person.current_household_id === null) {
return false;
}
return participation.person.current_household_address !== null;
},
initAddressContext() {
let context = {
target: {
name: this.accompanyingCourse.type,
id: this.accompanyingCourse.id,
},
key() {
return this.context.edit
? "address_" + this.context.addressId
: this.accompanyingCourse.type +
"_" +
this.accompanyingCourse.id;
},
isTemporaryAddress() {
return this.accompanyingCourse.locationStatus === "address";
},
isPersonLocation() {
return this.accompanyingCourse.locationStatus === "person";
},
hasNoLocation() {
return this.accompanyingCourse.locationStatus === "none";
},
currentParticipations() {
return this.accompanyingCourse.participations.filter(
(p) => p.enddate !== null,
edit: false,
addressId: null,
defaults: window.addaddress,
};
if (this.accompanyingCourse.location) {
context["edit"] = true;
context["addressId"] = this.accompanyingCourse.location.address_id;
}
this.$store.commit("setAddressContext", context);
},
displayErrors() {
return this.$refs.addAddress.errorMsg;
},
submitTemporaryAddress(payload) {
//console.log('@@@ click on Submit Temporary Address Button', payload);
payload["locationStatusTo"] = "address"; // <== temporary, not none, not person
this.$store
.dispatch("updateLocation", payload)
.catch(({ name, violations }) => {
if (name === "ValidationException" || name === "AccessException") {
violations.forEach((violation) =>
this.$toast.open({ message: violation }),
);
},
hasNoPersonLocation() {
let addressInParticipations_ = [];
this.currentParticipations.forEach((p) => {
addressInParticipations_.push(
this.checkHouseholdAddressForParticipation(p),
);
});
} else {
this.$toast.open({ message: "An error occurred" });
}
});
const booleanReducer = (previousValue, currentValue) =>
previousValue || currentValue;
let addressInParticipations =
addressInParticipations_.length > 0
? addressInParticipations_.reduce(booleanReducer)
: false;
//console.log(addressInParticipations_, addressInParticipations);
return (
this.accompanyingCourse.step !== "DRAFT" &&
this.isTemporaryAddress &&
!addressInParticipations
);
},
isContextEdit() {
return this.context.edit;
},
this.$store.commit("setEditContextTrue", payload);
},
methods: {
checkHouseholdAddressForParticipation(participation) {
if (participation.person.current_household_id === null) {
return false;
}
return participation.person.current_household_address !== null;
},
initAddressContext() {
let context = {
target: {
name: this.accompanyingCourse.type,
id: this.accompanyingCourse.id,
},
edit: false,
addressId: null,
defaults: window.addaddress,
};
if (this.accompanyingCourse.location) {
context["edit"] = true;
context["addressId"] =
this.accompanyingCourse.location.address_id;
}
this.$store.commit("setAddressContext", context);
},
displayErrors() {
return this.$refs.addAddress.errorMsg;
},
submitTemporaryAddress(payload) {
//console.log('@@@ click on Submit Temporary Address Button', payload);
payload["locationStatusTo"] = "address"; // <== temporary, not none, not person
this.$store
.dispatch("updateLocation", payload)
.catch(({ name, violations }) => {
if (
name === "ValidationException" ||
name === "AccessException"
) {
violations.forEach((violation) =>
this.$toast.open({ message: violation }),
);
} else {
this.$toast.open({ message: "An error occurred" });
}
});
},
created() {
this.initAddressContext();
this.$store.commit("setEditContextTrue", payload);
},
},
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>
<style lang="scss" scoped>
div#accompanying-course {
div.vue-component {
& > div.alert.no-person-location {
margin: 1px 0 0;
}
div.no-person-location {
padding-top: 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;
}
& > div {
flex-basis: auto;
div.action {
button.btn-update {
margin-right: 2em;
}
}
}
}
div.flex-table {
div.item-bloc {
div.alert {
margin: 0 -0.9em -1em;
}
}
}
div.vue-component {
& > div.alert.no-person-location {
margin: 1px 0 0;
}
div.no-person-location {
padding-top: 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;
}
& > div {
flex-basis: auto;
div.action {
button.btn-update {
margin-right: 2em;
}
}
}
}
div.flex-table {
div.item-bloc {
div.alert {
margin: 0 -0.9em -1em;
}
}
}
}
}
</style>

View File

@@ -1,33 +1,33 @@
<template>
<div class="vue-component">
<h2><a id="section-30" />{{ $t("origin.title") }}</h2>
<div class="vue-component">
<h2><a id="section-30" />{{ $t("origin.title") }}</h2>
<div class="mb-4">
<label for="selectOrigin">
{{ $t("origin.title") }}
</label>
<div class="mb-4">
<label for="selectOrigin">
{{ $t("origin.title") }}
</label>
<VueMultiselect
name="selectOrigin"
label="text"
:custom-label="transText"
track-by="id"
:multiple="false"
:searchable="true"
:placeholder="$t('origin.placeholder')"
v-model="value"
:options="options"
:select-label="$t('multiselect.select_label')"
:deselect-label="$t('multiselect.deselect_label')"
:selected-label="$t('multiselect.selected_label')"
@select="updateOrigin"
/>
</div>
<div v-if="!isOriginValid" class="alert alert-warning to-confirm">
{{ $t("origin.not_valid") }}
</div>
<VueMultiselect
name="selectOrigin"
label="text"
:custom-label="transText"
track-by="id"
:multiple="false"
:searchable="true"
:placeholder="$t('origin.placeholder')"
v-model="value"
:options="options"
:select-label="$t('multiselect.select_label')"
:deselect-label="$t('multiselect.deselect_label')"
:selected-label="$t('multiselect.selected_label')"
@select="updateOrigin"
/>
</div>
<div v-if="!isOriginValid" class="alert alert-warning to-confirm">
{{ $t("origin.not_valid") }}
</div>
</div>
</template>
<script>
@@ -36,61 +36,58 @@ import { makeFetch } from "ChillMainAssets/lib/api/apiMethods";
import { mapState, mapGetters } from "vuex";
export default {
name: "OriginDemand",
components: { VueMultiselect },
data() {
return {
options: [],
};
name: "OriginDemand",
components: { VueMultiselect },
data() {
return {
options: [],
};
},
computed: {
...mapState({
value: (state) => state.accompanyingCourse.origin,
}),
...mapGetters(["isOriginValid"]),
},
mounted() {
this.getOptions();
},
methods: {
getOptions() {
const url = `/api/1.0/person/accompanying-period/origin.json`;
makeFetch("GET", url)
.then((response) => {
this.options = response.results;
return response;
})
.catch((error) => {
commit("catchError", error);
this.$toast.open({ message: error.txt });
});
},
computed: {
...mapState({
value: (state) => state.accompanyingCourse.origin,
}),
...mapGetters(["isOriginValid"]),
updateOrigin(value) {
this.$store
.dispatch("updateOrigin", value)
.catch(({ name, violations }) => {
if (name === "ValidationException" || name === "AccessException") {
violations.forEach((violation) =>
this.$toast.open({ message: violation }),
);
} else {
this.$toast.open({ message: "An error occurred" });
}
});
},
mounted() {
this.getOptions();
},
methods: {
getOptions() {
const url = `/api/1.0/person/accompanying-period/origin.json`;
makeFetch("GET", url)
.then((response) => {
this.options = response.results;
return response;
})
.catch((error) => {
commit("catchError", error);
this.$toast.open({ message: error.txt });
});
},
updateOrigin(value) {
this.$store
.dispatch("updateOrigin", value)
.catch(({ name, violations }) => {
if (
name === "ValidationException" ||
name === "AccessException"
) {
violations.forEach((violation) =>
this.$toast.open({ message: violation }),
);
} else {
this.$toast.open({ message: "An error occurred" });
}
});
},
transText({ text }) {
return text.fr;
},
transText({ text }) {
return text.fr;
},
},
};
</script>
<style src="vue-multiselect/dist/vue-multiselect.css"></style>
<style lang="css" scoped>
label {
display: none;
display: none;
}
</style>

View File

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

View File

@@ -1,98 +1,97 @@
<template>
<person-render-box
render="bloc"
:options="{
addInfo: true,
addId: false,
addEntity: false,
addLink: false,
addHouseholdLink: false,
addAltNames: true,
addAge: true,
hLevel: 3,
isConfidential: false,
isMultiline: true,
}"
:person="participation.person"
:return-path="getAccompanyingCourseReturnPath"
>
<template #end-bloc>
<div class="item-row separator">
<ul class="record_actions">
<button-location
v-if="
hasCurrentHouseholdAddress &&
!isPersonLocatingCourse(participation.person)
"
:person="participation.person"
/>
<li v-if="participation.person.current_household_id">
<a
class="btn btn-sm btn-chill-beige"
:href="getCurrentHouseholdUrl"
:title="
$t('persons_associated.show_household_number', {
id: participation.person
.current_household_id,
})
"
>
<i class="fa fa-fw fa-home" />
</a>
</li>
<li>
<on-the-fly
:type="participation.person.type"
:id="participation.person.id"
action="show"
/>
</li>
<li>
<on-the-fly
:type="participation.person.type"
:id="participation.person.id"
action="edit"
@save-form-on-the-fly="saveFormOnTheFly"
ref="onTheFly"
/>
</li>
<li>
<button
v-if="!participation.endDate"
class="btn btn-sm btn-remove"
:title="$t('persons_associated.leave_course')"
@click="modal.showModal = true"
/>
</li>
</ul>
</div>
</template>
</person-render-box>
<person-render-box
render="bloc"
:options="{
addInfo: true,
addId: false,
addEntity: false,
addLink: false,
addHouseholdLink: false,
addAltNames: true,
addAge: true,
hLevel: 3,
isConfidential: false,
isMultiline: true,
}"
:person="participation.person"
:return-path="getAccompanyingCourseReturnPath"
>
<template #end-bloc>
<div class="item-row separator">
<ul class="record_actions">
<button-location
v-if="
hasCurrentHouseholdAddress &&
!isPersonLocatingCourse(participation.person)
"
:person="participation.person"
/>
<li v-if="participation.person.current_household_id">
<a
class="btn btn-sm btn-chill-beige"
:href="getCurrentHouseholdUrl"
:title="
$t('persons_associated.show_household_number', {
id: participation.person.current_household_id,
})
"
>
<i class="fa fa-fw fa-home" />
</a>
</li>
<li>
<on-the-fly
:type="participation.person.type"
:id="participation.person.id"
action="show"
/>
</li>
<li>
<on-the-fly
:type="participation.person.type"
:id="participation.person.id"
action="edit"
@save-form-on-the-fly="saveFormOnTheFly"
ref="onTheFly"
/>
</li>
<li>
<button
v-if="!participation.endDate"
class="btn btn-sm btn-remove"
:title="$t('persons_associated.leave_course')"
@click="modal.showModal = true"
/>
</li>
</ul>
</div>
</template>
</person-render-box>
<teleport to="body">
<modal
v-if="modal.showModal"
:modal-dialog-class="modal.modalDialogClass"
@close="modal.showModal = false"
<teleport to="body">
<modal
v-if="modal.showModal"
:modal-dialog-class="modal.modalDialogClass"
@close="modal.showModal = false"
>
<template #header>
<h2 class="modal-title">
{{ $t("persons_associated.sure") }}
</h2>
</template>
<template #body>
<p>{{ $t("persons_associated.sure_description") }}</p>
</template>
<template #footer>
<button
class="btn btn-danger"
@click.prevent="$emit('close', participation)"
>
<template #header>
<h2 class="modal-title">
{{ $t("persons_associated.sure") }}
</h2>
</template>
<template #body>
<p>{{ $t("persons_associated.sure_description") }}</p>
</template>
<template #footer>
<button
class="btn btn-danger"
@click.prevent="$emit('close', participation)"
>
{{ $t("persons_associated.ok") }}
</button>
</template>
</modal>
</teleport>
{{ $t("persons_associated.ok") }}
</button>
</template>
</modal>
</teleport>
</template>
<script>
@@ -103,135 +102,135 @@ import Modal from "ChillMainAssets/vuejs/_components/Modal";
import { makeFetch } from "ChillMainAssets/lib/api/apiMethods";
export default {
name: "ParticipationItem",
components: {
OnTheFly,
ButtonLocation,
PersonRenderBox,
Modal,
name: "ParticipationItem",
components: {
OnTheFly,
ButtonLocation,
PersonRenderBox,
Modal,
},
props: ["participation"],
emits: ["remove", "close"],
data() {
return {
modal: {
showModal: false,
modalDialogClass: "modal-dialog-centered modal-md",
},
PersonRenderBox: {
participation: "participation",
options: {
addInfo: false,
addId: true,
addAge: false,
hLevel: 1,
},
},
};
},
computed: {
hasCurrentHouseholdAddress() {
if (
!this.participation.endDate &&
this.participation.person.current_household_address !== null
) {
return true;
}
return false;
},
props: ["participation"],
emits: ["remove", "close"],
data() {
return {
modal: {
showModal: false,
modalDialogClass: "modal-dialog-centered modal-md",
},
PersonRenderBox: {
participation: "participation",
options: {
addInfo: false,
addId: true,
addAge: false,
hLevel: 1,
},
},
getAccompanyingCourseReturnPath() {
return `fr/parcours/${this.$store.state.accompanyingCourse.id}/edit#section-10`;
},
getCurrentHouseholdUrl() {
return `/fr/person/household/${this.participation.person.current_household_id}/summary?returnPath=${this.getAccompanyingCourseReturnPath}`;
},
},
methods: {
isPersonLocatingCourse(person) {
return this.$store.getters.isPersonLocatingCourse(person);
},
saveFormOnTheFly(payload) {
console.log(
"saveFormOnTheFly: type",
payload.type,
", data",
payload.data,
);
payload.target = "participation";
let body = { type: payload.type };
if (payload.type === "person") {
body.firstName = payload.data.firstName;
body.lastName = payload.data.lastName;
if (payload.data.birthdate !== null) {
body.birthdate = payload.data.birthdate;
}
body.phonenumber = payload.data.phonenumber;
body.mobilenumber = payload.data.mobilenumber;
body.email = payload.data.email;
body.altNames = payload.data.altNames;
body.gender = {
id: payload.data.gender.id,
type: payload.data.gender.type,
};
},
computed: {
hasCurrentHouseholdAddress() {
if (
!this.participation.endDate &&
this.participation.person.current_household_address !== null
) {
return true;
if (payload.data.civility !== null) {
body.civility = {
id: payload.data.civility.id,
type: payload.data.civility.type,
};
}
makeFetch(
"PATCH",
`/api/1.0/person/person/${payload.data.id}.json`,
body,
)
.then((response) => {
this.$store.dispatch("addPerson", {
target: payload.target,
body: response,
});
this.$refs.onTheFly.closeModal();
})
.catch((error) => {
if (error.name === "ValidationException") {
for (let v of error.violations) {
this.$toast.open({ message: v });
}
} else {
this.$toast.open({ message: "An error occurred" });
}
return false;
},
getAccompanyingCourseReturnPath() {
return `fr/parcours/${this.$store.state.accompanyingCourse.id}/edit#section-10`;
},
getCurrentHouseholdUrl() {
return `/fr/person/household/${this.participation.person.current_household_id}/summary?returnPath=${this.getAccompanyingCourseReturnPath}`;
},
},
methods: {
isPersonLocatingCourse(person) {
return this.$store.getters.isPersonLocatingCourse(person);
},
saveFormOnTheFly(payload) {
console.log(
"saveFormOnTheFly: type",
payload.type,
", data",
payload.data,
);
payload.target = "participation";
});
} else if (payload.type === "thirdparty") {
body.name = payload.data.text;
body.email = payload.data.email;
body.telephone = payload.data.telephone;
body.telephone2 = payload.data.telephone2;
body.address = { id: payload.data.address.address_id };
let body = { type: payload.type };
if (payload.type === "person") {
body.firstName = payload.data.firstName;
body.lastName = payload.data.lastName;
if (payload.data.birthdate !== null) {
body.birthdate = payload.data.birthdate;
}
body.phonenumber = payload.data.phonenumber;
body.mobilenumber = payload.data.mobilenumber;
body.email = payload.data.email;
body.altNames = payload.data.altNames;
body.gender = {
id: payload.data.gender.id,
type: payload.data.gender.type,
};
if (payload.data.civility !== null) {
body.civility = {
id: payload.data.civility.id,
type: payload.data.civility.type,
};
}
makeFetch(
"PATCH",
`/api/1.0/person/person/${payload.data.id}.json`,
body,
)
.then((response) => {
this.$store.dispatch("addPerson", {
target: payload.target,
body: response,
});
this.$refs.onTheFly.closeModal();
})
.catch((error) => {
if (error.name === "ValidationException") {
for (let v of error.violations) {
this.$toast.open({ message: v });
}
} else {
this.$toast.open({ message: "An error occurred" });
}
});
} else if (payload.type === "thirdparty") {
body.name = payload.data.text;
body.email = payload.data.email;
body.telephone = payload.data.telephone;
body.telephone2 = payload.data.telephone2;
body.address = { id: payload.data.address.address_id };
makeFetch(
"PATCH",
`/api/1.0/thirdparty/thirdparty/${payload.data.id}.json`,
body,
)
.then((response) => {
this.$store.dispatch("addThirdparty", {
target: payload.target,
body: response,
});
this.$refs.onTheFly.closeModal();
})
.catch((error) => {
if (error.name === "ValidationException") {
for (let v of error.violations) {
this.$toast.open({ message: v });
}
} else {
this.$toast.open({ message: "An error occurred" });
}
});
makeFetch(
"PATCH",
`/api/1.0/thirdparty/thirdparty/${payload.data.id}.json`,
body,
)
.then((response) => {
this.$store.dispatch("addThirdparty", {
target: payload.target,
body: response,
});
this.$refs.onTheFly.closeModal();
})
.catch((error) => {
if (error.name === "ValidationException") {
for (let v of error.violations) {
this.$toast.open({ message: v });
}
} else {
this.$toast.open({ message: "An error occurred" });
}
},
});
}
},
},
};
</script>

View File

@@ -1,116 +1,113 @@
<template>
<div class="vue-component">
<h2><a id="section-80" />{{ $t("referrer.title") }}</h2>
<div class="vue-component">
<h2><a id="section-80" />{{ $t("referrer.title") }}</h2>
<teleport to="body">
<modal
v-if="modal.showModal"
:modal-dialog-class="modal.modalDialogClass"
@close="cancelChange"
>
<template #header>
<h3 class="modal-title">
{{ $t("confirm.title") }}
</h3>
</template>
<teleport to="body">
<modal
v-if="modal.showModal"
:modal-dialog-class="modal.modalDialogClass"
@close="cancelChange"
>
<template #header>
<h3 class="modal-title">
{{ $t("confirm.title") }}
</h3>
</template>
<template #body-head>
<div class="modal-body">
<p
v-html="
$t('confirm.sure_referrer', {
referrer: this.value.text,
})
"
/>
</div>
</template>
<template #footer>
<button
class="btn btn-save"
@click.prevent="this.confirmReferrer"
>
{{ $t("confirm.ok_referrer") }}
</button>
</template>
</modal>
</teleport>
<div>
<label class="col-form-label" for="selectJob">
{{ $t("job.label") }}
</label>
<VueMultiselect
name="selectJob"
label="text"
:custom-label="customJobLabel"
track-by="id"
:multiple="false"
:searchable="true"
:placeholder="$t('job.placeholder')"
v-model="valueJob"
:options="jobs"
:select-label="$t('multiselect.select_label')"
:deselect-label="$t('multiselect.deselect_label')"
:selected-label="$t('multiselect.selected_label')"
<template #body-head>
<div class="modal-body">
<p
v-html="
$t('confirm.sure_referrer', {
referrer: this.value.text,
})
"
/>
</div>
</template>
<label class="col-form-label" for="selectReferrer">
{{ $t("referrer.label") }}
</label>
<template #footer>
<button class="btn btn-save" @click.prevent="this.confirmReferrer">
{{ $t("confirm.ok_referrer") }}
</button>
</template>
</modal>
</teleport>
<VueMultiselect
name="selectReferrer"
label="text"
track-by="id"
:multiple="false"
:searchable="true"
:placeholder="$t('referrer.placeholder')"
v-model="value"
@select="updateReferrer"
@remove="removeReferrer"
:options="users"
:select-label="$t('multiselect.select_label')"
:deselect-label="$t('multiselect.deselect_label')"
:selected-label="$t('multiselect.selected_label')"
/>
<div>
<label class="col-form-label" for="selectJob">
{{ $t("job.label") }}
</label>
<template v-if="usersSuggestedFilteredByJob.length > 0">
<ul class="list-suggest add-items inline">
<li
v-for="(u, i) in usersSuggestedFilteredByJob"
@click="updateReferrer(u)"
:key="`referrer-${i}`"
>
<span>
<user-render-box-badge :user="u" />
</span>
</li>
</ul>
</template>
</div>
<VueMultiselect
name="selectJob"
label="text"
:custom-label="customJobLabel"
track-by="id"
:multiple="false"
:searchable="true"
:placeholder="$t('job.placeholder')"
v-model="valueJob"
:options="jobs"
:select-label="$t('multiselect.select_label')"
:deselect-label="$t('multiselect.deselect_label')"
:selected-label="$t('multiselect.selected_label')"
/>
<div>
<ul class="record_actions">
<li>
<button
class="btn btn-create"
type="button"
name="button"
@click="assignMe"
>
{{ $t("referrer.assign_me") }}
</button>
</li>
</ul>
</div>
<label class="col-form-label" for="selectReferrer">
{{ $t("referrer.label") }}
</label>
<div v-if="!isJobValid" class="alert alert-warning to-confirm">
{{ $t("job.not_valid") }}
</div>
<VueMultiselect
name="selectReferrer"
label="text"
track-by="id"
:multiple="false"
:searchable="true"
:placeholder="$t('referrer.placeholder')"
v-model="value"
@select="updateReferrer"
@remove="removeReferrer"
:options="users"
:select-label="$t('multiselect.select_label')"
:deselect-label="$t('multiselect.deselect_label')"
:selected-label="$t('multiselect.selected_label')"
/>
<template v-if="usersSuggestedFilteredByJob.length > 0">
<ul class="list-suggest add-items inline">
<li
v-for="(u, i) in usersSuggestedFilteredByJob"
@click="updateReferrer(u)"
:key="`referrer-${i}`"
>
<span>
<user-render-box-badge :user="u" />
</span>
</li>
</ul>
</template>
</div>
<div>
<ul class="record_actions">
<li>
<button
class="btn btn-create"
type="button"
name="button"
@click="assignMe"
>
{{ $t("referrer.assign_me") }}
</button>
</li>
</ul>
</div>
<div v-if="!isJobValid" class="alert alert-warning to-confirm">
{{ $t("job.not_valid") }}
</div>
</div>
</template>
<script>
@@ -121,134 +118,124 @@ import UserRenderBoxBadge from "ChillMainAssets/vuejs/_components/Entity/UserRen
import Modal from "ChillMainAssets/vuejs/_components/Modal";
export default {
name: "Referrer",
components: {
UserRenderBoxBadge,
VueMultiselect,
Modal,
name: "Referrer",
components: {
UserRenderBoxBadge,
VueMultiselect,
Modal,
},
data() {
return {
jobs: [],
modal: {
showModal: false,
modalDialogClass: "modal-dialog-scrollable modal-xl",
},
value: this.$store.state.accompanyingCourse.user,
confirmed: false,
};
},
computed: {
...mapState({
valueJob: (state) => state.accompanyingCourse.job,
}),
...mapGetters(["isJobValid", "usersSuggestedFilteredByJob"]),
users: function () {
let users = this.$store.getters.usersFilteredByJob;
// ensure that the selected user is in the list. add it if necessary
if (
this.$store.state.accompanyingCourse.user !== null &&
users.find(
(u) => this.$store.state.accompanyingCourse.user.id === u.id,
) === undefined
) {
users.push(this.$store.state.accompanyingCourse.user);
}
return users;
},
data() {
return {
jobs: [],
modal: {
showModal: false,
modalDialogClass: "modal-dialog-scrollable modal-xl",
},
value: this.$store.state.accompanyingCourse.user,
confirmed: false,
};
},
computed: {
...mapState({
valueJob: (state) => state.accompanyingCourse.job,
}),
...mapGetters(["isJobValid", "usersSuggestedFilteredByJob"]),
users: function () {
let users = this.$store.getters.usersFilteredByJob;
// ensure that the selected user is in the list. add it if necessary
if (
this.$store.state.accompanyingCourse.user !== null &&
users.find(
(u) =>
this.$store.state.accompanyingCourse.user.id === u.id,
) === undefined
) {
users.push(this.$store.state.accompanyingCourse.user);
valueJob: {
get() {
return this.$store.state.accompanyingCourse.job;
},
set(value) {
this.$store
.dispatch("updateJob", value)
.catch(({ name, violations }) => {
if (name === "ValidationException" || name === "AccessException") {
violations.forEach((violation) =>
this.$toast.open({ message: violation }),
);
} else {
this.$toast.open({ message: "An error occurred" });
}
return users;
},
valueJob: {
get() {
return this.$store.state.accompanyingCourse.job;
},
set(value) {
this.$store
.dispatch("updateJob", value)
.catch(({ name, violations }) => {
if (
name === "ValidationException" ||
name === "AccessException"
) {
violations.forEach((violation) =>
this.$toast.open({ message: violation }),
);
} else {
this.$toast.open({ message: "An error occurred" });
}
});
},
},
});
},
},
mounted() {
this.getJobs();
},
mounted() {
this.getJobs();
},
methods: {
updateReferrer(value) {
this.value = value;
this.toggleModal();
},
methods: {
updateReferrer(value) {
this.value = value;
this.toggleModal();
},
getJobs() {
const url = "/api/1.0/main/user-job.json";
makeFetch("GET", url)
.then((response) => {
this.jobs = response.results;
})
.catch((error) => {
this.$toast.open({ message: error.txt });
});
},
customJobLabel(value) {
return value.label.fr;
},
assignMe() {
const url = `/api/1.0/main/whoami.json`;
makeFetch("GET", url).then((user) => {
// this.value = user
this.updateReferrer(user);
});
},
toggleModal() {
this.modal.showModal = !this.modal.showModal;
},
confirmReferrer() {
this.$store
.dispatch("updateReferrer", this.value)
.catch(({ name, violations }) => {
if (
name === "ValidationException" ||
name === "AccessException"
) {
violations.forEach((violation) =>
this.$toast.open({ message: violation }),
);
} else {
this.$toast.open({ message: "An error occurred" });
}
});
this.toggleModal();
},
removeReferrer() {
console.log("remove option");
this.$store
.dispatch("updateReferrer", null)
.catch(({ name, violations }) => {
if (
name === "ValidationException" ||
name === "AccessException"
) {
violations.forEach((violation) =>
this.$toast.open({ message: violation }),
);
} else {
this.$toast.open({ message: "An error occurred" });
}
});
},
cancelChange() {
this.value = this.$store.state.accompanyingCourse.user;
this.toggleModal();
},
getJobs() {
const url = "/api/1.0/main/user-job.json";
makeFetch("GET", url)
.then((response) => {
this.jobs = response.results;
})
.catch((error) => {
this.$toast.open({ message: error.txt });
});
},
customJobLabel(value) {
return value.label.fr;
},
assignMe() {
const url = `/api/1.0/main/whoami.json`;
makeFetch("GET", url).then((user) => {
// this.value = user
this.updateReferrer(user);
});
},
toggleModal() {
this.modal.showModal = !this.modal.showModal;
},
confirmReferrer() {
this.$store
.dispatch("updateReferrer", this.value)
.catch(({ name, violations }) => {
if (name === "ValidationException" || name === "AccessException") {
violations.forEach((violation) =>
this.$toast.open({ message: violation }),
);
} else {
this.$toast.open({ message: "An error occurred" });
}
});
this.toggleModal();
},
removeReferrer() {
console.log("remove option");
this.$store
.dispatch("updateReferrer", null)
.catch(({ name, violations }) => {
if (name === "ValidationException" || name === "AccessException") {
violations.forEach((violation) =>
this.$toast.open({ message: violation }),
);
} else {
this.$toast.open({ message: "An error occurred" });
}
});
},
cancelChange() {
this.value = this.$store.state.accompanyingCourse.user;
this.toggleModal();
},
},
};
</script>

View File

@@ -1,263 +1,239 @@
<template>
<div class="vue-component">
<h2><a id="section-50" />{{ $t("requestor.title") }}</h2>
<div class="vue-component">
<h2><a id="section-50" />{{ $t("requestor.title") }}</h2>
<div
v-if="accompanyingCourse.requestor && isAnonymous"
class="flex-table"
>
<label>
<input
type="checkbox"
v-model="requestorIsAnonymous"
class="me-2"
/>
{{ $t("requestor.is_anonymous") }}
</label>
<confidential
v-if="accompanyingCourse.requestor.type === 'thirdparty'"
>
<template #confidential-content>
<third-party-render-box
:thirdparty="accompanyingCourse.requestor"
:options="{
addLink: false,
addId: false,
addEntity: true,
addInfo: false,
hLevel: 3,
isMultiline: true,
isConfidential: true,
}"
>
<template #record-actions>
<ul class="record_actions">
<li>
<on-the-fly
:type="
accompanyingCourse.requestor.type
"
:id="accompanyingCourse.requestor.id"
action="show"
/>
</li>
<li>
<on-the-fly
:type="
accompanyingCourse.requestor.type
"
:id="accompanyingCourse.requestor.id"
action="edit"
@save-form-on-the-fly="saveFormOnTheFly"
ref="onTheFly"
/>
</li>
</ul>
</template>
</third-party-render-box>
</template>
</confidential>
<confidential
v-else-if="accompanyingCourse.requestor.type === 'person'"
>
<template #confidential-content>
<person-render-box
render="bloc"
:person="accompanyingCourse.requestor"
:options="{
addLink: false,
addId: false,
addAltNames: false,
addEntity: true,
addInfo: true,
hLevel: 3,
isMultiline: true,
isConfidential: false,
addAge: true,
}"
>
<template #record-actions>
<ul class="record_actions">
<li>
<on-the-fly
:type="
accompanyingCourse.requestor.type
"
:id="accompanyingCourse.requestor.id"
action="show"
/>
</li>
<li>
<on-the-fly
:type="
accompanyingCourse.requestor.type
"
:id="accompanyingCourse.requestor.id"
action="edit"
@save-form-on-the-fly="saveFormOnTheFly"
ref="onTheFly"
/>
</li>
</ul>
</template>
</person-render-box>
</template>
</confidential>
<ul class="record_actions">
<div v-if="accompanyingCourse.requestor && isAnonymous" class="flex-table">
<label>
<input type="checkbox" v-model="requestorIsAnonymous" class="me-2" />
{{ $t("requestor.is_anonymous") }}
</label>
<confidential v-if="accompanyingCourse.requestor.type === 'thirdparty'">
<template #confidential-content>
<third-party-render-box
:thirdparty="accompanyingCourse.requestor"
:options="{
addLink: false,
addId: false,
addEntity: true,
addInfo: false,
hLevel: 3,
isMultiline: true,
isConfidential: true,
}"
>
<template #record-actions>
<ul class="record_actions">
<li>
<button
class="btn btn-remove"
:title="$t('action.remove')"
@click="removeRequestor"
>
{{ $t("action.remove") }}
</button>
<on-the-fly
:type="accompanyingCourse.requestor.type"
:id="accompanyingCourse.requestor.id"
action="show"
/>
</li>
</ul>
</div>
<div
v-else-if="accompanyingCourse.requestor && !isAnonymous"
class="flex-table"
>
<label>
<input
type="checkbox"
v-model="requestorIsAnonymous"
class="me-2"
/>
{{ $t("requestor.is_anonymous") }}
</label>
<third-party-render-box
v-if="accompanyingCourse.requestor.type === 'thirdparty'"
:thirdparty="accompanyingCourse.requestor"
:options="{
addLink: false,
addId: false,
addEntity: true,
addInfo: false,
hLevel: 3,
isMultiline: true,
isConfidential: true,
}"
>
<template #record-actions>
<ul class="record_actions">
<li>
<on-the-fly
:type="accompanyingCourse.requestor.type"
:id="accompanyingCourse.requestor.id"
action="show"
/>
</li>
<li>
<on-the-fly
:type="accompanyingCourse.requestor.type"
:id="accompanyingCourse.requestor.id"
action="edit"
@save-form-on-the-fly="saveFormOnTheFly"
ref="onTheFly"
/>
</li>
</ul>
</template>
</third-party-render-box>
<person-render-box
render="bloc"
v-if="accompanyingCourse.requestor.type === 'person'"
:person="accompanyingCourse.requestor"
:options="{
addLink: false,
addId: false,
addAltNames: false,
addEntity: true,
addInfo: true,
hLevel: 3,
isMultiline: true,
isConfidential: false,
}"
>
<template #record-actions>
<ul class="record_actions">
<li>
<on-the-fly
:type="accompanyingCourse.requestor.type"
:id="accompanyingCourse.requestor.id"
action="show"
/>
</li>
<li>
<on-the-fly
:type="accompanyingCourse.requestor.type"
:id="accompanyingCourse.requestor.id"
action="edit"
@save-form-on-the-fly="saveFormOnTheFly"
ref="onTheFly"
/>
</li>
</ul>
</template>
</person-render-box>
<ul class="record_actions">
<li>
<button
class="btn btn-remove"
:title="$t('action.remove')"
@click="removeRequestor"
>
{{ $t("action.remove") }}
</button>
<on-the-fly
:type="accompanyingCourse.requestor.type"
:id="accompanyingCourse.requestor.id"
action="edit"
@save-form-on-the-fly="saveFormOnTheFly"
ref="onTheFly"
/>
</li>
</ul>
</div>
</ul>
</template>
</third-party-render-box>
</template>
</confidential>
<div v-else>
<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 inline">
<li
v-for="p in suggestedEntities"
:key="uniqueId(p)"
@click="addSuggestedEntity(p)"
>
<person-text v-if="p.type === 'person'" :person="p" />
<span v-else>{{ p.text }}</span>
<confidential v-else-if="accompanyingCourse.requestor.type === 'person'">
<template #confidential-content>
<person-render-box
render="bloc"
:person="accompanyingCourse.requestor"
:options="{
addLink: false,
addId: false,
addAltNames: false,
addEntity: true,
addInfo: true,
hLevel: 3,
isMultiline: true,
isConfidential: false,
addAge: true,
}"
>
<template #record-actions>
<ul class="record_actions">
<li>
<on-the-fly
:type="accompanyingCourse.requestor.type"
:id="accompanyingCourse.requestor.id"
action="show"
/>
</li>
</ul>
</div>
<div>
<ul class="record_actions">
<li class="add-persons">
<add-persons
v-if="accompanyingCourse.requestor === null"
button-title="requestor.add_requestor"
modal-title="requestor.add_requestor"
:key="addPersons.key"
:options="addPersons.options"
@add-new-persons="addNewPersons"
ref="addPersons"
>
<!-- to cast child method -->
</add-persons>
<li>
<on-the-fly
:type="accompanyingCourse.requestor.type"
:id="accompanyingCourse.requestor.id"
action="edit"
@save-form-on-the-fly="saveFormOnTheFly"
ref="onTheFly"
/>
</li>
</ul>
</div>
</ul>
</template>
</person-render-box>
</template>
</confidential>
<ul class="record_actions">
<li>
<button
class="btn btn-remove"
:title="$t('action.remove')"
@click="removeRequestor"
>
{{ $t("action.remove") }}
</button>
</li>
</ul>
</div>
<div
v-else-if="accompanyingCourse.requestor && !isAnonymous"
class="flex-table"
>
<label>
<input type="checkbox" v-model="requestorIsAnonymous" class="me-2" />
{{ $t("requestor.is_anonymous") }}
</label>
<third-party-render-box
v-if="accompanyingCourse.requestor.type === 'thirdparty'"
:thirdparty="accompanyingCourse.requestor"
:options="{
addLink: false,
addId: false,
addEntity: true,
addInfo: false,
hLevel: 3,
isMultiline: true,
isConfidential: true,
}"
>
<template #record-actions>
<ul class="record_actions">
<li>
<on-the-fly
:type="accompanyingCourse.requestor.type"
:id="accompanyingCourse.requestor.id"
action="show"
/>
</li>
<li>
<on-the-fly
:type="accompanyingCourse.requestor.type"
:id="accompanyingCourse.requestor.id"
action="edit"
@save-form-on-the-fly="saveFormOnTheFly"
ref="onTheFly"
/>
</li>
</ul>
</template>
</third-party-render-box>
<person-render-box
render="bloc"
v-if="accompanyingCourse.requestor.type === 'person'"
:person="accompanyingCourse.requestor"
:options="{
addLink: false,
addId: false,
addAltNames: false,
addEntity: true,
addInfo: true,
hLevel: 3,
isMultiline: true,
isConfidential: false,
}"
>
<template #record-actions>
<ul class="record_actions">
<li>
<on-the-fly
:type="accompanyingCourse.requestor.type"
:id="accompanyingCourse.requestor.id"
action="show"
/>
</li>
<li>
<on-the-fly
:type="accompanyingCourse.requestor.type"
:id="accompanyingCourse.requestor.id"
action="edit"
@save-form-on-the-fly="saveFormOnTheFly"
ref="onTheFly"
/>
</li>
</ul>
</template>
</person-render-box>
<ul class="record_actions">
<li>
<button
class="btn btn-remove"
:title="$t('action.remove')"
@click="removeRequestor"
>
{{ $t("action.remove") }}
</button>
</li>
</ul>
</div>
<div v-else>
<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 inline">
<li
v-for="p in suggestedEntities"
:key="uniqueId(p)"
@click="addSuggestedEntity(p)"
>
<person-text v-if="p.type === 'person'" :person="p" />
<span v-else>{{ p.text }}</span>
</li>
</ul>
</div>
<div>
<ul class="record_actions">
<li class="add-persons">
<add-persons
v-if="accompanyingCourse.requestor === null"
button-title="requestor.add_requestor"
modal-title="requestor.add_requestor"
:key="addPersons.key"
:options="addPersons.options"
@add-new-persons="addNewPersons"
ref="addPersons"
>
<!-- to cast child method -->
</add-persons>
</li>
</ul>
</div>
</div>
</template>
<script>
@@ -271,221 +247,208 @@ import { makeFetch } from "ChillMainAssets/lib/api/apiMethods";
import PersonText from "ChillPersonAssets/vuejs/_components/Entity/PersonText.vue";
export default {
name: "Requestor",
components: {
AddPersons,
OnTheFly,
PersonRenderBox,
ThirdPartyRenderBox,
Confidential,
PersonText,
},
props: ["isAnonymous"],
data() {
return {
addPersons: {
key: "requestor",
options: {
type: ["person", "thirdparty"],
priority: null,
uniq: true,
},
},
};
},
computed: {
...mapState({
suggestedEntities: (state) => {
return (
[
...state.accompanyingCourse.participations
.filter((p) => p.endDate === null)
.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;
}
}
name: "Requestor",
components: {
AddPersons,
OnTheFly,
PersonRenderBox,
ThirdPartyRenderBox,
Confidential,
PersonText,
},
props: ["isAnonymous"],
data() {
return {
addPersons: {
key: "requestor",
options: {
type: ["person", "thirdparty"],
priority: null,
uniq: true,
},
},
};
},
computed: {
...mapState({
suggestedEntities: (state) => {
return (
[
...state.accompanyingCourse.participations
.filter((p) => p.endDate === null)
.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;
},
requestorIsAnonymous: {
set(value) {
this.$store.dispatch("requestorIsAnonymous", value);
},
get() {
return this.$store.state.accompanyingCourse.requestorAnonymous;
},
},
return true;
})
);
},
}),
accompanyingCourse() {
return this.$store.state.accompanyingCourse;
},
methods: {
removeRequestor() {
//console.log('@@ CLICK remove requestor: item');
this.$store
.dispatch("removeRequestor")
.catch(({ name, violations }) => {
if (
name === "ValidationException" ||
name === "AccessException"
) {
violations.forEach((violation) =>
this.$toast.open({ message: violation }),
);
} else {
this.$toast.open({ message: "An error occurred" });
}
});
},
addNewPersons({ selected, modal }) {
//console.log('@@@ CLICK button addNewPersons', selected);
this.$store
.dispatch("addRequestor", selected.shift())
.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.$refs.addPersons.resetSearch(); // to cast child method
modal.showModal = false;
},
saveFormOnTheFly(payload) {
console.log(
"saveFormOnTheFly: type",
payload.type,
", data",
payload.data,
requestorIsAnonymous: {
set(value) {
this.$store.dispatch("requestorIsAnonymous", value);
},
get() {
return this.$store.state.accompanyingCourse.requestorAnonymous;
},
},
},
methods: {
removeRequestor() {
//console.log('@@ CLICK remove requestor: item');
this.$store.dispatch("removeRequestor").catch(({ name, violations }) => {
if (name === "ValidationException" || name === "AccessException") {
violations.forEach((violation) =>
this.$toast.open({ message: violation }),
);
} else {
this.$toast.open({ message: "An error occurred" });
}
});
},
addNewPersons({ selected, modal }) {
//console.log('@@@ CLICK button addNewPersons', selected);
this.$store
.dispatch("addRequestor", selected.shift())
.catch(({ name, violations }) => {
if (name === "ValidationException" || name === "AccessException") {
violations.forEach((violation) =>
this.$toast.open({ message: violation }),
);
payload.target = "requestor";
} else {
this.$toast.open({ message: "An error occurred" });
}
});
let body = { type: payload.type };
if (payload.type === "person") {
body.firstName = payload.data.firstName;
body.lastName = payload.data.lastName;
if (payload.data.birthdate !== null) {
body.birthdate = payload.data.birthdate;
}
body.phonenumber = payload.data.phonenumber;
body.mobilenumber = payload.data.mobilenumber;
body.email = payload.data.email;
body.altNames = payload.data.altNames;
body.gender = payload.data.gender;
makeFetch(
"PATCH",
`/api/1.0/person/person/${payload.data.id}.json`,
body,
)
.then((response) => {
this.$store.dispatch("addPerson", {
target: payload.target,
body: response,
});
this.$refs.onTheFly.closeModal();
})
.catch((error) => {
if (error.name === "ValidationException") {
for (let v of error.violations) {
this.$toast.open({ message: v });
}
} else {
this.$toast.open({ message: "An error occurred" });
}
});
} else if (payload.type === "thirdparty") {
body.name = payload.data.text;
body.email = payload.data.email;
body.telephone = payload.data.telephone;
body.telephone2 = payload.data.telephone2;
if (payload.data.address) {
body.address = { id: payload.data.address.address_id };
}
makeFetch(
"PATCH",
`/api/1.0/thirdparty/thirdparty/${payload.data.id}.json`,
body,
)
.then((response) => {
this.$store.dispatch("addThirdparty", {
target: payload.target,
body: response,
});
this.$refs.onTheFly.closeModal();
})
.catch((error) => {
if (error.name === "ValidationException") {
for (let v of error.violations) {
this.$toast.open({ message: v });
}
} else {
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}`;
},
this.$refs.addPersons.resetSearch(); // to cast child method
modal.showModal = false;
},
saveFormOnTheFly(payload) {
console.log(
"saveFormOnTheFly: type",
payload.type,
", data",
payload.data,
);
payload.target = "requestor";
let body = { type: payload.type };
if (payload.type === "person") {
body.firstName = payload.data.firstName;
body.lastName = payload.data.lastName;
if (payload.data.birthdate !== null) {
body.birthdate = payload.data.birthdate;
}
body.phonenumber = payload.data.phonenumber;
body.mobilenumber = payload.data.mobilenumber;
body.email = payload.data.email;
body.altNames = payload.data.altNames;
body.gender = payload.data.gender;
makeFetch(
"PATCH",
`/api/1.0/person/person/${payload.data.id}.json`,
body,
)
.then((response) => {
this.$store.dispatch("addPerson", {
target: payload.target,
body: response,
});
this.$refs.onTheFly.closeModal();
})
.catch((error) => {
if (error.name === "ValidationException") {
for (let v of error.violations) {
this.$toast.open({ message: v });
}
} else {
this.$toast.open({ message: "An error occurred" });
}
});
} else if (payload.type === "thirdparty") {
body.name = payload.data.text;
body.email = payload.data.email;
body.telephone = payload.data.telephone;
body.telephone2 = payload.data.telephone2;
if (payload.data.address) {
body.address = { id: payload.data.address.address_id };
}
makeFetch(
"PATCH",
`/api/1.0/thirdparty/thirdparty/${payload.data.id}.json`,
body,
)
.then((response) => {
this.$store.dispatch("addThirdparty", {
target: payload.target,
body: response,
});
this.$refs.onTheFly.closeModal();
})
.catch((error) => {
if (error.name === "ValidationException") {
for (let v of error.violations) {
this.$toast.open({ message: v });
}
} else {
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}`;
},
},
};
</script>
<style lang="scss" scoped>
div.flex-table {
margin: 1em 0 0 !important;
& > label,
& > ul.record_actions {
margin: 1em 3em 0 !important;
}
div.item-bloc {
background-color: white !important;
margin-top: 1em;
}
margin: 1em 0 0 !important;
& > label,
& > ul.record_actions {
margin: 1em 3em 0 !important;
}
div.item-bloc {
background-color: white !important;
margin-top: 1em;
}
}
.confidential {
display: block;
margin-right: 0px !important;
display: block;
margin-right: 0px !important;
}
</style>

View File

@@ -1,57 +1,57 @@
<template>
<div class="vue-component">
<h2><a id="section-90" />{{ $t("resources.title") }}</h2>
<div class="vue-component">
<h2><a id="section-90" />{{ $t("resources.title") }}</h2>
<div v-if="resources.length > 0">
<label class="col-form-label">{{
$tc("resources.counter", counter)
}}</label>
</div>
<div v-else>
<label class="chill-no-data-statement">{{
$tc("resources.counter", counter)
}}</label>
</div>
<div class="flex-table mb-3">
<resource-item
v-for="resource in resources"
:resource="resource"
:key="resource.id"
@remove="removeResource"
/>
</div>
<div v-if="suggestedEntities.length > 0">
<ul class="list-suggest add-items inline">
<li
v-for="p in suggestedEntities"
:key="uniqueId(p)"
@click="addSuggestedEntity(p)"
>
<person-text v-if="p.type === 'person'" :person="p" />
<span v-else>{{ p.text }}</span>
</li>
</ul>
</div>
<div>
<ul class="record_actions">
<li class="add-persons">
<add-persons
button-title="resources.add_resources"
modal-title="resources.add_resources"
:key="addPersons.key"
:options="addPersons.options"
@add-new-persons="addNewPersons"
ref="addPersons"
>
<!-- to cast child method -->
</add-persons>
</li>
</ul>
</div>
<div v-if="resources.length > 0">
<label class="col-form-label">{{
$tc("resources.counter", counter)
}}</label>
</div>
<div v-else>
<label class="chill-no-data-statement">{{
$tc("resources.counter", counter)
}}</label>
</div>
<div class="flex-table mb-3">
<resource-item
v-for="resource in resources"
:resource="resource"
:key="resource.id"
@remove="removeResource"
/>
</div>
<div v-if="suggestedEntities.length > 0">
<ul class="list-suggest add-items inline">
<li
v-for="p in suggestedEntities"
:key="uniqueId(p)"
@click="addSuggestedEntity(p)"
>
<person-text v-if="p.type === 'person'" :person="p" />
<span v-else>{{ p.text }}</span>
</li>
</ul>
</div>
<div>
<ul class="record_actions">
<li class="add-persons">
<add-persons
button-title="resources.add_resources"
modal-title="resources.add_resources"
:key="addPersons.key"
:options="addPersons.options"
@add-new-persons="addNewPersons"
ref="addPersons"
>
<!-- to cast child method -->
</add-persons>
</li>
</ul>
</div>
</div>
</template>
<script>
@@ -61,126 +61,117 @@ import ResourceItem from "./Resources/ResourceItem.vue";
import PersonText from "ChillPersonAssets/vuejs/_components/Entity/PersonText.vue";
export default {
name: "Resources",
components: {
AddPersons,
ResourceItem,
PersonText,
},
data() {
return {
addPersons: {
key: "resources",
options: {
type: ["person", "thirdparty"],
priority: null,
uniq: false,
},
},
};
},
computed: mapState({
resources: (state) => state.accompanyingCourse.resources,
counter: (state) => state.accompanyingCourse.resources.length,
suggestedEntities: (state) =>
[
state.accompanyingCourse.requestor,
...state.accompanyingCourse.participations
.filter((p) => p.endDate === null)
.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;
}
}
name: "Resources",
components: {
AddPersons,
ResourceItem,
PersonText,
},
data() {
return {
addPersons: {
key: "resources",
options: {
type: ["person", "thirdparty"],
priority: null,
uniq: false,
},
},
};
},
computed: mapState({
resources: (state) => state.accompanyingCourse.resources,
counter: (state) => state.accompanyingCourse.resources.length,
suggestedEntities: (state) =>
[
state.accompanyingCourse.requestor,
...state.accompanyingCourse.participations
.filter((p) => p.endDate === null)
.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) {
//console.log('@@ CLICK remove resource: item', item);
this.$store
.dispatch("removeResource", item)
.catch(({ name, violations }) => {
if (
name === "ValidationException" ||
name === "AccessException"
) {
violations.forEach((violation) =>
this.$toast.open({ message: violation }),
);
} else {
this.$toast.open({ message: "An error occurred" });
}
});
},
addNewPersons({ selected, modal }) {
//console.log('@@@ CLICK button addNewPersons', selected);
selected.forEach(function (item) {
this.$store
.dispatch("addResource", item)
.catch(({ name, violations }) => {
if (
name === "ValidationException" ||
name === "AccessException"
) {
violations.forEach((violation) =>
this.$toast.open({ message: violation }),
);
} else {
this.$toast.open({ message: violations });
}
});
}, this);
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}`;
},
return true;
}),
}),
methods: {
removeResource(item) {
//console.log('@@ CLICK remove resource: item', item);
this.$store
.dispatch("removeResource", item)
.catch(({ name, violations }) => {
if (name === "ValidationException" || name === "AccessException") {
violations.forEach((violation) =>
this.$toast.open({ message: violation }),
);
} else {
this.$toast.open({ message: "An error occurred" });
}
});
},
addNewPersons({ selected, modal }) {
//console.log('@@@ CLICK button addNewPersons', selected);
selected.forEach(function (item) {
this.$store
.dispatch("addResource", item)
.catch(({ name, violations }) => {
if (name === "ValidationException" || name === "AccessException") {
violations.forEach((violation) =>
this.$toast.open({ message: violation }),
);
} else {
this.$toast.open({ message: violations });
}
});
}, this);
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}`;
},
},
};
</script>
<style lang="scss">
div.flex-bloc {
div.item-bloc {
flex-basis: 50%;
}
div.item-bloc {
flex-basis: 50%;
}
}
</style>

View File

@@ -1,107 +1,107 @@
<template>
<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,
isConfidential: true,
}"
>
<template #end-bloc>
<div class="item-row separator">
<ul class="record_actions">
<li>
<write-comment
:resource="resource"
@update-comment="updateComment"
/>
</li>
<li>
<on-the-fly
:parent="parent"
:type="resource.resource.type"
:id="resource.resource.id"
action="show"
/>
</li>
<li>
<on-the-fly
:parent="parent"
:type="resource.resource.type"
:id="resource.resource.id"
action="edit"
@save-form-on-the-fly="saveFormOnTheFly"
ref="onTheFly"
/>
</li>
<li>
<button
class="btn btn-sm btn-remove"
:title="$t('action.remove')"
@click.prevent="$emit('remove', resource)"
/>
</li>
</ul>
</div>
</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,
isConfidential: true,
}"
>
<template #end-bloc>
<div class="item-row separator">
<ul class="record_actions">
<li>
<write-comment
:resource="resource"
@update-comment="updateComment"
/>
</li>
<li>
<on-the-fly
:parent="parent"
:type="resource.resource.type"
:id="resource.resource.id"
action="show"
/>
</li>
<li>
<on-the-fly
:parent="parent"
:type="resource.resource.type"
:id="resource.resource.id"
action="edit"
@save-form-on-the-fly="saveFormOnTheFly"
ref="onTheFly"
/>
</li>
<li>
<button
class="btn btn-sm btn-remove"
:title="$t('action.remove')"
@click.prevent="$emit('remove', resource)"
/>
</li>
</ul>
</div>
</template>
</person-render-box>
<third-party-render-box
v-if="resource.resource.type === 'thirdparty'"
:thirdparty="resource.resource"
:options="{
addLink: false,
addId: false,
addEntity: true,
addInfo: false,
hLevel: 3,
}"
>
<template #end-bloc>
<div class="item-row separator">
<ul class="record_actions">
<li>
<write-comment
:resource="resource"
@update-comment="updateComment"
/>
</li>
<li>
<on-the-fly
:parent="parent"
:type="resource.resource.type"
:id="resource.resource.id"
action="show"
/>
</li>
<li>
<on-the-fly
:parent="parent"
:type="resource.resource.type"
:id="resource.resource.id"
action="edit"
@save-form-on-the-fly="saveFormOnTheFly"
ref="onTheFly"
/>
</li>
<li>
<button
class="btn btn-sm btn-remove"
:title="$t('action.remove')"
@click.prevent="$emit('remove', resource)"
/>
</li>
</ul>
</div>
</template>
</third-party-render-box>
<third-party-render-box
v-if="resource.resource.type === 'thirdparty'"
:thirdparty="resource.resource"
:options="{
addLink: false,
addId: false,
addEntity: true,
addInfo: false,
hLevel: 3,
}"
>
<template #end-bloc>
<div class="item-row separator">
<ul class="record_actions">
<li>
<write-comment
:resource="resource"
@update-comment="updateComment"
/>
</li>
<li>
<on-the-fly
:parent="parent"
:type="resource.resource.type"
:id="resource.resource.id"
action="show"
/>
</li>
<li>
<on-the-fly
:parent="parent"
:type="resource.resource.type"
:id="resource.resource.id"
action="edit"
@save-form-on-the-fly="saveFormOnTheFly"
ref="onTheFly"
/>
</li>
<li>
<button
class="btn btn-sm btn-remove"
:title="$t('action.remove')"
@click.prevent="$emit('remove', resource)"
/>
</li>
</ul>
</div>
</template>
</third-party-render-box>
</template>
<script>
@@ -112,130 +112,130 @@ import WriteComment from "./WriteComment";
import { makeFetch } from "ChillMainAssets/lib/api/apiMethods";
export default {
name: "ResourceItem",
components: {
OnTheFly,
PersonRenderBox,
ThirdPartyRenderBox,
WriteComment,
},
props: ["resource"],
emits: ["remove"],
computed: {
parent() {
return {
type: this.resource.type,
id: this.resource.id,
comment: this.resource.comment,
parent: {
type: this.$store.state.accompanyingCourse.type,
id: this.$store.state.accompanyingCourse.id,
},
};
name: "ResourceItem",
components: {
OnTheFly,
PersonRenderBox,
ThirdPartyRenderBox,
WriteComment,
},
props: ["resource"],
emits: ["remove"],
computed: {
parent() {
return {
type: this.resource.type,
id: this.resource.id,
comment: this.resource.comment,
parent: {
type: this.$store.state.accompanyingCourse.type,
id: this.$store.state.accompanyingCourse.id,
},
hasCurrentHouseholdAddress() {
if (this.resource.resource.current_household_address !== null) {
return true;
};
},
hasCurrentHouseholdAddress() {
if (this.resource.resource.current_household_address !== null) {
return true;
}
return false;
},
},
methods: {
saveFormOnTheFly(payload) {
// console.log('saveFormOnTheFly: type', payload.type, ', data', payload.data);
payload.target = "resource";
let body = { type: payload.type };
if (payload.type === "person") {
body.firstName = payload.data.firstName;
body.lastName = payload.data.lastName;
if (payload.data.birthdate !== null) {
body.birthdate = payload.data.birthdate;
}
body.phonenumber = payload.data.phonenumber;
body.mobilenumber = payload.data.mobilenumber;
body.email = payload.data.email;
body.altNames = payload.data.altNames;
body.gender = {
id: payload.data.gender.id,
type: payload.data.gender.type,
};
if (payload.data.civility !== null) {
body.civility = {
id: payload.data.civility.id,
type: payload.data.civility.type,
};
}
makeFetch(
"PATCH",
`/api/1.0/person/person/${payload.data.id}.json`,
body,
)
.then((response) => {
this.$store.dispatch("addPerson", {
target: payload.target,
body: response,
});
this.$refs.onTheFly.closeModal();
})
.catch((error) => {
if (error.name === "ValidationException") {
for (let v of error.violations) {
this.$toast.open({ message: v });
}
} else {
this.$toast.open({ message: "An error occurred" });
}
return false;
},
},
methods: {
saveFormOnTheFly(payload) {
// console.log('saveFormOnTheFly: type', payload.type, ', data', payload.data);
payload.target = "resource";
});
} else if (payload.type === "thirdparty") {
// console.log('data', payload.data)
body.firstname = payload.data.firstname;
body.name = payload.data.name;
body.email = payload.data.email;
body.telephone = payload.data.telephone;
body.telephone2 = payload.data.telephone2;
body.address = payload.data.address
? { id: payload.data.address.address_id }
: null;
if (null !== payload.data.civility) {
body.civility = {
type: "chill_main_civility",
id: payload.data.civility.id,
};
}
if (null !== payload.data.profession) {
body.profession = payload.data.profession;
}
// console.log('body', body);
let body = { type: payload.type };
if (payload.type === "person") {
body.firstName = payload.data.firstName;
body.lastName = payload.data.lastName;
if (payload.data.birthdate !== null) {
body.birthdate = payload.data.birthdate;
}
body.phonenumber = payload.data.phonenumber;
body.mobilenumber = payload.data.mobilenumber;
body.email = payload.data.email;
body.altNames = payload.data.altNames;
body.gender = {
id: payload.data.gender.id,
type: payload.data.gender.type,
};
if (payload.data.civility !== null) {
body.civility = {
id: payload.data.civility.id,
type: payload.data.civility.type,
};
}
makeFetch(
"PATCH",
`/api/1.0/person/person/${payload.data.id}.json`,
body,
)
.then((response) => {
this.$store.dispatch("addPerson", {
target: payload.target,
body: response,
});
this.$refs.onTheFly.closeModal();
})
.catch((error) => {
if (error.name === "ValidationException") {
for (let v of error.violations) {
this.$toast.open({ message: v });
}
} else {
this.$toast.open({ message: "An error occurred" });
}
});
} else if (payload.type === "thirdparty") {
// console.log('data', payload.data)
body.firstname = payload.data.firstname;
body.name = payload.data.name;
body.email = payload.data.email;
body.telephone = payload.data.telephone;
body.telephone2 = payload.data.telephone2;
body.address = payload.data.address
? { id: payload.data.address.address_id }
: null;
if (null !== payload.data.civility) {
body.civility = {
type: "chill_main_civility",
id: payload.data.civility.id,
};
}
if (null !== payload.data.profession) {
body.profession = payload.data.profession;
}
// console.log('body', body);
makeFetch(
"PATCH",
`/api/1.0/thirdparty/thirdparty/${payload.data.id}.json`,
body,
)
.then((response) => {
this.$store.dispatch("addThirdparty", {
target: payload.target,
body: response,
});
this.$refs.onTheFly.closeModal();
})
.catch((error) => {
if (error.name === "ValidationException") {
for (let v of error.violations) {
this.$toast.open({ message: v });
}
} else {
this.$toast.open({ message: "An error occurred" });
}
});
makeFetch(
"PATCH",
`/api/1.0/thirdparty/thirdparty/${payload.data.id}.json`,
body,
)
.then((response) => {
this.$store.dispatch("addThirdparty", {
target: payload.target,
body: response,
});
this.$refs.onTheFly.closeModal();
})
.catch((error) => {
if (error.name === "ValidationException") {
for (let v of error.violations) {
this.$toast.open({ message: v });
}
} else {
this.$toast.open({ message: "An error occurred" });
}
},
updateComment(resource) {
console.log("updateComment", resource);
this.$store.commit("updateResource", resource);
},
});
}
},
updateComment(resource) {
console.log("updateComment", resource);
this.$store.commit("updateResource", resource);
},
},
};
</script>

View File

@@ -1,34 +1,32 @@
<template>
<a
class="btn btn-sm btn-misc change-icon"
:title="$t('write_comment')"
@click="openModal"
><i class="fa fa-pencil-square-o" />
</a>
<a
class="btn btn-sm btn-misc change-icon"
:title="$t('write_comment')"
@click="openModal"
><i class="fa fa-pencil-square-o" />
</a>
<teleport to="body">
<modal
v-if="modal.showModal"
:modal-dialog-class="modal.modalDialogClass"
@close="modal.showModal = false"
>
<template #header>
<h3 class="modal-title">
{{
$t("write_comment_about", { r: resource.resource.text })
}}
</h3>
</template>
<template #body>
<comment-editor v-model="content" />
</template>
<template #footer>
<a class="btn btn-save" @click="saveAction">
{{ $t("action.save") }}
</a>
</template>
</modal>
</teleport>
<teleport to="body">
<modal
v-if="modal.showModal"
:modal-dialog-class="modal.modalDialogClass"
@close="modal.showModal = false"
>
<template #header>
<h3 class="modal-title">
{{ $t("write_comment_about", { r: resource.resource.text }) }}
</h3>
</template>
<template #body>
<comment-editor v-model="content" />
</template>
<template #footer>
<a class="btn btn-save" @click="saveAction">
{{ $t("action.save") }}
</a>
</template>
</modal>
</teleport>
</template>
<script>
@@ -37,71 +35,71 @@ import { makeFetch } from "ChillMainAssets/lib/api/apiMethods";
import CommentEditor from "ChillMainAssets/vuejs/_components/CommentEditor/CommentEditor.vue";
export default {
name: "WriteComment",
components: {
Modal,
CommentEditor,
name: "WriteComment",
components: {
Modal,
CommentEditor,
},
props: ["resource"],
emits: ["updateComment"],
data() {
return {
modal: {
showModal: false,
modalDialogClass: "modal-dialog-scrollable modal-xl",
},
formdata: {
content: this.resource.comment,
},
};
},
i18n: {
messages: {
fr: {
write_comment: "Écrire un commentaire",
write_comment_about: "Écrire un commentaire à propos de {r}",
comment_placeholder: "Commencez à écrire...",
},
},
props: ["resource"],
emits: ["updateComment"],
data() {
return {
modal: {
showModal: false,
modalDialogClass: "modal-dialog-scrollable modal-xl",
},
formdata: {
content: this.resource.comment,
},
},
computed: {
editor: () => ClassicEditor,
editorConfig: () => classicEditorConfig,
content: {
set(value) {
this.formdata.content = value;
},
get() {
return this.formdata.content;
},
},
},
methods: {
openModal() {
//console.log('write comment for', this.resource.resource.type, this.resource.resource.id);
this.modal.showModal = true;
},
saveAction() {
//console.log('save comment', this.resource.id, this.formdata.content);
this.patchResource(this.resource.id, this.formdata.content);
},
patchResource(id, comment) {
let url = `/api/1.0/person/accompanying-period/resource/${id}.json`,
body = {
type: "accompanying_period_resource",
comment: comment,
};
makeFetch("PATCH", url, body).then((r) => {
let resource = {
type: "accompanying_period_resource",
id: r.id,
comment: r.comment,
resource: r.resource,
};
this.$emit("updateComment", resource);
this.modal.showModal = false;
});
},
i18n: {
messages: {
fr: {
write_comment: "Écrire un commentaire",
write_comment_about: "Écrire un commentaire à propos de {r}",
comment_placeholder: "Commencez à écrire...",
},
},
},
computed: {
editor: () => ClassicEditor,
editorConfig: () => classicEditorConfig,
content: {
set(value) {
this.formdata.content = value;
},
get() {
return this.formdata.content;
},
},
},
methods: {
openModal() {
//console.log('write comment for', this.resource.resource.type, this.resource.resource.id);
this.modal.showModal = true;
},
saveAction() {
//console.log('save comment', this.resource.id, this.formdata.content);
this.patchResource(this.resource.id, this.formdata.content);
},
patchResource(id, comment) {
let url = `/api/1.0/person/accompanying-period/resource/${id}.json`,
body = {
type: "accompanying_period_resource",
comment: comment,
};
makeFetch("PATCH", url, body).then((r) => {
let resource = {
type: "accompanying_period_resource",
id: r.id,
comment: r.comment,
resource: r.resource,
};
this.$emit("updateComment", resource);
this.modal.showModal = false;
});
},
},
},
};
</script>

View File

@@ -1,25 +1,25 @@
<template>
<div class="vue-component">
<h2><a id="section-70" />{{ $t("scopes.title") }}</h2>
<div class="vue-component">
<h2><a id="section-70" />{{ $t("scopes.title") }}</h2>
<div class="mb-4">
<div class="form-check" v-for="s in scopes" :key="s.id">
<input
class="form-check-input"
type="checkbox"
v-model="checkedScopes"
:value="s"
/>
<label class="form-check-label">
{{ localizeString(s.name) }}
</label>
</div>
</div>
<div v-if="!isScopeValid" class="alert alert-warning to-confirm">
{{ $t("scopes.add_at_least_one") }}
</div>
<div class="mb-4">
<div class="form-check" v-for="s in scopes" :key="s.id">
<input
class="form-check-input"
type="checkbox"
v-model="checkedScopes"
:value="s"
/>
<label class="form-check-label">
{{ localizeString(s.name) }}
</label>
</div>
</div>
<div v-if="!isScopeValid" class="alert alert-warning to-confirm">
{{ $t("scopes.add_at_least_one") }}
</div>
</div>
</template>
<script>
@@ -27,38 +27,33 @@ import { mapState, mapGetters } from "vuex";
import { localizeString } from "ChillMainAssets/lib/localizationHelper/localizationHelper";
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)
.catch(({ name, violations }) => {
if (
name === "ValidationException" ||
name === "AccessException"
) {
violations.forEach((violation) =>
this.$toast.open({ message: violation }),
);
} else {
this.$toast.open({ message: "An error occurred" });
}
});
},
},
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).catch(({ name, violations }) => {
if (name === "ValidationException" || name === "AccessException") {
violations.forEach((violation) =>
this.$toast.open({ message: violation }),
);
} else {
this.$toast.open({ message: "An error occurred" });
}
});
},
},
methods: {
localizeString,
restore() {
console.log("restore");
},
},
methods: {
localizeString,
restore() {
console.log("restore");
},
},
};
</script>

View File

@@ -1,30 +1,30 @@
<template>
<div class="vue-component">
<h2><a id="section-60" />{{ $t("social_issue.title") }}</h2>
<div class="vue-component">
<h2><a id="section-60" />{{ $t("social_issue.title") }}</h2>
<div class="my-4">
<!--label for="field">{{ $t('social_issue.label') }}</label
<div class="my-4">
<!--label for="field">{{ $t('social_issue.label') }}</label
-->
<VueMultiselect
name="field"
:close-on-select="true"
:allow-empty="true"
:show-labels="false"
track-by="id"
label="text"
:multiple="true"
:searchable="true"
:placeholder="$t('social_issue.label')"
@update:model-value="updateSocialIssues"
:model-value="value"
:options="options"
/>
</div>
<div v-if="!isSocialIssueValid" class="alert alert-warning to-confirm">
{{ $t("social_issue.not_valid") }}
</div>
<VueMultiselect
name="field"
:close-on-select="true"
:allow-empty="true"
:show-labels="false"
track-by="id"
label="text"
:multiple="true"
:searchable="true"
:placeholder="$t('social_issue.label')"
@update:model-value="updateSocialIssues"
:model-value="value"
:options="options"
/>
</div>
<div v-if="!isSocialIssueValid" class="alert alert-warning to-confirm">
{{ $t("social_issue.not_valid") }}
</div>
</div>
</template>
<script>
@@ -33,59 +33,54 @@ import { fetchResults } from "ChillMainAssets/lib/api/apiMethods";
import { mapGetters, mapState } from "vuex";
export default {
name: "SocialIssue",
components: { VueMultiselect },
data() {
return {
options: [],
};
name: "SocialIssue",
components: { VueMultiselect },
data() {
return {
options: [],
};
},
computed: {
...mapState({
value: (state) => state.accompanyingCourse.socialIssues,
}),
...mapGetters(["isSocialIssueValid"]),
},
mounted() {
this.getOptions();
},
methods: {
getOptions() {
fetchResults(`/api/1.0/person/social-work/social-issue.json`).then(
(response) => {
this.options = response;
},
);
},
computed: {
...mapState({
value: (state) => state.accompanyingCourse.socialIssues,
}),
...mapGetters(["isSocialIssueValid"]),
},
mounted() {
this.getOptions();
},
methods: {
getOptions() {
fetchResults(`/api/1.0/person/social-work/social-issue.json`).then(
(response) => {
this.options = response;
},
updateSocialIssues(value) {
this.$store
.dispatch("updateSocialIssues", this.transformValue(value))
.catch(({ name, violations }) => {
if (name === "ValidationException" || name === "AccessException") {
violations.forEach((violation) =>
this.$toast.open({ message: violation }),
);
},
updateSocialIssues(value) {
this.$store
.dispatch("updateSocialIssues", this.transformValue(value))
.catch(({ name, violations }) => {
if (
name === "ValidationException" ||
name === "AccessException"
) {
violations.forEach((violation) =>
this.$toast.open({ message: violation }),
);
} else {
this.$toast.open({ message: "An error occurred" });
}
});
},
transformValue(updated) {
let stored = this.value;
let added = updated.filter((x) => stored.indexOf(x) === -1).shift();
let removed = stored
.filter((x) => updated.indexOf(x) === -1)
.shift();
let method = typeof removed === "undefined" ? "POST" : "DELETE";
let changed = typeof removed === "undefined" ? added : removed;
let body = { type: "social_issue", id: changed.id };
let payload = updated;
return { payload, body, method };
},
} else {
this.$toast.open({ message: "An error occurred" });
}
});
},
transformValue(updated) {
let stored = this.value;
let added = updated.filter((x) => stored.indexOf(x) === -1).shift();
let removed = stored.filter((x) => updated.indexOf(x) === -1).shift();
let method = typeof removed === "undefined" ? "POST" : "DELETE";
let changed = typeof removed === "undefined" ? added : removed;
let body = { type: "social_issue", id: changed.id };
let payload = updated;
return { payload, body, method };
},
},
};
</script>
@@ -96,20 +91,20 @@ export default {
@import "ChillPersonAssets/chill/scss/mixins";
@import "ChillMainAssets/chill/scss/chill_variables";
div#accompanying-course {
span.multiselect__tag {
@include badge_social($social-issue-color);
background: $chill-l-gray;
color: $dark;
span.multiselect__tag {
@include badge_social($social-issue-color);
background: $chill-l-gray;
color: $dark;
}
span.multiselect__option--highlight {
&::after {
background: $green;
}
span.multiselect__option--highlight {
&::after {
background: $green;
}
&.multiselect__option--selected {
&::after {
background: $red;
}
}
&.multiselect__option--selected {
&::after {
background: $red;
}
}
}
}
</style>

View File

@@ -1,22 +1,22 @@
<template>
<div class="vue-component">
<h2>
<a id="section-110" />
{{ $t("startdate.change") }}
</h2>
<div>
<div class="mb-3 row">
<div class="col-sm-12 date-update">
<input
class="form-control"
type="date"
id="startDate"
v-model="startDateInput"
/>
</div>
</div>
<div class="vue-component">
<h2>
<a id="section-110" />
{{ $t("startdate.change") }}
</h2>
<div>
<div class="mb-3 row">
<div class="col-sm-12 date-update">
<input
class="form-control"
type="date"
id="startDate"
v-model="startDateInput"
/>
</div>
</div>
</div>
</div>
</template>
<script>
@@ -24,69 +24,60 @@ import { dateToISO, ISOToDatetime } from "ChillMainAssets/chill/js/date";
import { mapState } from "vuex";
export default {
name: "StartDate",
data() {
return {
lastRecordedDate: null,
};
},
computed: {
...mapState({
startDate: (state) =>
dateToISO(
ISOToDatetime(
state.accompanyingCourse.openingDate.datetime,
),
),
}),
startDateInput: {
get() {
return this.startDate;
},
set(value) {
this.lastRecordedDate = value;
name: "StartDate",
data() {
return {
lastRecordedDate: null,
};
},
computed: {
...mapState({
startDate: (state) =>
dateToISO(ISOToDatetime(state.accompanyingCourse.openingDate.datetime)),
}),
startDateInput: {
get() {
return this.startDate;
},
set(value) {
this.lastRecordedDate = value;
setTimeout(() => {
console.log("timeout finished");
if (this.lastRecordedDate === value) {
console.log(
"last recorded",
this.lastRecordedDate,
"value",
value,
);
this.$store
.dispatch("updateStartDate", value)
.catch(({ name, violations }) => {
if (
name === "ValidationException" ||
name === "AccessException"
) {
violations.forEach((violation) =>
this.$toast.open({
message: violation,
}),
);
} else {
this.$toast.open({
message: "An error occurred",
});
}
});
}
}, 3000);
},
},
setTimeout(() => {
console.log("timeout finished");
if (this.lastRecordedDate === value) {
console.log("last recorded", this.lastRecordedDate, "value", value);
this.$store
.dispatch("updateStartDate", value)
.catch(({ name, violations }) => {
if (
name === "ValidationException" ||
name === "AccessException"
) {
violations.forEach((violation) =>
this.$toast.open({
message: violation,
}),
);
} else {
this.$toast.open({
message: "An error occurred",
});
}
});
}
}, 3000);
},
},
},
};
</script>
<style lang="scss" scoped>
.date-update {
display: flex;
justify-content: space-between;
&-btn {
margin-left: 1rem;
}
display: flex;
justify-content: space-between;
&-btn {
margin-left: 1rem;
}
}
</style>

View File

@@ -1,207 +1,195 @@
<template>
<teleport to="#content">
<div id="navmap">
<nav>
<a class="top" href="#top">
<i class="fa fa-fw fa-square" />
<span>{{ $t("nav.top") }}</span>
</a>
<item
v-for="item of items"
:key="item.key"
:item="item"
:step="step"
/>
</nav>
</div>
</teleport>
<teleport to="#content">
<div id="navmap">
<nav>
<a class="top" href="#top">
<i class="fa fa-fw fa-square" />
<span>{{ $t("nav.top") }}</span>
</a>
<item v-for="item of items" :key="item.key" :item="item" :step="step" />
</nav>
</div>
</teleport>
</template>
<script>
import Item from "./StickyNav/Item.vue";
export default {
name: "StickyNav",
components: {
Item,
name: "StickyNav",
components: {
Item,
},
data() {
return {
header: document.querySelector("header nav.navbar"),
bannerName: document.querySelector("#header-accompanying_course-name"),
bannerDetails: document.querySelector(
"#header-accompanying_course-details",
),
container: null,
heightSum: null,
stickyNav: null,
limit: 25,
anchors: null,
items: [],
};
},
computed: {
accompanyingCourse() {
return this.$store.state.accompanyingCourse;
},
data() {
return {
header: document.querySelector("header nav.navbar"),
bannerName: document.querySelector(
"#header-accompanying_course-name",
),
bannerDetails: document.querySelector(
"#header-accompanying_course-details",
),
container: null,
heightSum: null,
stickyNav: null,
limit: 25,
anchors: null,
items: [],
};
step() {
return this.accompanyingCourse.step;
},
computed: {
accompanyingCourse() {
return this.$store.state.accompanyingCourse;
},
step() {
return this.accompanyingCourse.step;
},
top() {
return parseInt(
window
.getComputedStyle(this.stickyNav)
.getPropertyValue("top")
.slice(0, -2),
);
},
top() {
return parseInt(
window
.getComputedStyle(this.stickyNav)
.getPropertyValue("top")
.slice(0, -2),
);
},
mounted() {
this.ready();
window.addEventListener("scroll", this.handleScroll);
},
mounted() {
this.ready();
window.addEventListener("scroll", this.handleScroll);
},
unmounted() {
window.removeEventListener("scroll", this.handleScroll);
},
methods: {
ready() {
// load datas DOM when mounted ready
this.container = document.querySelector("#content");
this.stickyNav = document.querySelector("#navmap");
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(() => {
this.refreshPos();
});
resizeObserver.observe(this.header);
resizeObserver.observe(this.bannerName);
resizeObserver.observe(this.bannerDetails);
resizeObserver.observe(this.container);
},
unmounted() {
window.removeEventListener("scroll", this.handleScroll);
initItemsMap() {
this.anchors.forEach((anchor) => {
this.items.push({
pos: null,
active: false,
key: parseInt(anchor.id.slice(8).slice(0, -1)),
id: "#" + anchor.id,
});
});
},
methods: {
ready() {
// load datas DOM when mounted ready
this.container = document.querySelector("#content");
this.stickyNav = document.querySelector("#navmap");
this.anchors = document.querySelectorAll("h2 a[id^='section']");
this.initItemsMap();
refreshPos() {
//console.log('refreshPos');
this.heightSum =
this.header.offsetHeight +
this.bannerName.offsetHeight +
this.bannerDetails.offsetHeight;
// TODO resizeObserver not supports IE !
// Listen when elements change size, then recalculate heightSum and initItemsMap
const resizeObserver = new ResizeObserver(() => {
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.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;
posY += element.offsetTop;
element = element.offsetParent;
} while (element != null);
let pos = [];
pos["x"] = posX;
pos["y"] = posY;
return pos;
},
handleScroll() {
let pos = this.findPos(this.stickyNav);
let top = this.heightSum + this.top - window.scrollY;
//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 =
(window.scrollY >= item.pos) & (window.scrollY < next)
? true
: false;
}, this);
// 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;
} else {
this.items[this.items.length - 1].active = false;
}
},
this.anchors.forEach((anchor, i) => {
this.items[i].pos = this.findPos(anchor)["y"];
});
},
findPos(element) {
let posX = 0,
posY = 0;
do {
posX += element.offsetLeft;
posY += element.offsetTop;
element = element.offsetParent;
} while (element != null);
let pos = [];
pos["x"] = posX;
pos["y"] = posY;
return pos;
},
handleScroll() {
let pos = this.findPos(this.stickyNav);
let top = this.heightSum + this.top - window.scrollY;
//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 =
(window.scrollY >= item.pos) & (window.scrollY < next) ? true : false;
}, this);
// 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;
} else {
this.items[this.items.length - 1].active = false;
}
},
},
};
</script>
<style lang="scss">
div#content {
position: relative;
position: relative;
div#navmap {
position: absolute;
top: 30px;
left: 10px; //-10%;
nav {
font-size: small;
a {
display: block;
box-sizing: border-box;
margin-bottom: -3px;
color: #71859669;
text-decoration: none;
&.top {
color: #718596;
}
span {
display: none;
}
&:hover,
&.active {
span {
display: inline;
padding-left: 8px;
}
}
&:hover {
color: #718596b5;
}
&.active {
color: #e2793d; //orange
//color: #eec84a; //jaune
}
}
div#navmap {
position: absolute;
top: 30px;
left: 10px; //-10%;
nav {
font-size: small;
a {
display: block;
box-sizing: border-box;
margin-bottom: -3px;
color: #71859669;
text-decoration: none;
&.top {
color: #718596;
}
span {
display: none;
}
&:hover,
&.active {
span {
display: inline;
padding-left: 8px;
}
}
&:hover {
color: #718596b5;
}
&.active {
color: #e2793d; //orange
//color: #eec84a; //jaune
}
}
}
}
}
@media only screen and (max-width: 768px) {
div#navmap {
display: none;
}
div#navmap {
display: none;
}
}
</style>

View File

@@ -1,26 +1,22 @@
<template>
<a v-if="item.key <= 8" :href="item.id" :class="{ active: isActive }">
<i class="fa fa-fw fa-square" />
<span>{{ item.key }}</span>
</a>
<a
v-else-if="step === 'DRAFT'"
:href="item.id"
:class="{ active: isActive }"
>
<i class="fa fa-fw fa-square" />
<span>{{ item.key }}</span>
</a>
<a v-if="item.key <= 8" :href="item.id" :class="{ active: isActive }">
<i class="fa fa-fw fa-square" />
<span>{{ item.key }}</span>
</a>
<a v-else-if="step === 'DRAFT'" :href="item.id" :class="{ active: isActive }">
<i class="fa fa-fw fa-square" />
<span>{{ item.key }}</span>
</a>
</template>
<script>
export default {
name: "Item",
props: ["item", "step"],
computed: {
isActive() {
return this.item.active;
},
name: "Item",
props: ["item", "step"],
computed: {
isActive() {
return this.item.active;
},
},
};
</script>

View File

@@ -1,155 +1,146 @@
<template>
<div class="vue-component">
<h2>Tests</h2>
<div class="vue-component">
<h2>Tests</h2>
<!-- Modal -->
<ul class="record_actions">
<li>
<button class="btn btn-create" @click="modal1.showModal = true">
{{ $t("action.show_modal") }}
</button>
</li>
<li>
<button class="btn btn-create" @click="modal2.showModal = true">
Ouvrir une seconde modale
</button>
</li>
</ul>
<!-- Modal -->
<ul class="record_actions">
<li>
<button class="btn btn-create" @click="modal1.showModal = true">
{{ $t("action.show_modal") }}
</button>
</li>
<li>
<button class="btn btn-create" @click="modal2.showModal = true">
Ouvrir une seconde modale
</button>
</li>
</ul>
<teleport to="body">
<modal
v-if="modal1.showModal"
:modal-dialog-class="modal1.modalDialogClass"
@close="modal1.showModal = false"
>
<template #header>
<h2 class="modal-title">Le titre de ma modale</h2>
</template>
<template #body>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Phasellus luctus facilisis suscipit. Cras pulvinar,
purus sagittis pulvinar porta, enim ex posuere lacus, in
pulvinar lectus magna in odio. Nullam iaculis congue
lorem ac suscipit. Proin ut rutrum augue. Ut vehicula
risus nec hendrerit ullamcorper. Ut volutpat eu mi eget
viverra. Morbi dictum placerat suscipit.
</p>
<p>
Quisque non erat tincidunt, lacinia justo ut, pulvinar
nisl. Nunc id enim ut sem pretium interdum consectetur
eu quam. Vestibulum ante ipsum primis in faucibus orci
luctus et ultrices posuere cubilia curae; Etiam posuere
erat eget augue finibus luctus. Maecenas auctor, tortor
non luctus ultrices, neque neque porttitor ex, nec
lacinia lorem ligula et elit. Sed tempor nulla vitae
lorem sollicitudin dictum. Vestibulum nec arcu eget elit
pulvinar pretium. Phasellus facilisis metus sed diam
luctus, feugiat scelerisque velit dignissim.
</p>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Phasellus luctus facilisis suscipit. Cras pulvinar,
purus sagittis pulvinar porta, enim ex posuere lacus, in
pulvinar lectus magna in odio. Nullam iaculis congue
lorem ac suscipit. Proin ut rutrum augue. Ut vehicula
risus nec hendrerit ullamcorper. Ut volutpat eu mi eget
viverra. Morbi dictum placerat suscipit.
</p>
<p>
Quisque non erat tincidunt, lacinia justo ut, pulvinar
nisl. Nunc id enim ut sem pretium interdum consectetur
eu quam. Vestibulum ante ipsum primis in faucibus orci
luctus et ultrices posuere cubilia curae; Etiam posuere
erat eget augue finibus luctus. Maecenas auctor, tortor
non luctus ultrices, neque neque porttitor ex, nec
lacinia lorem ligula et elit. Sed tempor nulla vitae
lorem sollicitudin dictum. Vestibulum nec arcu eget elit
pulvinar pretium. Phasellus facilisis metus sed diam
luctus, feugiat scelerisque velit dignissim.
</p>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Phasellus luctus facilisis suscipit. Cras pulvinar,
purus sagittis pulvinar porta, enim ex posuere lacus, in
pulvinar lectus magna in odio. Nullam iaculis congue
lorem ac suscipit. Proin ut rutrum augue. Ut vehicula
risus nec hendrerit ullamcorper. Ut volutpat eu mi eget
viverra. Morbi dictum placerat suscipit.
</p>
<p>
Quisque non erat tincidunt, lacinia justo ut, pulvinar
nisl. Nunc id enim ut sem pretium interdum consectetur
eu quam. Vestibulum ante ipsum primis in faucibus orci
luctus et ultrices posuere cubilia curae; Etiam posuere
erat eget augue finibus luctus. Maecenas auctor, tortor
non luctus ultrices, neque neque porttitor ex, nec
lacinia lorem ligula et elit. Sed tempor nulla vitae
lorem sollicitudin dictum. Vestibulum nec arcu eget elit
pulvinar pretium. Phasellus facilisis metus sed diam
luctus, feugiat scelerisque velit dignissim.
</p>
</template>
<template #footer>
<button
class="btn btn-create"
@click="
modal1.showModal = false;
modal2.showModal = true;
"
>
{{ $t("action.next") }}
</button>
</template>
</modal>
</teleport>
<teleport to="body">
<modal
v-if="modal1.showModal"
:modal-dialog-class="modal1.modalDialogClass"
@close="modal1.showModal = false"
>
<template #header>
<h2 class="modal-title">Le titre de ma modale</h2>
</template>
<template #body>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus
luctus facilisis suscipit. Cras pulvinar, purus sagittis pulvinar
porta, enim ex posuere lacus, in pulvinar lectus magna in odio.
Nullam iaculis congue lorem ac suscipit. Proin ut rutrum augue. Ut
vehicula risus nec hendrerit ullamcorper. Ut volutpat eu mi eget
viverra. Morbi dictum placerat suscipit.
</p>
<p>
Quisque non erat tincidunt, lacinia justo ut, pulvinar nisl. Nunc id
enim ut sem pretium interdum consectetur eu quam. Vestibulum ante
ipsum primis in faucibus orci luctus et ultrices posuere cubilia
curae; Etiam posuere erat eget augue finibus luctus. Maecenas
auctor, tortor non luctus ultrices, neque neque porttitor ex, nec
lacinia lorem ligula et elit. Sed tempor nulla vitae lorem
sollicitudin dictum. Vestibulum nec arcu eget elit pulvinar pretium.
Phasellus facilisis metus sed diam luctus, feugiat scelerisque velit
dignissim.
</p>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus
luctus facilisis suscipit. Cras pulvinar, purus sagittis pulvinar
porta, enim ex posuere lacus, in pulvinar lectus magna in odio.
Nullam iaculis congue lorem ac suscipit. Proin ut rutrum augue. Ut
vehicula risus nec hendrerit ullamcorper. Ut volutpat eu mi eget
viverra. Morbi dictum placerat suscipit.
</p>
<p>
Quisque non erat tincidunt, lacinia justo ut, pulvinar nisl. Nunc id
enim ut sem pretium interdum consectetur eu quam. Vestibulum ante
ipsum primis in faucibus orci luctus et ultrices posuere cubilia
curae; Etiam posuere erat eget augue finibus luctus. Maecenas
auctor, tortor non luctus ultrices, neque neque porttitor ex, nec
lacinia lorem ligula et elit. Sed tempor nulla vitae lorem
sollicitudin dictum. Vestibulum nec arcu eget elit pulvinar pretium.
Phasellus facilisis metus sed diam luctus, feugiat scelerisque velit
dignissim.
</p>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus
luctus facilisis suscipit. Cras pulvinar, purus sagittis pulvinar
porta, enim ex posuere lacus, in pulvinar lectus magna in odio.
Nullam iaculis congue lorem ac suscipit. Proin ut rutrum augue. Ut
vehicula risus nec hendrerit ullamcorper. Ut volutpat eu mi eget
viverra. Morbi dictum placerat suscipit.
</p>
<p>
Quisque non erat tincidunt, lacinia justo ut, pulvinar nisl. Nunc id
enim ut sem pretium interdum consectetur eu quam. Vestibulum ante
ipsum primis in faucibus orci luctus et ultrices posuere cubilia
curae; Etiam posuere erat eget augue finibus luctus. Maecenas
auctor, tortor non luctus ultrices, neque neque porttitor ex, nec
lacinia lorem ligula et elit. Sed tempor nulla vitae lorem
sollicitudin dictum. Vestibulum nec arcu eget elit pulvinar pretium.
Phasellus facilisis metus sed diam luctus, feugiat scelerisque velit
dignissim.
</p>
</template>
<template #footer>
<button
class="btn btn-create"
@click="
modal1.showModal = false;
modal2.showModal = true;
"
>
{{ $t("action.next") }}
</button>
</template>
</modal>
</teleport>
<teleport to="body">
<modal
v-if="modal2.showModal"
:modal-dialog-class="modal2.modalDialogClass"
@close="modal2.showModal = false"
>
<template #header>
<h2 class="modal-title">Une autre modale</h2>
</template>
<template #body>
<p>modal 2</p>
</template>
<template #footer>
<button
class="btn btn-create"
@click="modal2.showModal = false"
>
{{ $t("action.save") }}
</button>
</template>
</modal>
</teleport>
<!-- END Modal -->
</div>
<teleport to="body">
<modal
v-if="modal2.showModal"
:modal-dialog-class="modal2.modalDialogClass"
@close="modal2.showModal = false"
>
<template #header>
<h2 class="modal-title">Une autre modale</h2>
</template>
<template #body>
<p>modal 2</p>
</template>
<template #footer>
<button class="btn btn-create" @click="modal2.showModal = false">
{{ $t("action.save") }}
</button>
</template>
</modal>
</teleport>
<!-- END Modal -->
</div>
</template>
<script>
import Modal from "ChillMainAssets/vuejs/_components/Modal";
export default {
name: "Test",
components: {
Modal,
},
data() {
return {
modal1: {
showModal: false,
modalDialogClass: "modal-dialog-scrollable modal-xl", // modal-lg modal-md modal-sm
},
modal2: {
showModal: false,
modalDialogClass: "modal-dialog-centered modal-sm", // modal-lg modal-md modal-sm
},
};
},
computed: {},
name: "Test",
components: {
Modal,
},
data() {
return {
modal1: {
showModal: false,
modalDialogClass: "modal-dialog-scrollable modal-xl", // modal-lg modal-md modal-sm
},
modal2: {
showModal: false,
modalDialogClass: "modal-dialog-centered modal-sm", // modal-lg modal-md modal-sm
},
};
},
computed: {},
};
</script>