mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-08-20 14:43:49 +00:00
Merge remote-tracking branch 'origin/master' into 106_tasks_to_parcours
This commit is contained in:
@@ -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
|
||||
]);
|
||||
|
@@ -4,24 +4,31 @@ namespace Chill\PersonBundle\Controller;
|
||||
|
||||
use Chill\MainBundle\CRUD\Controller\ApiController;
|
||||
use Chill\MainBundle\Entity\Address;
|
||||
use Chill\MainBundle\Entity\AddressReference;
|
||||
use Chill\MainBundle\Serializer\Model\Collection;
|
||||
use Chill\PersonBundle\Entity\Person;
|
||||
use Chill\PersonBundle\Entity\Household\Household;
|
||||
use Chill\PersonBundle\Repository\Household\HouseholdACLAwareRepositoryInterface;
|
||||
use Chill\PersonBundle\Repository\Household\HouseholdRepository;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
|
||||
|
||||
class HouseholdApiController extends ApiController
|
||||
{
|
||||
private HouseholdRepository $householdRepository;
|
||||
|
||||
public function __construct(HouseholdRepository $householdRepository)
|
||||
{
|
||||
private HouseholdACLAwareRepositoryInterface $householdACLAwareRepository;
|
||||
|
||||
public function __construct(
|
||||
HouseholdRepository $householdRepository,
|
||||
HouseholdACLAwareRepositoryInterface $householdACLAwareRepository
|
||||
) {
|
||||
$this->householdRepository = $householdRepository;
|
||||
$this->householdACLAwareRepository = $householdACLAwareRepository;
|
||||
}
|
||||
|
||||
|
||||
public function householdAddressApi($id, Request $request, string $_format): Response
|
||||
{
|
||||
@@ -37,7 +44,7 @@ class HouseholdApiController extends ApiController
|
||||
{
|
||||
// TODO add acl
|
||||
|
||||
$count = $this->householdRepository->countByAccompanyingPeriodParticipation($person);
|
||||
$count = $this->householdRepository->countByAccompanyingPeriodParticipation($person);
|
||||
$paginator = $this->getPaginatorFactory()->create($count);
|
||||
|
||||
if ($count === 0) {
|
||||
@@ -93,4 +100,27 @@ class HouseholdApiController extends ApiController
|
||||
return $this->json(\array_values($addresses), Response::HTTP_OK, [],
|
||||
[ 'groups' => [ 'read' ] ]);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @Route("/api/1.0/person/household/by-address-reference/{id}.json",
|
||||
* name="chill_api_person_household_by_address_reference")
|
||||
* @param AddressReference $addressReference
|
||||
* @return \Symfony\Component\HttpFoundation\JsonResponse
|
||||
*/
|
||||
public function getHouseholdByAddressReference(AddressReference $addressReference): Response
|
||||
{
|
||||
// TODO ACL
|
||||
$this->denyAccessUnlessGranted('ROLE_USER');
|
||||
|
||||
$total = $this->householdACLAwareRepository->countByAddressReference($addressReference);
|
||||
$paginator = $this->getPaginatorFactory()->create($total);
|
||||
$households = $this->householdACLAwareRepository->findByAddressReference($addressReference,
|
||||
$paginator->getCurrentPageFirstItemNumber(), $paginator->getItemsPerPage());
|
||||
$collection = new Collection($households, $paginator);
|
||||
|
||||
return $this->json($collection, Response::HTTP_OK, [], [
|
||||
AbstractNormalizer::GROUPS => ['read']
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
@@ -167,6 +167,23 @@ class HouseholdController extends AbstractController
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route(
|
||||
* "/{household_id}/relationship",
|
||||
* name="chill_person_household_relationship",
|
||||
* methods={"GET", "HEAD"}
|
||||
* )
|
||||
* @ParamConverter("household", options={"id" = "household_id"})
|
||||
*/
|
||||
public function showRelationship(Request $request, Household $household)
|
||||
{
|
||||
return $this->render('@ChillPerson/Household/relationship.html.twig',
|
||||
[
|
||||
'household' => $household
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route(
|
||||
* "/{household_id}/members/metadata/edit",
|
||||
|
@@ -45,9 +45,9 @@ class PersonApiController extends ApiController
|
||||
$person = parent::createEntity($action, $request);
|
||||
|
||||
// TODO temporary hack to allow creation of person with fake center
|
||||
$centers = $this->authorizationHelper->getReachableCenters($this->getUser(),
|
||||
/* $centers = $this->authorizationHelper->getReachableCenters($this->getUser(),
|
||||
new Role(PersonVoter::CREATE));
|
||||
$person->setCenter($centers[0]);
|
||||
$person->setCenter($centers[0]); */
|
||||
|
||||
return $person;
|
||||
}
|
||||
@@ -77,13 +77,6 @@ class PersonApiController extends ApiController
|
||||
$a = $participation->getAccompanyingPeriod()->getAddressLocation();
|
||||
$addresses[$a->getId()] = $a;
|
||||
}
|
||||
if (null !== $personLocation = $participation
|
||||
->getAccompanyingPeriod()->getPersonLocation()) {
|
||||
$a = $personLocation->getCurrentHouseholdAddress();
|
||||
if (null !== $a) {
|
||||
$addresses[$a->getId()] = $a;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// remove the actual address
|
||||
|
@@ -155,7 +155,7 @@ final class PersonController extends AbstractController
|
||||
$person = $this->_getPerson($person_id);
|
||||
|
||||
if ($person === null) {
|
||||
return $this->createNotFoundException();
|
||||
throw $this->createNotFoundException();
|
||||
}
|
||||
|
||||
$this->denyAccessUnlessGranted('CHILL_PERSON_UPDATE', $person,
|
||||
|
@@ -247,7 +247,6 @@ class LoadPeople extends AbstractFixture implements OrderedFixtureInterface, Con
|
||||
if (\random_int(0, 10) > 3) {
|
||||
// always add social scope:
|
||||
$accompanyingPeriod->addScope($this->getReference('scope_social'));
|
||||
var_dump(count($accompanyingPeriod->getScopes()));
|
||||
|
||||
$accompanyingPeriod->setAddressLocation($this->createAddress());
|
||||
$manager->persist($accompanyingPeriod->getAddressLocation());
|
||||
|
@@ -84,6 +84,7 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac
|
||||
$loader->load('services/repository.yaml');
|
||||
$loader->load('services/serializer.yaml');
|
||||
$loader->load('services/security.yaml');
|
||||
$loader->load('services/doctrineEventListener.yaml');
|
||||
|
||||
// load service advanced search only if configure
|
||||
if ($config['search']['search_by_phone'] != 'never') {
|
||||
@@ -640,12 +641,13 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac
|
||||
Request::METHOD_GET => true,
|
||||
Request::METHOD_HEAD => true,
|
||||
Request::METHOD_POST=> true,
|
||||
Request::METHOD_PATCH => true
|
||||
],
|
||||
'roles' => [
|
||||
Request::METHOD_GET => \Chill\PersonBundle\Security\Authorization\PersonVoter::SEE,
|
||||
Request::METHOD_HEAD => \Chill\PersonBundle\Security\Authorization\PersonVoter::SEE,
|
||||
Request::METHOD_POST => \Chill\PersonBundle\Security\Authorization\PersonVoter::CREATE,
|
||||
|
||||
Request::METHOD_PATCH => \Chill\PersonBundle\Security\Authorization\PersonVoter::CREATE,
|
||||
],
|
||||
],
|
||||
'address' => [
|
||||
|
@@ -214,7 +214,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;
|
||||
@@ -514,6 +514,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.
|
||||
*
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
|
@@ -229,7 +229,7 @@ class Household
|
||||
))
|
||||
->andWhere($expr->orX(
|
||||
$expr->isNull('endDate'),
|
||||
$expr->gte('endDate', $date)
|
||||
$expr->gt('endDate', $date)
|
||||
));
|
||||
|
||||
return $criteria;
|
||||
@@ -306,7 +306,7 @@ class Household
|
||||
)
|
||||
->orWhere(
|
||||
$expr->andX(
|
||||
$expr->lt('endDate', $date),
|
||||
$expr->lte('endDate', $date),
|
||||
$expr->neq('endDate', null)
|
||||
)
|
||||
);
|
||||
|
@@ -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;
|
||||
|
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Chill\PersonBundle\EventListener;
|
||||
|
||||
use Chill\PersonBundle\Entity\Person;
|
||||
use Chill\PersonBundle\Entity\PersonAltName;
|
||||
use Doctrine\Persistence\Event\LifecycleEventArgs;
|
||||
use LogicException;
|
||||
use Symfony\Component\Validator\Exception\LogicException as ExceptionLogicException;
|
||||
|
||||
class PersonEventListener
|
||||
{
|
||||
public function prePersistPerson(Person $person): void
|
||||
{
|
||||
$firstnameCaps = mb_convert_case(mb_strtolower($person->getFirstName()), MB_CASE_TITLE, 'UTF-8');
|
||||
$firstnameCaps = ucwords(strtolower($firstnameCaps), " \t\r\n\f\v'-");
|
||||
$person->setFirstName($firstnameCaps);
|
||||
|
||||
$lastnameCaps = mb_strtoupper($person->getLastName(), 'UTF-8');
|
||||
$person->setLastName($lastnameCaps);
|
||||
}
|
||||
|
||||
public function prePersistAltName(PersonAltName $altname)
|
||||
{
|
||||
$altnameCaps = mb_strtoupper($altname->getLabel(), 'UTF-8');
|
||||
$altname->setLabel($altnameCaps);
|
||||
}
|
||||
}
|
@@ -22,7 +22,9 @@
|
||||
namespace Chill\PersonBundle\Form;
|
||||
|
||||
use Chill\MainBundle\Form\Event\CustomizeFormEvent;
|
||||
use Chill\MainBundle\Repository\CenterRepository;
|
||||
use Chill\PersonBundle\Entity\Person;
|
||||
use Chill\PersonBundle\Security\Authorization\PersonVoter;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
@@ -30,12 +32,11 @@ use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToStringTransformer;
|
||||
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
|
||||
use Chill\MainBundle\Form\Type\ChillDateType;
|
||||
use Chill\MainBundle\Form\Type\CenterType;
|
||||
use Chill\MainBundle\Form\Type\PickCenterType;
|
||||
use Chill\PersonBundle\Form\Type\GenderType;
|
||||
use Chill\MainBundle\Form\Type\DataTransformer\CenterTransformer;
|
||||
use Chill\PersonBundle\Config\ConfigPersonAltNamesHelper;
|
||||
use Chill\PersonBundle\Form\Type\PersonAltNameType;
|
||||
use Chill\MainBundle\Form\Type\Export\PickCenterType;
|
||||
|
||||
final class CreationPersonType extends AbstractType
|
||||
{
|
||||
@@ -43,11 +44,7 @@ final class CreationPersonType extends AbstractType
|
||||
// TODO: See if this is still valid and update accordingly.
|
||||
const NAME = 'chill_personbundle_person_creation';
|
||||
|
||||
/**
|
||||
*
|
||||
* @var CenterTransformer
|
||||
*/
|
||||
private $centerTransformer;
|
||||
private CenterRepository $centerRepository;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -58,11 +55,11 @@ final class CreationPersonType extends AbstractType
|
||||
private EventDispatcherInterface $dispatcher;
|
||||
|
||||
public function __construct(
|
||||
CenterTransformer $centerTransformer,
|
||||
CenterRepository $centerRepository,
|
||||
ConfigPersonAltNamesHelper $configPersonAltNamesHelper,
|
||||
EventDispatcherInterface $dispatcher
|
||||
) {
|
||||
$this->centerTransformer = $centerTransformer;
|
||||
$this->centerTransformer = $centerRepository;
|
||||
$this->configPersonAltNamesHelper = $configPersonAltNamesHelper;
|
||||
$this->dispatcher = $dispatcher;
|
||||
}
|
||||
@@ -82,8 +79,9 @@ final class CreationPersonType extends AbstractType
|
||||
->add('gender', GenderType::class, array(
|
||||
'required' => true, 'placeholder' => null
|
||||
))
|
||||
->add('center', CenterType::class, [
|
||||
'required' => false
|
||||
->add('center', PickCenterType::class, [
|
||||
'required' => false,
|
||||
'role' => PersonVoter::CREATE,
|
||||
])
|
||||
;
|
||||
|
||||
|
@@ -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
|
||||
));
|
||||
}
|
||||
|
||||
|
@@ -50,6 +50,13 @@ class HouseholdMenuBuilder implements LocalMenuBuilderInterface
|
||||
]])
|
||||
->setExtras(['order' => 30]);
|
||||
|
||||
$menu->addChild($this->translator->trans('household.Relationship'), [
|
||||
'route' => 'chill_person_household_relationship',
|
||||
'routeParameters' => [
|
||||
'household_id' => $household->getId()
|
||||
]])
|
||||
->setExtras(['order' => 40]);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
|
||||
namespace Chill\PersonBundle\Repository\Household;
|
||||
|
||||
use Chill\MainBundle\Entity\AddressReference;
|
||||
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
|
||||
use Chill\PersonBundle\Entity\Household\Household;
|
||||
use Chill\PersonBundle\Security\Authorization\HouseholdVoter;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Component\Security\Core\Security;
|
||||
|
||||
final class HouseholdACLAwareRepository implements HouseholdACLAwareRepositoryInterface
|
||||
{
|
||||
|
||||
private EntityManagerInterface $em;
|
||||
|
||||
private AuthorizationHelper $authorizationHelper;
|
||||
|
||||
private Security $security;
|
||||
|
||||
public function __construct(EntityManagerInterface $em, AuthorizationHelper $authorizationHelper, Security $security)
|
||||
{
|
||||
$this->em = $em;
|
||||
$this->authorizationHelper = $authorizationHelper;
|
||||
$this->security = $security;
|
||||
}
|
||||
|
||||
public function countByAddressReference(AddressReference $addressReference): int
|
||||
{
|
||||
$qb = $this->buildQueryByAddressReference($addressReference);
|
||||
$qb = $this->addACL($qb);
|
||||
|
||||
return $qb->select('COUNT(h)')
|
||||
->getQuery()
|
||||
->getSingleScalarResult();
|
||||
}
|
||||
|
||||
public function findByAddressReference(
|
||||
AddressReference $addressReference,
|
||||
?int $firstResult = 0,
|
||||
?int $maxResult = 50
|
||||
): array {
|
||||
$qb = $this->buildQueryByAddressReference($addressReference);
|
||||
$qb = $this->addACL($qb);
|
||||
|
||||
return $qb
|
||||
->select('h')
|
||||
->setFirstResult($firstResult)
|
||||
->setMaxResults($maxResult)
|
||||
->getQuery()
|
||||
->getResult();
|
||||
}
|
||||
|
||||
public function buildQueryByAddressReference(AddressReference $addressReference): QueryBuilder
|
||||
{
|
||||
$qb = $this->em->createQueryBuilder();
|
||||
$qb
|
||||
->select('h')
|
||||
->from(Household::class, 'h')
|
||||
->join('h.addresses', 'address')
|
||||
->where(
|
||||
$qb->expr()->eq('address.addressReference', ':reference')
|
||||
)
|
||||
->setParameter(':reference', $addressReference)
|
||||
->andWhere(
|
||||
$qb->expr()->andX(
|
||||
$qb->expr()->lte('address.validFrom', ':today'),
|
||||
$qb->expr()->orX(
|
||||
$qb->expr()->isNull('address.validTo'),
|
||||
$qb->expr()->gt('address.validTo', ':today')
|
||||
)
|
||||
)
|
||||
)
|
||||
->setParameter('today', new \DateTime('today'))
|
||||
;
|
||||
|
||||
return $qb;
|
||||
}
|
||||
|
||||
public function addACL(QueryBuilder $qb, string $alias = 'h'): QueryBuilder
|
||||
{
|
||||
$centers = $this->authorizationHelper->getReachableCenters(
|
||||
$this->security->getUser(),
|
||||
HouseholdVoter::SHOW
|
||||
);
|
||||
|
||||
if ([] === $centers) {
|
||||
return $qb
|
||||
->andWhere("'FALSE' = 'TRUE'");
|
||||
}
|
||||
|
||||
$qb
|
||||
->join($alias.'.members', 'members')
|
||||
->join('members.person', 'person')
|
||||
->andWhere(
|
||||
$qb->expr()->in('person.center', ':centers')
|
||||
)
|
||||
->setParameter('centers', $centers);
|
||||
|
||||
return $qb;
|
||||
}
|
||||
}
|
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace Chill\PersonBundle\Repository\Household;
|
||||
|
||||
use Chill\MainBundle\Entity\AddressReference;
|
||||
use Chill\PersonBundle\Entity\Household\Household;
|
||||
|
||||
interface HouseholdACLAwareRepositoryInterface
|
||||
{
|
||||
public function countByAddressReference(AddressReference $addressReference): int;
|
||||
|
||||
/**
|
||||
* @param AddressReference $addressReference
|
||||
* @param int|null $firstResult
|
||||
* @param int|null $maxResult
|
||||
* @return array|Household[]
|
||||
*/
|
||||
public function findByAddressReference(
|
||||
AddressReference $addressReference,
|
||||
?int $firstResult = 0,
|
||||
?int $maxResult = 50
|
||||
): array;
|
||||
}
|
@@ -199,7 +199,7 @@ final class PersonACLAwareRepository implements PersonACLAwareRepositoryInterfac
|
||||
}
|
||||
|
||||
if (NULL !== $birthdate) {
|
||||
$qb->andWhere($qb->expr()->eq('s.birthdate', ':birthdate'))
|
||||
$qb->andWhere($qb->expr()->eq('p.birthdate', ':birthdate'))
|
||||
->setParameter('birthdate', $birthdate);
|
||||
}
|
||||
|
||||
|
@@ -1,10 +1,13 @@
|
||||
// Access to Bootstrap variables and mixins
|
||||
@import '~ChillMainAssets/module/bootstrap/shared';
|
||||
|
||||
@import 'ChillMainAssets/chill/scss/chill_variables';
|
||||
|
||||
// Complete/override Main generic assets
|
||||
@import './scss/mixins';
|
||||
@import './scss/render_box.scss';
|
||||
@import './scss/flex_table.scss';
|
||||
@import './scss/badge.scss';
|
||||
|
||||
// Specific templates styles
|
||||
@import './scss/accompanying_period_work.scss';
|
||||
@@ -19,13 +22,13 @@
|
||||
|
||||
div.banner {
|
||||
div#header-person-name {
|
||||
background: none repeat scroll 0 0 $chill-green-dark;
|
||||
background: none repeat scroll 0 0 shade-color($chill-person-context, 20%);
|
||||
color: $white;
|
||||
padding-top: 1em;
|
||||
padding-bottom: 1em;
|
||||
}
|
||||
div#header-person-details {
|
||||
background: none repeat scroll 0 0 $chill-green;
|
||||
background: none repeat scroll 0 0 $chill-person-context;
|
||||
color: $white;
|
||||
padding-top: 1em;
|
||||
padding-bottom: 1em;
|
||||
@@ -92,7 +95,6 @@ div.person-view {
|
||||
* Header custom for Accompanying Course
|
||||
*/
|
||||
|
||||
$chill-accourse-context: #718596;
|
||||
|
||||
div.banner {
|
||||
div#header-accompanying_course-name {
|
||||
@@ -104,9 +106,9 @@ div.banner {
|
||||
span {
|
||||
a {
|
||||
color: $white;
|
||||
}
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -118,19 +120,11 @@ div.banner {
|
||||
}
|
||||
}
|
||||
|
||||
abbr.referrer {
|
||||
font-size: 70%;
|
||||
padding-right: 0.4em;
|
||||
align-self: center; // in flex context
|
||||
}
|
||||
|
||||
/*
|
||||
* HOUSEHOLD CONTEXT
|
||||
* Header custom for Household
|
||||
*/
|
||||
|
||||
$chill-household-context: #929d69;
|
||||
|
||||
div.banner {
|
||||
div#header-household-name {
|
||||
background: none repeat scroll 0 0 $chill-household-context;
|
||||
@@ -142,9 +136,9 @@ div.banner {
|
||||
span {
|
||||
a {
|
||||
color: $white;
|
||||
}
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
div.household-members {
|
||||
@@ -185,6 +179,7 @@ div.banner {
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
div.household-resume {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
@@ -208,42 +203,42 @@ div.household-resume {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* BADGES, MARKS, PINS
|
||||
* for chill person theme
|
||||
*/
|
||||
|
||||
// chill person badges
|
||||
span.badge-person,
|
||||
span.badge-thirdparty {
|
||||
display: inline-block;
|
||||
padding: 0 0.5em !important;
|
||||
background-color: $white;
|
||||
color: $dark;
|
||||
border: 1px solid $chill-ll-gray;
|
||||
border-bottom-width: 2px;
|
||||
border-bottom-style: solid;
|
||||
border-radius: 6px;
|
||||
a {
|
||||
text-decoration: none;
|
||||
/// Horizontal list of persons (Accourse resume page)
|
||||
div.accompanyingcourse-resume {
|
||||
div.associated-persons {
|
||||
font-size: 110%;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
span.badge-person {
|
||||
border-bottom-color: $chill-green;
|
||||
}
|
||||
// todo: move in thirdparty
|
||||
span.badge-thirdparty {
|
||||
border-bottom-color: shade-color($chill-pink, 10%);
|
||||
|
||||
///
|
||||
abbr.referrer { // still used ?
|
||||
font-size: 70%;
|
||||
padding-right: 0.4em;
|
||||
align-self: center; // in flex context
|
||||
}
|
||||
|
||||
// household holder mark
|
||||
span.fa-holder {
|
||||
width: 1em;
|
||||
margin: -10px 0.3em -8px 0;
|
||||
i:last-child {
|
||||
font-weight: 900;
|
||||
color: white;
|
||||
font-size: 70%;
|
||||
font-family: "Open Sans Extrabold";
|
||||
}
|
||||
.updatedBy {
|
||||
margin-top: 0.3rem;
|
||||
font-size: 0.9rem;
|
||||
font-style: italic;
|
||||
}
|
||||
|
@@ -1,31 +1,6 @@
|
||||
/// AccompanyingCourse Work list Page
|
||||
div.accompanying_course_work-list {
|
||||
|
||||
h2.title {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
width: 100%;
|
||||
color: $dark;
|
||||
height: 40px;
|
||||
|
||||
span.title_label {
|
||||
border-radius: 0.35rem 0 0 0.35rem;
|
||||
background-color: $social-action-label-color;
|
||||
color: $white;
|
||||
font-size: 80%;
|
||||
padding: 0.5em;
|
||||
padding-right: 0;
|
||||
}
|
||||
span.title_action {
|
||||
flex-grow: 1;
|
||||
margin: 0 0 0 auto;
|
||||
border-radius: 0 0.35rem 0.35rem 0;
|
||||
background-color: $light;
|
||||
padding: 0.2em 0.7em;
|
||||
@include badge_social_action;
|
||||
}
|
||||
}
|
||||
|
||||
div.timeline {
|
||||
width: 100%;
|
||||
ul {
|
||||
@@ -125,7 +100,7 @@ div.accompanying_course_work-list {
|
||||
}
|
||||
}
|
||||
&.goal_title li::marker {
|
||||
color: $sky-blue;
|
||||
color: $social-issue-color;
|
||||
}
|
||||
&.result_list li::marker {
|
||||
color: $pink;
|
||||
@@ -133,11 +108,4 @@ div.accompanying_course_work-list {
|
||||
}
|
||||
}
|
||||
|
||||
.updatedBy {
|
||||
margin-top: 0.3rem;
|
||||
font-size: 0.9rem;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* BADGES PERSON AND THIRDPARTY
|
||||
*/
|
||||
|
||||
span.badge-person,
|
||||
span.badge-thirdparty {
|
||||
display: inline-block;
|
||||
padding: 0 0.5em !important;
|
||||
background-color: $white;
|
||||
color: $dark;
|
||||
border: 1px solid $chill-ll-gray;
|
||||
border-bottom-width: 2px;
|
||||
border-bottom-style: solid;
|
||||
border-radius: 6px;
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
span.badge-person {
|
||||
border-bottom-color: $chill-green;
|
||||
}
|
||||
span.badge-thirdparty {
|
||||
border-bottom-color: shade-color($chill-pink, 10%);
|
||||
}
|
||||
|
||||
/*
|
||||
* HOUSEHOLD HOLDER MARK
|
||||
*/
|
||||
|
||||
span.fa-holder {
|
||||
width: 1em;
|
||||
margin: -10px 0.3em -8px 0;
|
||||
i:last-child {
|
||||
font-family: "Open Sans Extrabold";
|
||||
font-weight: 900;
|
||||
font-size: 70%;
|
||||
color: $white;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* BADGE_TITLE
|
||||
* Display Title like a badge (with background-colored label)
|
||||
*/
|
||||
|
||||
h2.badge-title {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
width: 100%;
|
||||
color: $dark;
|
||||
|
||||
a & { text-decoration: none; } // ?!? keep it ?
|
||||
|
||||
span.title_label {
|
||||
border-radius: 0.35rem 0 0 0.35rem;
|
||||
color: $white;
|
||||
font-size: 80%;
|
||||
padding: 0.5em;
|
||||
padding-right: 0;
|
||||
h3 {
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
}
|
||||
span.title_action {
|
||||
flex-grow: 1;
|
||||
margin: 0 0 0 auto;
|
||||
border-radius: 0 0.35rem 0.35rem 0;
|
||||
background-color: $light;
|
||||
padding: 0.2em 1em;
|
||||
|
||||
ul.small_in_title {
|
||||
margin-top: 0.5em;
|
||||
font-size: 70%;
|
||||
padding-left: 1rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// badge_title in AccompanyingCourse Work list Page
|
||||
div.accompanying_course_work-list {
|
||||
h2.badge-title {
|
||||
span.title_label {
|
||||
// Calculate same color then border:groove
|
||||
background-color: shade-color($social-action-color, 34%);
|
||||
}
|
||||
span.title_action {
|
||||
@include badge_title($social-action-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// badge_title in Activities on resume page
|
||||
div.activity-list {
|
||||
h2.badge-title {
|
||||
span.title_label {
|
||||
// Calculate same color then border:groove
|
||||
background-color: shade-color($activity-color, 34%);
|
||||
h3 {
|
||||
color: $white;
|
||||
}
|
||||
}
|
||||
span.title_action {
|
||||
@include badge_title($activity-color);
|
||||
}
|
||||
span.title_label {
|
||||
div.duration {
|
||||
font-size: 70%;
|
||||
font-weight: 500;
|
||||
p {
|
||||
margin-bottom: 0;
|
||||
text-align: right;
|
||||
abbr {
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,44 +1,39 @@
|
||||
// Additionnal colors
|
||||
$sky-blue: #4bafe8;
|
||||
|
||||
// mixins variables
|
||||
$social-issue-color: $sky-blue;
|
||||
$social-action-color: $orange;
|
||||
|
||||
// Calculate same color then border:groove
|
||||
// origin: $orange, computed: #965028
|
||||
$social-action-label-color: shade-color($orange, 34%);
|
||||
|
||||
///
|
||||
/// Social Issue mixin
|
||||
// define visual badge for all social issues
|
||||
/// Chill badge mixin
|
||||
// define chill visual badge
|
||||
///
|
||||
|
||||
@mixin badge_social_issue {
|
||||
@mixin chill_badge($color) {
|
||||
text-transform: capitalize !important;
|
||||
font-weight: 500 !important;
|
||||
border-left: 20px groove $social-issue-color;
|
||||
border-left: 20px groove $color;
|
||||
&:before {
|
||||
content: '\f04b';
|
||||
font-family: ForkAwesome;
|
||||
color: $social-issue-color;
|
||||
content: '\f04b';
|
||||
color: $color;
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Social badge mixin
|
||||
// define visual badge for social issues or social action
|
||||
///
|
||||
|
||||
@mixin badge_social($color) {
|
||||
@include chill_badge($color);
|
||||
&:before {
|
||||
margin: 0 0.3em 0 -0.75em;
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Social Action mixin
|
||||
// define visual badge for all social actions
|
||||
/// Generic mixin for titles like badge
|
||||
// define visual badge used in title area
|
||||
///
|
||||
|
||||
@mixin badge_social_action {
|
||||
text-transform: capitalize !important;
|
||||
font-weight: 500 !important;
|
||||
border-left: 20px groove $social-action-color;
|
||||
@mixin badge_title($color) {
|
||||
@include chill_badge($color);
|
||||
&:before {
|
||||
content: '\f04b';
|
||||
font-family: ForkAwesome;
|
||||
color: $social-action-color;
|
||||
margin: 0 0.3em 0 -0.75em;
|
||||
margin: 0 0.3em 0 -1.05em;
|
||||
}
|
||||
}
|
||||
|
@@ -8,21 +8,28 @@
|
||||
span.altname {}
|
||||
}
|
||||
|
||||
/// SOCIAL-ISSUE
|
||||
&.entity-social-issue {
|
||||
margin-right: 0.3em;
|
||||
font-size: 120%;
|
||||
span.badge {
|
||||
@include badge_social_issue;
|
||||
}
|
||||
}
|
||||
|
||||
/// SOCIAL-ACTION
|
||||
/// SOCIAL-ISSUE AND SOCIAL-ACTION
|
||||
&.entity-social-issue,
|
||||
&.entity-social-action {
|
||||
margin-right: 0.3em;
|
||||
font-size: 120%;
|
||||
span.badge {
|
||||
@include badge_social_action;
|
||||
// for too long badge in a narrow inside block
|
||||
text-align: initial;
|
||||
margin-bottom: 0.2em;
|
||||
> span {
|
||||
white-space: normal;
|
||||
}
|
||||
}
|
||||
}
|
||||
&.entity-social-issue {
|
||||
span.badge {
|
||||
@include badge_social($social-issue-color);
|
||||
}
|
||||
}
|
||||
&.entity-social-action {
|
||||
span.badge {
|
||||
@include badge_social($social-action-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,10 @@
|
||||
import { fetchResults } from 'ChillMainAssets/lib/api/download.js';
|
||||
|
||||
const fetchHouseholdByAddressReference = async (reference) => {
|
||||
const url = `/api/1.0/person/household/by-address-reference/${reference.id}.json`
|
||||
return fetchResults(url);
|
||||
};
|
||||
|
||||
export {
|
||||
fetchHouseholdByAddressReference
|
||||
};
|
@@ -0,0 +1,32 @@
|
||||
import vis from 'vis-network/dist/vis-network.min';
|
||||
|
||||
require('./scss/vis.scss');
|
||||
|
||||
// create an array with nodes
|
||||
let nodes = new vis.DataSet([
|
||||
{ id: 1, label: "Node 1" },
|
||||
{ id: 2, label: "Node 2" },
|
||||
{ id: 3, label: "Node 3" },
|
||||
{ id: 4, label: "Node 4" },
|
||||
{ id: 5, label: "Node 5", cid: 1 },
|
||||
]);
|
||||
|
||||
// create an array with edges
|
||||
let edges = new vis.DataSet([
|
||||
{ from: 1, to: 3 },
|
||||
{ from: 1, to: 2 },
|
||||
{ from: 2, to: 4 },
|
||||
{ from: 2, to: 5 },
|
||||
{ from: 3, to: 3 },
|
||||
]);
|
||||
|
||||
// create a network
|
||||
let container = document.getElementById("graph-relationship");
|
||||
let data = {
|
||||
nodes: nodes,
|
||||
edges: edges,
|
||||
};
|
||||
let options = {};
|
||||
|
||||
//
|
||||
let network = new vis.Network(container, data, options);
|
@@ -0,0 +1,5 @@
|
||||
div#graph-relationship {
|
||||
margin: 2em auto;
|
||||
height: 500px;
|
||||
border: 1px solid lightgray;
|
||||
}
|
@@ -87,8 +87,8 @@ export default {
|
||||
}
|
||||
padding: 0em 0em;
|
||||
margin: 1em 0;
|
||||
border: 1px dotted tint-color($chill-accourse-context, 10%);
|
||||
border-radius: 5px;
|
||||
border: 1px dotted tint-color($chill-accourse-context, 10%);
|
||||
border-left: 1px dotted tint-color($chill-accourse-context, 10%);
|
||||
border-right: 1px dotted tint-color($chill-accourse-context, 10%);
|
||||
dd {
|
||||
@@ -96,10 +96,15 @@ export default {
|
||||
}
|
||||
& > div {
|
||||
margin: 1em 3em 0;
|
||||
|
||||
&.flex-table,
|
||||
&.flex-bloc {
|
||||
margin: 1em 0 0;
|
||||
}
|
||||
&.alert.to-confirm {
|
||||
margin: 1em 0 0;
|
||||
padding: 1em 3em;
|
||||
}
|
||||
}
|
||||
|
||||
div.flex-table {
|
||||
|
@@ -22,7 +22,7 @@
|
||||
<i>{{ $t('course.open_at') }}{{ $d(accompanyingCourse.openingDate.datetime, 'text') }}</i>
|
||||
</span>
|
||||
<span v-if="accompanyingCourse.user" class="d-md-block ms-3 ms-md-0">
|
||||
{{ $t('course.by') }}<b>{{ accompanyingCourse.user.username }}</b>
|
||||
<abbr :title="$t('course.referrer')">{{ $t('course.referrer') }}:</abbr> <b>{{ accompanyingCourse.user.username }}</b>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
|
@@ -12,9 +12,9 @@ export default {
|
||||
<style lang="scss" scoped>
|
||||
@import 'ChillMainAssets/module/bootstrap/shared';
|
||||
@import 'ChillPersonAssets/chill/scss/mixins';
|
||||
|
||||
@import 'ChillMainAssets/chill/scss/chill_variables';
|
||||
span.badge {
|
||||
@include badge_social_issue;
|
||||
@include badge_social($social-issue-color);
|
||||
font-size: 95%;
|
||||
margin-bottom: 5px;
|
||||
margin-right: 1em;
|
||||
|
@@ -91,7 +91,7 @@ export default {
|
||||
},
|
||||
scopes: {
|
||||
msg: 'confirm.set_a_scope',
|
||||
anchor: '#section-65'
|
||||
anchor: '#section-60'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -27,19 +27,34 @@
|
||||
</div>
|
||||
|
||||
<div v-if="isTemporaryAddress" class="alert alert-warning separator">
|
||||
<p>{{ $t('courselocation.temporary_address_must_be_changed') }}</p>
|
||||
<p>
|
||||
{{ $t('courselocation.temporary_address_must_be_changed') }}
|
||||
<i class="fa fa-fw fa-map-marker"></i>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="hasNoPersonLocation" class="alert alert-danger no-person-location">
|
||||
<i class="fa fa-warning fa-2x"></i>
|
||||
<div>
|
||||
<p>
|
||||
{{ $t('courselocation.associate_at_least_one_person_with_one_household_with_address') }}
|
||||
<a href="#section-10">
|
||||
<i class="fa fa-level-up fa-fw"></i>
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<ul class="record_actions">
|
||||
<li>
|
||||
<add-address
|
||||
v-if="!isPersonLocation"
|
||||
:key="key"
|
||||
:context="context"
|
||||
:key="addAddress.type"
|
||||
:options="addAddress.options"
|
||||
:options="options"
|
||||
:addressChangedCallback="submitTemporaryAddress"
|
||||
ref="addAddress">
|
||||
</add-address>
|
||||
@@ -55,11 +70,15 @@
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div v-if="!isLocationValid" class="alert alert-warning to-confirm">
|
||||
{{ $t('courselocation.not_valid') }}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from "vuex";
|
||||
import {mapGetters, mapState} from "vuex";
|
||||
import AddAddress from 'ChillMainAssets/vuejs/Address/components/AddAddress.vue';
|
||||
import AddressRenderBox from 'ChillMainAssets/vuejs/_components/Entity/AddressRenderBox.vue';
|
||||
|
||||
@@ -72,10 +91,7 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
addAddress: {
|
||||
type: 'accompanying_course_location',
|
||||
options: {
|
||||
/// Options override default.
|
||||
/// null value take default component value
|
||||
button: {
|
||||
text: {
|
||||
create: 'courselocation.add_temporary_address',
|
||||
@@ -86,13 +102,7 @@ export default {
|
||||
create: 'courselocation.add_temporary_address',
|
||||
edit: 'courselocation.edit_temporary_address'
|
||||
},
|
||||
/// Display each step in page or Modal
|
||||
openPanesInModal: true,
|
||||
// Use Date fields
|
||||
//useDate: {
|
||||
// validFrom: true
|
||||
//},
|
||||
hideAddress: true
|
||||
onlyButton: true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -102,6 +112,16 @@ export default {
|
||||
accompanyingCourse: state => state.accompanyingCourse,
|
||||
context: state => state.addressContext
|
||||
}),
|
||||
...mapGetters([
|
||||
'isLocationValid'
|
||||
]),
|
||||
options() {
|
||||
return this.addAddress.options;
|
||||
},
|
||||
key() {
|
||||
return (this.context.edit) ? 'address_' + this.context.addressId
|
||||
: this.accompanyingCourse.type + '_' + this.accompanyingCourse.id ;
|
||||
},
|
||||
isTemporaryAddress() {
|
||||
return this.accompanyingCourse.locationStatus === 'address';
|
||||
},
|
||||
@@ -111,11 +131,40 @@ export default {
|
||||
hasNoLocation() {
|
||||
return this.accompanyingCourse.locationStatus === 'none';
|
||||
},
|
||||
currentParticipations() {
|
||||
return this.accompanyingCourse.participations.filter(p => p.enddate !== null);
|
||||
},
|
||||
hasNoPersonLocation() {
|
||||
|
||||
let addressInParticipations_ = []
|
||||
this.currentParticipations.forEach(p => {
|
||||
addressInParticipations_.push(this.checkHouseholdAddressForParticipation(p));
|
||||
});
|
||||
|
||||
const booleanReducer = (previousValue, currentValue) => previousValue || currentValue;
|
||||
|
||||
let addressInParticipations = (addressInParticipations_.length > 0) ?
|
||||
addressInParticipations_.reduce(booleanReducer) : false;
|
||||
|
||||
//console.log(addressInParticipations_, addressInParticipations);
|
||||
return (
|
||||
this.accompanyingCourse.step !== 'DRAFT'
|
||||
&& this.isTemporaryAddress
|
||||
&& !addressInParticipations
|
||||
)
|
||||
;
|
||||
},
|
||||
isContextEdit() {
|
||||
return this.context.edit;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
checkHouseholdAddressForParticipation(participation) {
|
||||
if (participation.person.current_household_id === null) {
|
||||
return false;
|
||||
}
|
||||
return participation.person.current_household_address !== null;
|
||||
},
|
||||
initAddressContext() {
|
||||
let context = {
|
||||
target: {
|
||||
@@ -153,20 +202,44 @@ export default {
|
||||
created() {
|
||||
this.initAddressContext();
|
||||
|
||||
console.log('ac.locationStatus', this.accompanyingCourse.locationStatus);
|
||||
console.log('ac.location (temporary location)', this.accompanyingCourse.location);
|
||||
console.log('ac.personLocation', this.accompanyingCourse.personLocation);
|
||||
//console.log('ac.locationStatus', this.accompanyingCourse.locationStatus);
|
||||
//console.log('ac.location (temporary location)', this.accompanyingCourse.location);
|
||||
//console.log('ac.personLocation', this.accompanyingCourse.personLocation);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
|
||||
div.flex-table {
|
||||
div.item-bloc {
|
||||
div.alert {
|
||||
margin: 0 -0.9em -1em;
|
||||
div#accompanying-course {
|
||||
div.vue-component {
|
||||
& > div.alert.no-person-location {
|
||||
margin: 1px 0 0;
|
||||
}
|
||||
div.no-person-location {
|
||||
padding-top: 1.5em;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
& > i {
|
||||
flex-basis: 1.5em; flex-grow: 0; flex-shrink: 0;
|
||||
padding-top: 0.2em;
|
||||
opacity: 0.75;
|
||||
}
|
||||
& > div {
|
||||
flex-basis: auto;
|
||||
div.action {
|
||||
button.btn-update {
|
||||
margin-right: 2em;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
div.flex-table {
|
||||
div.item-bloc {
|
||||
div.alert {
|
||||
margin: 0 -0.9em -1em;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
@@ -26,7 +26,7 @@
|
||||
:id="p.person.id"
|
||||
:value="p.person.id"
|
||||
/>
|
||||
<label class="form-check-label" for="hasNoHousehold">
|
||||
<label class="form-check-label">
|
||||
{{ p.person.text }}
|
||||
</label>
|
||||
</div>
|
||||
@@ -58,11 +58,14 @@
|
||||
</add-persons>
|
||||
</div>
|
||||
|
||||
<div v-if="!isParticipationValid" class="alert alert-warning to-confirm">
|
||||
{{ $t('persons_associated.participation_not_valid') }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'vuex';
|
||||
import {mapGetters, mapState} from 'vuex';
|
||||
import ParticipationItem from "./PersonsAssociated/ParticipationItem.vue"
|
||||
import AddPersons from 'ChillPersonAssets/vuejs/_components/AddPersons.vue'
|
||||
|
||||
@@ -89,6 +92,9 @@ export default {
|
||||
courseId: state => state.accompanyingCourse.id,
|
||||
participations: state => state.accompanyingCourse.participations
|
||||
}),
|
||||
...mapGetters([
|
||||
'isParticipationValid'
|
||||
]),
|
||||
currentParticipations() {
|
||||
return this.participations.filter(p => p.endDate === null)
|
||||
},
|
||||
@@ -126,7 +132,7 @@ export default {
|
||||
<style lang="scss" scoped>
|
||||
div#accompanying-course {
|
||||
div.vue-component {
|
||||
& > div.alert {
|
||||
& > div.alert.no-household {
|
||||
margin: 0 0 -1em;
|
||||
}
|
||||
div.no-household {
|
||||
|
@@ -19,20 +19,8 @@
|
||||
v-if="hasCurrentHouseholdAddress"
|
||||
v-bind:person="participation.person">
|
||||
</button-location>
|
||||
<li>
|
||||
<on-the-fly
|
||||
v-bind:type="participation.person.type"
|
||||
v-bind:id="participation.person.id"
|
||||
action="show">
|
||||
</on-the-fly>
|
||||
</li>
|
||||
<li>
|
||||
<on-the-fly
|
||||
v-bind:type="participation.person.type"
|
||||
v-bind:id="participation.person.id"
|
||||
action="edit">
|
||||
</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>
|
||||
<button class="btn btn-delete"
|
||||
:title="$t('action.delete')"
|
||||
@@ -69,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';
|
||||
@@ -112,22 +100,13 @@ export default {
|
||||
getAccompanyingCourseReturnPath() {
|
||||
return `fr/parcours/${this.$store.state.accompanyingCourse.id}/edit#section-10`;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
saveFormOnTheFly(payload) {
|
||||
console.log('saveFormOnTheFly: type', payload.type, ', data', payload.data);
|
||||
payload.target = 'participation';
|
||||
this.$store.dispatch('patchOnTheFly', payload);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* dates of participation
|
||||
*
|
||||
*
|
||||
*
|
||||
* <tr>
|
||||
* <td><span v-if="participation.startDate">
|
||||
* {{ $d(participation.startDate.datetime, 'short') }}</span>
|
||||
* </td>
|
||||
* <td><span v-if="participation.endDate">
|
||||
* {{ $d(participation.endDate.datetime, 'short') }}</span>
|
||||
* </td>
|
||||
* </tr>
|
||||
*
|
||||
*/
|
||||
</script>
|
||||
|
@@ -10,7 +10,7 @@
|
||||
{{ $t('requestor.is_anonymous') }}
|
||||
</label>
|
||||
|
||||
<third-party-render-box v-if="accompanyingCourse.requestor.type == 'thirdparty'"
|
||||
<third-party-render-box v-if="accompanyingCourse.requestor.type === 'thirdparty'"
|
||||
:thirdparty="accompanyingCourse.requestor"
|
||||
:options="{
|
||||
addLink: false,
|
||||
@@ -23,14 +23,13 @@
|
||||
>
|
||||
<template v-slot:record-actions>
|
||||
<ul class="record_actions">
|
||||
<button-location v-if="hasCurrentHouseholdAddress" :thirdparty="accompanyingCourse.requestor"></button-location>
|
||||
<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"></on-the-fly></li>
|
||||
<li><on-the-fly :type="accompanyingCourse.requestor.type" :id="accompanyingCourse.requestor.id" action="edit" @saveFormOnTheFly="saveFormOnTheFly"></on-the-fly></li>
|
||||
</ul>
|
||||
</template>
|
||||
</third-party-render-box>
|
||||
|
||||
<person-render-box render="bloc" v-else-if="accompanyingCourse.requestor.type == 'person'"
|
||||
<person-render-box render="bloc" v-else-if="accompanyingCourse.requestor.type === 'person'"
|
||||
:person="accompanyingCourse.requestor"
|
||||
:options="{
|
||||
addLink: false,
|
||||
@@ -44,9 +43,8 @@
|
||||
>
|
||||
<template v-slot:record-actions>
|
||||
<ul class="record_actions">
|
||||
<button-location v-if="hasCurrentHouseholdAddress" :person="accompanyingCourse.requestor"></button-location>
|
||||
<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"></on-the-fly></li>
|
||||
<li><on-the-fly :type="accompanyingCourse.requestor.type" :id="accompanyingCourse.requestor.id" action="edit" @saveFormOnTheFly="saveFormOnTheFly"></on-the-fly></li>
|
||||
</ul>
|
||||
</template>
|
||||
</person-render-box>
|
||||
@@ -81,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';
|
||||
|
||||
@@ -129,6 +127,11 @@ export default {
|
||||
this.$store.dispatch('addRequestor', selected.shift());
|
||||
this.$refs.addPersons.resetSearch(); // to cast child method
|
||||
modal.showModal = false;
|
||||
},
|
||||
saveFormOnTheFly(payload) {
|
||||
console.log('saveFormOnTheFly: type', payload.type, ', data', payload.data);
|
||||
payload.target = 'requestor';
|
||||
this.$store.dispatch('patchOnTheFly', payload);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -6,9 +6,11 @@
|
||||
>
|
||||
<template v-slot:record-actions>
|
||||
<ul class="record_actions">
|
||||
<!--
|
||||
<button-location v-if="hasCurrentHouseholdAddress" :person="resource.resource"></button-location>
|
||||
-->
|
||||
<li><on-the-fly :type="resource.resource.type" :id="resource.resource.id" action="show"></on-the-fly></li>
|
||||
<li><on-the-fly :type="resource.resource.type" :id="resource.resource.id" action="edit"></on-the-fly></li>
|
||||
<li><on-the-fly :type="resource.resource.type" :id="resource.resource.id" action="edit" @saveFormOnTheFly="saveFormOnTheFly"></on-the-fly></li>
|
||||
<li><button class="btn btn-sm btn-remove" :title="$t('action.remove')" @click.prevent="$emit('remove', resource)"></button></li>
|
||||
</ul>
|
||||
</template>
|
||||
@@ -22,7 +24,7 @@
|
||||
<template v-slot:record-actions>
|
||||
<ul class="record_actions">
|
||||
<li><on-the-fly :type="resource.resource.type" :id="resource.resource.id" action="show"></on-the-fly></li>
|
||||
<li><on-the-fly :type="resource.resource.type" :id="resource.resource.id" action="edit"></on-the-fly></li>
|
||||
<li><on-the-fly :type="resource.resource.type" :id="resource.resource.id" action="edit" @saveFormOnTheFly="saveFormOnTheFly"></on-the-fly></li>
|
||||
<li><button class="btn btn-sm btn-remove" :title="$t('action.remove')" @click.prevent="$emit('remove', resource)"></button></li>
|
||||
</ul>
|
||||
</template>
|
||||
@@ -31,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';
|
||||
@@ -53,6 +55,13 @@ export default {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
saveFormOnTheFly(payload) {
|
||||
console.log('saveFormOnTheFly: type', payload.type, ', data', payload.data);
|
||||
payload.target = 'resource';
|
||||
this.$store.dispatch('patchOnTheFly', payload);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
@@ -1,18 +1,20 @@
|
||||
<template>
|
||||
<div class="vue-component">
|
||||
<h2><a id="section-60"></a>{{ $t('scopes.title') }}</h2>
|
||||
<h2><a id="section-60"></a>{{ $t('scopes.title') }}</h2>
|
||||
|
||||
<ul>
|
||||
<li v-for="s in scopes">
|
||||
<input type="checkbox" v-model="checkedScopes" :value="s" />
|
||||
{{ s.name.fr }}
|
||||
</li>
|
||||
</ul>
|
||||
<div class="mb-4">
|
||||
<div class="form-check" v-for="s in scopes">
|
||||
<input class="form-check-input" type="checkbox" v-model="checkedScopes" :value="s" />
|
||||
<label class="form-check-label">
|
||||
{{ s.name.fr }}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="!isScopeValid" class="alert alert-warning separator">
|
||||
<div v-if="!isScopeValid" class="alert alert-warning to-confirm">
|
||||
{{ $t('scopes.add_at_least_one') }}
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@@ -21,13 +21,17 @@
|
||||
</VueMultiselect>
|
||||
</div>
|
||||
|
||||
<div v-if="!isSocialIssueValid" class="alert alert-warning to-confirm">
|
||||
{{ $t('social_issue.not_valid') }}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import VueMultiselect from 'vue-multiselect';
|
||||
import { getSocialIssues } from '../api';
|
||||
import { mapState } from 'vuex';
|
||||
import {mapGetters, mapState} from 'vuex';
|
||||
|
||||
export default {
|
||||
name: "SocialIssue",
|
||||
@@ -41,6 +45,9 @@ export default {
|
||||
...mapState({
|
||||
value: state => state.accompanyingCourse.socialIssues,
|
||||
}),
|
||||
...mapGetters([
|
||||
'isSocialIssueValid'
|
||||
])
|
||||
},
|
||||
mounted() {
|
||||
this.getOptions();
|
||||
@@ -77,10 +84,10 @@ export default {
|
||||
<style lang="scss">
|
||||
@import 'ChillMainAssets/module/bootstrap/shared';
|
||||
@import 'ChillPersonAssets/chill/scss/mixins';
|
||||
|
||||
@import 'ChillMainAssets/chill/scss/chill_variables';
|
||||
div#accompanying-course {
|
||||
span.multiselect__tag {
|
||||
@include badge_social_issue;
|
||||
@include badge_social($social-issue-color);
|
||||
background: $chill-l-gray;
|
||||
color: $dark;
|
||||
}
|
||||
|
@@ -1,5 +1,7 @@
|
||||
import { personMessages } from 'ChillPersonAssets/vuejs/_js/i18n'
|
||||
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: {
|
||||
@@ -22,6 +24,7 @@ const appMessages = {
|
||||
},
|
||||
open_at: "ouvert le ",
|
||||
by: "par ",
|
||||
referrer: "Référent",
|
||||
emergency: "urgent",
|
||||
confidential: "confidentiel",
|
||||
regular: "régulier",
|
||||
@@ -48,8 +51,9 @@ const appMessages = {
|
||||
ok: "Oui, l'usager quitte le parcours",
|
||||
show_household_number: "Voir le ménage (n° {id})",
|
||||
show_household: "Voir le ménage",
|
||||
person_without_household_warning: "Certaines personnes n'appartiennent à aucun ménage actuellement. Renseignez leur appartenance à un ménage dès que possible.",
|
||||
person_without_household_warning: "Certaines usagers n'appartiennent actuellement à aucun ménage. Renseignez leur appartenance dès que possible.",
|
||||
update_household: "Modifier l'appartenance",
|
||||
participation_not_valid: "Sélectionnez ou créez au minimum 1 usager",
|
||||
},
|
||||
requestor: {
|
||||
title: "Demandeur",
|
||||
@@ -72,6 +76,7 @@ const appMessages = {
|
||||
social_issue: {
|
||||
title: "Problématiques sociales",
|
||||
label: "Choisir les problématiques sociales",
|
||||
not_valid: "Sélectionnez au minimum une problématique sociale",
|
||||
},
|
||||
courselocation: {
|
||||
title: "Localisation du parcours",
|
||||
@@ -79,11 +84,13 @@ const appMessages = {
|
||||
edit_temporary_address: "Modifier l'adresse temporaire",
|
||||
assign_course_address: "Désigner comme l'adresse du parcours",
|
||||
remove_button: "Enlever l'adresse",
|
||||
temporary_address_must_be_changed: "Cette adresse est temporaire et devrait être remplacée par celle d'un usager de référence.",
|
||||
temporary_address_must_be_changed: "Cette adresse est temporaire. Le parcours devrait être localisé auprès d'un usager concerné.",
|
||||
associate_at_least_one_person_with_one_household_with_address: "Commencez d'abord par associer un membre du parcours à un ménage, et indiquez une adresse à ce ménage.",
|
||||
sure: "Êtes-vous sûr ?",
|
||||
sure_description: "Voulez-vous faire de cette adresse l'adresse du parcours ?",
|
||||
ok: "Désigner comme adresse du parcours",
|
||||
person_locator: "Parcours localisé auprès de {0}",
|
||||
not_valid: "Indiquez au minimum une localisation temporaire du parcours",
|
||||
no_address: "Il n'y a pas d'adresse associée au parcours"
|
||||
},
|
||||
scopes: {
|
||||
@@ -137,7 +144,7 @@ const appMessages = {
|
||||
}
|
||||
};
|
||||
|
||||
Object.assign(appMessages.fr, personMessages.fr, addressMessages.fr);
|
||||
Object.assign(appMessages.fr, personMessages.fr, thirdpartyMessages.fr, addressMessages.fr, ontheflyMessages.fr);
|
||||
|
||||
export {
|
||||
appMessages
|
||||
|
@@ -11,6 +11,8 @@ import { getAccompanyingCourse,
|
||||
addScope,
|
||||
removeScope,
|
||||
} from '../api';
|
||||
import { patchPerson } from "ChillPersonAssets/vuejs/_api/OnTheFly";
|
||||
import { patchThirdparty } from "ChillThirdPartyAssets/vuejs/_api/OnTheFly";
|
||||
|
||||
|
||||
const debug = process.env.NODE_ENV !== 'production';
|
||||
@@ -48,7 +50,7 @@ let initPromise = Promise.all([scopesPromise, accompanyingCoursePromise])
|
||||
return state.accompanyingCourse.location !== null;
|
||||
},
|
||||
isScopeValid(state) {
|
||||
console.log('is scope valid', state.accompanyingCourse.scopes.length > 0);
|
||||
//console.log('is scope valid', state.accompanyingCourse.scopes.length > 0);
|
||||
return state.accompanyingCourse.scopes.length > 0;
|
||||
},
|
||||
validationKeys(state, getters) {
|
||||
@@ -107,6 +109,36 @@ let initPromise = Promise.all([scopesPromise, accompanyingCoursePromise])
|
||||
//console.log('### mutation: addResource', resource);
|
||||
state.accompanyingCourse.resources.push(resource);
|
||||
},
|
||||
updatePerson(state, payload) {
|
||||
console.log('### mutation: updatePerson', payload);
|
||||
let i = null;
|
||||
switch (payload.target) {
|
||||
case 'participation':
|
||||
i = state.accompanyingCourse.participations.findIndex(e => e.person.id === payload.person.id );
|
||||
state.accompanyingCourse.participations[i].person = payload.person;
|
||||
break;
|
||||
case 'requestor':
|
||||
state.accompanyingCourse.requestor = payload.person;
|
||||
break;
|
||||
case 'resource':
|
||||
i = state.accompanyingCourse.resources.findIndex(e => e.resource.id === payload.person.id );
|
||||
state.accompanyingCourse.resources[i].resource = payload.person;
|
||||
break;
|
||||
}
|
||||
},
|
||||
updateThirdparty(state, payload) {
|
||||
console.log('### mutation: updateThirdparty', payload);
|
||||
let i = null;
|
||||
switch (payload.target) {
|
||||
case 'requestor':
|
||||
state.accompanyingCourse.requestor = payload.thirdparty;
|
||||
break;
|
||||
case 'resource':
|
||||
i = state.accompanyingCourse.resources.findIndex(e => e.resource.id === payload.thirdparty.id );
|
||||
state.accompanyingCourse.resources[i].resource = payload.thirdparty;
|
||||
break;
|
||||
}
|
||||
},
|
||||
toggleIntensity(state, value) {
|
||||
state.accompanyingCourse.intensity = value;
|
||||
},
|
||||
@@ -239,6 +271,38 @@ let initPromise = Promise.all([scopesPromise, accompanyingCoursePromise])
|
||||
resolve();
|
||||
})).catch((error) => { commit('catchError', error) });
|
||||
},
|
||||
patchOnTheFly({ commit }, payload) {
|
||||
console.log('## action: patch OnTheFly', payload);
|
||||
let body = { type: payload.type };
|
||||
if (payload.type === 'person') {
|
||||
body.firstName = payload.data.firstName;
|
||||
body.lastName = payload.data.lastName;
|
||||
if (payload.data.birthdate !== null) { body.birthdate = payload.data.birthdate; }
|
||||
body.phonenumber = payload.data.phonenumber;
|
||||
body.mobilenumber = payload.data.mobilenumber;
|
||||
body.gender = payload.data.gender;
|
||||
console.log('id', payload.data.id, 'and body', body);
|
||||
patchPerson(payload.data.id, body)
|
||||
.then(person => new Promise((resolve, reject) => {
|
||||
console.log('patch person', person);
|
||||
commit('updatePerson', { target: payload.target, person: person });
|
||||
resolve();
|
||||
}));
|
||||
}
|
||||
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 };
|
||||
console.log('id', payload.data.id, 'and body', body);
|
||||
patchThirdparty(payload.data.id, body)
|
||||
.then(thirdparty => new Promise((resolve, reject) => {
|
||||
console.log('patch thirdparty', thirdparty);
|
||||
commit('updateThirdparty', { target: payload.target, thirdparty: thirdparty });
|
||||
resolve();
|
||||
}));
|
||||
}
|
||||
},
|
||||
toggleIntensity({ commit }, payload) {
|
||||
//console.log(payload);
|
||||
patchAccompanyingCourse(id, { type: "accompanying_period", intensity: payload })
|
||||
|
@@ -109,7 +109,7 @@ export default {
|
||||
this.toggleEditEvaluation();
|
||||
},
|
||||
buildEditLink(storedObject) {
|
||||
return `/fr/chill_wopi/edit/${storedObject.filename}?returnPath=` + encodeURIComponent(
|
||||
return `/edit/${storedObject.uuid}?returnPath=` + encodeURIComponent(
|
||||
window.location.pathname + window.location.search + window.location.hash);
|
||||
},
|
||||
}
|
||||
|
@@ -1,34 +1,150 @@
|
||||
<template>
|
||||
<household></household>
|
||||
<concerned v-if="hasHouseholdOrLeave"></concerned>
|
||||
<dates v-if="showConfirm"></dates>
|
||||
<confirmation v-if="showConfirm"></confirmation>
|
||||
<ol class="breadcrumb">
|
||||
<li
|
||||
v-for="s in steps"
|
||||
class="breadcrumb-item" :class="{ active: step === s }"
|
||||
>
|
||||
{{ $t('household_members_editor.app.steps.'+s) }}
|
||||
</li>
|
||||
</ol>
|
||||
<concerned v-if="step === 'concerned'"></concerned>
|
||||
<household v-if="step === 'household'" @ready-to-go="goToNext"></household>
|
||||
<household-address v-if="step === 'household_address'"></household-address>
|
||||
<positioning v-if="step === 'positioning'"></positioning>
|
||||
<dates v-if="step === 'confirm'"></dates>
|
||||
<confirmation v-if="step === 'confirm'"></confirmation>
|
||||
|
||||
<ul class="record_actions sticky-form-buttons">
|
||||
<li class="cancel" v-if="step !== 'concerned' || hasReturnPath">
|
||||
<button class="btn btn-cancel" @click="goToPrevious">
|
||||
{{ $t('household_members_editor.app.cancel') }}
|
||||
</button>
|
||||
</li>
|
||||
<li v-if="step !== 'confirm'">
|
||||
<button class="btn btn-action" @click="goToNext" :disabled="!isNextAllowed">
|
||||
{{ $t('household_members_editor.app.next') }} <i class="fa fa-arrow-right"></i>
|
||||
</button>
|
||||
</li>
|
||||
<li v-else>
|
||||
<button class="btn btn-save" @click="confirm" :disabled="hasWarnings">
|
||||
{{ $t('household_members_editor.app.save') }}
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import { mapGetters } from 'vuex';
|
||||
import {mapGetters, mapState} from 'vuex';
|
||||
import Concerned from './components/Concerned.vue';
|
||||
import Household from './components/Household.vue';
|
||||
import HouseholdAddress from './components/HouseholdAddress';
|
||||
import Dates from './components/Dates.vue';
|
||||
import Confirmation from './components/Confirmation.vue';
|
||||
import Positioning from "./components/Positioning";
|
||||
|
||||
export default {
|
||||
name: 'App',
|
||||
components: {
|
||||
Positioning,
|
||||
Concerned,
|
||||
Household,
|
||||
HouseholdAddress,
|
||||
Dates,
|
||||
Confirmation,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
step: 'concerned',
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'hasHouseholdOrLeave',
|
||||
'hasPersonsWellPositionnated',
|
||||
]),
|
||||
showConfirm () {
|
||||
return this.$store.getters.hasHouseholdOrLeave
|
||||
&& this.$store.getters.hasPersonsWellPositionnated;
|
||||
...mapState({
|
||||
hasWarnings: (state) => state.warnings.length > 0 || state.errors.length > 0,
|
||||
}),
|
||||
steps() {
|
||||
let s = ['concerned', 'household'];
|
||||
|
||||
if (this.$store.getters.isHouseholdNew) {
|
||||
s.push('household_address');
|
||||
}
|
||||
|
||||
if (!this.$store.getters.isModeLeave) {
|
||||
s.push('positioning');
|
||||
}
|
||||
|
||||
s.push('confirm');
|
||||
|
||||
return s;
|
||||
},
|
||||
hasReturnPath() {
|
||||
let params = new URLSearchParams(window.location.search);
|
||||
|
||||
return params.has('returnPath');
|
||||
},
|
||||
// return true if the next step is allowed
|
||||
isNextAllowed() {
|
||||
switch (this.$data.step) {
|
||||
case 'concerned':
|
||||
return this.$store.state.concerned.length > 0;
|
||||
case 'household':
|
||||
return this.$store.state.mode !== null;
|
||||
case 'household_address':
|
||||
return this.$store.getters.hasHouseholdAddress || this.$store.getters.isHouseholdForceNoAddress;
|
||||
case 'positioning':
|
||||
return this.$store.getters.hasHouseholdOrLeave
|
||||
&& this.$store.getters.hasPersonsWellPositionnated;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
goToNext() {
|
||||
console.log('go to next');
|
||||
switch (this.$data.step) {
|
||||
case 'concerned':
|
||||
this.$data.step = 'household';
|
||||
break;
|
||||
case 'household':
|
||||
if (this.$store.getters.isHouseholdNew) {
|
||||
this.$data.step = 'household_address';
|
||||
break;
|
||||
} else if (this.$store.getters.isModeLeave) {
|
||||
this.$data.step = 'confirm';
|
||||
break;
|
||||
} else {
|
||||
this.$data.step = 'positioning';
|
||||
break;
|
||||
}
|
||||
case 'household_address':
|
||||
this.$data.step = 'positioning';
|
||||
break;
|
||||
case 'positioning':
|
||||
this.$data.step = 'confirm';
|
||||
break;
|
||||
}
|
||||
},
|
||||
goToPrevious() {
|
||||
if (this.$data.step === 'concerned') {
|
||||
let params = new URLSearchParams(window.location.search);
|
||||
if (params.has('returnPath')) {
|
||||
window.location.replace(params.get('returnPath'));
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let s = this.steps;
|
||||
let index = s.indexOf(this.$data.step);
|
||||
if (s[index - 1] === undefined) {
|
||||
throw Error("step not found");
|
||||
}
|
||||
|
||||
this.$data.step = s[index - 1];
|
||||
},
|
||||
confirm() {
|
||||
this.$store.dispatch('confirm');
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@@ -1,118 +1,41 @@
|
||||
<template>
|
||||
<h2 class="mt-4">{{ $t('household_members_editor.concerned.title') }}</h2>
|
||||
|
||||
<h3 v-if="needsPositionning">
|
||||
{{ $t('household_members_editor.concerned.persons_to_positionnate') }}
|
||||
</h3>
|
||||
<h3 v-else>
|
||||
{{ $t('household_members_editor.concerned.persons_leaving') }}
|
||||
</h3>
|
||||
|
||||
<div v-if="noPerson">
|
||||
<div class="alert alert-info">
|
||||
{{ $t('household_members_editor.add_at_least_onePerson') }}
|
||||
{{ $t('household_members_editor.concerned.add_at_least_onePerson') }}
|
||||
</div>
|
||||
</div>
|
||||
<div v-else-if="allPersonsPositionnated">
|
||||
<span class="chill-no-data-statement">{{ $t('household_members_editor.all_positionnated') }}</span>
|
||||
</div>
|
||||
<div v-else>
|
||||
<div class="flex-table list-household-members">
|
||||
<div v-for="conc in concUnpositionned"
|
||||
class="item-bloc"
|
||||
v-bind:key="conc.person.id"
|
||||
>
|
||||
<div class="item-row">
|
||||
<div class="item-col">
|
||||
<div>
|
||||
<person-render-box render="badge" :options="{}" :person="conc.person"></person-render-box>
|
||||
</div>
|
||||
<div v-if="conc.person.birthdate !== null">
|
||||
{{ $t('person.born', {'gender': conc.person.gender} ) }}
|
||||
{{ $d(conc.person.birthdate.datetime, 'short') }}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="item-col">
|
||||
<ul class="list-content fa-ul">
|
||||
<li>
|
||||
<i class="fa fa-li fa-map-marker"></i>
|
||||
<span class="chill-no-data-statement">Sans adresse</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="needsPositionning" class="item-row move_to">
|
||||
<div class="item-col">
|
||||
|
||||
<p class="move_hint">{{ $t('household_members_editor.concerned.move_to') }}:</p>
|
||||
|
||||
<template
|
||||
v-for="position in positions"
|
||||
>
|
||||
|
||||
<button
|
||||
class="btn btn-outline-primary"
|
||||
@click="moveToPosition(conc.person.id, position.id)"
|
||||
>
|
||||
{{ position.label.fr }}
|
||||
</button>
|
||||
|
||||
</template>
|
||||
|
||||
<button v-if="conc.allowRemove" @click="removeConcerned(conc)" class="btn btn-primary">
|
||||
{{ $t('household_members_editor.remove_concerned') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p>
|
||||
{{ $t('household_members_editor.concerned.persons_will_be_moved') }} :
|
||||
<span v-for="c in concerned">
|
||||
<person-render-box render="badge" :options="{addLink: false}" :person="c.person"></person-render-box>
|
||||
<button class="btn" @click="removePerson(c.person)" v-if="c.allowRemove" style="padding-left:0;">
|
||||
<span class="fa-stack fa-lg" :title="$t('household_members_editor.concerned.remove_concerned')">
|
||||
<i class="fa fa-circle fa-stack-1x text-danger"></i>
|
||||
<i class="fa fa-times fa-stack-1x"></i>
|
||||
</span>
|
||||
</button>
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<add-persons
|
||||
buttonTitle="household_members_editor.concerned.add_persons"
|
||||
modalTitle="household_members_editor.concerned.search"
|
||||
v-bind:key="addPersons.key"
|
||||
v-bind:options="addPersons.options"
|
||||
@addNewPersons="addNewPersons"
|
||||
ref="addPersons"> <!-- to cast child method -->
|
||||
</add-persons>
|
||||
</div>
|
||||
|
||||
|
||||
<div v-if="needsPositionning" class="positions">
|
||||
<div
|
||||
v-for="position in positions"
|
||||
>
|
||||
<h3>{{ position.label.fr }}</h3>
|
||||
|
||||
<div v-if="concByPosition(position.id).length > 0" class="flex-table list-household-members">
|
||||
<member-details
|
||||
v-for="conc in concByPosition(position.id)"
|
||||
v-bind:key="conc.person.id"
|
||||
v-bind:conc="conc"
|
||||
>
|
||||
</member-details>
|
||||
</div>
|
||||
|
||||
<div v-else>
|
||||
<p class="chill-no-data-statement">{{ $t('household_members_editor.concerned.no_person_in_position') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<ul class="record_actions">
|
||||
<li>
|
||||
<add-persons
|
||||
buttonTitle="household_members_editor.concerned.add_persons"
|
||||
modalTitle="household_members_editor.concerned.search"
|
||||
v-bind:key="addPersons.key"
|
||||
v-bind:options="addPersons.options"
|
||||
@addNewPersons="addNewPersons"
|
||||
ref="addPersons"> <!-- to cast child method -->
|
||||
</add-persons>
|
||||
</li>
|
||||
</ul>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
div.person {
|
||||
cursor: move;
|
||||
|
||||
* {
|
||||
cursor: move
|
||||
}
|
||||
}
|
||||
|
||||
.move_to {
|
||||
.move_hint {
|
||||
@@ -124,33 +47,26 @@ div.person {
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
import { mapState, mapGetters } from 'vuex';
|
||||
import AddPersons from 'ChillPersonAssets/vuejs/_components/AddPersons.vue';
|
||||
import PersonRenderBox from 'ChillPersonAssets/vuejs/_components/Entity/PersonRenderBox.vue';
|
||||
import MemberDetails from './MemberDetails.vue';
|
||||
import { ISOToDatetime } from 'ChillMainAssets/chill/js/date.js';
|
||||
|
||||
export default {
|
||||
name: 'Concerned',
|
||||
components: {
|
||||
AddPersons,
|
||||
MemberDetails,
|
||||
PersonRenderBox,
|
||||
},
|
||||
computed: {
|
||||
...mapState([
|
||||
'concerned'
|
||||
]),
|
||||
...mapGetters([
|
||||
'concUnpositionned',
|
||||
'positions',
|
||||
'concByPosition',
|
||||
'needsPositionning'
|
||||
'persons',
|
||||
]),
|
||||
noPerson () {
|
||||
return this.$store.getters.persons.length === 0;
|
||||
},
|
||||
allPersonsPositionnated () {
|
||||
return this.$store.getters.persons.length > 0
|
||||
&& this.$store.getters.concUnpositionned.length === 0;
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@@ -172,11 +88,9 @@ export default {
|
||||
this.$refs.addPersons.resetSearch(); // to cast child method
|
||||
modal.showModal = false;
|
||||
},
|
||||
moveToPosition(person_id, position_id) {
|
||||
this.$store.dispatch('markPosition', { person_id, position_id });
|
||||
},
|
||||
removeConcerned(conc) {
|
||||
this.$store.dispatch('removeConcerned', conc);
|
||||
removePerson(person) {
|
||||
console.log('remove person in concerned', person);
|
||||
this.$store.dispatch('removePerson', person);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@@ -1,28 +1,19 @@
|
||||
<template>
|
||||
|
||||
<div v-if="hasWarnings" class="alert alert-warning">
|
||||
<div v-if="hasWarning" class="alert alert-warning">
|
||||
{{ $t('household_members_editor.confirmation.there_are_warnings') }}
|
||||
</div>
|
||||
|
||||
<p v-if="hasWarnings">
|
||||
<p v-if="hasWarning">
|
||||
{{ $t('household_members_editor.confirmation.check_those_items') }}
|
||||
</p>
|
||||
|
||||
|
||||
<ul>
|
||||
<li v-for="(msg, index) in warnings">
|
||||
<li v-for="(msg, index) in warnings" class="warning">
|
||||
{{ $t(msg.m, msg.a) }}
|
||||
</li>
|
||||
<li v-for="msg in errors">
|
||||
<li v-for="msg in errors" class="error">
|
||||
{{ msg }}
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<ul class="record_actions sticky-form-buttons">
|
||||
<li>
|
||||
<button class="btn btn-save" :disabled="hasWarnings" @click="confirm">
|
||||
{{ $t('household_members_editor.confirmation.save') }}
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</template>
|
||||
|
||||
@@ -36,17 +27,11 @@ export default {
|
||||
name: 'Confirmation',
|
||||
computed: {
|
||||
...mapState({
|
||||
hasWarnings: (state) => state.warnings.length > 0 || state.errors.length > 0,
|
||||
warnings: (state) => state.warnings,
|
||||
errors: (state) => state.errors,
|
||||
hasNoWarnings: (state) => state.warnings.length === 0 && state.errors.length === 0,
|
||||
hasWarnings: (state) => state.warnings.length > 0 || state.errors.length > 0,
|
||||
}),
|
||||
},
|
||||
methods: {
|
||||
confirm() {
|
||||
this.$store.dispatch('confirm');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
@@ -0,0 +1,50 @@
|
||||
<template>
|
||||
<div class="flex-table" v-if="hasHousehold">
|
||||
<div class="item-bloc">
|
||||
<household-render-box :household="fakeHouseholdWithConcerned"></household-render-box>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-table" v-if="isModeLeave">
|
||||
<div class="item-bloc">
|
||||
<section>
|
||||
<div class="item-row">
|
||||
<div class="item-col">
|
||||
<div class="h4">
|
||||
<span class="fa-stack fa-lg">
|
||||
<i class="fa fa-home fa-stack-1x"></i>
|
||||
<i class="fa fa-ban fa-stack-2x text-danger"></i>
|
||||
</span>
|
||||
{{ $t('household_members_editor.household.leave_without_household') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item-row">
|
||||
{{ $t('household_members_editor.household.will_leave_any_household_explanation')}}
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
import HouseholdRenderBox from 'ChillPersonAssets/vuejs/_components/Entity/HouseholdRenderBox.vue';
|
||||
|
||||
export default {
|
||||
name: "CurrentHousehold",
|
||||
components: {
|
||||
HouseholdRenderBox,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'hasHousehold',
|
||||
'fakeHouseholdWithConcerned',
|
||||
'isModeLeave'
|
||||
])
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
</style>
|
@@ -1,5 +1,8 @@
|
||||
<template>
|
||||
<h2>{{ $t('household_members_editor.dates_title') }}</h2>
|
||||
|
||||
<current-household></current-household>
|
||||
|
||||
<h2>{{ $t('household_members_editor.dates.dates_title') }}</h2>
|
||||
|
||||
<p>
|
||||
<label for="start_date">
|
||||
@@ -11,8 +14,13 @@
|
||||
|
||||
<script>
|
||||
|
||||
import CurrentHousehold from "./CurrentHousehold";
|
||||
|
||||
export default {
|
||||
name: 'Dates',
|
||||
components: {
|
||||
CurrentHousehold
|
||||
},
|
||||
computed: {
|
||||
startDate: {
|
||||
get() {
|
||||
@@ -23,10 +31,10 @@ export default {
|
||||
].join('-');
|
||||
},
|
||||
set(value) {
|
||||
let
|
||||
let
|
||||
[year, month, day] = value.split('-'),
|
||||
dValue = new Date(year, month-1, day);
|
||||
|
||||
|
||||
this.$store.dispatch('setStartDate', dValue);
|
||||
}
|
||||
}
|
||||
|
@@ -2,218 +2,118 @@
|
||||
|
||||
<h2 class="mt-4">{{ $t('household_members_editor.household_part') }}</h2>
|
||||
|
||||
<div v-if="hasHousehold">
|
||||
|
||||
<div class="flex-table">
|
||||
<div class="item-bloc">
|
||||
<household-render-box :household="household" :isAddressMultiline="true"></household-render-box>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="isHouseholdNew && !hasHouseholdAddress">
|
||||
|
||||
<div v-if="hasAddressSuggestion" class="householdAddressSuggestion my-5">
|
||||
<h4 class="mb-3">
|
||||
{{ $t('household_members_editor.household.where_live_the_household') }}
|
||||
</h4>
|
||||
<div class="accordion" id="addressSuggestions">
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header" id="heading_address_suggestions">
|
||||
<button v-if="!showAddressSuggestion"
|
||||
class="accordion-button collapsed"
|
||||
type="button"
|
||||
data-bs-toggle="collapse"
|
||||
aria-expanded="false"
|
||||
@click="toggleAddressSuggestion">
|
||||
{{ $tc('household_members_editor.show_household_suggestion', countAddressSuggestion) }}
|
||||
</button>
|
||||
<button v-if="showAddressSuggestion"
|
||||
class="accordion-button"
|
||||
type="button"
|
||||
data-bs-toggle="collapse"
|
||||
aria-expanded="true"
|
||||
@click="toggleAddressSuggestion">
|
||||
{{ $t('household_members_editor.hide_household_suggestion') }}
|
||||
</button>
|
||||
</h2>
|
||||
<div class="accordion-collapse" id="collapse_address_suggestions"
|
||||
aria-labelledby="heading_address_suggestions" data-bs-parent="#addressSuggestions">
|
||||
<div v-if="showAddressSuggestion">
|
||||
<div class="flex-table householdAddressSuggestionList">
|
||||
<div v-for="a in filterAddressesSuggestion" class="item-bloc">
|
||||
<div class="float-button bottom">
|
||||
<div class="box">
|
||||
<div class="action">
|
||||
<ul class="record_actions">
|
||||
<li>
|
||||
<button class="btn btn-sm btn-choose" @click="setHouseholdAddress(a)">
|
||||
{{ $t('household_members_editor.household.household_live_to_this_address') }}
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<ul class="list-content fa-ul">
|
||||
<li>
|
||||
<i class="fa fa-li fa-map-marker"></i>
|
||||
<address-render-box :address="a"></address-render-box>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ul class="record_actions">
|
||||
<li >
|
||||
<add-address
|
||||
:context="addAddress.context"
|
||||
:key="addAddress.key"
|
||||
:options="addAddress.options"
|
||||
:result="addAddress.result"
|
||||
@addressChangedCallback="setHouseholdCreatedAddress"
|
||||
ref="addAddress">
|
||||
</add-address>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div v-if="isHouseholdNew && hasHouseholdAddress">
|
||||
<ul class="record_actions">
|
||||
<li >
|
||||
<button class="btn btn-misc" @click="removeHouseholdAddress">
|
||||
{{ $t('household_members_editor.household.delete_this_address') }}
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="alert alert-info" v-if="!hasHousehold">
|
||||
{{ $t('household_members_editor.household.no_household_choose_one') }}
|
||||
</div>
|
||||
<div v-else-if="isForceLeaveWithoutHousehold">
|
||||
{{ $t('household_members_editor.household.will_leave_any_household') }}
|
||||
</div>
|
||||
<div v-else class="alert alert-info">{{ $t('household_members_editor.household.no_household_choose_one') }}</div>
|
||||
<template v-else>
|
||||
<current-household></current-household>
|
||||
</template>
|
||||
|
||||
<ul v-if="allowChangeHousehold" class="record_actions">
|
||||
<li v-if="allowHouseholdCreate">
|
||||
<button class="btn btn-create" @click="createHousehold">
|
||||
{{ $t('household_members_editor.household.create_household') }}
|
||||
</button>
|
||||
</li>
|
||||
<li v-if="allowHouseholdSearch">
|
||||
<button class="btn btn-misc">
|
||||
<i class="fa fa-search"></i>{{ $t('household_members_editor.household.search_household') }}
|
||||
</button>
|
||||
</li>
|
||||
<li v-if="allowLeaveWithoutHousehold" >
|
||||
<button @click="forceLeaveWithoutHousehold" class="btn btn-orange">
|
||||
<i class="fa fa-sign-out"></i>{{ $t('household_members_editor.household.leave_without_household') }}
|
||||
</button>
|
||||
</li>
|
||||
<li v-if="allowRemoveHousehold">
|
||||
<button @click="removeHousehold" class="btn">
|
||||
{{ $t('household_members_editor.household.change') }}
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div v-if="hasHouseholdSuggestion" class="householdSuggestions my-5">
|
||||
<h4 class="mb-3">
|
||||
{{ $t('household_members_editor.household_for_participants_accompanying_period') }} :
|
||||
</h4>
|
||||
<div class="accordion" id="householdSuggestions">
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header" id="heading_household_suggestions">
|
||||
<button v-if="!showHouseholdSuggestion"
|
||||
<div v-if="hasHouseholdSuggestion" class="householdSuggestions my-5">
|
||||
<h4 class="mb-3">
|
||||
{{ $t('household_members_editor.household.household_suggested') }}
|
||||
</h4>
|
||||
<p>{{ $t('household_members_editor.household.household_suggested_explanation') }}</p>
|
||||
<div class="accordion" id="householdSuggestions">
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header" id="heading_household_suggestions">
|
||||
<button v-if="!showHouseholdSuggestion"
|
||||
class="accordion-button collapsed"
|
||||
type="button"
|
||||
data-bs-toggle="collapse"
|
||||
aria-expanded="false"
|
||||
@click="toggleHouseholdSuggestion">
|
||||
{{ $tc('household_members_editor.show_household_suggestion', countHouseholdSuggestion) }}
|
||||
</button>
|
||||
<button v-if="showHouseholdSuggestion"
|
||||
{{ $tc('household_members_editor.show_household_suggestion', countHouseholdSuggestion) }}
|
||||
</button>
|
||||
<button v-if="showHouseholdSuggestion"
|
||||
class="accordion-button"
|
||||
type="button"
|
||||
data-bs-toggle="collapse"
|
||||
aria-expanded="true"
|
||||
@click="toggleHouseholdSuggestion">
|
||||
{{ $t('household_members_editor.hide_household_suggestion') }}
|
||||
</button>
|
||||
<!-- disabled bootstrap behaviour: data-bs-target="#collapse_household_suggestions" aria-controls="collapse_household_suggestions" -->
|
||||
</h2>
|
||||
<div class="accordion-collapse" id="collapse_household_suggestions"
|
||||
aria-labelledby="heading_household_suggestions" data-bs-parent="#householdSuggestions">
|
||||
<div v-if="showHouseholdSuggestion">
|
||||
<div class="flex-table householdSuggestionList">
|
||||
<div v-for="h in filterHouseholdSuggestionByAccompanyingPeriod" class="item-bloc">
|
||||
<household-render-box :household="h"></household-render-box>
|
||||
<ul class="record_actions">
|
||||
<li>
|
||||
<button class="btn btn-sm btn-choose" @click="selectHousehold(h)">
|
||||
{{ $t('household_members_editor.select_household') }}
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{ $t('household_members_editor.hide_household_suggestion') }}
|
||||
</button>
|
||||
<!-- disabled bootstrap behaviour: data-bs-target="#collapse_household_suggestions" aria-controls="collapse_household_suggestions" -->
|
||||
</h2>
|
||||
<div class="accordion-collapse" id="collapse_household_suggestions"
|
||||
aria-labelledby="heading_household_suggestions" data-bs-parent="#householdSuggestions">
|
||||
<div v-if="showHouseholdSuggestion">
|
||||
<div class="flex-table householdSuggestionList">
|
||||
<div v-for="s in getSuggestions" class="item-bloc">
|
||||
<household-render-box :household="s.household"></household-render-box>
|
||||
<ul class="record_actions">
|
||||
<li>
|
||||
<button class="btn btn-sm btn-choose" @click="selectHousehold(s.household)">
|
||||
{{ $t('household_members_editor.select_household') }}
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<ul class="record_actions">
|
||||
<li v-if="hasHousehold">
|
||||
<button @click="resetMode" class="btn btn-sm btn-misc">{{ $t('household_members_editor.household.reset_mode')}}</button>
|
||||
</li>
|
||||
<li v-if="!hasHousehold">
|
||||
<button @click="setModeNew" class="btn btn-sm btn-create">{{ $t('household_members_editor.household.create_household') }}</button>
|
||||
</li>
|
||||
<li v-if="isModeLeaveAllowed && !hasHousehold">
|
||||
<button @click="setModeLeave" class="btn btn-sm btn-misc">
|
||||
<i class="fa fa-sign-out"></i>
|
||||
{{ $t('household_members_editor.household.leave') }}
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters, mapState } from 'vuex';
|
||||
import HouseholdRenderBox from 'ChillPersonAssets/vuejs/_components/Entity/HouseholdRenderBox.vue';
|
||||
import AddressRenderBox from 'ChillMainAssets/vuejs/_components/Entity/AddressRenderBox.vue';
|
||||
import AddAddress from 'ChillMainAssets/vuejs/Address/components/AddAddress.vue';
|
||||
import CurrentHousehold from './CurrentHousehold';
|
||||
|
||||
export default {
|
||||
name: 'Household',
|
||||
components: {
|
||||
CurrentHousehold,
|
||||
HouseholdRenderBox,
|
||||
AddressRenderBox,
|
||||
AddAddress,
|
||||
},
|
||||
emits: ['readyToGo'],
|
||||
data() {
|
||||
return {
|
||||
addAddress: {
|
||||
context: {
|
||||
target: {
|
||||
name: 'household_create',
|
||||
id: 0
|
||||
},
|
||||
edit: false,
|
||||
addressId: null
|
||||
},
|
||||
key: 'household_new',
|
||||
options: {
|
||||
useDate: {
|
||||
validFrom: true
|
||||
validFrom: false,
|
||||
validTo: false,
|
||||
},
|
||||
onlyButton: true,
|
||||
button: {
|
||||
text: {
|
||||
create: 'household_members_editor.household.or_create_new_address',
|
||||
edit: null,
|
||||
create: 'household_members_editor.household.set_address',
|
||||
edit: 'household_members_editor.household.update_address',
|
||||
}
|
||||
},
|
||||
title: {
|
||||
create: 'household_members_editor.household.create_new_address',
|
||||
edit: null,
|
||||
edit: 'household_members_editor.household.update_address_title',
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'isModeNewAllowed',
|
||||
'isModeLeaveAllowed',
|
||||
'getSuggestions',
|
||||
'hasHousehold',
|
||||
'isHouseholdNew',
|
||||
'hasHouseholdSuggestion',
|
||||
@@ -223,72 +123,55 @@ export default {
|
||||
'countAddressSuggestion',
|
||||
'filterAddressesSuggestion',
|
||||
'hasHouseholdAddress',
|
||||
'isModeLeave',
|
||||
'getAddressContext',
|
||||
]),
|
||||
...mapState([
|
||||
'household',
|
||||
'showHouseholdSuggestion',
|
||||
'showAddressSuggestion'
|
||||
'showAddressSuggestion',
|
||||
'mode',
|
||||
]),
|
||||
household() {
|
||||
return this.$store.state.household;
|
||||
},
|
||||
allowHouseholdCreate() {
|
||||
return this.$store.state.allowHouseholdCreate && !this.$store.getters.hasHousehold;
|
||||
},
|
||||
allowHouseholdSearch() {
|
||||
return false;
|
||||
return this.$store.state.allowHouseholdSearch && !this.$store.getters.hasHousehold;
|
||||
},
|
||||
allowLeaveWithoutHousehold() {
|
||||
return this.$store.state.allowLeaveWithoutHousehold && !this.$store.getters.hasHousehold;
|
||||
isHouseholdNewDesactivated() {
|
||||
return this.$store.state.mode !== null && !this.$store.getters.isHouseholdNew;
|
||||
},
|
||||
allowRemoveHousehold() {
|
||||
return this.$store.getters.hasHousehold &&
|
||||
(
|
||||
this.allowHouseholdCreate || this.allowHouseholdSearch ||
|
||||
this.allowLeaveWithoutHousehold
|
||||
)
|
||||
;
|
||||
},
|
||||
allowChangeHousehold() {
|
||||
return this.allowHouseholdCreate || this.allowHouseholdSearch ||
|
||||
this.allowLeaveWithoutHousehold;
|
||||
},
|
||||
isForceLeaveWithoutHousehold() {
|
||||
return this.$store.state.forceLeaveWithoutHousehold;
|
||||
isHouseholdLeaveDesactivated() {
|
||||
return this.$store.state.mode !== null && this.$store.state.mode !== "leave";
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
createHousehold() {
|
||||
setModeNew() {
|
||||
this.$store.dispatch('createHousehold');
|
||||
this.$emit('readyToGo');
|
||||
},
|
||||
forceLeaveWithoutHousehold() {
|
||||
setModeLeave() {
|
||||
this.$store.dispatch('forceLeaveWithoutHousehold');
|
||||
this.$emit('readyToGo');
|
||||
},
|
||||
toggleHouseholdSuggestion() {
|
||||
this.$store.commit('toggleHouseholdSuggestion');
|
||||
resetMode() {
|
||||
this.$store.commit('resetMode');
|
||||
},
|
||||
toggleAddressSuggestion() {
|
||||
this.$store.commit('toggleAddressSuggestion');
|
||||
addressChanged(payload) {
|
||||
console.log("addressChanged", payload);
|
||||
this.$store.dispatch('setHouseholdNewAddress', payload.address);
|
||||
},
|
||||
selectHousehold(h) {
|
||||
this.$store.dispatch('selectHousehold', h);
|
||||
this.toggleHouseholdSuggestion();
|
||||
},
|
||||
removeHousehold() {
|
||||
this.$store.dispatch('removeHousehold');
|
||||
},
|
||||
setHouseholdAddress(a) {
|
||||
let payload = this.$refs.addAddress.submitNewAddress();
|
||||
console.log('setHouseholdAddress', a);
|
||||
this.$store.commit('setHouseholdAddress', a);
|
||||
},
|
||||
setHouseholdCreatedAddress(payload) {
|
||||
console.log('setHouseholdAddress', payload);
|
||||
this.$store.dispatch('setHouseholdNewAddress', payload);
|
||||
this.$emit('readyToGo');
|
||||
},
|
||||
removeHouseholdAddress() {
|
||||
this.$store.commit('removeHouseholdAddress');
|
||||
},
|
||||
toggleHouseholdSuggestion() {
|
||||
this.$store.commit('toggleHouseholdSuggestion');
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -296,6 +179,18 @@ export default {
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
.filtered {
|
||||
filter: grayscale(1) opacity(0.6);
|
||||
}
|
||||
|
||||
.filteredButActive {
|
||||
|
||||
filter: grayscale(1) opacity(0.6);
|
||||
&:hover {
|
||||
filter: unset;
|
||||
}
|
||||
}
|
||||
|
||||
div#household_members_editor div,
|
||||
div.householdSuggestionList {
|
||||
&.flex-table {
|
||||
@@ -310,28 +205,4 @@ div.householdSuggestionList {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
div.householdAddressSuggestionList {
|
||||
display: flex;
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
& > li {}
|
||||
}
|
||||
.householdSuggestionList {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
& > .item {
|
||||
margin-bottom: 0.8rem;
|
||||
width: calc(50% - 1rem);
|
||||
border: 1px solid var(--chill-light-gray);
|
||||
padding: 0.5rem 0.5rem 0 0.5rem;
|
||||
ul.record_actions {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
</style>
|
||||
|
@@ -0,0 +1,88 @@
|
||||
<template>
|
||||
<current-household></current-household>
|
||||
|
||||
<ul class="record_actions">
|
||||
<li v-if="!hasHouseholdAddress && !isHouseholdForceAddress">
|
||||
<button class="btn" @click="markNoAddress">
|
||||
{{ $t('household_members_editor.household_address.mark_no_address') }}
|
||||
</button>
|
||||
</li>
|
||||
<li v-if="!hasHouseholdAddress">
|
||||
<add-address
|
||||
:context="getAddressContext"
|
||||
:key="addAddress.key"
|
||||
:options="addAddress.options"
|
||||
:addressChangedCallback="addressChanged"
|
||||
></add-address>
|
||||
</li>
|
||||
<li v-if="hasHouseholdAddress">
|
||||
<button class="btn btn-remove"
|
||||
@click="removeHouseholdAddress">
|
||||
{{ $t('household_members_editor.household_address.remove_address') }}
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import AddAddress from 'ChillMainAssets/vuejs/Address/components/AddAddress.vue';
|
||||
import CurrentHousehold from './CurrentHousehold';
|
||||
import { mapGetters } from 'vuex';
|
||||
|
||||
export default {
|
||||
name: "HouseholdAddress.vue",
|
||||
components: {
|
||||
CurrentHousehold,
|
||||
AddAddress,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
addAddress: {
|
||||
key: 'household_new',
|
||||
options: {
|
||||
useDate: {
|
||||
validFrom: false,
|
||||
validTo: false,
|
||||
},
|
||||
onlyButton: true,
|
||||
button: {
|
||||
text: {
|
||||
create: 'household_members_editor.household_address.set_address',
|
||||
edit: 'household_members_editor.household_address.update_address',
|
||||
}
|
||||
},
|
||||
title: {
|
||||
create: 'household_members_editor.household_address.create_new_address',
|
||||
edit: 'household_members_editor.household_address.update_address_title',
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'isHouseholdNew',
|
||||
'hasHouseholdAddress',
|
||||
'getAddressContext',
|
||||
'isHouseholdForceNoAddress'
|
||||
])
|
||||
},
|
||||
methods: {
|
||||
addressChanged(payload) {
|
||||
console.log("addressChanged", payload);
|
||||
this.$store.dispatch('setHouseholdNewAddress', payload.address);
|
||||
},
|
||||
markNoAddress() {
|
||||
this.$store.commit('markHouseholdNoAddress');
|
||||
},
|
||||
removeHouseholdAddress() {
|
||||
this.$store.commit('removeHouseholdAddress');
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
@@ -0,0 +1,106 @@
|
||||
<template>
|
||||
<current-household></current-household>
|
||||
|
||||
<h2>{{ $t('household_members_editor.positioning.persons_to_positionnate')}}</h2>
|
||||
|
||||
<div class="list-household-members">
|
||||
<div
|
||||
v-for="conc in concerned"
|
||||
class="item-bloc"
|
||||
v-bind:key="conc.person.id"
|
||||
>
|
||||
<div class="pick-position">
|
||||
<div class="person">
|
||||
<person-render-box render="badge" :options="{}" :person="conc.person"></person-render-box>
|
||||
</div>
|
||||
<div class="holder">
|
||||
<button
|
||||
class="btn"
|
||||
:disabled="!allowHolderForConcerned(conc)"
|
||||
:class="{'btn-outline-chill-green': !conc.holder, 'btn-chill-green': conc.holder }"
|
||||
@click="toggleHolder(conc)"
|
||||
>
|
||||
{{ $t('household_members_editor.positioning.holder') }}
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
v-for="position in positions"
|
||||
class="position"
|
||||
>
|
||||
<button
|
||||
class="btn"
|
||||
:class="{ 'btn-primary': conc.position === position, 'btn-outline-primary': conc.position !== position }"
|
||||
@click="moveToPosition(conc.person.id, position.id)"
|
||||
>
|
||||
{{ position.label.fr }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MemberDetails from './MemberDetails.vue';
|
||||
import {mapGetters, mapState} from "vuex";
|
||||
import CurrentHousehold from "./CurrentHousehold";
|
||||
import PersonRenderBox from 'ChillPersonAssets/vuejs/_components/Entity/PersonRenderBox.vue';
|
||||
|
||||
export default {
|
||||
name: "Positioning",
|
||||
components: {
|
||||
CurrentHousehold,
|
||||
PersonRenderBox,
|
||||
},
|
||||
computed: {
|
||||
...mapState([
|
||||
'concerned'
|
||||
]),
|
||||
...mapGetters([
|
||||
'persons',
|
||||
'concUnpositionned',
|
||||
'positions',
|
||||
'concByPosition',
|
||||
]),
|
||||
allPersonsPositionnated () {
|
||||
return this.$store.getters.persons.length > 0
|
||||
&& this.$store.getters.concUnpositionned.length === 0;
|
||||
},
|
||||
allowHolderForConcerned: (app) => (conc) => {
|
||||
console.log('allow holder for concerned', conc);
|
||||
if (conc.position === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return conc.position.allowHolder;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
moveToPosition(person_id, position_id) {
|
||||
this.$store.dispatch('markPosition', { person_id, position_id });
|
||||
},
|
||||
toggleHolder(conc) {
|
||||
console.log('toggle holder', conc);
|
||||
this.$store.dispatch('toggleHolder', conc);
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
.pick-position {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
|
||||
.person {
|
||||
margin-right: auto;
|
||||
}
|
||||
.holder {
|
||||
margin-right: 1.2rem;
|
||||
}
|
||||
}
|
||||
</style>
|
@@ -5,54 +5,80 @@ const appMessages = {
|
||||
fr: {
|
||||
household_members_editor: {
|
||||
household: {
|
||||
no_household_choose_one: "Aucun ménage de destination. Choisissez un ménage. Les usagers concernés par la modification apparaitront ensuite.",
|
||||
new_household: "Nouveau ménage",
|
||||
create_household: "Créer un nouveau ménage de destination",
|
||||
no_household_choose_one: "Aucun ménage de destination. Choisissez un ménage.",
|
||||
// new_household: "Nouveau ménage",
|
||||
create_household: "Créer",
|
||||
search_household: "Chercher un ménage",
|
||||
will_leave_any_household: "Ne rejoignent pas de ménage",
|
||||
will_leave_any_household: "Les usagers ne rejoignent pas de ménage",
|
||||
leave: "Quitter sans rejoindre un ménage",
|
||||
will_leave_any_household_explanation: "Les usagers quitteront leur ménage actuel, et ne seront pas associés à un autre ménage. Par ailleurs, ils seront enregistrés comme étant sans adresse connue.",
|
||||
leave_without_household: "Sans nouveau ménage",
|
||||
reset_mode: "Modifier la destination",
|
||||
household_suggested: "Suggestions de ménage",
|
||||
household_suggested_explanation: "Les ménages suivants sont connus et pourraient peut-être correspondre à des ménages recherchés."
|
||||
// remove ?
|
||||
/*
|
||||
where_live_the_household: "À quelle adresse habite ce ménage ?",
|
||||
household_live_to_this_address: "Sélectionner l'adresse",
|
||||
no_suggestions: "Aucune adresse à suggérer",
|
||||
delete_this_address: "Supprimer cette adresse",
|
||||
create_new_address: "Créer une nouvelle adresse",
|
||||
or_create_new_address: "Ou créer une nouvelle adresse",
|
||||
|
||||
*/
|
||||
// end remove ?
|
||||
},
|
||||
household_address: {
|
||||
mark_no_address: "Ne pas indiquer d'adresse",
|
||||
remove_address: "Supprimer l'adresse",
|
||||
update_address: "Mettre à jour l'adresse",
|
||||
set_address: "Indiquer une adresse",
|
||||
create_new_address: "Créer une nouvelle adresse",
|
||||
},
|
||||
concerned: {
|
||||
title: "Nouveaux membres du ménage",
|
||||
title: "Usagers déplacés",
|
||||
persons_will_be_moved: "Les usagers suivants vont être déplacés",
|
||||
add_at_least_onePerson: "Indiquez au moins un usager à déplacer",
|
||||
remove_concerned: "Ne plus transférer",
|
||||
// old ?
|
||||
add_persons: "Ajouter d'autres usagers",
|
||||
search: "Rechercher des usagers",
|
||||
move_to: "Déplacer vers",
|
||||
persons_to_positionnate: 'Usagers à positionner',
|
||||
persons_leaving: "Usagers quittant leurs ménages",
|
||||
no_person_in_position: "Aucun usager ne sera ajouté à cette position",
|
||||
},
|
||||
positioning: {
|
||||
persons_to_positionnate: 'Usagers à positionner',
|
||||
holder: "Titulaire",
|
||||
},
|
||||
app: {
|
||||
next: 'Suivant',
|
||||
cancel: 'Annuler',
|
||||
save: 'Enregistrer',
|
||||
steps: {
|
||||
concerned: 'Usagers concernés',
|
||||
household: 'Ménage de destination',
|
||||
household_address: 'Adresse du nouveau ménage',
|
||||
positioning: 'Position dans le ménage',
|
||||
confirm: 'Confirmation'
|
||||
}
|
||||
},
|
||||
drop_persons_here: "Glissez-déposez ici les usagers pour la position \"{position}\"",
|
||||
all_positionnated: "Tous les usagers sont positionnés",
|
||||
holder: "Titulaire",
|
||||
is_holder: "Est titulaire",
|
||||
is_not_holder: "N'est pas titulaire",
|
||||
remove_position: "Retirer des {position}",
|
||||
remove_concerned: "Ne plus transférer",
|
||||
household_part: "Ménage de destination",
|
||||
household_part: "Destination",
|
||||
suggestions: "Suggestions",
|
||||
hide_household_suggestion: "Masquer les suggestions",
|
||||
show_household_suggestion: 'Aucune suggestion | Afficher une suggestion | Afficher {count} suggestions',
|
||||
household_for_participants_accompanying_period: "Des ménages partagent le même parcours",
|
||||
select_household: "Sélectionner le ménage",
|
||||
dates_title: "Période de validité",
|
||||
dates: {
|
||||
start_date: "Début de validité",
|
||||
end_date: "Fin de validité",
|
||||
dates_title: "Période de validité",
|
||||
},
|
||||
confirmation: {
|
||||
save: "Enregistrer",
|
||||
there_are_warnings: "Impossible de valider actuellement",
|
||||
check_those_items: "Veuillez corriger les éléments suivants",
|
||||
},
|
||||
give_a_position_to_every_person: "Indiquez une position pour chaque usager concerné",
|
||||
add_destination: "Indiquez un ménage de destination",
|
||||
add_at_least_onePerson: "Indiquez au moins un usager à transférer",
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@@ -1,5 +1,6 @@
|
||||
import { createStore } from 'vuex';
|
||||
import { householdMove, fetchHouseholdSuggestionByAccompanyingPeriod, fetchAddressSuggestionByPerson} from './../api.js';
|
||||
import { fetchHouseholdByAddressReference } from 'ChillPersonAssets/lib/household.js';
|
||||
import { datetimeToISO } from 'ChillMainAssets/chill/js/date.js';
|
||||
|
||||
const debug = process.env.NODE_ENV !== 'production';
|
||||
@@ -29,11 +30,29 @@ const store = createStore({
|
||||
return 0;
|
||||
}),
|
||||
startDate: new Date(),
|
||||
/**
|
||||
* Indicates if the destination is:
|
||||
*
|
||||
* * "new" => a new household
|
||||
* * "existing" => an existing household
|
||||
* * "leave" => leave without household
|
||||
* * null if not set
|
||||
*/
|
||||
mode: window.household_members_editor_data.household === null ? null : "existing",
|
||||
allowHouseholdCreate: window.household_members_editor_data.allowHouseholdCreate,
|
||||
allowHouseholdSearch: window.household_members_editor_data.allowHouseholdSearch,
|
||||
allowLeaveWithoutHousehold: window.household_members_editor_data.allowLeaveWithoutHousehold,
|
||||
forceLeaveWithoutHousehold: false,
|
||||
householdSuggestionByAccompanyingPeriod: [],
|
||||
/**
|
||||
* If true, the user explicitly said that no address is possible
|
||||
*/
|
||||
forceHouseholdNoAddress: false,
|
||||
/**
|
||||
* Household suggestions
|
||||
*
|
||||
* (this is not restricted to "suggestion by accompanying periods")
|
||||
*/
|
||||
householdSuggestionByAccompanyingPeriod: [], // TODO rename into householdsSuggestion
|
||||
showHouseholdSuggestion: window.household_members_editor_expand_suggestions === 1,
|
||||
addressesSuggestion: [],
|
||||
showAddressSuggestion: true,
|
||||
@@ -41,11 +60,69 @@ const store = createStore({
|
||||
errors: []
|
||||
},
|
||||
getters: {
|
||||
/**
|
||||
* return true if this page allow to create a new household
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isModeNewAllowed(state) {
|
||||
return state.allowHouseholdCreate;
|
||||
},
|
||||
/**
|
||||
* return true if this page allow to "leave without household"
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isModeLeaveAllowed(state) {
|
||||
return state.allowLeaveWithoutHousehold;
|
||||
},
|
||||
/**
|
||||
* return true if the mode "leave" is selected
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isModeLeave(state) {
|
||||
return state.mode === "leave";
|
||||
},
|
||||
isHouseholdForceNoAddress(state) {
|
||||
return state.forceHouseholdNoAddress;
|
||||
},
|
||||
getSuggestions(state) {
|
||||
let suggestions = [];
|
||||
state.householdSuggestionByAccompanyingPeriod.forEach(h => {
|
||||
suggestions.push({household: h});
|
||||
});
|
||||
|
||||
return suggestions;
|
||||
},
|
||||
isHouseholdNew(state) {
|
||||
return state.mode === "new";
|
||||
},
|
||||
getAddressContext(state, getters) {
|
||||
if (state.household === null) {
|
||||
return false;
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!getters.hasHouseholdAddress) {
|
||||
return {
|
||||
edit: false,
|
||||
addressId: null,
|
||||
target: {
|
||||
name: state.household.type,
|
||||
id: state.household.id
|
||||
},
|
||||
suggestions: state.addressesSuggestion
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
edit: true,
|
||||
addressId: state.household.current_address.id,
|
||||
target: {
|
||||
name: state.household.type,
|
||||
id: state.household.id
|
||||
},
|
||||
};
|
||||
}
|
||||
return !Number.isInteger(state.household.id);
|
||||
},
|
||||
hasHouseholdAddress(state) {
|
||||
if (null === state.household) {
|
||||
@@ -130,6 +207,40 @@ const store = createStore({
|
||||
needsPositionning(state) {
|
||||
return state.forceLeaveWithoutHousehold === false;
|
||||
},
|
||||
fakeHouseholdWithConcerned(state, getters) {
|
||||
if (null === state.household) {
|
||||
throw Error('cannot create fake household without household');
|
||||
}
|
||||
let h = {
|
||||
type: 'household',
|
||||
members: state.household.members,
|
||||
current_address: state.household.current_address,
|
||||
current_members_id: state.household.current_members_id,
|
||||
new_members: [],
|
||||
};
|
||||
|
||||
if (!getters.isHouseholdNew){
|
||||
h.id = state.household.id;
|
||||
}
|
||||
|
||||
state.concerned.forEach((c, index) => {
|
||||
let m = {
|
||||
id: index * -1,
|
||||
person: c.person,
|
||||
holder: c.holder,
|
||||
position: c.position,
|
||||
};
|
||||
if (c.position === null) {
|
||||
m.position = {
|
||||
ordering: 999999
|
||||
}
|
||||
}
|
||||
h.new_members.push(m);
|
||||
})
|
||||
|
||||
console.log('fake household', h);
|
||||
return h;
|
||||
},
|
||||
buildPayload: (state, getters) => {
|
||||
let
|
||||
conc,
|
||||
@@ -180,6 +291,11 @@ const store = createStore({
|
||||
},
|
||||
},
|
||||
mutations: {
|
||||
resetMode(state) {
|
||||
state.mode = null;
|
||||
state.household = null;
|
||||
state.forceLeaveWithoutHousehold = false;
|
||||
},
|
||||
addConcerned(state, person) {
|
||||
let persons = state.concerned.map(conc => conc.person.id);
|
||||
if (!persons.includes(person.id)) {
|
||||
@@ -199,6 +315,10 @@ const store = createStore({
|
||||
position = state.positions.find(pos => pos.id === position_id),
|
||||
conc = state.concerned.find(c => c.person.id === person_id);
|
||||
conc.position = position;
|
||||
// reset position if changed:
|
||||
if (!position.allowHolder && conc.holder) {
|
||||
conc.holder = false;
|
||||
}
|
||||
},
|
||||
setComment(state, {conc, comment}) {
|
||||
conc.comment = comment;
|
||||
@@ -210,9 +330,9 @@ const store = createStore({
|
||||
conc.holder = false;
|
||||
conc.position = null;
|
||||
},
|
||||
removeConcerned(state, conc) {
|
||||
removePerson(state, person) {
|
||||
state.concerned = state.concerned.filter(c =>
|
||||
c.person.id !== conc.person.id
|
||||
c.person.id !== person.id
|
||||
)
|
||||
},
|
||||
createHousehold(state) {
|
||||
@@ -222,6 +342,7 @@ const store = createStore({
|
||||
current_address: null,
|
||||
current_members_id: []
|
||||
};
|
||||
state.mode = "new";
|
||||
state.forceLeaveWithoutHousehold = false;
|
||||
},
|
||||
removeHousehold(state) {
|
||||
@@ -229,12 +350,14 @@ const store = createStore({
|
||||
state.forceLeaveWithoutHousehold = false;
|
||||
},
|
||||
setHouseholdAddress(state, address) {
|
||||
console.log('setHouseholdAddress commit', address);
|
||||
if (null === state.household) {
|
||||
console.error("no household");
|
||||
throw new Error("No household");
|
||||
}
|
||||
|
||||
state.household.current_address = address;
|
||||
state.forceHouseholdNoAddress = false;
|
||||
},
|
||||
removeHouseholdAddress(state, address) {
|
||||
if (null === state.household) {
|
||||
@@ -244,15 +367,20 @@ const store = createStore({
|
||||
|
||||
state.household.current_address = null;
|
||||
},
|
||||
markHouseholdNoAddress(state) {
|
||||
state.forceHouseholdNoAddress = true;
|
||||
},
|
||||
forceLeaveWithoutHousehold(state) {
|
||||
state.household = null;
|
||||
state.mode = "leave";
|
||||
state.forceLeaveWithoutHousehold = true;
|
||||
},
|
||||
selectHousehold(state, household) {
|
||||
state.household = household;
|
||||
state.mode = "existing";
|
||||
state.forceLeaveWithoutHousehold = false;
|
||||
},
|
||||
setHouseholdSuggestionByAccompanyingPeriod(state, households) {
|
||||
addHouseholdSuggestionByAccompanyingPeriod(state, households) {
|
||||
let existingIds = state.householdSuggestionByAccompanyingPeriod
|
||||
.map(h => h.id);
|
||||
for (let i in households) {
|
||||
@@ -307,8 +435,8 @@ const store = createStore({
|
||||
commit('removePosition', conc);
|
||||
dispatch('computeWarnings');
|
||||
},
|
||||
removeConcerned({ commit, dispatch }, conc) {
|
||||
commit('removeConcerned', conc);
|
||||
removePerson({ commit, dispatch }, person) {
|
||||
commit('removePerson', person);
|
||||
dispatch('computeWarnings');
|
||||
dispatch('fetchAddressSuggestions');
|
||||
},
|
||||
@@ -320,18 +448,8 @@ const store = createStore({
|
||||
commit('createHousehold');
|
||||
dispatch('computeWarnings');
|
||||
},
|
||||
setHouseholdNewAddress({ commit }, payload) {
|
||||
let url = `/api/1.0/main/address/${payload.addressId}.json`;
|
||||
window.fetch(url).then(r => {
|
||||
if (r.ok) {
|
||||
return r.json();
|
||||
}
|
||||
throw new Error("error while fetch address");
|
||||
}).then(data => {
|
||||
commit('setHouseholdAddress', data);
|
||||
}).catch(e => {
|
||||
console.error(e);
|
||||
});
|
||||
setHouseholdNewAddress({ commit }, address) {
|
||||
commit('setHouseholdAddress', address);
|
||||
},
|
||||
forceLeaveWithoutHousehold({ commit, dispatch }) {
|
||||
commit('forceLeaveWithoutHousehold');
|
||||
@@ -351,20 +469,33 @@ const store = createStore({
|
||||
fetchHouseholdSuggestionForConcerned({ commit, state }, person) {
|
||||
fetchHouseholdSuggestionByAccompanyingPeriod(person.id)
|
||||
.then(households => {
|
||||
commit('setHouseholdSuggestionByAccompanyingPeriod', households);
|
||||
commit('addHouseholdSuggestionByAccompanyingPeriod', households);
|
||||
});
|
||||
},
|
||||
fetchAddressSuggestions({ commit, state }) {
|
||||
fetchAddressSuggestions({ commit, state, dispatch }) {
|
||||
for (let i in state.concerned) {
|
||||
fetchAddressSuggestionByPerson(state.concerned[i].person.id)
|
||||
.then(addresses => {
|
||||
commit('addAddressesSuggestion', addresses);
|
||||
dispatch('fetchHouseholdSuggestionByAddresses', addresses);
|
||||
})
|
||||
.catch(e => {
|
||||
console.log(e);
|
||||
});
|
||||
}
|
||||
},
|
||||
async fetchHouseholdSuggestionByAddresses({commit}, addresses) {
|
||||
console.log('fetchHouseholdSuggestionByAddresses', addresses);
|
||||
// foreach address, find household suggestions
|
||||
addresses.forEach(async a => {
|
||||
if (a.addressReference !== null) {
|
||||
let households = await fetchHouseholdByAddressReference(a.addressReference);
|
||||
commit('addHouseholdSuggestionByAccompanyingPeriod', households);
|
||||
} else {
|
||||
console.log('not an adresse reference')
|
||||
}
|
||||
});
|
||||
},
|
||||
computeWarnings({ commit, state, getters }) {
|
||||
let warnings = [],
|
||||
payload;
|
||||
|
@@ -27,8 +27,27 @@ const postPerson = (body) => {
|
||||
throw Error('Error with request resource response');
|
||||
});
|
||||
};
|
||||
|
||||
export {
|
||||
getPerson,
|
||||
postPerson
|
||||
|
||||
/*
|
||||
* PATCH an existing person
|
||||
*/
|
||||
const patchPerson = (id, body) => {
|
||||
const url = `/api/1.0/person/person/${id}.json`;
|
||||
return fetch(url, {
|
||||
method: 'PATCH',
|
||||
headers: {
|
||||
'Content-Type': 'application/json;charset=utf-8'
|
||||
},
|
||||
body: JSON.stringify(body)
|
||||
})
|
||||
.then(response => {
|
||||
if (response.ok) { return response.json(); }
|
||||
throw Error('Error with request resource response');
|
||||
});
|
||||
};
|
||||
|
||||
export {
|
||||
getPerson,
|
||||
postPerson,
|
||||
patchPerson
|
||||
};
|
||||
|
@@ -88,10 +88,11 @@
|
||||
|
||||
<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";
|
||||
import { postThirdparty } from "ChillThirdPartyAssets/vuejs/_api/OnTheFly";
|
||||
|
||||
export default {
|
||||
name: 'AddPersons',
|
||||
@@ -229,7 +230,7 @@ export default {
|
||||
return item.result.type + item.result.id;
|
||||
},
|
||||
addPriorSuggestion() {
|
||||
console.log('echo', this.hasPriorSuggestion);
|
||||
//console.log('addPriorSuggestion', this.hasPriorSuggestion);
|
||||
if (this.hasPriorSuggestion) {
|
||||
console.log('addPriorSuggestion',);
|
||||
this.suggested.unshift(this.priorSuggestion);
|
||||
@@ -248,31 +249,31 @@ export default {
|
||||
result: entity
|
||||
}
|
||||
this.search.priorSuggestion = suggestion;
|
||||
console.log('ici', this.search.priorSuggestion);
|
||||
console.log('search priorSuggestion', this.search.priorSuggestion);
|
||||
} else {
|
||||
this.search.priorSuggestion = {};
|
||||
}
|
||||
},
|
||||
saveFormOnTheFly({ type, data }) {
|
||||
console.log('saveFormOnTheFly from addPersons', { type, data });
|
||||
|
||||
// create/edit person
|
||||
console.log('saveFormOnTheFly from addPersons, type', type, ', data', data);
|
||||
if (type === 'person') {
|
||||
|
||||
console.log('type person with', data);
|
||||
postPerson(data)
|
||||
.then(person => new Promise((resolve, reject) => {
|
||||
//this.person = person;
|
||||
console.log('onthefly create: post person', person);
|
||||
this.newPriorSuggestion(person);
|
||||
resolve();
|
||||
}));
|
||||
}
|
||||
|
||||
// create/edit thirdparty
|
||||
else if (type === 'thirdparty') {
|
||||
console.log('not yet implemented: type thirdparty with', type, data);
|
||||
console.log('type thirdparty with', data);
|
||||
postThirdparty(data)
|
||||
.then(thirdparty => new Promise((resolve, reject) => {
|
||||
console.log('onthefly create: post thirdparty', thirdparty);
|
||||
this.newPriorSuggestion(thirdparty);
|
||||
resolve();
|
||||
}));
|
||||
}
|
||||
|
||||
}
|
||||
},
|
||||
}
|
||||
|
@@ -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',
|
||||
|
@@ -1,37 +1,102 @@
|
||||
<template>
|
||||
<div class="container">
|
||||
|
||||
<span class="name">
|
||||
{{ item.result.text }}
|
||||
<div class="container tpartycontainer">
|
||||
<div class="tparty-identification">
|
||||
<span class="name">
|
||||
{{ item.result.text }}
|
||||
</span>
|
||||
<span class="location">
|
||||
<template v-if="hasAddress">
|
||||
{{ getAddress.text }} -
|
||||
{{ getAddress.postcode.name }}
|
||||
</template>
|
||||
</span>
|
||||
</div>
|
||||
<div class="tpartyparent" v-if="hasParent">
|
||||
<span class="name">
|
||||
> {{ item.result.parent.text }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="right_actions">
|
||||
|
||||
<span class="badge bg-thirdparty-child" v-if="item.result.kind == 'child'">
|
||||
{{ $t('thirdparty.child')}}
|
||||
</span>
|
||||
<span class="badge bg-thirdparty-company" v-else-if="item.result.kind == 'company'">
|
||||
{{ $t('thirdparty.company')}}
|
||||
</span>
|
||||
<span class="location">
|
||||
{{ item.result.address.text }} -
|
||||
{{ item.result.address.postcode.name }}
|
||||
<span class="badge bg-thirdparty-contact" v-else="item.result.kind == 'contact'">
|
||||
{{ $t('thirdparty.contact')}}
|
||||
</span>
|
||||
|
||||
</div>
|
||||
<div class="right_actions">
|
||||
|
||||
|
||||
<span class="badge rounded-pill bg-secondary" :title="item.key">
|
||||
{{ $t('item.type_thirdparty') }}
|
||||
</span>
|
||||
|
||||
<on-the-fly
|
||||
type="thirdparty"
|
||||
v-bind:id="item.result.id"
|
||||
action="show">
|
||||
type="thirdparty"
|
||||
v-bind:id="item.result.id"
|
||||
action="show">
|
||||
</on-the-fly>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import OnTheFly from 'ChillMainAssets/vuejs/_components/OnTheFly.vue';
|
||||
import OnTheFly from 'ChillMainAssets/vuejs/OnTheFly/components/OnTheFly.vue';
|
||||
|
||||
const i18n = {
|
||||
messages: {
|
||||
fr: {
|
||||
thirdparty: {
|
||||
contact: "Personne physique",
|
||||
company: "Personne morale",
|
||||
child: "Personne de contact"
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default {
|
||||
name: 'SuggestionThirdParty',
|
||||
components: {
|
||||
OnTheFly
|
||||
},
|
||||
props: ['item']
|
||||
props: ['item'],
|
||||
i18n,
|
||||
computed: {
|
||||
hasAddress() {
|
||||
if (this.$props.item.result.address !== null) {
|
||||
return true;
|
||||
}
|
||||
if (this.$props.item.result.parent !== null) {
|
||||
this.$props.item.result.parent.address !== null;
|
||||
}
|
||||
},
|
||||
hasParent() {
|
||||
return this.$props.item.result.parent !== null;
|
||||
},
|
||||
getAddress() {
|
||||
if (this.$props.item.result.address !== null) {
|
||||
return this.$props.item.result.address;
|
||||
}
|
||||
if (this.$props.item.result.parent.address !== null) {
|
||||
return this.$props.item.result.parent.address;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.tpartycontainer {
|
||||
.tpartyparent {
|
||||
.name {
|
||||
font-weight: bold;
|
||||
font-variant: all-small-caps;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@@ -19,15 +19,18 @@
|
||||
|
||||
<!-- member part -->
|
||||
<li v-if="hasCurrentMembers" class="members" :title="$t('current_members')">
|
||||
<template v-for="m in currentMembers()" :key="m.id">
|
||||
<span v-for="m in currentMembers()" :key="m.id" class="m" :class="{ is_new: m.is_new === true}">
|
||||
<person-render-box render="badge"
|
||||
:person="m.person"
|
||||
:options="{
|
||||
isHolder: m.holder,
|
||||
addLink: true
|
||||
}">
|
||||
<template v-slot:post-badge v-if="m.is_new === true">
|
||||
<span class="post-badge is_new"><i class="fa fa-sign-in"></i></span>
|
||||
</template>
|
||||
</person-render-box>
|
||||
</template>
|
||||
</span>
|
||||
</li>
|
||||
<li v-else class="members" :title="$t('current_members')">
|
||||
<p class="chill-no-data-statement">{{ $t('no_members_yet') }}</p>
|
||||
@@ -82,7 +85,7 @@ export default {
|
||||
return this.household.current_members_id.length > 0;
|
||||
},
|
||||
currentMembers() {
|
||||
return this.household.members.filter(m => this.household.current_members_id.includes(m.id))
|
||||
let members = this.household.members.filter(m => this.household.current_members_id.includes(m.id))
|
||||
.sort((a, b) => {
|
||||
if (a.position.ordering < b.position.ordering) {
|
||||
return -1;
|
||||
@@ -98,6 +101,17 @@ export default {
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
|
||||
if (this.household.new_members !== undefined) {
|
||||
this.household.new_members.map(m => {
|
||||
m.is_new = true;
|
||||
return m;
|
||||
}).forEach(m => {
|
||||
members.push(m);
|
||||
});
|
||||
}
|
||||
|
||||
return members;
|
||||
},
|
||||
currentMembersLength() {
|
||||
return this.household.current_members_id.length;
|
||||
@@ -121,6 +135,13 @@ section.chill-entity {
|
||||
content: '';
|
||||
}
|
||||
|
||||
.members {
|
||||
.post-badge.is_new {
|
||||
margin-left: 0.5rem;
|
||||
color: var(--bs-chill-green);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@@ -27,17 +27,21 @@
|
||||
|
||||
</div>
|
||||
|
||||
<p v-if="options.addInfo == true" class="moreinfo">
|
||||
<i :class="'fa fa-fw ' + getGenderIcon" title="{{ getGender }}"></i>
|
||||
<time v-if="person.birthdate && !person.deathdate" datetime="{{ person.birthdate }}" title="{{ birthdate }}">
|
||||
<p v-if="options.addInfo === true" class="moreinfo">
|
||||
<i :class="'fa fa-fw ' + getGenderIcon" :title="$t(getGender)"></i>
|
||||
|
||||
<time v-if="person.birthdate && !person.deathdate" :datetime="person.birthdate" :title="birthdate">
|
||||
{{ $t(getGenderTranslation) + ' ' + $d(birthdate, 'text') }}
|
||||
</time>
|
||||
<time v-else-if="person.birthdate && person.deathdate" datetime="{{ person.deathdate }}" title="{{ person.deathdate }}">
|
||||
|
||||
<time v-else-if="person.birthdate && person.deathdate" :datetime="person.deathdate" :title="person.deathdate">
|
||||
{{ birthdate }} - {{ deathdate }}
|
||||
</time>
|
||||
<time v-else-if="person.deathdate" datetime="{{ person.deathdate }}" title="{{ person.deathdate }}">
|
||||
|
||||
<time v-else-if="person.deathdate" :datetime="person.deathdate" :title="person.deathdate">
|
||||
{{ $t('renderbox.deathdate') + ' ' + deathdate }}
|
||||
</time>
|
||||
|
||||
<span v-if="options.addAge && person.birthdate" class="age">{{ getAge }} {{ $t('renderbox.years_old')}}</span>
|
||||
</p>
|
||||
</div>
|
||||
@@ -126,6 +130,7 @@
|
||||
</span>
|
||||
{{ person.text }}
|
||||
</span>
|
||||
<slot name="post-badge"></slot>
|
||||
</span>
|
||||
|
||||
</template>
|
||||
@@ -141,9 +146,6 @@ export default {
|
||||
},
|
||||
props: ['person', 'options', 'render', 'returnPath'],
|
||||
computed: {
|
||||
getGenderTranslation: function() {
|
||||
return this.person.gender == 'woman' ? 'renderbox.birthday.woman' : 'renderbox.birthday.man';
|
||||
},
|
||||
isMultiline: function() {
|
||||
if(this.options.isMultiline){
|
||||
return this.options.isMultiline
|
||||
@@ -152,7 +154,13 @@ export default {
|
||||
}
|
||||
},
|
||||
getGenderIcon: function() {
|
||||
return this.person.gender == 'woman' ? 'fa-venus' : this.person.gender == 'man' ? 'fa-mars' : 'fa-neuter';
|
||||
return this.person.gender === 'woman' ? 'fa-venus' : this.person.gender === 'man' ? 'fa-mars' : 'fa-neuter';
|
||||
},
|
||||
getGenderTranslation: function() {
|
||||
return this.person.gender === 'woman' ? 'renderbox.birthday.woman' : 'renderbox.birthday.man';
|
||||
},
|
||||
getGender() {
|
||||
return this.person.gender === 'woman' ? 'person.gender.woman' : this.person.gender === 'man' ? 'person.gender.man' : 'person.gender.neuter';
|
||||
},
|
||||
birthdate: function(){
|
||||
if(this.person.birthdate !== null){
|
||||
|
@@ -40,7 +40,7 @@
|
||||
<option value="man">{{ $t('person.gender.man') }}</option>
|
||||
<option value="neuter">{{ $t('person.gender.neuter') }}</option>
|
||||
</select>
|
||||
<label for="gender">{{ $t('person.gender.title') }}</label>
|
||||
<label>{{ $t('person.gender.title') }}</label>
|
||||
</div>
|
||||
|
||||
<div class="input-group mb-3">
|
||||
@@ -75,7 +75,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getPerson, postPerson } from '../../_api/OnTheFly';
|
||||
import { getPerson } from '../../_api/OnTheFly';
|
||||
import PersonRenderBox from '../Entity/PersonRenderBox.vue';
|
||||
|
||||
export default {
|
||||
@@ -159,7 +159,7 @@ export default {
|
||||
getPerson(this.id)
|
||||
.then(person => new Promise((resolve, reject) => {
|
||||
this.person = person;
|
||||
//console.log('get person', this.person);
|
||||
console.log('get person', this.person);
|
||||
resolve();
|
||||
}));
|
||||
}
|
||||
|
@@ -33,11 +33,11 @@ const personMessages = {
|
||||
gender: {
|
||||
title: "Genre",
|
||||
placeholder: "Choisissez le genre de l'usager",
|
||||
woman: "Femme",
|
||||
man: "Homme",
|
||||
neuter: "Neutre",
|
||||
woman: "Féminin",
|
||||
man: "Masculin",
|
||||
neuter: "Neutre, non binaire",
|
||||
}
|
||||
|
||||
|
||||
},
|
||||
error_only_one_person: "Une seule personne peut être sélectionnée !"
|
||||
}
|
||||
|
@@ -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>
|
||||
|
@@ -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>
|
@@ -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>
|
||||
|
@@ -21,123 +21,70 @@
|
||||
{% 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>
|
||||
|
||||
{% 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>
|
||||
|
||||
{#
|
||||
<h1>{{ 'Resume Accompanying Course'|trans }}</h1>
|
||||
|
||||
<div class="associated-persons mb-5">
|
||||
<h2 class="mb-3">{{ 'Associated peoples'|trans }}</h2>
|
||||
<div class="flex-table mb-3">
|
||||
{% for participation in accompanyingCourse.participations %}
|
||||
{% if participation.enddate is null %}
|
||||
<div class="item-bloc">
|
||||
{{ participation.person|chill_entity_render_box({
|
||||
'render': 'bloc', 'addLink': false, 'addInfo': true, 'addAltNames': false,
|
||||
'customButtons': { 'before': _self.button_person(participation.person) }
|
||||
}) }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
#}
|
||||
{% if 'DRAFT' != accompanyingCourse.step %}
|
||||
{% if withoutHousehold|length > 0 %}
|
||||
{% include '@ChillPerson/AccompanyingCourse/_join_household.html.twig' with {} %}
|
||||
{% 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 %}
|
||||
{#
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="location mb-5">
|
||||
<h2 class="mb-3">{{ 'Accompanying course location'|trans }}</h2>
|
||||
{% 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 %}
|
||||
|
||||
<div class="col-md-6 location mb-5">
|
||||
{% if accompanyingCourse.locationStatus == 'person' %}
|
||||
<p>{{ 'This course is located by'|trans }}
|
||||
<b>{{ accompanyingCourse.personLocation|chill_entity_render_string }}</b>
|
||||
</p>
|
||||
<h2>{{ 'This course is located by'|trans }}</h2>
|
||||
<h4>{{ accompanyingCourse.personLocation|chill_entity_render_string }}</h4>
|
||||
{% elseif accompanyingCourse.locationStatus == 'address' %}
|
||||
<p>{{ 'This course has a temporarily location'|trans }}</p>
|
||||
<h4>{{ 'This course has a temporarily location'|trans }}</h4>
|
||||
{% endif %}
|
||||
|
||||
{% if accompanyingCourse.locationStatus != 'none' %}
|
||||
<div class="flex-table">
|
||||
<div class="item-bloc">
|
||||
{{ accompanyingCourse.location|chill_entity_render_box }}
|
||||
</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">
|
||||
<h2 class="mb-3">{{ 'Requestor'|trans }}</h2>
|
||||
{% if accompanyingCourse.requestorPerson is not empty %}
|
||||
{% set requestor = accompanyingCourse.requestorPerson %}
|
||||
{% set info = true %}
|
||||
{% elseif accompanyingCourse.requestor is not empty %}
|
||||
{% set requestor = accompanyingCourse.requestorThirdParty %}
|
||||
{% set info = false %}
|
||||
{% endif %}
|
||||
{% if accompanyingCourse.requestor == null %}
|
||||
<p class="chill-no-data-statement">{{ 'Any requestor to this accompanying course'|trans }}</p>
|
||||
{% else %}
|
||||
<div class="flex-bloc row row-cols-1 g-0">
|
||||
<div class="item-bloc col">
|
||||
{{ requestor|chill_entity_render_box({
|
||||
'render': 'bloc', 'addLink': false, 'addEntity': true, 'addInfo': info, 'addAltNames': false
|
||||
}) }}
|
||||
</div>
|
||||
</div>
|
||||
{{ accompanyingCourse.location|chill_entity_render_box }}
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="resources mb-5">
|
||||
<h2 class="mb-3">{{ 'Resources'|trans }}</h2>
|
||||
{% if accompanyingCourse.resources|length == 0 %}
|
||||
<p class="chill-no-data-statement">{{ 'Any resource for this accompanying course'|trans }}</p>
|
||||
{% else %}
|
||||
<div class="flex-bloc row row-cols-1 row-cols-sm-2 row-cols-xl-3 row-cols-xxl-4 g-0">
|
||||
{% for r in accompanyingCourse.resources %}
|
||||
<div class="item-bloc col">
|
||||
{% if r.person %}
|
||||
{{ r.person|chill_entity_render_box({
|
||||
'render': 'bloc', 'addLink': false, 'addEntity': true, 'addInfo': true, 'addAltNames': false
|
||||
}) }}
|
||||
{% endif %}
|
||||
{% if r.thirdParty %}
|
||||
{{ r.thirdParty|chill_entity_render_box({
|
||||
'render': 'bloc', 'addLink': false, 'addEntity': true, 'addInfo': false
|
||||
}) }}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
#}
|
||||
<div class="mt-5"></div>
|
||||
|
||||
<div class="social-actions mb-5">
|
||||
<h2 class="mb-3">{{ 'Social actions'|trans }}</h2>
|
||||
{% include 'ChillPersonBundle:AccompanyingCourseWork:list_by_accompanying_period.html.twig' with {'buttonText': false } %}
|
||||
<h2 class="mb-3">{{ 'Last social actions'|trans }}</h2>
|
||||
{% include 'ChillPersonBundle:AccompanyingCourseWork:list_recent_by_accompanying_period.html.twig' with {'buttonText': false } %}
|
||||
</div>
|
||||
|
||||
{% block contentActivity %}
|
||||
@@ -154,9 +101,9 @@
|
||||
{% set accompanying_course_id = accompanyingCourse.id %}
|
||||
{% endif %}
|
||||
|
||||
<h2>{{ 'Activity list' |trans }}</h2>
|
||||
<h2 class="mb-3">{{ 'Last activities' |trans }}</h2>
|
||||
|
||||
{% include 'ChillActivityBundle:Activity:list.html.twig' with { 'context': 'accompanyingCourse', 'no_action': true } %}
|
||||
{% include 'ChillActivityBundle:Activity:list_recent.html.twig' with { 'context': 'accompanyingCourse', 'no_action': true } %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
|
@@ -10,7 +10,7 @@
|
||||
<div class="item-bloc">
|
||||
<div class="item-row">
|
||||
|
||||
<h2 class="title">
|
||||
<h2 class="badge-title">
|
||||
<span class="title_label">{{ 'accompanying_course_work.action'|trans }}</span>
|
||||
<span class="title_action">{{ w.socialAction|chill_entity_render_string }}</span>
|
||||
</h2>
|
||||
|
@@ -0,0 +1,32 @@
|
||||
{% if works|length == 0 %}
|
||||
<p class="chill-no-data-statement">{{ 'accompanying_course_work.Any work'|trans }}
|
||||
<a class="btn btn-sm btn-create"
|
||||
href="" title="TODO"></a>{# TODO link #}
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
<div class="accompanying_course_work-list">
|
||||
{% for w in works | slice(0,5) %}
|
||||
<a href="{{ chill_path_add_return_path('chill_person_accompanying_period_work_edit', { 'id': w.id }) }}"></a>
|
||||
|
||||
<h2 class="badge-title">
|
||||
<span class="title_label">{{ 'accompanying_course_work.action'|trans }}</span>
|
||||
<span class="title_action">{{ w.socialAction|chill_entity_render_string }}
|
||||
|
||||
<ul class="small_in_title">
|
||||
<li>
|
||||
<abbr title="{{ 'accompanying_course_work.start_date'|trans }}">{{ 'accompanying_course_work.start_date'|trans ~ ' : ' }}</abbr>
|
||||
{{ w.startDate|format_date('short') }}
|
||||
</li>
|
||||
<li>
|
||||
<abbr title="{{ 'Last updated by'|trans }}">{{ 'Last updated by'|trans ~ ' : ' }}</abbr>
|
||||
{{ w.updatedBy|chill_entity_render_box }}, {{ w.updatedAt|format_datetime('short', 'short') }}
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</span>
|
||||
</h2>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
|
@@ -58,11 +58,10 @@
|
||||
|
||||
</div>
|
||||
<div class="item-row separator">
|
||||
|
||||
<div class="wrap-list">
|
||||
{% if accompanying_period.requestorPerson is not null or accompanying_period.requestorThirdParty is not null %}
|
||||
<div class="wl-row">
|
||||
<div class="wl-col title"><h3>{{ 'Requestor'|trans }}</h3></div>
|
||||
<div class="wl-col title"><h3>{{ 'Requestor'|trans({'gender': null }) }}</h3></div>
|
||||
<div class="wl-col list">
|
||||
{% if accompanying_period.requestorPerson is not null %}
|
||||
<span class="wl-item badge-person">{{ accompanying_period.requestorPerson|chill_entity_render_string }}</span>
|
||||
|
@@ -0,0 +1,27 @@
|
||||
{% extends '@ChillPerson/Household/layout.html.twig' %}
|
||||
|
||||
{% block title 'household.Relationship'|trans %}
|
||||
|
||||
{% block content %}
|
||||
<h1>{{ block('title') }}</h1>
|
||||
<div id="graph-relationship"></div>
|
||||
|
||||
{% for m in household.members %}
|
||||
{% if m.endDate is null %}
|
||||
{{ dump(m) }}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block js %}
|
||||
{{ parent() }}
|
||||
{{ encore_entry_script_tags('page_vis') }}
|
||||
{% endblock %}
|
||||
|
||||
{% block css %}
|
||||
{{ parent() }}
|
||||
{{ encore_entry_link_tags('page_vis') }}
|
||||
{% endblock %}
|
||||
|
||||
{% block block_post_menu %}{% endblock %}
|
@@ -32,7 +32,7 @@
|
||||
{% include '@ChillMain/Address/_insert_vue_address.html.twig' with {
|
||||
targetEntity: { name: 'household', id: household.id },
|
||||
backUrl: path('chill_person_household_summary', { 'household_id': household.id }),
|
||||
hideAddress: true,
|
||||
onlyButton: true,
|
||||
mode: 'new',
|
||||
buttonSize: 'btn-sm',
|
||||
buttonText: 'Move household',
|
||||
@@ -48,7 +48,6 @@
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
{% if address is not empty %}
|
||||
<div class="item-bloc col-7 col-comment">
|
||||
{% if form is null %}
|
||||
|
||||
@@ -95,16 +94,14 @@
|
||||
</div>
|
||||
<ul class="record_actions">
|
||||
<li>
|
||||
<button type="submit" class="btn btn-save">
|
||||
<button type="submit" class="btn btn-save" id="form_household_comment_confirm">
|
||||
{{ 'Save'|trans }}
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
{{ form_end(form) }}
|
||||
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<h2 class="my-5">{{ 'household.Household members'|trans }}</h2>
|
||||
|
@@ -17,11 +17,19 @@
|
||||
{%- endif -%}
|
||||
</div>
|
||||
<div class="text-md-end">
|
||||
{% if person|chill_resolve_center is not null%}
|
||||
{% if person|chill_resolve_center is not null %}
|
||||
<span class="open_sansbold">
|
||||
{{ 'Center'|trans|upper}} :
|
||||
</span>
|
||||
{{ person|chill_resolve_center.name|upper }}
|
||||
|
||||
{% if person|chill_resolve_center is iterable %}
|
||||
{% for c in person|chill_resolve_center %}
|
||||
{{ c.name|upper }}{% if not loop.last %}, {% endif %}
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
{{ person|chill_resolve_center.name|upper }}
|
||||
{% endif %}
|
||||
|
||||
{%- endif -%}
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -61,7 +61,7 @@
|
||||
</table>
|
||||
{% endif %}
|
||||
|
||||
{{ form_start(form) }}
|
||||
{{ form_start(form, {'attr' : {'id' : 'create-form'}}) }}
|
||||
|
||||
|
||||
{{ form_row(form.lastName, { 'label' : 'Last name'|trans }) }}
|
||||
@@ -104,3 +104,7 @@
|
||||
|
||||
</div>
|
||||
{% endblock content %}
|
||||
|
||||
{% block js %}
|
||||
{{ encore_entry_script_tags('mod_disablebuttons') }}
|
||||
{% endblock js %}
|
||||
|
@@ -18,12 +18,12 @@
|
||||
|
||||
{% set activeRouteKey = '' %}
|
||||
|
||||
{% block title %}{{ 'Update details for %name%'|trans({ '%name%': person.firstName|capitalize ~ ' ' ~ person.lastName } )|capitalize }}{% endblock %}
|
||||
{% block title %}{{ 'Update details for %name%'|trans({ '%name%': person|chill_entity_render_string } ) }}{% endblock %}
|
||||
|
||||
{% block personcontent %}
|
||||
<div class="person-edit">
|
||||
|
||||
<h1>{{ 'Update details for %name%'|trans({ '%name%': person.firstName|capitalize ~ ' ' ~ person.lastName|capitalize } ) }}</h1>
|
||||
<h1>{{ block('title') }}</h1>
|
||||
|
||||
{% form_theme form '@ChillMain/Form/fields.html.twig' %}
|
||||
{{ form_start(form) }}
|
||||
|
@@ -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>
|
||||
|
@@ -23,8 +23,7 @@ This view should receive those arguments:
|
||||
- person
|
||||
#}
|
||||
|
||||
{% block title %}{{ 'Person details'|trans|capitalize ~ ' ' ~ person.firstName|capitalize ~
|
||||
' ' ~ person.lastName }}{% endblock %}
|
||||
{% block title %}{{ 'Person details'|trans|capitalize ~ ' ' ~ person|chill_entity_render_string }}{% endblock %}
|
||||
{#
|
||||
we define variables to include an edit form repeated multiple time across
|
||||
the page
|
||||
|
@@ -26,7 +26,7 @@ class SearchPersonApiProvider implements SearchApiInterface
|
||||
"(person.fullnamecanonical LIKE '%' || LOWER(UNACCENT(?)) || '%')::int".
|
||||
")", [ $pattern, $pattern ])
|
||||
->setFromClause("chill_person_person AS person")
|
||||
->setWhereClause("LOWER(UNACCENT(?)) <<% person.fullnamecanonical OR ".
|
||||
->setWhereClauses("LOWER(UNACCENT(?)) <<% person.fullnamecanonical OR ".
|
||||
"person.fullnamecanonical LIKE '%' || LOWER(UNACCENT(?)) || '%' ", [ $pattern, $pattern ])
|
||||
;
|
||||
|
||||
|
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace Chill\PersonBundle\Security\Authorization;
|
||||
|
||||
class HouseholdVoter
|
||||
{
|
||||
const SHOW = PersonVoter::SEE;
|
||||
}
|
@@ -2,9 +2,14 @@
|
||||
|
||||
namespace Chill\PersonBundle\Tests\Controller;
|
||||
|
||||
use Chill\MainBundle\Entity\Address;
|
||||
use Chill\MainBundle\Entity\AddressReference;
|
||||
use Chill\MainBundle\Entity\Center;
|
||||
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||
use Chill\MainBundle\Test\PrepareClientTrait;
|
||||
use Chill\PersonBundle\Entity\Household\Household;
|
||||
use Chill\PersonBundle\Entity\Household\HouseholdMember;
|
||||
use Chill\PersonBundle\Entity\Person;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||
@@ -15,6 +20,8 @@ class HouseholdApiControllerTest extends WebTestCase
|
||||
|
||||
use PrepareClientTrait;
|
||||
|
||||
private array $toDelete = [];
|
||||
|
||||
/**
|
||||
* @dataProvider generatePersonId
|
||||
*/
|
||||
@@ -45,6 +52,77 @@ class HouseholdApiControllerTest extends WebTestCase
|
||||
$this->assertResponseIsSuccessful();
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider generateHouseholdAssociatedWithAddressReference
|
||||
*/
|
||||
public function testFindHouseholdByAddressReference(int $addressReferenceId, int $expectedHouseholdId)
|
||||
{
|
||||
$client = $this->getClientAuthenticated();
|
||||
|
||||
$client->request(
|
||||
Request::METHOD_GET,
|
||||
"/api/1.0/person/household/by-address-reference/$addressReferenceId.json"
|
||||
);
|
||||
|
||||
$this->assertResponseIsSuccessful();
|
||||
$data = json_decode($client->getResponse()->getContent(), true);
|
||||
$this->assertArrayHasKey('count', $data);
|
||||
$this->assertArrayHasKey('results', $data);
|
||||
|
||||
$householdIds = \array_map(function($r) {
|
||||
return $r['id'];
|
||||
}, $data['results']);
|
||||
|
||||
$this->assertContains($expectedHouseholdId, $householdIds);
|
||||
}
|
||||
|
||||
public function generateHouseholdAssociatedWithAddressReference()
|
||||
{
|
||||
self::bootKernel();
|
||||
$em = self::$container->get(EntityManagerInterface::class);
|
||||
$centerA = $em->getRepository(Center::class)->findOneBy(['name' => 'Center A']);
|
||||
$nbReference = $em->createQueryBuilder()->select('count(ar)')->from(AddressReference::class, 'ar')
|
||||
->getQuery()->getSingleScalarResult();
|
||||
$reference = $em->createQueryBuilder()->select('ar')->from(AddressReference::class, 'ar')
|
||||
->setFirstResult(\random_int(0, $nbReference))
|
||||
->setMaxResults(1)
|
||||
->getQuery()->getSingleResult();
|
||||
$p = new Person();
|
||||
$p->setFirstname('test')->setLastName('test lastname')
|
||||
->setGender(Person::BOTH_GENDER)
|
||||
->setCenter($centerA)
|
||||
;
|
||||
$em->persist($p);
|
||||
$h = new Household();
|
||||
$h->addMember($m = (new HouseholdMember())->setPerson($p));
|
||||
$h->addAddress(Address::createFromAddressReference($reference)->setValidFrom(new \DateTime('today')));
|
||||
$em->persist($m);
|
||||
$em->persist($h);
|
||||
|
||||
$em->flush();
|
||||
|
||||
$this->toDelete = $this->toDelete + [
|
||||
[HouseholdMember::class, $m->getId()],
|
||||
[User::class, $p->getId()],
|
||||
[Household::class, $h->getId()]
|
||||
];
|
||||
|
||||
yield [$reference->getId(), $h->getId()];
|
||||
}
|
||||
|
||||
protected function tearDown()
|
||||
{
|
||||
self::bootKernel();
|
||||
$em = self::$container->get(EntityManagerInterface::class);
|
||||
|
||||
foreach ($this->toDelete as list($class, $id)) {
|
||||
$obj = $em->getRepository($class)->find($id);
|
||||
$em->remove($obj);
|
||||
}
|
||||
|
||||
$em->flush();
|
||||
}
|
||||
|
||||
public function generatePersonId()
|
||||
{
|
||||
self::bootKernel();
|
||||
@@ -64,7 +142,7 @@ class HouseholdApiControllerTest extends WebTestCase
|
||||
;
|
||||
|
||||
$person = $period->getParticipations()
|
||||
->first()->getPerson();
|
||||
->first()->getPerson();
|
||||
|
||||
yield [ $person->getId() ];
|
||||
}
|
||||
|
@@ -18,7 +18,7 @@ class HouseholdControllerTest extends WebTestCase
|
||||
protected function setUp()
|
||||
{
|
||||
$this->client = $this->getClientAuthenticated();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider generateValidHouseholdIds
|
||||
@@ -49,7 +49,7 @@ class HouseholdControllerTest extends WebTestCase
|
||||
|
||||
$this->assertResponseIsSuccessful();
|
||||
|
||||
$form = $crawler->selectButton('Enregistrer')
|
||||
$form = $crawler->filter('#form_household_comment_confirm')
|
||||
->form();
|
||||
|
||||
$form['household[commentMembers][comment]'] = "This is a text **generated** by automatic tests";
|
||||
@@ -109,8 +109,8 @@ class HouseholdControllerTest extends WebTestCase
|
||||
|
||||
\shuffle($ids);
|
||||
|
||||
yield [ \array_pop($ids)['id'] ];
|
||||
yield [ \array_pop($ids)['id'] ];
|
||||
yield [ \array_pop($ids)['id'] ];
|
||||
yield [ \array_pop($ids)['id'] ];
|
||||
yield [ \array_pop($ids)['id'] ];
|
||||
yield [ \array_pop($ids)['id'] ];
|
||||
}
|
||||
}
|
||||
|
@@ -177,9 +177,11 @@ class PersonControllerCreateTest extends WebTestCase
|
||||
$this->assertTrue($form->has(self::CENTER_INPUT),
|
||||
'The page contains a "center" input');
|
||||
$centerInput = $form->get(self::CENTER_INPUT);
|
||||
/*
|
||||
$availableValues = $centerInput->availableOptionValues();
|
||||
$lastCenterInputValue = end($availableValues);
|
||||
$centerInput->setValue($lastCenterInputValue);
|
||||
*/
|
||||
|
||||
$client->submit($form);
|
||||
|
||||
@@ -205,7 +207,7 @@ class PersonControllerCreateTest extends WebTestCase
|
||||
$form = $this->fillAValidCreationForm($form, 'Charline', 'dd');
|
||||
$client->submit($form);
|
||||
|
||||
$this->assertContains('Depardieu', $client->getCrawler()->text(),
|
||||
$this->assertContains('DEPARDIEU', $client->getCrawler()->text(),
|
||||
"check that the page has detected the lastname of a person existing in database");
|
||||
|
||||
//inversion
|
||||
@@ -213,7 +215,7 @@ class PersonControllerCreateTest extends WebTestCase
|
||||
$form = $this->fillAValidCreationForm($form, 'dd', 'Charline');
|
||||
$client->submit($form);
|
||||
|
||||
$this->assertContains('Depardieu', $client->getCrawler()->text(),
|
||||
$this->assertContains('DEPARDIEU', $client->getCrawler()->text(),
|
||||
"check that the page has detected the lastname of a person existing in database");
|
||||
}
|
||||
|
||||
|
@@ -30,38 +30,38 @@ class PersonControllerViewTest extends WebTestCase
|
||||
{
|
||||
/** @var \Doctrine\ORM\EntityManagerInterface The entity manager */
|
||||
private $em;
|
||||
|
||||
|
||||
/** @var Person A person used on which to run the test */
|
||||
private $person;
|
||||
|
||||
/** @var String The url to view the person details */
|
||||
private $viewUrl;
|
||||
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
static::bootKernel();
|
||||
|
||||
|
||||
$this->em = static::$kernel->getContainer()
|
||||
->get('doctrine.orm.entity_manager');
|
||||
|
||||
|
||||
$center = $this->em->getRepository('ChillMainBundle:Center')
|
||||
->findOneBy(array('name' => 'Center A'));
|
||||
|
||||
|
||||
$this->person = (new Person())
|
||||
->setLastName("Tested Person")
|
||||
->setFirstName("Réginald")
|
||||
->setCenter($center)
|
||||
->setGender(Person::MALE_GENDER);
|
||||
|
||||
|
||||
$this->em->persist($this->person);
|
||||
$this->em->flush();
|
||||
|
||||
|
||||
$this->viewUrl = '/en/person/'.$this->person->getId().'/general';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test if the view page is accessible
|
||||
*
|
||||
*
|
||||
* @group configurable_fields
|
||||
*/
|
||||
public function testViewPerson()
|
||||
@@ -70,20 +70,20 @@ class PersonControllerViewTest extends WebTestCase
|
||||
'PHP_AUTH_USER' => 'center a_social',
|
||||
'PHP_AUTH_PW' => 'password',
|
||||
));
|
||||
|
||||
|
||||
$crawler = $client->request('GET', $this->viewUrl);
|
||||
$response = $client->getResponse();
|
||||
|
||||
$this->assertTrue($response->isSuccessful());
|
||||
|
||||
$this->assertGreaterThan(0, $crawler->filter('html:contains("Tested Person")')->count());
|
||||
$this->assertGreaterThan(0, $crawler->filter('html:contains("TESTED PERSON")')->count());
|
||||
$this->assertGreaterThan(0, $crawler->filter('html:contains("Réginald")')->count());
|
||||
$this->assertContains('Email addresses', $crawler->text());
|
||||
$this->assertContains('Phonenumber', $crawler->text());
|
||||
$this->assertContains('Langues parlées', $crawler->text());
|
||||
$this->assertContains(/* Etat */ 'civil', $crawler->text());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test if the view page of a given person is not accessible for a user
|
||||
* of another center of the person
|
||||
@@ -94,26 +94,26 @@ class PersonControllerViewTest extends WebTestCase
|
||||
'PHP_AUTH_USER' => 'center b_social',
|
||||
'PHP_AUTH_PW' => 'password',
|
||||
));
|
||||
|
||||
|
||||
$client->request('GET', $this->viewUrl);
|
||||
$this->assertEquals(403, $client->getResponse()->getStatusCode(),
|
||||
"The view page of a person of a center A must not be accessible for user of center B");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reload the person from the db
|
||||
*/
|
||||
protected function refreshPerson()
|
||||
protected function refreshPerson()
|
||||
{
|
||||
$this->person = $this->em->getRepository('ChillPersonBundle:Person')
|
||||
->find($this->person->getId());
|
||||
}
|
||||
|
||||
|
||||
public function tearDown()
|
||||
{
|
||||
$this->refreshPerson();
|
||||
$this->em->remove($this->person);
|
||||
$this->em->flush();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Chill\PersonBundle\EventListener\PersonEventListener;
|
||||
use Chill\PersonBundle\Entity\Person;
|
||||
use Chill\PersonBundle\Entity\PersonAltName;
|
||||
use Doctrine\Persistence\Event\LifecycleEventArgs;
|
||||
|
||||
class PersonCreateEventTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider generateNames
|
||||
*/
|
||||
public function testOnPrePersist($firstname, $firstnameExpected, $lastname, $lastnameExpected)
|
||||
{
|
||||
$listener = new PersonEventListener();
|
||||
|
||||
$person = new Person();
|
||||
|
||||
$person->setFirstName($firstname);
|
||||
$person->setLastName($lastname);
|
||||
|
||||
$listener->prePersistPerson($person);
|
||||
|
||||
$this->assertEquals($firstnameExpected, $person->getFirstName());
|
||||
$this->assertEquals($lastnameExpected, $person->getLastName());
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider generateAltNames
|
||||
*/
|
||||
public function testAltNamesOnPrePersist($altname, $altnameExpected)
|
||||
{
|
||||
$listener = new PersonEventListener();
|
||||
|
||||
$personAltname = new PersonAltName();
|
||||
|
||||
$personAltname->setLabel($altname);
|
||||
|
||||
$listener->prePersistAltName($personAltname);
|
||||
|
||||
$this->assertEquals($altnameExpected, $personAltname->getLabel());
|
||||
}
|
||||
|
||||
public function generateNames(): iterator
|
||||
{
|
||||
yield ['émelie-marie', 'Émelie-Marie', 'lenaerts', 'LENAERTS'];
|
||||
yield ['jean-marie', 'Jean-Marie', 'lenaerts', 'LENAERTS'];
|
||||
yield ['vinCENT', 'Vincent', 'fastré', 'FASTRÉ'];
|
||||
yield ['Vincent', 'Vincent', 'van Gogh', 'VAN GOGH'];
|
||||
yield ['André marie', 'André Marie', 'Bah', 'BAH'];
|
||||
}
|
||||
|
||||
public function generateAltNames(): iterator
|
||||
{
|
||||
yield ['vinCENT', 'VINCENT'];
|
||||
yield ['jean-marie', 'JEAN-MARIE'];
|
||||
yield ['fastré', 'FASTRÉ'];
|
||||
yield ['émile', 'ÉMILE'];
|
||||
}
|
||||
}
|
@@ -26,7 +26,6 @@ use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||
/**
|
||||
* Test Person search
|
||||
*
|
||||
* @author Julien Fastré <julien.fastre@champs-libres.coop>
|
||||
*/
|
||||
class PersonSearchTest extends WebTestCase
|
||||
{
|
||||
@@ -38,7 +37,7 @@ class PersonSearchTest extends WebTestCase
|
||||
'q' => '@person Depardieu'
|
||||
));
|
||||
|
||||
$this->assertRegExp('/Depardieu/', $crawler->filter('.list-with-period')->text());
|
||||
$this->assertRegExp('/DEPARDIEU/', $crawler->filter('.list-with-period')->text());
|
||||
}
|
||||
|
||||
public function testExpectedNamed()
|
||||
@@ -49,61 +48,61 @@ class PersonSearchTest extends WebTestCase
|
||||
'q' => '@person Depardieu', 'name' => 'person_regular'
|
||||
));
|
||||
|
||||
$this->assertRegExp('/Depardieu/', $crawler->filter('.list-with-period')->text());
|
||||
$this->assertRegExp('/DEPARDIEU/', $crawler->filter('.list-with-period')->text());
|
||||
}
|
||||
|
||||
public function testSearchByLastName()
|
||||
{
|
||||
$crawler = $this->generateCrawlerForSearch('@person lastname:Depardieu');
|
||||
|
||||
$this->assertRegExp('/Depardieu/', $crawler->filter('.list-with-period')->text());
|
||||
$this->assertRegExp('/DEPARDIEU/', $crawler->filter('.list-with-period')->text());
|
||||
}
|
||||
|
||||
public function testSearchByFirstNameLower()
|
||||
{
|
||||
$crawler = $this->generateCrawlerForSearch('@person firstname:Gérard');
|
||||
|
||||
$this->assertRegExp('/Depardieu/', $crawler->filter('.list-with-period')->text());
|
||||
$this->assertRegExp('/DEPARDIEU/', $crawler->filter('.list-with-period')->text());
|
||||
}
|
||||
|
||||
public function testSearchByFirstNamePartim()
|
||||
{
|
||||
$crawler = $this->generateCrawlerForSearch('@person firstname:Ger');
|
||||
|
||||
$this->assertRegExp('/Depardieu/', $crawler->filter('.list-with-period')->text());
|
||||
$this->assertRegExp('/DEPARDIEU/', $crawler->filter('.list-with-period')->text());
|
||||
}
|
||||
|
||||
public function testLastNameAccentued()
|
||||
{
|
||||
$crawlerSpecial = $this->generateCrawlerForSearch('@person lastname:manço');
|
||||
|
||||
$this->assertRegExp('/Manço/', $crawlerSpecial->filter('.list-with-period')->text());
|
||||
$this->assertRegExp('/MANÇO/', $crawlerSpecial->filter('.list-with-period')->text());
|
||||
|
||||
|
||||
$crawlerNoSpecial = $this->generateCrawlerForSearch('@person lastname:manco');
|
||||
|
||||
$this->assertRegExp('/Manço/', $crawlerNoSpecial->filter('.list-with-period')->text());
|
||||
$this->assertRegExp('/MANÇO/', $crawlerNoSpecial->filter('.list-with-period')->text());
|
||||
}
|
||||
|
||||
public function testSearchByFirstName()
|
||||
{
|
||||
$crawler = $this->generateCrawlerForSearch('@person firstname:Jean');
|
||||
|
||||
$this->assertRegExp('/Depardieu/', $crawler->filter('.list-with-period')->text());
|
||||
$this->assertRegExp('/DEPARDIEU/', $crawler->filter('.list-with-period')->text());
|
||||
}
|
||||
|
||||
public function testSearchByFirstNameLower2()
|
||||
{
|
||||
$crawler = $this->generateCrawlerForSearch('@person firstname:jean');
|
||||
|
||||
$this->assertRegExp('/Depardieu/', $crawler->filter('.list-with-period')->text());
|
||||
$this->assertRegExp('/DEPARDIEU/', $crawler->filter('.list-with-period')->text());
|
||||
}
|
||||
|
||||
public function testSearchByFirstNamePartim2()
|
||||
{
|
||||
$crawler = $this->generateCrawlerForSearch('@person firstname:ean');
|
||||
|
||||
$this->assertRegExp('/Depardieu/', $crawler->filter('.list-with-period')->text());
|
||||
$this->assertRegExp('/DEPARDIEU/', $crawler->filter('.list-with-period')->text());
|
||||
}
|
||||
|
||||
public function testSearchByFirstNameAccented()
|
||||
@@ -154,7 +153,7 @@ class PersonSearchTest extends WebTestCase
|
||||
$crawler = $this->generateCrawlerForSearch('@person birthdate:1948-12-27 lastname:(Van Snick)');
|
||||
|
||||
$this->assertRegExp('/Bart/', $crawler->filter('.list-with-period')->text());
|
||||
$this->assertNotRegExp('/Depardieu/', $crawler->filter('.list-with-period')->text());
|
||||
$this->assertNotRegExp('/DEPARDIEU/', $crawler->filter('.list-with-period')->text());
|
||||
}
|
||||
|
||||
public function testSearchCombineGenderAndLastName()
|
||||
@@ -181,12 +180,12 @@ class PersonSearchTest extends WebTestCase
|
||||
$this->markTestSkipped("skipped until adapted to new fixtures");
|
||||
$crawlerSpecial = $this->generateCrawlerForSearch('@person manço');
|
||||
|
||||
$this->assertRegExp('/Manço/', $crawlerSpecial->filter('.list-with-period')->text());
|
||||
$this->assertRegExp('/MANÇO/', $crawlerSpecial->filter('.list-with-period')->text());
|
||||
|
||||
|
||||
$crawlerNoSpecial = $this->generateCrawlerForSearch('@person manco');
|
||||
|
||||
$this->assertRegExp('/Manço/', $crawlerNoSpecial->filter('.list-with-period')->text());
|
||||
$this->assertRegExp('/MANÇO/', $crawlerNoSpecial->filter('.list-with-period')->text());
|
||||
|
||||
$crawlerSpecial = $this->generateCrawlerForSearch('@person Étienne');
|
||||
|
||||
@@ -206,10 +205,10 @@ class PersonSearchTest extends WebTestCase
|
||||
$crawlerCanSee = $this->generateCrawlerForSearch('Gérard', 'center a_social');
|
||||
$crawlerCannotSee = $this->generateCrawlerForSearch('Gérard', 'center b_social');
|
||||
|
||||
$this->assertRegExp('/Depardieu/', $crawlerCanSee->text(),
|
||||
$this->assertRegExp('/DEPARDIEU/', $crawlerCanSee->text(),
|
||||
'center a_social may see "Depardieu" in center a');
|
||||
$this->assertNotRegExp('/Depardieu/', $crawlerCannotSee->text(),
|
||||
'center b_social may see "Depardieu" in center b');
|
||||
$this->assertNotRegExp('/DEPARDIEU/', $crawlerCannotSee->text(),
|
||||
'center b_social may not see "Depardieu" in center b');
|
||||
|
||||
}
|
||||
|
||||
|
@@ -298,6 +298,35 @@ paths:
|
||||
$ref: "#/components/schemas/Person"
|
||||
403:
|
||||
description: "Unauthorized"
|
||||
patch:
|
||||
tags:
|
||||
- person
|
||||
summary: "Alter a person"
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
required: true
|
||||
description: The person's id
|
||||
schema:
|
||||
type: integer
|
||||
format: integer
|
||||
minimum: 1
|
||||
requestBody:
|
||||
description: "A person"
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Person"
|
||||
responses:
|
||||
401:
|
||||
description: "Unauthorized"
|
||||
404:
|
||||
description: "Not found"
|
||||
200:
|
||||
description: "OK"
|
||||
422:
|
||||
description: "Object with validation errors"
|
||||
|
||||
/1.0/person/person.json:
|
||||
post:
|
||||
@@ -1098,6 +1127,32 @@ paths:
|
||||
401:
|
||||
description: "Unauthorized"
|
||||
|
||||
/1.0/person/household/by-address-reference/{address_id}.json:
|
||||
get:
|
||||
tags:
|
||||
- household
|
||||
summary: Return a list of household which are sharing the same address reference
|
||||
parameters:
|
||||
- name: address_id
|
||||
in: path
|
||||
required: true
|
||||
description: the address reference id
|
||||
schema:
|
||||
type: integer
|
||||
format: integer
|
||||
minimum: 1
|
||||
responses:
|
||||
200:
|
||||
description: "ok"
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Household"
|
||||
404:
|
||||
description: "not found"
|
||||
401:
|
||||
description: "Unauthorized"
|
||||
|
||||
/1.0/person/household/suggest/by-person/{person_id}/through-accompanying-period-participation.json:
|
||||
get:
|
||||
tags:
|
||||
|
@@ -8,7 +8,6 @@ module.exports = function(encore, entries)
|
||||
ChillPersonAssets: __dirname + '/Resources/public'
|
||||
});
|
||||
|
||||
|
||||
encore.addEntry('vue_household_members_editor', __dirname + '/Resources/public/vuejs/HouseholdMembersEditor/index.js');
|
||||
encore.addEntry('vue_accourse', __dirname + '/Resources/public/vuejs/AccompanyingCourse/index.js');
|
||||
encore.addEntry('vue_accourse_work_create', __dirname + '/Resources/public/vuejs/AccompanyingCourseWorkCreate/index.js');
|
||||
@@ -17,4 +16,5 @@ module.exports = function(encore, entries)
|
||||
encore.addEntry('page_household_edit_metadata', __dirname + '/Resources/public/page/household_edit_metadata/index.js');
|
||||
encore.addEntry('page_person', __dirname + '/Resources/public/page/person/index.js');
|
||||
encore.addEntry('page_accompanying_course_index_person_locate', __dirname + '/Resources/public/page/accompanying_course_index/person_locate.js');
|
||||
encore.addEntry('page_vis', __dirname + '/Resources/public/page/vis/index.js');
|
||||
};
|
||||
|
@@ -0,0 +1,14 @@
|
||||
services:
|
||||
Chill\PersonBundle\EventListener\PersonEventListener:
|
||||
autoconfigure: true
|
||||
tags:
|
||||
-
|
||||
name: 'doctrine.orm.entity_listener'
|
||||
event: 'prePersist'
|
||||
entity: 'Chill\PersonBundle\Entity\Person'
|
||||
method: 'prePersistPerson'
|
||||
-
|
||||
name: 'doctrine.orm.entity_listener'
|
||||
event: 'prePersist'
|
||||
entity: 'Chill\PersonBundle\Entity\PersonAltName'
|
||||
method: 'prePersistAltName'
|
@@ -10,3 +10,5 @@ services:
|
||||
Chill\PersonBundle\Repository\PersonACLAwareRepositoryInterface: '@Chill\PersonBundle\Repository\PersonACLAwareRepository'
|
||||
|
||||
Chill\PersonBundle\Repository\AccompanyingPeriodACLAwareRepositoryInterface: '@Chill\PersonBundle\Repository\AccompanyingPeriodACLAwareRepository'
|
||||
|
||||
Chill\PersonBundle\Repository\Household\HouseholdACLAwareRepositoryInterface: '@Chill\PersonBundle\Repository\Household\HouseholdACLAwareRepository'
|
||||
|
@@ -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}
|
||||
@@ -44,6 +51,8 @@ household:
|
||||
Household summary: Résumé du ménage
|
||||
Accompanying period: Parcours d'accompagnement
|
||||
Addresses: Historique adresse
|
||||
Relationship: Composition familiale
|
||||
Household relationships: Composition du ménage
|
||||
Current address: Adresse actuelle
|
||||
Household does not have any address currently: Le ménage n'a pas d'adresse renseignée actuellement
|
||||
Edit household members: Modifier l'appartenance au ménage
|
||||
|
@@ -186,12 +186,12 @@ 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
|
||||
Last social actions: Les dernières actions d'accompagnement
|
||||
Social issues: Problématiques sociales
|
||||
Last events on accompanying course: Dernières actions de suivi
|
||||
Edit & activate accompanying course: Modifier et valider
|
||||
@@ -379,10 +379,10 @@ Show Accompanying Course: Voir le parcours
|
||||
Edit Accompanying Course: Modifier le parcours
|
||||
Create Accompanying Course: Créer un nouveau parcours
|
||||
Drop Accompanying Course: Supprimer le parcours
|
||||
This course is located at a temporarily address. You should locate this course to an user: Ce parcours est localisé à une adresse temporaire. Il devrait être localisé auprès d'un usager concerné.
|
||||
This course is located at a temporarily address. You should locate this course to an user: Le parcours est localisé à une adresse temporaire. Il devrait être localisé auprès d'une personne concernée.
|
||||
Accompanying course location: Localisation du parcours
|
||||
This course is located by: Ce parcours est localisé auprès de
|
||||
This course has a temporarily location: Ce parcours a une localisation temporaire
|
||||
This course is located by: Localisé auprès de
|
||||
This course has a temporarily location: Localisation temporaire
|
||||
Choose a person to locate by: Localiser auprès d'un usager concerné
|
||||
Associate at least one member with an household, and set an address to this household: Associez au moins un membre du parcours à un ménage, et indiquez une adresse à ce ménage.
|
||||
Locate by: Localiser auprès de
|
||||
|
Reference in New Issue
Block a user