Clean skeleton (and add Junie guidelines)

This commit is contained in:
2025-06-04 08:13:35 +00:00
parent 4c0c66bdb4
commit 49cbb6a002
146 changed files with 14778 additions and 30737 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%;
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;
&.errors {
//display: flex;
//position: sticky;
//bottom: 0.3em;
//z-index: 1000;
margin: 1em 0;
padding: 1em;
border-radius: 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,35 +1,38 @@
<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"
/>
<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>
<div v-if="!isAdminLocationValid" class="alert alert-warning to-confirm">
{{ $t("admin_location.not_valid") }}
</div>
</div>
</template>
<script>
@@ -38,67 +41,72 @@ import { fetchResults } from "ChillMainAssets/lib/api/apiMethods";
import { mapState, mapGetters } from "vuex";
export default {
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;
});
name: "AdminLocation",
components: { VueMultiselect },
data() {
return {
options: [],
};
},
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" });
}
});
computed: {
...mapState({
value: (state) => state.accompanyingCourse.administrativeLocation,
}),
...mapGetters(["isAdminLocationValid"]),
},
customLabel(value) {
return value.locationType
? value.name
? `${value.name} (${value.locationType.title.fr})`
: value.locationType.title.fr
: "";
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
: "";
},
},
},
};
</script>
<style src="vue-multiselect/dist/vue-multiselect.css"></style>
<style lang="css" scoped>
label {
display: none;
display: none;
}
</style>

View File

@@ -1,106 +1,132 @@
<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"
<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"
>
<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
: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
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>
<persons-associated
:accompanying-course="accompanyingCourse"
:shortlist="false"
/>
</teleport>
</template>
<script>
@@ -109,30 +135,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,123 +1,129 @@
<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 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>
<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 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>
</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,
},
props: ["accompanyingCourse", "shortlist"],
data() {
return {
showAllPersons: false,
maxTotalPersons: 2,
nbShortList: 3,
};
},
computed: {
participations() {
return this.accompanyingCourse.participations.filter(
(p) => p.endDate === null,
);
name: "PersonsAssociated",
components: {
OnTheFly,
},
persons() {
return this.participations.map((p) => p.person);
props: ["accompanyingCourse", "shortlist"],
data() {
return {
showAllPersons: false,
maxTotalPersons: 2,
nbShortList: 3,
};
},
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);
});
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);
});
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,142 +1,158 @@
<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;
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;
},
},
isEmergency() {
return this.emergency ? 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" });
}
});
},
},
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;
text-decoration: underline;
border-radius: 20px;
}
i {
margin: auto 0.4em;
}
span.on {
font-weight: bolder;
}
cursor: pointer;
&:hover {
color: white;
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,36 +1,38 @@
<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>
<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") }}
<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>
</template>
</modal>
</teleport>
</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>
</template>
<script>
@@ -39,49 +41,52 @@ 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" });
}
});
window.location.assign("#section-20");
this.modal.showModal = false;
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;
},
},
},
};
</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>
<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>
<form @submit.prevent="submitform">
<label class="col-form-label" for="content">{{
$t("comment.label")
}}</label>
<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>
</form>
</div>
</div>
</template>
<script>
@@ -58,113 +58,127 @@ 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" });
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 : "";
},
}, 3000);
},
get() {
return this.pinnedComment ? this.pinnedComment.content : "";
},
},
errors() {
return this.$store.state.errorMsg;
},
},
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" });
}
});
},
},
},
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,120 +1,127 @@
<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 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>
<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>
<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"
<teleport to="body">
<modal
v-if="modal.showModal"
:modal-dialog-class="modal.modalDialogClass"
@close="modal.showModal = false"
>
<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 #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>
@@ -123,106 +130,112 @@ 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,
},
disableConfirm() {
return (
this.accompanyingCourse.user === null &&
this.usersSuggestedFilteredByJob.length === 1 &&
this.clickedDoNotChooseReferrer === false
);
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,
};
},
},
methods: {
confirmCourse() {
this.$store
.dispatch("confirmAccompanyingCourse")
.catch(({ name, violations }) => {
if (name === "ValidationException" || name === "AccessException") {
violations.forEach((violation) =>
this.$toast.open({ message: violation }),
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
);
} 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" });
}
});
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;
},
},
doNotChooseSuggestedReferrer() {
this.clickedDoNotChooseReferrer = true;
},
},
};
</script>

View File

@@ -1,85 +1,95 @@
<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
v-for="error in displayErrors"
class="alert alert-danger my-2"
:key="error"
>
{{ error }}
</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 v-if="hasNoLocation">
<label class="chill-no-data-statement">
{{ $t("courselocation.no_address") }}
</label>
</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 class="flex-table" v-if="accompanyingCourse.location">
<div class="item-bloc">
<address-render-box :address="accompanyingCourse.location" />
<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="isPersonLocation"
class="alert alert-secondary separator"
>
<label class="col-form-label">
{{
$t("courselocation.person_locator", [
accompanyingCourse.personLocation.text,
])
}}
</label>
</div>
<div v-if="!isLocationValid" class="alert alert-warning to-confirm">
{{ $t("courselocation.not_valid") }}
<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>
</div>
</template>
<script>
@@ -88,171 +98,177 @@ 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",
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,
},
},
},
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;
},
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 }),
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,
);
} else {
this.$toast.open({ message: "An error occurred" });
}
});
},
hasNoPersonLocation() {
let addressInParticipations_ = [];
this.currentParticipations.forEach((p) => {
addressInParticipations_.push(
this.checkHouseholdAddressForParticipation(p),
);
});
this.$store.commit("setEditContextTrue", payload);
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;
},
},
},
created() {
this.initAddressContext();
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" });
}
});
//console.log('ac.locationStatus', this.accompanyingCourse.locationStatus);
//console.log('ac.location (temporary location)', this.accompanyingCourse.location);
//console.log('ac.personLocation', this.accompanyingCourse.personLocation);
},
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);
},
};
</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.vue-component {
& > div.alert.no-person-location {
margin: 1px 0 0;
}
}
}
div.flex-table {
div.item-bloc {
div.alert {
margin: 0 -0.9em -1em;
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"
/>
<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>
<div v-if="!isOriginValid" class="alert alert-warning to-confirm">
{{ $t("origin.not_valid") }}
</div>
</div>
</template>
<script>
@@ -36,58 +36,61 @@ import { makeFetch } from "ChillMainAssets/lib/api/apiMethods";
import { mapState, mapGetters } from "vuex";
export default {
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 });
});
name: "OriginDemand",
components: { VueMultiselect },
data() {
return {
options: [],
};
},
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" });
}
});
computed: {
...mapState({
value: (state) => state.accompanyingCourse.origin,
}),
...mapGetters(["isOriginValid"]),
},
transText({ text }) {
return text.fr;
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;
},
},
},
};
</script>
<style src="vue-multiselect/dist/vue-multiselect.css"></style>
<style lang="css" scoped>
label {
display: none;
display: none;
}
</style>

View File

@@ -1,106 +1,121 @@
<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 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>
</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)"
<div
v-if="participationWithoutHousehold.length > 0"
class="alert alert-warning no-household"
>
<person-text :person="p" />
</li>
</ul>
</div>
<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>
<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 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="!isParticipationValid" class="alert alert-warning to-confirm">
{{ $t("persons_associated.participation_not_valid") }}
<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>
</div>
</template>
<script>
@@ -110,157 +125,176 @@ 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
);
},
},
methods: {
removeParticipation(item) {
this.$store
.dispatch("removeParticipation", item)
.catch(({ name, violations }) => {
if (name === "ValidationException" || name === "AccessException") {
violations.forEach((violation) =>
this.$toast.open({ message: violation }),
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,
);
} 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 }),
},
getReturnPath() {
return (
window.location.pathname +
window.location.search +
window.location.hash
);
} 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;
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" });
}
});
},
},
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,97 +1,98 @@
<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>
<teleport to="body">
<modal
v-if="modal.showModal"
:modal-dialog-class="modal.modalDialogClass"
@close="modal.showModal = false"
<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 #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 #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"
>
{{ $t("persons_associated.ok") }}
</button>
</template>
</modal>
</teleport>
<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>
</template>
<script>
@@ -102,135 +103,135 @@ import Modal from "ChillMainAssets/vuejs/_components/Modal";
import { makeFetch } from "ChillMainAssets/lib/api/apiMethods";
export default {
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;
name: "ParticipationItem",
components: {
OnTheFly,
ButtonLocation,
PersonRenderBox,
Modal,
},
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,
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,
},
},
};
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" });
}
});
}
},
},
computed: {
hasCurrentHouseholdAddress() {
if (
!this.participation.endDate &&
this.participation.person.current_household_address !== null
) {
return true;
}
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";
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" });
}
});
}
},
},
};
</script>

View File

@@ -1,111 +1,116 @@
<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 })
"
<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')"
/>
</div>
</template>
<template #footer>
<button class="btn btn-save" @click.prevent="this.confirmReferrer">
{{ $t("confirm.ok_referrer") }}
</button>
</template>
</modal>
</teleport>
<label class="col-form-label" for="selectReferrer">
{{ $t("referrer.label") }}
</label>
<div>
<label class="col-form-label" for="selectJob">
{{ $t("job.label") }}
</label>
<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')"
/>
<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 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>
<label class="col-form-label" for="selectReferrer">
{{ $t("referrer.label") }}
</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>
<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 v-if="!isJobValid" class="alert alert-warning to-confirm">
{{ $t("job.not_valid") }}
</div>
</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>
@@ -116,124 +121,134 @@ import UserRenderBoxBadge from "ChillMainAssets/vuejs/_components/Entity/UserRen
import Modal from "ChillMainAssets/vuejs/_components/Modal";
export default {
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;
name: "Referrer",
components: {
UserRenderBoxBadge,
VueMultiselect,
Modal,
},
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" });
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;
},
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();
},
methods: {
updateReferrer(value) {
this.value = value;
this.toggleModal();
mounted() {
this.getJobs();
},
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 });
});
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();
},
},
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,239 +1,263 @@
<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">
<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)"
<div
v-if="accompanyingCourse.requestor && isAnonymous"
class="flex-table"
>
<person-text v-if="p.type === 'person'" :person="p" />
<span v-else>{{ p.text }}</span>
</li>
</ul>
</div>
<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>
<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>
<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">
<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>
</div>
</template>
<script>
@@ -247,208 +271,221 @@ 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,
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;
},
},
};
},
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;
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 }),
);
} 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,
);
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;
return true;
})
);
},
}),
accompanyingCourse() {
return this.$store.state.accompanyingCourse;
},
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 }),
);
} else {
this.$toast.open({ message: "An error occurred" });
}
});
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 };
}
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" });
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" });
}
});
}
});
} 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}`;
},
},
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 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 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 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>
<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>
</div>
</template>
<script>
@@ -61,117 +61,126 @@ 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" });
}
});
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}`;
},
},
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;
}
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" });
hasCurrentHouseholdAddress() {
if (this.resource.resource.current_household_address !== null) {
return true;
}
});
} 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);
return false;
},
},
methods: {
saveFormOnTheFly(payload) {
// console.log('saveFormOnTheFly: type', payload.type, ', data', payload.data);
payload.target = "resource";
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" });
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" });
}
});
}
});
}
},
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,32 +1,34 @@
<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>
@@ -35,71 +37,71 @@ import { makeFetch } from "ChillMainAssets/lib/api/apiMethods";
import CommentEditor from "ChillMainAssets/vuejs/_components/CommentEditor/CommentEditor.vue";
export default {
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...",
},
name: "WriteComment",
components: {
Modal,
CommentEditor,
},
},
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,
props: ["resource"],
emits: ["updateComment"],
data() {
return {
modal: {
showModal: false,
modalDialogClass: "modal-dialog-scrollable modal-xl",
},
formdata: {
content: this.resource.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 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 v-if="!isScopeValid" class="alert alert-warning to-confirm">
{{ $t("scopes.add_at_least_one") }}
</div>
</div>
</div>
</template>
<script>
@@ -27,33 +27,38 @@ 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>
<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 v-if="!isSocialIssueValid" class="alert alert-warning to-confirm">
{{ $t("social_issue.not_valid") }}
</div>
</div>
</div>
</template>
<script>
@@ -33,54 +33,59 @@ import { fetchResults } from "ChillMainAssets/lib/api/apiMethods";
import { mapGetters, mapState } from "vuex";
export default {
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;
},
);
name: "SocialIssue",
components: { VueMultiselect },
data() {
return {
options: [],
};
},
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 }),
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;
},
);
} else {
this.$toast.open({ message: "An error occurred" });
}
});
},
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 };
},
},
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>
@@ -91,20 +96,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__option--highlight {
&::after {
background: $green;
span.multiselect__tag {
@include badge_social($social-issue-color);
background: $chill-l-gray;
color: $dark;
}
&.multiselect__option--selected {
&::after {
background: $red;
}
span.multiselect__option--highlight {
&::after {
background: $green;
}
&.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 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>
</div>
</div>
</template>
<script>
@@ -24,56 +24,69 @@ 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;
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);
},
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);
},
},
},
},
};
</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,195 +1,207 @@
<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,
},
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;
name: "StickyNav",
components: {
Item,
},
step() {
return this.accompanyingCourse.step;
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: [],
};
},
top() {
return parseInt(
window
.getComputedStyle(this.stickyNav)
.getPropertyValue("top")
.slice(0, -2),
);
computed: {
accompanyingCourse() {
return this.$store.state.accompanyingCourse;
},
step() {
return this.accompanyingCourse.step;
},
top() {
return parseInt(
window
.getComputedStyle(this.stickyNav)
.getPropertyValue("top")
.slice(0, -2),
);
},
},
},
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();
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();
});
// 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);
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(event) {
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;
}
},
},
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(event) {
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;
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
}
}
}
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,22 +1,26 @@
<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,146 +1,155 @@
<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>

View File

@@ -1,14 +0,0 @@
{
"name": "vendor_name/AccompanyingCourse",
"description": "description",
"minimum-stability": "stable",
"license": "proprietary",
"authors": [
{
"name": "mat",
"email": "email@example.com"
}
],
"require": {
}
}