Merge branch 'master' into 'fix/household-summary-show-comment-when-no-address'

# Conflicts:
#   CHANGELOG.md
This commit is contained in:
Julien Fastré 2021-10-03 19:17:35 +00:00
commit 7f661f9022
29 changed files with 491 additions and 187 deletions

View File

@ -13,7 +13,22 @@ and this project adheres to
* [Household editor][UI] Update how household suggestion and addresses are picked;
* [AddAddress] Handle address suggestion;
* [Household] Show comment event if no address are associated with the household;
* [Person results] Add requestor into search results:
* a badge "requestor" is shown into search results;
* periods where the person is only requestor (without participating) are also shown;
Issues:
* https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/13
* https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/199
* [Person form] "accept sms" not required:
https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/37
https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/221
## Test release yyyy-mm-dd
* On-The-Fly modale works for showing, editing and creating person and thirdparty
* On-The-Fly modale works for showing, editing and creating person and thirdparty ;
* AccompanyingCourse Resume page: list associated persons by household, see household when hover, and show on-the-fly modale when clicking on person ;

View File

@ -0,0 +1,41 @@
<template>
<on-the-fly
:type="context.type"
:id="context.id"
:action="context.action"
:buttonText="options.buttonText"
:displayBadge="options.displayBadge === 'true'"
@saveFormOnTheFly="saveFormOnTheFly">
</on-the-fly>
</template>
<script>
import OnTheFly from './components/OnTheFly.vue';
export default {
name: "App",
components: {
OnTheFly
},
props: ['onTheFly'],
computed: {
context() {
return this.onTheFly.context;
},
options() {
return this.onTheFly.options;
}
},
mounted() {
console.log('OnTheFly mounted');
console.log('OnTheFly: data context', this.context);
console.log('OnTheFly: data options', this.options);
},
methods: {
saveFormOnTheFly(payload) {
console.log('saveFormOnTheFly', payload);
}
}
}
</script>

View File

@ -1,6 +1,11 @@
<template>
<a class="btn btn-sm" target="_blank"
<a v-if="isDisplayBadge" @click="openModal">
<span class="chill-entity" :class="badgeType">
{{ buttonText }}
</span>
</a>
<a v-else class="btn btn-sm" target="_blank"
:class="classAction"
:title="$t(titleAction)"
@click="openModal">
@ -61,7 +66,7 @@
<script>
import Modal from 'ChillMainAssets/vuejs/_components/Modal.vue';
import OnTheFlyCreate from './OnTheFly/Create.vue';
import OnTheFlyCreate from './Create.vue';
import OnTheFlyPerson from 'ChillPersonAssets/vuejs/_components/OnTheFly/Person.vue';
import OnTheFlyThirdparty from 'ChillThirdPartyAssets/vuejs/_components/OnTheFly/ThirdParty.vue';
@ -73,7 +78,7 @@ export default {
OnTheFlyThirdparty,
OnTheFlyCreate
},
props: ['type', 'id', 'action', 'buttonText'],
props: ['type', 'id', 'action', 'buttonText', 'displayBadge'],
emits: ['saveFormOnTheFly'],
data() {
return {
@ -123,13 +128,19 @@ export default {
return 'action.redirect.' + this.type;
}
},
buttonMessage(){
buttonMessage() {
switch (this.type){
case 'person':
return 'onthefly.show.file_' + this.type;
case 'thirdparty':
return 'onthefly.show.file_' + this.type;
}
},
isDisplayBadge() {
return (this.displayBadge === true && this.buttonText !== null);
},
badgeType() {
return 'entity-' + this.type + ' badge-' + this.type;
}
},
methods: {
@ -174,10 +185,10 @@ export default {
this.modal.showModal = false;
},
buildLocation(id, type) {
if (type == 'person') {
if (type === 'person') {
// TODO i18n
return `/fr/person/${id}/general`;
} else if (type == 'thirdparty') {
} else if (type === 'thirdparty') {
return `/fr/thirdparty/thirdparty/${id}/show`;
}
}
@ -189,5 +200,4 @@ export default {
a {
cursor: pointer;
}
</style>

View File

@ -0,0 +1,24 @@
const ontheflyMessages = {
fr: {
onthefly: {
show: {
person: "Détails de l'usager",
thirdparty: "Détails du tiers",
file_person: "Ouvrir la fiche de l'usager",
file_thirdparty: "Voir le Tiers",
},
edit: {
person: "Modifier un usager",
thirdparty: "Modifier un tiers"
},
create: {
button: "Créer \"{q}\"",
title: "Création d'un nouvel usager ou d'un tiers professionnel",
person: "un nouvel usager",
thirdparty: "un nouveau tiers professionnel"
},
}
}
}
export { ontheflyMessages };

View File

@ -0,0 +1,35 @@
import { createApp } from "vue";
import { _createI18n } from 'ChillMainAssets/vuejs/_js/i18n';
import { ontheflyMessages } from './i18n.js';
import App from "./App.vue";
const i18n = _createI18n( ontheflyMessages );
let containers = document.querySelectorAll('.onthefly-container');
containers.forEach((container) => {
const app = createApp({
template: `<app :onTheFly="this.onTheFly" ></app>`,
data() {
return {
onTheFly: {
context: {
action: container.dataset.action,
type: container.dataset.targetName,
id: parseInt(container.dataset.targetId),
},
options: {
buttonText: container.dataset.buttonText || null,
displayBadge: container.dataset.displayBadge || false
}
}
}
}
})
.use(i18n)
.component('app', App)
.mount(container);
//console.log('container dataset', container.dataset);
});

View File

@ -53,24 +53,6 @@ const messages = {
top: "Haut",
bottom: "Bas",
},
onthefly: {
show: {
person: "Détails de l'usager",
thirdparty: "Détails du tiers",
file_person: "Ouvrir la fiche de l'usager",
file_thirdparty: "Voir le Tiers",
},
edit: {
person: "Modifier un usager",
thirdparty: "Modifier un tiers"
},
create: {
button: "Créer \"{q}\"",
title: "Création d'un nouvel usager ou d'un tiers professionnel",
person: "un nouvel usager",
thirdparty: "un nouveau tiers professionnel"
},
},
renderbox: {
person: "Usager",
birthday: {

View File

@ -0,0 +1,37 @@
{#
This Twig template include load vue_onthefly component.
It push all variables from context in OnTheFly/App.vue.
OPTIONS
* targetEntity {
name: string 'person', 'thirdparty'
id: integer
}
* action string 'show', 'edit', 'create'
* buttonText string
* displayBadge boolean (default: false) replace button by badge, need to define buttonText for content
#}
<span class="onthefly-container"
data-target-name="{{ targetEntity.name|e('html_attr') }}"
data-target-id="{{ targetEntity.id|e('html_attr') }}"
{% if action is defined %}
data-action="{{ action|e('html_attr') }}"
{% else %}
data-action="show"
{% endif %}
{% if buttonText is defined %}
data-button-text="{{ buttonText|e('html_attr') }}"
{% endif %}
{% if displayBadge is defined and displayBadge == 1 %}
data-display-badge="true"
{% endif %}
></span>
{{ encore_entry_script_tags('vue_onthefly') }}
{{ encore_entry_link_tags('vue_onthefly') }}

View File

@ -61,5 +61,6 @@ module.exports = function(encore, entries)
// Vue entrypoints
encore.addEntry('vue_address', __dirname + '/Resources/public/vuejs/Address/index.js');
encore.addEntry('vue_onthefly', __dirname + '/Resources/public/vuejs/OnTheFly/index.js');
};

View File

@ -118,6 +118,7 @@ class AccompanyingCourseController extends Controller
return $this->render('@ChillPerson/AccompanyingCourse/index.html.twig', [
'accompanyingCourse' => $accompanyingCourse,
'withoutHousehold' => $withoutHousehold,
'participationsByHousehold' => $accompanyingCourse->actualParticipationsByHousehold(),
'works' => $works,
'activities' => $activities
]);

View File

@ -213,7 +213,7 @@ class AccompanyingPeriod implements TrackCreationInterface, TrackUpdateInterface
private $scopes;
/**
* @ORM\ManyToOne(targetEntity=Person::class)
* @ORM\ManyToOne(targetEntity=Person::class, inversedBy="accompanyingPeriodRequested")
* @ORM\JoinColumn(nullable=true)
*/
private $requestorPerson;
@ -513,6 +513,44 @@ class AccompanyingPeriod implements TrackCreationInterface, TrackUpdateInterface
);
}
/**
* Return an array with open participations sorted by household
* [
* [
* "household" => Household x,
* "members" => [
* Participation y , Participation z, ...
* ]
* ],
* ]
*
*/
public function actualParticipationsByHousehold(): array
{
$participations = $this->getOPenParticipations()->toArray();
$households = [];
foreach ($participations as $p) {
$households[] = $p->getPerson()->getCurrentHousehold();
}
$households = array_unique($households, SORT_REGULAR);
$array = [];
foreach ($households as $household) {
$members = [];
foreach ($participations as $p) {
if ($household === $p->getPerson()->getCurrentHousehold()) {
$members[] = array_shift($participations);
} else {
$participations[] = array_shift($participations);
}
}
$array[] = [ 'household' => $household, 'members' => $members ];
}
return $array;
}
/**
* Return true if the accompanying period contains a person.
*

View File

@ -47,86 +47,91 @@ class AccompanyingPeriodParticipation
* @Groups({"read"})
*/
private $id;
/**
* @ORM\ManyToOne(targetEntity=Person::class, inversedBy="accompanyingPeriodParticipations")
* @ORM\JoinColumn(name="person_id", referencedColumnName="id", nullable=false)
* @Groups({"read"})
*/
private $person;
/**
* @ORM\ManyToOne(targetEntity=AccompanyingPeriod::class, inversedBy="participations", cascade={"persist"})
* @ORM\JoinColumn(name="accompanyingperiod_id", referencedColumnName="id", nullable=false)
*/
private $accompanyingPeriod;
/**
* @ORM\Column(type="date", nullable=false)
* @Groups({"read"})
*/
private $startDate;
/**
* @ORM\Column(type="date", nullable=true)
* @Groups({"read"})
*/
private $endDate = null;
public function __construct(AccompanyingPeriod $accompanyingPeriod, Person $person)
{
$this->startDate = new \DateTimeImmutable('now');
$this->accompanyingPeriod = $accompanyingPeriod;
$this->person = $person;
}
public function getId(): ?int
{
return $this->id;
}
public function getPerson(): ?Person
{
return $this->person;
}
public function setPerson(?Person $person): self
{
$this->person = $person;
return $this;
}
public function getAccompanyingPeriod(): ?AccompanyingPeriod
{
return $this->accompanyingPeriod;
}
public function setAccompanyingPeriod(?AccompanyingPeriod $accompanyingPeriod): self
{
$this->accompanyingPeriod = $accompanyingPeriod;
return $this;
}
public function getStartDate(): ?\DateTimeInterface
{
return $this->startDate;
}
/*
* public function setStartDate(\DateTimeInterface $startDate): self { $this->startDate = $startDate; return $this; }
*/
public function getEndDate(): ?\DateTimeInterface
{
return $this->endDate;
}
public function setEndDate(?\DateTimeInterface $endDate): self
{
$this->endDate = $endDate;
return $this;
}
public function isOpen(): bool
{
return $this->endDate === null;
}
}

View File

@ -28,9 +28,9 @@ use Chill\MainBundle\Doctrine\Model\TrackUpdateInterface;
use Chill\MainBundle\Entity\Center;
use Chill\MainBundle\Entity\Country;
use Chill\MainBundle\Entity\User;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\Household\Household;
use Chill\PersonBundle\Entity\MaritalStatus;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\Household\HouseholdMember;
use Chill\MainBundle\Entity\HasCenterInterface;
use Chill\MainBundle\Entity\Address;
@ -329,6 +329,15 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
*/
private $accompanyingPeriodParticipations;
/**
* The accompanying period requested by the Person
*
* @ORM\OneToMany(targetEntity=AccompanyingPeriod::class,
* mappedBy="requestorPerson")
* @var Collection|AccompanyingPeriod[]
*/
private Collection $accompanyingPeriodRequested;
/**
* A remark over the person
* @var string
@ -478,6 +487,7 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
$this->genderComment = new CommentEmbeddable();
$this->maritalStatusComment = new CommentEmbeddable();
$this->periodLocatedOn = new ArrayCollection();
$this->accompanyingPeriodRequested = new ArrayCollection();
}
/**
@ -605,6 +615,8 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
/**
* Get AccompanyingPeriodParticipations Collection
*
* @return AccompanyingPeriodParticipation[]|Collection
*/
public function getAccompanyingPeriodParticipations(): Collection
{
@ -614,6 +626,8 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
/**
* Return a collection of participation, where the participation
* is still opened, not a draft, and the period is still opened
*
* @return AccompanyingPeriodParticipation[]|Collection
*/
public function getOpenedParticipations(): Collection
{
@ -1650,6 +1664,84 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
return $this;
}
/**
* @return AccompanyingPeriod[]|Collection
*/
public function getAccompanyingPeriodRequested(): Collection
{
return $this->accompanyingPeriodRequested;
}
/**
* Return a list of all accompanying period where the person is involved:
*
* * as requestor;
* * as participant, only for opened participation;
*
* @param bool $asParticipantOpen add participation which are still opened
* @param bool $asRequestor add accompanying period where the person is requestor
* @return AccompanyingPeriod[]|Collection
*/
public function getAccompanyingPeriodInvolved(
bool $asParticipantOpen = true,
bool $asRequestor = true
): Collection
{
$result = new ArrayCollection();
if ($asParticipantOpen) {
foreach ($this->getOpenedParticipations()
->map(fn (AccompanyingPeriodParticipation $app) =>
$app->getAccompanyingPeriod())
as $period
) {
if (!$result->contains($period)) {
$result->add($period);
}
}
}
if ($asRequestor) {
foreach ($this->accompanyingPeriodRequested as $period) {
if (!$result->contains($period)) {
$result->add($period);
}
}
}
return $result;
}
/**
* Handy method to get the AccompanyingPeriodParticipation
* matching a given AccompanyingPeriod.
*
* Used in template, to find the participation when iterating on a list
* of period.
*
* @param \Chill\PersonBundle\Entity\AccompanyingPeriod $period
* @return AccompanyingPeriodParticipation
*/
public function findParticipationForPeriod(AccompanyingPeriod $period): ?AccompanyingPeriodParticipation
{
$closeCandidates = [];
foreach ($this->getAccompanyingPeriodParticipations() as $participation) {
if ($participation->getAccompanyingPeriod() === $period) {
if ($participation->isOpen()) {
return $participation;
}
$closeCandidates[] = $participation;
}
}
if (0 < count($closeCandidates)) {
return $closeCandidates[0];
}
return null;
}
public function getCreatedBy(): ?User
{
return $this->createdBy;

View File

@ -129,8 +129,7 @@ class PersonType extends AbstractType
$builder
->add('mobilenumber', TelType::class, array('required' => false))
->add('acceptSMS', CheckboxType::class, array(
'value' => false,
'required' => true
'required' => false
));
}

View File

@ -247,3 +247,28 @@ span.fa-holder {
font-family: "Open Sans Extrabold";
}
}
div.accompanyingcourse-resume {
div.associated-persons {
span.household {
display: inline-block;
border-radius: 8px;
border: 1px solid $white;
&:hover {
border: 1px solid $chill-beige;
i {
display: inline-block;
}
}
&.no-household:hover {
border: 1px solid $white;
}
i {
color: $chill-beige;
display: none;
}
padding: 0.3em;
margin-right: 2px;
}
}
}

View File

@ -57,7 +57,7 @@
</template>
<script>
import OnTheFly from 'ChillMainAssets/vuejs/_components/OnTheFly.vue';
import OnTheFly from 'ChillMainAssets/vuejs/OnTheFly/components/OnTheFly.vue';
import ButtonLocation from '../ButtonLocation.vue';
import PersonRenderBox from 'ChillPersonAssets/vuejs/_components/Entity/PersonRenderBox.vue';
import Modal from 'ChillMainAssets/vuejs/_components/Modal';

View File

@ -79,7 +79,7 @@
<script>
import AddPersons from 'ChillPersonAssets/vuejs/_components/AddPersons.vue';
import OnTheFly from 'ChillMainAssets/vuejs/_components/OnTheFly.vue';
import OnTheFly from 'ChillMainAssets/vuejs/OnTheFly/components/OnTheFly.vue';
import PersonRenderBox from '../../_components/Entity/PersonRenderBox.vue';
import ThirdPartyRenderBox from 'ChillThirdPartyAssets/vuejs/_components/Entity/ThirdPartyRenderBox.vue';

View File

@ -33,7 +33,7 @@
</template>
<script>
import OnTheFly from 'ChillMainAssets/vuejs/_components/OnTheFly.vue';
import OnTheFly from 'ChillMainAssets/vuejs/OnTheFly/components/OnTheFly.vue';
import ButtonLocation from '../ButtonLocation.vue';
import PersonRenderBox from 'ChillPersonAssets/vuejs/_components/Entity/PersonRenderBox.vue';
import ThirdPartyRenderBox from 'ChillThirdPartyAssets/vuejs/_components/Entity/ThirdPartyRenderBox.vue';

View File

@ -1,6 +1,7 @@
import { personMessages } from 'ChillPersonAssets/vuejs/_js/i18n';
import { thirdpartyMessages } from 'ChillThirdPartyAssets/vuejs/_js/i18n';
import { addressMessages } from 'ChillMainAssets/vuejs/Address/i18n';
import { ontheflyMessages } from 'ChillMainAssets/vuejs/OnTheFly/i18n';
const appMessages = {
fr: {
@ -142,7 +143,7 @@ const appMessages = {
}
};
Object.assign(appMessages.fr, personMessages.fr, thirdpartyMessages.fr, addressMessages.fr);
Object.assign(appMessages.fr, personMessages.fr, thirdpartyMessages.fr, addressMessages.fr, ontheflyMessages.fr);
export {
appMessages

View File

@ -88,7 +88,7 @@
<script>
import Modal from 'ChillMainAssets/vuejs/_components/Modal';
import OnTheFly from 'ChillMainAssets/vuejs/_components/OnTheFly.vue';
import OnTheFly from 'ChillMainAssets/vuejs/OnTheFly/components/OnTheFly.vue';
import PersonSuggestion from './AddPersons/PersonSuggestion';
import { searchPersons, searchPersons_2 } from 'ChillPersonAssets/vuejs/_api/AddPersons';
import { postPerson } from "ChillPersonAssets/vuejs/_api/OnTheFly";

View File

@ -28,7 +28,7 @@
</template>
<script>
import OnTheFly from 'ChillMainAssets/vuejs/_components/OnTheFly.vue';
import OnTheFly from 'ChillMainAssets/vuejs/OnTheFly/components/OnTheFly.vue';
export default {
name: 'SuggestionPerson',

View File

@ -25,7 +25,7 @@
</template>
<script>
import OnTheFly from 'ChillMainAssets/vuejs/_components/OnTheFly.vue';
import OnTheFly from 'ChillMainAssets/vuejs/OnTheFly/components/OnTheFly.vue';
export default {
name: 'SuggestionThirdParty',

View File

@ -1,41 +1,16 @@
<div class="border border-warning">
<div class="alert alert-warning alert-with-actions mb-0">
<div class="message">
{{ 'Some peoples does not belong to any household currently. Add them to an household soon'|trans }}
</div>
<ul class="record_actions">
<li>
<button class="btn btn-chill-beige" data-bs-toggle="collapse" href="#withoutHouseholdList">
<i class="fa fa-fw fa-caret-down"></i><span class="">{{ 'Add to household now'|trans }}</span>
</button>
</li>
</ul>
</div>
<div id="withoutHouseholdList" class="collapse p-3">
<form method="GET"
action="{{ path('chill_person_household_members_editor') }}">
<h3>{{ 'household.Select people to move'|trans }}</h3>
<ul>
{% for p in withoutHousehold %}
<li>
<input type="checkbox" name="persons[]" value="{{ p.id }}" checked />
{{ p|chill_entity_render_box }}
</li>
{% endfor %}
</ul>
<input type="hidden" name="expand_suggestions" value="true" />
<input type="hidden" name="returnPath" value="{{ app.request.requestUri|escape('html_attr') }}" />
<input type="hidden" name="accompanying_period_id" value="{{ accompanyingCourse.id }}" />
<ul class="record_actions mb-0">
<div class="alert alert-warning alert-with-actions">
<div class="float-button bottom"><div class="box">
<div class="action">
<ul class="record_actions">
<li>
<button type="submit" class="btn btn-edit">
{{ 'household.Household editor'|trans }}
</button>
<a class="btn btn-sm btn-update change-icon"
href="{{ path('chill_person_accompanying_course_edit', { 'accompanying_period_id': accompanyingCourse.id, '_fragment': 'section-10' }) }}">
<i class="fa fa-fw fa-crosshairs"></i>
Corriger
</a>
</li>
</ul>
</form>
</div>
</div>
{{ 'Some peoples does not belong to any household currently. Add them to an household soon'|trans }}
</div></div>
</div>

View File

@ -0,0 +1,16 @@
<div class="alert alert-warning">
<div class="float-button bottom"><div class="box">
<div class="action">
<ul class="record_actions">
<li>
<a class="btn btn-sm btn-update change-icon"
href="{{ path('chill_person_accompanying_course_edit', { 'accompanying_period_id': accompanyingCourse.id, '_fragment': 'section-100' } ) }}">
<i class="fa fa-fw fa-crosshairs"></i>
{{ 'Edit & activate accompanying course'|trans }}
</a>
</li>
</ul>
</div>
<p>{{ 'This accompanying course is still a draft'|trans }}</p>
</div></div>
</div>

View File

@ -1,61 +1,23 @@
{%- set countPersonLocation = accompanyingCourse.availablePersonLocation|length -%}
{%- set hasPersonLocation = countPersonLocation|length > 0 -%}
{% macro quickLocationForm(accompanyingCourse, person, whichButton) %}
<form method="PATCH" action="{{ path('chill_api_single_accompanying_course__entity', {'id': accompanyingCourse.id, '_format': 'json'}) }}" class="quickLocationForm">
<input type="hidden" name="personLocation" value="{{ person.id }}" />
<input type="hidden" name="periodId" value="{{ accompanyingCourse.id }}" />
{% if whichButton == 'string' %}
<button type="submit" class="btn btn-chill-pink">
<span class="text-light">{{ 'Locate by'|trans }} {{ person|chill_entity_render_string }}</span>
</button>
{% elseif whichButton == 'icon' %}
<button type="submit" class="btn btn-sm btn-secondary">
<i class="fa fa-map-marker"></i>
</button>
{% endif %}
</form>
{% endmacro %}
<div class="border border-danger">
<div class="alert alert-danger {% if hasPersonLocation %}alert-with-actions{% endif %} mb-0">
<div class="message">
{{ 'This course is located at a temporarily address. You should locate this course to an user'|trans }}
{% if not hasPersonLocation %}
{{ 'Associate at least one member with an household, and set an address to this household'|trans }}
{% endif %}
</div>
{% if 1 == countPersonLocation %}
{%- set hasPersonLocation = countPersonLocation > 0 -%}
<div class="alert alert-danger {% if hasPersonLocation %}alert-with-actions{% endif %}">
<div class="float-button bottom"><div class="box">
<div class="action">
<ul class="record_actions">
<li>
{{ _self.quickLocationForm(accompanyingCourse, accompanyingCourse.availablePersonLocation.first, 'string') }}
<a class="btn btn-sm btn-update change-icon"
href="{{ path('chill_person_accompanying_course_edit', { 'accompanying_period_id': accompanyingCourse.id, '_fragment': 'section-20' }) }}">
<i class="fa fa-fw fa-crosshairs"></i>
Corriger
</a>
</li>
</ul>
{% elseif 1 < countPersonLocation %}
<ul class="record_actions">
<li>
<button class="btn btn-chill-pink" data-bs-toggle="collapse" href="#locateAtPerson">
<i class="fa fa-fw fa-caret-down"></i><span class="text-light">{{ 'Choose a person to locate by'|trans }}</span>
</button>
</li>
</ul>
{% endif %}
</div>
{% if 1 < countPersonLocation %}
<div id="locateAtPerson" class="collapse">
<p>{{ 'Locate by'|trans }}:</p>
<div class="flex-table mb-3">
{% for p in accompanyingCourse.availablePersonLocation %}
<div class="item-bloc">
{{ p|chill_entity_render_box({
'render': 'bloc', 'addLink': false, 'addInfo': true, 'addAltNames': false, 'customButtons': {
'replace': _self.quickLocationForm(accompanyingCourse, p, 'icon')
}
}) }}
</div>
{% endfor %}
</div>
</div>
{% endif %}
<p>
{{ 'This course is located at a temporarily address. You should locate this course to an user'|trans }}</p>
{% if not hasPersonLocation %}
<p>
{{ 'Associate at least one member with an household, and set an address to this household'|trans }}</p>
{% endif %}
</div></div>
</div>

View File

@ -21,22 +21,69 @@
{% endblock %}
{% block content %}
<div class="accompanyingcourse-resume">
<div class="accompanyingcourse-resume row">
<div class="associated-persons mb-5">
{% for h in participationsByHousehold %}
{% set householdClass = (h.household is not null) ? 'household-' ~ h.household.id : 'no-household alert alert-warning' %}
{% set householdTitle = (h.household is not null) ?
'household.Household number'|trans({'household_num': h.household.id }) : 'household.Never in any household'|trans %}
<span class="household {{ householdClass }}" title="{{ householdTitle }}">
{% if h.household is not null %}
<a href="{{ path('chill_person_household_summary', { 'household_id': h.household.id }) }}"
title="{{ 'household.Household number'|trans({'household_num': h.household.id }) }}"
><i class="fa fa-home fa-fw"></i></a>
{% endif %}
{% for p in h.members %}
{# include vue_onthefly component #}
{% include '@ChillMain/OnTheFly/_insert_vue_onthefly.html.twig' with {
targetEntity: { name: 'person', id: p.person.id },
action: 'show',
displayBadge: true,
buttonText: p.person|chill_entity_render_string
} %}
{% endfor %}
</span>
{% endfor %}
</div>
<div class="col-md-6 location mb-5">
{% if accompanyingCourse.locationStatus == 'person' %}
<h5>{{ 'This course is located by'|trans }}</h5>
<h4>{{ accompanyingCourse.personLocation|chill_entity_render_string }}</h4>
{% elseif accompanyingCourse.locationStatus == 'address' %}
<h4>{{ 'This course has a temporarily location'|trans }}</h4>
{% endif %}
{% if accompanyingCourse.locationStatus != 'none' %}
{{ accompanyingCourse.location|chill_entity_render_box }}
{% endif %}
</div>
{% if 'DRAFT' == accompanyingCourse.step %}
<div class="alert alert-danger flash_message mb-5">
<span>
{{ 'This accompanying course is still a draft'|trans }}
<a href="{{ path('chill_person_accompanying_course_edit', { 'accompanying_period_id': accompanyingCourse.id } ) }}">
{{ 'Edit & activate accompanying course'|trans }}
</a>
</span>
<div class="col-md-6 warnings mb-5">
{% include '@ChillPerson/AccompanyingCourse/_still_draft.html.twig' %}
</div>
{% endif %}
<pre>WIP .. AccompanyingCourse Resume dashboard</pre>
{% if accompanyingCourse.locationStatus == 'address' or accompanyingCourse.locationStatus == 'none' %}
<div class="col-md-6 warnings mb-5">
{% include '@ChillPerson/AccompanyingCourse/_warning_address.html.twig' %}
</div>
{% endif %}
{#
{% if 'DRAFT' != accompanyingCourse.step %}
{% if withoutHousehold|length > 0 %}
<div class="col-md-6 warnings mb-5">
{% include '@ChillPerson/AccompanyingCourse/_join_household.html.twig' %}
</div>
{% endif %}
{% endif %}
{# DISABLED
<h1>{{ 'Resume Accompanying Course'|trans }}</h1>
<div class="associated-persons mb-5">
@ -53,13 +100,6 @@
{% endif %}
{% endfor %}
</div>
#}
{% if 'DRAFT' != accompanyingCourse.step %}
{% if withoutHousehold|length > 0 %}
{% include '@ChillPerson/AccompanyingCourse/_join_household.html.twig' with {} %}
{% endif %}
{% endif %}
{#
</div>
<div class="location mb-5">
@ -80,11 +120,6 @@
</div>
</div>
{% endif %}
#}
{% if accompanyingCourse.locationStatus == 'address' or accompanyingCourse.locationStatus == 'none' %}
{% include '@ChillPerson/AccompanyingCourse/_warning_address.html.twig' with {} %}
{% endif %}
{#
</div>
<div class="requestor mb-5">

View File

@ -59,47 +59,51 @@
'customButtons': { 'after': _self.button_person(person) }
}) }}
{#- 'apps' is for AccompanyingPeriodParticipationS #}
{%- set apps = [] %}
{%- for app in person.openedParticipations %}
{%- if is_granted('CHILL_PERSON_ACCOMPANYING_PERIOD_SEE', app.accompanyingPeriod) %}
{%- set apps = apps|merge([app]) %}
{#- 'acps' is for AcCompanyingPeriodS #}
{%- set acps = [] %}
{%- for acp in person.accompanyingPeriodInvolved %}
{%- if is_granted('CHILL_PERSON_ACCOMPANYING_PERIOD_SEE', acp) %}
{%- set acps = acps|merge([acp]) %}
{%- endif %}
{%- endfor %}
{% if apps|length > 0 %}
{# add as requestor #}
{% if acps|length > 0 %}
<div class="item-row">
<div class="wrap-list periods-list">
{% for app in apps %}
{% for acp in acps %}
{% set app = person.findParticipationForPeriod(acp) %}
<div class="wl-row separator">
<div class="wl-col title">
<div class="date">
{{ 'Since %date%'|trans({'%date%': app.startDate|format_date('medium') }) }}
{% 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 app != null %}
{{ 'Since %date%'|trans({'%date%': app.startDate|format_date('medium') }) }}
{% endif %}
</div>
{% if app.accompanyingPeriod.user is not null %}
{% if acp.user is not null %}
<div class="user">
<abbr class="referrer" title="{{ 'Referrer'|trans }}">ref:</abbr>
{{ app.accompanyingPeriod.user|chill_entity_render_box }}
{{ acp.user|chill_entity_render_box }}
</div>
{% endif %}
</div>
<div class="wl-col list">
{% for issue in app.accompanyingPeriod.socialIssues %}
{% for issue in acp.socialIssues %}
{{ issue|chill_entity_render_box }}
{% endfor %}
{# ^^ display all socialIssues, or slice vv
|slice(0,2)
{% if app.accompanyingPeriod.socialIssues|length > 2 %}
<span class="more">{{ 'and %number% other'|transchoice(app.accompanyingPeriod.socialIssues|length-2) }}</span>
{% endif %}
#}
<ul class="record_actions">
<li>
<a href="{{ path('chill_person_accompanying_course_index', { 'accompanying_period_id': app.accompanyingPeriod.id }) }}"
<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>

View File

@ -5,6 +5,13 @@ Born the date: >-
other {Né·e le {birthdate}}
}
Requestor: >-
{gender, select,
man {Demandeur}
woman {Demandeuse}
other {Demandeur·euse}
}
household:
Household: Ménage
Household number: Ménage {household_num}

View File

@ -186,10 +186,9 @@ No accompanying user: Aucun accompagnant
No data given: Pas d'information
Participants: Personnes impliquées
Create an accompanying course: Créer un parcours
This accompanying course is still a draft: Ce parcours est à l'état brouillon
This accompanying course is still a draft: Ce parcours est encore à l'état brouillon.
Associated peoples: Usagers concernés
Resources: Interlocuteurs privilégiés
Requestor: Demandeur
Any requestor to this accompanying course: Aucun demandeur pour ce parcours
Social actions: Actions d'accompagnement
Social issues: Problématiques sociales