mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-06-07 18:44:08 +00:00
Merge remote-tracking branch 'origin/master' into foldlist_in_entity
This commit is contained in:
commit
971789d5cf
27
CHANGELOG.md
27
CHANGELOG.md
@ -11,23 +11,40 @@ and this project adheres to
|
|||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
<!-- write down unreleased development here -->
|
<!-- write down unreleased development here -->
|
||||||
|
[fast_actions] improve fast-actions buttons override mechanism, fix https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/413
|
||||||
|
[homepage widget] add vue homepage_widget with asynchone loading, give a global view resume of the user concerned actions, notifications, etc.
|
||||||
|
* [person] accompanying course: optimisation: do not fetch some resources for the banner (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/409)
|
||||||
|
* [person] accompanying course: close modal when edit participation (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/420)
|
||||||
|
* [person] accompanying course: treat validation error when editing on-the-fly entities (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/420)
|
||||||
|
* [activity] show activity attendee (présence) in the activity list (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/412)
|
||||||
|
* [activity] admin: change validation rule for social action visible field (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/413)
|
||||||
|
* [parcours]: component added to change the opening date of a parcours (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/411)
|
||||||
|
* [search]: listing of parcours display changed (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/410)
|
||||||
|
* [user]: page with accompanying periods to which is user is referent (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/408)
|
||||||
|
* [person] age added to renderstring + renderbox/ vue component created to display person text (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/389)
|
||||||
|
* [household member editor] allow to push to existing household
|
||||||
|
* [workflow][notification] improve how notifications and workflows are 'attached' to entities: contextual list, counter, buttons and vue modal
|
||||||
|
|
||||||
|
|
||||||
|
## Test releases
|
||||||
|
|
||||||
|
### test release 2021-01-28
|
||||||
|
|
||||||
* [person] improve filiations vis graph: disable physics, use chill colors for persons-households-course, increase label of relations, remove labels on household arrows and other improvements (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/286, https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/362)
|
* [person] improve filiations vis graph: disable physics, use chill colors for persons-households-course, increase label of relations, remove labels on household arrows and other improvements (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/286, https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/362)
|
||||||
* [activity] Order activity by date and by id (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/364)
|
* [activity] Order activity by date and by id (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/364)
|
||||||
* [main] increase length of 4 Address fields (change to TEXT, no size limits) (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/277)
|
* [main] increase length of 4 Address fields (change to TEXT, no size limits) (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/277)
|
||||||
* [main] Add confidential option for address, in edit and view (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/165)
|
* [main] Add confidential option for address, in edit and view (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/165)
|
||||||
* [person] name suggestions within create person form when person is created departing from a search input (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/377)
|
* [person] name suggestions within create person form when person is created departing from a search input (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/377)
|
||||||
* [workflow][notification] improve how notifications and workflows are 'attached' to entities: contextual list, counter, buttons and vue modal
|
* [person] Add residential address entity, form and list for each person
|
||||||
|
* [aside_activity]: dynamicUserPickerType used (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/399)
|
||||||
|
* dispatching list
|
||||||
|
|
||||||
## Test releases
|
|
||||||
|
|
||||||
### test release 2021-01-26
|
### test release 2021-01-26
|
||||||
|
|
||||||
* [parcours] comments truncated if too long + link added (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/406)
|
* [parcours] comments truncated if too long + link added (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/406)
|
||||||
* [person]: possibility to add person resources (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/382)
|
* [person]: possibility to add person resources (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/382)
|
||||||
* [person ressources]: module added
|
* [person ressources]: module added
|
||||||
* [parcours] bugfix if deathdate is not defined (eg. for a thirdparty) parcours is still displayed. Gave error before.
|
|
||||||
* dispatching list
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### test release 2022-01-24
|
### test release 2022-01-24
|
||||||
|
@ -80,11 +80,6 @@ parameters:
|
|||||||
count: 1
|
count: 1
|
||||||
path: src/Bundle/ChillPersonBundle/Form/ChoiceLoader/PersonChoiceLoader.php
|
path: src/Bundle/ChillPersonBundle/Form/ChoiceLoader/PersonChoiceLoader.php
|
||||||
|
|
||||||
-
|
|
||||||
message: "#^Foreach overwrites \\$action with its value variable\\.$#"
|
|
||||||
count: 1
|
|
||||||
path: src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/AccompanyingPeriodWorkRepository.php
|
|
||||||
|
|
||||||
-
|
-
|
||||||
message: "#^Foreach overwrites \\$action with its value variable\\.$#"
|
message: "#^Foreach overwrites \\$action with its value variable\\.$#"
|
||||||
count: 1
|
count: 1
|
||||||
|
@ -30,36 +30,6 @@ parameters:
|
|||||||
count: 2
|
count: 2
|
||||||
path: src/Bundle/ChillPersonBundle/Household/MembersEditorFactory.php
|
path: src/Bundle/ChillPersonBundle/Household/MembersEditorFactory.php
|
||||||
|
|
||||||
-
|
|
||||||
message: "#^Parameter \\$action of method Chill\\\\PersonBundle\\\\Repository\\\\AccompanyingPeriod\\\\AccompanyingPeriodWorkRepository\\:\\:buildQueryBySocialActionWithDescendants\\(\\) has invalid type Chill\\\\PersonBundle\\\\Repository\\\\AccompanyingPeriod\\\\SocialAction\\.$#"
|
|
||||||
count: 1
|
|
||||||
path: src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/AccompanyingPeriodWorkRepository.php
|
|
||||||
|
|
||||||
-
|
|
||||||
message: "#^Parameter \\$action of method Chill\\\\PersonBundle\\\\Repository\\\\AccompanyingPeriod\\\\AccompanyingPeriodWorkRepository\\:\\:countBySocialActionWithDescendants\\(\\) has invalid type Chill\\\\PersonBundle\\\\Repository\\\\AccompanyingPeriod\\\\SocialAction\\.$#"
|
|
||||||
count: 1
|
|
||||||
path: src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/AccompanyingPeriodWorkRepository.php
|
|
||||||
|
|
||||||
-
|
|
||||||
message: "#^Undefined variable\\: \\$action$#"
|
|
||||||
count: 1
|
|
||||||
path: src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/AccompanyingPeriodWorkRepository.php
|
|
||||||
|
|
||||||
-
|
|
||||||
message: "#^Undefined variable\\: \\$limit$#"
|
|
||||||
count: 1
|
|
||||||
path: src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/AccompanyingPeriodWorkRepository.php
|
|
||||||
|
|
||||||
-
|
|
||||||
message: "#^Undefined variable\\: \\$offset$#"
|
|
||||||
count: 1
|
|
||||||
path: src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/AccompanyingPeriodWorkRepository.php
|
|
||||||
|
|
||||||
-
|
|
||||||
message: "#^Undefined variable\\: \\$orderBy$#"
|
|
||||||
count: 1
|
|
||||||
path: src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/AccompanyingPeriodWorkRepository.php
|
|
||||||
|
|
||||||
-
|
-
|
||||||
message: "#^Variable variables are not allowed\\.$#"
|
message: "#^Variable variables are not allowed\\.$#"
|
||||||
count: 4
|
count: 4
|
||||||
|
@ -400,11 +400,6 @@ parameters:
|
|||||||
count: 1
|
count: 1
|
||||||
path: src/Bundle/ChillPersonBundle/Form/Type/PersonPhoneType.php
|
path: src/Bundle/ChillPersonBundle/Form/Type/PersonPhoneType.php
|
||||||
|
|
||||||
-
|
|
||||||
message: "#^Method Chill\\\\PersonBundle\\\\Repository\\\\AccompanyingPeriod\\\\AccompanyingPeriodWorkRepository\\:\\:buildQueryBySocialActionWithDescendants\\(\\) has invalid return type Chill\\\\PersonBundle\\\\Repository\\\\AccompanyingPeriod\\\\QueryBuilder\\.$#"
|
|
||||||
count: 1
|
|
||||||
path: src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/AccompanyingPeriodWorkRepository.php
|
|
||||||
|
|
||||||
-
|
-
|
||||||
message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
|
message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
|
||||||
count: 3
|
count: 3
|
||||||
|
@ -16,6 +16,7 @@ use InvalidArgumentException;
|
|||||||
use Symfony\Component\Serializer\Annotation as Serializer;
|
use Symfony\Component\Serializer\Annotation as Serializer;
|
||||||
use Symfony\Component\Serializer\Annotation\Groups;
|
use Symfony\Component\Serializer\Annotation\Groups;
|
||||||
use Symfony\Component\Validator\Constraints as Assert;
|
use Symfony\Component\Validator\Constraints as Assert;
|
||||||
|
use Symfony\Component\Validator\Context\ExecutionContextInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class ActivityType.
|
* Class ActivityType.
|
||||||
@ -193,7 +194,6 @@ class ActivityType
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\Column(type="smallint", nullable=false, options={"default": 1})
|
* @ORM\Column(type="smallint", nullable=false, options={"default": 1})
|
||||||
* @Assert\EqualTo(propertyPath="socialIssuesVisible", message="This parameter must be equal to social issue parameter")
|
|
||||||
*/
|
*/
|
||||||
private int $socialActionsVisible = self::FIELD_INVISIBLE;
|
private int $socialActionsVisible = self::FIELD_INVISIBLE;
|
||||||
|
|
||||||
@ -263,6 +263,23 @@ class ActivityType
|
|||||||
*/
|
*/
|
||||||
private int $userVisible = self::FIELD_REQUIRED;
|
private int $userVisible = self::FIELD_REQUIRED;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Assert\Callback
|
||||||
|
*
|
||||||
|
* @param mixed $payload
|
||||||
|
*/
|
||||||
|
public function checkSocialActionsVisibility(ExecutionContextInterface $context, $payload)
|
||||||
|
{
|
||||||
|
if ($this->socialIssuesVisible !== $this->socialActionsVisible) {
|
||||||
|
if (!($this->socialIssuesVisible === 2 && $this->socialActionsVisible === 1)) {
|
||||||
|
$context
|
||||||
|
->buildViolation('The socialActionsVisible value is not compatible with the socialIssuesVisible value')
|
||||||
|
->atPath('socialActionsVisible')
|
||||||
|
->addViolation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get active
|
* Get active
|
||||||
* return true if the type is active.
|
* return true if the type is active.
|
||||||
|
@ -34,6 +34,8 @@ p.date-label {
|
|||||||
font-size: 18pt;
|
font-size: 18pt;
|
||||||
}
|
}
|
||||||
div.dashboard,
|
div.dashboard,
|
||||||
|
h4.badge-title,
|
||||||
|
h3.badge-title,
|
||||||
h2.badge-title {
|
h2.badge-title {
|
||||||
ul.list-content {
|
ul.list-content {
|
||||||
font-size: 70%;
|
font-size: 70%;
|
||||||
|
@ -1,45 +1,48 @@
|
|||||||
<template>
|
<template>
|
||||||
<teleport to="#add-persons" v-if="isComponentVisible">
|
<teleport to="#add-persons" v-if="isComponentVisible">
|
||||||
|
|
||||||
<div class="flex-bloc concerned-groups" :class="getContext">
|
<div class="flex-bloc concerned-groups" :class="getContext">
|
||||||
<persons-bloc
|
<persons-bloc
|
||||||
v-for="bloc in contextPersonsBlocs"
|
v-for="bloc in contextPersonsBlocs"
|
||||||
v-bind:key="bloc.key"
|
v-bind:key="bloc.key"
|
||||||
v-bind:bloc="bloc"
|
v-bind:bloc="bloc"
|
||||||
v-bind:blocWidth="getBlocWidth"
|
v-bind:blocWidth="getBlocWidth"
|
||||||
v-bind:setPersonsInBloc="setPersonsInBloc">
|
v-bind:setPersonsInBloc="setPersonsInBloc">
|
||||||
</persons-bloc>
|
</persons-bloc>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="getContext === 'accompanyingCourse' && suggestedEntities.length > 0">
|
<div v-if="getContext === 'accompanyingCourse' && suggestedEntities.length > 0">
|
||||||
<ul class="list-suggest add-items inline">
|
<ul class="list-suggest add-items inline">
|
||||||
<li v-for="(p, i) in suggestedEntities" @click="addSuggestedEntity(p)" :key="`suggestedEntities-${i}`">
|
<li v-for="(p, i) in suggestedEntities" @click="addSuggestedEntity(p)" :key="`suggestedEntities-${i}`">
|
||||||
<span>{{ p.text }}</span>
|
<person-text v-if="p.type === 'person'" :person="p"></person-text>
|
||||||
</li>
|
<span v-else>{{ p.text }}</span>
|
||||||
</ul>
|
</li>
|
||||||
</div>
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
<add-persons
|
<add-persons
|
||||||
buttonTitle="activity.add_persons"
|
buttonTitle="activity.add_persons"
|
||||||
modalTitle="activity.add_persons"
|
modalTitle="activity.add_persons"
|
||||||
v-bind:key="addPersons.key"
|
v-bind:key="addPersons.key"
|
||||||
v-bind:options="addPersonsOptions"
|
v-bind:options="addPersonsOptions"
|
||||||
@addNewPersons="addNewPersons"
|
@addNewPersons="addNewPersons"
|
||||||
ref="addPersons">
|
ref="addPersons">
|
||||||
</add-persons>
|
</add-persons>
|
||||||
|
|
||||||
</teleport>
|
</teleport>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapState, mapGetters } from 'vuex';
|
import { mapState, mapGetters } from 'vuex';
|
||||||
import AddPersons from 'ChillPersonAssets/vuejs/_components/AddPersons.vue';
|
import AddPersons from 'ChillPersonAssets/vuejs/_components/AddPersons.vue';
|
||||||
import PersonsBloc from './ConcernedGroups/PersonsBloc.vue';
|
import PersonsBloc from './ConcernedGroups/PersonsBloc.vue';
|
||||||
|
import PersonText from 'ChillPersonAssets/vuejs/_components/Entity/PersonText.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "ConcernedGroups",
|
name: "ConcernedGroups",
|
||||||
components: {
|
components: {
|
||||||
AddPersons,
|
AddPersons,
|
||||||
PersonsBloc
|
PersonsBloc,
|
||||||
|
PersonText
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
@ -1,21 +1,29 @@
|
|||||||
<template>
|
<template>
|
||||||
<li>
|
<li>
|
||||||
<span :title="person.text">
|
<span :title="person.text">
|
||||||
<span class="chill_denomination" @click.prevent="$emit('remove', person)">{{ textCutted }}</span>
|
<span class="chill_denomination" @click.prevent="$emit('remove', person)">
|
||||||
|
<person-text :person="person" :isCut="true"></person-text>
|
||||||
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import PersonText from 'ChillPersonAssets/vuejs/_components/Entity/PersonText.vue';
|
||||||
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "PersonBadge",
|
name: "PersonBadge",
|
||||||
props: ['person'],
|
props: ['person'],
|
||||||
computed: {
|
components: {
|
||||||
textCutted() {
|
PersonText
|
||||||
let more = (this.person.text.length > 15) ?'…' : '';
|
|
||||||
return this.person.text.slice(0,15) + more;
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
// computed: {
|
||||||
|
// textCutted() {
|
||||||
|
// let more = (this.person.text.length > 15) ?'…' : '';
|
||||||
|
// return this.person.text.slice(0,15) + more;
|
||||||
|
// }
|
||||||
|
// },
|
||||||
emits: ['remove'],
|
emits: ['remove'],
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -41,6 +41,17 @@
|
|||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
{% if activity.attendee and t.attendeeVisible %}
|
||||||
|
<div class="wl-row">
|
||||||
|
<div class="wl-col title"><h3>{{ 'Attendee'|trans }}</h3></div>
|
||||||
|
<div class="wl-col list">
|
||||||
|
<p class="wl-item">
|
||||||
|
{{ activity.attendee.name|localize_translatable_string }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% if activity.sentReceived is not empty and t.sentReceivedVisible %}
|
{% if activity.sentReceived is not empty and t.sentReceivedVisible %}
|
||||||
<div class="wl-row">
|
<div class="wl-row">
|
||||||
<div class="wl-col title"><h3>{{ 'Sent received'|trans }}</h3></div>
|
<div class="wl-col title"><h3>{{ 'Sent received'|trans }}</h3></div>
|
||||||
|
@ -48,7 +48,7 @@
|
|||||||
<li class="associated-persons">
|
<li class="associated-persons">
|
||||||
<span class="item-key">{{ 'Participants'|trans ~ ' : ' }}</span>
|
<span class="item-key">{{ 'Participants'|trans ~ ' : ' }}</span>
|
||||||
{% for p in activity.personsAssociated %}
|
{% for p in activity.personsAssociated %}
|
||||||
<span class="badge-person">{{ p|chill_entity_render_box }}</span>
|
<span class="badge-person">{{ p|chill_entity_render_box({'addAgeBadge': true}) }}</span>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -165,11 +165,7 @@
|
|||||||
<dt class="inline">{{ 'Attendee'|trans }}</dt>
|
<dt class="inline">{{ 'Attendee'|trans }}</dt>
|
||||||
<dd>
|
<dd>
|
||||||
{% if entity.attendee is not null %}
|
{% if entity.attendee is not null %}
|
||||||
{% if entity.attendee %}
|
{{ entity.attendee.name|localize_translatable_string }}
|
||||||
{{ 'present'|trans|capitalize }}
|
|
||||||
{% else %}
|
|
||||||
{{ 'not present'|trans|capitalize }}
|
|
||||||
{% endif %}
|
|
||||||
{% else %}
|
{% else %}
|
||||||
<span class="chill-no-data-statement">{{ 'None'|trans|capitalize }}</span>
|
<span class="chill-no-data-statement">{{ 'None'|trans|capitalize }}</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -20,3 +20,4 @@ For this type of activity, you must add at least one social action: Pour ce type
|
|||||||
|
|
||||||
# admin
|
# admin
|
||||||
This parameter must be equal to social issue parameter: Ce paramètre doit être égal au paramètre "Visibilité du champs Problématiques sociales"
|
This parameter must be equal to social issue parameter: Ce paramètre doit être égal au paramètre "Visibilité du champs Problématiques sociales"
|
||||||
|
The socialActionsVisible value is not compatible with the socialIssuesVisible value: Cette valeur du paramètre "Visibilité du champs Actions sociales" n'est pas compatible avec la valeur du paramètre "Visibilité du champs Problématiques sociales"
|
@ -32,6 +32,8 @@ final class AsideActivityController extends CRUDController
|
|||||||
{
|
{
|
||||||
$asideActivity = new AsideActivity();
|
$asideActivity = new AsideActivity();
|
||||||
|
|
||||||
|
$asideActivity->setAgent($this->getUser());
|
||||||
|
|
||||||
$duration = $request->query->get('duration', '300');
|
$duration = $request->query->get('duration', '300');
|
||||||
$duration = DateTime::createFromFormat('U', $duration);
|
$duration = DateTime::createFromFormat('U', $duration);
|
||||||
$asideActivity->setDuration($duration);
|
$asideActivity->setDuration($duration);
|
||||||
|
@ -14,9 +14,9 @@ namespace Chill\AsideActivityBundle\Form;
|
|||||||
use Chill\AsideActivityBundle\Entity\AsideActivity;
|
use Chill\AsideActivityBundle\Entity\AsideActivity;
|
||||||
use Chill\AsideActivityBundle\Entity\AsideActivityCategory;
|
use Chill\AsideActivityBundle\Entity\AsideActivityCategory;
|
||||||
use Chill\AsideActivityBundle\Templating\Entity\CategoryRender;
|
use Chill\AsideActivityBundle\Templating\Entity\CategoryRender;
|
||||||
use Chill\MainBundle\Entity\User;
|
|
||||||
use Chill\MainBundle\Form\Type\ChillDateType;
|
use Chill\MainBundle\Form\Type\ChillDateType;
|
||||||
use Chill\MainBundle\Form\Type\ChillTextareaType;
|
use Chill\MainBundle\Form\Type\ChillTextareaType;
|
||||||
|
use Chill\MainBundle\Form\Type\PickUserDynamicType;
|
||||||
use DateInterval;
|
use DateInterval;
|
||||||
use DateTime;
|
use DateTime;
|
||||||
use DateTimeImmutable;
|
use DateTimeImmutable;
|
||||||
@ -68,22 +68,10 @@ final class AsideActivityFormType extends AbstractType
|
|||||||
];
|
];
|
||||||
|
|
||||||
$builder
|
$builder
|
||||||
->add(
|
->add('agent', PickUserDynamicType::class, [
|
||||||
'agent',
|
'label' => 'For agent',
|
||||||
EntityType::class,
|
'required' => true,
|
||||||
[
|
])
|
||||||
'label' => 'For agent',
|
|
||||||
'required' => true,
|
|
||||||
'class' => User::class,
|
|
||||||
'data' => $this->storage->getToken()->getUser(),
|
|
||||||
'query_builder' => static function (EntityRepository $er) {
|
|
||||||
return $er->createQueryBuilder('u')->where('u.enabled = true');
|
|
||||||
},
|
|
||||||
'attr' => ['class' => 'select2 '],
|
|
||||||
'placeholder' => 'Choose the agent for whom this activity is created',
|
|
||||||
'choice_label' => 'username',
|
|
||||||
]
|
|
||||||
)
|
|
||||||
->add(
|
->add(
|
||||||
'date',
|
'date',
|
||||||
ChillDateType::class,
|
ChillDateType::class,
|
||||||
|
@ -1,5 +1,15 @@
|
|||||||
{% extends '@ChillMain/Admin/layout.html.twig' %}
|
{% extends '@ChillMain/Admin/layout.html.twig' %}
|
||||||
|
|
||||||
|
{% block js %}
|
||||||
|
{{ parent() }}
|
||||||
|
{{ encore_entry_script_tags('mod_pickentity_type') }}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block css %}
|
||||||
|
{{ parent() }}
|
||||||
|
{{ encore_entry_link_tags('mod_pickentity_type') }}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
{% block title %}
|
{% block title %}
|
||||||
{% include('@ChillMain/CRUD/_new_title.html.twig') %}
|
{% include('@ChillMain/CRUD/_new_title.html.twig') %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@ -8,4 +18,5 @@
|
|||||||
{% embed '@ChillMain/CRUD/_new_content.html.twig' %}
|
{% embed '@ChillMain/CRUD/_new_content.html.twig' %}
|
||||||
{% block content_form_actions_save_and_show %}{% endblock %}
|
{% block content_form_actions_save_and_show %}{% endblock %}
|
||||||
{% endembed %}
|
{% endembed %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
@ -13,13 +13,19 @@ namespace Chill\MainBundle\Controller;
|
|||||||
|
|
||||||
use Chill\MainBundle\Entity\Notification;
|
use Chill\MainBundle\Entity\Notification;
|
||||||
use Chill\MainBundle\Entity\User;
|
use Chill\MainBundle\Entity\User;
|
||||||
|
use Chill\MainBundle\Pagination\PaginatorFactory;
|
||||||
|
use Chill\MainBundle\Repository\NotificationRepository;
|
||||||
use Chill\MainBundle\Security\Authorization\NotificationVoter;
|
use Chill\MainBundle\Security\Authorization\NotificationVoter;
|
||||||
|
use Chill\MainBundle\Serializer\Model\Collection;
|
||||||
|
use Chill\MainBundle\Serializer\Model\Counter;
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
use RuntimeException;
|
use RuntimeException;
|
||||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\Routing\Annotation\Route;
|
use Symfony\Component\Routing\Annotation\Route;
|
||||||
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
|
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
|
||||||
use Symfony\Component\Security\Core\Security;
|
use Symfony\Component\Security\Core\Security;
|
||||||
|
use Symfony\Component\Serializer\SerializerInterface;
|
||||||
use UnexpectedValueException;
|
use UnexpectedValueException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -29,12 +35,26 @@ class NotificationApiController
|
|||||||
{
|
{
|
||||||
private EntityManagerInterface $entityManager;
|
private EntityManagerInterface $entityManager;
|
||||||
|
|
||||||
|
private NotificationRepository $notificationRepository;
|
||||||
|
|
||||||
|
private PaginatorFactory $paginatorFactory;
|
||||||
|
|
||||||
private Security $security;
|
private Security $security;
|
||||||
|
|
||||||
public function __construct(EntityManagerInterface $entityManager, Security $security)
|
private SerializerInterface $serializer;
|
||||||
{
|
|
||||||
|
public function __construct(
|
||||||
|
EntityManagerInterface $entityManager,
|
||||||
|
NotificationRepository $notificationRepository,
|
||||||
|
PaginatorFactory $paginatorFactory,
|
||||||
|
Security $security,
|
||||||
|
SerializerInterface $serializer
|
||||||
|
) {
|
||||||
$this->entityManager = $entityManager;
|
$this->entityManager = $entityManager;
|
||||||
|
$this->notificationRepository = $notificationRepository;
|
||||||
|
$this->paginatorFactory = $paginatorFactory;
|
||||||
$this->security = $security;
|
$this->security = $security;
|
||||||
|
$this->serializer = $serializer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -53,6 +73,37 @@ class NotificationApiController
|
|||||||
return $this->markAs('unread', $notification);
|
return $this->markAs('unread', $notification);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Route("/my/unread")
|
||||||
|
*/
|
||||||
|
public function myUnreadNotifications(Request $request): JsonResponse
|
||||||
|
{
|
||||||
|
$total = $this->notificationRepository->countUnreadByUser($this->security->getUser());
|
||||||
|
|
||||||
|
if ($request->query->getBoolean('countOnly')) {
|
||||||
|
return new JsonResponse(
|
||||||
|
$this->serializer->serialize(new Counter($total), 'json', ['groups' => ['read']]),
|
||||||
|
JsonResponse::HTTP_OK,
|
||||||
|
[],
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
$paginator = $this->paginatorFactory->create($total);
|
||||||
|
$notifications = $this->notificationRepository->findUnreadByUser(
|
||||||
|
$this->security->getUser(),
|
||||||
|
$paginator->getItemsPerPage(),
|
||||||
|
$paginator->getCurrentPageFirstItemNumber()
|
||||||
|
);
|
||||||
|
$collection = new Collection($notifications, $paginator);
|
||||||
|
|
||||||
|
return new JsonResponse(
|
||||||
|
$this->serializer->serialize($collection, 'json', ['groups' => ['read']]),
|
||||||
|
JsonResponse::HTTP_OK,
|
||||||
|
[],
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
private function markAs(string $target, Notification $notification): JsonResponse
|
private function markAs(string $target, Notification $notification): JsonResponse
|
||||||
{
|
{
|
||||||
if (!$this->security->isGranted(NotificationVoter::NOTIFICATION_TOGGLE_READ_STATUS, $notification)) {
|
if (!$this->security->isGranted(NotificationVoter::NOTIFICATION_TOGGLE_READ_STATUS, $notification)) {
|
||||||
|
166
src/Bundle/ChillMainBundle/Entity/ResidentialAddress.php
Normal file
166
src/Bundle/ChillMainBundle/Entity/ResidentialAddress.php
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Chill\MainBundle\Entity;
|
||||||
|
|
||||||
|
use Chill\MainBundle\Entity\Embeddable\CommentEmbeddable;
|
||||||
|
use Chill\MainBundle\Repository\ResidentialAddressRepository;
|
||||||
|
use Chill\PersonBundle\Entity\Person;
|
||||||
|
use Chill\ThirdPartyBundle\Entity\ThirdParty;
|
||||||
|
use DateTimeImmutable;
|
||||||
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Entity(repositoryClass=ResidentialAddressRepository::class)
|
||||||
|
* @ORM\Table(name="chill_main_residential_address")
|
||||||
|
*/
|
||||||
|
class ResidentialAddress
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @ORM\ManyToOne(targetEntity=Address::class)
|
||||||
|
* @ORM\JoinColumn(nullable=true)
|
||||||
|
*/
|
||||||
|
private ?Address $address = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Embedded(class="Chill\MainBundle\Entity\Embeddable\CommentEmbeddable", columnPrefix="residentialAddressComment_")
|
||||||
|
*/
|
||||||
|
private CommentEmbeddable $comment;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Column(type="datetime_immutable", nullable=true)
|
||||||
|
*/
|
||||||
|
private ?DateTimeImmutable $endDate = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\ManyToOne(targetEntity=Person::class)
|
||||||
|
* @ORM\JoinColumn(nullable=true)
|
||||||
|
*/
|
||||||
|
private ?Person $hostPerson = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\ManyToOne(targetEntity=ThirdParty::class)
|
||||||
|
* @ORM\JoinColumn(nullable=true)
|
||||||
|
*/
|
||||||
|
private ?ThirdParty $hostThirdParty = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Id
|
||||||
|
* @ORM\GeneratedValue
|
||||||
|
* @ORM\Column(type="integer")
|
||||||
|
*/
|
||||||
|
private $id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\ManyToOne(targetEntity=Person::class)
|
||||||
|
* @ORM\JoinColumn(nullable=false)
|
||||||
|
*/
|
||||||
|
private Person $person;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Column(type="datetime_immutable")
|
||||||
|
*/
|
||||||
|
private ?DateTimeImmutable $startDate = null;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->comment = new CommentEmbeddable();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAddress(): ?Address
|
||||||
|
{
|
||||||
|
return $this->address;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getComment(): CommentEmbeddable
|
||||||
|
{
|
||||||
|
return $this->comment;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getEndDate(): ?DateTimeImmutable
|
||||||
|
{
|
||||||
|
return $this->endDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getHostPerson(): ?Person
|
||||||
|
{
|
||||||
|
return $this->hostPerson;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getHostThirdParty(): ?ThirdParty
|
||||||
|
{
|
||||||
|
return $this->hostThirdParty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getId(): ?int
|
||||||
|
{
|
||||||
|
return $this->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPerson(): ?Person
|
||||||
|
{
|
||||||
|
return $this->person;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getStartDate(): ?DateTimeImmutable
|
||||||
|
{
|
||||||
|
return $this->startDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setAddress(?Address $address): self
|
||||||
|
{
|
||||||
|
$this->address = $address;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setComment(CommentEmbeddable $comment): self
|
||||||
|
{
|
||||||
|
$this->comment = $comment;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setEndDate(?DateTimeImmutable $endDate): self
|
||||||
|
{
|
||||||
|
$this->endDate = $endDate;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setHostPerson(?Person $hostPerson): self
|
||||||
|
{
|
||||||
|
$this->hostPerson = $hostPerson;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setHostThirdParty(?ThirdParty $hostThirdParty): self
|
||||||
|
{
|
||||||
|
$this->hostThirdParty = $hostThirdParty;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setPerson(?Person $person): self
|
||||||
|
{
|
||||||
|
$this->person = $person;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setStartDate(DateTimeImmutable $startDate): self
|
||||||
|
{
|
||||||
|
$this->startDate = $startDate;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,73 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Chill\MainBundle\Form\Type;
|
||||||
|
|
||||||
|
use Chill\MainBundle\Entity\ResidentialAddress;
|
||||||
|
use Chill\PersonBundle\Form\Type\PickPersonDynamicType;
|
||||||
|
use Chill\ThirdPartyBundle\Form\Type\PickThirdpartyDynamicType;
|
||||||
|
use Symfony\Component\Form\AbstractType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\DateType;
|
||||||
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
|
||||||
|
final class ResidentialAddressType extends AbstractType
|
||||||
|
{
|
||||||
|
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||||
|
{
|
||||||
|
$builder
|
||||||
|
->add('startDate', DateType::class, [
|
||||||
|
'required' => true,
|
||||||
|
'input' => 'datetime_immutable',
|
||||||
|
'widget' => 'single_text',
|
||||||
|
])
|
||||||
|
->add('endDate', DateType::class, [
|
||||||
|
'required' => false,
|
||||||
|
'input' => 'datetime_immutable',
|
||||||
|
'widget' => 'single_text',
|
||||||
|
])
|
||||||
|
->add('comment', CommentType::class, [
|
||||||
|
'required' => false,
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ('person' === $options['kind']) {
|
||||||
|
$builder
|
||||||
|
->add('hostPerson', PickPersonDynamicType::class, [
|
||||||
|
'label' => 'Person',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('thirdparty' === $options['kind']) {
|
||||||
|
$builder
|
||||||
|
->add('hostThirdParty', PickThirdpartyDynamicType::class, [
|
||||||
|
'label' => 'Third party',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('address' === $options['kind']) {
|
||||||
|
$builder
|
||||||
|
->add('address', PickAddressType::class, [
|
||||||
|
'required' => false,
|
||||||
|
'label' => 'Address',
|
||||||
|
'use_valid_from' => false,
|
||||||
|
'use_valid_to' => false,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function configureOptions(OptionsResolver $resolver)
|
||||||
|
{
|
||||||
|
$resolver->setDefaults([
|
||||||
|
'data_class' => ResidentialAddress::class,
|
||||||
|
'kind' => null,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
@ -193,6 +193,29 @@ final class NotificationRepository implements ObjectRepository
|
|||||||
return $this->repository->findOneBy($criteria, $orderBy);
|
return $this->repository->findOneBy($criteria, $orderBy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array|Notification[]
|
||||||
|
*/
|
||||||
|
public function findUnreadByUser(User $user, int $limit = 20, int $offset = 0): array
|
||||||
|
{
|
||||||
|
$rsm = new Query\ResultSetMappingBuilder($this->em);
|
||||||
|
$rsm->addRootEntityFromClassMetadata(Notification::class, 'cmn');
|
||||||
|
|
||||||
|
$sql = 'SELECT ' . $rsm->generateSelectClause(['cmn' => 'cmn']) . ' ' .
|
||||||
|
'FROM chill_main_notification cmn ' .
|
||||||
|
'WHERE ' .
|
||||||
|
'EXISTS (select 1 FROM chill_main_notification_addresses_unread cmnau WHERE cmnau.user_id = :userId and cmnau.notification_id = cmn.id) ' .
|
||||||
|
'ORDER BY cmn.date DESC ' .
|
||||||
|
'LIMIT :limit OFFSET :offset';
|
||||||
|
|
||||||
|
$nq = $this->em->createNativeQuery($sql, $rsm)
|
||||||
|
->setParameter('userId', $user->getId())
|
||||||
|
->setParameter('limit', $limit)
|
||||||
|
->setParameter('offset', $offset);
|
||||||
|
|
||||||
|
return $nq->getResult();
|
||||||
|
}
|
||||||
|
|
||||||
public function getClassName()
|
public function getClassName()
|
||||||
{
|
{
|
||||||
return Notification::class;
|
return Notification::class;
|
||||||
|
@ -0,0 +1,59 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Chill\MainBundle\Repository;
|
||||||
|
|
||||||
|
use Chill\MainBundle\Entity\ResidentialAddress;
|
||||||
|
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||||
|
use Doctrine\Persistence\ManagerRegistry;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @method ResidentialAddress|null find($id, $lockMode = null, $lockVersion = null)
|
||||||
|
* @method ResidentialAddress|null findOneBy(array $criteria, array $orderBy = null)
|
||||||
|
* @method ResidentialAddress[] findAll()
|
||||||
|
* @method ResidentialAddress[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
|
||||||
|
*/
|
||||||
|
class ResidentialAddressRepository extends ServiceEntityRepository
|
||||||
|
{
|
||||||
|
public function __construct(ManagerRegistry $registry)
|
||||||
|
{
|
||||||
|
parent::__construct($registry, ResidentialAddress::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
// /**
|
||||||
|
// * @return ResidentialAddress[] Returns an array of ResidentialAddress objects
|
||||||
|
// */
|
||||||
|
/*
|
||||||
|
public function findByExampleField($value)
|
||||||
|
{
|
||||||
|
return $this->createQueryBuilder('r')
|
||||||
|
->andWhere('r.exampleField = :val')
|
||||||
|
->setParameter('val', $value)
|
||||||
|
->orderBy('r.id', 'ASC')
|
||||||
|
->setMaxResults(10)
|
||||||
|
->getQuery()
|
||||||
|
->getResult()
|
||||||
|
;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
public function findOneBySomeField($value): ?ResidentialAddress
|
||||||
|
{
|
||||||
|
return $this->createQueryBuilder('r')
|
||||||
|
->andWhere('r.exampleField = :val')
|
||||||
|
->setParameter('val', $value)
|
||||||
|
->getQuery()
|
||||||
|
->getOneOrNullResult()
|
||||||
|
;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
@ -12,6 +12,7 @@
|
|||||||
display: block;
|
display: block;
|
||||||
top: calc(50% - 7px);
|
top: calc(50% - 7px);
|
||||||
right: 10px;
|
right: 10px;
|
||||||
|
line-height: 11px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,14 +63,19 @@ ul.list-suggest {
|
|||||||
& span:hover {
|
& span:hover {
|
||||||
color: $chill-l-gray;
|
color: $chill-l-gray;
|
||||||
}
|
}
|
||||||
|
.person-text {
|
||||||
|
span {
|
||||||
|
padding-left: 0px;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&.remove-items {
|
&.remove-items {
|
||||||
li {
|
li {
|
||||||
position: relative;
|
position: relative;
|
||||||
span {
|
& > span {
|
||||||
display: block;
|
display: block;
|
||||||
padding-right: .75rem;
|
padding-right: 1.75rem;
|
||||||
@include remove_link;
|
@include remove_link;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@ $chill-theme-buttons: (
|
|||||||
"cancel": $gray-300,
|
"cancel": $gray-300,
|
||||||
"choose": $gray-300,
|
"choose": $gray-300,
|
||||||
"notify": $chill-blue,
|
"notify": $chill-blue,
|
||||||
|
"search": $gray-300,
|
||||||
"unlink": $chill-red,
|
"unlink": $chill-red,
|
||||||
"tpchild": $chill-pink,
|
"tpchild": $chill-pink,
|
||||||
);
|
);
|
||||||
@ -80,6 +81,7 @@ $chill-theme-buttons: (
|
|||||||
&.btn-notify::before,
|
&.btn-notify::before,
|
||||||
&.btn-tpchild::before,
|
&.btn-tpchild::before,
|
||||||
&.btn-download::before,
|
&.btn-download::before,
|
||||||
|
&.btn-search::before,
|
||||||
&.btn-cancel::before {
|
&.btn-cancel::before {
|
||||||
font: normal normal normal 14px/1 ForkAwesome;
|
font: normal normal normal 14px/1 ForkAwesome;
|
||||||
margin-right: 0.5em;
|
margin-right: 0.5em;
|
||||||
@ -108,6 +110,7 @@ $chill-theme-buttons: (
|
|||||||
&.btn-notify::before { content: "\f1d8"; } // fa-paper-plane
|
&.btn-notify::before { content: "\f1d8"; } // fa-paper-plane
|
||||||
&.btn-tpchild::before { content: "\f007"; } // fa-user
|
&.btn-tpchild::before { content: "\f007"; } // fa-user
|
||||||
&.btn-download::before { content: "\f019"; } // fa-download
|
&.btn-download::before { content: "\f019"; } // fa-download
|
||||||
|
&.btn-search::before { content: "\f002"; } // fa-search
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -133,3 +136,18 @@ $chill-theme-buttons: (
|
|||||||
.btn-sm, .btn-group-sm > .btn {
|
.btn-sm, .btn-group-sm > .btn {
|
||||||
min-width: 36px;
|
min-width: 36px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Homepage special fast action buttons
|
||||||
|
div.sticky-buttons {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 3em;
|
||||||
|
right: 2em;
|
||||||
|
.btn-circle {
|
||||||
|
width: 50px; height: 50px;
|
||||||
|
border-radius: 50%;
|
||||||
|
text-align: center;
|
||||||
|
padding: 0.45rem 0.7rem;
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -19,6 +19,12 @@ function loadDynamicPicker(element) {
|
|||||||
input = element.querySelector('[data-input-uniqid="'+ el.dataset.uniqid +'"]'),
|
input = element.querySelector('[data-input-uniqid="'+ el.dataset.uniqid +'"]'),
|
||||||
picked = (isMultiple) ? (JSON.parse(input.value)) : ((input.value === '[]') ? (null) : ([JSON.parse(input.value)]));
|
picked = (isMultiple) ? (JSON.parse(input.value)) : ((input.value === '[]') ? (null) : ([JSON.parse(input.value)]));
|
||||||
|
|
||||||
|
if (!isMultiple) {
|
||||||
|
if (input.value === '[]'){
|
||||||
|
input.value = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const app = createApp({
|
const app = createApp({
|
||||||
template: '<pick-entity ' +
|
template: '<pick-entity ' +
|
||||||
':multiple="multiple" ' +
|
':multiple="multiple" ' +
|
||||||
|
@ -0,0 +1,16 @@
|
|||||||
|
import { createApp } from 'vue';
|
||||||
|
import { _createI18n } from 'ChillMainAssets/vuejs/_js/i18n';
|
||||||
|
import { appMessages } from 'ChillMainAssets/vuejs/HomepageWidget/js/i18n';
|
||||||
|
import { store } from 'ChillMainAssets/vuejs/HomepageWidget/js/store';
|
||||||
|
import App from 'ChillMainAssets/vuejs/HomepageWidget/App';
|
||||||
|
|
||||||
|
const i18n = _createI18n(appMessages);
|
||||||
|
|
||||||
|
const app = createApp({
|
||||||
|
template: `<app></app>`,
|
||||||
|
})
|
||||||
|
.use(store)
|
||||||
|
.use(i18n)
|
||||||
|
.component('app', App)
|
||||||
|
.mount('#homepage_widget')
|
||||||
|
;
|
@ -0,0 +1,140 @@
|
|||||||
|
<template>
|
||||||
|
|
||||||
|
<h2>{{ $t('main_title') }}</h2>
|
||||||
|
|
||||||
|
<ul class="nav nav-tabs">
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link"
|
||||||
|
:class="{'active': activeTab === 'MyCustoms'}"
|
||||||
|
@click="selectTab('MyCustoms')">
|
||||||
|
<i class="fa fa-dashboard"></i>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link"
|
||||||
|
:class="{'active': activeTab === 'MyNotifications'}"
|
||||||
|
@click="selectTab('MyNotifications')">
|
||||||
|
{{ $t('my_notifications.tab') }}
|
||||||
|
<tab-counter :count="state.notifications.count"></tab-counter>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link"
|
||||||
|
:class="{'active': activeTab === 'MyAccompanyingCourses'}"
|
||||||
|
@click="selectTab('MyAccompanyingCourses')">
|
||||||
|
{{ $t('my_accompanying_courses.tab') }}
|
||||||
|
<tab-counter :count="state.accompanyingCourses.count"></tab-counter>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link"
|
||||||
|
:class="{'active': activeTab === 'MyWorks'}"
|
||||||
|
@click="selectTab('MyWorks')">
|
||||||
|
{{ $t('my_works.tab') }}
|
||||||
|
<tab-counter :count="state.works.count"></tab-counter>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link"
|
||||||
|
:class="{'active': activeTab === 'MyEvaluations'}"
|
||||||
|
@click="selectTab('MyEvaluations')">
|
||||||
|
{{ $t('my_evaluations.tab') }}
|
||||||
|
<tab-counter :count="state.evaluations.count"></tab-counter>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link"
|
||||||
|
:class="{'active': activeTab === 'MyTasks'}"
|
||||||
|
@click="selectTab('MyTasks')">
|
||||||
|
{{ $t('my_tasks.tab') }}
|
||||||
|
<tab-counter :count="state.tasks.warning.count"></tab-counter>
|
||||||
|
<tab-counter :count="state.tasks.alert.count"></tab-counter>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item loading ms-auto py-2" v-if="loading">
|
||||||
|
<i class="fa fa-circle-o-notch fa-spin fa-lg text-chill-gray" :title="$t('loading')"></i>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<div class="my-4">
|
||||||
|
<my-customs
|
||||||
|
v-if="activeTab === 'MyCustoms'">
|
||||||
|
</my-customs>
|
||||||
|
<my-works
|
||||||
|
v-else-if="activeTab === 'MyWorks'">
|
||||||
|
</my-works>
|
||||||
|
<my-evaluations
|
||||||
|
v-else-if="activeTab === 'MyEvaluations'">
|
||||||
|
</my-evaluations>
|
||||||
|
<my-tasks
|
||||||
|
v-else-if="activeTab === 'MyTasks'">
|
||||||
|
</my-tasks>
|
||||||
|
<my-accompanying-courses
|
||||||
|
v-else-if="activeTab === 'MyAccompanyingCourses'">
|
||||||
|
</my-accompanying-courses>
|
||||||
|
<my-notifications
|
||||||
|
v-else-if="activeTab === 'MyNotifications'">
|
||||||
|
</my-notifications>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import MyCustoms from './MyCustoms';
|
||||||
|
import MyWorks from './MyWorks';
|
||||||
|
import MyEvaluations from './MyEvaluations';
|
||||||
|
import MyTasks from './MyTasks';
|
||||||
|
import MyAccompanyingCourses from './MyAccompanyingCourses';
|
||||||
|
import MyNotifications from './MyNotifications';
|
||||||
|
import TabCounter from './TabCounter';
|
||||||
|
import { mapState } from "vuex";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "App",
|
||||||
|
components: {
|
||||||
|
MyCustoms,
|
||||||
|
MyWorks,
|
||||||
|
MyEvaluations,
|
||||||
|
MyTasks,
|
||||||
|
MyAccompanyingCourses,
|
||||||
|
MyNotifications,
|
||||||
|
TabCounter,
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
activeTab: 'MyCustoms'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapState([
|
||||||
|
'loading',
|
||||||
|
]),
|
||||||
|
// just to see all in devtool :
|
||||||
|
...mapState({
|
||||||
|
state: (state) => state,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
selectTab(tab) {
|
||||||
|
this.$store.dispatch('getByTab', { tab: tab });
|
||||||
|
this.activeTab = tab;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
for (const m of [
|
||||||
|
'MyNotifications',
|
||||||
|
'MyAccompanyingCourses',
|
||||||
|
'MyWorks',
|
||||||
|
'MyEvaluations',
|
||||||
|
'MyTasks',
|
||||||
|
]) {
|
||||||
|
this.$store.dispatch('getByTab', { tab: m, param: "countOnly=1" });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
a.nav-link {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
</style>
|
@ -0,0 +1,60 @@
|
|||||||
|
<template>
|
||||||
|
<div class="alert alert-light">{{ $t('my_accompanying_courses.description') }}</div>
|
||||||
|
<span v-if="noResults" class="chill-no-data-statement">{{ $t('no_data') }}</span>
|
||||||
|
<tab-table v-else>
|
||||||
|
<template v-slot:thead>
|
||||||
|
<th scope="col">id</th>
|
||||||
|
<th scope="col">Ouvert le</th>
|
||||||
|
<th scope="col">Usagers concernés</th>
|
||||||
|
<th scope="col"></th>
|
||||||
|
</template>
|
||||||
|
<template v-slot:tbody>
|
||||||
|
<tr v-for="(c, i) in accompanyingCourses.results" :key="`course-${i}`">
|
||||||
|
<td>{{ c.id}}</td>
|
||||||
|
<td>{{ $d(c.openingDate.datetime, 'long') }}</td>
|
||||||
|
<td>{{ c.participations.length }}</td>
|
||||||
|
<td>
|
||||||
|
<a class="btn btn-sm btn-show" :href="getUrl(c)">
|
||||||
|
{{ $t('show_entity', { entity: $t('the_course') }) }}
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</template>
|
||||||
|
</tab-table>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { mapState, mapGetters } from "vuex";
|
||||||
|
import TabTable from "./TabTable";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "MyAccompanyingCourses",
|
||||||
|
components: {
|
||||||
|
TabTable
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapState([
|
||||||
|
'accompanyingCourses',
|
||||||
|
]),
|
||||||
|
...mapGetters([
|
||||||
|
'isAccompanyingCoursesLoaded',
|
||||||
|
]),
|
||||||
|
noResults() {
|
||||||
|
if (!this.isAccompanyingCoursesLoaded) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return this.accompanyingCourses.count === 0;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getUrl(c) {
|
||||||
|
return `/fr/parcours/${c.id}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
@ -0,0 +1,77 @@
|
|||||||
|
<template>
|
||||||
|
<span v-if="noResults" class="chill-no-data-statement">{{ $t('no_dashboard') }}</span>
|
||||||
|
<div v-else id="dashboards" class="row g-3" data-masonry='{"percentPosition": true }'>
|
||||||
|
|
||||||
|
<div class="mbloc col col-sm-6 col-lg-4">
|
||||||
|
<div class="custom1">
|
||||||
|
<ul class="list-unstyled">
|
||||||
|
<li v-if="counter.notifications > 0">
|
||||||
|
<b>{{ counter.notifications }}</b> {{ $t('counter.unread_notifications') }}
|
||||||
|
</li>
|
||||||
|
<li v-if="counter.accompanyingCourses > 0">
|
||||||
|
<b>{{ counter.accompanyingCourses }}</b> {{ $t('counter.assignated_courses') }}
|
||||||
|
</li>
|
||||||
|
<li v-if="counter.works > 0">
|
||||||
|
<b>{{ counter.works }}</b> {{ $t('counter.assignated_actions') }}
|
||||||
|
</li>
|
||||||
|
<li v-if="counter.evaluations > 0">
|
||||||
|
<b>{{ counter.evaluations }}</b> {{ $t('counter.assignated_evaluations') }}
|
||||||
|
</li>
|
||||||
|
<li v-if="counter.tasksAlert > 0">
|
||||||
|
<b>{{ counter.tasksAlert }}</b> {{ $t('counter.alert_tasks') }}
|
||||||
|
</li>
|
||||||
|
<li v-if="counter.tasksWarning > 0">
|
||||||
|
<b>{{ counter.tasksWarning }}</b> {{ $t('counter.warning_tasks') }}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
<div class="mbloc col col-sm-6 col-lg-4">
|
||||||
|
<div class="custom2">
|
||||||
|
Mon dashboard personnalisé
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mbloc col col-sm-6 col-lg-4">
|
||||||
|
<div class="custom3">
|
||||||
|
Mon dashboard personnalisé
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mbloc col col-sm-6 col-lg-4">
|
||||||
|
<div class="custom4">
|
||||||
|
Mon dashboard personnalisé
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
-->
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { mapGetters } from "vuex";
|
||||||
|
import Masonry from 'masonry-layout/masonry';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "MyCustoms",
|
||||||
|
computed: {
|
||||||
|
...mapGetters(['counter']),
|
||||||
|
noResults() {
|
||||||
|
return false
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
const elem = document.querySelector('#dashboards');
|
||||||
|
const masonry = new Masonry(elem, {});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
div.custom4,
|
||||||
|
div.custom3,
|
||||||
|
div.custom2 {
|
||||||
|
font-style: italic;
|
||||||
|
color: var(--bs-chill-gray);
|
||||||
|
}
|
||||||
|
</style>
|
@ -0,0 +1,57 @@
|
|||||||
|
<template>
|
||||||
|
<div class="alert alert-light">{{ $t('my_evaluations.description') }}</div>
|
||||||
|
<span v-if="noResults" class="chill-no-data-statement">{{ $t('no_data') }}</span>
|
||||||
|
<tab-table v-else>
|
||||||
|
<template v-slot:thead>
|
||||||
|
<th scope="col">id</th>
|
||||||
|
<th scope="col"></th>
|
||||||
|
</template>
|
||||||
|
<template v-slot:tbody>
|
||||||
|
<tr v-for="(e, i) in evaluations.results" :key="`evaluation-${i}`">
|
||||||
|
<td>{{ e.id}}</td>
|
||||||
|
<td>
|
||||||
|
<a class="btn btn-sm btn-show" :href="getUrl(e)">
|
||||||
|
{{ $t('show_entity', { entity: $t('the_evaluation') }) }}
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</template>
|
||||||
|
</tab-table>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { mapState, mapGetters } from "vuex";
|
||||||
|
import TabTable from "./TabTable";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "MyEvaluations",
|
||||||
|
components: {
|
||||||
|
TabTable
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapState([
|
||||||
|
'evaluations',
|
||||||
|
]),
|
||||||
|
...mapGetters([
|
||||||
|
'isEvaluationsLoaded',
|
||||||
|
]),
|
||||||
|
noResults() {
|
||||||
|
if (!this.isEvaluationsLoaded) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return this.evaluations.count === 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getUrl(e) {
|
||||||
|
let anchor = '#evaluations';
|
||||||
|
return `/fr/person/accompanying-period/work/${e.id}/edit${anchor}`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
@ -0,0 +1,96 @@
|
|||||||
|
<template>
|
||||||
|
<div class="alert alert-light">{{ $t('my_notifications.description') }}</div>
|
||||||
|
<span v-if="noResults" class="chill-no-data-statement">{{ $t('no_data') }}</span>
|
||||||
|
<tab-table v-else>
|
||||||
|
<template v-slot:thead>
|
||||||
|
<th scope="col">{{ $t('Date') }}</th>
|
||||||
|
<th scope="col">{{ $t('Subject') }}</th>
|
||||||
|
<th scope="col">{{ $t('From') }}</th>
|
||||||
|
<th scope="col"></th>
|
||||||
|
</template>
|
||||||
|
<template v-slot:tbody>
|
||||||
|
<tr v-for="(n, i) in notifications.results" :key="`notify-${i}`">
|
||||||
|
<td>{{ $d(n.date.datetime, 'long') }}</td>
|
||||||
|
<td>
|
||||||
|
<span class="unread">
|
||||||
|
<i class="fa fa-envelope-o"></i>
|
||||||
|
<a :href="getNotificationUrl(n)">{{ n.title }}</a>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>{{ n.sender.text }}</td>
|
||||||
|
<td>
|
||||||
|
<a class="btn btn-sm btn-show"
|
||||||
|
:href="getEntityUrl(n)">
|
||||||
|
{{ $t('show_entity', { entity: getEntityName(n) }) }}
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</template>
|
||||||
|
</tab-table>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { mapState, mapGetters } from "vuex";
|
||||||
|
import TabTable from "./TabTable";
|
||||||
|
import { appMessages } from 'ChillMainAssets/vuejs/HomepageWidget/js/i18n';
|
||||||
|
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "MyNotifications",
|
||||||
|
components: {
|
||||||
|
TabTable
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapState([
|
||||||
|
'notifications',
|
||||||
|
]),
|
||||||
|
...mapGetters([
|
||||||
|
'isNotificationsLoaded',
|
||||||
|
]),
|
||||||
|
noResults() {
|
||||||
|
if (!this.isNotificationsLoaded) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return this.notifications.count === 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getNotificationUrl(n) {
|
||||||
|
return `/fr/notification/${n.id}/show`
|
||||||
|
},
|
||||||
|
getEntityName(n) {
|
||||||
|
switch (n.relatedEntityClass) {
|
||||||
|
case 'Chill\\ActivityBundle\\Entity\\Activity':
|
||||||
|
return appMessages.fr.the_activity;
|
||||||
|
case 'Chill\\PersonBundle\\Entity\\AccompanyingPeriod':
|
||||||
|
return appMessages.fr.the_course;
|
||||||
|
default:
|
||||||
|
throw 'notification type unknown';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getEntityUrl(n) {
|
||||||
|
switch (n.relatedEntityClass) {
|
||||||
|
case 'Chill\\ActivityBundle\\Entity\\Activity':
|
||||||
|
return `/fr/activity/${n.relatedEntityId}/show`
|
||||||
|
case 'Chill\\PersonBundle\\Entity\\AccompanyingPeriod':
|
||||||
|
return `/fr/parcours/${n.relatedEntityId}`
|
||||||
|
default:
|
||||||
|
throw 'notification type unknown';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
span.unread {
|
||||||
|
font-weight: bold;
|
||||||
|
i {
|
||||||
|
margin-right: 0.5em;
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
text-decoration: unset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -0,0 +1,85 @@
|
|||||||
|
<template>
|
||||||
|
|
||||||
|
<div class="alert alert-light">{{ $t('my_tasks.description_alert') }}</div>
|
||||||
|
<span v-if="noResultsWarning" class="chill-no-data-statement">{{ $t('no_data') }}</span>
|
||||||
|
<tab-table v-else>
|
||||||
|
<template v-slot:thead>
|
||||||
|
<th scope="col">id</th>
|
||||||
|
<th scope="col"></th>
|
||||||
|
</template>
|
||||||
|
<template v-slot:tbody>
|
||||||
|
<tr v-for="(t, i) in tasks.warning" :key="`task-warning-${i}`">
|
||||||
|
<td>{{ t.id}}</td>
|
||||||
|
<td>
|
||||||
|
<a class="btn btn-sm btn-show" :href="getUrl(t)">
|
||||||
|
{{ $t('show_entity', { entity: $t('the_task') }) }}
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</template>
|
||||||
|
</tab-table>
|
||||||
|
|
||||||
|
<div class="alert alert-light">{{ $t('my_tasks.description_warning') }}</div>
|
||||||
|
<span v-if="noResultsAlert" class="chill-no-data-statement">{{ $t('no_data') }}</span>
|
||||||
|
<tab-table v-else>
|
||||||
|
<template v-slot:thead>
|
||||||
|
<th scope="col">id</th>
|
||||||
|
<th scope="col"></th>
|
||||||
|
</template>
|
||||||
|
<template v-slot:tbody>
|
||||||
|
<tr v-for="(t, i) in tasks.alert" :key="`task-alert-${i}`">
|
||||||
|
<td>{{ t.id}}</td>
|
||||||
|
<td>
|
||||||
|
<a class="btn btn-sm btn-show" :href="getUrl(t)">
|
||||||
|
{{ $t('show_entity', { entity: $t('the_task') }) }}
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</template>
|
||||||
|
</tab-table>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { mapState, mapGetters } from "vuex";
|
||||||
|
import TabTable from "./TabTable";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "MyTasks",
|
||||||
|
components: {
|
||||||
|
TabTable
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapState([
|
||||||
|
'tasks',
|
||||||
|
]),
|
||||||
|
...mapGetters([
|
||||||
|
'isTasksWarningLoaded',
|
||||||
|
'isTasksAlertLoaded',
|
||||||
|
]),
|
||||||
|
noResultsAlert() {
|
||||||
|
if (!this.isTasksAlertLoaded) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return this.tasks.alert.count === 0;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
noResultsWarning() {
|
||||||
|
if (!this.isTasksWarningLoaded) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return this.tasks.warning.count === 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getUrl(t) {
|
||||||
|
return `/fr/task/single-task/${t.id}/show`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
@ -0,0 +1,79 @@
|
|||||||
|
<template>
|
||||||
|
<div class="accompanying_course_work">
|
||||||
|
<div class="alert alert-light">{{ $t('my_works.description') }}</div>
|
||||||
|
<span v-if="noResults" class="chill-no-data-statement">{{ $t('no_data') }}</span>
|
||||||
|
<tab-table v-else>
|
||||||
|
<template v-slot:thead>
|
||||||
|
<th scope="col">{{ $t('StartDate') }}</th>
|
||||||
|
<th scope="col">{{ $t('SocialAction') }}</th>
|
||||||
|
<th scope="col"></th>
|
||||||
|
</template>
|
||||||
|
<template v-slot:tbody>
|
||||||
|
<tr v-for="(w, i) in works.results" :key="`works-${i}`">
|
||||||
|
<td>{{ $d(w.startDate.datetime, 'short') }}</td>
|
||||||
|
<td>
|
||||||
|
<h4 class="badge-title">
|
||||||
|
<span class="title_label"></span>
|
||||||
|
<span class="title_action">
|
||||||
|
{{ w.socialAction.text }}
|
||||||
|
</span>
|
||||||
|
</h4>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<div class="btn-group" role="group" aria-label="Actions">
|
||||||
|
<a class="btn btn-sm btn-update" :href="getUrl(w)">
|
||||||
|
{{ $t('show_entity', { entity: $t('the_action') }) }}
|
||||||
|
</a>
|
||||||
|
<a class="btn btn-sm btn-show" :href="getUrl(w.accompanyingPeriod)">
|
||||||
|
{{ $t('show_entity', { entity: $t('the_course') }) }}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</template>
|
||||||
|
</tab-table>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { mapState, mapGetters } from "vuex";
|
||||||
|
import TabTable from "./TabTable";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "MyWorks",
|
||||||
|
components: {
|
||||||
|
TabTable
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapState([
|
||||||
|
'works',
|
||||||
|
]),
|
||||||
|
...mapGetters([
|
||||||
|
'isWorksLoaded',
|
||||||
|
]),
|
||||||
|
noResults() {
|
||||||
|
if (!this.isWorksLoaded) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return this.works.count === 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getUrl(e) {
|
||||||
|
switch (e.type) {
|
||||||
|
case 'accompanying_period_work':
|
||||||
|
return `/fr/person/accompanying-period/work/${e.id}/edit`
|
||||||
|
case 'accompanying_period':
|
||||||
|
return `/fr/parcours/${e.id}`
|
||||||
|
default:
|
||||||
|
throw 'entity type unknown';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
@ -0,0 +1,18 @@
|
|||||||
|
<template>
|
||||||
|
<span v-if="isCounterAvailable"
|
||||||
|
class="badge rounded-pill bg-danger counter">
|
||||||
|
{{ count }}
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "TabCounter",
|
||||||
|
props: ['count'],
|
||||||
|
computed: {
|
||||||
|
isCounterAvailable() {
|
||||||
|
return (typeof this.count !== 'undefined' && this.count > 0 )
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
@ -0,0 +1,21 @@
|
|||||||
|
<template>
|
||||||
|
<table class="table table-striped table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<slot name="thead"></slot>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<slot name="tbody"></slot>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "TabTable",
|
||||||
|
props: []
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
@ -0,0 +1,54 @@
|
|||||||
|
const appMessages = {
|
||||||
|
fr: {
|
||||||
|
main_title: "Vue d'ensemble",
|
||||||
|
my_works: {
|
||||||
|
tab: "Mes actions",
|
||||||
|
description: "Liste des actions d'accompagnement dont je suis référent et qui arrivent à échéance.",
|
||||||
|
},
|
||||||
|
my_evaluations: {
|
||||||
|
tab: "Mes évaluations",
|
||||||
|
description: "Liste des évaluations dont je suis référent et qui arrivent à échéance.",
|
||||||
|
},
|
||||||
|
my_tasks: {
|
||||||
|
tab: "Mes tâches",
|
||||||
|
description_alert: "Liste des tâches auxquelles je suis assigné et dont la date de rappel est dépassée.",
|
||||||
|
description_warning: "Liste des tâches auxquelles je suis assigné et dont la date d'échéance est dépassée.",
|
||||||
|
},
|
||||||
|
my_accompanying_courses: {
|
||||||
|
tab: "Mes parcours",
|
||||||
|
description: "Liste des parcours d'accompagnement que l'on vient de m'attribuer.",
|
||||||
|
},
|
||||||
|
my_notifications: {
|
||||||
|
tab: "Mes notifications",
|
||||||
|
description: "Liste des notifications reçues et non lues.",
|
||||||
|
},
|
||||||
|
Date: "Date",
|
||||||
|
From: "De",
|
||||||
|
Subject: "Objet",
|
||||||
|
Entity: "Associé à",
|
||||||
|
show_entity: "Voir {entity}",
|
||||||
|
the_activity: "l'échange",
|
||||||
|
the_course: "le parcours",
|
||||||
|
the_action: "l'action",
|
||||||
|
the_evaluation: "l'évaluation",
|
||||||
|
the_task: "la tâche",
|
||||||
|
StartDate: "Date d'ouverture",
|
||||||
|
SocialAction: "Action d'accompagnement",
|
||||||
|
no_data: "Aucun résultats",
|
||||||
|
no_dashboard: "Pas de tableaux de bord",
|
||||||
|
counter: {
|
||||||
|
unread_notifications: "notifications non lues",
|
||||||
|
assignated_courses: "parcours récents assignés",
|
||||||
|
assignated_actions: "actions assignées",
|
||||||
|
assignated_evaluations: "évaluations assignées",
|
||||||
|
alert_tasks: "tâches en rappel",
|
||||||
|
warning_tasks: "tâches à échéances",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Object.assign(appMessages.fr);
|
||||||
|
|
||||||
|
export {
|
||||||
|
appMessages
|
||||||
|
};
|
@ -0,0 +1,200 @@
|
|||||||
|
import 'es6-promise/auto';
|
||||||
|
import { createStore } from 'vuex';
|
||||||
|
import { makeFetch } from "ChillMainAssets/lib/api/apiMethods";
|
||||||
|
import MyCustoms from "../MyCustoms";
|
||||||
|
import MyWorks from "../MyWorks";
|
||||||
|
import MyEvaluations from "../MyEvaluations";
|
||||||
|
import MyTasks from "../MyTasks";
|
||||||
|
import MyAccompanyingCourses from "../MyAccompanyingCourses";
|
||||||
|
import MyNotifications from "../MyNotifications";
|
||||||
|
|
||||||
|
const debug = process.env.NODE_ENV !== 'production';
|
||||||
|
|
||||||
|
const isEmpty = (obj) => {
|
||||||
|
return obj
|
||||||
|
&& Object.keys(obj).length <= 1
|
||||||
|
&& Object.getPrototypeOf(obj) === Object.prototype;
|
||||||
|
};
|
||||||
|
|
||||||
|
const store = createStore({
|
||||||
|
strict: debug,
|
||||||
|
state: {
|
||||||
|
works: {},
|
||||||
|
evaluations: {},
|
||||||
|
tasks: {
|
||||||
|
warning: {},
|
||||||
|
alert: {}
|
||||||
|
},
|
||||||
|
accompanyingCourses: {},
|
||||||
|
notifications: {},
|
||||||
|
errorMsg: [],
|
||||||
|
loading: false
|
||||||
|
},
|
||||||
|
getters: {
|
||||||
|
isWorksLoaded(state) {
|
||||||
|
return !isEmpty(state.works);
|
||||||
|
},
|
||||||
|
isEvaluationsLoaded(state) {
|
||||||
|
return !isEmpty(state.evaluations);
|
||||||
|
},
|
||||||
|
isTasksWarningLoaded(state) {
|
||||||
|
return !isEmpty(state.tasks.warning);
|
||||||
|
},
|
||||||
|
isTasksAlertLoaded(state) {
|
||||||
|
return !isEmpty(state.tasks.alert);
|
||||||
|
},
|
||||||
|
isAccompanyingCoursesLoaded(state) {
|
||||||
|
return !isEmpty(state.accompanyingCourses);
|
||||||
|
},
|
||||||
|
isNotificationsLoaded(state) {
|
||||||
|
return !isEmpty(state.notifications);
|
||||||
|
},
|
||||||
|
counter(state) {
|
||||||
|
return {
|
||||||
|
works: state.works.count,
|
||||||
|
evaluations: state.evaluations.count,
|
||||||
|
tasksWarning: state.tasks.warning.count,
|
||||||
|
tasksAlert: state.tasks.alert.count,
|
||||||
|
accompanyingCourses: state.accompanyingCourses.count,
|
||||||
|
notifications: state.notifications.count,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mutations: {
|
||||||
|
addWorks(state, works) {
|
||||||
|
console.log('addWorks', works);
|
||||||
|
state.works = works;
|
||||||
|
},
|
||||||
|
addEvaluations(state, evaluations) {
|
||||||
|
console.log('addEvaluations', evaluations);
|
||||||
|
state.evaluations = evaluations;
|
||||||
|
},
|
||||||
|
addTasksWarning(state, tasks) {
|
||||||
|
console.log('addTasksWarning', tasks);
|
||||||
|
state.tasks.warning = tasks;
|
||||||
|
},
|
||||||
|
addTasksAlert(state, tasks) {
|
||||||
|
console.log('addTasksAlert', tasks);
|
||||||
|
state.tasks.alert = tasks;
|
||||||
|
},
|
||||||
|
addCourses(state, courses) {
|
||||||
|
console.log('addCourses', courses);
|
||||||
|
state.accompanyingCourses = courses;
|
||||||
|
},
|
||||||
|
addNotifications(state, notifications) {
|
||||||
|
console.log('addNotifications', notifications);
|
||||||
|
state.notifications = notifications;
|
||||||
|
},
|
||||||
|
setLoading(state, bool) {
|
||||||
|
state.loading = bool;
|
||||||
|
},
|
||||||
|
catchError(state, error) {
|
||||||
|
state.errorMsg.push(error);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
getByTab({ commit, getters }, { tab, param }) {
|
||||||
|
switch (tab) {
|
||||||
|
case 'MyCustoms':
|
||||||
|
break;
|
||||||
|
case 'MyWorks':
|
||||||
|
if (!getters.isWorksLoaded) {
|
||||||
|
commit('setLoading', true);
|
||||||
|
const url = `/api/1.0/person/accompanying-period/work/my-near-end${'?'+ param}`;
|
||||||
|
makeFetch('GET', url)
|
||||||
|
.then((response) => {
|
||||||
|
commit('addWorks', response);
|
||||||
|
commit('setLoading', false);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
commit('catchError', error);
|
||||||
|
throw error;
|
||||||
|
})
|
||||||
|
;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'MyEvaluations':
|
||||||
|
if (!getters.isEvaluationsLoaded) {
|
||||||
|
commit('setLoading', true);
|
||||||
|
const url = `/api/1.0/person/accompanying-period/work/evaluation/my-near-end${'?'+ param}`;
|
||||||
|
makeFetch('GET', url)
|
||||||
|
.then((response) => {
|
||||||
|
commit('addEvaluations', response);
|
||||||
|
commit('setLoading', false);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
commit('catchError', error);
|
||||||
|
throw error;
|
||||||
|
})
|
||||||
|
;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'MyTasks':
|
||||||
|
if (!(getters.isTasksWarningLoaded && getters.isTasksAlertLoaded)) {
|
||||||
|
commit('setLoading', true);
|
||||||
|
const
|
||||||
|
urlWarning = `/api/1.0/task/single-task/list/my?f[q]=&f[checkboxes][status][]=warning&f[checkboxes][states][]=new&f[checkboxes][states][]=in_progress${'&'+ param}`,
|
||||||
|
urlAlert = `/api/1.0/task/single-task/list/my?f[q]=&f[checkboxes][status][]=alert&f[checkboxes][states][]=new&f[checkboxes][states][]=in_progress${'&'+ param}`
|
||||||
|
;
|
||||||
|
makeFetch('GET', urlWarning)
|
||||||
|
.then((response) => {
|
||||||
|
commit('addTasksWarning', response);
|
||||||
|
commit('setLoading', false);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
commit('catchError', error);
|
||||||
|
throw error;
|
||||||
|
})
|
||||||
|
;
|
||||||
|
makeFetch('GET', urlAlert)
|
||||||
|
.then((response) => {
|
||||||
|
commit('addTasksAlert', response);
|
||||||
|
commit('setLoading', false);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
commit('catchError', error);
|
||||||
|
throw error;
|
||||||
|
})
|
||||||
|
;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'MyAccompanyingCourses':
|
||||||
|
if (!getters.isAccompanyingCoursesLoaded) {
|
||||||
|
commit('setLoading', true);
|
||||||
|
const url = `/api/1.0/person/accompanying-course/list/by-recent-attributions${'?'+ param}`;
|
||||||
|
makeFetch('GET', url)
|
||||||
|
.then((response) => {
|
||||||
|
commit('addCourses', response);
|
||||||
|
commit('setLoading', false);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
commit('catchError', error);
|
||||||
|
throw error;
|
||||||
|
})
|
||||||
|
;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'MyNotifications':
|
||||||
|
if (!getters.isNotificationsLoaded) {
|
||||||
|
commit('setLoading', true);
|
||||||
|
const url = `/api/1.0/main/notification/my/unread${'?'+ param}`;
|
||||||
|
makeFetch('GET', url)
|
||||||
|
.then((response) => {
|
||||||
|
commit('addNotifications', response);
|
||||||
|
commit('setLoading', false);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
commit('catchError', error);
|
||||||
|
throw error;
|
||||||
|
})
|
||||||
|
;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw 'tab '+ tab;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export { store };
|
@ -24,6 +24,11 @@
|
|||||||
{{ $t('user')}}
|
{{ $t('user')}}
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
|
<span v-if="entity.type === 'household'" class="badge rounded-pill bg-user">
|
||||||
|
{{ $t('household')}}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@ -40,7 +45,8 @@ export default {
|
|||||||
company: "Personne morale",
|
company: "Personne morale",
|
||||||
contact: "Personne physique",
|
contact: "Personne physique",
|
||||||
},
|
},
|
||||||
user: 'TMS'
|
user: 'TMS',
|
||||||
|
household: 'Ménage',
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<div class="flex-table workflow" id="workflow-list">
|
<div class="flex-table workflow" id="workflow-list">
|
||||||
<div v-for="(w, i) in workflows" :key="`workflow-${i}`"
|
<div v-for="(w, i) in workflows" :key="`workflow-${i}`"
|
||||||
class="item-bloc">
|
class="item-bloc">
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<div class="item-row col">
|
<div class="item-row col">
|
||||||
<h2>Workflow</h2>
|
<h2>Workflow</h2>
|
||||||
@ -13,11 +13,10 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="breadcrumb">
|
<div class="breadcrumb">
|
||||||
<template v-for="(step, j) in w.steps">
|
<template v-for="(step, j) in w.steps" :key="`step-${j}`">
|
||||||
<span class="mx-2"
|
<span class="mx-2"
|
||||||
:key="`step-${j}`"
|
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
data-bs-trigger="focus hover"
|
data-bs-trigger="focus hover"
|
||||||
data-bs-toggle="popover"
|
data-bs-toggle="popover"
|
||||||
@ -25,7 +24,7 @@
|
|||||||
data-bs-custom-class="workflow-transition"
|
data-bs-custom-class="workflow-transition"
|
||||||
:title="getPopTitle(step)"
|
:title="getPopTitle(step)"
|
||||||
:data-bs-content="getPopContent(step)">
|
:data-bs-content="getPopContent(step)">
|
||||||
|
|
||||||
<i v-if="step.currentStep.name === 'initial'"
|
<i v-if="step.currentStep.name === 'initial'"
|
||||||
class="fa fa-circle me-1 text-chill-yellow">
|
class="fa fa-circle me-1 text-chill-yellow">
|
||||||
</i>
|
</i>
|
||||||
@ -40,7 +39,7 @@
|
|||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="item-row">
|
<div class="item-row">
|
||||||
<div class="item-col flex-grow-1">
|
<div class="item-col flex-grow-1">
|
||||||
<p v-if="isUserSubscribedToStep(w)">
|
<p v-if="isUserSubscribedToStep(w)">
|
||||||
@ -60,7 +59,7 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -61,14 +61,15 @@ const messages = {
|
|||||||
woman: "Née le"
|
woman: "Née le"
|
||||||
},
|
},
|
||||||
deathdate: "Date de décès",
|
deathdate: "Date de décès",
|
||||||
years_old: "ans",
|
|
||||||
household_without_address: "Le ménage de l'usager est sans adresse",
|
household_without_address: "Le ménage de l'usager est sans adresse",
|
||||||
no_data: "Aucune information renseignée",
|
no_data: "Aucune information renseignée",
|
||||||
type: {
|
type: {
|
||||||
thirdparty: "Tiers",
|
thirdparty: "Tiers",
|
||||||
person: "Usager"
|
person: "Usager"
|
||||||
},
|
},
|
||||||
holder: "Titulaire"
|
holder: "Titulaire",
|
||||||
|
years_old: "an | {n} an | {n} ans",
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -0,0 +1,3 @@
|
|||||||
|
<div class="sticky-buttons">
|
||||||
|
{# Override this file to add fast actions buttons #}
|
||||||
|
</div>
|
@ -0,0 +1,15 @@
|
|||||||
|
<div class="col-10 mt-5">
|
||||||
|
|
||||||
|
{# vue component #}
|
||||||
|
<div id="homepage_widget"></div>
|
||||||
|
|
||||||
|
{% include '@ChillMain/Homepage/fast_actions.html.twig' %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% block css %}
|
||||||
|
{{ encore_entry_link_tags('page_homepage_widget') }}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block js %}
|
||||||
|
{{ encore_entry_script_tags('page_homepage_widget') }}
|
||||||
|
{% endblock %}
|
@ -42,6 +42,3 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
></span>
|
></span>
|
||||||
|
|
||||||
{{ encore_entry_script_tags('vue_onthefly') }}
|
|
||||||
{{ encore_entry_link_tags('vue_onthefly') }}
|
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
{{ encore_entry_link_tags('mod_ckeditor5') }}
|
{{ encore_entry_link_tags('mod_ckeditor5') }}
|
||||||
{{ encore_entry_link_tags('chill') }}
|
{{ encore_entry_link_tags('chill') }}
|
||||||
{{ encore_entry_link_tags('mod_blur') }}
|
{{ encore_entry_link_tags('mod_blur') }}
|
||||||
|
{{ encore_entry_link_tags('vue_onthefly') }}
|
||||||
{% block css %}<!-- nothing added to css -->{% endblock %}
|
{% block css %}<!-- nothing added to css -->{% endblock %}
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
@ -59,26 +60,26 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="col-8 main_search">
|
<div class="col-8 main_search">
|
||||||
<h2>{{ 'Search'|trans }}</h2>
|
<h2>{{ 'Search'|trans }}</h2>
|
||||||
|
|
||||||
<form action="{{ path('chill_main_search') }}" method="get">
|
<form action="{{ path('chill_main_search') }}" method="get">
|
||||||
<input class="form-control form-control-lg" name="q" type="search" placeholder="{{ 'Search persons, ...'|trans }}" />
|
<input class="form-control form-control-lg" name="q" type="search" placeholder="{{ 'Search persons, ...'|trans }}" />
|
||||||
<center>
|
<center>
|
||||||
<button type="submit" class="btn btn-lg btn-warning mt-3">
|
<button type="submit" class="btn btn-lg btn-warning mt-3">
|
||||||
<i class="fa fa-fw fa-search"></i> {{ 'Search'|trans }}
|
<i class="fa fa-fw fa-search"></i> {{ 'Search'|trans }}
|
||||||
</button>
|
</button>
|
||||||
<a class="btn btn-lg btn-misc mt-3" href="{{ path('chill_main_advanced_search_list') }}">
|
<a class="btn btn-lg btn-misc mt-3" href="{{ path('chill_main_advanced_search_list') }}">
|
||||||
<i class="fa fa-fw fa-search"></i> {{ 'Advanced search'|trans }}
|
<i class="fa fa-fw fa-search"></i> {{ 'Advanced search'|trans }}
|
||||||
</a>
|
</a>
|
||||||
</center>
|
</center>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-8">
|
|
||||||
<a href="{{ path('chill_crud_aside_activity_new', {'type' : 7, 'duration' : '600', 'note' : 'Pas des remarques' }) }}"><div class="bloc btn btn-success btn-md btn-block">Appel téléphonique</div></a>
|
{# DISABLED {{ chill_widget('homepage', {} ) }} #}
|
||||||
</div>
|
|
||||||
|
{% include '@ChillMain/Homepage/index.html.twig' %}
|
||||||
{{ chill_widget('homepage', {} ) }}
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@ -94,6 +95,7 @@
|
|||||||
{{ encore_entry_script_tags('mod_ckeditor5') }}
|
{{ encore_entry_script_tags('mod_ckeditor5') }}
|
||||||
{{ encore_entry_script_tags('mod_blur') }}
|
{{ encore_entry_script_tags('mod_blur') }}
|
||||||
{{ encore_entry_script_tags('chill') }}
|
{{ encore_entry_script_tags('chill') }}
|
||||||
|
{{ encore_entry_script_tags('vue_onthefly') }}
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
window.addEventListener('DOMContentLoaded', function(e) {
|
window.addEventListener('DOMContentLoaded', function(e) {
|
||||||
|
@ -45,13 +45,15 @@ class SearchUserApiProvider implements SearchApiInterface
|
|||||||
$query
|
$query
|
||||||
->setSelectKey('user')
|
->setSelectKey('user')
|
||||||
->setSelectJsonbMetadata("jsonb_build_object('id', u.id)")
|
->setSelectJsonbMetadata("jsonb_build_object('id', u.id)")
|
||||||
->setSelectPertinence('GREATEST(SIMILARITY(LOWER(UNACCENT(?)), u.usernamecanonical),
|
->setSelectPertinence('GREATEST(SIMILARITY(LOWER(UNACCENT(?)), u.label),
|
||||||
SIMILARITY(LOWER(UNACCENT(?)), u.emailcanonical))', [$pattern, $pattern])
|
SIMILARITY(LOWER(UNACCENT(?)), u.usernamecanonical))', [$pattern, $pattern])
|
||||||
->setFromClause('users AS u')
|
->setFromClause('users AS u')
|
||||||
->setWhereClauses('SIMILARITY(LOWER(UNACCENT(?)), u.usernamecanonical) > 0.15
|
->setWhereClauses('
|
||||||
OR
|
SIMILARITY(LOWER(UNACCENT(?)), u.usernamecanonical) > 0.15
|
||||||
SIMILARITY(LOWER(UNACCENT(?)), u.emailcanonical) > 0.15
|
OR u.usernamecanonical LIKE \'%\' || LOWER(UNACCENT(?)) || \'%\'
|
||||||
', [$pattern, $pattern]);
|
OR SIMILARITY(LOWER(UNACCENT(?)), LOWER(UNACCENT(u.label))) > 0.15
|
||||||
|
OR u.label LIKE \'%\' || LOWER(UNACCENT(?)) || \'%\'
|
||||||
|
', [$pattern, $pattern, $pattern, $pattern]);
|
||||||
|
|
||||||
return $query;
|
return $query;
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,10 @@ class SearchApiQuery
|
|||||||
|
|
||||||
private array $fromClauseParams = [];
|
private array $fromClauseParams = [];
|
||||||
|
|
||||||
|
private bool $isDistinct = false;
|
||||||
|
|
||||||
|
private ?string $isDistinctKey = null;
|
||||||
|
|
||||||
private ?string $jsonbMetadata = null;
|
private ?string $jsonbMetadata = null;
|
||||||
|
|
||||||
private array $jsonbMetadataParams = [];
|
private array $jsonbMetadataParams = [];
|
||||||
@ -105,6 +109,11 @@ class SearchApiQuery
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getDistinct(): bool
|
||||||
|
{
|
||||||
|
return $this->isDistinct;
|
||||||
|
}
|
||||||
|
|
||||||
public function getFromClause(): string
|
public function getFromClause(): string
|
||||||
{
|
{
|
||||||
return $this->fromClause;
|
return $this->fromClause;
|
||||||
@ -139,6 +148,14 @@ class SearchApiQuery
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setDistinct(bool $distinct, string $distinctKey): self
|
||||||
|
{
|
||||||
|
$this->isDistinct = $distinct;
|
||||||
|
$this->isDistinctKey = $distinctKey;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
public function setFromClause(string $fromClause, array $params = []): self
|
public function setFromClause(string $fromClause, array $params = []): self
|
||||||
{
|
{
|
||||||
$this->fromClause = $fromClause;
|
$this->fromClause = $fromClause;
|
||||||
@ -185,7 +202,11 @@ class SearchApiQuery
|
|||||||
private function buildSelectClause(bool $countOnly = false): string
|
private function buildSelectClause(bool $countOnly = false): string
|
||||||
{
|
{
|
||||||
if ($countOnly) {
|
if ($countOnly) {
|
||||||
return 'count(*) AS c';
|
if (!$this->isDistinct) {
|
||||||
|
return 'count(*) AS c';
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'count(distinct ' . $this->isDistinctKey . ') AS c';
|
||||||
}
|
}
|
||||||
|
|
||||||
$selects = $this->getSelectClauses();
|
$selects = $this->getSelectClauses();
|
||||||
@ -202,7 +223,7 @@ class SearchApiQuery
|
|||||||
$selects[] = strtr('{pertinence} AS pertinence', ['{pertinence}' => $this->pertinence]);
|
$selects[] = strtr('{pertinence} AS pertinence', ['{pertinence}' => $this->pertinence]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return implode(', ', $selects);
|
return ($this->isDistinct ? 'DISTINCT ' : '') . implode(', ', $selects);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function buildSelectParams(bool $count = false): array
|
private function buildSelectParams(bool $count = false): array
|
||||||
|
41
src/Bundle/ChillMainBundle/Serializer/Model/Counter.php
Normal file
41
src/Bundle/ChillMainBundle/Serializer/Model/Counter.php
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Chill\MainBundle\Serializer\Model;
|
||||||
|
|
||||||
|
use JsonSerializable;
|
||||||
|
|
||||||
|
class Counter implements JsonSerializable
|
||||||
|
{
|
||||||
|
private int $counter;
|
||||||
|
|
||||||
|
public function __construct(?int $counter)
|
||||||
|
{
|
||||||
|
$this->counter = $counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCounter(): ?int
|
||||||
|
{
|
||||||
|
return $this->counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function jsonSerialize()
|
||||||
|
{
|
||||||
|
return ['count' => $this->counter];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setCounter(?int $counter): Counter
|
||||||
|
{
|
||||||
|
$this->counter = $counter;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
}
|
@ -55,7 +55,7 @@ class CommentEmbeddableDocGenNormalizer implements ContextAwareNormalizerInterfa
|
|||||||
$user = $this->userRepository->find($object->getUserId());
|
$user = $this->userRepository->find($object->getUserId());
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'comment' => (string) $object->getComment(),
|
'comment' => $object->getComment(),
|
||||||
'isNull' => false,
|
'isNull' => false,
|
||||||
'date' => $this->normalizer->normalize($object->getDate(), $format, array_merge($context, [
|
'date' => $this->normalizer->normalize($object->getDate(), $format, array_merge($context, [
|
||||||
'docgen:expects' => DateTime::class,
|
'docgen:expects' => DateTime::class,
|
||||||
|
@ -0,0 +1,71 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Chill\MainBundle\Serializer\Normalizer;
|
||||||
|
|
||||||
|
use ArrayObject;
|
||||||
|
use Chill\MainBundle\Entity\Notification;
|
||||||
|
use Chill\MainBundle\Notification\NotificationHandlerManager;
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use Symfony\Component\Security\Core\Security;
|
||||||
|
use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface;
|
||||||
|
use Symfony\Component\Serializer\Normalizer\NormalizerAwareTrait;
|
||||||
|
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
|
||||||
|
|
||||||
|
class NotificationNormalizer implements NormalizerAwareInterface, NormalizerInterface
|
||||||
|
{
|
||||||
|
use NormalizerAwareTrait;
|
||||||
|
|
||||||
|
private EntityManagerInterface $entityManager;
|
||||||
|
|
||||||
|
private NotificationHandlerManager $notificationHandlerManager;
|
||||||
|
|
||||||
|
private Security $security;
|
||||||
|
|
||||||
|
public function __construct(NotificationHandlerManager $notificationHandlerManager, EntityManagerInterface $entityManager, Security $security)
|
||||||
|
{
|
||||||
|
$this->notificationHandlerManager = $notificationHandlerManager;
|
||||||
|
$this->entityManager = $entityManager;
|
||||||
|
$this->security = $security;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Notification $object
|
||||||
|
*
|
||||||
|
* @return array|ArrayObject|bool|float|int|string|void|null
|
||||||
|
*/
|
||||||
|
public function normalize($object, ?string $format = null, array $context = [])
|
||||||
|
{
|
||||||
|
dump($object);
|
||||||
|
$entity = $this->entityManager
|
||||||
|
->getRepository($object->getRelatedEntityClass())
|
||||||
|
->find($object->getRelatedEntityId());
|
||||||
|
|
||||||
|
return [
|
||||||
|
'type' => 'notification',
|
||||||
|
'id' => $object->getId(),
|
||||||
|
'addressees' => $this->normalizer->normalize($object->getAddressees(), $format, $context),
|
||||||
|
'date' => $this->normalizer->normalize($object->getDate(), $format, $context),
|
||||||
|
'isRead' => $object->isReadBy($this->security->getUser()),
|
||||||
|
'message' => $object->getMessage(),
|
||||||
|
'relatedEntityClass' => $object->getRelatedEntityClass(),
|
||||||
|
'relatedEntityId' => $object->getRelatedEntityId(),
|
||||||
|
'sender' => $this->normalizer->normalize($object->getSender(), $format, $context),
|
||||||
|
'title' => $object->getTitle(),
|
||||||
|
'entity' => null !== $entity ? $this->normalizer->normalize($entity, $format, $context) : null,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function supportsNormalization($data, ?string $format = null)
|
||||||
|
{
|
||||||
|
return $data instanceof Notification && 'json' === $format;
|
||||||
|
}
|
||||||
|
}
|
@ -134,6 +134,7 @@ paths:
|
|||||||
- search
|
- search
|
||||||
- person
|
- person
|
||||||
- thirdparty
|
- thirdparty
|
||||||
|
- household
|
||||||
description: >
|
description: >
|
||||||
The search is performed across multiple entities. The entities must be listed into
|
The search is performed across multiple entities. The entities must be listed into
|
||||||
`type` parameters.
|
`type` parameters.
|
||||||
@ -159,6 +160,7 @@ paths:
|
|||||||
- person
|
- person
|
||||||
- thirdparty
|
- thirdparty
|
||||||
- user
|
- user
|
||||||
|
- household
|
||||||
responses:
|
responses:
|
||||||
200:
|
200:
|
||||||
description: "OK"
|
description: "OK"
|
||||||
|
@ -53,6 +53,7 @@ module.exports = function(encore, entries)
|
|||||||
encore.addEntry('page_login', __dirname + '/Resources/public/page/login/index.js');
|
encore.addEntry('page_login', __dirname + '/Resources/public/page/login/index.js');
|
||||||
encore.addEntry('page_location', __dirname + '/Resources/public/page/location/index.js');
|
encore.addEntry('page_location', __dirname + '/Resources/public/page/location/index.js');
|
||||||
encore.addEntry('page_workflow_show', __dirname + '/Resources/public/page/workflow-show/index.js');
|
encore.addEntry('page_workflow_show', __dirname + '/Resources/public/page/workflow-show/index.js');
|
||||||
|
encore.addEntry('page_homepage_widget', __dirname + '/Resources/public/page/homepage_widget/index.js');
|
||||||
|
|
||||||
buildCKEditor(encore);
|
buildCKEditor(encore);
|
||||||
|
|
||||||
|
@ -0,0 +1,48 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Chill\Migrations\Main;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\Schema\Schema;
|
||||||
|
use Doctrine\Migrations\AbstractMigration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new entity ResidentialAddress.
|
||||||
|
*/
|
||||||
|
final class Version20220125134253 extends AbstractMigration
|
||||||
|
{
|
||||||
|
public function down(Schema $schema): void
|
||||||
|
{
|
||||||
|
$this->addSql('DROP SEQUENCE chill_main_residential_address_id_seq CASCADE');
|
||||||
|
$this->addSql('DROP TABLE chill_main_residential_address');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDescription(): string
|
||||||
|
{
|
||||||
|
return 'Create a new entity ResidentialAddress';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function up(Schema $schema): void
|
||||||
|
{
|
||||||
|
$this->addSql('CREATE SEQUENCE chill_main_residential_address_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
|
||||||
|
$this->addSql('CREATE TABLE chill_main_residential_address (id INT NOT NULL, person_id INT NOT NULL, address_id INT DEFAULT NULL, startDate TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, endDate TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL, residentialAddressComment_comment TEXT DEFAULT NULL, residentialAddressComment_date TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL, residentialAddressComment_userId INT DEFAULT NULL, hostPerson_id INT DEFAULT NULL, hostThirdParty_id INT DEFAULT NULL, PRIMARY KEY(id))');
|
||||||
|
$this->addSql('CREATE INDEX IDX_9BC1FD50217BBB47 ON chill_main_residential_address (person_id)');
|
||||||
|
$this->addSql('CREATE INDEX IDX_9BC1FD50DCA38092 ON chill_main_residential_address (hostPerson_id)');
|
||||||
|
$this->addSql('CREATE INDEX IDX_9BC1FD508DFC48DC ON chill_main_residential_address (hostThirdParty_id)');
|
||||||
|
$this->addSql('CREATE INDEX IDX_9BC1FD50F5B7AF75 ON chill_main_residential_address (address_id)');
|
||||||
|
$this->addSql('COMMENT ON COLUMN chill_main_residential_address.startDate IS \'(DC2Type:datetime_immutable)\'');
|
||||||
|
$this->addSql('COMMENT ON COLUMN chill_main_residential_address.endDate IS \'(DC2Type:datetime_immutable)\'');
|
||||||
|
$this->addSql('ALTER TABLE chill_main_residential_address ADD CONSTRAINT FK_9BC1FD50217BBB47 FOREIGN KEY (person_id) REFERENCES chill_person_person (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||||
|
$this->addSql('ALTER TABLE chill_main_residential_address ADD CONSTRAINT FK_9BC1FD50DCA38092 FOREIGN KEY (hostPerson_id) REFERENCES chill_person_person (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||||
|
$this->addSql('ALTER TABLE chill_main_residential_address ADD CONSTRAINT FK_9BC1FD508DFC48DC FOREIGN KEY (hostThirdParty_id) REFERENCES chill_3party.third_party (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||||
|
$this->addSql('ALTER TABLE chill_main_residential_address ADD CONSTRAINT FK_9BC1FD50F5B7AF75 FOREIGN KEY (address_id) REFERENCES chill_main_address (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||||
|
}
|
||||||
|
}
|
@ -52,6 +52,8 @@ Since %date%: Depuis le %date%
|
|||||||
since %date%: depuis le %date%
|
since %date%: depuis le %date%
|
||||||
Until %date%: Jusqu'au %date%
|
Until %date%: Jusqu'au %date%
|
||||||
until %date%: jusqu'au %date%
|
until %date%: jusqu'au %date%
|
||||||
|
Since: Depuis le
|
||||||
|
Until: Jusqu'au
|
||||||
#elements used in software
|
#elements used in software
|
||||||
centers: centres
|
centers: centres
|
||||||
Centers: Centres
|
Centers: Centres
|
||||||
|
@ -13,7 +13,9 @@ namespace Chill\PersonBundle\Controller;
|
|||||||
|
|
||||||
use Chill\MainBundle\CRUD\Controller\ApiController;
|
use Chill\MainBundle\CRUD\Controller\ApiController;
|
||||||
use Chill\MainBundle\Entity\Scope;
|
use Chill\MainBundle\Entity\Scope;
|
||||||
|
use Chill\MainBundle\Entity\User;
|
||||||
use Chill\MainBundle\Serializer\Model\Collection;
|
use Chill\MainBundle\Serializer\Model\Collection;
|
||||||
|
use Chill\MainBundle\Serializer\Model\Counter;
|
||||||
use Chill\PersonBundle\AccompanyingPeriod\Suggestion\ReferralsSuggestionInterface;
|
use Chill\PersonBundle\AccompanyingPeriod\Suggestion\ReferralsSuggestionInterface;
|
||||||
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||||
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWork;
|
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWork;
|
||||||
@ -23,8 +25,11 @@ use Chill\PersonBundle\Entity\Person;
|
|||||||
use Chill\PersonBundle\Entity\SocialWork\SocialIssue;
|
use Chill\PersonBundle\Entity\SocialWork\SocialIssue;
|
||||||
use Chill\PersonBundle\Privacy\AccompanyingPeriodPrivacyEvent;
|
use Chill\PersonBundle\Privacy\AccompanyingPeriodPrivacyEvent;
|
||||||
use Chill\PersonBundle\Repository\AccompanyingPeriodACLAwareRepository;
|
use Chill\PersonBundle\Repository\AccompanyingPeriodACLAwareRepository;
|
||||||
|
use Chill\PersonBundle\Repository\AccompanyingPeriodRepository;
|
||||||
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter;
|
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter;
|
||||||
use Chill\ThirdPartyBundle\Entity\ThirdParty;
|
use Chill\ThirdPartyBundle\Entity\ThirdParty;
|
||||||
|
use DateInterval;
|
||||||
|
use DateTimeImmutable;
|
||||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
|
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
|
||||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||||
use Symfony\Component\HttpFoundation\Exception\BadRequestException;
|
use Symfony\Component\HttpFoundation\Exception\BadRequestException;
|
||||||
@ -32,13 +37,14 @@ use Symfony\Component\HttpFoundation\JsonResponse;
|
|||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Component\Routing\Annotation\Route;
|
use Symfony\Component\Routing\Annotation\Route;
|
||||||
|
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
|
||||||
use Symfony\Component\Serializer\Exception\RuntimeException;
|
use Symfony\Component\Serializer\Exception\RuntimeException;
|
||||||
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
|
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
|
||||||
use Symfony\Component\Validator\ConstraintViolationList;
|
use Symfony\Component\Validator\ConstraintViolationList;
|
||||||
use Symfony\Component\Validator\ConstraintViolationListInterface;
|
use Symfony\Component\Validator\ConstraintViolationListInterface;
|
||||||
|
|
||||||
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
||||||
use Symfony\Component\Workflow\Registry;
|
use Symfony\Component\Workflow\Registry;
|
||||||
|
|
||||||
use function array_values;
|
use function array_values;
|
||||||
use function count;
|
use function count;
|
||||||
|
|
||||||
@ -46,6 +52,8 @@ final class AccompanyingCourseApiController extends ApiController
|
|||||||
{
|
{
|
||||||
private AccompanyingPeriodACLAwareRepository $accompanyingPeriodACLAwareRepository;
|
private AccompanyingPeriodACLAwareRepository $accompanyingPeriodACLAwareRepository;
|
||||||
|
|
||||||
|
private AccompanyingPeriodRepository $accompanyingPeriodRepository;
|
||||||
|
|
||||||
private EventDispatcherInterface $eventDispatcher;
|
private EventDispatcherInterface $eventDispatcher;
|
||||||
|
|
||||||
private ReferralsSuggestionInterface $referralAvailable;
|
private ReferralsSuggestionInterface $referralAvailable;
|
||||||
@ -55,17 +63,19 @@ final class AccompanyingCourseApiController extends ApiController
|
|||||||
private ValidatorInterface $validator;
|
private ValidatorInterface $validator;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
EventDispatcherInterface $eventDispatcher,
|
AccompanyingPeriodRepository $accompanyingPeriodRepository,
|
||||||
ValidatorInterface $validator,
|
|
||||||
Registry $registry,
|
|
||||||
AccompanyingPeriodACLAwareRepository $accompanyingPeriodACLAwareRepository,
|
AccompanyingPeriodACLAwareRepository $accompanyingPeriodACLAwareRepository,
|
||||||
ReferralsSuggestionInterface $referralAvailable
|
EventDispatcherInterface $eventDispatcher,
|
||||||
|
ReferralsSuggestionInterface $referralAvailable,
|
||||||
|
Registry $registry,
|
||||||
|
ValidatorInterface $validator
|
||||||
) {
|
) {
|
||||||
$this->eventDispatcher = $eventDispatcher;
|
$this->accompanyingPeriodRepository = $accompanyingPeriodRepository;
|
||||||
$this->validator = $validator;
|
|
||||||
$this->registry = $registry;
|
|
||||||
$this->accompanyingPeriodACLAwareRepository = $accompanyingPeriodACLAwareRepository;
|
$this->accompanyingPeriodACLAwareRepository = $accompanyingPeriodACLAwareRepository;
|
||||||
|
$this->eventDispatcher = $eventDispatcher;
|
||||||
$this->referralAvailable = $referralAvailable;
|
$this->referralAvailable = $referralAvailable;
|
||||||
|
$this->registry = $registry;
|
||||||
|
$this->validator = $validator;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function commentApi($id, Request $request, string $_format): Response
|
public function commentApi($id, Request $request, string $_format): Response
|
||||||
@ -99,6 +109,57 @@ final class AccompanyingCourseApiController extends ApiController
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Route("/api/1.0/person/accompanying-course/list/by-recent-attributions")
|
||||||
|
*/
|
||||||
|
public function findMyRecentCourseAttribution(Request $request): JsonResponse
|
||||||
|
{
|
||||||
|
$this->denyAccessUnlessGranted('ROLE_USER');
|
||||||
|
$user = $this->getUser();
|
||||||
|
|
||||||
|
if (!$user instanceof User) {
|
||||||
|
throw new AccessDeniedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
$since = (new DateTimeImmutable('now'))->sub(new DateInterval('P15D'));
|
||||||
|
|
||||||
|
$total = $this->accompanyingPeriodRepository->countByRecentUserHistory($user, $since);
|
||||||
|
|
||||||
|
if ($request->query->getBoolean('countOnly', false)) {
|
||||||
|
return new JsonResponse(
|
||||||
|
$this->getSerializer()->serialize(new Counter($total), 'json'),
|
||||||
|
JsonResponse::HTTP_OK,
|
||||||
|
[],
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$paginator = $this->getPaginatorFactory()->create($total);
|
||||||
|
|
||||||
|
if (0 === $total) {
|
||||||
|
return new JsonResponse(
|
||||||
|
$this->getSerializer()->serialize(new Collection([], $paginator), 'json'),
|
||||||
|
JsonResponse::HTTP_OK,
|
||||||
|
[],
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$courses = $this->accompanyingPeriodRepository->findByRecentUserHistory(
|
||||||
|
$user,
|
||||||
|
$since,
|
||||||
|
$paginator->getItemsPerPage(),
|
||||||
|
$paginator->getCurrentPageFirstItemNumber()
|
||||||
|
);
|
||||||
|
|
||||||
|
return new JsonResponse(
|
||||||
|
$this->getSerializer()->serialize(new Collection($courses, $paginator), 'json', ['groups' => ['read']]),
|
||||||
|
JsonResponse::HTTP_OK,
|
||||||
|
[],
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ParamConverter("person", options={"id": "person_id"})
|
* @ParamConverter("person", options={"id": "person_id"})
|
||||||
*/
|
*/
|
||||||
|
@ -12,10 +12,54 @@ declare(strict_types=1);
|
|||||||
namespace Chill\PersonBundle\Controller;
|
namespace Chill\PersonBundle\Controller;
|
||||||
|
|
||||||
use Chill\MainBundle\CRUD\Controller\ApiController;
|
use Chill\MainBundle\CRUD\Controller\ApiController;
|
||||||
|
use Chill\MainBundle\Serializer\Model\Collection;
|
||||||
|
use Chill\MainBundle\Serializer\Model\Counter;
|
||||||
|
use Chill\PersonBundle\Repository\AccompanyingPeriod\AccompanyingPeriodWorkRepository;
|
||||||
|
use DateInterval;
|
||||||
|
use DateTimeImmutable;
|
||||||
|
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\Routing\Annotation\Route;
|
||||||
|
|
||||||
class AccompanyingCourseWorkApiController extends ApiController
|
class AccompanyingCourseWorkApiController extends ApiController
|
||||||
{
|
{
|
||||||
|
private AccompanyingPeriodWorkRepository $accompanyingPeriodWorkRepository;
|
||||||
|
|
||||||
|
public function __construct(AccompanyingPeriodWorkRepository $accompanyingPeriodWorkRepository)
|
||||||
|
{
|
||||||
|
$this->accompanyingPeriodWorkRepository = $accompanyingPeriodWorkRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Route("/api/1.0/person/accompanying-period/work/my-near-end")
|
||||||
|
*/
|
||||||
|
public function myWorksNearEndDate(Request $request): JsonResponse
|
||||||
|
{
|
||||||
|
$since = (new DateTimeImmutable('now'))
|
||||||
|
->sub(new DateInterval('P' . $request->query->getInt('since', 15) . 'D'));
|
||||||
|
$until = (new DateTimeImmutable('now'))
|
||||||
|
->add(new DateInterval('P' . $request->query->getInt('since', 15) . 'D'));
|
||||||
|
$total = $this->accompanyingPeriodWorkRepository
|
||||||
|
->countNearEndDateByUser($this->getUser(), $since, $until);
|
||||||
|
|
||||||
|
if ($request->query->getBoolean('countOnly', false)) {
|
||||||
|
return $this->json(
|
||||||
|
new Counter($total),
|
||||||
|
JsonResponse::HTTP_OK,
|
||||||
|
[],
|
||||||
|
['groups' => ['read']]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$paginator = $this->getPaginatorFactory()->create($total);
|
||||||
|
$works = $this->accompanyingPeriodWorkRepository
|
||||||
|
->findNearEndDateByUser($this->getUser(), $since, $until, $paginator->getItemsPerPage(), $paginator->getCurrentPageFirstItemNumber());
|
||||||
|
|
||||||
|
$collection = new Collection($works, $paginator);
|
||||||
|
|
||||||
|
return $this->json($collection, 200, [], ['groups' => ['read']]);
|
||||||
|
}
|
||||||
|
|
||||||
protected function getContextForSerialization(string $action, Request $request, string $_format, $entity): array
|
protected function getContextForSerialization(string $action, Request $request, string $_format, $entity): array
|
||||||
{
|
{
|
||||||
switch ($action) {
|
switch ($action) {
|
||||||
|
@ -15,11 +15,15 @@ use Chill\DocGeneratorBundle\Entity\DocGeneratorTemplate;
|
|||||||
use Chill\DocGeneratorBundle\Repository\DocGeneratorTemplateRepository;
|
use Chill\DocGeneratorBundle\Repository\DocGeneratorTemplateRepository;
|
||||||
use Chill\MainBundle\Pagination\PaginatorFactory;
|
use Chill\MainBundle\Pagination\PaginatorFactory;
|
||||||
use Chill\MainBundle\Serializer\Model\Collection;
|
use Chill\MainBundle\Serializer\Model\Collection;
|
||||||
|
use Chill\MainBundle\Serializer\Model\Counter;
|
||||||
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluation;
|
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluation;
|
||||||
use Chill\PersonBundle\Entity\SocialWork\Evaluation;
|
use Chill\PersonBundle\Entity\SocialWork\Evaluation;
|
||||||
|
use Chill\PersonBundle\Repository\AccompanyingPeriod\AccompanyingPeriodWorkEvaluationRepository;
|
||||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
||||||
use Symfony\Component\Routing\Annotation\Route;
|
use Symfony\Component\Routing\Annotation\Route;
|
||||||
|
use Symfony\Component\Security\Core\Security;
|
||||||
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
|
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
|
||||||
use Symfony\Component\Serializer\SerializerInterface;
|
use Symfony\Component\Serializer\SerializerInterface;
|
||||||
|
|
||||||
@ -28,20 +32,28 @@ use function in_array;
|
|||||||
|
|
||||||
class AccompanyingPeriodWorkEvaluationApiController
|
class AccompanyingPeriodWorkEvaluationApiController
|
||||||
{
|
{
|
||||||
|
private AccompanyingPeriodWorkEvaluationRepository $accompanyingPeriodWorkEvaluationRepository;
|
||||||
|
|
||||||
private DocGeneratorTemplateRepository $docGeneratorTemplateRepository;
|
private DocGeneratorTemplateRepository $docGeneratorTemplateRepository;
|
||||||
|
|
||||||
private PaginatorFactory $paginatorFactory;
|
private PaginatorFactory $paginatorFactory;
|
||||||
|
|
||||||
|
private Security $security;
|
||||||
|
|
||||||
private SerializerInterface $serializer;
|
private SerializerInterface $serializer;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
|
AccompanyingPeriodWorkEvaluationRepository $accompanyingPeriodWorkEvaluationRepository,
|
||||||
DocGeneratorTemplateRepository $docGeneratorTemplateRepository,
|
DocGeneratorTemplateRepository $docGeneratorTemplateRepository,
|
||||||
SerializerInterface $serializer,
|
SerializerInterface $serializer,
|
||||||
PaginatorFactory $paginatorFactory
|
PaginatorFactory $paginatorFactory,
|
||||||
|
Security $security
|
||||||
) {
|
) {
|
||||||
|
$this->accompanyingPeriodWorkEvaluationRepository = $accompanyingPeriodWorkEvaluationRepository;
|
||||||
$this->docGeneratorTemplateRepository = $docGeneratorTemplateRepository;
|
$this->docGeneratorTemplateRepository = $docGeneratorTemplateRepository;
|
||||||
$this->serializer = $serializer;
|
$this->serializer = $serializer;
|
||||||
$this->paginatorFactory = $paginatorFactory;
|
$this->paginatorFactory = $paginatorFactory;
|
||||||
|
$this->security = $security;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -76,4 +88,39 @@ class AccompanyingPeriodWorkEvaluationApiController
|
|||||||
]
|
]
|
||||||
), JsonResponse::HTTP_OK, [], true);
|
), JsonResponse::HTTP_OK, [], true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Route("/api/1.0/person/accompanying-period/work/evaluation/my-near-end")
|
||||||
|
*/
|
||||||
|
public function myWorksNearEndDate(Request $request): JsonResponse
|
||||||
|
{
|
||||||
|
$total = $this->accompanyingPeriodWorkEvaluationRepository
|
||||||
|
->countNearMaxDateByUser($this->security->getUser());
|
||||||
|
|
||||||
|
if ($request->query->getBoolean('countOnly', false)) {
|
||||||
|
return new JsonResponse(
|
||||||
|
$this->serializer->serialize(new Counter($total), 'json', ['groups' => 'read']),
|
||||||
|
JsonResponse::HTTP_OK,
|
||||||
|
[],
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$paginator = $this->paginatorFactory->create($total);
|
||||||
|
$works = $this->accompanyingPeriodWorkEvaluationRepository
|
||||||
|
->findNearMaxDateByUser(
|
||||||
|
$this->security->getUser(),
|
||||||
|
$paginator->getItemsPerPage(),
|
||||||
|
$paginator->getCurrentPageFirstItemNumber()
|
||||||
|
);
|
||||||
|
|
||||||
|
$collection = new Collection($works, $paginator);
|
||||||
|
|
||||||
|
return new JsonResponse(
|
||||||
|
$this->serializer->serialize($collection, 'json', ['groups' => 'read']),
|
||||||
|
JsonResponse::HTTP_OK,
|
||||||
|
[],
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,161 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Chill\PersonBundle\Controller;
|
||||||
|
|
||||||
|
use Chill\MainBundle\Entity\ResidentialAddress;
|
||||||
|
use Chill\MainBundle\Form\Type\ResidentialAddressType;
|
||||||
|
use Chill\MainBundle\Repository\ResidentialAddressRepository;
|
||||||
|
use Chill\PersonBundle\Entity\Person;
|
||||||
|
use Chill\PersonBundle\Security\Authorization\PersonVoter;
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\FormType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
use Symfony\Component\Routing\Annotation\Route;
|
||||||
|
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||||
|
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||||
|
|
||||||
|
final class ResidentialAddressController extends AbstractController
|
||||||
|
{
|
||||||
|
private UrlGeneratorInterface $generator;
|
||||||
|
|
||||||
|
private ResidentialAddressRepository $residentialAddressRepository;
|
||||||
|
|
||||||
|
private TranslatorInterface $translator;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
UrlGeneratorInterface $generator,
|
||||||
|
TranslatorInterface $translator,
|
||||||
|
ResidentialAddressRepository $residentialAddressRepository
|
||||||
|
) {
|
||||||
|
$this->generator = $generator;
|
||||||
|
$this->translator = $translator;
|
||||||
|
$this->residentialAddressRepository = $residentialAddressRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Route("/{_locale}/person/residential-address/{id}/delete", name="chill_person_residential_address_delete")
|
||||||
|
*/
|
||||||
|
public function deleteAction(Request $request, ResidentialAddress $residentialAddress): Response
|
||||||
|
{
|
||||||
|
$this->denyAccessUnlessGranted(PersonVoter::UPDATE, $residentialAddress->getPerson());
|
||||||
|
|
||||||
|
$form = $this->createForm(FormType::class);
|
||||||
|
$form->add('submit', SubmitType::class, ['label' => 'Delete']);
|
||||||
|
$form->handleRequest($request);
|
||||||
|
|
||||||
|
if ($form->isSubmitted() && $form->isValid()) {
|
||||||
|
$em = $this->getDoctrine()->getManager();
|
||||||
|
$em->remove($residentialAddress);
|
||||||
|
$em->flush();
|
||||||
|
|
||||||
|
$this->addFlash('success', $this->translator->trans('Residential address had been deleted'));
|
||||||
|
|
||||||
|
return $this->redirectToRoute('chill_person_residential_address_list', ['id' => $residentialAddress->getPerson()->getId()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->render('@ChillPerson/ResidentialAddress/delete.html.twig', [
|
||||||
|
'person' => $residentialAddress->getPerson(),
|
||||||
|
'residentialAddress' => $residentialAddress,
|
||||||
|
'delete_form' => $form->createView(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Route("/{_locale}/person/residential-address/{id}/edit", name="chill_person_residential_address_edit")
|
||||||
|
*/
|
||||||
|
public function editAction(Request $request, ResidentialAddress $residentialAddress): Response
|
||||||
|
{
|
||||||
|
if ($request->query->has('kind')) {
|
||||||
|
$kind = $request->query->getAlpha('kind', '');
|
||||||
|
} else {
|
||||||
|
$kind = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$person = $residentialAddress->getPerson();
|
||||||
|
$this->denyAccessUnlessGranted(PersonVoter::UPDATE, $person);
|
||||||
|
|
||||||
|
$form = $this->createForm(ResidentialAddressType::class, $residentialAddress, ['kind' => $kind]);
|
||||||
|
$form->handleRequest($request);
|
||||||
|
|
||||||
|
if ($form->isSubmitted() && $form->isValid()) {
|
||||||
|
$this->getDoctrine()->getManager()->flush();
|
||||||
|
|
||||||
|
$this->addFlash('success', $this->translator
|
||||||
|
->trans('The residential address was updated successfully'));
|
||||||
|
|
||||||
|
return $this->redirect(
|
||||||
|
$request->get('returnPath', null) ??
|
||||||
|
$this->generator->generate('chill_person_residential_address_list', ['id' => $person->getId()])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->render('@ChillPerson/ResidentialAddress/edit.html.twig', [
|
||||||
|
'residentialAddress' => $residentialAddress,
|
||||||
|
'person' => $person,
|
||||||
|
'form' => $form->createView(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Route("/{_locale}/person/{id}/residential-address/list", name="chill_person_residential_address_list")
|
||||||
|
*/
|
||||||
|
public function listAction(Request $request, Person $person): Response
|
||||||
|
{
|
||||||
|
$this->denyAccessUnlessGranted(PersonVoter::SEE, $person);
|
||||||
|
|
||||||
|
$residentialAddresses = $this->residentialAddressRepository->findBy(['person' => $person], ['startDate' => 'DESC']);
|
||||||
|
|
||||||
|
return $this->render('@ChillPerson/ResidentialAddress/list.html.twig', [
|
||||||
|
'person' => $person,
|
||||||
|
'addresses' => $residentialAddresses,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Route("/{_locale}/person/{id}/residential-address/new", name="chill_person_residential_address_new")
|
||||||
|
*/
|
||||||
|
public function newAction(Request $request, Person $person): Response
|
||||||
|
{
|
||||||
|
$residentialAddress = new ResidentialAddress();
|
||||||
|
$residentialAddress->setPerson($person);
|
||||||
|
|
||||||
|
$this->denyAccessUnlessGranted(PersonVoter::UPDATE, $person);
|
||||||
|
|
||||||
|
if (!$request->query->has('kind')) {
|
||||||
|
return $this->render('@ChillPerson/ResidentialAddress/new_pick_kind.html.twig', ['person' => $person]);
|
||||||
|
}
|
||||||
|
$kind = $request->query->getAlpha('kind', '');
|
||||||
|
|
||||||
|
$form = $this->createForm(ResidentialAddressType::class, $residentialAddress, ['kind' => $kind]);
|
||||||
|
$form->handleRequest($request);
|
||||||
|
|
||||||
|
if ($form->isSubmitted() && $form->isValid()) {
|
||||||
|
$this->getDoctrine()->getManager()->persist($residentialAddress);
|
||||||
|
$this->getDoctrine()->getManager()->flush();
|
||||||
|
|
||||||
|
$this->addFlash('success', $this->translator
|
||||||
|
->trans('The new residential address was created successfully'));
|
||||||
|
|
||||||
|
return $this->redirect(
|
||||||
|
$request->get('returnPath', null) ??
|
||||||
|
$this->generator->generate('chill_person_residential_address_list', ['id' => $residentialAddress->getPerson()->getId()])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->render('@ChillPerson/ResidentialAddress/new.html.twig', [
|
||||||
|
'person' => $person,
|
||||||
|
'form' => $form->createView(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,51 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Chill\PersonBundle\Controller;
|
||||||
|
|
||||||
|
use Chill\MainBundle\Pagination\PaginatorFactory;
|
||||||
|
use Chill\PersonBundle\Repository\AccompanyingPeriodRepository;
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\Routing\Annotation\Route;
|
||||||
|
|
||||||
|
class UserAccompanyingPeriodController extends AbstractController
|
||||||
|
{
|
||||||
|
private AccompanyingPeriodRepository $accompanyingPeriodRepository;
|
||||||
|
|
||||||
|
private PaginatorFactory $paginatorFactory;
|
||||||
|
|
||||||
|
public function __construct(AccompanyingPeriodRepository $accompanyingPeriodRepository, PaginatorFactory $paginatorFactory)
|
||||||
|
{
|
||||||
|
$this->accompanyingPeriodRepository = $accompanyingPeriodRepository;
|
||||||
|
$this->paginatorFactory = $paginatorFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Route("/{_locale}/accompanying-periods", name="chill_person_accompanying_period_user")
|
||||||
|
*/
|
||||||
|
public function listAction(Request $request)
|
||||||
|
{
|
||||||
|
$total = $this->accompanyingPeriodRepository->countBy(['user' => $this->getUser()]);
|
||||||
|
$pagination = $this->paginatorFactory->create($total);
|
||||||
|
$accompanyingPeriods = $this->accompanyingPeriodRepository->findBy(
|
||||||
|
['user' => $this->getUser()],
|
||||||
|
['openingDate' => 'DESC'],
|
||||||
|
$pagination->getItemsPerPage(),
|
||||||
|
$pagination->getCurrentPageFirstItemNumber()
|
||||||
|
);
|
||||||
|
|
||||||
|
return $this->render('@ChillPerson/AccompanyingPeriod/user_periods_list.html.twig', [
|
||||||
|
'accompanyingPeriods' => $accompanyingPeriods,
|
||||||
|
'pagination' => $pagination,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
@ -26,6 +26,7 @@ use Chill\PersonBundle\Entity\AccompanyingPeriod\ClosingMotive;
|
|||||||
use Chill\PersonBundle\Entity\AccompanyingPeriod\Comment;
|
use Chill\PersonBundle\Entity\AccompanyingPeriod\Comment;
|
||||||
use Chill\PersonBundle\Entity\AccompanyingPeriod\Origin;
|
use Chill\PersonBundle\Entity\AccompanyingPeriod\Origin;
|
||||||
use Chill\PersonBundle\Entity\AccompanyingPeriod\Resource;
|
use Chill\PersonBundle\Entity\AccompanyingPeriod\Resource;
|
||||||
|
use Chill\PersonBundle\Entity\AccompanyingPeriod\UserHistory;
|
||||||
use Chill\PersonBundle\Entity\SocialWork\SocialIssue;
|
use Chill\PersonBundle\Entity\SocialWork\SocialIssue;
|
||||||
use Chill\PersonBundle\Validator\Constraints\AccompanyingPeriod\AccompanyingPeriodValidity;
|
use Chill\PersonBundle\Validator\Constraints\AccompanyingPeriod\AccompanyingPeriodValidity;
|
||||||
use Chill\PersonBundle\Validator\Constraints\AccompanyingPeriod\ParticipationOverlap;
|
use Chill\PersonBundle\Validator\Constraints\AccompanyingPeriod\ParticipationOverlap;
|
||||||
@ -212,6 +213,8 @@ class AccompanyingPeriod implements
|
|||||||
*
|
*
|
||||||
* @ORM\Column(type="date")
|
* @ORM\Column(type="date")
|
||||||
* @Groups({"read", "write", "docgen:read"})
|
* @Groups({"read", "write", "docgen:read"})
|
||||||
|
* @Assert\LessThan(value= "today", groups={AccompanyingPeriod::STEP_CONFIRMED})
|
||||||
|
* @Assert\LessThan(propertyPath="closingDate", groups={AccompanyingPeriod::STEP_CONFIRMED})
|
||||||
*/
|
*/
|
||||||
private ?DateTime $openingDate = null;
|
private ?DateTime $openingDate = null;
|
||||||
|
|
||||||
@ -336,6 +339,14 @@ class AccompanyingPeriod implements
|
|||||||
*/
|
*/
|
||||||
private ?User $user = null;
|
private ?User $user = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\OneToMany(targetEntity=UserHistory::class, mappedBy="accompanyingPeriod", orphanRemoval=true,
|
||||||
|
* cascade={"persist", "remove"})
|
||||||
|
*
|
||||||
|
* @var Collection|UserHistory[]
|
||||||
|
*/
|
||||||
|
private Collection $userHistories;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Temporary field, which is filled when the user is changed.
|
* Temporary field, which is filled when the user is changed.
|
||||||
*
|
*
|
||||||
@ -368,6 +379,7 @@ class AccompanyingPeriod implements
|
|||||||
$this->comments = new ArrayCollection();
|
$this->comments = new ArrayCollection();
|
||||||
$this->works = new ArrayCollection();
|
$this->works = new ArrayCollection();
|
||||||
$this->resources = new ArrayCollection();
|
$this->resources = new ArrayCollection();
|
||||||
|
$this->userHistories = new ArrayCollection();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1212,10 +1224,20 @@ class AccompanyingPeriod implements
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setUser(User $user): self
|
public function setUser(?User $user): self
|
||||||
{
|
{
|
||||||
if ($this->user !== $user) {
|
if ($this->user !== $user) {
|
||||||
$this->userPrevious = $this->user;
|
$this->userPrevious = $this->user;
|
||||||
|
|
||||||
|
foreach ($this->userHistories as $history) {
|
||||||
|
if (null === $history->getEndDate()) {
|
||||||
|
$history->setEndDate(new DateTimeImmutable('now'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null !== $user) {
|
||||||
|
$this->userHistories->add(new UserHistory($this, $user));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->user = $user;
|
$this->user = $user;
|
||||||
|
@ -0,0 +1,96 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||||
|
|
||||||
|
use Chill\MainBundle\Doctrine\Model\TrackCreationInterface;
|
||||||
|
use Chill\MainBundle\Doctrine\Model\TrackCreationTrait;
|
||||||
|
use Chill\MainBundle\Entity\User;
|
||||||
|
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||||
|
use DateTimeImmutable;
|
||||||
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Entity
|
||||||
|
* @ORM\Table("chill_person_accompanying_period_user_history")
|
||||||
|
*/
|
||||||
|
class UserHistory implements TrackCreationInterface
|
||||||
|
{
|
||||||
|
use TrackCreationTrait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\ManyToOne(targetEntity=AccompanyingPeriod::class, inversedBy="userHistories")
|
||||||
|
* @ORM\JoinColumn(nullable=false)
|
||||||
|
*/
|
||||||
|
private ?AccompanyingPeriod $accompanyingPeriod;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Column(type="datetime_immutable", nullable=true, options={"default": null})
|
||||||
|
*/
|
||||||
|
private ?DateTimeImmutable $endDate = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Id
|
||||||
|
* @ORM\Column(name="id", type="integer")
|
||||||
|
* @ORM\GeneratedValue(strategy="AUTO")
|
||||||
|
*/
|
||||||
|
private ?int $id = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Column(type="datetime_immutable", nullable=false)
|
||||||
|
*/
|
||||||
|
private DateTimeImmutable $startDate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\ManyToOne(targetEntity=User::class)
|
||||||
|
* @ORM\JoinColumn(nullable=false)
|
||||||
|
*/
|
||||||
|
private User $user;
|
||||||
|
|
||||||
|
public function __construct(AccompanyingPeriod $accompanyingPeriod, User $user, ?DateTimeImmutable $startDate = null)
|
||||||
|
{
|
||||||
|
$this->startDate = $startDate ?? new DateTimeImmutable('now');
|
||||||
|
$this->accompanyingPeriod = $accompanyingPeriod;
|
||||||
|
$this->user = $user;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAccompanyingPeriod(): AccompanyingPeriod
|
||||||
|
{
|
||||||
|
return $this->accompanyingPeriod;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getEndDate(): ?DateTimeImmutable
|
||||||
|
{
|
||||||
|
return $this->endDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getId(): ?int
|
||||||
|
{
|
||||||
|
return $this->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getStartDate(): DateTimeImmutable
|
||||||
|
{
|
||||||
|
return $this->startDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUser(): User
|
||||||
|
{
|
||||||
|
return $this->user;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setEndDate(?DateTimeImmutable $endDate): UserHistory
|
||||||
|
{
|
||||||
|
$this->endDate = $endDate;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
}
|
@ -784,12 +784,18 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
|
|||||||
* If the `$at` parameter is now, use the method `getCurrentPersonAddress`, which is optimized
|
* If the `$at` parameter is now, use the method `getCurrentPersonAddress`, which is optimized
|
||||||
* on database side.
|
* on database side.
|
||||||
*
|
*
|
||||||
|
* @deprecated since chill2.0, address is linked to the household. Use @see{Person::getCurrentHouseholdAddress}
|
||||||
|
*
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function getAddressAt(?DateTime $at = null): ?Address
|
public function getAddressAt(?DateTimeInterface $at = null): ?Address
|
||||||
{
|
{
|
||||||
$at ??= new DateTime('now');
|
$at ??= new DateTime('now');
|
||||||
|
|
||||||
|
if ($at instanceof DateTimeImmutable) {
|
||||||
|
$at = DateTime::createFromImmutable($at);
|
||||||
|
}
|
||||||
|
|
||||||
/** @var ArrayIterator $addressesIterator */
|
/** @var ArrayIterator $addressesIterator */
|
||||||
$addressesIterator = $this->getAddresses()
|
$addressesIterator = $this->getAddresses()
|
||||||
->filter(static fn (Address $address): bool => $address->getValidFrom() <= $at)
|
->filter(static fn (Address $address): bool => $address->getValidFrom() <= $at)
|
||||||
@ -950,6 +956,12 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
|
|||||||
: null;
|
: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the household address at the given date.
|
||||||
|
*
|
||||||
|
* if the given date is 'now', use instead @see{getCurrentPersonAddress}, which is optimized on
|
||||||
|
* database side.
|
||||||
|
*/
|
||||||
public function getCurrentHouseholdAddress(?DateTimeImmutable $at = null): ?Address
|
public function getCurrentHouseholdAddress(?DateTimeImmutable $at = null): ?Address
|
||||||
{
|
{
|
||||||
if (
|
if (
|
||||||
|
@ -62,6 +62,16 @@ class PersonMenuBuilder implements LocalMenuBuilderInterface
|
|||||||
'order' => 50,
|
'order' => 50,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
$menu->addChild($this->translator->trans('Residential addresses'), [
|
||||||
|
'route' => 'chill_person_residential_address_list',
|
||||||
|
'routeParameters' => [
|
||||||
|
'id' => $parameters['person']->getId(),
|
||||||
|
],
|
||||||
|
])
|
||||||
|
->setExtras([
|
||||||
|
'order' => 60,
|
||||||
|
]);
|
||||||
|
|
||||||
$menu->addChild($this->translator->trans('household.person history'), [
|
$menu->addChild($this->translator->trans('household.person history'), [
|
||||||
'route' => 'chill_person_household_person_history',
|
'route' => 'chill_person_household_person_history',
|
||||||
'routeParameters' => [
|
'routeParameters' => [
|
||||||
|
54
src/Bundle/ChillPersonBundle/Menu/UserMenuBuilder.php
Normal file
54
src/Bundle/ChillPersonBundle/Menu/UserMenuBuilder.php
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Chill\PersonBundle\Menu;
|
||||||
|
|
||||||
|
use Chill\MainBundle\Routing\LocalMenuBuilderInterface;
|
||||||
|
use Knp\Menu\MenuItem;
|
||||||
|
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
|
||||||
|
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||||
|
|
||||||
|
class UserMenuBuilder implements LocalMenuBuilderInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var AuthorizationCheckerInterface
|
||||||
|
*/
|
||||||
|
public $authorizationChecker;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var TranslatorInterface
|
||||||
|
*/
|
||||||
|
public $translator;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
AuthorizationCheckerInterface $authorizationChecker
|
||||||
|
) {
|
||||||
|
$this->authorizationChecker = $authorizationChecker;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function buildMenu($menuId, MenuItem $menu, array $parameters)
|
||||||
|
{
|
||||||
|
if ($this->authorizationChecker->isGranted('ROLE_USER')) {
|
||||||
|
$menu->addChild('My accompanying periods', [
|
||||||
|
'route' => 'chill_person_accompanying_period_user',
|
||||||
|
])
|
||||||
|
->setExtras([
|
||||||
|
'order' => 20,
|
||||||
|
'icon' => 'tasks',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getMenuIds(): array
|
||||||
|
{
|
||||||
|
return ['user'];
|
||||||
|
}
|
||||||
|
}
|
@ -11,9 +11,12 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Chill\PersonBundle\Repository\AccompanyingPeriod;
|
namespace Chill\PersonBundle\Repository\AccompanyingPeriod;
|
||||||
|
|
||||||
|
use Chill\MainBundle\Entity\User;
|
||||||
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluation;
|
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluation;
|
||||||
|
use DateTimeImmutable;
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
use Doctrine\ORM\EntityRepository;
|
use Doctrine\ORM\EntityRepository;
|
||||||
|
use Doctrine\ORM\QueryBuilder;
|
||||||
use Doctrine\Persistence\ObjectRepository;
|
use Doctrine\Persistence\ObjectRepository;
|
||||||
|
|
||||||
class AccompanyingPeriodWorkEvaluationRepository implements ObjectRepository
|
class AccompanyingPeriodWorkEvaluationRepository implements ObjectRepository
|
||||||
@ -25,6 +28,12 @@ class AccompanyingPeriodWorkEvaluationRepository implements ObjectRepository
|
|||||||
$this->repository = $entityManager->getRepository(AccompanyingPeriodWorkEvaluation::class);
|
$this->repository = $entityManager->getRepository(AccompanyingPeriodWorkEvaluation::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function countNearMaxDateByUser(User $user): int
|
||||||
|
{
|
||||||
|
return $this->buildQueryNearMaxDateByUser($user)
|
||||||
|
->select('count(e)')->getQuery()->getSingleScalarResult();
|
||||||
|
}
|
||||||
|
|
||||||
public function find($id): ?AccompanyingPeriodWorkEvaluation
|
public function find($id): ?AccompanyingPeriodWorkEvaluation
|
||||||
{
|
{
|
||||||
return $this->repository->find($id);
|
return $this->repository->find($id);
|
||||||
@ -39,8 +48,8 @@ class AccompanyingPeriodWorkEvaluationRepository implements ObjectRepository
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param null|mixed $limit
|
* @param int $limit
|
||||||
* @param null|mixed $offset
|
* @param int $offset
|
||||||
*
|
*
|
||||||
* @return array|AccompanyingPeriodWorkEvaluation[]
|
* @return array|AccompanyingPeriodWorkEvaluation[]
|
||||||
*/
|
*/
|
||||||
@ -49,13 +58,45 @@ class AccompanyingPeriodWorkEvaluationRepository implements ObjectRepository
|
|||||||
return $this->repository->findBy($criteria, $orderBy, $limit, $offset);
|
return $this->repository->findBy($criteria, $orderBy, $limit, $offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function findOneBy(array $criteria): ?AccompanyingPeriodWorkEvaluation
|
public function findNearMaxDateByUser(User $user, int $limit = 20, int $offset = 0): array
|
||||||
{
|
{
|
||||||
return $this->findOneBy($criteria);
|
return $this->buildQueryNearMaxDateByUser($user)
|
||||||
|
->select('e')
|
||||||
|
->setFirstResult($offset)
|
||||||
|
->setMaxResults($limit)
|
||||||
|
->getQuery()
|
||||||
|
->getResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getClassName()
|
public function findOneBy(array $criteria): ?AccompanyingPeriodWorkEvaluation
|
||||||
|
{
|
||||||
|
return $this->repository->findOneBy($criteria);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getClassName(): string
|
||||||
{
|
{
|
||||||
return AccompanyingPeriodWorkEvaluation::class;
|
return AccompanyingPeriodWorkEvaluation::class;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function buildQueryNearMaxDateByUser(User $user): QueryBuilder
|
||||||
|
{
|
||||||
|
$qb = $this->repository->createQueryBuilder('e');
|
||||||
|
|
||||||
|
$qb
|
||||||
|
->join('e.accompanyingPeriodWork', 'work')
|
||||||
|
->join('work.accompanyingPeriod', 'period')
|
||||||
|
->where(
|
||||||
|
$qb->expr()->andX(
|
||||||
|
$qb->expr()->eq('period.user', ':user'),
|
||||||
|
$qb->expr()->isNull('e.endDate'),
|
||||||
|
$qb->expr()->gte(':now', $qb->expr()->diff('e.maxDate', 'e.warningInterval'))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
->setParameters([
|
||||||
|
'user' => $user,
|
||||||
|
'now' => new DateTimeImmutable('now'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
return $qb;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,10 +11,14 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Chill\PersonBundle\Repository\AccompanyingPeriod;
|
namespace Chill\PersonBundle\Repository\AccompanyingPeriod;
|
||||||
|
|
||||||
|
use Chill\MainBundle\Entity\User;
|
||||||
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||||
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWork;
|
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWork;
|
||||||
|
use Chill\PersonBundle\Entity\SocialWork\SocialAction;
|
||||||
|
use DateTimeImmutable;
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
use Doctrine\ORM\EntityRepository;
|
use Doctrine\ORM\EntityRepository;
|
||||||
|
use Doctrine\ORM\QueryBuilder;
|
||||||
use Doctrine\Persistence\ObjectRepository;
|
use Doctrine\Persistence\ObjectRepository;
|
||||||
|
|
||||||
final class AccompanyingPeriodWorkRepository implements ObjectRepository
|
final class AccompanyingPeriodWorkRepository implements ObjectRepository
|
||||||
@ -41,6 +45,12 @@ final class AccompanyingPeriodWorkRepository implements ObjectRepository
|
|||||||
->getSingleScalarResult();
|
->getSingleScalarResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function countNearEndDateByUser(User $user, DateTimeImmutable $since, DateTimeImmutable $until): int
|
||||||
|
{
|
||||||
|
return $this->buildQueryNearEndDateByUser($user, $since, $until)
|
||||||
|
->select('count(w)')->getQuery()->getSingleScalarResult();
|
||||||
|
}
|
||||||
|
|
||||||
public function find($id): ?AccompanyingPeriodWork
|
public function find($id): ?AccompanyingPeriodWork
|
||||||
{
|
{
|
||||||
return $this->repository->find($id);
|
return $this->repository->find($id);
|
||||||
@ -68,6 +78,16 @@ final class AccompanyingPeriodWorkRepository implements ObjectRepository
|
|||||||
return $this->repository->findByAccompanyingPeriod($period, $orderBy, $limit, $offset);
|
return $this->repository->findByAccompanyingPeriod($period, $orderBy, $limit, $offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function findNearEndDateByUser(User $user, DateTimeImmutable $since, DateTimeImmutable $until, int $limit = 20, int $offset = 0): array
|
||||||
|
{
|
||||||
|
return $this->buildQueryNearEndDateByUser($user, $since, $until)
|
||||||
|
->select('w')
|
||||||
|
->setFirstResult($offset)
|
||||||
|
->setMaxResults($limit)
|
||||||
|
->getQuery()
|
||||||
|
->getResult();
|
||||||
|
}
|
||||||
|
|
||||||
public function findOneBy(array $criteria): ?AccompanyingPeriodWork
|
public function findOneBy(array $criteria): ?AccompanyingPeriodWork
|
||||||
{
|
{
|
||||||
return $this->repository->findOneBy($criteria);
|
return $this->repository->findOneBy($criteria);
|
||||||
@ -78,22 +98,6 @@ final class AccompanyingPeriodWorkRepository implements ObjectRepository
|
|||||||
return AccompanyingPeriodWork::class;
|
return AccompanyingPeriodWork::class;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function toDelete()
|
|
||||||
{
|
|
||||||
$qb = $this->buildQueryBySocialActionWithDescendants($action);
|
|
||||||
$qb->select('g');
|
|
||||||
|
|
||||||
foreach ($orderBy as $sort => $order) {
|
|
||||||
$qb->addOrderBy('g.' . $sort, $order);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $qb
|
|
||||||
->setMaxResults($limit)
|
|
||||||
->setFirstResult($offset)
|
|
||||||
->getQuery()
|
|
||||||
->getResult();
|
|
||||||
}
|
|
||||||
|
|
||||||
private function buildQueryBySocialActionWithDescendants(SocialAction $action): QueryBuilder
|
private function buildQueryBySocialActionWithDescendants(SocialAction $action): QueryBuilder
|
||||||
{
|
{
|
||||||
$actions = $action->getDescendantsWithThis();
|
$actions = $action->getDescendantsWithThis();
|
||||||
@ -103,12 +107,34 @@ final class AccompanyingPeriodWorkRepository implements ObjectRepository
|
|||||||
$orx = $qb->expr()->orX();
|
$orx = $qb->expr()->orX();
|
||||||
$i = 0;
|
$i = 0;
|
||||||
|
|
||||||
foreach ($actions as $action) {
|
foreach ($actions as $a) {
|
||||||
$orx->add(":action_{$i} MEMBER OF g.socialActions");
|
$orx->add(":action_{$i} MEMBER OF g.socialActions");
|
||||||
$qb->setParameter("action_{$i}", $action);
|
$qb->setParameter("action_{$i}", $a);
|
||||||
}
|
}
|
||||||
$qb->where($orx);
|
$qb->where($orx);
|
||||||
|
|
||||||
return $qb;
|
return $qb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function buildQueryNearEndDateByUser(User $user, DateTimeImmutable $since, DateTimeImmutable $until): QueryBuilder
|
||||||
|
{
|
||||||
|
$qb = $this->repository->createQueryBuilder('w');
|
||||||
|
|
||||||
|
$qb
|
||||||
|
->join('w.accompanyingPeriod', 'period')
|
||||||
|
->where(
|
||||||
|
$qb->expr()->andX(
|
||||||
|
$qb->expr()->eq('period.user', ':user'),
|
||||||
|
$qb->expr()->gte('w.endDate', ':since'),
|
||||||
|
$qb->expr()->lte('w.startDate', ':until')
|
||||||
|
)
|
||||||
|
)
|
||||||
|
->setParameters([
|
||||||
|
'user' => $user,
|
||||||
|
'since' => $since,
|
||||||
|
'until' => $until,
|
||||||
|
]);
|
||||||
|
|
||||||
|
return $qb;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,9 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Chill\PersonBundle\Repository;
|
namespace Chill\PersonBundle\Repository;
|
||||||
|
|
||||||
|
use Chill\MainBundle\Entity\User;
|
||||||
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||||
|
use DateTimeImmutable;
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
use Doctrine\ORM\EntityRepository;
|
use Doctrine\ORM\EntityRepository;
|
||||||
use Doctrine\ORM\QueryBuilder;
|
use Doctrine\ORM\QueryBuilder;
|
||||||
@ -26,6 +28,18 @@ final class AccompanyingPeriodRepository implements ObjectRepository
|
|||||||
$this->repository = $entityManager->getRepository(AccompanyingPeriod::class);
|
$this->repository = $entityManager->getRepository(AccompanyingPeriod::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function countByRecentUserHistory(User $user, DateTimeImmutable $since): int
|
||||||
|
{
|
||||||
|
$qb = $this->buildQueryByRecentUserHistory($user, $since);
|
||||||
|
|
||||||
|
return $qb->select('count(a)')->getQuery()->getSingleScalarResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function countBy(array $criteria): int
|
||||||
|
{
|
||||||
|
return $this->repository->count($criteria);
|
||||||
|
}
|
||||||
|
|
||||||
public function createQueryBuilder(string $alias, ?string $indexBy = null): QueryBuilder
|
public function createQueryBuilder(string $alias, ?string $indexBy = null): QueryBuilder
|
||||||
{
|
{
|
||||||
return $this->repository->createQueryBuilder($alias, $indexBy);
|
return $this->repository->createQueryBuilder($alias, $indexBy);
|
||||||
@ -49,6 +63,21 @@ final class AccompanyingPeriodRepository implements ObjectRepository
|
|||||||
return $this->repository->findBy($criteria, $orderBy, $limit, $offset);
|
return $this->repository->findBy($criteria, $orderBy, $limit, $offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array|AccompanyingPeriod[]
|
||||||
|
*/
|
||||||
|
public function findByRecentUserHistory(User $user, DateTimeImmutable $since, ?int $limit = 20, ?int $offset = 0): array
|
||||||
|
{
|
||||||
|
$qb = $this->buildQueryByRecentUserHistory($user, $since);
|
||||||
|
|
||||||
|
return $qb->select('a')
|
||||||
|
->distinct(true)
|
||||||
|
->getQuery()
|
||||||
|
->setMaxResults($limit)
|
||||||
|
->setFirstResult($offset)
|
||||||
|
->getResult();
|
||||||
|
}
|
||||||
|
|
||||||
public function findOneBy(array $criteria): ?AccompanyingPeriod
|
public function findOneBy(array $criteria): ?AccompanyingPeriod
|
||||||
{
|
{
|
||||||
return $this->findOneBy($criteria);
|
return $this->findOneBy($criteria);
|
||||||
@ -58,4 +87,19 @@ final class AccompanyingPeriodRepository implements ObjectRepository
|
|||||||
{
|
{
|
||||||
return AccompanyingPeriod::class;
|
return AccompanyingPeriod::class;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function buildQueryByRecentUserHistory(User $user, DateTimeImmutable $since): QueryBuilder
|
||||||
|
{
|
||||||
|
$qb = $this->repository->createQueryBuilder('a');
|
||||||
|
|
||||||
|
$qb
|
||||||
|
->join('a.userHistories', 'userHistory')
|
||||||
|
->where($qb->expr()->eq('a.user', ':user'))
|
||||||
|
->andWhere($qb->expr()->gte('userHistory.startDate', ':since'))
|
||||||
|
->andWhere($qb->expr()->isNull('userHistory.endDate'))
|
||||||
|
->setParameter('user', $user)
|
||||||
|
->setParameter('since', $since);
|
||||||
|
|
||||||
|
return $qb;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -80,6 +80,8 @@ div.dashboard {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
div.dashboard,
|
div.dashboard,
|
||||||
|
h4.badge-title,
|
||||||
|
h3.badge-title,
|
||||||
h2.badge-title {
|
h2.badge-title {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
@ -128,6 +130,8 @@ ul.columns { // XS:1 SM:2 MD:1 LG:2 XL:2 XXL:2
|
|||||||
/// dashboard_like_badge in AccompanyingCourse Work list Page
|
/// dashboard_like_badge in AccompanyingCourse Work list Page
|
||||||
div[class*='accompanying_course_work'] {
|
div[class*='accompanying_course_work'] {
|
||||||
div.dashboard,
|
div.dashboard,
|
||||||
|
h4.badge-title,
|
||||||
|
h3.badge-title,
|
||||||
h2.badge-title {
|
h2.badge-title {
|
||||||
span.title_label {
|
span.title_label {
|
||||||
// Calculate same color then border:groove
|
// Calculate same color then border:groove
|
||||||
@ -143,6 +147,8 @@ div[class*='accompanying_course_work'] {
|
|||||||
/// dashboard_like_badge in Activities on resume page
|
/// dashboard_like_badge in Activities on resume page
|
||||||
div[class*='activity-'] {
|
div[class*='activity-'] {
|
||||||
div.dashboard,
|
div.dashboard,
|
||||||
|
h4.badge-title,
|
||||||
|
h3.badge-title,
|
||||||
h2.badge-title {
|
h2.badge-title {
|
||||||
span.title_label {
|
span.title_label {
|
||||||
// Calculate same color then border:groove
|
// Calculate same color then border:groove
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
<scopes></scopes>
|
<scopes></scopes>
|
||||||
<referrer></referrer>
|
<referrer></referrer>
|
||||||
<resources></resources>
|
<resources></resources>
|
||||||
|
<start-date v-if="accompanyingCourse.step === 'CONFIRMED'"></start-date>
|
||||||
<comment v-if="accompanyingCourse.step === 'DRAFT'"></comment>
|
<comment v-if="accompanyingCourse.step === 'DRAFT'"></comment>
|
||||||
<confirm v-if="accompanyingCourse.step === 'DRAFT'"></confirm>
|
<confirm v-if="accompanyingCourse.step === 'DRAFT'"></confirm>
|
||||||
|
|
||||||
@ -39,6 +40,7 @@ import Referrer from './components/Referrer.vue';
|
|||||||
import Resources from './components/Resources.vue';
|
import Resources from './components/Resources.vue';
|
||||||
import Comment from './components/Comment.vue';
|
import Comment from './components/Comment.vue';
|
||||||
import Confirm from './components/Confirm.vue';
|
import Confirm from './components/Confirm.vue';
|
||||||
|
import StartDate from './components/StartDate.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'App',
|
name: 'App',
|
||||||
@ -56,6 +58,7 @@ export default {
|
|||||||
Resources,
|
Resources,
|
||||||
Comment,
|
Comment,
|
||||||
Confirm,
|
Confirm,
|
||||||
|
StartDate
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState([
|
...mapState([
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
<i class="fa fa-home fa-fw text-light" :title="$t('persons_associated.show_household_number', { id: h.id })"></i>
|
<i class="fa fa-home fa-fw text-light" :title="$t('persons_associated.show_household_number', { id: h.id })"></i>
|
||||||
</a>
|
</a>
|
||||||
<span v-for="person in h.persons" class="me-1" :key="person.id">
|
<span v-for="person in h.persons" class="me-1" :key="person.id">
|
||||||
<on-the-fly :type="person.type" :id="person.id" :buttonText="person.text" :displayBadge="'true' === 'true'" action="show"></on-the-fly>
|
<on-the-fly :type="person.type" :id="person.id" :buttonText="person.textAge" :displayBadge="'true' === 'true'" action="show"></on-the-fly>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
:value="p.person.id"
|
:value="p.person.id"
|
||||||
/>
|
/>
|
||||||
<label class="form-check-label">
|
<label class="form-check-label">
|
||||||
{{ p.person.text }}
|
<person-text :person="p.person"></person-text>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<input type="hidden" name="expand_suggestions" value="true">
|
<input type="hidden" name="expand_suggestions" value="true">
|
||||||
@ -50,9 +50,9 @@
|
|||||||
<div v-if="suggestedPersons.length > 0">
|
<div v-if="suggestedPersons.length > 0">
|
||||||
<ul class="list-suggest add-items inline">
|
<ul class="list-suggest add-items inline">
|
||||||
<li v-for="p in suggestedPersons" :key="p.id" @click="addSuggestedPerson(p)">
|
<li v-for="p in suggestedPersons" :key="p.id" @click="addSuggestedPerson(p)">
|
||||||
<span>{{ p.text }}</span>
|
<person-text :person="p"></person-text>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
@ -76,12 +76,14 @@
|
|||||||
import {mapGetters, mapState} from 'vuex';
|
import {mapGetters, mapState} from 'vuex';
|
||||||
import ParticipationItem from "./PersonsAssociated/ParticipationItem.vue";
|
import ParticipationItem from "./PersonsAssociated/ParticipationItem.vue";
|
||||||
import AddPersons from 'ChillPersonAssets/vuejs/_components/AddPersons.vue';
|
import AddPersons from 'ChillPersonAssets/vuejs/_components/AddPersons.vue';
|
||||||
|
import PersonText from 'ChillPersonAssets/vuejs/_components/Entity/PersonText.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'PersonsAssociated',
|
name: 'PersonsAssociated',
|
||||||
components: {
|
components: {
|
||||||
ParticipationItem,
|
ParticipationItem,
|
||||||
AddPersons
|
AddPersons,
|
||||||
|
PersonText
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
@ -110,15 +112,15 @@ export default {
|
|||||||
)
|
)
|
||||||
// filter persons appearing twice in requestor and resources
|
// filter persons appearing twice in requestor and resources
|
||||||
.filter(
|
.filter(
|
||||||
(e, index, suggested) => {
|
(e, index, suggested) => {
|
||||||
for (let i = 0; i < suggested.length; i = i+1) {
|
for (let i = 0; i < suggested.length; i = i+1) {
|
||||||
if (i < index && e.id === suggested[i].id) {
|
if (i < index && e.id === suggested[i].id) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}),
|
}),
|
||||||
...mapGetters([
|
...mapGetters([
|
||||||
|
@ -28,7 +28,7 @@
|
|||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li><on-the-fly :type="participation.person.type" :id="participation.person.id" action="show"></on-the-fly></li>
|
<li><on-the-fly :type="participation.person.type" :id="participation.person.id" action="show"></on-the-fly></li>
|
||||||
<li><on-the-fly :type="participation.person.type" :id="participation.person.id" action="edit" @saveFormOnTheFly="saveFormOnTheFly"></on-the-fly></li>
|
<li><on-the-fly :type="participation.person.type" :id="participation.person.id" action="edit" @saveFormOnTheFly="saveFormOnTheFly" :canCloseModal="canCloseOnTheFlyModal"></on-the-fly></li>
|
||||||
<li>
|
<li>
|
||||||
<button v-if="!participation.endDate"
|
<button v-if="!participation.endDate"
|
||||||
class="btn btn-sm btn-remove"
|
class="btn btn-sm btn-remove"
|
||||||
@ -63,6 +63,7 @@ import OnTheFly from 'ChillMainAssets/vuejs/OnTheFly/components/OnTheFly.vue';
|
|||||||
import ButtonLocation from '../ButtonLocation.vue';
|
import ButtonLocation from '../ButtonLocation.vue';
|
||||||
import PersonRenderBox from 'ChillPersonAssets/vuejs/_components/Entity/PersonRenderBox.vue';
|
import PersonRenderBox from 'ChillPersonAssets/vuejs/_components/Entity/PersonRenderBox.vue';
|
||||||
import Modal from 'ChillMainAssets/vuejs/_components/Modal';
|
import Modal from 'ChillMainAssets/vuejs/_components/Modal';
|
||||||
|
import { makeFetch } from 'ChillMainAssets/lib/api/apiMethods';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'ParticipationItem',
|
name: 'ParticipationItem',
|
||||||
@ -88,7 +89,8 @@ export default {
|
|||||||
addAge: false,
|
addAge: false,
|
||||||
hLevel: 1
|
hLevel: 1
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
canCloseOnTheFlyModal: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@ -110,14 +112,53 @@ export default {
|
|||||||
saveFormOnTheFly(payload) {
|
saveFormOnTheFly(payload) {
|
||||||
console.log('saveFormOnTheFly: type', payload.type, ', data', payload.data);
|
console.log('saveFormOnTheFly: type', payload.type, ', data', payload.data);
|
||||||
payload.target = 'participation';
|
payload.target = 'participation';
|
||||||
this.$store.dispatch('patchOnTheFly', payload)
|
|
||||||
.catch(({name, violations}) => {
|
let body = { type: payload.type };
|
||||||
if (name === 'ValidationException' || name === 'AccessException') {
|
if (payload.type === 'person') {
|
||||||
violations.forEach((violation) => this.$toast.open({message: violation}));
|
body.firstName = payload.data.firstName;
|
||||||
} else {
|
body.lastName = payload.data.lastName;
|
||||||
this.$toast.open({message: 'An error occurred'})
|
if (payload.data.birthdate !== null) { body.birthdate = payload.data.birthdate; }
|
||||||
}
|
body.phonenumber = payload.data.phonenumber;
|
||||||
});
|
body.mobilenumber = payload.data.mobilenumber;
|
||||||
|
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.canCloseOnTheFlyModal = true;
|
||||||
|
})
|
||||||
|
.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.phonenumber;
|
||||||
|
body.address = { id: payload.data.address.address_id };
|
||||||
|
|
||||||
|
makeFetch('PATCH', `/api/1.0/third-party/third-party/${payload.data.id}.json`, body)
|
||||||
|
.then(response => {
|
||||||
|
this.$store.dispatch('addThirdparty', { target: payload.target, body: response })
|
||||||
|
this.canCloseOnTheFlyModal = true;
|
||||||
|
})
|
||||||
|
.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'});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,8 @@
|
|||||||
addInfo: true,
|
addInfo: true,
|
||||||
hLevel: 3,
|
hLevel: 3,
|
||||||
isMultiline: true,
|
isMultiline: true,
|
||||||
isConfidential: false
|
isConfidential: false,
|
||||||
|
addAge: true,
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<template v-slot:record-actions>
|
<template v-slot:record-actions>
|
||||||
@ -113,7 +114,7 @@
|
|||||||
<template v-slot:record-actions>
|
<template v-slot:record-actions>
|
||||||
<ul class="record_actions">
|
<ul class="record_actions">
|
||||||
<li><on-the-fly :type="accompanyingCourse.requestor.type" :id="accompanyingCourse.requestor.id" action="show"></on-the-fly></li>
|
<li><on-the-fly :type="accompanyingCourse.requestor.type" :id="accompanyingCourse.requestor.id" action="show"></on-the-fly></li>
|
||||||
<li><on-the-fly :type="accompanyingCourse.requestor.type" :id="accompanyingCourse.requestor.id" action="edit" @saveFormOnTheFly="saveFormOnTheFly"></on-the-fly></li>
|
<li><on-the-fly :type="accompanyingCourse.requestor.type" :id="accompanyingCourse.requestor.id" action="edit" @saveFormOnTheFly="saveFormOnTheFly" :canCloseModal="canCloseOnTheFlyModal"></on-the-fly></li>
|
||||||
</ul>
|
</ul>
|
||||||
</template>
|
</template>
|
||||||
</person-render-box>
|
</person-render-box>
|
||||||
@ -136,9 +137,10 @@
|
|||||||
<div v-if="accompanyingCourse.requestor === null && suggestedEntities.length > 0">
|
<div v-if="accompanyingCourse.requestor === null && suggestedEntities.length > 0">
|
||||||
<ul class="list-suggest add-items inline">
|
<ul class="list-suggest add-items inline">
|
||||||
<li v-for="p in suggestedEntities" :key="uniqueId(p)" @click="addSuggestedEntity(p)">
|
<li v-for="p in suggestedEntities" :key="uniqueId(p)" @click="addSuggestedEntity(p)">
|
||||||
<span>{{ p.text }}</span>
|
<person-text v-if="p.type === 'person'" :person="p"></person-text>
|
||||||
</li>
|
<span v-else>{{ p.text }}</span>
|
||||||
</ul>
|
</li>
|
||||||
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
@ -162,6 +164,9 @@ import PersonRenderBox from '../../_components/Entity/PersonRenderBox.vue';
|
|||||||
import ThirdPartyRenderBox from 'ChillThirdPartyAssets/vuejs/_components/Entity/ThirdPartyRenderBox.vue';
|
import ThirdPartyRenderBox from 'ChillThirdPartyAssets/vuejs/_components/Entity/ThirdPartyRenderBox.vue';
|
||||||
import Confidential from 'ChillMainAssets/vuejs/_components/Confidential.vue';
|
import Confidential from 'ChillMainAssets/vuejs/_components/Confidential.vue';
|
||||||
import { mapState } from 'vuex';
|
import { mapState } from 'vuex';
|
||||||
|
import { makeFetch } from 'ChillMainAssets/lib/api/apiMethods';
|
||||||
|
import PersonText from 'ChillPersonAssets/vuejs/_components/Entity/PersonText.vue';
|
||||||
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Requestor',
|
name: 'Requestor',
|
||||||
@ -170,7 +175,8 @@ export default {
|
|||||||
OnTheFly,
|
OnTheFly,
|
||||||
PersonRenderBox,
|
PersonRenderBox,
|
||||||
ThirdPartyRenderBox,
|
ThirdPartyRenderBox,
|
||||||
Confidential
|
Confidential,
|
||||||
|
PersonText
|
||||||
},
|
},
|
||||||
props: ['isAnonymous'],
|
props: ['isAnonymous'],
|
||||||
data() {
|
data() {
|
||||||
@ -182,7 +188,8 @@ export default {
|
|||||||
priority: null,
|
priority: null,
|
||||||
uniq: true,
|
uniq: true,
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
canCloseOnTheFlyModal: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@ -246,14 +253,52 @@ export default {
|
|||||||
saveFormOnTheFly(payload) {
|
saveFormOnTheFly(payload) {
|
||||||
console.log('saveFormOnTheFly: type', payload.type, ', data', payload.data);
|
console.log('saveFormOnTheFly: type', payload.type, ', data', payload.data);
|
||||||
payload.target = 'requestor';
|
payload.target = 'requestor';
|
||||||
this.$store.dispatch('patchOnTheFly', payload)
|
|
||||||
.catch(({name, violations}) => {
|
let body = { type: payload.type };
|
||||||
if (name === 'ValidationException' || name === 'AccessException') {
|
if (payload.type === 'person') {
|
||||||
violations.forEach((violation) => this.$toast.open({message: violation}));
|
body.firstName = payload.data.firstName;
|
||||||
} else {
|
body.lastName = payload.data.lastName;
|
||||||
this.$toast.open({message: 'An error occurred'})
|
if (payload.data.birthdate !== null) { body.birthdate = payload.data.birthdate; }
|
||||||
}
|
body.phonenumber = payload.data.phonenumber;
|
||||||
});
|
body.mobilenumber = payload.data.mobilenumber;
|
||||||
|
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.canCloseOnTheFlyModal = true;
|
||||||
|
})
|
||||||
|
.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.phonenumber;
|
||||||
|
body.address = { id: payload.data.address.address_id };
|
||||||
|
|
||||||
|
makeFetch('PATCH', `/api/1.0/third-party/third-party/${payload.data.id}.json`, body)
|
||||||
|
.then(response => {
|
||||||
|
this.$store.dispatch('addThirdparty', { target: payload.target, body: response })
|
||||||
|
this.canCloseOnTheFlyModal = true;
|
||||||
|
})
|
||||||
|
.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) {
|
addSuggestedEntity(e) {
|
||||||
this.$store.dispatch('addRequestor', { result: e, type: e.type })
|
this.$store.dispatch('addRequestor', { result: e, type: e.type })
|
||||||
|
@ -22,7 +22,8 @@
|
|||||||
<div v-if="suggestedEntities.length > 0">
|
<div v-if="suggestedEntities.length > 0">
|
||||||
<ul class="list-suggest add-items inline">
|
<ul class="list-suggest add-items inline">
|
||||||
<li v-for="p in suggestedEntities" :key="uniqueId(p)" @click="addSuggestedEntity(p)">
|
<li v-for="p in suggestedEntities" :key="uniqueId(p)" @click="addSuggestedEntity(p)">
|
||||||
<span>{{ p.text }}</span>
|
<person-text v-if="p.type === 'person'" :person="p"></person-text>
|
||||||
|
<span v-else>{{ p.text }}</span>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
@ -45,12 +46,15 @@
|
|||||||
import { mapState } from 'vuex';
|
import { mapState } from 'vuex';
|
||||||
import AddPersons from 'ChillPersonAssets/vuejs/_components/AddPersons.vue';
|
import AddPersons from 'ChillPersonAssets/vuejs/_components/AddPersons.vue';
|
||||||
import ResourceItem from './Resources/ResourceItem.vue';
|
import ResourceItem from './Resources/ResourceItem.vue';
|
||||||
|
import PersonText from 'ChillPersonAssets/vuejs/_components/Entity/PersonText.vue';
|
||||||
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Resources',
|
name: 'Resources',
|
||||||
components: {
|
components: {
|
||||||
AddPersons,
|
AddPersons,
|
||||||
ResourceItem
|
ResourceItem,
|
||||||
|
PersonText
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
@ -34,7 +34,8 @@
|
|||||||
:type="resource.resource.type"
|
:type="resource.resource.type"
|
||||||
:id="resource.resource.id"
|
:id="resource.resource.id"
|
||||||
action="edit"
|
action="edit"
|
||||||
@saveFormOnTheFly="saveFormOnTheFly">
|
@saveFormOnTheFly="saveFormOnTheFly"
|
||||||
|
:canCloseModal="canCloseOnTheFlyModal">
|
||||||
</on-the-fly>
|
</on-the-fly>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
@ -80,7 +81,8 @@
|
|||||||
:type="resource.resource.type"
|
:type="resource.resource.type"
|
||||||
:id="resource.resource.id"
|
:id="resource.resource.id"
|
||||||
action="edit"
|
action="edit"
|
||||||
@saveFormOnTheFly="saveFormOnTheFly">
|
@saveFormOnTheFly="saveFormOnTheFly"
|
||||||
|
:canCloseModal="canCloseOnTheFlyModal">
|
||||||
</on-the-fly>
|
</on-the-fly>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
@ -101,6 +103,7 @@ import ButtonLocation from '../ButtonLocation.vue';
|
|||||||
import PersonRenderBox from 'ChillPersonAssets/vuejs/_components/Entity/PersonRenderBox.vue';
|
import PersonRenderBox from 'ChillPersonAssets/vuejs/_components/Entity/PersonRenderBox.vue';
|
||||||
import ThirdPartyRenderBox from 'ChillThirdPartyAssets/vuejs/_components/Entity/ThirdPartyRenderBox.vue';
|
import ThirdPartyRenderBox from 'ChillThirdPartyAssets/vuejs/_components/Entity/ThirdPartyRenderBox.vue';
|
||||||
import WriteComment from './WriteComment';
|
import WriteComment from './WriteComment';
|
||||||
|
import { makeFetch } from 'ChillMainAssets/lib/api/apiMethods';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'ResourceItem',
|
name: 'ResourceItem',
|
||||||
@ -113,6 +116,11 @@ export default {
|
|||||||
},
|
},
|
||||||
props: ['resource'],
|
props: ['resource'],
|
||||||
emits: ['remove'],
|
emits: ['remove'],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
canCloseOnTheFlyModal: false
|
||||||
|
}
|
||||||
|
},
|
||||||
computed: {
|
computed: {
|
||||||
parent() {
|
parent() {
|
||||||
return {
|
return {
|
||||||
@ -136,14 +144,52 @@ export default {
|
|||||||
saveFormOnTheFly(payload) {
|
saveFormOnTheFly(payload) {
|
||||||
console.log('saveFormOnTheFly: type', payload.type, ', data', payload.data);
|
console.log('saveFormOnTheFly: type', payload.type, ', data', payload.data);
|
||||||
payload.target = 'resource';
|
payload.target = 'resource';
|
||||||
this.$store.dispatch('patchOnTheFly', payload)
|
|
||||||
.catch(({name, violations}) => {
|
let body = { type: payload.type };
|
||||||
if (name === 'ValidationException' || name === 'AccessException') {
|
if (payload.type === 'person') {
|
||||||
violations.forEach((violation) => this.$toast.open({message: violation}));
|
body.firstName = payload.data.firstName;
|
||||||
} else {
|
body.lastName = payload.data.lastName;
|
||||||
this.$toast.open({message: 'An error occurred'})
|
if (payload.data.birthdate !== null) { body.birthdate = payload.data.birthdate; }
|
||||||
}
|
body.phonenumber = payload.data.phonenumber;
|
||||||
});
|
body.mobilenumber = payload.data.mobilenumber;
|
||||||
|
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.canCloseOnTheFlyModal = true;
|
||||||
|
})
|
||||||
|
.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.phonenumber;
|
||||||
|
body.address = { id: payload.data.address.address_id };
|
||||||
|
|
||||||
|
makeFetch('PATCH', `/api/1.0/third-party/third-party/${payload.data.id}.json`, body)
|
||||||
|
.then(response => {
|
||||||
|
this.$store.dispatch('addThirdparty', { target: payload.target, body: response })
|
||||||
|
this.canCloseOnTheFlyModal = true;
|
||||||
|
})
|
||||||
|
.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) {
|
updateComment(resource) {
|
||||||
console.log('updateComment', resource);
|
console.log('updateComment', resource);
|
||||||
|
@ -0,0 +1,46 @@
|
|||||||
|
<template>
|
||||||
|
<div class="vue-component">
|
||||||
|
<h2><a id="section-110"></a>
|
||||||
|
{{ $t('startdate.change') }}
|
||||||
|
</h2>
|
||||||
|
<div>
|
||||||
|
<div class="mb-3 row">
|
||||||
|
<label class="col-form-label col-sm-4">{{ $t('startdate.date') }}</label>
|
||||||
|
<div class="col-sm-8">
|
||||||
|
<input class="form-control" type="date" v-model="startDate" @change="updateStartDate" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
import { datetimeToISO, dateToISO, ISOToDate, ISOToDatetime} from 'ChillMainAssets/chill/js/date.js';
|
||||||
|
import { mapState, mapGetters } from 'vuex';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'startDate',
|
||||||
|
methods: {
|
||||||
|
updateStartDate(event) {
|
||||||
|
const date = event.target.value;
|
||||||
|
// console.log(date)
|
||||||
|
this.$store.dispatch('updateStartDate', date)
|
||||||
|
.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({
|
||||||
|
startDate: state => dateToISO(ISOToDatetime(state.accompanyingCourse.openingDate.datetime))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
@ -13,7 +13,7 @@ const root = window.vueRootComponent;
|
|||||||
* Load all App component, for AccompanyingCourse edition page
|
* Load all App component, for AccompanyingCourse edition page
|
||||||
*/
|
*/
|
||||||
if (root === 'app') {
|
if (root === 'app') {
|
||||||
initPromise.then(store => {
|
initPromise(root).then(store => {
|
||||||
|
|
||||||
const i18n = _createI18n(appMessages);
|
const i18n = _createI18n(appMessages);
|
||||||
|
|
||||||
@ -37,7 +37,7 @@ if (root === 'app') {
|
|||||||
* Load only Banner sub-component, for all others AccompanyingCourse page
|
* Load only Banner sub-component, for all others AccompanyingCourse page
|
||||||
*/
|
*/
|
||||||
if (root === 'banner') {
|
if (root === 'banner') {
|
||||||
initPromise.then(store => {
|
initPromise(root).then(store => {
|
||||||
|
|
||||||
const i18n = _createI18n(appMessages);
|
const i18n = _createI18n(appMessages);
|
||||||
|
|
||||||
|
@ -151,6 +151,10 @@ const appMessages = {
|
|||||||
placeholder: "Choisir un métier",
|
placeholder: "Choisir un métier",
|
||||||
not_valid: "Sélectionnez un métier du référent"
|
not_valid: "Sélectionnez un métier du référent"
|
||||||
},
|
},
|
||||||
|
startdate: {
|
||||||
|
change: "Modifier la date de début",
|
||||||
|
date: "Date de début",
|
||||||
|
},
|
||||||
// catch errors
|
// catch errors
|
||||||
'Error while updating AccompanyingPeriod Course.': "Erreur du serveur lors de la mise à jour du parcours d'accompagnement.",
|
'Error while updating AccompanyingPeriod Course.': "Erreur du serveur lors de la mise à jour du parcours d'accompagnement.",
|
||||||
'Error while retriving AccompanyingPeriod Course.': "Erreur du serveur lors du chargement du parcours d'accompagnement.",
|
'Error while retriving AccompanyingPeriod Course.': "Erreur du serveur lors du chargement du parcours d'accompagnement.",
|
||||||
|
@ -8,15 +8,20 @@ import { getAccompanyingCourse,
|
|||||||
import { patchPerson } from "ChillPersonAssets/vuejs/_api/OnTheFly";
|
import { patchPerson } from "ChillPersonAssets/vuejs/_api/OnTheFly";
|
||||||
import { patchThirdparty } from "ChillThirdPartyAssets/vuejs/_api/OnTheFly";
|
import { patchThirdparty } from "ChillThirdPartyAssets/vuejs/_api/OnTheFly";
|
||||||
import { makeFetch } from 'ChillMainAssets/lib/api/apiMethods';
|
import { makeFetch } from 'ChillMainAssets/lib/api/apiMethods';
|
||||||
|
import { datetimeToISO, ISOToDate, ISOToDatetime } from 'ChillMainAssets/chill/js/date.js';
|
||||||
|
|
||||||
|
|
||||||
const debug = process.env.NODE_ENV !== 'production';
|
const debug = process.env.NODE_ENV !== 'production';
|
||||||
const id = window.accompanyingCourseId;
|
const id = window.accompanyingCourseId;
|
||||||
|
|
||||||
let scopesPromise = fetchScopes();
|
let getScopesPromise = (root) => {
|
||||||
|
if (root === 'app') {
|
||||||
|
return fetchScopes();
|
||||||
|
}
|
||||||
|
}
|
||||||
let accompanyingCoursePromise = getAccompanyingCourse(id);
|
let accompanyingCoursePromise = getAccompanyingCourse(id);
|
||||||
|
|
||||||
let initPromise = Promise.all([scopesPromise, accompanyingCoursePromise])
|
let initPromise = (root) => Promise.all([getScopesPromise(root), accompanyingCoursePromise])
|
||||||
.then(([scopes, accompanyingCourse]) => new Promise((resolve, reject) => {
|
.then(([scopes, accompanyingCourse]) => new Promise((resolve, reject) => {
|
||||||
|
|
||||||
const store = createStore({
|
const store = createStore({
|
||||||
@ -278,6 +283,10 @@ let initPromise = Promise.all([scopesPromise, accompanyingCoursePromise])
|
|||||||
if (scopeIds.includes(scope.id)) {
|
if (scopeIds.includes(scope.id)) {
|
||||||
state.scopesAtBackend = state.scopesAtBackend.filter(s => s.id !== scope.id);
|
state.scopesAtBackend = state.scopesAtBackend.filter(s => s.id !== scope.id);
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
updateStartDate(state, date) {
|
||||||
|
console.log('new state date', date)
|
||||||
|
state.accompanyingCourse.openingDate = date;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
@ -286,6 +295,12 @@ let initPromise = Promise.all([scopesPromise, accompanyingCoursePromise])
|
|||||||
commit('removeParticipation', payload);
|
commit('removeParticipation', payload);
|
||||||
// fetch DELETE request...
|
// fetch DELETE request...
|
||||||
},
|
},
|
||||||
|
addPerson({ commit }, payload) {
|
||||||
|
commit('updatePerson', { target: payload.target, person: payload.body });
|
||||||
|
},
|
||||||
|
addThirdparty({ commit }, payload) {
|
||||||
|
commit('updateThirdparty', { target: payload.target, thirdparty: payload.body });
|
||||||
|
},
|
||||||
/**
|
/**
|
||||||
* Add/close participation
|
* Add/close participation
|
||||||
*/
|
*/
|
||||||
@ -701,15 +716,30 @@ let initPromise = Promise.all([scopesPromise, accompanyingCoursePromise])
|
|||||||
throw error;
|
throw error;
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
updateStartDate({commit}, payload) {
|
||||||
|
console.log('payload', payload)
|
||||||
|
const date = ISOToDate(payload);
|
||||||
|
const url = `/api/1.0/person/accompanying-course/${id}.json`;
|
||||||
|
const body = { type: "accompanying_period", openingDate: { datetime: datetimeToISO(date) }};
|
||||||
|
console.log('body', body)
|
||||||
|
return makeFetch('PATCH', url, body)
|
||||||
|
.then((response) => {
|
||||||
|
commit('updateStartDate', response.openingDate);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
commit('catchError', error);
|
||||||
|
throw error;
|
||||||
|
})
|
||||||
|
},
|
||||||
async fetchReferrersSuggested({ state, commit}) {
|
async fetchReferrersSuggested({ state, commit}) {
|
||||||
let users = await getReferrersSuggested(state.accompanyingCourse);
|
let users = await getReferrersSuggested(state.accompanyingCourse);
|
||||||
commit('setReferrersSuggested', users);
|
commit('setReferrersSuggested', users);
|
||||||
commit('setFilteredReferrersSuggested');
|
commit('setFilteredReferrersSuggested');
|
||||||
if (
|
if (
|
||||||
null === state.accompanyingCourse.user
|
null === state.accompanyingCourse.user
|
||||||
&& !state.accompanyingCourse.confidential
|
&& !state.accompanyingCourse.confidential
|
||||||
&& !state.accompanyingCourse.step === 'DRAFT'
|
&& !state.accompanyingCourse.step === 'DRAFT'
|
||||||
&& users.length === 1
|
&& users.length === 1
|
||||||
) {
|
) {
|
||||||
// set the user if unique
|
// set the user if unique
|
||||||
commit('updateReferrer', users[0]);
|
commit('updateReferrer', users[0]);
|
||||||
@ -790,8 +820,11 @@ let initPromise = Promise.all([scopesPromise, accompanyingCoursePromise])
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
store.dispatch('fetchReferrersSuggested');
|
if (root === 'app') {
|
||||||
store.dispatch('fetchUsers');
|
store.dispatch('fetchReferrersSuggested');
|
||||||
|
store.dispatch('fetchUsers');
|
||||||
|
}
|
||||||
|
|
||||||
resolve(store);
|
resolve(store);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
<div id="awc_create_form">
|
<div id="awc_create_form">
|
||||||
|
|
||||||
<div id="picking">
|
<div id="picking" class="">
|
||||||
<p>{{ $t('pick_social_issue_linked_with_action') }}</p>
|
<p>{{ $t('pick_social_issue_linked_with_action') }}</p>
|
||||||
<div v-for="si in socialIssues" :key="si.id">
|
<div v-for="si in socialIssues" :key="si.id">
|
||||||
<input type="radio" v-bind:value="si.id" name="socialIssue" v-model="socialIssuePicked"><span class="badge bg-chill-l-gray text-dark">{{ si.text }}</span>
|
<input type="radio" v-bind:value="si.id" name="socialIssue" v-model="socialIssuePicked"><span class="badge bg-chill-l-gray text-dark">{{ si.text }}</span>
|
||||||
@ -33,7 +33,7 @@
|
|||||||
</vue-multiselect>
|
</vue-multiselect>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="hasSocialIssuePicked">
|
<div v-if="hasSocialIssuePicked" class="mb-3">
|
||||||
<h2>{{ $t('pick_an_action') }}</h2>
|
<h2>{{ $t('pick_an_action') }}</h2>
|
||||||
<div class="col-11">
|
<div class="col-11">
|
||||||
<vue-multiselect
|
<vue-multiselect
|
||||||
@ -52,26 +52,43 @@
|
|||||||
<i class="fa fa-circle-o-notch fa-spin fa-fw"></i>
|
<i class="fa fa-circle-o-notch fa-spin fa-fw"></i>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="hasSocialActionPicked" id="persons">
|
<div v-if="hasSocialActionPicked" id="persons" class="mb-5">
|
||||||
<h2>{{ $t('persons_involved') }}</h2>
|
<h2>{{ $t('persons_involved') }}</h2>
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
<li v-for="p in personsReachables" :key="p.id">
|
<li v-for="p in personsReachables" :key="p.id">
|
||||||
<input type="checkbox" :value="p.id" v-model="personsPicked">
|
<div class="form-check">
|
||||||
<person-render-box render="badge" :options="{}" :person="p"></person-render-box>
|
<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"></person-text>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div v-if="hasSocialActionPicked" id="start_date">
|
<!-- <div v-if="hasSocialActionPicked" id="start_date">
|
||||||
<p><label>{{ $t('startDate') }}</label> <input type="date" v-model="startDate" /></p>
|
<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>
|
||||||
|
|
||||||
<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>
|
<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>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="confirm">
|
<div id="confirm">
|
||||||
<div v-if="hasErrors">
|
<div v-if="hasErrors">
|
||||||
<p>{{ $t('form_has_errors') }}</p>
|
<p>{{ $t('form_has_errors') }}</p>
|
||||||
@ -111,7 +128,7 @@
|
|||||||
import { mapState, mapActions, mapGetters } from 'vuex';
|
import { mapState, mapActions, mapGetters } from 'vuex';
|
||||||
import VueMultiselect from 'vue-multiselect';
|
import VueMultiselect from 'vue-multiselect';
|
||||||
import { dateToISO, ISOToDate } from 'ChillMainAssets/chill/js/date.js';
|
import { dateToISO, ISOToDate } from 'ChillMainAssets/chill/js/date.js';
|
||||||
import PersonRenderBox from 'ChillPersonAssets/vuejs/_components/Entity/PersonRenderBox.vue';
|
import PersonText from 'ChillPersonAssets/vuejs/_components/Entity/PersonText.vue';
|
||||||
|
|
||||||
const i18n = {
|
const i18n = {
|
||||||
messages: {
|
messages: {
|
||||||
@ -133,7 +150,7 @@ export default {
|
|||||||
name: 'App',
|
name: 'App',
|
||||||
components: {
|
components: {
|
||||||
VueMultiselect,
|
VueMultiselect,
|
||||||
PersonRenderBox,
|
PersonText,
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
submit() {
|
submit() {
|
||||||
|
@ -141,10 +141,12 @@
|
|||||||
|
|
||||||
<ul class="list-unstyled">
|
<ul class="list-unstyled">
|
||||||
<li v-for="p in personsReachables" :key="p.id">
|
<li v-for="p in personsReachables" :key="p.id">
|
||||||
<label :for="p.id">
|
<div class="form-check">
|
||||||
<input v-model="personsPicked" :value="p.id" :id="p.id" type="checkbox" class="me-2">
|
<input v-model="personsPicked" :value="p.id" type="checkbox" class="me-2 form-check-input" :id="'person_check'+p.id">
|
||||||
{{ p.text }}
|
<label :for="'person_check'+p.id" class="form-check-label">
|
||||||
|
<person-text :person="p"></person-text>
|
||||||
</label>
|
</label>
|
||||||
|
</div>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
@ -280,6 +282,8 @@ import ThirdPartyRenderBox from 'ChillThirdPartyAssets/vuejs/_components/Entity/
|
|||||||
import PickTemplate from 'ChillDocGeneratorAssets/vuejs/_components/PickTemplate.vue';
|
import PickTemplate from 'ChillDocGeneratorAssets/vuejs/_components/PickTemplate.vue';
|
||||||
import OnTheFly from 'ChillMainAssets/vuejs/OnTheFly/components/OnTheFly.vue';
|
import OnTheFly from 'ChillMainAssets/vuejs/OnTheFly/components/OnTheFly.vue';
|
||||||
import ListWorkflowModal from 'ChillMainAssets/vuejs/_components/EntityWorkflow/ListWorkflowModal.vue';
|
import ListWorkflowModal from 'ChillMainAssets/vuejs/_components/EntityWorkflow/ListWorkflowModal.vue';
|
||||||
|
import PickWorkflow from 'ChillMainAssets/vuejs/_components/EntityWorkflow/PickWorkflow.vue';
|
||||||
|
import PersonText from 'ChillPersonAssets/vuejs/_components/Entity/PersonText.vue';
|
||||||
|
|
||||||
const i18n = {
|
const i18n = {
|
||||||
messages: {
|
messages: {
|
||||||
@ -328,7 +332,10 @@ export default {
|
|||||||
ThirdPartyRenderBox,
|
ThirdPartyRenderBox,
|
||||||
PickTemplate,
|
PickTemplate,
|
||||||
ListWorkflowModal,
|
ListWorkflowModal,
|
||||||
OnTheFly
|
OnTheFly,
|
||||||
|
PickWorkflow,
|
||||||
|
OnTheFly,
|
||||||
|
PersonText,
|
||||||
},
|
},
|
||||||
i18n,
|
i18n,
|
||||||
data() {
|
data() {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
|
<a id="evaluations"></a>
|
||||||
<div class="item-title" :title="evaluation.id || 'no id yet'">
|
<div class="item-title" :title="evaluation.id || 'no id yet'">
|
||||||
<span>{{ evaluation.evaluation.title.fr }}</span>
|
<span>{{ evaluation.evaluation.title.fr }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
<ul class="list-suggest remove-items inline">
|
<ul class="list-suggest remove-items inline">
|
||||||
<li v-for="c in concerned" :key="c.person.id" @click="removeConcerned(c)">
|
<li v-for="c in concerned" :key="c.person.id" @click="removeConcerned(c)">
|
||||||
<span>{{ c.person.text }}</span>
|
<span><person-text :person="c.person"></person-text></span>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
@ -57,12 +57,14 @@
|
|||||||
import { mapState, mapGetters } from 'vuex';
|
import { mapState, mapGetters } from 'vuex';
|
||||||
import AddPersons from 'ChillPersonAssets/vuejs/_components/AddPersons.vue';
|
import AddPersons from 'ChillPersonAssets/vuejs/_components/AddPersons.vue';
|
||||||
import PersonRenderBox from 'ChillPersonAssets/vuejs/_components/Entity/PersonRenderBox.vue';
|
import PersonRenderBox from 'ChillPersonAssets/vuejs/_components/Entity/PersonRenderBox.vue';
|
||||||
|
import PersonText from 'ChillPersonAssets/vuejs/_components/Entity/PersonText.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Concerned',
|
name: 'Concerned',
|
||||||
components: {
|
components: {
|
||||||
AddPersons,
|
AddPersons,
|
||||||
PersonRenderBox,
|
PersonRenderBox,
|
||||||
|
PersonText,
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState([
|
...mapState([
|
||||||
|
@ -61,6 +61,16 @@
|
|||||||
<li v-if="hasHousehold">
|
<li v-if="hasHousehold">
|
||||||
<button @click="resetMode" class="btn btn-sm btn-misc">{{ $t('household_members_editor.household.reset_mode')}}</button>
|
<button @click="resetMode" class="btn btn-sm btn-misc">{{ $t('household_members_editor.household.reset_mode')}}</button>
|
||||||
</li>
|
</li>
|
||||||
|
<li v-if="!hasHousehold">
|
||||||
|
<add-persons
|
||||||
|
modalTitle="Chercher un ménage existant"
|
||||||
|
buttonTitle="Chercher un ménage existant"
|
||||||
|
v-bind:key="addPersons.key"
|
||||||
|
v-bind:options="addPersons.options"
|
||||||
|
@addNewPersons="pickHouseholdFound"
|
||||||
|
ref="pickHousehold"> <!-- to cast child method -->
|
||||||
|
</add-persons>
|
||||||
|
</li>
|
||||||
<li v-if="!hasHousehold">
|
<li v-if="!hasHousehold">
|
||||||
<button @click="setModeNew" class="btn btn-sm btn-create">{{ $t('household_members_editor.household.create_household') }}</button>
|
<button @click="setModeNew" class="btn btn-sm btn-create">{{ $t('household_members_editor.household.create_household') }}</button>
|
||||||
</li>
|
</li>
|
||||||
@ -77,16 +87,30 @@
|
|||||||
import { mapGetters, mapState } from 'vuex';
|
import { mapGetters, mapState } from 'vuex';
|
||||||
import HouseholdRenderBox from 'ChillPersonAssets/vuejs/_components/Entity/HouseholdRenderBox.vue';
|
import HouseholdRenderBox from 'ChillPersonAssets/vuejs/_components/Entity/HouseholdRenderBox.vue';
|
||||||
import CurrentHousehold from './CurrentHousehold';
|
import CurrentHousehold from './CurrentHousehold';
|
||||||
|
import AddPersons from 'ChillPersonAssets/vuejs/_components/AddPersons';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Household',
|
name: 'Household',
|
||||||
components: {
|
components: {
|
||||||
|
AddPersons,
|
||||||
CurrentHousehold,
|
CurrentHousehold,
|
||||||
HouseholdRenderBox,
|
HouseholdRenderBox,
|
||||||
},
|
},
|
||||||
emits: ['readyToGo'],
|
emits: ['readyToGo'],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
addPersons: {
|
||||||
|
key: 'household_find',
|
||||||
|
options: {
|
||||||
|
type: ['household'],
|
||||||
|
priority: null,
|
||||||
|
uniq: true,
|
||||||
|
button: {
|
||||||
|
size: 'btn-sm',
|
||||||
|
type: 'btn-search',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
addAddress: {
|
addAddress: {
|
||||||
key: 'household_new',
|
key: 'household_new',
|
||||||
options: {
|
options: {
|
||||||
@ -166,6 +190,13 @@ export default {
|
|||||||
this.$store.dispatch('selectHousehold', h);
|
this.$store.dispatch('selectHousehold', h);
|
||||||
this.$emit('readyToGo');
|
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() {
|
removeHouseholdAddress() {
|
||||||
this.$store.commit('removeHouseholdAddress');
|
this.$store.commit('removeHouseholdAddress');
|
||||||
},
|
},
|
||||||
|
@ -6,12 +6,13 @@
|
|||||||
<div class="list-household-members flex-table">
|
<div class="list-household-members flex-table">
|
||||||
<div
|
<div
|
||||||
v-for="conc in concerned"
|
v-for="conc in concerned"
|
||||||
class="item-bloc"
|
class="item-bloc"
|
||||||
v-bind:key="conc.person.id"
|
v-bind:key="conc.person.id"
|
||||||
>
|
>
|
||||||
<div class="pick-position item-row">
|
<div class="pick-position item-row">
|
||||||
<div class="person">
|
<div class="person">
|
||||||
<h3>{{ conc.person.text }}</h3>
|
<!-- <h3>{{ conc.person.text }}</h3> -->
|
||||||
|
<h3><person-text :person="conc.person"></person-text></h3>
|
||||||
</div>
|
</div>
|
||||||
<div class="holder">
|
<div class="holder">
|
||||||
<button
|
<button
|
||||||
@ -53,6 +54,7 @@ import {mapGetters, mapState} from "vuex";
|
|||||||
import CurrentHousehold from "./CurrentHousehold";
|
import CurrentHousehold from "./CurrentHousehold";
|
||||||
import PersonRenderBox from 'ChillPersonAssets/vuejs/_components/Entity/PersonRenderBox.vue';
|
import PersonRenderBox from 'ChillPersonAssets/vuejs/_components/Entity/PersonRenderBox.vue';
|
||||||
import PersonComment from './PersonComment';
|
import PersonComment from './PersonComment';
|
||||||
|
import PersonText from '../../_components/Entity/PersonText.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "Positioning",
|
name: "Positioning",
|
||||||
@ -60,6 +62,7 @@ export default {
|
|||||||
CurrentHousehold,
|
CurrentHousehold,
|
||||||
PersonRenderBox,
|
PersonRenderBox,
|
||||||
PersonComment,
|
PersonComment,
|
||||||
|
PersonText
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState([
|
...mapState([
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
<template>
|
<template>
|
||||||
<ul class="record_actions">
|
<ul class="record_actions">
|
||||||
<li class="add-persons">
|
<li class="add-persons">
|
||||||
<a class="btn" :class="getClassButton" :title="$t(buttonTitle)"
|
<a class="btn" :class="getClassButton" :title="$t(buttonTitle)"
|
||||||
@click="openModal"><span v-if="displayTextButton">{{ $t(buttonTitle) }}</span></a>
|
@click="openModal"><span v-if="displayTextButton">{{ $t(buttonTitle) }}</span></a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<teleport to="body">
|
<teleport to="body">
|
||||||
<modal v-if="modal.showModal"
|
<modal v-if="modal.showModal"
|
||||||
:modalDialogClass="modal.modalDialogClass"
|
:modalDialogClass="modal.modalDialogClass"
|
||||||
@close="modal.showModal = false">
|
@close="modal.showModal = false">
|
||||||
@ -181,7 +181,7 @@ export default {
|
|||||||
},
|
},
|
||||||
hasPriorSuggestion() {
|
hasPriorSuggestion() {
|
||||||
return this.search.priorSuggestion.key ? true : false;
|
return this.search.priorSuggestion.key ? true : false;
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
openModal() {
|
openModal() {
|
||||||
|
@ -25,6 +25,11 @@
|
|||||||
v-if="item.result.type === 'user'"
|
v-if="item.result.type === 'user'"
|
||||||
v-bind:item="item">
|
v-bind:item="item">
|
||||||
</suggestion-user>
|
</suggestion-user>
|
||||||
|
|
||||||
|
<suggestion-household
|
||||||
|
v-if="item.result.type === 'household'"
|
||||||
|
v-bind:item="item">
|
||||||
|
</suggestion-household>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@ -34,6 +39,7 @@
|
|||||||
import SuggestionPerson from './TypePerson';
|
import SuggestionPerson from './TypePerson';
|
||||||
import SuggestionThirdParty from './TypeThirdParty';
|
import SuggestionThirdParty from './TypeThirdParty';
|
||||||
import SuggestionUser from './TypeUser';
|
import SuggestionUser from './TypeUser';
|
||||||
|
import SuggestionHousehold from './TypeHousehold';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'PersonSuggestion',
|
name: 'PersonSuggestion',
|
||||||
@ -41,6 +47,7 @@ export default {
|
|||||||
SuggestionPerson,
|
SuggestionPerson,
|
||||||
SuggestionThirdParty,
|
SuggestionThirdParty,
|
||||||
SuggestionUser,
|
SuggestionUser,
|
||||||
|
SuggestionHousehold,
|
||||||
},
|
},
|
||||||
props: [
|
props: [
|
||||||
'item',
|
'item',
|
||||||
@ -83,11 +90,11 @@ export default {
|
|||||||
label {
|
label {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
div.container {
|
div.container:not(.household) {
|
||||||
& > input {
|
& > input {
|
||||||
margin-right: 0.8em;
|
margin-right: 0.8em;
|
||||||
}
|
}
|
||||||
span:not(.name) {
|
> span:not(.name) {
|
||||||
margin-left: 0.5em;
|
margin-left: 0.5em;
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
font-size: 90%;
|
font-size: 90%;
|
||||||
|
@ -0,0 +1,27 @@
|
|||||||
|
<template>
|
||||||
|
<div class="container household">
|
||||||
|
<household-render-box :household="item.result" :isAddressMultiline="false"></household-render-box>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="right_actions">
|
||||||
|
<badge-entity
|
||||||
|
:entity="item.result"
|
||||||
|
:options="{ displayLong: true }">
|
||||||
|
</badge-entity>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
import BadgeEntity from 'ChillMainAssets/vuejs/_components/BadgeEntity.vue';
|
||||||
|
import HouseholdRenderBox from 'ChillPersonAssets/vuejs/_components/Entity/HouseholdRenderBox.vue';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'SuggestionHousehold',
|
||||||
|
components: {
|
||||||
|
BadgeEntity,
|
||||||
|
HouseholdRenderBox,
|
||||||
|
},
|
||||||
|
props: ['item'],
|
||||||
|
}
|
||||||
|
</script>
|
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<span class="name">
|
<span class="name">
|
||||||
{{ item.result.text }}
|
<person-text :person="item.result"></person-text>
|
||||||
</span>
|
</span>
|
||||||
<span class="birthday" v-if="hasBirthdate">
|
<span class="birthday" v-if="hasBirthdate">
|
||||||
{{ $d(item.result.birthdate.datetime, 'short') }}
|
{{ $d(item.result.birthdate.datetime, 'short') }}
|
||||||
@ -28,12 +28,14 @@
|
|||||||
<script>
|
<script>
|
||||||
import OnTheFly from 'ChillMainAssets/vuejs/OnTheFly/components/OnTheFly.vue';
|
import OnTheFly from 'ChillMainAssets/vuejs/OnTheFly/components/OnTheFly.vue';
|
||||||
import BadgeEntity from 'ChillMainAssets/vuejs/_components/BadgeEntity.vue';
|
import BadgeEntity from 'ChillMainAssets/vuejs/_components/BadgeEntity.vue';
|
||||||
|
import PersonText from 'ChillPersonAssets/vuejs/_components/Entity/PersonText.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'SuggestionPerson',
|
name: 'SuggestionPerson',
|
||||||
components: {
|
components: {
|
||||||
OnTheFly,
|
OnTheFly,
|
||||||
BadgeEntity
|
BadgeEntity,
|
||||||
|
PersonText,
|
||||||
},
|
},
|
||||||
props: ['item'],
|
props: ['item'],
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -2,9 +2,9 @@
|
|||||||
<div class="container tpartycontainer">
|
<div class="container tpartycontainer">
|
||||||
<div class="tparty-identification">
|
<div class="tparty-identification">
|
||||||
<span class="name">
|
<span class="name">
|
||||||
{{ item.result.text }}
|
{{ item.result.text }}
|
||||||
</span>
|
</span>
|
||||||
<span class="location">
|
<span class="location">
|
||||||
<template v-if="hasAddress">
|
<template v-if="hasAddress">
|
||||||
{{ getAddress.text }} -
|
{{ getAddress.text }} -
|
||||||
{{ getAddress.postcode.name }}
|
{{ getAddress.postcode.name }}
|
||||||
@ -89,5 +89,13 @@ export default {
|
|||||||
font-variant: all-small-caps;
|
font-variant: all-small-caps;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.tparty-identification {
|
||||||
|
span:not(.name) {
|
||||||
|
margin-left: 0.5em;
|
||||||
|
opacity: 0.5;
|
||||||
|
font-size: 90%;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -1,14 +1,15 @@
|
|||||||
<template>
|
<template>
|
||||||
<div v-if="render === 'bloc'" class="item-bloc">
|
<div v-if="render === 'bloc'" class="item-bloc">
|
||||||
<section class="chill-entity entity-person">
|
<section class="chill-entity entity-person">
|
||||||
<div class="item-row entity-bloc">
|
<div class="item-row entity-bloc">
|
||||||
|
|
||||||
<div class="item-col">
|
<div class="item-col">
|
||||||
<div class="entity-label">
|
<div class="entity-label">
|
||||||
|
|
||||||
<div :class="'denomination h' + options.hLevel">
|
<div :class="'denomination h' + options.hLevel">
|
||||||
|
|
||||||
<a v-if="options.addLink === true" :href="getUrl">
|
<a v-if="options.addLink === true" :href="getUrl">
|
||||||
|
<!-- use person-text here to avoid code duplication ? TODO -->
|
||||||
<span class="firstname">{{ person.firstName }}</span>
|
<span class="firstname">{{ person.firstName }}</span>
|
||||||
<span class="lastname">{{ person.lastName }}</span>
|
<span class="lastname">{{ person.lastName }}</span>
|
||||||
<span v-if="person.altNames && options.addAltNames == true" class="altnames">
|
<span v-if="person.altNames && options.addAltNames == true" class="altnames">
|
||||||
@ -16,19 +17,20 @@
|
|||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<span class="firstname">{{ person.firstName }}</span>
|
<!-- use person-text here to avoid code duplication ? TODO -->
|
||||||
<span class="lastname">{{ person.lastName }}</span>
|
<span class="firstname">{{ person.firstName }}</span>
|
||||||
<span v-if="person.deathdate" class="deathdate"> (‡)</span>
|
<span class="lastname">{{ person.lastName }}</span>
|
||||||
<span v-if="person.altNames && options.addAltNames == true" class="altnames">
|
<span v-if="person.deathdate" class="deathdate"> (‡)</span>
|
||||||
<span :class="'altname altname-' + altNameKey">{{ altNameLabel }}</span>
|
<span v-if="person.altNames && options.addAltNames == true" class="altnames">
|
||||||
</span>
|
<span :class="'altname altname-' + altNameKey">{{ altNameLabel }}</span>
|
||||||
|
</span>
|
||||||
|
|
||||||
<span v-if="options.addId == true" class="id-number" :title="'n° ' + person.id">{{ person.id }}</span>
|
<span v-if="options.addId == true" class="id-number" :title="'n° ' + person.id">{{ person.id }}</span>
|
||||||
|
|
||||||
<badge-entity v-if="options.addEntity === true"
|
<badge-entity v-if="options.addEntity === true"
|
||||||
:entity="person"
|
:entity="person"
|
||||||
:options="{ displayLong: options.entityDisplayLong }">
|
:options="{ displayLong: options.entityDisplayLong }">
|
||||||
</badge-entity>
|
</badge-entity>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -47,98 +49,96 @@
|
|||||||
{{ $t('renderbox.deathdate') + ' ' + deathdate }}
|
{{ $t('renderbox.deathdate') + ' ' + deathdate }}
|
||||||
</time>
|
</time>
|
||||||
|
|
||||||
<span v-if="options.addAge && person.birthdate" class="age">{{ getAge }} {{ $t('renderbox.years_old')}}</span>
|
<span v-if="options.addAge && person.birthdate" class="age">{{ $tc('renderbox.years_old', person.age) }}</span>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="item-col">
|
<div class="item-col">
|
||||||
<div class="float-button bottom">
|
<div class="float-button bottom">
|
||||||
<div class="box">
|
<div class="box">
|
||||||
<div class="action">
|
<div class="action">
|
||||||
<slot name="record-actions"></slot>
|
<slot name="record-actions"></slot>
|
||||||
</div>
|
</div>
|
||||||
<ul class="list-content fa-ul">
|
<ul class="list-content fa-ul">
|
||||||
|
<li v-if="person.current_household_id">
|
||||||
|
<i class="fa fa-li fa-map-marker"></i>
|
||||||
|
<address-render-box v-if="person.current_household_address"
|
||||||
|
:address="person.current_household_address"
|
||||||
|
:isMultiline="isMultiline">
|
||||||
|
</address-render-box>
|
||||||
|
<p v-else class="chill-no-data-statement">
|
||||||
|
{{ $t('renderbox.household_without_address') }}
|
||||||
|
</p>
|
||||||
|
<a v-if="options.addHouseholdLink === true"
|
||||||
|
:href="getCurrentHouseholdUrl"
|
||||||
|
:title="$t('persons_associated.show_household_number', {id: person.current_household_id})">
|
||||||
|
<span class="badge rounded-pill bg-chill-beige">
|
||||||
|
<i class="fa fa-fw fa-home"></i><!--{{ $t('persons_associated.show_household') }}-->
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li v-else-if="options.addNoData">
|
||||||
|
<i class="fa fa-li fa-map-marker"></i>
|
||||||
|
<p class="chill-no-data-statement">
|
||||||
|
{{ $t('renderbox.no_data') }}
|
||||||
|
</p>
|
||||||
|
</li>
|
||||||
|
|
||||||
<li v-if="person.current_household_id">
|
<li v-if="person.mobilenumber">
|
||||||
<i class="fa fa-li fa-map-marker"></i>
|
<i class="fa fa-li fa-mobile"></i>
|
||||||
<address-render-box v-if="person.current_household_address"
|
<a :href="'tel: ' + person.mobilenumber">{{ person.mobilenumber }}</a>
|
||||||
:address="person.current_household_address"
|
</li>
|
||||||
:isMultiline="isMultiline">
|
<li v-else-if="options.addNoData">
|
||||||
</address-render-box>
|
<i class="fa fa-li fa-mobile"></i>
|
||||||
<p v-else class="chill-no-data-statement">
|
<p class="chill-no-data-statement">{{ $t('renderbox.no_data') }}</p>
|
||||||
{{ $t('renderbox.household_without_address') }}
|
</li>
|
||||||
</p>
|
<li v-if="person.phonenumber">
|
||||||
<a v-if="options.addHouseholdLink === true"
|
<i class="fa fa-li fa-phone"></i>
|
||||||
:href="getCurrentHouseholdUrl"
|
<a :href="'tel: ' + person.phonenumber">{{ person.phonenumber }}</a>
|
||||||
:title="$t('persons_associated.show_household_number', {id: person.current_household_id})">
|
</li>
|
||||||
<span class="badge rounded-pill bg-chill-beige">
|
<li v-else-if="options.addNoData">
|
||||||
<i class="fa fa-fw fa-home"></i><!--{{ $t('persons_associated.show_household') }}-->
|
<i class="fa fa-li fa-phone"></i>
|
||||||
</span>
|
<p class="chill-no-data-statement">{{ $t('renderbox.no_data') }}</p>
|
||||||
</a>
|
</li>
|
||||||
</li>
|
|
||||||
<li v-else-if="options.addNoData">
|
|
||||||
<i class="fa fa-li fa-map-marker"></i>
|
|
||||||
<p class="chill-no-data-statement">
|
|
||||||
{{ $t('renderbox.no_data') }}
|
|
||||||
</p>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li v-if="person.mobilenumber">
|
<li v-if="person.centers !== undefined && person.centers.length > 0 && options.addCenter">
|
||||||
<i class="fa fa-li fa-mobile"></i>
|
<i class="fa fa-li fa-long-arrow-right"></i>
|
||||||
<a :href="'tel: ' + person.mobilenumber">{{ person.mobilenumber }}</a>
|
<template v-for="c in person.centers">{{ c.name }}</template>
|
||||||
</li>
|
</li>
|
||||||
<li v-else-if="options.addNoData">
|
<li v-else-if="options.addNoData">
|
||||||
<i class="fa fa-li fa-mobile"></i>
|
<i class="fa fa-li fa-long-arrow-right"></i>
|
||||||
<p class="chill-no-data-statement">{{ $t('renderbox.no_data') }}</p>
|
<p class="chill-no-data-statement">{{ $t('renderbox.no_data') }}</p>
|
||||||
</li>
|
</li>
|
||||||
<li v-if="person.phonenumber">
|
<slot name="custom-zone"></slot>
|
||||||
<i class="fa fa-li fa-phone"></i>
|
|
||||||
<a :href="'tel: ' + person.phonenumber">{{ person.phonenumber }}</a>
|
|
||||||
</li>
|
|
||||||
<li v-else-if="options.addNoData">
|
|
||||||
<i class="fa fa-li fa-phone"></i>
|
|
||||||
<p class="chill-no-data-statement">{{ $t('renderbox.no_data') }}</p>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li v-if="person.centers !== undefined && person.centers.length > 0 && options.addCenter">
|
</ul>
|
||||||
<i class="fa fa-li fa-long-arrow-right"></i>
|
</div>
|
||||||
<template v-for="c in person.centers">{{ c.name }}</template>
|
</div>
|
||||||
</li>
|
</div>
|
||||||
<li v-else-if="options.addNoData">
|
|
||||||
<i class="fa fa-li fa-long-arrow-right"></i>
|
|
||||||
<p class="chill-no-data-statement">{{ $t('renderbox.no_data') }}</p>
|
|
||||||
</li>
|
|
||||||
<slot name="custom-zone"></slot>
|
|
||||||
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<span v-if="render === 'badge'" class="chill-entity entity-person badge-person">
|
<span v-if="render === 'badge'" class="chill-entity entity-person badge-person">
|
||||||
<a v-if="options.addLink === true" :href="getUrl">
|
<a v-if="options.addLink === true" :href="getUrl">
|
||||||
<span v-if="options.isHolder" class="fa-stack fa-holder" :title="$t('renderbox.holder')">
|
<span v-if="options.isHolder" class="fa-stack fa-holder" :title="$t('renderbox.holder')">
|
||||||
<i class="fa fa-circle fa-stack-1x text-success"></i>
|
<i class="fa fa-circle fa-stack-1x text-success"></i>
|
||||||
<i class="fa fa-stack-1x">T</i>
|
<i class="fa fa-stack-1x">T</i>
|
||||||
</span>
|
</span>
|
||||||
{{ person.text }}
|
|
||||||
<span v-if="person.deathdate" class="deathdate"> (‡)</span>
|
<person-text :person="person"></person-text>
|
||||||
</a>
|
</a>
|
||||||
<span v-else>
|
<span v-else>
|
||||||
<span v-if="options.isHolder" class="fa-stack fa-holder" :title="$t('renderbox.holder')">
|
<span v-if="options.isHolder" class="fa-stack fa-holder" :title="$t('renderbox.holder')">
|
||||||
<i class="fa fa-circle fa-stack-1x text-success"></i>
|
<i class="fa fa-circle fa-stack-1x text-success"></i>
|
||||||
<i class="fa fa-stack-1x">T</i>
|
<i class="fa fa-stack-1x">T</i>
|
||||||
</span>
|
</span>
|
||||||
{{ person.text }}
|
<person-text :person="person"></person-text>
|
||||||
<span v-if="person.deathdate" class="deathdate"> (‡)</span>
|
|
||||||
</span>
|
</span>
|
||||||
<slot name="post-badge"></slot>
|
<slot name="post-badge"></slot>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -147,13 +147,15 @@ import {dateToISO} from 'ChillMainAssets/chill/js/date.js';
|
|||||||
import AddressRenderBox from 'ChillMainAssets/vuejs/_components/Entity/AddressRenderBox.vue';
|
import AddressRenderBox from 'ChillMainAssets/vuejs/_components/Entity/AddressRenderBox.vue';
|
||||||
import Confidential from 'ChillMainAssets/vuejs/_components/Confidential.vue';
|
import Confidential from 'ChillMainAssets/vuejs/_components/Confidential.vue';
|
||||||
import BadgeEntity from 'ChillMainAssets/vuejs/_components/BadgeEntity.vue';
|
import BadgeEntity from 'ChillMainAssets/vuejs/_components/BadgeEntity.vue';
|
||||||
|
import PersonText from 'ChillPersonAssets/vuejs/_components/Entity/PersonText.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "PersonRenderBox",
|
name: "PersonRenderBox",
|
||||||
components: {
|
components: {
|
||||||
AddressRenderBox,
|
AddressRenderBox,
|
||||||
Confidential,
|
Confidential,
|
||||||
BadgeEntity
|
BadgeEntity,
|
||||||
|
PersonText
|
||||||
},
|
},
|
||||||
props: ['person', 'options', 'render', 'returnPath'],
|
props: ['person', 'options', 'render', 'returnPath'],
|
||||||
computed: {
|
computed: {
|
||||||
@ -168,7 +170,7 @@ export default {
|
|||||||
return this.person.gender === 'woman' ? 'fa-venus' : this.person.gender === 'man' ? 'fa-mars' : this.person.gender === 'neuter' ? 'fa-neuter' : 'fa-genderless';
|
return this.person.gender === 'woman' ? 'fa-venus' : this.person.gender === 'man' ? 'fa-mars' : this.person.gender === 'neuter' ? 'fa-neuter' : 'fa-genderless';
|
||||||
},
|
},
|
||||||
getGenderTranslation: function() {
|
getGenderTranslation: function() {
|
||||||
return this.person.gender === 'woman' ? 'renderbox.birthday.woman' : 'renderbox.birthday.man';
|
return this.person.gender === 'woman' ? 'renderbox.birthday.woman' : 'renderbox.birthday.man';
|
||||||
},
|
},
|
||||||
getGender() {
|
getGender() {
|
||||||
return this.person.gender === 'woman' ? 'person.gender.woman' : this.person.gender === 'man' ? 'person.gender.man' : this.person.gender === 'neuter' ? 'person.gender.neuter' : 'person.gender.undefined';
|
return this.person.gender === 'woman' ? 'person.gender.woman' : this.person.gender === 'man' ? 'person.gender.man' : this.person.gender === 'neuter' ? 'person.gender.neuter' : 'person.gender.undefined';
|
||||||
@ -200,24 +202,6 @@ export default {
|
|||||||
getUrl: function() {
|
getUrl: function() {
|
||||||
return `/fr/person/${this.person.id}/general`;
|
return `/fr/person/${this.person.id}/general`;
|
||||||
},
|
},
|
||||||
getAge: function() {
|
|
||||||
// TODO only one abstract function
|
|
||||||
if(this.person.birthdate && !this.person.deathdate){
|
|
||||||
const birthday = new Date(this.person.birthdate.datetime)
|
|
||||||
const now = new Date()
|
|
||||||
return (now.getFullYear() - birthday.getFullYear())
|
|
||||||
} else if(this.person.birthdate && this.person.deathdate){
|
|
||||||
const birthday = new Date(this.person.birthdate.datetime)
|
|
||||||
const deathdate = new Date(this.person.deathdate.datetime)
|
|
||||||
return (deathdate.getFullYear() - birthday.getFullYear())
|
|
||||||
} else if(!this.person.birthdate && this.person.deathdate.datetime) {
|
|
||||||
// todo: change this
|
|
||||||
return "Age unknown"
|
|
||||||
} else {
|
|
||||||
// todo: change this
|
|
||||||
return "Age unknown"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
getCurrentHouseholdUrl: function() {
|
getCurrentHouseholdUrl: function() {
|
||||||
let returnPath = this.returnPath ? `?returnPath=${this.returnPath}` : ``;
|
let returnPath = this.returnPath ? `?returnPath=${this.returnPath}` : ``;
|
||||||
return `/fr/person/household/${this.person.current_household_id}/summary${returnPath}`
|
return `/fr/person/household/${this.person.current_household_id}/summary${returnPath}`
|
||||||
|
@ -0,0 +1,50 @@
|
|||||||
|
<template>
|
||||||
|
<span v-if="isCut">{{ cutText }}</span>
|
||||||
|
<span v-else class="person-text">
|
||||||
|
<span class="firstname">{{ person.firstName }}</span>
|
||||||
|
<span class="lastname">{{ person.lastName }}</span>
|
||||||
|
<span v-if="person.altNames && person.altNames.length > 0" class="altnames">
|
||||||
|
<span :class="'altname altname-' + altNameKey"> ({{ altNameLabel }})</span>
|
||||||
|
</span>
|
||||||
|
<span class="age" v-if="this.addAge && person.birthdate !== null && person.deathdate === null">{{ $tc('renderbox.years_old', person.age) }}</span>
|
||||||
|
<span v-else-if="this.addAge && person.deathdate !== null"> (‡)</span>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "PersonText",
|
||||||
|
props: {
|
||||||
|
person: {
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
isCut: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
addAge: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: true,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
altNameLabel: function() {
|
||||||
|
for(let i = 0; i < this.person.altNames.length; i++){
|
||||||
|
return this.person.altNames[i].label
|
||||||
|
}
|
||||||
|
},
|
||||||
|
altNameKey: function() {
|
||||||
|
for(let i = 0; i < this.person.altNames.length; i++){
|
||||||
|
return this.person.altNames[i].key
|
||||||
|
}
|
||||||
|
},
|
||||||
|
cutText: function() {
|
||||||
|
let more = (this.person.text.length > 15) ?'…' : '';
|
||||||
|
return this.person.text.slice(0,15) + more;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
@ -31,7 +31,7 @@
|
|||||||
<li class="associated-persons">
|
<li class="associated-persons">
|
||||||
<span class="item-key">{{ 'Participants'|trans ~ ' : ' }}</span>
|
<span class="item-key">{{ 'Participants'|trans ~ ' : ' }}</span>
|
||||||
{% for p in w.persons %}
|
{% for p in w.persons %}
|
||||||
<span class="badge-person">{{ p|chill_entity_render_box }}</span>
|
<span class="badge-person">{{ p|chill_entity_render_box({'addAgeBadge': true}) }}</span>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -0,0 +1,30 @@
|
|||||||
|
{% extends "@ChillMain/layout.html.twig" %}
|
||||||
|
|
||||||
|
{% set activeRouteKey = 'chill_person_accompanying_period_user_list' %}
|
||||||
|
|
||||||
|
{% block title %}{{ 'My accompanying periods'|trans }}{% endblock title %}
|
||||||
|
|
||||||
|
{% macro recordAction(period) %}
|
||||||
|
<li>
|
||||||
|
<a href="{{ path('chill_person_accompanying_course_index', { 'accompanying_period_id': period.id }) }}"
|
||||||
|
class="btn btn-show" title="{{ 'See accompanying period'|trans }}"></a>
|
||||||
|
</li>
|
||||||
|
{% endmacro %}
|
||||||
|
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<div class="col-md-10">
|
||||||
|
<h1>{{ 'My accompanying periods'|trans }}</h1>
|
||||||
|
|
||||||
|
<div class="flex-table accompanyingcourse-list">
|
||||||
|
{% for period in accompanyingPeriods %}
|
||||||
|
{% include '@ChillPerson/AccompanyingPeriod/_list_item.html.twig' with {'period': period, 'recordAction': _self.recordAction(period)} %}
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{ chill_pagination(pagination) }}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endblock %}
|
@ -11,6 +11,7 @@
|
|||||||
* addCenter bool
|
* addCenter bool
|
||||||
* hLevel integer
|
* hLevel integer
|
||||||
* addDeath bool
|
* addDeath bool
|
||||||
|
* addAgeBadge bool
|
||||||
* address_multiline bool
|
* address_multiline bool
|
||||||
* customButtons [
|
* customButtons [
|
||||||
'before' Twig\Markup, (injected with macro)
|
'before' Twig\Markup, (injected with macro)
|
||||||
@ -40,6 +41,11 @@
|
|||||||
{%- endfor -%}
|
{%- endfor -%}
|
||||||
</span>
|
</span>
|
||||||
{%- endif -%}
|
{%- endif -%}
|
||||||
|
{%- if options['addAgeBadge'] -%}
|
||||||
|
{% if person.age is not null and person.deathDate is null %}
|
||||||
|
<span>({{- 'years_old'|trans({ 'age': person.age }) -}})</span>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
{% endmacro raw %}
|
{% endmacro raw %}
|
||||||
|
|
||||||
{% macro label(person, options) %}
|
{% macro label(person, options) %}
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
'render': 'label',
|
'render': 'label',
|
||||||
'addLink': true,
|
'addLink': true,
|
||||||
'addInfo': true,
|
'addInfo': true,
|
||||||
|
'addAgeBadge': true,
|
||||||
'customArea': {
|
'customArea': {
|
||||||
'afterLabel': _self.addHolder(member.holder)
|
'afterLabel': _self.addHolder(member.holder)
|
||||||
}
|
}
|
||||||
|
@ -78,16 +78,11 @@
|
|||||||
{% set app = person.findParticipationForPeriod(acp) %}
|
{% set app = person.findParticipationForPeriod(acp) %}
|
||||||
<div class="item-row separator">
|
<div class="item-row separator">
|
||||||
<div class="wrap-list periods-list">
|
<div class="wrap-list periods-list">
|
||||||
|
|
||||||
|
|
||||||
<div class="wl-row">
|
<div class="wl-row">
|
||||||
<div class="wl-col title">
|
<div class="wl-col title">
|
||||||
<h3 class="courseid mb-2">
|
<h3 class="courseid mb-2">
|
||||||
<a href="{{ path('chill_person_accompanying_course_index', { 'accompanying_period_id': acp.id }) }}"
|
|
||||||
title="{{ 'See accompanying period'|trans }}" class="btn btn-outline-primary">
|
|
||||||
<i class="fa fa-random fa-fw"></i>
|
<i class="fa fa-random fa-fw"></i>
|
||||||
{{ 'File number'|trans }} {{ acp.id }}
|
{{ 'File number'|trans }} {{ acp.id }}
|
||||||
</a>
|
|
||||||
</h3>
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
<div class="wl-col list">
|
<div class="wl-col list">
|
||||||
@ -97,28 +92,37 @@
|
|||||||
{{ 'Since %date%'|trans({'%date%': app.startDate|format_date('medium') }) }}
|
{{ 'Since %date%'|trans({'%date%': app.startDate|format_date('medium') }) }}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% set notif_counter = chill_count_notifications('Chill\\PersonBundle\\Entity\\AccompanyingPeriod', acp.id) %}
|
{% set notif_counter = chill_count_notifications('Chill\\PersonBundle\\Entity\\AccompanyingPeriod', acp.id) %}
|
||||||
{% if notif_counter.total > 0 %}
|
{% if notif_counter.total > 0 %}
|
||||||
{{ chill_counter_notifications('Chill\\PersonBundle\\Entity\\AccompanyingPeriod', acp.id) }}
|
{{ chill_counter_notifications('Chill\\PersonBundle\\Entity\\AccompanyingPeriod', acp.id) }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<div class="ms-auto">
|
<div class="ms-auto">
|
||||||
|
{% if acp.requestorPerson == person %}
|
||||||
|
<span class="as-requestor badge bg-info" title="{{ 'Requestor'|trans|e('html_attr') }}">
|
||||||
|
{{ 'Requestor'|trans({'gender': person.gender}) }}
|
||||||
|
</span>
|
||||||
|
{% endif %}
|
||||||
{% if acp.emergency %}
|
{% if acp.emergency %}
|
||||||
<span class="badge rounded-pill bg-danger">{{- 'Emergency'|trans|upper -}}</span>
|
<span class="badge rounded-pill bg-danger">{{- 'Emergency'|trans|upper -}}</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if acp.confidential %}
|
{% if acp.confidential %}
|
||||||
<span class="badge rounded-pill bg-confidential">{{- 'Confidential'|trans|upper -}}</span>
|
<span class="badge rounded-pill bg-confidential">{{- 'Confidential'|trans|upper -}}</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if acp.step == 'DRAFT' %}
|
{% if acp.step == 'DRAFT' %}
|
||||||
<span class="badge bg-secondary" style="font-size: 85%;" title="{{ 'course.draft'|trans }}">{{ 'course.draft'|trans }}</span>
|
<span class="badge bg-secondary" style="font-size: 85%;" title="{{ 'course.draft'|trans }}">{{ 'course.draft'|trans }}</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
{% if acp.step == 'CLOSED' %}
|
||||||
|
<span class="badge bg-secondary" style="font-size: 85%;" title="{{ 'course.closed'|trans }}">{{ 'course.closed'|trans }}</span>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% if acp.user is not null %}
|
{% if acp.user is not null %}
|
||||||
<div class="wl-row">
|
<div class="wl-row">
|
||||||
<div class="wl-col title">
|
<div class="wl-col title">
|
||||||
@ -131,7 +135,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if acp.socialIssues|length > 0 %}
|
{% if acp.socialIssues|length > 0 %}
|
||||||
<div class="wl-row">
|
<div class="wl-row">
|
||||||
<div class="wl-col title">
|
<div class="wl-col title">
|
||||||
@ -144,24 +148,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{# ????
|
|
||||||
{% if acp.requestorPerson == person %}
|
|
||||||
<div class="wl-row">
|
|
||||||
<div class="wl-col title">
|
|
||||||
<h3>
|
|
||||||
|
|
||||||
</h3>
|
|
||||||
</div>
|
|
||||||
<div class="wl-col list">
|
|
||||||
<span class="as-requestor badge bg-info" title="{{ 'Requestor'|trans|e('html_attr') }}">
|
|
||||||
{{ 'Requestor'|trans({'gender': person.gender}) }}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
#}
|
|
||||||
|
|
||||||
{% if acp.currentParticipations|length > 1 %}
|
{% if acp.currentParticipations|length > 1 %}
|
||||||
<div class="wl-row">
|
<div class="wl-row">
|
||||||
<div class="wl-col title">
|
<div class="wl-col title">
|
||||||
@ -190,7 +177,16 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
<ul class="record_actions record_actions_column">
|
||||||
|
<li>
|
||||||
|
<a href="{{ path('chill_person_accompanying_course_index', { 'accompanying_period_id': acp.id }) }}"
|
||||||
|
class="btn btn-sm btn-outline-primary" title="{{ 'See accompanying period'|trans }}">
|
||||||
|
<i class="fa fa-random fa-fw"></i>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
{% if (acp.requestorPerson is not null and acp.requestorPerson.id != person.id) or acp.requestorThirdParty is not null %}
|
{% if (acp.requestorPerson is not null and acp.requestorPerson.id != person.id) or acp.requestorThirdParty is not null %}
|
||||||
<div class="wl-row">
|
<div class="wl-row">
|
||||||
<div class="wl-col title">
|
<div class="wl-col title">
|
||||||
@ -222,7 +218,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
@ -12,4 +12,4 @@
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
</div>
|
</div>
|
@ -84,6 +84,8 @@
|
|||||||
<p class="chill-no-data-statement">{{ 'There are no available resources'|trans }}</p>
|
<p class="chill-no-data-statement">{{ 'There are no available resources'|trans }}</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
<h1 style="margin-bottom: 2rem;">{{ 'Add a person resource'|trans }}</h1>
|
||||||
|
|
||||||
{% include "@ChillPerson/PersonResource/create.html.twig" %}
|
{% include "@ChillPerson/PersonResource/create.html.twig" %}
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -0,0 +1,37 @@
|
|||||||
|
|
||||||
|
|
||||||
|
{{ form_start(form) }}
|
||||||
|
|
||||||
|
{{ form_row(form.startDate) }}
|
||||||
|
{{ form_row(form.endDate) }}
|
||||||
|
|
||||||
|
{% if form.hostPerson is defined %}
|
||||||
|
{{ form_row(form.hostPerson) }}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if form.hostThirdParty is defined %}
|
||||||
|
{{ form_row(form.hostThirdParty) }}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if form.address is defined %}
|
||||||
|
{{ form_row(form.address) }}
|
||||||
|
|
||||||
|
{% block js %}
|
||||||
|
{{ encore_entry_script_tags('mod_input_address') }}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block css %}
|
||||||
|
{{ encore_entry_link_tags('mod_input_address') }}
|
||||||
|
{% endblock %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{{ form_row(form.comment) }}
|
||||||
|
|
||||||
|
|
||||||
|
<ul class="record_actions sticky-form-buttons">
|
||||||
|
<li>
|
||||||
|
<button class="btn btn-update" type="submit">{{ 'Save'|trans }}</button>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
{{ form_end(form) }}
|
@ -0,0 +1,58 @@
|
|||||||
|
{% extends "@ChillPerson/Person/layout.html.twig" %}
|
||||||
|
|
||||||
|
{% set activeRouteKey = '' %}
|
||||||
|
|
||||||
|
{% block title %}{{ 'Delete residential address'|trans }}{% endblock %}
|
||||||
|
|
||||||
|
{% block personcontent %}
|
||||||
|
<div class="address-new">
|
||||||
|
|
||||||
|
<h1>{{ block('title') }}</h1>
|
||||||
|
{% set a = residentialAddress %}
|
||||||
|
<ul class="list-content fa-ul">
|
||||||
|
{% if a.hostPerson is not null %}
|
||||||
|
<li>
|
||||||
|
<i class="fa fa-li fa-home"></i>
|
||||||
|
<span class="item-key">{{ "Address of"|trans}} </span>
|
||||||
|
<span class="chill-entity entity-person badge-person">{{ a.hostPerson|chill_entity_render_box }}</span>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
{% set address_date = date(a.startDate|date("m/d/Y")) %}
|
||||||
|
{% if a.hostPerson.getCurrentHouseholdAddress(a.endDate) is not null %}
|
||||||
|
<i class="fa fa-li fa-map-marker"></i>
|
||||||
|
{{ a.hostPerson.getCurrentHouseholdAddress(a.endDate)|chill_entity_render_box }}
|
||||||
|
{% endif %}
|
||||||
|
</li>
|
||||||
|
{% elseif a.hostThirdParty is not null %}
|
||||||
|
<li>
|
||||||
|
<i class="fa fa-li fa-home"></i>
|
||||||
|
<span class="item-key">{{ "Address of"|trans}}</span>
|
||||||
|
<span class="chill-entity entity-person badge-person">{{ a.hostThirdParty|chill_entity_render_box }}</span>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
{% if a.hostThirdParty.address is not null %}
|
||||||
|
<i class="fa fa-li fa-map-marker"></i>
|
||||||
|
{{ a.hostThirdParty.address|chill_entity_render_box }}
|
||||||
|
{% endif %}
|
||||||
|
</li>
|
||||||
|
{% else %}
|
||||||
|
<li>
|
||||||
|
{% if a.address is not null %}
|
||||||
|
<i class="fa fa-li fa-map-marker"></i>
|
||||||
|
{{ a.address|chill_entity_render_box }}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
{{ include('@ChillMain/Util/confirmation_template.html.twig',
|
||||||
|
{
|
||||||
|
'title' : 'Delete residential address ?'|trans,
|
||||||
|
'confirm_question' : 'Are you sure you want to remove this residential address for %name% ?'|trans({'%name%': person|chill_entity_render_string }),
|
||||||
|
'cancel_route' : 'chill_person_residential_address_list',
|
||||||
|
'cancel_parameters' : {'id' : person.Id},
|
||||||
|
'form' : delete_form
|
||||||
|
} ) }}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
@ -0,0 +1,51 @@
|
|||||||
|
{% extends "@ChillPerson/Person/layout.html.twig" %}
|
||||||
|
|
||||||
|
{% set activeRouteKey = '' %}
|
||||||
|
|
||||||
|
{% block title 'Edit a residential address'|trans %}
|
||||||
|
|
||||||
|
{% block personcontent %}
|
||||||
|
<div class="address-edit">
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<h1>{{ block('title') }}</h1>
|
||||||
|
|
||||||
|
{{ form_start(form) }}
|
||||||
|
|
||||||
|
{{ form_row(form.startDate) }}
|
||||||
|
{{ form_row(form.endDate) }}
|
||||||
|
|
||||||
|
{% if residentialAddress.address is not null %}
|
||||||
|
|
||||||
|
{% if form.address is defined %}
|
||||||
|
{{ form_row(form.address) }}
|
||||||
|
|
||||||
|
{% block js %}
|
||||||
|
{{ encore_entry_script_tags('mod_input_address') }}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block css %}
|
||||||
|
{{ encore_entry_link_tags('mod_input_address') }}
|
||||||
|
{% endblock %}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{{ form_row(form.comment) }}
|
||||||
|
|
||||||
|
<ul class="record_actions sticky-form-buttons">
|
||||||
|
<li class="cancel">
|
||||||
|
<a href="{{ chill_path_add_return_path('chill_person_residential_address_list', {'id': person.id}) }}" class="btn btn-cancel">
|
||||||
|
{{ 'Cancel'|trans|chill_return_path_label }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<button class="btn btn-update" type="submit">{{ 'Save'|trans }}</button>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
{{ form_end(form) }}
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
@ -0,0 +1,116 @@
|
|||||||
|
{% extends "@ChillPerson/Person/layout.html.twig" %}
|
||||||
|
|
||||||
|
{% set activeRouteKey = '' %}
|
||||||
|
|
||||||
|
{% block title %}{{ 'Residential addresses history for %name%'|trans({ '%name%': person.firstName ~ ' ' ~ person.lastName } ) }}{% endblock %}
|
||||||
|
|
||||||
|
{% block personcontent %}
|
||||||
|
<div class="person-address">
|
||||||
|
|
||||||
|
<h1>{{ 'Residential addresses history'|trans }}</h1>
|
||||||
|
|
||||||
|
{% if is_granted('CHILL_PERSON_SEE', person) %}
|
||||||
|
|
||||||
|
{% if addresses|length == 0 %}
|
||||||
|
<span class="chill-no-data-statement">{{ 'No address given'|trans }}</span>
|
||||||
|
|
||||||
|
{% else %}
|
||||||
|
<div class="flex-table">
|
||||||
|
{% for a in addresses %}
|
||||||
|
|
||||||
|
{% if a.address is not null %}
|
||||||
|
{% set kind = 'address' %}
|
||||||
|
{% else %}
|
||||||
|
{% set kind = null %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<div class="item-bloc">
|
||||||
|
<div class="item-row">
|
||||||
|
|
||||||
|
<div class="item-col" style="width: 33%;">
|
||||||
|
<ul class="list-unstyled h3">
|
||||||
|
{% if a.endDate is not null %}
|
||||||
|
<li><span class="item-key">{{'Since'|trans}} : </span>{{ a.startDate|format_date('long') }}</li>
|
||||||
|
{% endif %}
|
||||||
|
<li><span class="item-key">{{'Until'|trans}} : </span><b>{{ a.endDate|format_date('long') }}</b></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="item-col flex-column justify-content-start">
|
||||||
|
<div class="float-button top">
|
||||||
|
<div class="box">
|
||||||
|
<div class="action">
|
||||||
|
{% if is_granted('CHILL_PERSON_UPDATE', person) %}
|
||||||
|
<a href="{{ path('chill_person_residential_address_edit', { 'id' : a.id, 'kind' : kind } ) }}" class="btn btn-update" title="{{ 'Update'|trans|e('html_attr') }}"></a>
|
||||||
|
<a href="{{ path('chill_person_residential_address_delete', { 'id' : a.id, 'kind' : kind } ) }}" class="btn btn-delete" title="{{ 'Delete'|trans|e('html_attr') }}"></a>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
<ul class="list-content fa-ul">
|
||||||
|
{% if a.hostPerson is not null %}
|
||||||
|
<li>
|
||||||
|
<i class="fa fa-li fa-home"></i>
|
||||||
|
<span class="item-key">{{ "Address of"|trans}} </span>
|
||||||
|
<span class="chill-entity entity-person badge-person">{{ a.hostPerson|chill_entity_render_box }}</span>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
{% set address_date = date(a.startDate|date("m/d/Y")) %}
|
||||||
|
{% if a.hostPerson.getCurrentHouseholdAddress(a.endDate) is not null %}
|
||||||
|
<i class="fa fa-li fa-map-marker"></i>
|
||||||
|
{{ a.hostPerson.getCurrentHouseholdAddress(a.endDate)|chill_entity_render_box }}
|
||||||
|
{% endif %}
|
||||||
|
</li>
|
||||||
|
{% elseif a.hostThirdParty is not null %}
|
||||||
|
<li>
|
||||||
|
<i class="fa fa-li fa-home"></i>
|
||||||
|
<span class="item-key">{{ "Address of"|trans}}</span>
|
||||||
|
<span class="chill-entity entity-person badge-person">{{ a.hostThirdParty|chill_entity_render_box }}</span>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
{% if a.hostThirdParty.address is not null %}
|
||||||
|
<i class="fa fa-li fa-map-marker"></i>
|
||||||
|
{{ a.hostThirdParty.address|chill_entity_render_box }}
|
||||||
|
{% endif %}
|
||||||
|
</li>
|
||||||
|
{% else %}
|
||||||
|
<li>
|
||||||
|
{% if a.address is not null %}
|
||||||
|
<i class="fa fa-li fa-map-marker"></i>
|
||||||
|
{{ a.address|chill_entity_render_box }}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<div class="item-row">
|
||||||
|
{% if not a.comment.isEmpty %}
|
||||||
|
{{ a.comment|chill_entity_render_box }}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<ul class="record_actions sticky-form-buttons">
|
||||||
|
<li class="cancel">
|
||||||
|
<a href="{{ path('chill_person_view', { 'person_id' : person.id } ) }}" class="btn btn-cancel">
|
||||||
|
{{ 'Back to the person details'|trans }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% if is_granted('CHILL_PERSON_UPDATE', person) %}
|
||||||
|
<li>
|
||||||
|
<a class="btn btn-create"
|
||||||
|
href="{{ path('chill_person_residential_address_new', { 'id' : person.id } ) }}">
|
||||||
|
{{ 'Add a residential address'|trans }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user