mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-06-07 18:44:08 +00:00
Merge branch 'master' into issue303_household_fixes
This commit is contained in:
commit
06f8014b76
@ -34,6 +34,7 @@ and this project adheres to
|
|||||||
* Household: show date validFrom and validTo when moving
|
* Household: show date validFrom and validTo when moving
|
||||||
* address reference: add index for refid
|
* address reference: add index for refid
|
||||||
* [accompanyingCourse_work] fix styles conflicts + fix bug with remove goal (remove goals one at a time)
|
* [accompanyingCourse_work] fix styles conflicts + fix bug with remove goal (remove goals one at a time)
|
||||||
|
* [accompanyingCourse] improve masonry on resume page, add origin
|
||||||
|
|
||||||
## Test releases
|
## Test releases
|
||||||
|
|
||||||
|
@ -11,8 +11,6 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Chill\PersonBundle\Config;
|
namespace Chill\PersonBundle\Config;
|
||||||
|
|
||||||
use function count;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Give help to interact with the config for alt names.
|
* Give help to interact with the config for alt names.
|
||||||
*/
|
*/
|
||||||
@ -69,6 +67,6 @@ class ConfigPersonAltNamesHelper
|
|||||||
*/
|
*/
|
||||||
public function hasAltNames(): bool
|
public function hasAltNames(): bool
|
||||||
{
|
{
|
||||||
return count($this->config) > 0;
|
return [] !== $this->config;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,15 +15,14 @@ use Chill\MainBundle\CRUD\Controller\ApiController;
|
|||||||
use Chill\MainBundle\Entity\Address;
|
use Chill\MainBundle\Entity\Address;
|
||||||
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
|
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
|
||||||
use Chill\PersonBundle\Config\ConfigPersonAltNamesHelper;
|
use Chill\PersonBundle\Config\ConfigPersonAltNamesHelper;
|
||||||
|
use Chill\PersonBundle\Entity\AccompanyingPeriodParticipation;
|
||||||
use Chill\PersonBundle\Entity\Person;
|
use Chill\PersonBundle\Entity\Person;
|
||||||
use Chill\PersonBundle\Security\Authorization\PersonVoter;
|
use Chill\PersonBundle\Security\Authorization\PersonVoter;
|
||||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
|
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
|
||||||
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 function in_array;
|
||||||
use function array_filter;
|
|
||||||
use function array_values;
|
|
||||||
|
|
||||||
class PersonApiController extends ApiController
|
class PersonApiController extends ApiController
|
||||||
{
|
{
|
||||||
@ -57,7 +56,9 @@ class PersonApiController extends ApiController
|
|||||||
$configAltNamesChoices,
|
$configAltNamesChoices,
|
||||||
array_keys($configAltNamesChoices)
|
array_keys($configAltNamesChoices)
|
||||||
),
|
),
|
||||||
Response::HTTP_OK, [], ['groups' => ['read']]
|
Response::HTTP_OK,
|
||||||
|
[],
|
||||||
|
['groups' => ['read']]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,23 +80,51 @@ class PersonApiController extends ApiController
|
|||||||
{
|
{
|
||||||
$this->denyAccessUnlessGranted(PersonVoter::SEE, $person);
|
$this->denyAccessUnlessGranted(PersonVoter::SEE, $person);
|
||||||
|
|
||||||
$addresses = [];
|
$seenAddressIds = [];
|
||||||
|
|
||||||
// collect addresses from location in courses
|
// collect addresses from location in courses
|
||||||
foreach ($person->getAccompanyingPeriodParticipations() as $participation) {
|
$addresses = $person
|
||||||
if (null !== $participation->getAccompanyingPeriod()->getAddressLocation()) {
|
->getAccompanyingPeriodParticipations()
|
||||||
$a = $participation->getAccompanyingPeriod()->getAddressLocation();
|
->filter(
|
||||||
$addresses[$a->getId()] = $a;
|
static function (AccompanyingPeriodParticipation $accompanyingPeriodParticipation): bool {
|
||||||
|
return null !== $accompanyingPeriodParticipation->getAccompanyingPeriod()->getAddressLocation();
|
||||||
}
|
}
|
||||||
|
)
|
||||||
|
->map(
|
||||||
|
static function (AccompanyingPeriodParticipation $accompanyingPeriodParticipation): ?Address {
|
||||||
|
return $accompanyingPeriodParticipation->getAccompanyingPeriod()->getAddressLocation();
|
||||||
}
|
}
|
||||||
|
)
|
||||||
|
->filter(
|
||||||
|
// We remove potential null addresses.
|
||||||
|
static fn (?Address $address): bool => null !== $address
|
||||||
|
)
|
||||||
|
->filter(
|
||||||
|
static function (Address $address) use (&$seenAddressIds): bool {
|
||||||
|
$id = $address->getId();
|
||||||
|
|
||||||
|
if (in_array($id, $seenAddressIds, true)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$seenAddressIds[] = $id;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
// remove the actual address
|
// remove the actual address
|
||||||
$actual = $person->getCurrentHouseholdAddress();
|
$actual = $person->getCurrentHouseholdAddress();
|
||||||
|
|
||||||
if (null !== $actual) {
|
if (null !== $actual) {
|
||||||
$addresses = array_filter($addresses, static fn ($a) => $a !== $actual);
|
$addresses = $addresses->filter(static fn (Address $address): bool => $address !== $actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->json(array_values($addresses), Response::HTTP_OK, [], ['groups' => ['read']]);
|
return $this->json(
|
||||||
|
$addresses->getValues(),
|
||||||
|
Response::HTTP_OK,
|
||||||
|
[],
|
||||||
|
['groups' => ['read']]
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -254,3 +254,24 @@ abbr.referrer { // still used ?
|
|||||||
border: 1px solid black;
|
border: 1px solid black;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Masonry blocs on AccompanyingCourse resume page
|
||||||
|
div#dashboards {
|
||||||
|
div.mbloc {
|
||||||
|
& > div:not(.warnings) {
|
||||||
|
border: 1px solid $chill-light-gray;
|
||||||
|
background-color: $chill-llight-gray;
|
||||||
|
border-radius: 0.35rem;
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
& > div.warnings .alert {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
blockquote.chill-user-quote {
|
||||||
|
margin: -1.2em;
|
||||||
|
p {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -21,29 +21,37 @@
|
|||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="accompanyingcourse-resume">
|
<div class="accompanyingcourse-resume">
|
||||||
|
|
||||||
<div id="dashboards" class="row" data-masonry='{"percentPosition": true }'>
|
<div id="dashboards" class="row g-3" data-masonry='{"percentPosition": true }'>
|
||||||
|
|
||||||
{% if 'DRAFT' == accompanyingCourse.step %}
|
{% if 'DRAFT' == accompanyingCourse.step %}
|
||||||
<div class="col-4 warnings mb-4">
|
<div class="mbloc col col-sm-6 col-lg-4">
|
||||||
|
<div class="warnings">
|
||||||
{% include '@ChillPerson/AccompanyingCourse/_still_draft.html.twig' %}
|
{% include '@ChillPerson/AccompanyingCourse/_still_draft.html.twig' %}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if 'DRAFT' != accompanyingCourse.step %}
|
{% if 'DRAFT' != accompanyingCourse.step %}
|
||||||
{% if withoutHousehold|length > 0 %}
|
{% if withoutHousehold|length > 0 %}
|
||||||
<div class="col-4 warnings mb-4">
|
<div class="mbloc col col-sm-6 col-lg-4">
|
||||||
|
<div class="warnings">
|
||||||
{% include '@ChillPerson/AccompanyingCourse/_join_household.html.twig' %}
|
{% include '@ChillPerson/AccompanyingCourse/_join_household.html.twig' %}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if accompanyingCourse.locationStatus == 'address'
|
{% if accompanyingCourse.locationStatus == 'address'
|
||||||
or accompanyingCourse.locationStatus == 'none' %}
|
or accompanyingCourse.locationStatus == 'none' %}
|
||||||
<div class="col-4 warnings mb-4">
|
<div class="mbloc col col-sm-6 col-lg-4">
|
||||||
|
<div class="warnings">
|
||||||
{% include '@ChillPerson/AccompanyingCourse/_warning_address.html.twig' %}
|
{% include '@ChillPerson/AccompanyingCourse/_warning_address.html.twig' %}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<div class="col col-sm-6 col-lg-4 location mb-4">
|
<div class="mbloc col col-sm-6 col-lg-4">
|
||||||
|
<div class="location">
|
||||||
{% if accompanyingCourse.locationStatus == 'person' %}
|
{% if accompanyingCourse.locationStatus == 'person' %}
|
||||||
<h2>{{ 'This course is located by'|trans }}</h2>
|
<h2>{{ 'This course is located by'|trans }}</h2>
|
||||||
<h4>{{ accompanyingCourse.personLocation|chill_entity_render_string }}</h4>
|
<h4>{{ accompanyingCourse.personLocation|chill_entity_render_string }}</h4>
|
||||||
@ -55,34 +63,15 @@
|
|||||||
{{ accompanyingCourse.location|chill_entity_render_box }}
|
{{ accompanyingCourse.location|chill_entity_render_box }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% if accompanyingCourse.participations is not empty %}
|
|
||||||
<div class="col col-sm-6 col-lg-4 persons mb-4">
|
|
||||||
<h4 class="item-key">{{ 'Persons associated'|trans }}</h4>
|
|
||||||
{% for r in accompanyingCourse.participations %}
|
|
||||||
{{ _self.insert_onthefly('person', r.person) }}
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if accompanyingCourse.resources is not empty %}
|
|
||||||
<div class="col col-sm-6 col-lg-4 resources mb-4">
|
|
||||||
<h4 class="item-key">{{ 'Resources'|trans }}</h4>
|
|
||||||
{% for r in accompanyingCourse.resources %}
|
|
||||||
{% if r.person is not null %}
|
|
||||||
{{ _self.insert_onthefly('person', r.person) }}
|
|
||||||
{% elseif r.thirdParty is not null %}
|
|
||||||
{{ _self.insert_onthefly('thirdparty', r.thirdParty) }}
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if accompanyingCourse.pinnedComment is not empty %}
|
{% if accompanyingCourse.pinnedComment is not empty %}
|
||||||
<div class="col col-sm-6 col-lg-4 comment mb-4">
|
<div class="mbloc col col-sm-6 col-lg-8">
|
||||||
<h4 class="item-key">{{ 'Pinned comment'|trans }}</h4>
|
<div class="comment">
|
||||||
|
<h4 class="item-key visually-hidden">{{ 'Pinned comment'|trans }}</h4>
|
||||||
<blockquote class="chill-user-quote">
|
<blockquote class="chill-user-quote">
|
||||||
{{ accompanyingCourse.pinnedComment.content }}
|
<i class="fa fa-flag float-end text-chill-gray" title="{{ 'pinned'|trans }}"></i>
|
||||||
|
{{ accompanyingCourse.pinnedComment.content|chill_markdown_to_html }}
|
||||||
<div class="metadata">
|
<div class="metadata">
|
||||||
{{ 'Last updated by'| trans }}
|
{{ 'Last updated by'| trans }}
|
||||||
<span class="user">
|
<span class="user">
|
||||||
@ -95,10 +84,38 @@
|
|||||||
</div>
|
</div>
|
||||||
</blockquote>
|
</blockquote>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if accompanyingCourse.participations is not empty %}
|
||||||
|
<div class="mbloc col col-sm-6 col-lg-4">
|
||||||
|
<div class="persons">
|
||||||
|
<h4 class="item-key">{{ 'Persons associated'|trans }}</h4>
|
||||||
|
{% for r in accompanyingCourse.participations %}
|
||||||
|
{{ _self.insert_onthefly('person', r.person) }}
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if accompanyingCourse.resources is not empty %}
|
||||||
|
<div class="mbloc col col-sm-6 col-lg-4">
|
||||||
|
<div class="resources">
|
||||||
|
<h4 class="item-key">{{ 'Resources'|trans }}</h4>
|
||||||
|
{% for r in accompanyingCourse.resources %}
|
||||||
|
{% if r.person is not null %}
|
||||||
|
{{ _self.insert_onthefly('person', r.person) }}
|
||||||
|
{% elseif r.thirdParty is not null %}
|
||||||
|
{{ _self.insert_onthefly('thirdparty', r.thirdParty) }}
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if accompanyingCourse.scopes is not empty %}
|
{% if accompanyingCourse.scopes is not empty %}
|
||||||
<div class="col col-sm-6 col-lg-4 scopes mb-4">
|
<div class="mbloc col col-sm-6 col-lg-4">
|
||||||
|
<div class="scopes">
|
||||||
<h4 class="item-key">{{ 'Scopes'|trans }}</h4>
|
<h4 class="item-key">{{ 'Scopes'|trans }}</h4>
|
||||||
<div>
|
<div>
|
||||||
{% for s in accompanyingCourse.scopes %}
|
{% for s in accompanyingCourse.scopes %}
|
||||||
@ -106,10 +123,12 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if accompanyingCourse.requestorPerson is not null or accompanyingCourse.requestorThirdParty is not null %}
|
{% if accompanyingCourse.requestorPerson is not null or accompanyingCourse.requestorThirdParty is not null %}
|
||||||
<div class="col col-sm-6 col-lg-4 requestor mb-4">
|
<div class="mbloc col col-sm-6 col-lg-4">
|
||||||
|
<div class="requestor">
|
||||||
{% if accompanyingCourse.requestorPerson is not null %}
|
{% if accompanyingCourse.requestorPerson is not null %}
|
||||||
<h4 class="item-key">{{ 'Requestor'|trans }}</h4>
|
<h4 class="item-key">{{ 'Requestor'|trans }}</h4>
|
||||||
{{ _self.insert_onthefly('person', accompanyingCourse.requestorPerson) }}
|
{{ _self.insert_onthefly('person', accompanyingCourse.requestorPerson) }}
|
||||||
@ -118,7 +137,18 @@
|
|||||||
{{ _self.insert_onthefly('thirdparty', accompanyingCourse.requestorThirdParty) }}
|
{{ _self.insert_onthefly('thirdparty', accompanyingCourse.requestorThirdParty) }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
{% if accompanyingCourse.origin is not empty %}
|
||||||
|
<div class="mbloc col col-sm-6 col-lg-4">
|
||||||
|
<div class="origin">
|
||||||
|
<h4 class="item-key">{{ 'Origin'|trans }}</h4>
|
||||||
|
{{ accompanyingCourse.origin.label|localize_translatable_string|capitalize }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="social-actions my-4">
|
<div class="social-actions my-4">
|
||||||
|
@ -19,7 +19,7 @@ use Chill\PersonBundle\Entity\PersonAltName;
|
|||||||
use Chill\PersonBundle\Repository\PersonRepository;
|
use Chill\PersonBundle\Repository\PersonRepository;
|
||||||
use DateTime;
|
use DateTime;
|
||||||
use DateTimeImmutable;
|
use DateTimeImmutable;
|
||||||
use LogicException;
|
use Doctrine\Common\Collections\Collection;
|
||||||
use Symfony\Component\Serializer\Exception\UnexpectedValueException;
|
use Symfony\Component\Serializer\Exception\UnexpectedValueException;
|
||||||
use Symfony\Component\Serializer\Normalizer\DenormalizerAwareInterface;
|
use Symfony\Component\Serializer\Normalizer\DenormalizerAwareInterface;
|
||||||
use Symfony\Component\Serializer\Normalizer\DenormalizerAwareTrait;
|
use Symfony\Component\Serializer\Normalizer\DenormalizerAwareTrait;
|
||||||
@ -79,13 +79,24 @@ class PersonJsonNormalizer implements
|
|||||||
$person = new Person();
|
$person = new Person();
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (['firstName', 'lastName', 'phonenumber', 'mobilenumber', 'gender',
|
$fields = [
|
||||||
'birthdate', 'deathdate', 'center', 'altNames', ]
|
'firstName',
|
||||||
as $item) {
|
'lastName',
|
||||||
if (!array_key_exists($item, $data)) {
|
'phonenumber',
|
||||||
continue;
|
'mobilenumber',
|
||||||
}
|
'gender',
|
||||||
|
'birthdate',
|
||||||
|
'deathdate',
|
||||||
|
'center',
|
||||||
|
'altNames',
|
||||||
|
];
|
||||||
|
|
||||||
|
$fields = array_filter(
|
||||||
|
$fields,
|
||||||
|
static fn (string $field): bool => array_key_exists($field, $data)
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach ($fields as $item) {
|
||||||
switch ($item) {
|
switch ($item) {
|
||||||
case 'firstName':
|
case 'firstName':
|
||||||
$person->setFirstName($data[$item]);
|
$person->setFirstName($data[$item]);
|
||||||
@ -149,9 +160,6 @@ class PersonJsonNormalizer implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
|
||||||
throw new LogicException("item not defined: {$item}");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -194,14 +202,22 @@ class PersonJsonNormalizer implements
|
|||||||
return $data instanceof Person && 'json' === $format;
|
return $data instanceof Person && 'json' === $format;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function normalizeAltNames($altNames): array
|
/**
|
||||||
|
* @param Collection<array-key, PersonAltName> $altNames
|
||||||
|
*
|
||||||
|
* @return array<array-key, array<string, string>>
|
||||||
|
*/
|
||||||
|
protected function normalizeAltNames(Collection $altNames): array
|
||||||
{
|
{
|
||||||
$r = [];
|
return $altNames
|
||||||
|
->map(
|
||||||
foreach ($altNames as $n) {
|
static function (PersonAltName $personAltName): array {
|
||||||
$r[] = ['key' => $n->getKey(), 'label' => $n->getLabel()];
|
return [
|
||||||
|
'key' => $personAltName->getKey(),
|
||||||
|
'label' => $personAltName->getLabel(),
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
)
|
||||||
return $r;
|
->toArray();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -215,6 +215,7 @@ Some peoples does not belong to any household currently. Add them to an househol
|
|||||||
Add to household now: Ajouter à un ménage
|
Add to household now: Ajouter à un ménage
|
||||||
Any resource for this accompanying course: Aucun interlocuteur privilégié pour ce parcours
|
Any resource for this accompanying course: Aucun interlocuteur privilégié pour ce parcours
|
||||||
course.draft: Brouillon
|
course.draft: Brouillon
|
||||||
|
Origin: Origine de la demande
|
||||||
|
|
||||||
# pickAPersonType
|
# pickAPersonType
|
||||||
Pick a person: Choisir une personne
|
Pick a person: Choisir une personne
|
||||||
|
Loading…
x
Reference in New Issue
Block a user