Merge remote-tracking branch 'origin/master' into ticket-app-master

This commit is contained in:
Julien Fastré 2025-06-20 12:53:20 +02:00
commit 45e193ff6d
Signed by: julienfastre
GPG Key ID: BDE2190974723FCB
49 changed files with 7986 additions and 7490 deletions

View File

@ -0,0 +1,7 @@
kind: Fixed
body: |
Allow null and cast as string to setContent method for NewsItem
time: 2025-06-19T17:01:42.125730402+02:00
custom:
Issue: "392"
SchemaChange: No schema change

View File

@ -46,7 +46,7 @@ stages:
build:
stage: Composer install
image: gitea.champs-libres.be/chill-project/chill-skeleton-basic/base-image:php82
image: chill/base-image:8.3-edge
before_script:
- composer config -g cache-dir "$(pwd)/.cache"
script:
@ -61,7 +61,7 @@ build:
code_style:
stage: Tests
image: gitea.champs-libres.be/chill-project/chill-skeleton-basic/base-image:php82
image: chill/base-image:8.3-edge
script:
- php-cs-fixer fix --dry-run -v --show-progress=none
cache:
@ -74,7 +74,7 @@ code_style:
phpstan_tests:
stage: Tests
image: gitea.champs-libres.be/chill-project/chill-skeleton-basic/base-image:php82
image: chill/base-image:8.3-edge
variables:
COMPOSER_MEMORY_LIMIT: 3G
before_script:
@ -91,7 +91,7 @@ phpstan_tests:
rector_tests:
stage: Tests
image: gitea.champs-libres.be/chill-project/chill-skeleton-basic/base-image:php82
image: chill/base-image:8.3-edge
before_script:
- bin/console cache:clear --env=dev
script:
@ -132,7 +132,7 @@ lint:
unit_tests:
stage: Tests
image: gitea.champs-libres.be/chill-project/chill-skeleton-basic/base-image:php82
image: chill/base-image:8.3-edge
variables:
COMPOSER_MEMORY_LIMIT: 3G
before_script:

View File

@ -70,9 +70,9 @@ class NewsItem implements TrackCreationInterface, TrackUpdateInterface
return $this->content;
}
public function setContent(string $content): void
public function setContent(?string $content): void
{
$this->content = $content;
$this->content = (string) $content;
}
public function getStartDate(): ?\DateTimeImmutable

View File

@ -2,10 +2,10 @@
<span class="chill-entity entity-user">
{{ user.label }}
<span class="user-job" v-if="user.user_job !== null"
>({{ localizeString(user.user_job.label) }})</span
> ({{ localizeString(user.user_job.label) }})</span
>
<span class="main-scope" v-if="user.main_scope !== null"
>({{ localizeString(user.main_scope.name) }})</span
> ({{ localizeString(user.main_scope.name) }})</span
>
<span
v-if="user.isAbsent"
@ -22,8 +22,8 @@ import { localizeString } from "ChillMainAssets/lib/localizationHelper/localizat
export default {
name: "UserRenderBoxBadge",
methods: {
localizeString() {
return localizeString;
localizeString(label) {
return localizeString(label);
},
},
props: ["user"],

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,135 +1,152 @@
<template>
<h2>{{ $t("pick_social_issue") }}</h2>
<h2>{{ $t("pick_social_issue") }}</h2>
<div id="awc_create_form">
<div id="picking" class="">
<p>{{ $t("pick_social_issue_linked_with_action") }}</p>
<div v-for="si in socialIssues" :key="si.id">
<input
type="radio"
:value="si.id"
name="socialIssue"
v-model="socialIssuePicked"
/><span class="badge bg-chill-l-gray text-dark">{{ si.text }}</span>
</div>
<div class="my-3">
<div class="col-11">
<vue-multiselect
name="otherIssues"
label="text"
track-by="id"
open-direction="bottom"
:close-on-select="true"
:preserve-search="false"
:reset-after="true"
:hide-selected="true"
:taggable="false"
:multiple="false"
:searchable="true"
:allow-empty="true"
:show-labels="false"
:loading="issueIsLoading"
:placeholder="$t('choose_other_social_issue')"
:options="socialIssuesOther"
@select="addIssueInList"
/>
</div>
</div>
<div v-if="hasSocialIssuePicked" class="mb-3">
<h2>{{ $t("pick_an_action") }}</h2>
<div class="col-11">
<vue-multiselect
v-model="socialActionPicked"
label="text"
:options="socialActionsReachables"
:searchable="true"
:close-on-select="true"
:show-labels="true"
track-by="id"
/>
</div>
</div>
<div v-if="isLoadingSocialActions">
<i class="fa fa-circle-o-notch fa-spin fa-fw" />
</div>
<div v-if="hasSocialActionPicked" id="persons" class="mb-5">
<h2>{{ $t("persons_involved") }}</h2>
<ul>
<li v-for="p in personsReachables" :key="p.id">
<div class="form-check">
<input
type="checkbox"
:value="p.id"
v-model="personsPicked"
class="form-check-input"
:id="'person_check' + p.id"
/>
<label class="form-check-label" :for="'person_check' + p.id">
<person-text :person="p" />
</label>
<div id="awc_create_form">
<div id="picking" class="">
<p>{{ $t("pick_social_issue_linked_with_action") }}</p>
<div v-for="si in socialIssues" :key="si.id">
<input
type="radio"
:value="si.id"
name="socialIssue"
v-model="socialIssuePicked"
/><span class="badge bg-chill-l-gray text-dark">{{
si.text
}}</span>
</div>
</li>
</ul>
</div>
</div>
<!-- <div v-if="hasSocialActionPicked" id="start_date">
<div class="my-3">
<div class="col-11">
<vue-multiselect
name="otherIssues"
label="text"
track-by="id"
open-direction="bottom"
:close-on-select="true"
:preserve-search="false"
:reset-after="true"
:hide-selected="true"
:taggable="false"
:multiple="false"
:searchable="true"
:allow-empty="true"
:show-labels="false"
:loading="issueIsLoading"
:placeholder="$t('choose_other_social_issue')"
:options="socialIssuesOther"
@select="addIssueInList"
/>
</div>
</div>
<div v-if="hasSocialIssuePicked" class="mb-3">
<h2>{{ $t("pick_an_action") }}</h2>
<div class="col-11">
<vue-multiselect
v-model="socialActionPicked"
label="text"
:options="socialActionsReachables"
:searchable="true"
:close-on-select="true"
:show-labels="true"
track-by="id"
/>
</div>
</div>
<div v-if="isLoadingSocialActions">
<i class="fa fa-circle-o-notch fa-spin fa-fw" />
</div>
<div v-if="hasSocialActionPicked" id="persons" class="mb-5">
<h2>{{ $t("persons_involved") }}</h2>
<ul>
<li v-for="p in personsReachables" :key="p.id">
<div class="form-check">
<input
type="checkbox"
:value="p.id"
v-model="personsPicked"
class="form-check-input"
:id="'person_check' + p.id"
/>
<label
class="form-check-label"
:for="'person_check' + p.id"
>
<person-text :person="p" />
</label>
</div>
</li>
</ul>
</div>
</div>
<!-- <div v-if="hasSocialActionPicked" id="start_date">
<p><label>{{ $t('startDate') }}</label> <input type="date" v-model="startDate" /></p>
</div> -->
<div class="row">
<div v-if="hasSocialActionPicked" id="start_date" class="mb-3 row">
<label class="col-form-label col-sm-4">{{ $t("startDate") }}</label>
<div class="col-sm-8">
<input class="form-control" type="date" v-model="startDate" />
</div>
</div>
<div class="row">
<div v-if="hasSocialActionPicked" id="start_date" class="mb-3 row">
<label class="col-form-label col-sm-4">{{
$t("startDate")
}}</label>
<div class="col-sm-8">
<input
class="form-control"
type="date"
v-model="startDate"
/>
</div>
</div>
<!-- <div v-if="hasSocialActionPicked" id="end_date">
<!-- <div v-if="hasSocialActionPicked" id="end_date">
<p><label>{{ $t('endDate') }}</label> <input type="date" v-model="endDate" /></p>
</div> -->
<div v-if="hasSocialActionPicked" id="end_date" class="mb-3 row">
<label class="col-form-label col-sm-4">{{ $t("endDate") }}</label>
<div class="col-sm-8">
<input class="form-control" type="date" v-model="endDate" />
<div v-if="hasSocialActionPicked" id="end_date" class="mb-3 row">
<label class="col-form-label col-sm-4">{{
$t("endDate")
}}</label>
<div class="col-sm-8">
<input class="form-control" type="date" v-model="endDate" />
</div>
</div>
</div>
</div>
</div>
<div id="confirm">
<div v-if="hasErrors">
<p>{{ $t("form_has_errors") }}</p>
<div id="confirm">
<div v-if="hasErrors">
<p>{{ $t("form_has_errors") }}</p>
<ul>
<li v-for="e in errors" :key="e.id">
{{ e }}
</li>
</ul>
</div>
<ul>
<li v-for="e in errors" :key="e.id">
{{ e }}
</li>
</ul>
</div>
<div>
<ul class="record_actions">
<li class="cancel">
<button class="btn btn-cancel" @click="goToPrevious">
{{ $t("action.cancel") }}
</button>
</li>
<li v-if="hasSocialActionPicked">
<button
class="btn btn-save"
v-show="!isPostingWork"
@click="submit"
>
{{ $t("action.save") }}
</button>
<button class="btn btn-save" v-show="isPostingWork" disabled>
{{ $t("action.save") }}
</button>
</li>
</ul>
</div>
<div>
<ul class="record_actions">
<li class="cancel">
<button class="btn btn-cancel" @click="goToPrevious">
{{ $t("action.cancel") }}
</button>
</li>
<li v-if="hasSocialActionPicked">
<button
class="btn btn-save"
v-show="!isPostingWork"
@click="submit"
>
{{ $t("action.save") }}
</button>
<button
class="btn btn-save"
v-show="isPostingWork"
disabled
>
{{ $t("action.save") }}
</button>
</li>
</ul>
</div>
</div>
</div>
</div>
</template>
<script>
@ -138,127 +155,131 @@ import VueMultiselect from "vue-multiselect";
import PersonText from "ChillPersonAssets/vuejs/_components/Entity/PersonText.vue";
const i18n = {
messages: {
fr: {
startDate: "Date de début",
endDate: "Date de fin",
form_has_errors: "Le formulaire comporte des erreurs",
pick_social_issue: "Choisir une problématique sociale",
pick_other_social_issue: "Veuillez choisir un autre problématique",
pick_an_action: "Choisir une action d'accompagnement",
pick_social_issue_linked_with_action:
"Indiquez la problématique sociale liée à l'action d'accompagnement",
persons_involved: "Usagers concernés",
choose_other_social_issue: "Veuillez choisir un autre problématique",
messages: {
fr: {
startDate: "Date de début",
endDate: "Date de fin",
form_has_errors: "Le formulaire comporte des erreurs",
pick_social_issue: "Choisir une problématique sociale",
pick_other_social_issue: "Veuillez choisir un autre problématique",
pick_an_action: "Choisir une action d'accompagnement",
pick_social_issue_linked_with_action:
"Indiquez la problématique sociale liée à l'action d'accompagnement",
persons_involved: "Usagers concernés",
choose_other_social_issue:
"Veuillez choisir un autre problématique",
},
},
},
};
export default {
name: "App",
components: {
VueMultiselect,
PersonText,
},
methods: {
submit() {
this.$store.dispatch("submit").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: "App",
components: {
VueMultiselect,
PersonText,
},
addIssueInList(value) {
this.$store.commit("addIssueInList", value);
this.$store.commit("removeIssueInOther", value);
this.$store.dispatch("pickSocialIssue", value.id);
methods: {
submit() {
this.$store.dispatch("submit").catch(({ name, violations }) => {
if (
name === "ValidationException" ||
name === "AccessException"
) {
violations.forEach((violation) =>
this.$toast.open({ message: violation }),
);
} else {
this.$toast.open({ message: "An error occurred" });
}
});
},
addIssueInList(value) {
this.$store.commit("addIssueInList", value);
this.$store.commit("removeIssueInOther", value);
this.$store.dispatch("pickSocialIssue", value.id);
},
goToPrevious() {
let params = new URLSearchParams(window.location.search);
if (params.has("returnPath")) {
window.location.replace(params.get("returnPath"));
} else {
return;
}
},
},
goToPrevious() {
let params = new URLSearchParams(window.location.search);
if (params.has("returnPath")) {
window.location.replace(params.get("returnPath"));
} else {
return;
}
},
},
i18n,
computed: {
...mapState([
"socialIssues",
"socialIssuesOther",
"socialActionsReachables",
"errors",
"personsReachables",
]),
...mapGetters([
"hasSocialIssuePicked",
"hasSocialActionPicked",
"isLoadingSocialActions",
"isPostingWork",
"hasErrors",
]),
personsPicked: {
get() {
let s = this.$store.state.personsPicked.map((p) => p.id);
i18n,
computed: {
...mapState([
"socialIssues",
"socialIssuesOther",
"socialActionsReachables",
"errors",
"personsReachables",
]),
...mapGetters([
"hasSocialIssuePicked",
"hasSocialActionPicked",
"isLoadingSocialActions",
"isPostingWork",
"hasErrors",
]),
personsPicked: {
get() {
let s = this.$store.state.personsPicked.map((p) => p.id);
return s;
},
set(v) {
this.$store.commit("setPersonsPickedIds", v);
},
},
socialIssuePicked: {
get() {
let s = this.$store.state.socialIssuePicked;
return s;
},
set(v) {
this.$store.commit("setPersonsPickedIds", v);
},
},
socialIssuePicked: {
get() {
let s = this.$store.state.socialIssuePicked;
if (s === null) {
return null;
}
if (s === null) {
return null;
}
return s.id;
},
set(value) {
this.$store.dispatch("pickSocialIssue", value);
},
return s.id;
},
set(value) {
this.$store.dispatch("pickSocialIssue", value);
},
},
socialActionPicked: {
get() {
return this.$store.state.socialActionPicked;
},
set(value) {
this.$store.commit("setSocialAction", value);
},
},
startDate: {
get() {
return this.$store.state.startDate;
},
set(value) {
this.$store.commit("setStartDate", value);
},
},
endDate: {
get() {
return this.$store.state.endDate;
},
set(value) {
this.$store.commit("setEndDate", value);
},
},
setSocialIssue: {
set() {
this.$store.dispatch(
"setSocialIssue",
socialIssues[socialIssues.length - 1],
);
},
},
},
socialActionPicked: {
get() {
return this.$store.state.socialActionPicked;
},
set(value) {
this.$store.commit("setSocialAction", value);
},
},
startDate: {
get() {
return this.$store.state.startDate;
},
set(value) {
this.$store.commit("setStartDate", value);
},
},
endDate: {
get() {
return this.$store.state.endDate;
},
set(value) {
this.$store.commit("setEndDate", value);
},
},
setSocialIssue: {
set() {
this.$store.dispatch(
"setSocialIssue",
socialIssues[socialIssues.length - 1],
);
},
},
},
};
</script>
@ -267,46 +288,46 @@ 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;
margin-left: 1em;
@include badge_social($social-issue-color);
font-size: 95%;
margin-bottom: 5px;
margin-right: 1em;
margin-left: 1em;
}
</style>
<style lang="scss">
#awc_create_form {
display: grid;
grid-template-areas:
"picking picking"
"start_date end_date"
"confirm confirm";
grid-template-columns: 50% 50%;
column-gap: 1.5rem;
display: grid;
grid-template-areas:
"picking picking"
"start_date end_date"
"confirm confirm";
grid-template-columns: 50% 50%;
column-gap: 1.5rem;
#picking {
grid-area: picking;
#picking {
grid-area: picking;
#persons {
ul {
padding: 0;
#persons {
ul {
padding: 0;
list-style-type: none;
}
list-style-type: none;
}
}
}
}
#start_date {
grid-area: start_date;
}
#start_date {
grid-area: start_date;
}
#end_date {
grid-area: end_date;
}
#end_date {
grid-area: end_date;
}
#confirm {
grid-area: confirm;
}
#confirm {
grid-area: confirm;
}
}
</style>

View File

@ -1,67 +1,70 @@
<template>
<div>
<a id="evaluations"></a>
<div class="item-title" :title="evaluation.id || 'no id yet'">
<span>{{ localizeString(evaluation.evaluation.title) }}</span>
</div>
<div class="item-url mt-3 mb-4" v-if="evaluation.evaluation.url">
<i class="fa fa-link fa-lg"></i>
<a :href="evaluation.evaluation.url" target="_blank">{{
evaluation.evaluation.url
}}</a>
</div>
<div>
<form-evaluation
ref="FormEvaluation"
:key="evaluation.key"
:evaluation="evaluation"
:docAnchorId="docAnchorId"
></form-evaluation>
<a id="evaluations"></a>
<div class="item-title" :title="evaluation.id || 'no id yet'">
<span>{{ localizeString(evaluation.evaluation.title) }}</span>
</div>
<ul class="record_actions">
<li v-if="evaluation.workflows_availables.length > 0">
<list-workflow-modal
:workflows="evaluation.workflows"
:allowCreate="true"
relatedEntityClass="Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluation"
:relatedEntityId="evaluation.id"
:workflowsAvailables="evaluation.workflows_availables"
@go-to-generate-workflow="goToGenerateWorkflow"
></list-workflow-modal>
</li>
<li v-if="canDelete">
<a
class="btn btn-delete"
@click="modal.showModal = true"
:title="$t('action.delete')"
>{{ $t("delete_evaluation") }}</a
>
</li>
</ul>
<div class="item-url mt-3 mb-4" v-if="evaluation.evaluation.url">
<i class="fa fa-link fa-lg"></i>
<a :href="evaluation.evaluation.url" target="_blank">{{
evaluation.evaluation.url
}}</a>
</div>
<div>
<form-evaluation
ref="FormEvaluation"
:key="evaluation.key"
:evaluation="evaluation"
:docAnchorId="docAnchorId"
></form-evaluation>
<ul class="record_actions">
<li v-if="evaluation.workflows_availables.length > 0">
<list-workflow-modal
:workflows="evaluation.workflows"
:allowCreate="true"
relatedEntityClass="Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluation"
:relatedEntityId="evaluation.id"
:workflowsAvailables="evaluation.workflows_availables"
@go-to-generate-workflow="goToGenerateWorkflow"
></list-workflow-modal>
</li>
<li v-if="canDelete">
<a
class="btn btn-delete"
@click="modal.showModal = true"
:title="$t('action.delete')"
>{{ $t("delete_evaluation") }}</a
>
</li>
</ul>
</div>
<teleport to="body">
<modal
v-if="modal.showModal"
:modalDialogClass="modal.modalDialogClass"
@close="modal.showModal = false"
>
<template v-slot:header>
<h2 class="modal-title">{{ $t("delete.sure") }}</h2>
</template>
<template v-slot:body>
<p>{{ $t("delete.sure_description") }}</p>
</template>
<template v-slot:footer>
<button
class="btn btn-danger"
@click="removeEvaluation(evaluation)"
>
{{ $t("delete.ok") }}
</button>
</template>
</modal>
</teleport>
</div>
<teleport to="body">
<modal
v-if="modal.showModal"
:modalDialogClass="modal.modalDialogClass"
@close="modal.showModal = false"
>
<template v-slot:header>
<h2 class="modal-title">{{ $t("delete.sure") }}</h2>
</template>
<template v-slot:body>
<p>{{ $t("delete.sure_description") }}</p>
</template>
<template v-slot:footer>
<button class="btn btn-danger" @click="removeEvaluation(evaluation)">
{{ $t("delete.ok") }}
</button>
</template>
</modal>
</teleport>
</div>
</template>
<script>
@ -72,112 +75,114 @@ import { buildLinkCreate } from "ChillMainAssets/lib/entity-workflow/api";
import { localizeString } from "ChillMainAssets/lib/localizationHelper/localizationHelper";
const i18n = {
messages: {
fr: {
no_evaluation_associated: "Aucune évaluation associée",
add_an_evaluation: "Évaluations disponibles",
evaluation_has_no_evaluation: "Aucune évaluation disponible",
startDate: "Date d'ouverture",
endDate: "Date de fin",
maxDate: "Date d'échéance",
warningInterval: "Rappel (jours)",
comment: "Note publique",
documents: "Documents",
delete: {
sure: "Êtes-vous sûr?",
sure_description:
"Cette évaluation sera supprimée de cette action d'accompagnement",
ok: "Supprimer",
},
delete_evaluation: "Supprimer l'évaluation",
messages: {
fr: {
no_evaluation_associated: "Aucune évaluation associée",
add_an_evaluation: "Évaluations disponibles",
evaluation_has_no_evaluation: "Aucune évaluation disponible",
startDate: "Date d'ouverture",
endDate: "Date de fin",
maxDate: "Date d'échéance",
warningInterval: "Rappel (jours)",
comment: "Note publique",
documents: "Documents",
delete: {
sure: "Êtes-vous sûr?",
sure_description:
"Cette évaluation sera supprimée de cette action d'accompagnement",
ok: "Supprimer",
},
delete_evaluation: "Supprimer l'évaluation",
},
},
},
};
export default {
name: "AddEvaluation",
components: {
FormEvaluation,
Modal,
ListWorkflowModal,
},
props: ["evaluation", "docAnchorId"],
i18n,
data() {
return {
modal: {
showModal: false,
modalDialogClass: "modal-dialog-centered modal-md",
},
};
},
computed: {
pickedEvaluations() {
return this.$store.state.evaluationsPicked;
name: "AddEvaluation",
components: {
FormEvaluation,
Modal,
ListWorkflowModal,
},
canDelete() {
if (this.evaluation.workflows.length > 0) {
return false;
}
props: ["evaluation", "docAnchorId"],
i18n,
data() {
return {
modal: {
showModal: false,
modalDialogClass: "modal-dialog-centered modal-md",
},
};
},
computed: {
pickedEvaluations() {
return this.$store.state.evaluationsPicked;
},
canDelete() {
if (this.evaluation.workflows.length > 0) {
return false;
}
for (let doc of this.evaluation.documents) {
if (doc.workflows.length > 0) {
return false;
}
}
for (let doc of this.evaluation.documents) {
if (doc.workflows.length > 0) {
return false;
}
}
return true;
return true;
},
},
},
methods: {
localizeString,
removeEvaluation(e) {
this.$store.commit("removeEvaluation", e);
return;
},
toggleEditEvaluation() {
this.$store.commit("toggleEvaluationEdit", { key: this.evaluation.key });
},
submitForm() {
this.toggleEditEvaluation();
},
goToGenerateWorkflow({ workflowName }) {
const callback = (data) => {
let evaluationId = data.accompanyingPeriodWorkEvaluations.find(
(e) => e.key === this.evaluation.key,
).id;
window.location.assign(
buildLinkCreate(
workflowName,
"Chill\\PersonBundle\\Entity\\AccompanyingPeriod\\AccompanyingPeriodWorkEvaluation",
evaluationId,
),
);
};
methods: {
localizeString,
removeEvaluation(e) {
this.$store.commit("removeEvaluation", e);
return;
},
toggleEditEvaluation() {
this.$store.commit("toggleEvaluationEdit", {
key: this.evaluation.key,
});
},
submitForm() {
this.toggleEditEvaluation();
},
goToGenerateWorkflow({ workflowName }) {
const callback = (data) => {
let evaluationId = data.accompanyingPeriodWorkEvaluations.find(
(e) => e.key === this.evaluation.key,
).id;
window.location.assign(
buildLinkCreate(
workflowName,
"Chill\\PersonBundle\\Entity\\AccompanyingPeriod\\AccompanyingPeriodWorkEvaluation",
evaluationId,
),
);
};
return this.$store.dispatch("submit", callback).catch((e) => {
console.log(e);
throw e;
});
return this.$store.dispatch("submit", callback).catch((e) => {
console.log(e);
throw e;
});
},
},
},
};
</script>
<style lang="scss" scoped>
div.item-title {
.evaluation-title {
cursor: default;
&::before {
content: "";
.evaluation-title {
cursor: default;
&::before {
content: "";
}
}
}
}
div.item-url {
i {
color: unset !important;
margin-left: 1rem;
margin-right: 0.5rem;
}
i {
color: unset !important;
margin-left: 1rem;
margin-right: 0.5rem;
}
}
</style>

View File

@ -1,167 +1,179 @@
<template>
<div v-if="hasResult" class="addResult">
<p v-if="pickedResults.length === 0" class="chill-no-data-statement">
Aucun résultat associé
</p>
<div v-if="hasResult" class="addResult">
<p v-if="pickedResults.length === 0" class="chill-no-data-statement">
Aucun résultat associé
</p>
<ul class="list-suggest remove-items">
<li v-for="r in pickedResults" @click="removeResult(r)" :key="r.id">
<span>
{{ localizeString(r.title) }}
</span>
</li>
</ul>
<ul class="list-suggest remove-items">
<li v-for="r in pickedResults" @click="removeResult(r)" :key="r.id">
<span>
{{ localizeString(r.title) }}
</span>
</li>
</ul>
<div class="accordion" id="expandedSuggestions">
<div class="accordion-item">
<h2 class="accordion-header" id="heading_expanded_suggestions">
<button
v-if="isExpanded"
class="accordion-button"
type="button"
data-bs-toggle="collapse"
aria-expanded="true"
@click="toggleSelect"
>
Masquer
</button>
<div class="accordion" id="expandedSuggestions">
<div class="accordion-item">
<h2 class="accordion-header" id="heading_expanded_suggestions">
<button
v-if="isExpanded"
class="accordion-button"
type="button"
data-bs-toggle="collapse"
aria-expanded="true"
@click="toggleSelect"
>
Masquer
</button>
<button
v-else
class="accordion-button collapsed"
type="button"
data-bs-toggle="collapse"
aria-expanded="false"
@click="toggleSelect"
>
Résultats et orientations disponibles
</button>
</h2>
<div
class="accordion-collapse"
id="collapse_expanded_suggestions"
aria-labelledby="heading_expanded_suggestions"
data-bs-parent="#expandedSuggestions"
>
<template v-if="isExpanded">
<ul class="list-suggest add-items">
<li
v-for="r in availableForCheckResults"
@click="addResult(r)"
:key="r.id"
>
<span>{{ localizeString(r.title) }}</span>
</li>
</ul>
</template>
<button
v-else
class="accordion-button collapsed"
type="button"
data-bs-toggle="collapse"
aria-expanded="false"
@click="toggleSelect"
>
Résultats et orientations disponibles
</button>
</h2>
<div
class="accordion-collapse"
id="collapse_expanded_suggestions"
aria-labelledby="heading_expanded_suggestions"
data-bs-parent="#expandedSuggestions"
>
<template v-if="isExpanded">
<ul class="list-suggest add-items">
<li
v-for="r in availableForCheckResults"
@click="addResult(r)"
:key="r.id"
>
<span>{{ localizeString(r.title) }}</span>
</li>
</ul>
</template>
</div>
</div>
</div>
</div>
</div>
</div>
<div v-if="!hasResult" class="noResult">
<div class="chill-no-data-statement">
{{ $t("goal_has_no_result") }}
<div v-if="!hasResult" class="noResult">
<div class="chill-no-data-statement">
{{ $t("goal_has_no_result") }}
</div>
</div>
</div>
</template>
<script>
import { localizeString } from "ChillMainAssets/lib/localizationHelper/localizationHelper";
const i18n = {
messages: {
fr: {
add_a_result: "Résultat - orientation disponibles",
goal_has_no_result: "Aucun résultat - orientation disponible",
messages: {
fr: {
add_a_result: "Résultat - orientation disponibles",
goal_has_no_result: "Aucun résultat - orientation disponible",
},
},
},
};
export default {
name: "AddResult",
props: ["destination", "goal", "availableResults"],
i18n,
data() {
return {
isExpanded: false,
};
},
computed: {
hasResult() {
if (this.destination === "action") {
return this.$store.state.resultsForAction.length > 0;
} else if (this.destination === "goal") {
return this.$store.getters.resultsForGoal(this.goal).length > 0;
}
name: "AddResult",
props: ["destination", "goal", "availableResults"],
i18n,
data() {
return {
isExpanded: false,
};
},
computed: {
hasResult() {
if (this.destination === "action") {
return this.$store.state.resultsForAction.length > 0;
} else if (this.destination === "goal") {
return this.$store.getters.resultsForGoal(this.goal).length > 0;
}
throw Error(`this.destination is not implemented: ${this.destination}`);
},
pickedResults() {
if (this.destination === "action") {
return this.$store.state.resultsPicked;
} else if (this.destination === "goal") {
return this.$store.getters.resultsPickedForGoal(this.goal);
}
throw Error(
`this.destination is not implemented: ${this.destination}`,
);
},
pickedResults() {
if (this.destination === "action") {
return this.$store.state.resultsPicked;
} else if (this.destination === "goal") {
return this.$store.getters.resultsPickedForGoal(this.goal);
}
throw Error(`this.destination is not implemented: ${this.destination}`);
},
availableForCheckResults() {
if (this.destination === "action") {
let pickedIds = this.$store.state.resultsPicked.map((r) => r.id);
throw Error(
`this.destination is not implemented: ${this.destination}`,
);
},
availableForCheckResults() {
if (this.destination === "action") {
let pickedIds = this.$store.state.resultsPicked.map(
(r) => r.id,
);
return this.$store.state.resultsForAction.filter(
(r) => !pickedIds.includes(r.id),
);
} else if (this.destination === "goal") {
let pickedIds = this.$store.getters
.resultsPickedForGoal(this.goal)
.map((r) => r.id);
return this.$store.state.resultsForAction.filter(
(r) => !pickedIds.includes(r.id),
);
} else if (this.destination === "goal") {
let pickedIds = this.$store.getters
.resultsPickedForGoal(this.goal)
.map((r) => r.id);
return this.$store.getters
.resultsForGoal(this.goal)
.filter((r) => !pickedIds.includes(r.id));
}
return this.$store.getters
.resultsForGoal(this.goal)
.filter((r) => !pickedIds.includes(r.id));
}
throw Error(`this.destination is not implemented: ${this.destination}`);
throw Error(
`this.destination is not implemented: ${this.destination}`,
);
},
},
},
methods: {
localizeString,
toggleSelect() {
this.isExpanded = !this.isExpanded;
methods: {
localizeString,
toggleSelect() {
this.isExpanded = !this.isExpanded;
},
addResult(r) {
if (this.destination === "action") {
this.$store.commit("addResultPicked", r);
return;
} else if (this.destination === "goal") {
this.$store.commit("addResultForGoalPicked", {
goal: this.goal,
result: r,
});
return;
}
throw Error(
`this.destination is not implemented: ${this.destination}`,
);
},
removeResult(r) {
if (this.destination === "action") {
this.$store.commit("removeResultPicked", r);
return;
} else if (this.destination === "goal") {
this.$store.commit("removeResultForGoalPicked", {
goal: this.goal,
result: r,
});
return;
}
throw Error(
`this.destination is not implemented: ${this.destination}`,
);
},
},
addResult(r) {
if (this.destination === "action") {
this.$store.commit("addResultPicked", r);
return;
} else if (this.destination === "goal") {
this.$store.commit("addResultForGoalPicked", {
goal: this.goal,
result: r,
});
return;
}
throw Error(`this.destination is not implemented: ${this.destination}`);
},
removeResult(r) {
if (this.destination === "action") {
this.$store.commit("removeResultPicked", r);
return;
} else if (this.destination === "goal") {
this.$store.commit("removeResultForGoalPicked", {
goal: this.goal,
result: r,
});
return;
}
throw Error(`this.destination is not implemented: ${this.destination}`);
},
},
};
</script>
<style lang="scss" scoped>
.accordion-button {
padding: 0.25rem;
padding: 0.25rem;
}
</style>

View File

@ -1,447 +1,445 @@
<template>
<fieldset class="mb-3" id="actionType">
<div class="row">
<legend class="col-sm-4 col-form-label">
{{ $t("action.label") }}
</legend>
<div class="col-sm-8">
<VueMultiselect
v-model="action"
:options="actions.options"
@select="selectAction"
@remove="unselectAction"
:multiple="true"
:close-on-select="false"
:placeholder="$t('action.placeholder')"
:custom-label="formatSocialAction"
track-by="id"
:searchable="true"
/>
</div>
</div>
</fieldset>
<fieldset class="mb-3" id="actionType">
<div class="row">
<legend class="col-sm-4 col-form-label">
{{ $t("action.label") }}
</legend>
<div class="col-sm-8">
<VueMultiselect
v-model="action"
:options="actions.options"
@select="selectAction"
@remove="unselectAction"
:multiple="true"
:close-on-select="false"
:placeholder="$t('action.placeholder')"
:custom-label="formatSocialAction"
track-by="id"
:searchable="true"
/>
</div>
</div>
</fieldset>
<fieldset class="mb-3" id="goal">
<div class="row">
<legend class="col-sm-4 col-form-label">
{{ $t("goal.label") }}
</legend>
<div class="col-sm-8">
<VueMultiselect
v-model="goal"
:options="goals.options"
@select="selectGoal"
@remove="unselectGoal"
:multiple="true"
:close-on-select="false"
:placeholder="$t('goal.placeholder')"
label="title"
:custom-label="transTitle"
track-by="id"
:searchable="true"
/>
</div>
</div>
</fieldset>
<fieldset class="mb-3" id="goal">
<div class="row">
<legend class="col-sm-4 col-form-label">
{{ $t("goal.label") }}
</legend>
<div class="col-sm-8">
<VueMultiselect
v-model="goal"
:options="goals.options"
@select="selectGoal"
@remove="unselectGoal"
:multiple="true"
:close-on-select="false"
:placeholder="$t('goal.placeholder')"
label="title"
:custom-label="transTitle"
track-by="id"
:searchable="true"
/>
</div>
</div>
</fieldset>
<fieldset class="mb-3" id="result">
<div class="row">
<legend class="col-sm-4 col-form-label">
{{ $t("result.label") }}
</legend>
<div class="col-sm-8">
<VueMultiselect
v-model="result"
:options="results.options"
@select="selectResult"
@remove="unselectResult"
:multiple="true"
:close-on-select="false"
:placeholder="$t('result.placeholder')"
label="title"
:custom-label="transTitle"
track-by="id"
:searchable="true"
/>
</div>
</div>
</fieldset>
<fieldset class="mb-3" id="result">
<div class="row">
<legend class="col-sm-4 col-form-label">
{{ $t("result.label") }}
</legend>
<div class="col-sm-8">
<VueMultiselect
v-model="result"
:options="results.options"
@select="selectResult"
@remove="unselectResult"
:multiple="true"
:close-on-select="false"
:placeholder="$t('result.placeholder')"
label="title"
:custom-label="transTitle"
track-by="id"
:searchable="true"
/>
</div>
</div>
</fieldset>
</template>
<script>
import VueMultiselect from "vue-multiselect";
import {
getSocialActions,
getGoalByAction,
getResultByAction,
getResultByGoal,
getSocialActions,
getGoalByAction,
getResultByAction,
getResultByGoal,
} from "./api";
export default {
name: "App",
components: {
VueMultiselect,
},
i18n: {
messages: {
fr: {
name: "App",
components: {
VueMultiselect,
},
i18n: {
messages: {
fr: {
action: {
label: "Types d'actions",
placeholder: "Choisissez une ou plusieurs actions",
},
goal: {
label: "Objectifs",
placeholder: "Choisissez un ou plusieurs objectifs",
},
result: {
label: "Résultats",
placeholder: "Choisissez un ou plusieurs résultats",
},
},
},
},
data() {
return {
actions: {
options: [], // array with multiselect options
value: [], // array with selected values
hiddenField: document.getElementById(
"export_filters_social_work_type_filter_form_actionType",
),
},
goals: {
options: [],
value: [],
hiddenField: document.getElementById(
"export_filters_social_work_type_filter_form_goal",
),
},
results: {
options: [],
value: [],
hiddenField: document.getElementById(
"export_filters_social_work_type_filter_form_result",
),
},
};
},
computed: {
action: {
label: "Types d'actions",
placeholder: "Choisissez une ou plusieurs actions",
get() {
return this.actions.value;
},
set(value) {
this.actions.value = value;
this.rebuildHiddenFieldValues("actions");
},
},
goal: {
label: "Objectifs",
placeholder: "Choisissez un ou plusieurs objectifs",
get() {
return this.goals.value;
},
set(value) {
this.goals.value = value;
this.rebuildHiddenFieldValues("goals");
},
},
result: {
label: "Résultats",
placeholder: "Choisissez un ou plusieurs résultats",
get() {
return this.results.value;
},
set(value) {
this.results.value = value;
this.rebuildHiddenFieldValues("results");
},
},
},
},
},
data() {
return {
actions: {
options: [], // array with multiselect options
value: [], // array with selected values
hiddenField: document.getElementById(
"export_filters_social_work_type_filter_form_actionType",
),
},
goals: {
options: [],
value: [],
hiddenField: document.getElementById(
"export_filters_social_work_type_filter_form_goal",
),
},
results: {
options: [],
value: [],
hiddenField: document.getElementById(
"export_filters_social_work_type_filter_form_result",
),
},
};
},
computed: {
action: {
get() {
return this.actions.value;
},
set(value) {
this.actions.value = value;
this.rebuildHiddenFieldValues("actions");
},
},
goal: {
get() {
return this.goals.value;
},
set(value) {
this.goals.value = value;
this.rebuildHiddenFieldValues("goals");
},
},
result: {
get() {
return this.results.value;
},
set(value) {
this.results.value = value;
this.rebuildHiddenFieldValues("results");
},
},
},
async mounted() {
await this.getSocialActionsList();
async mounted() {
await this.getSocialActionsList();
if ("" !== this.actions.hiddenField.value) {
const actionIds = this.actions.hiddenField.value.split(",");
for (const aid of actionIds) {
let action = this.actions.options.find(
(a) => Number.parseInt(aid) === a.id,
);
if (undefined !== action) {
this.action.push(action);
await this.selectAction(action);
}
}
}
if ("" !== this.goals.hiddenField.value) {
const goalsIds = this.goals.hiddenField.value
.split(",")
.map((s) => Number.parseInt(s));
for (const gid of goalsIds) {
let goal = this.goals.options.find((g) => gid === g.id);
if (undefined !== goal) {
this.goal.push(goal);
await this.selectGoal(goal);
}
}
}
if ("" !== this.results.hiddenField.value) {
const resultsIds = this.results.hiddenField.value
.split(",")
.map((s) => Number.parseInt(s));
for (const rid of resultsIds) {
let result = this.results.options.find((r) => rid === r.id);
if (undefined !== result) {
this.result.push(result);
}
}
}
},
methods: {
async getSocialActionsList() {
let actions = await getSocialActions();
this.actions.options = actions.toSorted(function (a, b) {
if (a.issue.ordering === b.issue.ordering) {
if (a.ordering === b.ordering) {
return 0;
}
if (a.ordering < b.ordering) {
return -1;
}
return 1;
if ("" !== this.actions.hiddenField.value) {
const actionIds = this.actions.hiddenField.value.split(",");
for (const aid of actionIds) {
let action = this.actions.options.find(
(a) => Number.parseInt(aid) === a.id,
);
if (undefined !== action) {
this.action.push(action);
await this.selectAction(action);
}
}
}
if (a.issue.ordering < b.issue.ordering) {
return -1;
if ("" !== this.goals.hiddenField.value) {
const goalsIds = this.goals.hiddenField.value
.split(",")
.map((s) => Number.parseInt(s));
for (const gid of goalsIds) {
let goal = this.goals.options.find((g) => gid === g.id);
if (undefined !== goal) {
this.goal.push(goal);
await this.selectGoal(goal);
}
}
}
return 1;
});
return Promise.resolve();
if ("" !== this.results.hiddenField.value) {
const resultsIds = this.results.hiddenField.value
.split(",")
.map((s) => Number.parseInt(s));
for (const rid of resultsIds) {
let result = this.results.options.find((r) => rid === r.id);
if (undefined !== result) {
this.result.push(result);
}
}
}
},
methods: {
async getSocialActionsList() {
let actions = await getSocialActions();
this.actions.options = actions.toSorted(function (a, b) {
if (a.issue.ordering === b.issue.ordering) {
if (a.ordering === b.ordering) {
return 0;
}
if (a.ordering < b.ordering) {
return -1;
}
return 1;
}
formatSocialAction({ text, issue }) {
return text + " (" + issue.text + ")";
},
if (a.issue.ordering < b.issue.ordering) {
return -1;
}
/**
* Select/unselect in Action Multiselect
* @param value
*/
async selectAction(value) {
//console.log('----'); console.log('select action', value.id);
let children = this.getChildrensFromParent(value);
this.addSelectedElement("actions", children);
return 1;
});
let parentAndChildren = [...[value], ...children];
const promises = [];
parentAndChildren.forEach((elem) => {
promises.push(
getGoalByAction(elem.id).then((goals) => {
this.addElementInData("goals", goals);
return Promise.resolve();
}),
);
promises.push(
getResultByAction(elem.id).then((results) => {
this.addElementInData("results", results);
},
formatSocialAction({ text, issue }) {
return text + " (" + issue.text + ")";
},
/**
* Select/unselect in Action Multiselect
* @param value
*/
async selectAction(value) {
//console.log('----'); console.log('select action', value.id);
let children = this.getChildrensFromParent(value);
this.addSelectedElement("actions", children);
let parentAndChildren = [...[value], ...children];
const promises = [];
parentAndChildren.forEach((elem) => {
promises.push(
getGoalByAction(elem.id).then((goals) => {
this.addElementInData("goals", goals);
return Promise.resolve();
}),
);
promises.push(
getResultByAction(elem.id).then((results) => {
this.addElementInData("results", results);
return Promise.resolve();
}),
);
});
await Promise.all(promises);
return Promise.resolve();
}),
);
});
},
await Promise.all(promises);
return Promise.resolve();
unselectAction(value) {
getGoalByAction(value.id).then((goals) => {
[this.results.options, this.results.value] =
this.removeElementInData("goals", goals);
});
getResultByAction(value.id).then((results) => {
[this.results.options, this.results.value] =
this.removeElementInData("results", results);
});
},
/**
* Select/unselect in Goal Multiselect
* @param value
*/
async selectGoal(value) {
return getResultByGoal(value.id).then((results) => {
this.addElementInData("results", results);
});
},
unselectGoal(value) {
getResultByGoal(value.id).then(
(results) =>
([this.results.options, this.results.value] =
this.removeElementInData("results", results)),
).catch;
},
// selectResult(value) {
//console.log('----'); console.log('select result', value.id);
// },
// unselectResult(value) {
//console.log('----'); console.log('unselect result', value.id);
// },
/**
* Choose parent action will involve retaining the "children" actions.
* @param value
* @return array
*/
getChildrensFromParent(value) {
if (null === value.parent) {
let excludeParent = this.actions.options.filter(
(o) => o.parent !== null,
);
let children = excludeParent.filter(
(o) => o.parent.id === value.id,
);
//console.log("get childrens", children.map(e => e.id));
return children;
}
return [];
},
/**
* Add response elements in data target
* @param target string -> 'actions', 'goals' or 'results'
* @param response array of objects with fetch results
*/
addElementInData(target, response) {
let data = this[target];
let dump = [];
response.forEach((elem) => {
let found = data.options.some((e) => e.id === elem.id);
if (!found) {
data.options.push(elem);
dump.push(elem.id);
}
});
if (dump.length > 0) {
//console.log('push ' + dump.length + ' elems in', target, dump);
}
data.options.sort();
},
/**
* Remove response elements from data target
* @param target string -> 'actions', 'goals' or 'results'
* @param response array of objects with fetch results
* @returns data.<target>.options
*/
removeElementInData(target, response) {
let data = this[target];
let dump = [];
response.forEach((elem) => {
let found = data.options.some((e) => e.id === elem.id);
if (found) {
data.options = data.options.filter((e) => e.id !== elem.id);
dump.push(elem.id);
this.removeSelectedElement(target, elem);
}
});
if (dump.length > 0) {
//console.log('remove ' + dump.length + ' elems from ' + target + ' options', dump);
}
return [data.options, data.value];
},
/**
*
* @param target
* @param elements
*/
addSelectedElement(target, elements) {
let data = this[target];
let dump = [];
elements.forEach((elem) => {
let selected = data.value.some((e) => e.id === elem.id);
if (!selected) {
data.value.push(elem);
dump.push(elem.id);
// add in hiddenField
this.rebuildHiddenFieldValues(target);
}
});
if (dump.length > 0) {
//console.log('add ' + dump.length + ' selected elems in', target, dump);
}
},
/**
* Remove element from selected and from hiddenField
* @param target
* @param elem
*/
removeSelectedElement(target, elem) {
let data = this[target];
let selected = data.value.some((e) => e.id === elem.id);
if (selected) {
// remove from selected
data.value = data.value.filter((e) => e.id !== elem.id);
//console.log('remove ' + elem.id + ' from selected ' + target);
// remove from hiddenField
this.rebuildHiddenFieldValues(target);
// in any cases, remove should be recursive
this.unselectToNextField(target, elem);
}
},
/**
* When unselect Action, it could remove elements in goals multiselect.
* In that case, we have to unselect Goal to remove elements in results too.
* @param target
* @param elem
*/
unselectToNextField(target, elem) {
if (target === "goals") {
//console.log('!!!! target is goal: unselect goal', elem.id);
this.unselectGoal(elem);
//console.log('!!!! done');
}
},
/**
* Rebuild values serie (string) in target HiddenField
* @param target
*/
rebuildHiddenFieldValues(target) {
let data = this[target];
//console.log('rebuild hiddenFields ' + target + ' values :');
data.hiddenField.value = ""; // reset
data.value.forEach((elem) => {
data.hiddenField.value = this.addIdToValue(
data.hiddenField.value,
elem.id,
);
});
//console.log(data.hiddenField);
},
addIdToValue(string, id) {
let array = string ? string.split(",") : [];
array.push(id.toString());
let str = array.join();
return str;
},
transTitle({ title }) {
return title.fr; //TODO multilang
},
},
unselectAction(value) {
getGoalByAction(value.id).then((goals) => {
[this.results.options, this.results.value] = this.removeElementInData(
"goals",
goals,
);
});
getResultByAction(value.id).then((results) => {
[this.results.options, this.results.value] = this.removeElementInData(
"results",
results,
);
});
},
/**
* Select/unselect in Goal Multiselect
* @param value
*/
async selectGoal(value) {
return getResultByGoal(value.id).then((results) => {
this.addElementInData("results", results);
});
},
unselectGoal(value) {
getResultByGoal(value.id).then(
(results) =>
([this.results.options, this.results.value] =
this.removeElementInData("results", results)),
).catch;
},
// selectResult(value) {
//console.log('----'); console.log('select result', value.id);
// },
// unselectResult(value) {
//console.log('----'); console.log('unselect result', value.id);
// },
/**
* Choose parent action will involve retaining the "children" actions.
* @param value
* @return array
*/
getChildrensFromParent(value) {
if (null === value.parent) {
let excludeParent = this.actions.options.filter(
(o) => o.parent !== null,
);
let children = excludeParent.filter((o) => o.parent.id === value.id);
//console.log("get childrens", children.map(e => e.id));
return children;
}
return [];
},
/**
* Add response elements in data target
* @param target string -> 'actions', 'goals' or 'results'
* @param response array of objects with fetch results
*/
addElementInData(target, response) {
let data = this[target];
let dump = [];
response.forEach((elem) => {
let found = data.options.some((e) => e.id === elem.id);
if (!found) {
data.options.push(elem);
dump.push(elem.id);
}
});
if (dump.length > 0) {
//console.log('push ' + dump.length + ' elems in', target, dump);
}
data.options.sort();
},
/**
* Remove response elements from data target
* @param target string -> 'actions', 'goals' or 'results'
* @param response array of objects with fetch results
* @returns data.<target>.options
*/
removeElementInData(target, response) {
let data = this[target];
let dump = [];
response.forEach((elem) => {
let found = data.options.some((e) => e.id === elem.id);
if (found) {
data.options = data.options.filter((e) => e.id !== elem.id);
dump.push(elem.id);
this.removeSelectedElement(target, elem);
}
});
if (dump.length > 0) {
//console.log('remove ' + dump.length + ' elems from ' + target + ' options', dump);
}
return [data.options, data.value];
},
/**
*
* @param target
* @param elements
*/
addSelectedElement(target, elements) {
let data = this[target];
let dump = [];
elements.forEach((elem) => {
let selected = data.value.some((e) => e.id === elem.id);
if (!selected) {
data.value.push(elem);
dump.push(elem.id);
// add in hiddenField
this.rebuildHiddenFieldValues(target);
}
});
if (dump.length > 0) {
//console.log('add ' + dump.length + ' selected elems in', target, dump);
}
},
/**
* Remove element from selected and from hiddenField
* @param target
* @param elem
*/
removeSelectedElement(target, elem) {
let data = this[target];
let selected = data.value.some((e) => e.id === elem.id);
if (selected) {
// remove from selected
data.value = data.value.filter((e) => e.id !== elem.id);
//console.log('remove ' + elem.id + ' from selected ' + target);
// remove from hiddenField
this.rebuildHiddenFieldValues(target);
// in any cases, remove should be recursive
this.unselectToNextField(target, elem);
}
},
/**
* When unselect Action, it could remove elements in goals multiselect.
* In that case, we have to unselect Goal to remove elements in results too.
* @param target
* @param elem
*/
unselectToNextField(target, elem) {
if (target === "goals") {
//console.log('!!!! target is goal: unselect goal', elem.id);
this.unselectGoal(elem);
//console.log('!!!! done');
}
},
/**
* Rebuild values serie (string) in target HiddenField
* @param target
*/
rebuildHiddenFieldValues(target) {
let data = this[target];
//console.log('rebuild hiddenFields ' + target + ' values :');
data.hiddenField.value = ""; // reset
data.value.forEach((elem) => {
data.hiddenField.value = this.addIdToValue(
data.hiddenField.value,
elem.id,
);
});
//console.log(data.hiddenField);
},
addIdToValue(string, id) {
let array = string ? string.split(",") : [];
array.push(id.toString());
let str = array.join();
return str;
},
transTitle({ title }) {
return title.fr; //TODO multilang
},
},
};
</script>

View File

@ -1,53 +1,53 @@
<template>
<ol class="breadcrumb">
<li
v-for="s in steps"
:key="s"
class="breadcrumb-item"
:class="{ active: step === s }"
>
{{ $t("household_members_editor.app.steps." + s) }}
</li>
</ol>
<concerned v-if="step === 'concerned'" />
<household v-if="step === 'household'" @ready-to-go="goToNext" />
<household-address v-if="step === 'household_address'" />
<positioning v-if="step === 'positioning'" />
<dates v-if="step === 'confirm'" />
<confirmation v-if="step === 'confirm'" />
<ol class="breadcrumb">
<li
v-for="s in steps"
:key="s"
class="breadcrumb-item"
:class="{ active: step === s }"
>
{{ $t("household_members_editor.app.steps." + s) }}
</li>
</ol>
<concerned v-if="step === 'concerned'" />
<household v-if="step === 'household'" @ready-to-go="goToNext" />
<household-address v-if="step === 'household_address'" />
<positioning v-if="step === 'positioning'" />
<dates v-if="step === 'confirm'" />
<confirmation v-if="step === 'confirm'" />
<ul class="record_actions sticky-form-buttons">
<li class="cancel" v-if="step !== 'concerned'">
<button class="btn btn-cancel" @click="goToPrevious">
{{ $t("household_members_editor.app.previous") }}
</button>
</li>
<li class="cancel" v-else-if="hasReturnPath">
<button class="btn btn-cancel" @click="goToPrevious">
{{ $t("household_members_editor.app.cancel") }}
</button>
</li>
<li v-if="step !== 'confirm'">
<button
class="btn btn-action"
@click="goToNext"
:disabled="!isNextAllowed"
>
{{ $t("household_members_editor.app.next") }}&nbsp;<i
class="fa fa-arrow-right"
/>
</button>
</li>
<li v-else>
<button
class="btn btn-save"
@click="confirm"
:disabled="hasWarnings || !lastStepIsSaveAllowed"
>
{{ $t("household_members_editor.app.save") }}
</button>
</li>
</ul>
<ul class="record_actions sticky-form-buttons">
<li class="cancel" v-if="step !== 'concerned'">
<button class="btn btn-cancel" @click="goToPrevious">
{{ $t("household_members_editor.app.previous") }}
</button>
</li>
<li class="cancel" v-else-if="hasReturnPath">
<button class="btn btn-cancel" @click="goToPrevious">
{{ $t("household_members_editor.app.cancel") }}
</button>
</li>
<li v-if="step !== 'confirm'">
<button
class="btn btn-action"
@click="goToNext"
:disabled="!isNextAllowed"
>
{{ $t("household_members_editor.app.next") }}&nbsp;<i
class="fa fa-arrow-right"
/>
</button>
</li>
<li v-else>
<button
class="btn btn-save"
@click="confirm"
:disabled="hasWarnings || !lastStepIsSaveAllowed"
>
{{ $t("household_members_editor.app.save") }}
</button>
</li>
</ul>
</template>
<script>
@ -60,123 +60,123 @@ import Confirmation from "./components/Confirmation.vue";
import Positioning from "./components/Positioning";
export default {
name: "App",
components: {
Positioning,
Concerned,
Household,
HouseholdAddress,
Dates,
Confirmation,
},
data() {
return {
step: "concerned",
};
},
computed: {
...mapState({
hasWarnings: (state) =>
state.warnings.length > 0 || state.errors.length > 0,
}),
steps() {
let s = ["concerned", "household"];
if (this.$store.getters.isHouseholdNew) {
s.push("household_address");
}
if (!this.$store.getters.isModeLeave) {
s.push("positioning");
}
s.push("confirm");
return s;
name: "App",
components: {
Positioning,
Concerned,
Household,
HouseholdAddress,
Dates,
Confirmation,
},
hasReturnPath() {
let params = new URLSearchParams(window.location.search);
data() {
return {
step: "concerned",
};
},
computed: {
...mapState({
hasWarnings: (state) =>
state.warnings.length > 0 || state.errors.length > 0,
}),
steps() {
let s = ["concerned", "household"];
return params.has("returnPath");
},
// return true if the next step is allowed
isNextAllowed() {
switch (this.$data.step) {
case "concerned":
return this.$store.state.concerned.length > 0;
case "household":
return this.$store.state.mode !== null;
case "household_address":
return (
this.$store.getters.hasHouseholdAddress ||
this.$store.getters.isHouseholdForceNoAddress
);
case "positioning":
return (
this.$store.getters.hasHouseholdOrLeave &&
this.$store.getters.hasPersonsWellPositionnated
);
}
if (this.$store.getters.isHouseholdNew) {
s.push("household_address");
}
return false;
},
lastStepIsSaveAllowed() {
let r =
!this.$store.getters.isHouseholdNew ||
(this.$store.state.numberOfChildren !== null &&
this.$store.state.householdCompositionType !== null);
console.log("is saved allowed ?", r);
if (!this.$store.getters.isModeLeave) {
s.push("positioning");
}
return r;
},
},
methods: {
goToNext() {
console.log("go to next");
switch (this.$data.step) {
case "concerned":
this.$data.step = "household";
break;
case "household":
if (this.$store.getters.isHouseholdNew) {
this.$data.step = "household_address";
break;
} else if (this.$store.getters.isModeLeave) {
this.$data.step = "confirm";
break;
} else {
this.$data.step = "positioning";
break;
}
case "household_address":
this.$data.step = "positioning";
break;
case "positioning":
this.$data.step = "confirm";
break;
}
},
goToPrevious() {
if (this.$data.step === "concerned") {
let params = new URLSearchParams(window.location.search);
if (params.has("returnPath")) {
window.location.replace(params.get("returnPath"));
} else {
return;
}
}
s.push("confirm");
let s = this.steps;
let index = s.indexOf(this.$data.step);
if (s[index - 1] === undefined) {
throw Error("step not found");
}
return s;
},
hasReturnPath() {
let params = new URLSearchParams(window.location.search);
this.$data.step = s[index - 1];
return params.has("returnPath");
},
// return true if the next step is allowed
isNextAllowed() {
switch (this.$data.step) {
case "concerned":
return this.$store.state.concerned.length > 0;
case "household":
return this.$store.state.mode !== null;
case "household_address":
return (
this.$store.getters.hasHouseholdAddress ||
this.$store.getters.isHouseholdForceNoAddress
);
case "positioning":
return (
this.$store.getters.hasHouseholdOrLeave &&
this.$store.getters.hasPersonsWellPositionnated
);
}
return false;
},
lastStepIsSaveAllowed() {
let r =
!this.$store.getters.isHouseholdNew ||
(this.$store.state.numberOfChildren !== null &&
this.$store.state.householdCompositionType !== null);
console.log("is saved allowed ?", r);
return r;
},
},
confirm() {
this.$store.dispatch("confirm");
methods: {
goToNext() {
console.log("go to next");
switch (this.$data.step) {
case "concerned":
this.$data.step = "household";
break;
case "household":
if (this.$store.getters.isHouseholdNew) {
this.$data.step = "household_address";
break;
} else if (this.$store.getters.isModeLeave) {
this.$data.step = "confirm";
break;
} else {
this.$data.step = "positioning";
break;
}
case "household_address":
this.$data.step = "positioning";
break;
case "positioning":
this.$data.step = "confirm";
break;
}
},
goToPrevious() {
if (this.$data.step === "concerned") {
let params = new URLSearchParams(window.location.search);
if (params.has("returnPath")) {
window.location.replace(params.get("returnPath"));
} else {
return;
}
}
let s = this.steps;
let index = s.indexOf(this.$data.step);
if (s[index - 1] === undefined) {
throw Error("step not found");
}
this.$data.step = s[index - 1];
},
confirm() {
this.$store.dispatch("confirm");
},
},
},
};
</script>

View File

@ -1,74 +1,88 @@
<template>
<h2 class="mt-4">
{{ $t("household_members_editor.concerned.title") }}
</h2>
<h2 class="mt-4">
{{ $t("household_members_editor.concerned.title") }}
</h2>
<div v-if="noPerson">
<div class="alert alert-info">
{{ $t("household_members_editor.concerned.add_at_least_onePerson") }}
<div v-if="noPerson">
<div class="alert alert-info">
{{
$t("household_members_editor.concerned.add_at_least_onePerson")
}}
</div>
</div>
</div>
<div v-else>
<p>
{{
$t("household_members_editor.concerned.persons_will_be_moved")
}}&nbsp;:
</p>
<div v-else>
<p>
{{
$t("household_members_editor.concerned.persons_will_be_moved")
}}&nbsp;:
</p>
<ul class="list-suggest remove-items inline">
<li v-for="c in concerned" :key="c.person.id" @click="removeConcerned(c)">
<span><person-text :person="c.person" /></span>
</li>
</ul>
<ul class="list-suggest remove-items inline">
<li
v-for="c in concerned"
:key="c.person.id"
@click="removeConcerned(c)"
>
<span><person-text :person="c.person" /></span>
</li>
</ul>
<div
class="alert alert-info"
v-if="concernedPersonsWithHouseholds.length > 0"
>
<p>
{{ $t("household_members_editor.concerned.persons_with_household") }}
</p>
<ul v-for="c in concernedPersonsWithHouseholds" :key="c.person.id">
<li>
{{ c.person.text }}
{{
$t(
"household_members_editor.concerned.already_belongs_to_household",
)
}}
<a
target="_blank"
:href="this.makeHouseholdLink(c.person.current_household_id)"
>{{ c.person.current_household_id }}</a
>.
<div
class="alert alert-info"
v-if="concernedPersonsWithHouseholds.length > 0"
>
<p>
{{
$t(
"household_members_editor.concerned.persons_with_household",
)
}}
</p>
<ul v-for="c in concernedPersonsWithHouseholds" :key="c.person.id">
<li>
{{ c.person.text }}
{{
$t(
"household_members_editor.concerned.already_belongs_to_household",
)
}}
<a
target="_blank"
:href="
this.makeHouseholdLink(
c.person.current_household_id,
)
"
>{{ c.person.current_household_id }}</a
>.
</li>
</ul>
</div>
</div>
<ul class="record_actions">
<li class="add-persons">
<add-persons
button-title="household_members_editor.concerned.add_persons"
modal-title="household_members_editor.concerned.search"
:key="addPersons.key"
:options="addPersons.options"
@add-new-persons="addNewPersons"
ref="addPersons"
>
<!-- to cast child method -->
</add-persons>
</li>
</ul>
</div>
</div>
<ul class="record_actions">
<li class="add-persons">
<add-persons
button-title="household_members_editor.concerned.add_persons"
modal-title="household_members_editor.concerned.search"
:key="addPersons.key"
:options="addPersons.options"
@add-new-persons="addNewPersons"
ref="addPersons"
>
<!-- to cast child method -->
</add-persons>
</li>
</ul>
</ul>
</template>
<style lang="scss">
.move_to {
.move_hint {
text-align: center;
display: inline-block;
padding: 0.4rem 0.5rem;
}
.move_hint {
text-align: center;
display: inline-block;
padding: 0.4rem 0.5rem;
}
}
</style>
@ -78,61 +92,62 @@ import AddPersons from "ChillPersonAssets/vuejs/_components/AddPersons.vue";
import PersonText from "ChillPersonAssets/vuejs/_components/Entity/PersonText.vue";
export default {
name: "Concerned",
components: {
AddPersons,
PersonText,
},
computed: {
...mapState(["concerned", "household"]),
...mapGetters(["persons"]),
noPerson() {
return this.$store.getters.persons.length === 0;
name: "Concerned",
components: {
AddPersons,
PersonText,
},
concernedPersonsWithHouseholds() {
if (this.$store.state.household) {
return this.$store.state.concerned.filter(
(c) =>
c.person.current_household_id !== null &&
c.person.current_household_id !== this.$store.state.household.id,
);
} else {
return [];
}
},
},
data() {
return {
addPersons: {
key: "household_members_editor_concerned",
options: {
type: ["person"],
priority: null,
uniq: false,
computed: {
...mapState(["concerned", "household"]),
...mapGetters(["persons"]),
noPerson() {
return this.$store.getters.persons.length === 0;
},
concernedPersonsWithHouseholds() {
if (this.$store.state.household) {
return this.$store.state.concerned.filter(
(c) =>
c.person.current_household_id !== null &&
c.person.current_household_id !==
this.$store.state.household.id,
);
} else {
return [];
}
},
},
};
},
methods: {
addNewPersons({ selected, modal }) {
selected.forEach(function (item) {
this.$store.dispatch("addConcerned", item.result);
}, this);
this.$refs.addPersons.resetSearch(); // to cast child method
modal.showModal = false;
},
removeConcerned(concerned) {
console.log("removedconcerned", concerned);
data() {
return {
addPersons: {
key: "household_members_editor_concerned",
options: {
type: ["person"],
priority: null,
uniq: false,
},
},
};
},
methods: {
addNewPersons({ selected, modal }) {
selected.forEach(function (item) {
this.$store.dispatch("addConcerned", item.result);
}, this);
this.$refs.addPersons.resetSearch(); // to cast child method
modal.showModal = false;
},
removeConcerned(concerned) {
console.log("removedconcerned", concerned);
if (!concerned.allowRemove) {
return;
}
if (!concerned.allowRemove) {
return;
}
this.$store.dispatch("removePerson", concerned.person);
this.$store.dispatch("removePerson", concerned.person);
},
makeHouseholdLink(id) {
return `/fr/person/household/${id}/summary`;
},
},
makeHouseholdLink(id) {
return `/fr/person/household/${id}/summary`;
},
},
};
</script>

View File

@ -1,20 +1,20 @@
<template>
<div v-if="hasWarning" class="alert alert-warning">
{{ $t("household_members_editor.confirmation.there_are_warnings") }}
</div>
<div v-if="hasWarning" class="alert alert-warning">
{{ $t("household_members_editor.confirmation.there_are_warnings") }}
</div>
<p v-if="hasWarning">
{{ $t("household_members_editor.confirmation.check_those_items") }}
</p>
<p v-if="hasWarning">
{{ $t("household_members_editor.confirmation.check_those_items") }}
</p>
<ul>
<li v-for="(msg, i) in warnings" class="warning" :key="i">
{{ $t(msg.m, msg.a) }}
</li>
<li v-for="(msg, i) in errors" class="error" :key="i">
{{ msg }}
</li>
</ul>
<ul>
<li v-for="(msg, i) in warnings" class="warning" :key="i">
{{ $t(msg.m, msg.a) }}
</li>
<li v-for="(msg, i) in errors" class="error" :key="i">
{{ msg }}
</li>
</ul>
</template>
<style scoped lang="scss"></style>
@ -23,14 +23,14 @@
import { mapState } from "vuex";
export default {
name: "Confirmation",
computed: {
...mapState({
hasWarnings: (state) =>
state.warnings.length > 0 || state.errors.length > 0,
warnings: (state) => state.warnings,
errors: (state) => state.errors,
}),
},
name: "Confirmation",
computed: {
...mapState({
hasWarnings: (state) =>
state.warnings.length > 0 || state.errors.length > 0,
warnings: (state) => state.warnings,
errors: (state) => state.errors,
}),
},
};
</script>

View File

@ -1,35 +1,37 @@
<template>
<div class="flex-table mb-5" v-if="hasHousehold">
<div class="item-bloc">
<household-render-box :household="fakeHouseholdWithConcerned" />
</div>
</div>
<div class="flex-table" v-if="isModeLeave">
<div class="item-bloc">
<section>
<div class="item-row">
<div class="item-col">
<div class="h4">
<span class="fa-stack fa-lg">
<i class="fa fa-home fa-stack-1x" />
<i class="fa fa-ban fa-stack-2x text-danger" />
</span>
{{
$t("household_members_editor.household.leave_without_household")
}}
</div>
</div>
<div class="flex-table mb-5" v-if="hasHousehold">
<div class="item-bloc">
<household-render-box :household="fakeHouseholdWithConcerned" />
</div>
</div>
<div class="flex-table" v-if="isModeLeave">
<div class="item-bloc">
<section>
<div class="item-row">
<div class="item-col">
<div class="h4">
<span class="fa-stack fa-lg">
<i class="fa fa-home fa-stack-1x" />
<i class="fa fa-ban fa-stack-2x text-danger" />
</span>
{{
$t(
"household_members_editor.household.leave_without_household",
)
}}
</div>
</div>
</div>
<div class="item-row">
{{
$t(
"household_members_editor.household.will_leave_any_household_explanation",
)
}}
</div>
</section>
</div>
<div class="item-row">
{{
$t(
"household_members_editor.household.will_leave_any_household_explanation",
)
}}
</div>
</section>
</div>
</div>
</template>
<script>
@ -37,17 +39,17 @@ import { mapGetters } from "vuex";
import HouseholdRenderBox from "ChillPersonAssets/vuejs/_components/Entity/HouseholdRenderBox.vue";
export default {
name: "CurrentHousehold",
components: {
HouseholdRenderBox,
},
computed: {
...mapGetters([
"hasHousehold",
"fakeHouseholdWithConcerned",
"isModeLeave",
]),
},
name: "CurrentHousehold",
components: {
HouseholdRenderBox,
},
computed: {
...mapGetters([
"hasHousehold",
"fakeHouseholdWithConcerned",
"isModeLeave",
]),
},
};
</script>

View File

@ -1,83 +1,83 @@
<template>
<current-household />
<current-household />
<h2>{{ $t("household_members_editor.dates.dates_title") }}</h2>
<h2>{{ $t("household_members_editor.dates.dates_title") }}</h2>
<div class="mb-3 row">
<label for="start_date" class="col-form-label col-sm-4 required">
{{ $t("household_members_editor.dates.start_date") }}
</label>
<div class="col-sm-8">
<input type="date" v-model="startDate" class="form-control" />
</div>
</div>
<div v-if="this.isHouseholdNew">
<h2>{{ $t("household_members_editor.composition.composition") }}</h2>
<div class="mb-3 row">
<label class="col-form-label col-sm-4 required">{{
$t("household_members_editor.composition.household_composition")
}}</label>
<div class="col-sm-8">
<select
v-model="householdCompositionType"
class="form-select form-control"
>
<option
v-for="t in householdCompositionTypes"
:key="t.id"
:value="t.id"
>
{{ localizeString(t.label) }}
</option>
</select>
</div>
<label for="start_date" class="col-form-label col-sm-4 required">
{{ $t("household_members_editor.dates.start_date") }}
</label>
<div class="col-sm-8">
<input type="date" v-model="startDate" class="form-control" />
</div>
</div>
<div class="mb-3 row">
<label class="col-form-label col-sm-4 required">{{
$t("household_members_editor.composition.number_of_children")
}}</label>
<div class="col-sm-8">
<input
type="number"
v-model="numberOfChildren"
min="0"
max="30"
class="form-control"
/>
</div>
<div v-if="this.isHouseholdNew">
<h2>{{ $t("household_members_editor.composition.composition") }}</h2>
<div class="mb-3 row">
<label class="col-form-label col-sm-4 required">{{
$t("household_members_editor.composition.household_composition")
}}</label>
<div class="col-sm-8">
<select
v-model="householdCompositionType"
class="form-select form-control"
>
<option
v-for="t in householdCompositionTypes"
:key="t.id"
:value="t.id"
>
{{ localizeString(t.label) }}
</option>
</select>
</div>
</div>
<div class="mb-3 row">
<label class="col-form-label col-sm-4 required">{{
$t("household_members_editor.composition.number_of_children")
}}</label>
<div class="col-sm-8">
<input
type="number"
v-model="numberOfChildren"
min="0"
max="30"
class="form-control"
/>
</div>
</div>
<div v-if="this.displayDependents" class="mb-3 row">
<label class="col-form-label col-sm-4 required">{{
$t("household_members_editor.composition.number_of_dependents")
}}</label>
<div class="col-sm-8">
<input
type="number"
v-model="numberOfDependents"
min="0"
max="30"
class="form-control"
/>
</div>
</div>
<div v-if="this.displayDependents" class="mb-3 row">
<label class="col-form-label col-sm-4 required">{{
$t(
"household_members_editor.composition.number_of_dependents_with_disabilities",
)
}}</label>
<div class="col-sm-8">
<input
type="number"
v-model="numberOfDependentsWithDisabilities"
min="0"
max="30"
class="form-control"
/>
</div>
</div>
</div>
<div v-if="this.displayDependents" class="mb-3 row">
<label class="col-form-label col-sm-4 required">{{
$t("household_members_editor.composition.number_of_dependents")
}}</label>
<div class="col-sm-8">
<input
type="number"
v-model="numberOfDependents"
min="0"
max="30"
class="form-control"
/>
</div>
</div>
<div v-if="this.displayDependents" class="mb-3 row">
<label class="col-form-label col-sm-4 required">{{
$t(
"household_members_editor.composition.number_of_dependents_with_disabilities",
)
}}</label>
<div class="col-sm-8">
<input
type="number"
v-model="numberOfDependentsWithDisabilities"
min="0"
max="30"
class="form-control"
/>
</div>
</div>
</div>
</template>
<script>
@ -86,71 +86,74 @@ import { mapGetters, mapState } from "vuex";
import { localizeString } from "ChillMainAssets/lib/localizationHelper/localizationHelper";
export default {
name: "Dates",
methods: { localizeString },
components: {
CurrentHousehold,
},
computed: {
...mapState(["householdCompositionTypes"]),
...mapGetters(["isHouseholdNew"]),
displayDependents: {
get() {
return window.household_members_editor_data.displayDependents;
},
name: "Dates",
methods: { localizeString },
components: {
CurrentHousehold,
},
householdCompositionType: {
get() {
if (this.$store.state.householdCompositionType !== null) {
return this.$store.state.householdCompositionType.id;
}
return null;
},
set(value) {
this.$store.dispatch("setHouseholdCompositionType", value);
},
},
numberOfChildren: {
get() {
return this.$store.state.numberOfChildren;
},
set(value) {
this.$store.commit("setNumberOfChildren", value);
},
},
numberOfDependents: {
get() {
return this.$store.state.numberOfDependents;
},
set(value) {
this.$store.commit("setNumberOfDependents", value);
},
},
numberOfDependentsWithDisabilities: {
get() {
return this.$store.state.numberOfDependentsWithDisabilities;
},
set(value) {
this.$store.commit("setNumberOfDependentsWithDisabilities", value);
},
},
startDate: {
get() {
return this.$store.state.startDate;
// return [
// this.$store.state.startDate.getFullYear(),
// (this.$store.state.startDate.getMonth() + 1).toString().padStart(2, '0'),
// this.$store.state.startDate.getDate().toString().padStart(2, '0')
// ].join('-');
},
set(value) {
// let
// [year, month, day] = value.split('-'),
// dValue = new Date(year, month-1, day);
computed: {
...mapState(["householdCompositionTypes"]),
...mapGetters(["isHouseholdNew"]),
displayDependents: {
get() {
return window.household_members_editor_data.displayDependents;
},
},
householdCompositionType: {
get() {
if (this.$store.state.householdCompositionType !== null) {
return this.$store.state.householdCompositionType.id;
}
return null;
},
set(value) {
this.$store.dispatch("setHouseholdCompositionType", value);
},
},
numberOfChildren: {
get() {
return this.$store.state.numberOfChildren;
},
set(value) {
this.$store.commit("setNumberOfChildren", value);
},
},
numberOfDependents: {
get() {
return this.$store.state.numberOfDependents;
},
set(value) {
this.$store.commit("setNumberOfDependents", value);
},
},
numberOfDependentsWithDisabilities: {
get() {
return this.$store.state.numberOfDependentsWithDisabilities;
},
set(value) {
this.$store.commit(
"setNumberOfDependentsWithDisabilities",
value,
);
},
},
startDate: {
get() {
return this.$store.state.startDate;
// return [
// this.$store.state.startDate.getFullYear(),
// (this.$store.state.startDate.getMonth() + 1).toString().padStart(2, '0'),
// this.$store.state.startDate.getDate().toString().padStart(2, '0')
// ].join('-');
},
set(value) {
// let
// [year, month, day] = value.split('-'),
// dValue = new Date(year, month-1, day);
this.$store.dispatch("setStartDate", value);
},
this.$store.dispatch("setStartDate", value);
},
},
},
},
};
</script>

View File

@ -1,116 +1,130 @@
<template>
<h2 class="mt-4">
{{ $t("household_members_editor.household_part") }}
</h2>
<h2 class="mt-4">
{{ $t("household_members_editor.household_part") }}
</h2>
<div class="alert alert-info" v-if="!hasHousehold">
{{ $t("household_members_editor.household.no_household_choose_one") }}
</div>
<template v-else>
<current-household />
</template>
<div v-if="hasHouseholdSuggestion" class="householdSuggestions my-5">
<h4 class="mb-3">
{{ $t("household_members_editor.household.household_suggested") }}
</h4>
<p>
{{
$t("household_members_editor.household.household_suggested_explanation")
}}
</p>
<div class="accordion" id="householdSuggestions">
<div class="accordion-item">
<h2 class="accordion-header" id="heading_household_suggestions">
<button
v-if="!showHouseholdSuggestion"
class="accordion-button collapsed"
type="button"
data-bs-toggle="collapse"
aria-expanded="false"
@click="toggleHouseholdSuggestion"
>
{{
$tc(
"household_members_editor.show_household_suggestion",
countHouseholdSuggestion,
)
}}
</button>
<button
v-if="showHouseholdSuggestion"
class="accordion-button"
type="button"
data-bs-toggle="collapse"
aria-expanded="true"
@click="toggleHouseholdSuggestion"
>
{{ $t("household_members_editor.hide_household_suggestion") }}
</button>
<!-- disabled bootstrap behaviour: data-bs-target="#collapse_household_suggestions" aria-controls="collapse_household_suggestions" -->
</h2>
<div
class="accordion-collapse"
id="collapse_household_suggestions"
aria-labelledby="heading_household_suggestions"
data-bs-parent="#householdSuggestions"
>
<div v-if="showHouseholdSuggestion">
<div class="flex-table householdSuggestionList">
<div
v-for="(s, i) in getSuggestions"
class="item-bloc"
:key="`householdSuggestions-${i}`"
>
<household-render-box :household="s.household" />
<ul class="record_actions">
<li>
<button
class="btn btn-sm btn-choose"
@click="selectHousehold(s.household)"
>
{{ $t("household_members_editor.select_household") }}
</button>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
<div class="alert alert-info" v-if="!hasHousehold">
{{ $t("household_members_editor.household.no_household_choose_one") }}
</div>
</div>
<template v-else>
<current-household />
</template>
<ul class="record_actions">
<li v-if="hasHousehold">
<button @click="resetMode" class="btn btn-sm btn-misc">
{{ $t("household_members_editor.household.reset_mode") }}
</button>
</li>
<li v-if="!hasHousehold" class="add-persons">
<add-persons
modal-title="Chercher un ménage existant"
button-title="Chercher un ménage existant"
:key="addPersons.key"
:options="addPersons.options"
@add-new-persons="pickHouseholdFound"
ref="pickHousehold"
>
<!-- to cast child method -->
</add-persons>
</li>
<li v-if="!hasHousehold">
<button @click="setModeNew" class="btn btn-sm btn-create">
{{ $t("household_members_editor.household.create_household") }}
</button>
</li>
<li v-if="isModeLeaveAllowed && !hasHousehold">
<button @click="setModeLeave" class="btn btn-sm btn-misc">
<i class="fa fa-sign-out" />
{{ $t("household_members_editor.household.leave") }}
</button>
</li>
</ul>
<div v-if="hasHouseholdSuggestion" class="householdSuggestions my-5">
<h4 class="mb-3">
{{ $t("household_members_editor.household.household_suggested") }}
</h4>
<p>
{{
$t(
"household_members_editor.household.household_suggested_explanation",
)
}}
</p>
<div class="accordion" id="householdSuggestions">
<div class="accordion-item">
<h2 class="accordion-header" id="heading_household_suggestions">
<button
v-if="!showHouseholdSuggestion"
class="accordion-button collapsed"
type="button"
data-bs-toggle="collapse"
aria-expanded="false"
@click="toggleHouseholdSuggestion"
>
{{
$tc(
"household_members_editor.show_household_suggestion",
countHouseholdSuggestion,
)
}}
</button>
<button
v-if="showHouseholdSuggestion"
class="accordion-button"
type="button"
data-bs-toggle="collapse"
aria-expanded="true"
@click="toggleHouseholdSuggestion"
>
{{
$t(
"household_members_editor.hide_household_suggestion",
)
}}
</button>
<!-- disabled bootstrap behaviour: data-bs-target="#collapse_household_suggestions" aria-controls="collapse_household_suggestions" -->
</h2>
<div
class="accordion-collapse"
id="collapse_household_suggestions"
aria-labelledby="heading_household_suggestions"
data-bs-parent="#householdSuggestions"
>
<div v-if="showHouseholdSuggestion">
<div class="flex-table householdSuggestionList">
<div
v-for="(s, i) in getSuggestions"
class="item-bloc"
:key="`householdSuggestions-${i}`"
>
<household-render-box
:household="s.household"
/>
<ul class="record_actions">
<li>
<button
class="btn btn-sm btn-choose"
@click="
selectHousehold(s.household)
"
>
{{
$t(
"household_members_editor.select_household",
)
}}
</button>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<ul class="record_actions">
<li v-if="hasHousehold">
<button @click="resetMode" class="btn btn-sm btn-misc">
{{ $t("household_members_editor.household.reset_mode") }}
</button>
</li>
<li v-if="!hasHousehold" class="add-persons">
<add-persons
modal-title="Chercher un ménage existant"
button-title="Chercher un ménage existant"
:key="addPersons.key"
:options="addPersons.options"
@add-new-persons="pickHouseholdFound"
ref="pickHousehold"
>
<!-- to cast child method -->
</add-persons>
</li>
<li v-if="!hasHousehold">
<button @click="setModeNew" class="btn btn-sm btn-create">
{{ $t("household_members_editor.household.create_household") }}
</button>
</li>
<li v-if="isModeLeaveAllowed && !hasHousehold">
<button @click="setModeLeave" class="btn btn-sm btn-misc">
<i class="fa fa-sign-out" />
{{ $t("household_members_editor.household.leave") }}
</button>
</li>
</ul>
</template>
<script>
@ -120,154 +134,156 @@ import CurrentHousehold from "./CurrentHousehold";
import AddPersons from "ChillPersonAssets/vuejs/_components/AddPersons";
export default {
name: "Household",
components: {
AddPersons,
CurrentHousehold,
HouseholdRenderBox,
},
emits: ["readyToGo"],
data() {
return {
addPersons: {
key: "household_find",
options: {
type: ["household"],
priority: null,
uniq: true,
button: {
size: "btn-sm",
type: "btn-search",
},
},
},
addAddress: {
key: "household_new",
options: {
useDate: {
validFrom: false,
validTo: false,
},
onlyButton: true,
button: {
text: {
create: "household_members_editor.household.set_address",
edit: "household_members_editor.household.update_address",
name: "Household",
components: {
AddPersons,
CurrentHousehold,
HouseholdRenderBox,
},
emits: ["readyToGo"],
data() {
return {
addPersons: {
key: "household_find",
options: {
type: ["household"],
priority: null,
uniq: true,
button: {
size: "btn-sm",
type: "btn-search",
},
},
},
},
title: {
create: "household_members_editor.household.create_new_address",
edit: "household_members_editor.household.update_address_title",
},
addAddress: {
key: "household_new",
options: {
useDate: {
validFrom: false,
validTo: false,
},
onlyButton: true,
button: {
text: {
create: "household_members_editor.household.set_address",
edit: "household_members_editor.household.update_address",
},
},
title: {
create: "household_members_editor.household.create_new_address",
edit: "household_members_editor.household.update_address_title",
},
},
},
};
},
computed: {
...mapGetters([
"isModeNewAllowed",
"isModeLeaveAllowed",
"getSuggestions",
"hasHousehold",
"isHouseholdNew",
"hasHouseholdSuggestion",
"countHouseholdSuggestion",
"filterHouseholdSuggestionByAccompanyingPeriod",
"hasAddressSuggestion",
"countAddressSuggestion",
"filterAddressesSuggestion",
"hasHouseholdAddress",
"isModeLeave",
"getAddressContext",
]),
...mapState([
"household",
"showHouseholdSuggestion",
"showAddressSuggestion",
"mode",
]),
household() {
return this.$store.state.household;
},
allowHouseholdSearch() {
return false;
return (
this.$store.state.allowHouseholdSearch &&
!this.$store.getters.hasHousehold
);
},
isHouseholdNewDesactivated() {
return (
this.$store.state.mode !== null &&
!this.$store.getters.isHouseholdNew
);
},
isHouseholdLeaveDesactivated() {
return (
this.$store.state.mode !== null &&
this.$store.state.mode !== "leave"
);
},
},
};
},
computed: {
...mapGetters([
"isModeNewAllowed",
"isModeLeaveAllowed",
"getSuggestions",
"hasHousehold",
"isHouseholdNew",
"hasHouseholdSuggestion",
"countHouseholdSuggestion",
"filterHouseholdSuggestionByAccompanyingPeriod",
"hasAddressSuggestion",
"countAddressSuggestion",
"filterAddressesSuggestion",
"hasHouseholdAddress",
"isModeLeave",
"getAddressContext",
]),
...mapState([
"household",
"showHouseholdSuggestion",
"showAddressSuggestion",
"mode",
]),
household() {
return this.$store.state.household;
},
allowHouseholdSearch() {
return false;
return (
this.$store.state.allowHouseholdSearch &&
!this.$store.getters.hasHousehold
);
methods: {
setModeNew() {
this.$store.dispatch("createHousehold");
this.$emit("readyToGo");
},
setModeLeave() {
this.$store.dispatch("forceLeaveWithoutHousehold");
this.$emit("readyToGo");
},
resetMode() {
this.$store.commit("resetMode");
},
addressChanged(payload) {
console.log("addressChanged", payload);
this.$store.dispatch("setHouseholdNewAddress", payload.address);
},
selectHousehold(h) {
this.$store.dispatch("selectHousehold", h);
this.$emit("readyToGo");
},
pickHouseholdFound({ selected, modal }) {
selected.forEach(function (item) {
this.selectHousehold(item.result);
}, this);
this.$refs.pickHousehold.resetSearch(); // to cast child method
modal.showModal = false;
},
removeHouseholdAddress() {
this.$store.commit("removeHouseholdAddress");
},
toggleHouseholdSuggestion() {
this.$store.commit("toggleHouseholdSuggestion");
},
},
isHouseholdNewDesactivated() {
return (
this.$store.state.mode !== null && !this.$store.getters.isHouseholdNew
);
},
isHouseholdLeaveDesactivated() {
return (
this.$store.state.mode !== null && this.$store.state.mode !== "leave"
);
},
},
methods: {
setModeNew() {
this.$store.dispatch("createHousehold");
this.$emit("readyToGo");
},
setModeLeave() {
this.$store.dispatch("forceLeaveWithoutHousehold");
this.$emit("readyToGo");
},
resetMode() {
this.$store.commit("resetMode");
},
addressChanged(payload) {
console.log("addressChanged", payload);
this.$store.dispatch("setHouseholdNewAddress", payload.address);
},
selectHousehold(h) {
this.$store.dispatch("selectHousehold", h);
this.$emit("readyToGo");
},
pickHouseholdFound({ selected, modal }) {
selected.forEach(function (item) {
this.selectHousehold(item.result);
}, this);
this.$refs.pickHousehold.resetSearch(); // to cast child method
modal.showModal = false;
},
removeHouseholdAddress() {
this.$store.commit("removeHouseholdAddress");
},
toggleHouseholdSuggestion() {
this.$store.commit("toggleHouseholdSuggestion");
},
},
};
</script>
<style lang="scss" scoped>
.filtered {
filter: grayscale(1) opacity(0.6);
filter: grayscale(1) opacity(0.6);
}
.filteredButActive {
filter: grayscale(1) opacity(0.6);
&:hover {
filter: unset;
}
filter: grayscale(1) opacity(0.6);
&:hover {
filter: unset;
}
}
div#household_members_editor div,
div.householdSuggestionList {
&.flex-table {
margin: 0;
div.item-bloc div.item-row div.item-col {
&:first-child {
width: 25%;
}
&:last-child {
display: initial;
}
&.flex-table {
margin: 0;
div.item-bloc div.item-row div.item-col {
&:first-child {
width: 25%;
}
&:last-child {
display: initial;
}
}
}
}
}
</style>

View File

@ -1,26 +1,30 @@
<template>
<current-household />
<current-household />
<ul class="record_actions">
<!-- <li v-if="!hasHouseholdAddress && !isHouseholdForceAddress">
<ul class="record_actions">
<!-- <li v-if="!hasHouseholdAddress && !isHouseholdForceAddress">
<button class="btn btn-misc" @click="markNoAddress">
{{ $t('household_members_editor.household_address.mark_no_address') }}
</button>
</li> -->
<li v-if="!hasHouseholdAddress">
<add-address
:context="getAddressContext"
:key="addAddress.key"
:options="addAddress.options"
:address-changed-callback="addressChanged"
/>
</li>
<li v-if="hasHouseholdAddress">
<button class="btn btn-remove" @click="removeHouseholdAddress">
{{ $t("household_members_editor.household_address.remove_address") }}
</button>
</li>
</ul>
<li v-if="!hasHouseholdAddress">
<add-address
:context="getAddressContext"
:key="addAddress.key"
:options="addAddress.options"
:address-changed-callback="addressChanged"
/>
</li>
<li v-if="hasHouseholdAddress">
<button class="btn btn-remove" @click="removeHouseholdAddress">
{{
$t(
"household_members_editor.household_address.remove_address",
)
}}
</button>
</li>
</ul>
</template>
<script>
@ -29,56 +33,55 @@ import CurrentHousehold from "./CurrentHousehold";
import { mapGetters } from "vuex";
export default {
name: "HouseholdAddress.vue",
components: {
CurrentHousehold,
AddAddress,
},
data() {
return {
addAddress: {
key: "household_new",
options: {
useDate: {
validFrom: false,
validTo: false,
},
onlyButton: true,
button: {
text: {
create: "household_members_editor.household_address.set_address",
edit: "household_members_editor.household_address.update_address",
name: "HouseholdAddress.vue",
components: {
CurrentHousehold,
AddAddress,
},
data() {
return {
addAddress: {
key: "household_new",
options: {
useDate: {
validFrom: false,
validTo: false,
},
onlyButton: true,
button: {
text: {
create: "household_members_editor.household_address.set_address",
edit: "household_members_editor.household_address.update_address",
},
},
title: {
create: "household_members_editor.household_address.create_new_address",
edit: "household_members_editor.household_address.update_address_title",
},
},
},
},
title: {
create:
"household_members_editor.household_address.create_new_address",
edit: "household_members_editor.household_address.update_address_title",
},
};
},
computed: {
...mapGetters([
"isHouseholdNew",
"hasHouseholdAddress",
"getAddressContext",
"isHouseholdForceNoAddress",
]),
},
methods: {
addressChanged(payload) {
console.log("addressChanged", payload);
this.$store.dispatch("setHouseholdNewAddress", payload.address);
},
markNoAddress() {
this.$store.commit("markHouseholdNoAddress");
},
removeHouseholdAddress() {
this.$store.commit("removeHouseholdAddress");
},
},
};
},
computed: {
...mapGetters([
"isHouseholdNew",
"hasHouseholdAddress",
"getAddressContext",
"isHouseholdForceNoAddress",
]),
},
methods: {
addressChanged(payload) {
console.log("addressChanged", payload);
this.$store.dispatch("setHouseholdNewAddress", payload.address);
},
markNoAddress() {
this.$store.commit("markHouseholdNoAddress");
},
removeHouseholdAddress() {
this.$store.commit("removeHouseholdAddress");
},
},
};
</script>

View File

@ -1,97 +1,104 @@
<template>
<div class="item-bloc">
<div class="item-row">
<div class="item-col">
<div>
<person-render-box
render="badge"
:options="{}"
:person="conc.person"
/>
<span v-if="isHolder" class="badge bg-primary holder">
{{ $t("household_members_editor.holder") }}
</span>
<div class="item-bloc">
<div class="item-row">
<div class="item-col">
<div>
<person-render-box
render="badge"
:options="{}"
:person="conc.person"
/>
<span v-if="isHolder" class="badge bg-primary holder">
{{ $t("household_members_editor.holder") }}
</span>
</div>
<div v-if="conc.person.birthdate !== null">
{{
$t("person.born", {
gender: conc.person.gender.genderTranslation,
})
}}
</div>
</div>
<div class="item-col">
<ul class="list-content fa-ul">
<li>
<i class="fa fa-li fa-map-marker" />
<span class="chill-no-data-statement"
>Sans adresse</span
>
</li>
</ul>
</div>
</div>
<div v-if="conc.person.birthdate !== null">
{{
$t("person.born", { gender: conc.person.gender.genderTranslation })
}}
<div class="item-row comment">
<comment-editor v-model="comment" />
</div>
<div class="item-row participation-details">
<div v-if="conc.position.allowHolder" class="action">
<button
class="btn"
:class="{
'btn-primary': isHolder,
'btn-secondary': !isHolder,
}"
@click="toggleHolder"
>
{{
$t(
isHolder
? "household_members_editor.is_holder"
: "household_members_editor.is_not_holder",
)
}}
</button>
</div>
<div>
<button @click="removePosition" class="btn btn-outline-primary">
{{
$t("household_members_editor.remove_position", {
position: conc.position.label.fr,
})
}}
</button>
</div>
<div>
<button
v-if="conc.allowRemove"
@click="removeConcerned"
class="btn btn-primary"
>
{{ $t("household_members_editor.remove_concerned") }}
</button>
</div>
</div>
</div>
<div class="item-col">
<ul class="list-content fa-ul">
<li>
<i class="fa fa-li fa-map-marker" />
<span class="chill-no-data-statement">Sans adresse</span>
</li>
</ul>
</div>
</div>
<div class="item-row comment">
<comment-editor v-model="comment" />
</div>
<div class="item-row participation-details">
<div v-if="conc.position.allowHolder" class="action">
<button
class="btn"
:class="{ 'btn-primary': isHolder, 'btn-secondary': !isHolder }"
@click="toggleHolder"
>
{{
$t(
isHolder
? "household_members_editor.is_holder"
: "household_members_editor.is_not_holder",
)
}}
</button>
</div>
<div>
<button @click="removePosition" class="btn btn-outline-primary">
{{
$t("household_members_editor.remove_position", {
position: conc.position.label.fr,
})
}}
</button>
</div>
<div>
<button
v-if="conc.allowRemove"
@click="removeConcerned"
class="btn btn-primary"
>
{{ $t("household_members_editor.remove_concerned") }}
</button>
</div>
</div>
</div>
</template>
<style scoped lang="scss">
.drag-icon {
height: 1.1em;
margin-right: 0.5em;
height: 1.1em;
margin-right: 0.5em;
}
div.participation-details {
display: flex;
flex-direction: row !important;
justify-content: flex-end;
display: flex;
flex-direction: row !important;
justify-content: flex-end;
.action {
align-self: flex-start;
margin-right: auto;
}
.action {
align-self: flex-start;
margin-right: auto;
}
}
.holder {
display: inline;
vertical-align: super;
font-size: 0.6em;
display: inline;
vertical-align: super;
font-size: 0.6em;
}
</style>
@ -101,41 +108,44 @@ import PersonRenderBox from "ChillPersonAssets/vuejs/_components/Entity/PersonRe
import CommentEditor from "ChillMainAssets/vuejs/_components/CommentEditor/CommentEditor.vue";
export default {
name: "MemberDetails",
components: {
PersonRenderBox,
CommentEditor,
},
props: ["conc"],
computed: {
...mapGetters(["concByPersonId"]),
classicEditor: () => ClassicEditor,
editorConfig: () => classicEditorConfig,
isHolder() {
return this.conc.holder;
name: "MemberDetails",
components: {
PersonRenderBox,
CommentEditor,
},
comment: {
get() {
return this.conc.comment;
},
set(text) {
console.log("set comment");
console.log("comment", text);
props: ["conc"],
computed: {
...mapGetters(["concByPersonId"]),
classicEditor: () => ClassicEditor,
editorConfig: () => classicEditorConfig,
isHolder() {
return this.conc.holder;
},
comment: {
get() {
return this.conc.comment;
},
set(text) {
console.log("set comment");
console.log("comment", text);
this.$store.dispatch("setComment", { conc: this.conc, comment: text });
},
this.$store.dispatch("setComment", {
conc: this.conc,
comment: text,
});
},
},
},
},
methods: {
toggleHolder() {
this.$store.dispatch("toggleHolder", this.conc);
methods: {
toggleHolder() {
this.$store.dispatch("toggleHolder", this.conc);
},
removePosition() {
this.$store.dispatch("removePosition", this.conc);
},
removeConcerned() {
this.$store.dispatch("removeConcerned", this.conc);
},
},
removePosition() {
this.$store.dispatch("removePosition", this.conc);
},
removeConcerned() {
this.$store.dispatch("removeConcerned", this.conc);
},
},
};
</script>

View File

@ -1,30 +1,30 @@
<template>
<comment-editor v-model="content" />
<comment-editor v-model="content" />
</template>
<script>
import CommentEditor from "ChillMainAssets/vuejs/_components/CommentEditor/CommentEditor.vue";
export default {
name: "PersonComment.vue",
components: {
CommentEditor,
},
props: ["conc"],
computed: {
content: {
get() {
return this.$props.conc.comment || "";
},
set(value) {
console.log("set content", value);
this.$store.commit("setComment", {
conc: this.$props.conc,
comment: value,
});
},
name: "PersonComment.vue",
components: {
CommentEditor,
},
props: ["conc"],
computed: {
content: {
get() {
return this.$props.conc.comment || "";
},
set(value) {
console.log("set content", value);
this.$store.commit("setComment", {
conc: this.$props.conc,
comment: value,
});
},
},
},
},
};
</script>

View File

@ -1,55 +1,57 @@
<template>
<current-household />
<current-household />
<h2>
{{ $t("household_members_editor.positioning.persons_to_positionnate") }}
</h2>
<h2>
{{ $t("household_members_editor.positioning.persons_to_positionnate") }}
</h2>
<div class="list-household-members flex-table">
<div v-for="conc in concerned" class="item-bloc" :key="conc.person.id">
<div class="pick-position item-row">
<div class="person">
<!-- <h3>{{ conc.person.text }}</h3> -->
<h3><person-text :person="conc.person" /></h3>
<div class="list-household-members flex-table">
<div v-for="conc in concerned" class="item-bloc" :key="conc.person.id">
<div class="pick-position item-row">
<div class="person">
<!-- <h3>{{ conc.person.text }}</h3> -->
<h3><person-text :person="conc.person" /></h3>
</div>
<div class="holder">
<button
class="btn"
:disabled="!allowHolderForConcerned(conc)"
:class="{
'btn-outline-chill-green': !conc.holder,
'btn-chill-green': conc.holder,
}"
@click="toggleHolder(conc)"
>
{{ $t("household_members_editor.positioning.holder") }}
</button>
</div>
<div
v-for="(position, i) in positions"
:key="`position-${i}`"
class="position"
>
<button
class="btn"
:class="{
'btn-primary': conc.position === position,
'btn-outline-primary': conc.position !== position,
}"
@click="moveToPosition(conc.person.id, position.id)"
>
{{ localizeString(position.label) }}
</button>
</div>
</div>
<div class="item-row">
<div class="col-12">
<h6>
{{ $t("household_members_editor.positioning.comment") }}
</h6>
<person-comment :conc="conc" />
</div>
</div>
</div>
<div class="holder">
<button
class="btn"
:disabled="!allowHolderForConcerned(conc)"
:class="{
'btn-outline-chill-green': !conc.holder,
'btn-chill-green': conc.holder,
}"
@click="toggleHolder(conc)"
>
{{ $t("household_members_editor.positioning.holder") }}
</button>
</div>
<div
v-for="(position, i) in positions"
:key="`position-${i}`"
class="position"
>
<button
class="btn"
:class="{
'btn-primary': conc.position === position,
'btn-outline-primary': conc.position !== position,
}"
@click="moveToPosition(conc.person.id, position.id)"
>
{{ localizeString(position.label) }}
</button>
</div>
</div>
<div class="item-row">
<div class="col-12">
<h6>{{ $t("household_members_editor.positioning.comment") }}</h6>
<person-comment :conc="conc" />
</div>
</div>
</div>
</div>
</template>
<script>
@ -60,61 +62,61 @@ import PersonText from "../../_components/Entity/PersonText.vue";
import { localizeString } from "ChillMainAssets/lib/localizationHelper/localizationHelper";
export default {
name: "Positioning",
components: {
CurrentHousehold,
PersonComment,
PersonText,
},
computed: {
...mapState(["concerned"]),
...mapGetters([
"persons",
"concUnpositionned",
"positions",
"concByPosition",
]),
allPersonsPositionnated() {
return (
this.$store.getters.persons.length > 0 &&
this.$store.getters.concUnpositionned.length === 0
);
name: "Positioning",
components: {
CurrentHousehold,
PersonComment,
PersonText,
},
allowHolderForConcerned: () => (conc) => {
console.log("allow holder for concerned", conc);
if (conc.position === null) {
return false;
}
computed: {
...mapState(["concerned"]),
...mapGetters([
"persons",
"concUnpositionned",
"positions",
"concByPosition",
]),
allPersonsPositionnated() {
return (
this.$store.getters.persons.length > 0 &&
this.$store.getters.concUnpositionned.length === 0
);
},
allowHolderForConcerned: () => (conc) => {
console.log("allow holder for concerned", conc);
if (conc.position === null) {
return false;
}
return conc.position.allowHolder;
return conc.position.allowHolder;
},
},
},
methods: {
localizeString,
moveToPosition(person_id, position_id) {
this.$store.dispatch("markPosition", { person_id, position_id });
methods: {
localizeString,
moveToPosition(person_id, position_id) {
this.$store.dispatch("markPosition", { person_id, position_id });
},
toggleHolder(conc) {
console.log("toggle holder", conc);
this.$store.dispatch("toggleHolder", conc);
},
},
toggleHolder(conc) {
console.log("toggle holder", conc);
this.$store.dispatch("toggleHolder", conc);
},
},
};
</script>
<style lang="scss" scoped>
.pick-position {
margin: 0;
padding: 0;
display: flex;
justify-content: flex-end;
align-items: center;
margin: 0;
padding: 0;
display: flex;
justify-content: flex-end;
align-items: center;
.person {
margin-right: auto;
}
.holder {
margin-right: 1.2rem;
}
.person {
margin-right: auto;
}
.holder {
margin-right: 1.2rem;
}
}
</style>

View File

@ -2,10 +2,10 @@ import { AccompanyingPeriodWorkEvaluationDocument } from "../../types";
import { makeFetch } from "../../../../../ChillMainBundle/Resources/public/lib/api/apiMethods";
export const duplicate = async (
id: number,
id: number,
): Promise<AccompanyingPeriodWorkEvaluationDocument> => {
return makeFetch<null, AccompanyingPeriodWorkEvaluationDocument>(
"POST",
`/api/1.0/person/accompanying-course-work-evaluation-document/${id}/duplicate`,
);
return makeFetch<null, AccompanyingPeriodWorkEvaluationDocument>(
"POST",
`/api/1.0/person/accompanying-course-work-evaluation-document/${id}/duplicate`,
);
};

View File

@ -1,26 +1,26 @@
<template>
<a
class="btn"
:class="getClassButton"
:title="buttonTitle"
@click="openModal"
>
<span v-if="displayTextButton">{{ buttonTitle }}</span>
</a>
<teleport to="body">
<modal
v-if="showModal"
@close="closeModal"
:modal-dialog-class="modalDialogClass"
:show="showModal"
:hide-footer="false"
<a
class="btn"
:class="getClassButton"
:title="buttonTitle"
@click="openModal"
>
<template #header>
<h3 class="modal-title">
{{ modalTitle }}
</h3>
</template>
<span v-if="displayTextButton">{{ buttonTitle }}</span>
</a>
<teleport to="body">
<modal
v-if="showModal"
@close="closeModal"
:modal-dialog-class="modalDialogClass"
:show="showModal"
:hide-footer="false"
>
<template #header>
<h3 class="modal-title">
{{ modalTitle }}
</h3>
</template>
<template #body-head>
<div class="modal-body">
@ -437,9 +437,9 @@ defineExpose({
<style lang="scss">
li.add-persons {
a {
cursor: pointer;
}
a {
cursor: pointer;
}
}
div.body-head {
overflow-y: unset;
@ -480,7 +480,7 @@ div.body-head {
}
}
.create-button > a {
margin-top: 0.5em;
margin-left: 2.6em;
margin-top: 0.5em;
margin-left: 2.6em;
}
</style>

View File

@ -1,63 +1,64 @@
const personMessages = {
fr: {
add_persons: {
title: "Ajouter des usagers",
suggested_counter: "Pas de résultats | 1 résultat | {count} résultats",
selected_counter: " 1 sélectionné | {count} sélectionnés",
search_some_persons: "Rechercher des personnes..",
fr: {
add_persons: {
title: "Ajouter des usagers",
suggested_counter:
"Pas de résultats | 1 résultat | {count} résultats",
selected_counter: " 1 sélectionné | {count} sélectionnés",
search_some_persons: "Rechercher des personnes..",
},
item: {
type_person: "Usager",
type_user: "TMS",
type_thirdparty: "Tiers professionnel",
type_household: "Ménage",
},
person: {
firstname: "Prénom",
lastname: "Nom",
born: (ctx: { gender: "man" | "woman" | "neutral" }) => {
if (ctx.gender === "man") {
return "Né le";
} else if (ctx.gender === "woman") {
return "Née le";
} else {
return "Né·e le";
}
},
center_id: "Identifiant du centre",
center_type: "Type de centre",
center_name: "Territoire", // vendée
phonenumber: "Téléphone",
mobilenumber: "Mobile",
altnames: "Autres noms",
email: "Courriel",
gender: {
title: "Genre",
placeholder: "Choisissez le genre de l'usager",
woman: "Féminin",
man: "Masculin",
neutral: "Neutre, non binaire",
unknown: "Non renseigné",
undefined: "Non renseigné",
},
civility: {
title: "Civilité",
placeholder: "Choisissez la civilité",
},
address: {
create_address: "Ajouter une adresse",
show_address_form:
"Ajouter une adresse pour un usager non suivi et seul dans un ménage",
warning:
"Un nouveau ménage va être créé. L'usager sera membre de ce ménage.",
},
center: {
placeholder: "Choisissez un centre",
title: "Centre",
},
},
error_only_one_person: "Une seule personne peut être sélectionnée !",
},
item: {
type_person: "Usager",
type_user: "TMS",
type_thirdparty: "Tiers professionnel",
type_household: "Ménage",
},
person: {
firstname: "Prénom",
lastname: "Nom",
born: (ctx: { gender: "man" | "woman" | "neutral" }) => {
if (ctx.gender === "man") {
return "Né le";
} else if (ctx.gender === "woman") {
return "Née le";
} else {
return "Né·e le";
}
},
center_id: "Identifiant du centre",
center_type: "Type de centre",
center_name: "Territoire", // vendée
phonenumber: "Téléphone",
mobilenumber: "Mobile",
altnames: "Autres noms",
email: "Courriel",
gender: {
title: "Genre",
placeholder: "Choisissez le genre de l'usager",
woman: "Féminin",
man: "Masculin",
neutral: "Neutre, non binaire",
unknown: "Non renseigné",
undefined: "Non renseigné",
},
civility: {
title: "Civilité",
placeholder: "Choisissez la civilité",
},
address: {
create_address: "Ajouter une adresse",
show_address_form:
"Ajouter une adresse pour un usager non suivi et seul dans un ménage",
warning:
"Un nouveau ménage va être créé. L'usager sera membre de ce ménage.",
},
center: {
placeholder: "Choisissez un centre",
title: "Centre",
},
},
error_only_one_person: "Une seule personne peut être sélectionnée !",
},
};
export { personMessages };

View File

@ -1,40 +1,40 @@
import { is_object_ready } from "../../../../../../ChillDocStoreBundle/Resources/public/vuejs/StoredObjectButton/helpers";
import {
StoredObject,
StoredObjectStatus,
StoredObjectStatusChange,
StoredObject,
StoredObjectStatus,
StoredObjectStatusChange,
} from "../../../../../../ChillDocStoreBundle/Resources/public/types";
async function reload_if_needed(
stored_object: StoredObject,
i: number,
stored_object: StoredObject,
i: number,
): Promise<void> {
const current_status = await is_object_ready(stored_object);
const current_status = await is_object_ready(stored_object);
if (stored_object.status !== current_status.status) {
window.location.reload();
}
wait_before_reload(stored_object, i + 1);
return Promise.resolve();
if (stored_object.status !== current_status.status) {
window.location.reload();
}
wait_before_reload(stored_object, i + 1);
return Promise.resolve();
}
function wait_before_reload(stored_object: StoredObject, i: number): void {
/**
* value of the timeout. Set to 5 sec during the first 10 minutes, then every 1 minute
*/
const timeout = i < 1200 ? 5000 : 60000;
/**
* value of the timeout. Set to 5 sec during the first 10 minutes, then every 1 minute
*/
const timeout = i < 1200 ? 5000 : 60000;
setTimeout(reload_if_needed, timeout, stored_object, i);
setTimeout(reload_if_needed, timeout, stored_object, i);
}
window.addEventListener("DOMContentLoaded", async function (e) {
if (undefined === (window as any).stored_object) {
console.error("window.stored_object is undefined");
throw Error("window.stored_object is undefined");
}
if (undefined === (window as any).stored_object) {
console.error("window.stored_object is undefined");
throw Error("window.stored_object is undefined");
}
const stored_object = JSON.parse(
(window as any).stored_object,
) as StoredObject;
reload_if_needed(stored_object, 0);
const stored_object = JSON.parse(
(window as any).stored_object,
) as StoredObject;
reload_if_needed(stored_object, 0);
});