mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-06-07 18:44:08 +00:00
Merge remote-tracking branch 'origin/master' into HEAD
This commit is contained in:
commit
d3bf64a00c
118
composer.json
118
composer.json
@ -1,12 +1,70 @@
|
|||||||
{
|
{
|
||||||
"name": "chill-project/chill-bundles",
|
"name": "chill-project/chill-bundles",
|
||||||
"license": "AGPL-3.0-only",
|
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"description": "Most used bundles for chill-project",
|
"description": "Most used bundles for chill-project",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"chill",
|
"chill",
|
||||||
"social worker"
|
"social worker"
|
||||||
],
|
],
|
||||||
|
"license": "AGPL-3.0-only",
|
||||||
|
"require": {
|
||||||
|
"champs-libres/async-uploader-bundle": "dev-sf4",
|
||||||
|
"champs-libres/wopi-bundle": "dev-master",
|
||||||
|
"composer/package-versions-deprecated": "^1.10",
|
||||||
|
"doctrine/doctrine-bundle": "^2.1",
|
||||||
|
"doctrine/doctrine-migrations-bundle": "^3.0",
|
||||||
|
"doctrine/orm": "^2.7",
|
||||||
|
"erusev/parsedown": "^1.7",
|
||||||
|
"graylog2/gelf-php": "^1.5",
|
||||||
|
"knplabs/knp-menu": "^3.1",
|
||||||
|
"knplabs/knp-menu-bundle": "^3.0",
|
||||||
|
"knplabs/knp-time-bundle": "^1.12",
|
||||||
|
"league/csv": "^9.7.1",
|
||||||
|
"nyholm/psr7": "^1.4",
|
||||||
|
"phpoffice/phpspreadsheet": "^1.16",
|
||||||
|
"sensio/framework-extra-bundle": "^5.5",
|
||||||
|
"symfony/asset": "4.*",
|
||||||
|
"symfony/browser-kit": "^5.2",
|
||||||
|
"symfony/css-selector": "^5.2",
|
||||||
|
"symfony/expression-language": "4.*",
|
||||||
|
"symfony/form": "4.*",
|
||||||
|
"symfony/intl": "4.*",
|
||||||
|
"symfony/monolog-bundle": "^3.5",
|
||||||
|
"symfony/security-bundle": "4.*",
|
||||||
|
"symfony/serializer": "^5.2",
|
||||||
|
"symfony/swiftmailer-bundle": "^3.5",
|
||||||
|
"symfony/templating": "4.*",
|
||||||
|
"symfony/translation": "4.*",
|
||||||
|
"symfony/twig-bundle": "^4.4",
|
||||||
|
"symfony/validator": "4.*",
|
||||||
|
"symfony/webpack-encore-bundle": "^1.11",
|
||||||
|
"symfony/workflow": "4.*",
|
||||||
|
"symfony/yaml": "4.*",
|
||||||
|
"twig/extra-bundle": "^2.12 || ^3.0",
|
||||||
|
"twig/intl-extra": "^3.0",
|
||||||
|
"twig/markdown-extra": "^3.3",
|
||||||
|
"twig/twig": "^2.12 || ^3.0"
|
||||||
|
},
|
||||||
|
"conflict": {
|
||||||
|
"symfony/symfony": "*"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"doctrine/doctrine-fixtures-bundle": "^3.3",
|
||||||
|
"fakerphp/faker": "^1.13",
|
||||||
|
"nelmio/alice": "^3.8",
|
||||||
|
"phpunit/phpunit": "^7.0",
|
||||||
|
"symfony/debug-bundle": "^5.1",
|
||||||
|
"symfony/dotenv": "^5.1",
|
||||||
|
"symfony/maker-bundle": "^1.20",
|
||||||
|
"symfony/phpunit-bridge": "^5.2",
|
||||||
|
"symfony/stopwatch": "^5.1",
|
||||||
|
"symfony/var-dumper": "4.*",
|
||||||
|
"symfony/web-profiler-bundle": "^5.0"
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"bin-dir": "bin",
|
||||||
|
"vendor-dir": "tests/app/vendor"
|
||||||
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
"Chill\\ActivityBundle\\": "src/Bundle/ChillActivityBundle",
|
"Chill\\ActivityBundle\\": "src/Bundle/ChillActivityBundle",
|
||||||
@ -33,68 +91,10 @@
|
|||||||
},
|
},
|
||||||
"minimum-stability": "dev",
|
"minimum-stability": "dev",
|
||||||
"prefer-stable": true,
|
"prefer-stable": true,
|
||||||
"require": {
|
|
||||||
"champs-libres/async-uploader-bundle": "dev-sf4",
|
|
||||||
"champs-libres/wopi-bundle": "dev-master",
|
|
||||||
"nyholm/psr7": "^1.4",
|
|
||||||
"graylog2/gelf-php": "^1.5",
|
|
||||||
"symfony/form": "4.*",
|
|
||||||
"symfony/twig-bundle": "^4.4",
|
|
||||||
"twig/extra-bundle": "^2.12|^3.0",
|
|
||||||
"twig/twig": "^2.12|^3.0",
|
|
||||||
"composer/package-versions-deprecated": "^1.10",
|
|
||||||
"doctrine/doctrine-bundle": "^2.1",
|
|
||||||
"doctrine/doctrine-migrations-bundle": "^3.0",
|
|
||||||
"doctrine/orm": "^2.7",
|
|
||||||
"symfony/asset": "4.*",
|
|
||||||
"symfony/monolog-bundle": "^3.5",
|
|
||||||
"symfony/security-bundle": "4.*",
|
|
||||||
"symfony/translation": "4.*",
|
|
||||||
"symfony/validator": "4.*",
|
|
||||||
"sensio/framework-extra-bundle": "^5.5",
|
|
||||||
"symfony/yaml": "4.*",
|
|
||||||
"symfony/webpack-encore-bundle": "^1.11",
|
|
||||||
"knplabs/knp-menu": "^3.1",
|
|
||||||
"knplabs/knp-menu-bundle": "^3.0",
|
|
||||||
"symfony/templating": "4.*",
|
|
||||||
"twig/intl-extra": "^3.0",
|
|
||||||
"symfony/workflow": "4.*",
|
|
||||||
"symfony/expression-language": "4.*",
|
|
||||||
"knplabs/knp-time-bundle": "^1.12",
|
|
||||||
"symfony/intl": "4.*",
|
|
||||||
"symfony/swiftmailer-bundle": "^3.5",
|
|
||||||
"league/csv": "^9.7.1",
|
|
||||||
"phpoffice/phpspreadsheet": "^1.16",
|
|
||||||
"symfony/browser-kit": "^5.2",
|
|
||||||
"symfony/css-selector": "^5.2",
|
|
||||||
"twig/markdown-extra": "^3.3",
|
|
||||||
"erusev/parsedown": "^1.7",
|
|
||||||
"symfony/serializer": "^5.2",
|
|
||||||
"symfony/webpack-encore-bundle": "^1.11"
|
|
||||||
},
|
|
||||||
"conflict": {
|
|
||||||
"symfony/symfony": "*"
|
|
||||||
},
|
|
||||||
"require-dev": {
|
|
||||||
"fakerphp/faker": "^1.13",
|
|
||||||
"phpunit/phpunit": "^7.0",
|
|
||||||
"symfony/dotenv": "^5.1",
|
|
||||||
"symfony/maker-bundle": "^1.20",
|
|
||||||
"doctrine/doctrine-fixtures-bundle": "^3.3",
|
|
||||||
"symfony/stopwatch": "^5.1",
|
|
||||||
"symfony/web-profiler-bundle": "^5.0",
|
|
||||||
"symfony/var-dumper": "4.*",
|
|
||||||
"symfony/debug-bundle": "^5.1",
|
|
||||||
"symfony/phpunit-bridge": "^5.2",
|
|
||||||
"nelmio/alice": "^3.8"
|
|
||||||
},
|
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"auto-scripts": {
|
"auto-scripts": {
|
||||||
"cache:clear": "symfony-cmd",
|
"cache:clear": "symfony-cmd",
|
||||||
"assets:install %PUBLIC_DIR%": "symfony-cmd"
|
"assets:install %PUBLIC_DIR%": "symfony-cmd"
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"config": {
|
|
||||||
"bin-dir": "bin"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,6 +31,11 @@
|
|||||||
<!-- temporarily removed, the time to find a fix -->
|
<!-- temporarily removed, the time to find a fix -->
|
||||||
<exclude>src/Bundle/ChillPersonBundle/Tests/Controller/PersonDuplicateControllerViewTest.php</exclude>
|
<exclude>src/Bundle/ChillPersonBundle/Tests/Controller/PersonDuplicateControllerViewTest.php</exclude>
|
||||||
</testsuite>
|
</testsuite>
|
||||||
|
<testsuite name="AsideActivityBundle">
|
||||||
|
<directory suffix="Test.php">src/Bundle/ChillAsideActivityBundle/src/Tests/</directory>
|
||||||
|
<testsuite name="CalendarBundle">
|
||||||
|
<directory suffix="Test.php">src/Bundle/ChillCalendarBundle/Tests/</directory>
|
||||||
|
</testsuite>
|
||||||
</testsuites>
|
</testsuites>
|
||||||
|
|
||||||
<listeners>
|
<listeners>
|
||||||
|
@ -22,6 +22,9 @@
|
|||||||
|
|
||||||
namespace Chill\ActivityBundle\Controller;
|
namespace Chill\ActivityBundle\Controller;
|
||||||
|
|
||||||
|
use Chill\ActivityBundle\Repository\ActivityACLAwareRepository;
|
||||||
|
use Chill\ActivityBundle\Repository\ActivityACLAwareRepositoryInterface;
|
||||||
|
use Chill\ActivityBundle\Security\Authorization\ActivityVoter;
|
||||||
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
|
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
|
||||||
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||||
use Chill\PersonBundle\Entity\Person;
|
use Chill\PersonBundle\Entity\Person;
|
||||||
@ -36,6 +39,7 @@ use Symfony\Component\HttpFoundation\Response;
|
|||||||
use Symfony\Component\Security\Core\Role\Role;
|
use Symfony\Component\Security\Core\Role\Role;
|
||||||
use Chill\ActivityBundle\Entity\Activity;
|
use Chill\ActivityBundle\Entity\Activity;
|
||||||
use Chill\ActivityBundle\Form\ActivityType;
|
use Chill\ActivityBundle\Form\ActivityType;
|
||||||
|
use Chill\MainBundle\Entity\Embeddable\CommentEmbeddable;
|
||||||
use Symfony\Component\Serializer\SerializerInterface;
|
use Symfony\Component\Serializer\SerializerInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -53,12 +57,16 @@ class ActivityController extends AbstractController
|
|||||||
|
|
||||||
protected SerializerInterface $serializer;
|
protected SerializerInterface $serializer;
|
||||||
|
|
||||||
|
protected ActivityACLAwareRepositoryInterface $activityACLAwareRepository;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
|
ActivityACLAwareRepositoryInterface $activityACLAwareRepository,
|
||||||
EventDispatcherInterface $eventDispatcher,
|
EventDispatcherInterface $eventDispatcher,
|
||||||
AuthorizationHelper $authorizationHelper,
|
AuthorizationHelper $authorizationHelper,
|
||||||
LoggerInterface $logger,
|
LoggerInterface $logger,
|
||||||
SerializerInterface $serializer
|
SerializerInterface $serializer
|
||||||
) {
|
) {
|
||||||
|
$this->activityACLAwareRepository = $activityACLAwareRepository;
|
||||||
$this->eventDispatcher = $eventDispatcher;
|
$this->eventDispatcher = $eventDispatcher;
|
||||||
$this->authorizationHelper = $authorizationHelper;
|
$this->authorizationHelper = $authorizationHelper;
|
||||||
$this->logger = $logger;
|
$this->logger = $logger;
|
||||||
@ -77,13 +85,9 @@ class ActivityController extends AbstractController
|
|||||||
[$person, $accompanyingPeriod] = $this->getEntity($request);
|
[$person, $accompanyingPeriod] = $this->getEntity($request);
|
||||||
|
|
||||||
if ($person instanceof Person) {
|
if ($person instanceof Person) {
|
||||||
$reachableScopes = $this->authorizationHelper
|
$this->denyAccessUnlessGranted(ActivityVoter::SEE, $person);
|
||||||
->getReachableCircles($this->getUser(), new Role('CHILL_ACTIVITY_SEE'),
|
$activities = $this->activityACLAwareRepository
|
||||||
$person->getCenter());
|
->findByPerson($person, ActivityVoter::SEE, 0, null);
|
||||||
|
|
||||||
$activities = $em->getRepository(Activity::class)
|
|
||||||
->findByPersonImplied($person, $reachableScopes)
|
|
||||||
;
|
|
||||||
|
|
||||||
$event = new PrivacyEvent($person, array(
|
$event = new PrivacyEvent($person, array(
|
||||||
'element_class' => Activity::class,
|
'element_class' => Activity::class,
|
||||||
@ -93,10 +97,10 @@ class ActivityController extends AbstractController
|
|||||||
|
|
||||||
$view = 'ChillActivityBundle:Activity:listPerson.html.twig';
|
$view = 'ChillActivityBundle:Activity:listPerson.html.twig';
|
||||||
} elseif ($accompanyingPeriod instanceof AccompanyingPeriod) {
|
} elseif ($accompanyingPeriod instanceof AccompanyingPeriod) {
|
||||||
$activities = $em->getRepository('ChillActivityBundle:Activity')->findBy(
|
$this->denyAccessUnlessGranted(ActivityVoter::SEE, $accompanyingPeriod);
|
||||||
['accompanyingPeriod' => $accompanyingPeriod],
|
|
||||||
['date' => 'DESC'],
|
$activities = $this->activityACLAwareRepository
|
||||||
);
|
->findByAccompanyingPeriod($accompanyingPeriod, ActivityVoter::SEE);
|
||||||
|
|
||||||
$view = 'ChillActivityBundle:Activity:listAccompanyingCourse.html.twig';
|
$view = 'ChillActivityBundle:Activity:listAccompanyingCourse.html.twig';
|
||||||
}
|
}
|
||||||
@ -136,6 +140,12 @@ class ActivityController extends AbstractController
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($request->query->has('activityData')) {
|
||||||
|
$activityData = $request->query->get('activityData');
|
||||||
|
} else {
|
||||||
|
$activityData = [];
|
||||||
|
}
|
||||||
|
|
||||||
if ($view === null) {
|
if ($view === null) {
|
||||||
throw $this->createNotFoundException('Template not found');
|
throw $this->createNotFoundException('Template not found');
|
||||||
}
|
}
|
||||||
@ -144,6 +154,7 @@ class ActivityController extends AbstractController
|
|||||||
'person' => $person,
|
'person' => $person,
|
||||||
'accompanyingCourse' => $accompanyingPeriod,
|
'accompanyingCourse' => $accompanyingPeriod,
|
||||||
'data' => $data,
|
'data' => $data,
|
||||||
|
'activityData' => $activityData
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,10 +174,19 @@ class ActivityController extends AbstractController
|
|||||||
$activityType = $em->getRepository(\Chill\ActivityBundle\Entity\ActivityType::class)
|
$activityType = $em->getRepository(\Chill\ActivityBundle\Entity\ActivityType::class)
|
||||||
->find($activityType_id);
|
->find($activityType_id);
|
||||||
|
|
||||||
|
$activityData = null;
|
||||||
|
if ($request->query->has('activityData')) {
|
||||||
|
$activityData = $request->query->get('activityData');
|
||||||
|
}
|
||||||
|
|
||||||
if (!$activityType instanceof \Chill\ActivityBundle\Entity\ActivityType ||
|
if (!$activityType instanceof \Chill\ActivityBundle\Entity\ActivityType ||
|
||||||
!$activityType->isActive()) {
|
!$activityType->isActive()) {
|
||||||
|
|
||||||
$params = $this->buildParamsToUrl($person, $accompanyingPeriod);
|
$params = $this->buildParamsToUrl($person, $accompanyingPeriod);
|
||||||
|
|
||||||
|
if (null !== $activityData) {
|
||||||
|
$params['activityData'] = $activityData;
|
||||||
|
}
|
||||||
return $this->redirectToRoute('chill_activity_activity_select_type', $params);
|
return $this->redirectToRoute('chill_activity_activity_select_type', $params);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -184,6 +204,50 @@ class ActivityController extends AbstractController
|
|||||||
$entity->setType($activityType);
|
$entity->setType($activityType);
|
||||||
$entity->setDate(new \DateTime('now'));
|
$entity->setDate(new \DateTime('now'));
|
||||||
|
|
||||||
|
if ($request->query->has('activityData')) {
|
||||||
|
$activityData = $request->query->get('activityData');
|
||||||
|
|
||||||
|
if (array_key_exists('durationTime', $activityData)) {
|
||||||
|
$durationTimeInMinutes = $activityData['durationTime'];
|
||||||
|
$hours = floor($durationTimeInMinutes / 60);
|
||||||
|
$minutes = $durationTimeInMinutes % 60;
|
||||||
|
$duration = \DateTime::createFromFormat("H:i", $hours.':'.$minutes);
|
||||||
|
if ($duration) {
|
||||||
|
$entity->setDurationTime($duration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (array_key_exists('date', $activityData)) {
|
||||||
|
$date = \DateTime::createFromFormat('Y-m-d', $activityData['date']);
|
||||||
|
if ($date) {
|
||||||
|
$entity->setDate($date);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (array_key_exists('personsId', $activityData)) {
|
||||||
|
foreach($activityData['personsId'] as $personId){
|
||||||
|
$concernedPerson = $em->getRepository(\Chill\PersonBundle\Entity\Person::class)->find($personId);
|
||||||
|
$entity->addPerson($concernedPerson);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (array_key_exists('professionalsId', $activityData)) {
|
||||||
|
foreach($activityData['professionalsId'] as $professionalsId){
|
||||||
|
$professional = $em->getRepository(\Chill\ThirdPartyBundle\Entity\ThirdParty::class)->find($professionalsId);
|
||||||
|
$entity->addThirdParty($professional);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (array_key_exists('comment', $activityData)) {
|
||||||
|
$comment = new CommentEmbeddable();
|
||||||
|
$comment->setComment($activityData['comment']);
|
||||||
|
$comment->setUserId($this->getUser()->getid());
|
||||||
|
$comment->setDate(new \DateTime('now'));
|
||||||
|
$entity->setComment($comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// TODO revoir le Voter de Activity pour tenir compte qu'une activité peut appartenir a une période
|
// TODO revoir le Voter de Activity pour tenir compte qu'une activité peut appartenir a une période
|
||||||
// $this->denyAccessUnlessGranted('CHILL_ACTIVITY_CREATE', $entity);
|
// $this->denyAccessUnlessGranted('CHILL_ACTIVITY_CREATE', $entity);
|
||||||
|
|
||||||
@ -201,6 +265,7 @@ class ActivityController extends AbstractController
|
|||||||
$this->addFlash('success', $this->get('translator')->trans('Success : activity created!'));
|
$this->addFlash('success', $this->get('translator')->trans('Success : activity created!'));
|
||||||
|
|
||||||
$params = $this->buildParamsToUrl($person, $accompanyingPeriod);
|
$params = $this->buildParamsToUrl($person, $accompanyingPeriod);
|
||||||
|
|
||||||
$params['id'] = $entity->getId();
|
$params['id'] = $entity->getId();
|
||||||
|
|
||||||
return $this->redirectToRoute('chill_activity_activity_show', $params);
|
return $this->redirectToRoute('chill_activity_activity_show', $params);
|
||||||
|
@ -23,6 +23,8 @@
|
|||||||
namespace Chill\ActivityBundle\Repository;
|
namespace Chill\ActivityBundle\Repository;
|
||||||
|
|
||||||
use Chill\ActivityBundle\Entity\Activity;
|
use Chill\ActivityBundle\Entity\Activity;
|
||||||
|
use Chill\MainBundle\Security\Resolver\CenterResolverDispatcher;
|
||||||
|
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||||
use Chill\PersonBundle\Entity\Person;
|
use Chill\PersonBundle\Entity\Person;
|
||||||
use Chill\ActivityBundle\Repository\ActivityRepository;
|
use Chill\ActivityBundle\Repository\ActivityRepository;
|
||||||
use Chill\ActivityBundle\Security\Authorization\ActivityVoter;
|
use Chill\ActivityBundle\Security\Authorization\ActivityVoter;
|
||||||
@ -33,9 +35,10 @@ use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
|
|||||||
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
|
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
|
||||||
use Symfony\Component\Security\Core\Role\Role;
|
use Symfony\Component\Security\Core\Role\Role;
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use Symfony\Component\Security\Core\Security;
|
||||||
|
|
||||||
|
|
||||||
final class ActivityACLAwareRepository
|
final class ActivityACLAwareRepository implements ActivityACLAwareRepositoryInterface
|
||||||
{
|
{
|
||||||
private AuthorizationHelper $authorizationHelper;
|
private AuthorizationHelper $authorizationHelper;
|
||||||
|
|
||||||
@ -45,16 +48,63 @@ final class ActivityACLAwareRepository
|
|||||||
|
|
||||||
private EntityManagerInterface $em;
|
private EntityManagerInterface $em;
|
||||||
|
|
||||||
|
private Security $security;
|
||||||
|
|
||||||
|
private CenterResolverDispatcher $centerResolverDispatcher;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
AuthorizationHelper $authorizationHelper,
|
AuthorizationHelper $authorizationHelper,
|
||||||
|
CenterResolverDispatcher $centerResolverDispatcher,
|
||||||
TokenStorageInterface $tokenStorage,
|
TokenStorageInterface $tokenStorage,
|
||||||
ActivityRepository $repository,
|
ActivityRepository $repository,
|
||||||
EntityManagerInterface $em
|
EntityManagerInterface $em,
|
||||||
|
Security $security
|
||||||
) {
|
) {
|
||||||
$this->authorizationHelper = $authorizationHelper;
|
$this->authorizationHelper = $authorizationHelper;
|
||||||
|
$this->centerResolverDispatcher = $centerResolverDispatcher;
|
||||||
$this->tokenStorage = $tokenStorage;
|
$this->tokenStorage = $tokenStorage;
|
||||||
$this->repository = $repository;
|
$this->repository = $repository;
|
||||||
$this->em = $em;
|
$this->em = $em;
|
||||||
|
$this->security = $security;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Person $person
|
||||||
|
* @param string $role
|
||||||
|
* @param int|null $start
|
||||||
|
* @param int|null $limit
|
||||||
|
* @param array $orderBy
|
||||||
|
* @return array|Activity[]
|
||||||
|
*/
|
||||||
|
public function findByPerson(Person $person, string $role, ?int $start = 0, ?int $limit = 1000, ?array $orderBy = []): array
|
||||||
|
{
|
||||||
|
$user = $this->security->getUser();
|
||||||
|
$center = $this->centerResolverDispatcher->resolveCenter($person);
|
||||||
|
if (0 === count($orderBy)) {
|
||||||
|
$orderBy = ['date' => 'DESC'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$reachableScopes = $this->authorizationHelper
|
||||||
|
->getReachableCircles($user, $role, $center);
|
||||||
|
|
||||||
|
return $this->em->getRepository(Activity::class)
|
||||||
|
->findByPersonImplied($person, $reachableScopes, $orderBy, $limit, $start);
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function findByAccompanyingPeriod(AccompanyingPeriod $period, string $role, ?int $start = 0, ?int $limit = 1000, ?array $orderBy = []): array
|
||||||
|
{
|
||||||
|
$user = $this->security->getUser();
|
||||||
|
$center = $this->centerResolverDispatcher->resolveCenter($period);
|
||||||
|
if (0 === count($orderBy)) {
|
||||||
|
$orderBy = ['date' => 'DESC'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$scopes = $this->authorizationHelper
|
||||||
|
->getReachableCircles($user, $role, $center);
|
||||||
|
|
||||||
|
return $this->em->getRepository(Activity::class)
|
||||||
|
->findByAccompanyingPeriod($period, $scopes, true, $limit, $start, $orderBy);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function queryTimelineIndexer(string $context, array $args = []): array
|
public function queryTimelineIndexer(string $context, array $args = []): array
|
||||||
|
@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Chill\ActivityBundle\Repository;
|
||||||
|
|
||||||
|
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||||
|
use Chill\PersonBundle\Entity\Person;
|
||||||
|
|
||||||
|
interface ActivityACLAwareRepositoryInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @return array|Activity[]
|
||||||
|
*/
|
||||||
|
public function findByPerson(Person $person, string $role, ?int $start = 0, ?int $limit = 1000, ?array $orderBy = []): array;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array|Activity[]
|
||||||
|
*/
|
||||||
|
public function findByAccompanyingPeriod(AccompanyingPeriod $period, string $role, ?int $start = 0, ?int $limit = 1000, ?array $orderBy = []): array;
|
||||||
|
}
|
@ -23,6 +23,8 @@
|
|||||||
namespace Chill\ActivityBundle\Repository;
|
namespace Chill\ActivityBundle\Repository;
|
||||||
|
|
||||||
use Chill\ActivityBundle\Entity\Activity;
|
use Chill\ActivityBundle\Entity\Activity;
|
||||||
|
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||||
|
use Chill\PersonBundle\Entity\Person;
|
||||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||||
use Doctrine\Persistence\ManagerRegistry;
|
use Doctrine\Persistence\ManagerRegistry;
|
||||||
|
|
||||||
@ -39,15 +41,22 @@ class ActivityRepository extends ServiceEntityRepository
|
|||||||
parent::__construct($registry, Activity::class);
|
parent::__construct($registry, Activity::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function findByPersonImplied($person, array $scopes, $orderBy = [ 'date' => 'DESC'], $limit = 100, $offset = 0)
|
/**
|
||||||
|
* @param $person
|
||||||
|
* @param array $scopes
|
||||||
|
* @param string[] $orderBy
|
||||||
|
* @param int $limit
|
||||||
|
* @param int $offset
|
||||||
|
* @return array|Activity[]
|
||||||
|
*/
|
||||||
|
public function findByPersonImplied(Person $person, array $scopes, ?array $orderBy = [ 'date' => 'DESC'], ?int $limit = 100, ?int $offset = 0): array
|
||||||
{
|
{
|
||||||
$qb = $this->createQueryBuilder('a');
|
$qb = $this->createQueryBuilder('a');
|
||||||
$qb->select('a');
|
$qb->select('a');
|
||||||
|
|
||||||
$qb
|
$qb
|
||||||
// TODO add acl
|
->where($qb->expr()->in('a.scope', ':scopes'))
|
||||||
//->where($qb->expr()->in('a.scope', ':scopes'))
|
->setParameter('scopes', $scopes)
|
||||||
//->setParameter('scopes', $scopes)
|
|
||||||
->andWhere(
|
->andWhere(
|
||||||
$qb->expr()->orX(
|
$qb->expr()->orX(
|
||||||
$qb->expr()->eq('a.person', ':person'),
|
$qb->expr()->eq('a.person', ':person'),
|
||||||
@ -61,6 +70,55 @@ class ActivityRepository extends ServiceEntityRepository
|
|||||||
$qb->addOrderBy('a.'.$k, $dir);
|
$qb->addOrderBy('a.'.$k, $dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$qb->setMaxResults($limit)->setFirstResult($offset);
|
||||||
|
|
||||||
|
return $qb->getQuery()
|
||||||
|
->getResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param AccompanyingPeriod $period
|
||||||
|
* @param array $scopes
|
||||||
|
* @param int|null $limit
|
||||||
|
* @param int|null $offset
|
||||||
|
* @param array|string[] $orderBy
|
||||||
|
* @return array|Activity[]
|
||||||
|
*/
|
||||||
|
public function findByAccompanyingPeriod(AccompanyingPeriod $period, array $scopes, ?bool $allowNullScope = false, ?int $limit = 100, ?int $offset = 0, array $orderBy = ['date' => 'desc']): array
|
||||||
|
{
|
||||||
|
$qb = $this->createQueryBuilder('a');
|
||||||
|
$qb->select('a');
|
||||||
|
|
||||||
|
if (!$allowNullScope) {
|
||||||
|
$qb
|
||||||
|
->where($qb->expr()->in('a.scope', ':scopes'))
|
||||||
|
->setParameter('scopes', $scopes)
|
||||||
|
;
|
||||||
|
} else {
|
||||||
|
$qb
|
||||||
|
->where(
|
||||||
|
$qb->expr()->orX(
|
||||||
|
$qb->expr()->in('a.scope', ':scopes'),
|
||||||
|
$qb->expr()->isNull('a.scope')
|
||||||
|
)
|
||||||
|
)
|
||||||
|
->setParameter('scopes', $scopes)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
$qb
|
||||||
|
->andWhere(
|
||||||
|
$qb->expr()->eq('a.accompanyingPeriod', ':period')
|
||||||
|
)
|
||||||
|
->setParameter('period', $period)
|
||||||
|
;
|
||||||
|
|
||||||
|
foreach ($orderBy as $k => $dir) {
|
||||||
|
$qb->addOrderBy('a.'.$k, $dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
$qb->setMaxResults($limit)->setFirstResult($offset);
|
||||||
|
|
||||||
return $qb->getQuery()
|
return $qb->getQuery()
|
||||||
->getResult();
|
->getResult();
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<div class="duration">
|
<div class="duration">
|
||||||
{% if t.durationTimeVisible > 0 %}
|
{% if activity.durationTime and t.durationTimeVisible %}
|
||||||
<p>
|
<p>
|
||||||
<i class="fa fa-fw fa-hourglass-end"></i>
|
<i class="fa fa-fw fa-hourglass-end"></i>
|
||||||
{{ activity.durationTime|date('H:i') }}
|
{{ activity.durationTime|date('H:i') }}
|
||||||
@ -47,6 +47,39 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="item-col">
|
<div class="item-col">
|
||||||
|
|
||||||
|
<div class="float-button top">
|
||||||
|
<div class="box">
|
||||||
|
|
||||||
|
<div class="action">
|
||||||
|
<ul class="record_actions">
|
||||||
|
<li>
|
||||||
|
<a href="{{ path('chill_activity_activity_show', { 'id': activity.id, 'person_id': person_id, 'accompanying_period_id': accompanying_course_id }) }}"
|
||||||
|
class="btn btn-sm btn-show "></a>
|
||||||
|
</li>
|
||||||
|
{% if no_action is not defined or no_action == false %}
|
||||||
|
{# TODO
|
||||||
|
{% if is_granted('CHILL_ACTIVITY_UPDATE', activity) %}
|
||||||
|
#}
|
||||||
|
<li>
|
||||||
|
<a href="{{ path('chill_activity_activity_edit', { 'id': activity.id, 'person_id': person_id, 'accompanying_period_id': accompanying_course_id }) }}"
|
||||||
|
class="btn btn-sm btn-update "></a>
|
||||||
|
</li>
|
||||||
|
{# TODO
|
||||||
|
{% endif %}
|
||||||
|
{% if is_granted('CHILL_ACTIVITY_DELETE', activity) %}
|
||||||
|
#}
|
||||||
|
<li>
|
||||||
|
<a href="{{ path('chill_activity_activity_delete', { 'id': activity.id, 'person_id' : person_id, 'accompanying_period_id': accompanying_course_id } ) }}"
|
||||||
|
class="btn btn-sm btn-delete "></a>
|
||||||
|
</li>
|
||||||
|
{# TODO
|
||||||
|
{% endif %}
|
||||||
|
#}
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
<ul class="list-content">
|
<ul class="list-content">
|
||||||
|
|
||||||
{% if activity.user and t.userVisible %}
|
{% if activity.user and t.userVisible %}
|
||||||
@ -71,9 +104,10 @@
|
|||||||
<li>
|
<li>
|
||||||
<b>{{ 'location'|trans ~ ': ' }}</b>
|
<b>{{ 'location'|trans ~ ': ' }}</b>
|
||||||
Domicile de l'usager
|
Domicile de l'usager
|
||||||
{# TODO
|
|
||||||
{% if activity.location %}{{ activity.location }}{% endif %}
|
{# TODO {% if activity.location %}{{ activity.location }}{% endif %}
|
||||||
#}
|
#}
|
||||||
|
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
{%- if t.reasonsVisible -%}
|
{%- if t.reasonsVisible -%}
|
||||||
@ -108,32 +142,13 @@
|
|||||||
|
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
<ul class="record_actions">
|
|
||||||
<li>
|
|
||||||
<a href="{{ path('chill_activity_activity_show', { 'id': activity.id, 'person_id': person_id, 'accompanying_period_id': accompanying_course_id }) }}"
|
|
||||||
class="btn btn-sm btn-show "></a>
|
|
||||||
</li>
|
</div>
|
||||||
{% if no_action is not defined or no_action == false %}
|
</div>
|
||||||
{# TODO
|
|
||||||
{% if is_granted('CHILL_ACTIVITY_UPDATE', activity) %}
|
|
||||||
#}
|
|
||||||
<li>
|
|
||||||
<a href="{{ path('chill_activity_activity_edit', { 'id': activity.id, 'person_id': person_id, 'accompanying_period_id': accompanying_course_id }) }}"
|
|
||||||
class="btn btn-sm btn-update "></a>
|
|
||||||
</li>
|
|
||||||
{# TODO
|
|
||||||
{% endif %}
|
|
||||||
{% if is_granted('CHILL_ACTIVITY_DELETE', activity) %}
|
|
||||||
#}
|
|
||||||
<li>
|
|
||||||
<a href="{{ path('chill_activity_activity_delete', { 'id': activity.id, 'person_id' : person_id, 'accompanying_period_id': accompanying_course_id } ) }}"
|
|
||||||
class="btn btn-sm btn-delete "></a>
|
|
||||||
</li>
|
|
||||||
{# TODO
|
|
||||||
{% endif %}
|
|
||||||
#}
|
|
||||||
{% endif %}
|
|
||||||
</ul>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -18,7 +18,12 @@
|
|||||||
{% set accompanying_course_id = accompanyingCourse.id %}
|
{% set accompanying_course_id = accompanyingCourse.id %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<a href="{{ path('chill_activity_activity_new', {'person_id': person_id, 'activityType_id': activityType.id, 'accompanying_period_id': accompanying_course_id }) }}">
|
<a href="{{ path('chill_activity_activity_new', {
|
||||||
|
'person_id': person_id,
|
||||||
|
'activityType_id': activityType.id,
|
||||||
|
'accompanying_period_id': accompanying_course_id,
|
||||||
|
'activityData': activityData
|
||||||
|
}) }}">
|
||||||
|
|
||||||
<div class="bloc btn btn-primary btn-lg btn-block">
|
<div class="bloc btn btn-primary btn-lg btn-block">
|
||||||
{{ activityType.name|localize_translatable_string }}
|
{{ activityType.name|localize_translatable_string }}
|
||||||
|
@ -64,16 +64,26 @@
|
|||||||
|
|
||||||
{% if t.durationTimeVisible %}
|
{% if t.durationTimeVisible %}
|
||||||
<dt class="inline">{{ 'Duration Time'|trans }}</dt>
|
<dt class="inline">{{ 'Duration Time'|trans }}</dt>
|
||||||
<dd>{{ entity.durationTime|date('H:i') }}</dd>
|
<dd>{% if entity.durationTime is not null %}
|
||||||
|
{{ entity.durationTime|date('H:i') }}
|
||||||
|
{% else %}
|
||||||
|
{{ 'None'|trans|capitalize }}
|
||||||
|
{% endif %}
|
||||||
|
</dd>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if t.travelTimeVisible %}
|
{% if t.travelTimeVisible %}
|
||||||
<dt class="inline">{{ 'Travel Time'|trans }}</dt>
|
<dt class="inline">{{ 'Travel Time'|trans }}</dt>
|
||||||
<dd>{{ entity.travelTime|date('H:i') }}</dd>
|
<dd>{% if entity.travelTime is not null %}
|
||||||
|
{{ entity.travelTime|date('H:i') }}
|
||||||
|
{% else %}
|
||||||
|
{{ 'None'|trans|capitalize }}
|
||||||
|
{% endif %}
|
||||||
|
</dd>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if t.commentVisible %}
|
{% if t.commentVisible %}
|
||||||
<dt class="inline">{{ 'Comment'|trans }}</dt>
|
<dt class="inline">{{ 'activity.comment'|trans }}</dt>
|
||||||
{%- if entity.comment.empty -%}
|
{%- if entity.comment.empty -%}
|
||||||
<dd><span class="chill-no-data-statement">{{ 'No comment associated'|trans }}</span></dd>
|
<dd><span class="chill-no-data-statement">{{ 'No comment associated'|trans }}</span></dd>
|
||||||
{%- else -%}
|
{%- else -%}
|
||||||
|
@ -19,6 +19,11 @@
|
|||||||
|
|
||||||
namespace Chill\ActivityBundle\Security\Authorization;
|
namespace Chill\ActivityBundle\Security\Authorization;
|
||||||
|
|
||||||
|
use Chill\MainBundle\Security\Authorization\VoterHelperFactoryInterface;
|
||||||
|
use Chill\MainBundle\Security\Authorization\VoterHelperInterface;
|
||||||
|
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||||
|
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter;
|
||||||
|
use Chill\PersonBundle\Security\Authorization\PersonVoter;
|
||||||
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
||||||
|
|
||||||
use Chill\MainBundle\Security\Authorization\AbstractChillVoter;
|
use Chill\MainBundle\Security\Authorization\AbstractChillVoter;
|
||||||
@ -28,11 +33,10 @@ use Chill\MainBundle\Entity\User;
|
|||||||
use Chill\ActivityBundle\Entity\Activity;
|
use Chill\ActivityBundle\Entity\Activity;
|
||||||
use Chill\PersonBundle\Entity\Person;
|
use Chill\PersonBundle\Entity\Person;
|
||||||
use Symfony\Component\Security\Core\Role\Role;
|
use Symfony\Component\Security\Core\Role\Role;
|
||||||
|
use Symfony\Component\Security\Core\Security;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* Voter for Activity class
|
||||||
*
|
|
||||||
* @author Julien Fastré <julien.fastre@champs-libres.coop>
|
|
||||||
*/
|
*/
|
||||||
class ActivityVoter extends AbstractChillVoter implements ProvideRoleHierarchyInterface
|
class ActivityVoter extends AbstractChillVoter implements ProvideRoleHierarchyInterface
|
||||||
{
|
{
|
||||||
@ -41,30 +45,37 @@ class ActivityVoter extends AbstractChillVoter implements ProvideRoleHierarchyIn
|
|||||||
const SEE_DETAILS = 'CHILL_ACTIVITY_SEE_DETAILS';
|
const SEE_DETAILS = 'CHILL_ACTIVITY_SEE_DETAILS';
|
||||||
const UPDATE = 'CHILL_ACTIVITY_UPDATE';
|
const UPDATE = 'CHILL_ACTIVITY_UPDATE';
|
||||||
const DELETE = 'CHILL_ACTIVITY_DELETE';
|
const DELETE = 'CHILL_ACTIVITY_DELETE';
|
||||||
|
const FULL = 'CHILL_ACTIVITY_FULL';
|
||||||
|
|
||||||
/**
|
private const ALL = [
|
||||||
*
|
self::CREATE,
|
||||||
* @var AuthorizationHelper
|
self::SEE,
|
||||||
*/
|
self::UPDATE,
|
||||||
protected $helper;
|
self::DELETE,
|
||||||
|
self::SEE_DETAILS,
|
||||||
|
self::FULL
|
||||||
|
];
|
||||||
|
|
||||||
public function __construct(AuthorizationHelper $helper)
|
protected VoterHelperInterface $voterHelper;
|
||||||
{
|
|
||||||
$this->helper = $helper;
|
protected Security $security;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
Security $security,
|
||||||
|
VoterHelperFactoryInterface $voterHelperFactory
|
||||||
|
) {
|
||||||
|
$this->security = $security;
|
||||||
|
$this->voterHelper = $voterHelperFactory->generate(self::class)
|
||||||
|
->addCheckFor(Person::class, [self::SEE, self::CREATE])
|
||||||
|
->addCheckFor(AccompanyingPeriod::class, [self::SEE, self::CREATE])
|
||||||
|
->addCheckFor(Activity::class, self::ALL)
|
||||||
|
->build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected function supports($attribute, $subject)
|
protected function supports($attribute, $subject)
|
||||||
{
|
{
|
||||||
if ($subject instanceof Activity) {
|
return $this->voterHelper->supports($attribute, $subject);
|
||||||
return \in_array($attribute, $this->getAttributes());
|
|
||||||
} elseif ($subject instanceof Person) {
|
|
||||||
return $attribute === self::SEE
|
|
||||||
||
|
|
||||||
$attribute === self::CREATE;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function voteOnAttribute($attribute, $subject, TokenInterface $token)
|
protected function voteOnAttribute($attribute, $subject, TokenInterface $token)
|
||||||
@ -73,31 +84,33 @@ class ActivityVoter extends AbstractChillVoter implements ProvideRoleHierarchyIn
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($subject instanceof Person) {
|
if ($subject instanceof Activity) {
|
||||||
$centers = $this->helper->getReachableCenters($token->getUser(), new Role($attribute));
|
if ($subject->getPerson() instanceof Person) {
|
||||||
|
// the context is person: we must have the right to see the person
|
||||||
return \in_array($subject->getCenter(), $centers);
|
if (!$this->security->isGranted(PersonVoter::SEE, $subject->getPerson())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} elseif ($subject->getAccompanyingPeriod() instanceof AccompanyingPeriod) {
|
||||||
|
if (!$this->security->isGranted(AccompanyingPeriodVoter::SEE, $subject->getAccompanyingPeriod())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new \RuntimeException("could not determine context of activity");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* @var $subject Activity */
|
return $this->voterHelper->voteOnAttribute($attribute, $subject, $token);
|
||||||
return $this->helper->userHasAccess($token->getUser(), $subject, $attribute);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function getAttributes()
|
|
||||||
{
|
|
||||||
return [ self::CREATE, self::SEE, self::UPDATE, self::DELETE,
|
|
||||||
self::SEE_DETAILS ];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function getRoles()
|
public function getRoles()
|
||||||
{
|
{
|
||||||
return $this->getAttributes();
|
return self::ALL;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getRolesWithoutScope()
|
public function getRolesWithoutScope()
|
||||||
{
|
{
|
||||||
return array();
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,20 +1,4 @@
|
|||||||
services:
|
services:
|
||||||
chill.activity.security.authorization.activity_voter:
|
|
||||||
class: Chill\ActivityBundle\Security\Authorization\ActivityVoter
|
|
||||||
arguments:
|
|
||||||
- "@chill.main.security.authorization.helper"
|
|
||||||
tags:
|
|
||||||
- { name: security.voter }
|
|
||||||
- { name: chill.role }
|
|
||||||
|
|
||||||
chill.activity.security.authorization.activity_stats_voter:
|
|
||||||
class: Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter
|
|
||||||
arguments:
|
|
||||||
- "@chill.main.security.authorization.helper"
|
|
||||||
tags:
|
|
||||||
- { name: security.voter }
|
|
||||||
- { name: chill.role }
|
|
||||||
|
|
||||||
|
|
||||||
chill.activity.timeline:
|
chill.activity.timeline:
|
||||||
class: Chill\ActivityBundle\Timeline\TimelineActivityProvider
|
class: Chill\ActivityBundle\Timeline\TimelineActivityProvider
|
||||||
@ -38,3 +22,8 @@ services:
|
|||||||
autowire: true
|
autowire: true
|
||||||
autoconfigure: true
|
autoconfigure: true
|
||||||
resource: '../Notification'
|
resource: '../Notification'
|
||||||
|
|
||||||
|
Chill\ActivityBundle\Security\Authorization\:
|
||||||
|
resource: '../Security/Authorization/'
|
||||||
|
autowire: true
|
||||||
|
autoconfigure: true
|
||||||
|
@ -1,8 +1,4 @@
|
|||||||
services:
|
services:
|
||||||
Chill\ActivityBundle\Controller\ActivityController:
|
Chill\ActivityBundle\Controller\ActivityController:
|
||||||
arguments:
|
autowire: true
|
||||||
$eventDispatcher: '@Symfony\Component\EventDispatcher\EventDispatcherInterface'
|
|
||||||
$authorizationHelper: '@Chill\MainBundle\Security\Authorization\AuthorizationHelper'
|
|
||||||
$logger: '@chill.main.logger'
|
|
||||||
$serializer: '@Symfony\Component\Serializer\SerializerInterface'
|
|
||||||
tags: ['controller.service_arguments']
|
tags: ['controller.service_arguments']
|
||||||
|
@ -24,9 +24,7 @@ services:
|
|||||||
- '@Doctrine\Persistence\ManagerRegistry'
|
- '@Doctrine\Persistence\ManagerRegistry'
|
||||||
|
|
||||||
Chill\ActivityBundle\Repository\ActivityACLAwareRepository:
|
Chill\ActivityBundle\Repository\ActivityACLAwareRepository:
|
||||||
arguments:
|
autowire: true
|
||||||
$tokenStorage: '@Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface'
|
autoconfigure: true
|
||||||
$authorizationHelper: '@Chill\MainBundle\Security\Authorization\AuthorizationHelper'
|
Chill\ActivityBundle\Repository\ActivityACLAwareRepositoryInterface: '@Chill\ActivityBundle\Repository\ActivityACLAwareRepository'
|
||||||
$repository: '@Chill\ActivityBundle\Repository\ActivityRepository'
|
|
||||||
$em: '@Doctrine\ORM\EntityManagerInterface'
|
|
||||||
|
|
||||||
|
@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Chill\AsideActivityBundle\Controller;
|
||||||
|
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controller for activity configuration
|
||||||
|
*
|
||||||
|
* @author Julien Fastré <julien.fastre@champs-libres.coop>
|
||||||
|
* @author Champs Libres <info@champs-libres.coop>
|
||||||
|
*/
|
||||||
|
class AdminController extends AbstractController
|
||||||
|
{
|
||||||
|
|
||||||
|
public function redirectToAdminIndexAction()
|
||||||
|
{
|
||||||
|
return $this->redirectToRoute('chill_main_admin_central');
|
||||||
|
}
|
||||||
|
}
|
@ -1,14 +1,41 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace Chill\AsideActivityBundle\Controller;
|
namespace Chill\AsideActivityBundle\Controller;
|
||||||
|
|
||||||
use Chill\MainBundle\CRUD\Controller\CRUDController;
|
use Chill\MainBundle\CRUD\Controller\CRUDController;
|
||||||
|
use Doctrine\ORM\QueryBuilder;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Chill\MainBundle\Pagination\PaginatorInterface;
|
||||||
|
use Doctrine\Common\Collections\Criteria;
|
||||||
|
|
||||||
|
final class AsideActivityController extends CRUDController
|
||||||
/**
|
|
||||||
* Class AsideActivityBundle
|
|
||||||
*/
|
|
||||||
class AsideActivityController extends CRUDController
|
|
||||||
{
|
{
|
||||||
|
protected function buildQueryEntities(string $action, Request $request)
|
||||||
|
{
|
||||||
|
$qb = parent::buildQueryEntities($action, $request);
|
||||||
|
|
||||||
|
if ('index' === $action) {
|
||||||
|
$qb->andWhere($qb->expr()->eq('e.agent', ':user'));
|
||||||
|
$qb->setParameter('user', $this->getUser());
|
||||||
|
}
|
||||||
|
|
||||||
|
return $qb;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function orderQuery(
|
||||||
|
string $action,
|
||||||
|
$query,
|
||||||
|
Request $request,
|
||||||
|
PaginatorInterface $paginator
|
||||||
|
) {
|
||||||
|
if ('index' === $action) {
|
||||||
|
return $query->orderBy('e.date', 'DESC');
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent::orderQuery($action, $query, $request, $paginator);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,53 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Chill\AsideActivityBundle\DataFixtures\ORM;
|
||||||
|
|
||||||
|
use Chill\AsideActivityBundle\Entity\AsideActivity;
|
||||||
|
use Chill\MainBundle\DataFixtures\ORM\LoadUsers;
|
||||||
|
use Chill\MainBundle\Repository\UserRepository;
|
||||||
|
use Doctrine\Bundle\FixturesBundle\Fixture;
|
||||||
|
use Doctrine\Common\DataFixtures\DependentFixtureInterface;
|
||||||
|
use Doctrine\Persistence\ObjectManager;
|
||||||
|
|
||||||
|
class LoadAsideActivity extends Fixture implements DependentFixtureInterface
|
||||||
|
{
|
||||||
|
private UserRepository $userRepository;
|
||||||
|
|
||||||
|
public function __construct(UserRepository $userRepository)
|
||||||
|
{
|
||||||
|
$this->userRepository = $userRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDependencies(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
LoadUsers::class,
|
||||||
|
LoadAsideActivityCategory::class
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function load(ObjectManager $manager)
|
||||||
|
{
|
||||||
|
$user = $this->userRepository->findOneBy(['username' => 'center a_social']);
|
||||||
|
|
||||||
|
for ($i = 0; $i < 50; $i++) {
|
||||||
|
$activity = new AsideActivity();
|
||||||
|
$activity
|
||||||
|
->setAgent($user)
|
||||||
|
->setCreatedAt(new \DateTimeImmutable('now'))
|
||||||
|
->setCreatedBy($user)
|
||||||
|
->setUpdatedAt(new \DateTimeImmutable('now'))
|
||||||
|
->setUpdatedBy($user)
|
||||||
|
->setType(
|
||||||
|
$this->getReference('aside_activity_category_0')
|
||||||
|
)
|
||||||
|
->setDate((new \DateTimeImmutable('today'))
|
||||||
|
->sub(new \DateInterval('P'.\random_int(1, 100).'D')))
|
||||||
|
;
|
||||||
|
|
||||||
|
$manager->persist($activity);
|
||||||
|
}
|
||||||
|
|
||||||
|
$manager->flush();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Chill\AsideActivityBundle\DataFixtures\ORM;
|
||||||
|
|
||||||
|
use Chill\AsideActivityBundle\Entity\AsideActivityCategory;
|
||||||
|
use Doctrine\Persistence\ObjectManager;
|
||||||
|
|
||||||
|
class LoadAsideActivityCategory extends \Doctrine\Bundle\FixturesBundle\Fixture
|
||||||
|
{
|
||||||
|
public function load(ObjectManager $manager)
|
||||||
|
{
|
||||||
|
foreach ([
|
||||||
|
'Appel téléphonique',
|
||||||
|
'Formation'
|
||||||
|
] as $key => $label) {
|
||||||
|
$category = new AsideActivityCategory();
|
||||||
|
$category->setTitle(['fr' => $label]);
|
||||||
|
$manager->persist($category);
|
||||||
|
$this->setReference('aside_activity_category_'.$key, $category);
|
||||||
|
}
|
||||||
|
|
||||||
|
$manager->flush();
|
||||||
|
}
|
||||||
|
}
|
@ -25,8 +25,9 @@ final class ChillAsideActivityExtension extends Extension implements PrependExte
|
|||||||
public function load(array $configs, ContainerBuilder $container): void
|
public function load(array $configs, ContainerBuilder $container): void
|
||||||
{
|
{
|
||||||
$loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../config'));
|
$loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../config'));
|
||||||
// $loader->load('services.yaml');
|
$loader->load('services.yaml');
|
||||||
$loader->load('services/form.yaml');
|
$loader->load('services/form.yaml');
|
||||||
|
$loader->load('services/menu.yaml');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function prepend(ContainerBuilder $container)
|
public function prepend(ContainerBuilder $container)
|
||||||
|
@ -200,10 +200,4 @@ class AsideActivity implements TrackUpdateInterface, TrackCreationInterface
|
|||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
// public function __toString()
|
|
||||||
// {
|
|
||||||
// // dump($this->type->getTitle());
|
|
||||||
// return $this->type->getTitle();
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,9 @@ use Chill\MainBundle\Entity\User;
|
|||||||
use Chill\MainBundle\Form\Type\ChillDateType;
|
use Chill\MainBundle\Form\Type\ChillDateType;
|
||||||
use Chill\MainBundle\Form\Type\ChillTextareaType;
|
use Chill\MainBundle\Form\Type\ChillTextareaType;
|
||||||
use Chill\MainBundle\Templating\TranslatableStringHelper;
|
use Chill\MainBundle\Templating\TranslatableStringHelper;
|
||||||
|
use Doctrine\ORM\EntityRepository;
|
||||||
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
||||||
|
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
|
||||||
use Symfony\Component\Form\AbstractType;
|
use Symfony\Component\Form\AbstractType;
|
||||||
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToTimestampTransformer;
|
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToTimestampTransformer;
|
||||||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||||
@ -26,8 +28,12 @@ final class AsideActivityFormType extends AbstractType
|
|||||||
private TranslatableStringHelper $translatableStringHelper;
|
private TranslatableStringHelper $translatableStringHelper;
|
||||||
private TokenStorageInterface $storage;
|
private TokenStorageInterface $storage;
|
||||||
|
|
||||||
public function __construct (TranslatableStringHelper $translatableStringHelper, array $timeChoices, TokenStorageInterface $storage){
|
public function __construct (
|
||||||
$this->timeChoices = $timeChoices;
|
TranslatableStringHelper $translatableStringHelper,
|
||||||
|
ParameterBagInterface $parameterBag,
|
||||||
|
TokenStorageInterface $storage
|
||||||
|
){
|
||||||
|
$this->timeChoices = $parameterBag->get('chill_activity.form.time_duration');
|
||||||
$this->translatableStringHelper = $translatableStringHelper;
|
$this->translatableStringHelper = $translatableStringHelper;
|
||||||
$this->storage = $storage;
|
$this->storage = $storage;
|
||||||
}
|
}
|
||||||
@ -53,6 +59,9 @@ final class AsideActivityFormType extends AbstractType
|
|||||||
'required' => true,
|
'required' => true,
|
||||||
'class' => User::class,
|
'class' => User::class,
|
||||||
'data' => $this->storage->getToken()->getUser(),
|
'data' => $this->storage->getToken()->getUser(),
|
||||||
|
'query_builder' => function(EntityRepository $er){
|
||||||
|
return $er->createQueryBuilder('u')->where('u.enabled = true');
|
||||||
|
},
|
||||||
'attr' => array('class' => 'select2 '),
|
'attr' => array('class' => 'select2 '),
|
||||||
'placeholder' => 'Choose the agent for whom this activity is created',
|
'placeholder' => 'Choose the agent for whom this activity is created',
|
||||||
'choice_label' => 'username'
|
'choice_label' => 'username'
|
||||||
@ -108,7 +117,6 @@ final class AsideActivityFormType extends AbstractType
|
|||||||
$seconds = $data->getTimezone()->getOffset($data);
|
$seconds = $data->getTimezone()->getOffset($data);
|
||||||
$data->setTimeZone($timezoneUTC);
|
$data->setTimeZone($timezoneUTC);
|
||||||
$data->add(new \DateInterval('PT'.$seconds.'S'));
|
$data->add(new \DateInterval('PT'.$seconds.'S'));
|
||||||
dump($data);
|
|
||||||
|
|
||||||
// test if the timestamp is in the choices.
|
// test if the timestamp is in the choices.
|
||||||
// If not, recreate the field with the new timestamp
|
// If not, recreate the field with the new timestamp
|
||||||
|
@ -0,0 +1,46 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Chill\AsideActivityBundle\Menu;
|
||||||
|
|
||||||
|
use Chill\MainBundle\Routing\LocalMenuBuilderInterface;
|
||||||
|
use Knp\Menu\MenuItem;
|
||||||
|
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class SectionMenuBuilder
|
||||||
|
*
|
||||||
|
* @package Chill\AsideActivityBundle\Menu
|
||||||
|
*/
|
||||||
|
class SectionMenuBuilder implements LocalMenuBuilderInterface
|
||||||
|
{
|
||||||
|
protected TranslatorInterface $translator;
|
||||||
|
|
||||||
|
public function __construct(TranslatorInterface $translator)
|
||||||
|
{
|
||||||
|
$this->translator = $translator;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $menuId
|
||||||
|
* @param MenuItem $menu
|
||||||
|
* @param array $parameters
|
||||||
|
*/
|
||||||
|
public function buildMenu($menuId, MenuItem $menu, array $parameters)
|
||||||
|
{
|
||||||
|
$menu->addChild($this->translator->trans('Create an aside activity'), [
|
||||||
|
'route' => 'chill_crud_aside_activity_new'
|
||||||
|
])
|
||||||
|
->setExtras([
|
||||||
|
'order' => 11,
|
||||||
|
'icons' => [ 'plus' ]
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public static function getMenuIds(): array
|
||||||
|
{
|
||||||
|
return [ 'section' ];
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
{% extends "@ChillMain/Admin/layoutWithVerticalMenu.html.twig" %}
|
||||||
|
|
||||||
|
{% block vertical_menu_content %}
|
||||||
|
{{ chill_menu('admin_aside_activity', {
|
||||||
|
'layout': '@ChillAsideActivity/Admin/menu_asideactivity.html.twig',
|
||||||
|
}) }}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block layout_wvm_content %}
|
||||||
|
{% block admin_content %}
|
||||||
|
<!-- block personcontent empty -->
|
||||||
|
<h1>{{ 'Aside activity configuration' |trans }}</h1>
|
||||||
|
{% endblock %}
|
||||||
|
{% endblock %}
|
@ -0,0 +1,4 @@
|
|||||||
|
{% extends "@ChillMain/Menu/verticalMenu.html.twig" %}
|
||||||
|
{% block v_menu_title %}
|
||||||
|
{{ 'Aside activity configuration menu'|trans }}
|
||||||
|
{% endblock %}
|
@ -15,15 +15,8 @@
|
|||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block content_form_actions_before %}{% endblock %}
|
{% block content_form_actions_before %}
|
||||||
{% block content_form_actions_view %}
|
|
||||||
{% if is_granted(chill_crud_config('role', crud_name, 'view'), entity) %}
|
|
||||||
<li class="">
|
|
||||||
<a class="btn btn-show" href="{{ chill_return_path_or('chill_crud_'~crud_name~'_view', { 'id': entity.id }) }}">
|
|
||||||
{{ 'crud.edit.back_to_view'|trans }}
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block content_form_actions_confirm_delete %}
|
{% block content_form_actions_confirm_delete %}
|
||||||
<li>
|
<li>
|
||||||
|
@ -3,6 +3,6 @@
|
|||||||
{# {% block title %}{{ ('crud.' ~ crud_name ~ '.delete.title')|trans({'%crud_name%': crud_name}) }}{% endblock %} #}
|
{# {% block title %}{{ ('crud.' ~ crud_name ~ '.delete.title')|trans({'%crud_name%': crud_name}) }}{% endblock %} #}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
{% embed '@ChillAsideActivity/AsideActivity/_delete.html.twig' %}
|
{% embed '@ChillAsideActivity/asideActivity/_delete.html.twig' %}
|
||||||
{% endembed %}
|
{% endembed %}
|
||||||
{% endblock content %}
|
{% endblock content %}
|
@ -9,5 +9,6 @@
|
|||||||
{% embed '@ChillMain/CRUD/_edit_content.html.twig' %}
|
{% embed '@ChillMain/CRUD/_edit_content.html.twig' %}
|
||||||
{# we do not have "view" page. We empty the corresponding block #}
|
{# we do not have "view" page. We empty the corresponding block #}
|
||||||
{% block content_form_actions_view %}{% endblock %}
|
{% block content_form_actions_view %}{% endblock %}
|
||||||
|
{% block content_form_actions_save_and_show %}{% endblock %}
|
||||||
{% endembed %}
|
{% endembed %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -1,26 +1,26 @@
|
|||||||
{% extends "@ChillMain/layout.html.twig" %}
|
{% extends "@ChillMain/layout.html.twig" %}
|
||||||
|
|
||||||
{% block title %}{{ 'Aside activity list' |trans }}{% endblock title %}
|
{% block title %}
|
||||||
|
{{ 'Aside activity list' |trans }}
|
||||||
|
{% endblock title %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="col-md-10 col-xxl asideactivity-list">
|
<div class="col-md-10 col-xxl asideactivity-list">
|
||||||
<h2>{{ 'My aside activities' |trans }}</h2>
|
<h2>{{ 'My aside activities' |trans }}</h2>
|
||||||
|
|
||||||
{% if entities|length == 0 %}
|
{% if entities|length == 0 %}
|
||||||
<p class="chill-no-data-statement">
|
<p class="chill-no-data-statement">
|
||||||
{{ "There aren't any aside activities."|trans }}
|
{{ "There aren't any aside activities."|trans }}
|
||||||
<a href="{{ path('chill_crud_aside_activity_new') }}" class="btn btn-create button-small"></a>
|
<a href="{{ path('chill_crud_aside_activity_new') }}" class="btn btn-create button-small"></a>
|
||||||
</p>
|
</p>
|
||||||
{% else %}
|
{% else %}
|
||||||
|
|
||||||
<div class="flex-table my-4 list-records">
|
<div
|
||||||
|
class="flex-table my-4 list-records">
|
||||||
{# Sort activities according to date in descending order #}
|
{# Sort activities according to date in descending order #}
|
||||||
{% for entity in entities|sort ((a, b) => b.date <=> a.date) %}
|
{% for entity in entities %}
|
||||||
{% set t = entity.type %}
|
{% set t = entity.type %}
|
||||||
|
|
||||||
{# only load aside activities of current user. #}
|
|
||||||
{% if entity.agent == app.user %}
|
|
||||||
|
|
||||||
<div class="item-bloc">
|
<div class="item-bloc">
|
||||||
<div class="item-row main">
|
<div class="item-row main">
|
||||||
<div class="item-col">
|
<div class="item-col">
|
||||||
@ -68,40 +68,30 @@
|
|||||||
<div class="item-col">
|
<div class="item-col">
|
||||||
<ul class="list-content">
|
<ul class="list-content">
|
||||||
<ul class="record_actions">
|
<ul class="record_actions">
|
||||||
{# <li>
|
|
||||||
<a href="{{ path('chill_crud_aside_activity_view', { 'id': entity.id} ) }}" class="btn btn-show "></a>
|
|
||||||
</li> #}
|
|
||||||
{# TOOD
|
|
||||||
{% if is_granted('CHILL_ACTIVITY_UPDATE', activity) %}
|
|
||||||
#}
|
|
||||||
<li>
|
<li>
|
||||||
<a href="{{ path('chill_crud_aside_activity_edit', { 'id': entity.id }) }}" class="btn btn-update "></a>
|
<a href="{{ chill_path_add_return_path('chill_crud_aside_activity_edit', { 'id': entity.id }) }}" class="btn btn-update btn-mini "></a>
|
||||||
</li>
|
</li>
|
||||||
{# TOOD
|
|
||||||
{% endif %}
|
|
||||||
{% if is_granted('CHILL_ACTIVITY_DELETE', activity) %}
|
|
||||||
#}
|
|
||||||
<li>
|
<li>
|
||||||
<a href="{{ path('chill_crud_aside_activity_delete', { 'id': entity.id } ) }}" class="btn btn-delete "></a>
|
<a href="{{ chill_path_add_return_path('chill_crud_aside_activity_delete', { 'id': entity.id } ) }}" class="btn btn-delete btn-mini"></a>
|
||||||
</li>
|
</li>
|
||||||
{#
|
|
||||||
{% endif %}
|
|
||||||
#}
|
|
||||||
</ul>
|
</ul>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{{ chill_pagination(paginator) }}
|
||||||
|
|
||||||
<ul class="record_actions">
|
<ul class="record_actions">
|
||||||
<li>
|
<li>
|
||||||
<a href="{{ path('chill_crud_aside_activity_new') }}" class="btn btn-create">
|
<a href="{{ chill_path_add_return_path('chill_crud_aside_activity_new') }}" class="btn btn-create">
|
||||||
{{ 'Add a new aside activity' | trans }}
|
{{ 'Create' | trans }}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
{% extends "@ChillActivity/Admin/layout_activity.html.twig" %}
|
{% extends "@ChillAsideActivity/Admin/layout_asideactivity.html.twig" %}
|
||||||
|
|
||||||
{% block admin_content %}
|
{% block admin_content %}
|
||||||
<h1>{{ 'ActivityType list'|trans }}</h1>
|
<h1>{{ 'ActivityType list'|trans }}</h1>
|
||||||
@ -23,7 +23,7 @@
|
|||||||
{%- endif -%}
|
{%- endif -%}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<ul class="record_actions sticky-form-buttons">
|
<ul class="record_actions">
|
||||||
<li>
|
<li>
|
||||||
<a href="{{ path('chill_crud_aside_activity_category_edit', { 'id': entity.id }) }}" class="btn btn-edit" title="{{ 'edit'|trans }}"></a>
|
<a href="{{ path('chill_crud_aside_activity_category_edit', { 'id': entity.id }) }}" class="btn btn-edit" title="{{ 'edit'|trans }}"></a>
|
||||||
</li>
|
</li>
|
||||||
@ -41,4 +41,4 @@
|
|||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -0,0 +1,73 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Chill\AsideActivityBundle\Tests\Controller;
|
||||||
|
|
||||||
|
use Chill\MainBundle\Test\PrepareClientTrait;
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||||
|
use Chill\AsideActivityBundle\Entity\AsideActivity;
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
|
||||||
|
|
||||||
|
class AccompanyingCourseControllerTest extends WebTestCase
|
||||||
|
{
|
||||||
|
use PrepareClientTrait;
|
||||||
|
|
||||||
|
public function setUp()
|
||||||
|
{
|
||||||
|
parent::setUp();
|
||||||
|
self::bootKernel();
|
||||||
|
$this->client = $this->getClientAuthenticated();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testIndexWithoutUsers()
|
||||||
|
{
|
||||||
|
$this->client->request('GET', '/fr/asideactivity');
|
||||||
|
|
||||||
|
$this->assertEquals(200, $this->client->getResponse()->getStatusCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testNewWithoutUsers()
|
||||||
|
{
|
||||||
|
$this->client->request('GET', '/fr/asideactivity/new');
|
||||||
|
|
||||||
|
$this->assertEquals(200, $this->client->getResponse()->getStatusCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider generateAsideActivityId
|
||||||
|
*/
|
||||||
|
|
||||||
|
public function testEditWithoutUsers(int $asideActivityId)
|
||||||
|
{
|
||||||
|
$this->client->request('GET', "/fr/asideactivity/{$asideActivityId}/edit");
|
||||||
|
|
||||||
|
$this->assertEquals(200, $this->client->getResponse()->getStatusCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function generateAsideActivityId()
|
||||||
|
{
|
||||||
|
self::bootKernel();
|
||||||
|
|
||||||
|
$qb = self::$container->get(EntityManagerInterface::class)
|
||||||
|
->createQueryBuilder();
|
||||||
|
|
||||||
|
$asideActivityIds = $qb
|
||||||
|
->select('DISTINCT asideactivity.id')
|
||||||
|
->from(AsideActivity::class, 'asideactivity')
|
||||||
|
->innerJoin('asideactivity.agent', 'agent')
|
||||||
|
->where($qb->expr()->eq('agent.username', ':center_name'))
|
||||||
|
->setParameter('center_name', 'center a_social')
|
||||||
|
->setMaxResults(100)
|
||||||
|
->getQuery()
|
||||||
|
->getResult()
|
||||||
|
;
|
||||||
|
|
||||||
|
\shuffle($asideActivityIds);
|
||||||
|
|
||||||
|
yield [ \array_pop($asideActivityIds)['id'] ];
|
||||||
|
yield [ \array_pop($asideActivityIds)['id'] ];
|
||||||
|
yield [ \array_pop($asideActivityIds)['id'] ];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -1,3 +1,12 @@
|
|||||||
chill_asideactivities_controllers:
|
chill_asideactivities_controllers:
|
||||||
resource: "@ChillAsideActivityBundle/Controller"
|
resource: "@ChillAsideActivityBundle/Controller"
|
||||||
type: annotation
|
type: annotation
|
||||||
|
|
||||||
|
chill_admin_aside_activity_redirect_to_admin_index:
|
||||||
|
path: /{_locale}/admin/activity_redirect_to_main
|
||||||
|
controller: Chill\ActivityBundle\Controller\AdminController::redirectToAdminIndexAction
|
||||||
|
options:
|
||||||
|
menus:
|
||||||
|
admin_aside_activity:
|
||||||
|
order: 0
|
||||||
|
label: Main admin menu
|
||||||
|
@ -1,8 +1,5 @@
|
|||||||
# services:
|
services:
|
||||||
# chill.asideactivity.form.type.asideactivity:
|
Chill\AsideActivityBundle\DataFixtures\:
|
||||||
# class: Chill\AsideActivityBundle\Form\AsideActivityFormType
|
resource: './../DataFixtures'
|
||||||
# arguments:
|
autowire: true
|
||||||
# - "@chill.main.helper.translatable_string"
|
autoconfigure: true
|
||||||
# # - "%chill_activity.form.time_duration%"
|
|
||||||
# tags:
|
|
||||||
# - { name: form.type, alias: chill_asideactivitybundle_asideactivity }
|
|
||||||
|
@ -1,10 +1,6 @@
|
|||||||
---
|
---
|
||||||
services:
|
services:
|
||||||
chill.asideactivity.form.type.asideactivity:
|
Chill\AsideActivityBundle\Form\:
|
||||||
class: Chill\AsideActivityBundle\Form\AsideActivityFormType
|
resource: './../../Form'
|
||||||
arguments:
|
autowire: true
|
||||||
- "@chill.main.helper.translatable_string"
|
autoconfigure: true
|
||||||
- "%chill_activity.form.time_duration%"
|
|
||||||
- "@security.token_storage"
|
|
||||||
tags:
|
|
||||||
- { name: form.type, alias: chill_asideactivitybundle_asideactivity }
|
|
||||||
|
@ -0,0 +1,5 @@
|
|||||||
|
services:
|
||||||
|
Chill\AsideActivityBundle\Menu\:
|
||||||
|
resource: './../../Menu'
|
||||||
|
autowire: true
|
||||||
|
autoconfigure: true
|
@ -1,6 +1,7 @@
|
|||||||
#general
|
#general
|
||||||
Show the aside activity: Voir l'activité annexe
|
Show the aside activity: Voir l'activité annexe
|
||||||
Edit the aside activity: Modifier l'activité annexe
|
Edit the aside activity: Modifier l'activité annexe
|
||||||
|
Remove aside activity: Supprimer l'activité annexe
|
||||||
Aside activity: Activité annexe
|
Aside activity: Activité annexe
|
||||||
Duration time: Durée
|
Duration time: Durée
|
||||||
durationTime: durée
|
durationTime: durée
|
||||||
@ -25,7 +26,7 @@ Required: Obligatoire
|
|||||||
Persons: Personnes
|
Persons: Personnes
|
||||||
Users: Utilisateurs
|
Users: Utilisateurs
|
||||||
Emergency: Urgent
|
Emergency: Urgent
|
||||||
by: 'Par '
|
by: "Par "
|
||||||
location: Lieu
|
location: Lieu
|
||||||
|
|
||||||
# Crud
|
# Crud
|
||||||
@ -33,50 +34,42 @@ crud:
|
|||||||
aside_activity:
|
aside_activity:
|
||||||
title_view: Détail de l'activité annexe
|
title_view: Détail de l'activité annexe
|
||||||
title_new: Nouvelle activité annexe
|
title_new: Nouvelle activité annexe
|
||||||
title_edit: Edition d'une activité annexe
|
title_edit: Édition d'une activité annexe
|
||||||
title_delete: Supprimation d'une activité annexe
|
title_delete: Supprimer une activité annexe
|
||||||
button_delete: Supprimer
|
button_delete: Supprimer
|
||||||
confirm_message_delete: Êtes-vous sûr de vouloir supprimer cet activité annexe?
|
confirm_message_delete: Êtes-vous sûr de vouloir supprimer cette activité annexe?
|
||||||
aside_activity_category:
|
aside_activity_category:
|
||||||
title_new: Nouvelle catégorie d'activité annexe
|
title_new: Nouvelle catégorie d'activité annexe
|
||||||
title_edit: Edition d'une catégorie de type d'activité
|
title_edit: Edition d'une catégorie de type d'activité
|
||||||
|
|
||||||
#forms
|
#forms
|
||||||
Activity creation: Nouvelle activité annexe
|
Activity creation: Nouvelle activité annexe
|
||||||
Create a new aside activity type: Nouvelle categorie d'activité annexe
|
Create a new aside activity type: Nouvelle catégorie d'activité annexe
|
||||||
Create: Créer
|
Create: Créer
|
||||||
Back to the list: Retour à la liste
|
Back to the list: Retour à la liste
|
||||||
Save activity: Sauver l'activité
|
Save activity: Sauver l'activité
|
||||||
Reset form: Remise à zéro du formulaire
|
Reset form: Remise à zéro du formulaire
|
||||||
Choose the agent for whom this activity is created: Choissisez l'utilisateur pour qui l'activité est creéé.
|
Choose the agent for whom this activity is created: Choisissez l'utilisateur pour qui l'activité est créée.
|
||||||
Choose the activity category: Choissisez le type d'activité
|
Choose the activity category: Choisissez le type d'activité
|
||||||
Choose the duration: Choisir la durée
|
Choose the duration: Choisir la durée
|
||||||
Choose a category: Choisir un categorie
|
Choose a category: Choisir une catégorie
|
||||||
Is active: Actif
|
Is active: Actif
|
||||||
Agent: Utilisateur
|
Agent: Utilisateur
|
||||||
date: Date
|
date: Date
|
||||||
Duration: Durée
|
Duration: Durée
|
||||||
Note: Note
|
Note: Note
|
||||||
5 minutes: 5 minutes
|
|
||||||
10 minutes: 10 minutes
|
|
||||||
15 minutes: 15 minutes
|
|
||||||
20 minutes: 20 minutes
|
|
||||||
25 minutes: 25 minutes
|
|
||||||
30 minutes: 30 minutes
|
|
||||||
45 minutes: 45 minutes
|
|
||||||
1 hour: 1 heure
|
|
||||||
1 hour 15: 1 heure 15
|
|
||||||
1 hour 30: 1 heure 30
|
|
||||||
1 hour 45: 1 heure 45
|
|
||||||
2 hours: 2 heures
|
|
||||||
|
|
||||||
#list
|
#list
|
||||||
My aside activities: Mes activités annexes
|
My aside activities: Mes activités annexes
|
||||||
Date: Date
|
Date: Date
|
||||||
Created by: Creér par
|
Created by: Créée par
|
||||||
|
|
||||||
|
|
||||||
#Aside activity delete
|
#Aside activity delete
|
||||||
Delete aside activity: Supprimer une activité annexe
|
Delete aside activity: Supprimer une activité annexe
|
||||||
Are you sure you want to remove the aside activity concerning "%name%" ?: Êtes-vous sûr de vouloir supprimer une activité annexe qui concerne "%name%" ?
|
Are you sure you want to remove the aside activity concerning "%name%" ?: Êtes-vous sûr de vouloir supprimer une activité annexe qui concerne "%name%" ?
|
||||||
The activity has been successfully removed.: L'activité a été supprimée.
|
The activity has been successfully removed.: L'activité a été supprimée.
|
||||||
|
|
||||||
|
#Menu
|
||||||
|
Create an aside activity: "Créer une activité annexe"
|
||||||
|
Aside activity configuration menu: "Menu de configuration des activités annexes"
|
||||||
|
Aside activity configuration: "Configuration des activités annexes"
|
||||||
|
@ -36,7 +36,9 @@ use Symfony\Component\HttpFoundation\Response;
|
|||||||
use Symfony\Component\Security\Core\Role\Role;
|
use Symfony\Component\Security\Core\Role\Role;
|
||||||
use Chill\CalendarBundle\Entity\Calendar;
|
use Chill\CalendarBundle\Entity\Calendar;
|
||||||
use Chill\CalendarBundle\Form\CalendarType;
|
use Chill\CalendarBundle\Form\CalendarType;
|
||||||
|
use Chill\CalendarBundle\Repository\CalendarRepository;
|
||||||
use Chill\MainBundle\Entity\User;
|
use Chill\MainBundle\Entity\User;
|
||||||
|
use Chill\MainBundle\Pagination\PaginatorFactory;
|
||||||
use Symfony\Component\Serializer\SerializerInterface;
|
use Symfony\Component\Serializer\SerializerInterface;
|
||||||
use Symfony\Component\Routing\Annotation\Route;
|
use Symfony\Component\Routing\Annotation\Route;
|
||||||
|
|
||||||
@ -55,55 +57,71 @@ class CalendarController extends AbstractController
|
|||||||
|
|
||||||
protected SerializerInterface $serializer;
|
protected SerializerInterface $serializer;
|
||||||
|
|
||||||
|
protected PaginatorFactory $paginator;
|
||||||
|
|
||||||
|
private CalendarRepository $calendarRepository;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
EventDispatcherInterface $eventDispatcher,
|
EventDispatcherInterface $eventDispatcher,
|
||||||
AuthorizationHelper $authorizationHelper,
|
AuthorizationHelper $authorizationHelper,
|
||||||
LoggerInterface $logger,
|
LoggerInterface $logger,
|
||||||
SerializerInterface $serializer
|
SerializerInterface $serializer,
|
||||||
|
PaginatorFactory $paginator,
|
||||||
|
CalendarRepository $calendarRepository
|
||||||
) {
|
) {
|
||||||
$this->eventDispatcher = $eventDispatcher;
|
$this->eventDispatcher = $eventDispatcher;
|
||||||
$this->authorizationHelper = $authorizationHelper;
|
$this->authorizationHelper = $authorizationHelper;
|
||||||
$this->logger = $logger;
|
$this->logger = $logger;
|
||||||
$this->serializer = $serializer;
|
$this->serializer = $serializer;
|
||||||
|
$this->paginator = $paginator;
|
||||||
|
$this->calendarRepository = $calendarRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lists all Calendar entities.
|
* Lists all Calendar entities.
|
||||||
* @Route("/{_locale}/calendar/", name="chill_calendar_calendar")
|
* @Route("/{_locale}/calendar/calendar/", name="chill_calendar_calendar_list")
|
||||||
*/
|
*/
|
||||||
public function listAction(Request $request): Response
|
public function listAction(Request $request): Response
|
||||||
{
|
{
|
||||||
$em = $this->getDoctrine()->getManager();
|
|
||||||
$view = null;
|
$view = null;
|
||||||
|
|
||||||
[$user, $accompanyingPeriod] = $this->getEntity($request);
|
[$user, $accompanyingPeriod] = $this->getEntity($request);
|
||||||
|
|
||||||
if ($user instanceof User) {
|
if ($user instanceof User) {
|
||||||
|
|
||||||
// $calendar = $em->getRepository(Calendar::class)
|
$calendarItems = $this->calendarRepository->findByUser($user);
|
||||||
// ->findByUser($user)
|
|
||||||
// ;
|
|
||||||
|
|
||||||
// $view = 'ChillCalendarBundle:Calendar:listByUser.html.twig';
|
$view = '@ChillCalendar/Calendar/listByUser.html.twig';
|
||||||
} elseif ($accompanyingPeriod instanceof AccompanyingPeriod) {
|
|
||||||
$calendarItems = $em->getRepository(Calendar::class)->findBy(
|
|
||||||
['accompanyingPeriod' => $accompanyingPeriod],
|
|
||||||
['startDate' => 'DESC']
|
|
||||||
);
|
|
||||||
|
|
||||||
$view = 'ChillCalendarBundle:Calendar:listByAccompanyingCourse.html.twig';
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->render($view, [
|
return $this->render($view, [
|
||||||
'calendarItems' => $calendarItems,
|
'calendarItems' => $calendarItems,
|
||||||
'user' => $user,
|
'user' => $user
|
||||||
'accompanyingCourse' => $accompanyingPeriod,
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
} elseif ($accompanyingPeriod instanceof AccompanyingPeriod) {
|
||||||
|
|
||||||
|
$total = $this->calendarRepository->countByAccompanyingPeriod($accompanyingPeriod);
|
||||||
|
$paginator = $this->paginator->create($total);
|
||||||
|
$calendarItems = $this->calendarRepository->findBy(
|
||||||
|
['accompanyingPeriod' => $accompanyingPeriod],
|
||||||
|
['startDate' => 'DESC'],
|
||||||
|
$paginator->getItemsPerPage(),
|
||||||
|
$paginator->getCurrentPageFirstItemNumber()
|
||||||
|
);
|
||||||
|
|
||||||
|
$view = '@ChillCalendar/Calendar/listByAccompanyingCourse.html.twig';
|
||||||
|
|
||||||
|
return $this->render($view, [
|
||||||
|
'calendarItems' => $calendarItems,
|
||||||
|
'accompanyingCourse' => $accompanyingPeriod,
|
||||||
|
'paginator' => $paginator
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new calendar item
|
* Create a new calendar item
|
||||||
* @Route("/{_locale}/calendar/new", name="chill_calendar_calendar_new")
|
* @Route("/{_locale}/calendar/calendar/new", name="chill_calendar_calendar_new")
|
||||||
*/
|
*/
|
||||||
public function newAction(Request $request): Response
|
public function newAction(Request $request): Response
|
||||||
{
|
{
|
||||||
@ -112,10 +130,10 @@ class CalendarController extends AbstractController
|
|||||||
[$user, $accompanyingPeriod] = $this->getEntity($request);
|
[$user, $accompanyingPeriod] = $this->getEntity($request);
|
||||||
|
|
||||||
if ($accompanyingPeriod instanceof AccompanyingPeriod) {
|
if ($accompanyingPeriod instanceof AccompanyingPeriod) {
|
||||||
$view = 'ChillCalendarBundle:Calendar:newAccompanyingCourse.html.twig';
|
$view = '@ChillCalendar/Calendar/newByAccompanyingCourse.html.twig';
|
||||||
}
|
}
|
||||||
// elseif ($user instanceof User) {
|
// elseif ($user instanceof User) {
|
||||||
// $view = 'ChillCalendarBundle:Calendar:newUser.html.twig';
|
// $view = '@ChillCalendar/Calendar/newUser.html.twig';
|
||||||
// }
|
// }
|
||||||
|
|
||||||
$entity = new Calendar();
|
$entity = new Calendar();
|
||||||
@ -142,7 +160,7 @@ class CalendarController extends AbstractController
|
|||||||
|
|
||||||
$params = $this->buildParamsToUrl($user, $accompanyingPeriod);
|
$params = $this->buildParamsToUrl($user, $accompanyingPeriod);
|
||||||
|
|
||||||
return $this->redirectToRoute('chill_calendar_calendar', $params);
|
return $this->redirectToRoute('chill_calendar_calendar_list', $params);
|
||||||
} elseif ($form->isSubmitted() and !$form->isValid()) {
|
} elseif ($form->isSubmitted() and !$form->isValid()) {
|
||||||
$this->addFlash('error', $this->get('translator')->trans('This form contains errors'));
|
$this->addFlash('error', $this->get('translator')->trans('This form contains errors'));
|
||||||
}
|
}
|
||||||
@ -165,7 +183,7 @@ class CalendarController extends AbstractController
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Show a calendar item
|
* Show a calendar item
|
||||||
* @Route("/{_locale}/calendar/{id}/show", name="chill_calendar_calendar_show")
|
* @Route("/{_locale}/calendar/calendar/{id}/show", name="chill_calendar_calendar_show")
|
||||||
*/
|
*/
|
||||||
public function showAction(Request $request, $id): Response
|
public function showAction(Request $request, $id): Response
|
||||||
{
|
{
|
||||||
@ -174,11 +192,11 @@ class CalendarController extends AbstractController
|
|||||||
[$user, $accompanyingPeriod] = $this->getEntity($request);
|
[$user, $accompanyingPeriod] = $this->getEntity($request);
|
||||||
|
|
||||||
if ($accompanyingPeriod instanceof AccompanyingPeriod) {
|
if ($accompanyingPeriod instanceof AccompanyingPeriod) {
|
||||||
$view = 'ChillCalendarBundle:Calendar:showAccompanyingCourse.html.twig';
|
$view = '@ChillCalendar/Calendar/showByAccompanyingCourse.html.twig';
|
||||||
|
}
|
||||||
|
elseif ($user instanceof User) {
|
||||||
|
$view = '@ChillCalendar/Calendar/showByUser.html.twig';
|
||||||
}
|
}
|
||||||
// elseif ($person instanceof Person) {
|
|
||||||
// $view = 'ChillCalendarBundle:Calendar:showPerson.html.twig';
|
|
||||||
// }
|
|
||||||
|
|
||||||
$entity = $em->getRepository('ChillCalendarBundle:Calendar')->find($id);
|
$entity = $em->getRepository('ChillCalendarBundle:Calendar')->find($id);
|
||||||
|
|
||||||
@ -197,10 +215,33 @@ class CalendarController extends AbstractController
|
|||||||
throw $this->createNotFoundException('Template not found');
|
throw $this->createNotFoundException('Template not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$personsId = [];
|
||||||
|
foreach ($entity->getPersons() as $p) {
|
||||||
|
array_push($personsId, $p->getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
$professionalsId = [];
|
||||||
|
foreach ($entity->getProfessionals() as $p) {
|
||||||
|
array_push($professionalsId, $p->getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
$durationTime = $entity->getEndDate()->diff($entity->getStartDate());
|
||||||
|
$durationTimeInMinutes = $durationTime->days*1440 + $durationTime->h*60 + $durationTime->i;
|
||||||
|
|
||||||
|
$activityData = [
|
||||||
|
'calendarId' => $id,
|
||||||
|
'personsId' => $personsId,
|
||||||
|
'professionalsId' => $professionalsId,
|
||||||
|
'date' => $entity->getStartDate()->format('Y-m-d'),
|
||||||
|
'durationTime' => $durationTimeInMinutes,
|
||||||
|
'comment' => $entity->getComment()->getComment(),
|
||||||
|
];
|
||||||
|
|
||||||
return $this->render($view, [
|
return $this->render($view, [
|
||||||
//'person' => $person,
|
|
||||||
'accompanyingCourse' => $accompanyingPeriod,
|
'accompanyingCourse' => $accompanyingPeriod,
|
||||||
'entity' => $entity,
|
'entity' => $entity,
|
||||||
|
'user' => $user,
|
||||||
|
'activityData' => $activityData
|
||||||
//'delete_form' => $deleteForm->createView(),
|
//'delete_form' => $deleteForm->createView(),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
@ -209,7 +250,7 @@ class CalendarController extends AbstractController
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Edit a calendar item
|
* Edit a calendar item
|
||||||
* @Route("/{_locale}/calendar/{id}/edit", name="chill_calendar_calendar_edit")
|
* @Route("/{_locale}/calendar/calendar/{id}/edit", name="chill_calendar_calendar_edit")
|
||||||
*/
|
*/
|
||||||
public function editAction($id, Request $request): Response
|
public function editAction($id, Request $request): Response
|
||||||
{
|
{
|
||||||
@ -218,11 +259,11 @@ class CalendarController extends AbstractController
|
|||||||
[$user, $accompanyingPeriod] = $this->getEntity($request);
|
[$user, $accompanyingPeriod] = $this->getEntity($request);
|
||||||
|
|
||||||
if ($accompanyingPeriod instanceof AccompanyingPeriod) {
|
if ($accompanyingPeriod instanceof AccompanyingPeriod) {
|
||||||
$view = 'ChillCalendarBundle:Calendar:editAccompanyingCourse.html.twig';
|
$view = '@ChillCalendar/Calendar/editByAccompanyingCourse.html.twig';
|
||||||
|
}
|
||||||
|
elseif ($user instanceof User) {
|
||||||
|
$view = '@ChillCalendar/Calendar/editByUser.html.twig';
|
||||||
}
|
}
|
||||||
// elseif ($person instanceof Person) {
|
|
||||||
// $view = 'ChillCalendarBundle:Calendar:editPerson.html.twig';
|
|
||||||
// }
|
|
||||||
|
|
||||||
$entity = $em->getRepository('ChillCalendarBundle:Calendar')->find($id);
|
$entity = $em->getRepository('ChillCalendarBundle:Calendar')->find($id);
|
||||||
|
|
||||||
@ -241,7 +282,7 @@ class CalendarController extends AbstractController
|
|||||||
$this->addFlash('success', $this->get('translator')->trans('Success : calendar item updated!'));
|
$this->addFlash('success', $this->get('translator')->trans('Success : calendar item updated!'));
|
||||||
|
|
||||||
$params = $this->buildParamsToUrl($user, $accompanyingPeriod);
|
$params = $this->buildParamsToUrl($user, $accompanyingPeriod);
|
||||||
return $this->redirectToRoute('chill_calendar_calendar', $params);
|
return $this->redirectToRoute('chill_calendar_calendar_list', $params);
|
||||||
} elseif ($form->isSubmitted() and !$form->isValid()) {
|
} elseif ($form->isSubmitted() and !$form->isValid()) {
|
||||||
$this->addFlash('error', $this->get('translator')->trans('This form contains errors'));
|
$this->addFlash('error', $this->get('translator')->trans('This form contains errors'));
|
||||||
}
|
}
|
||||||
@ -259,6 +300,7 @@ class CalendarController extends AbstractController
|
|||||||
'form' => $form->createView(),
|
'form' => $form->createView(),
|
||||||
'delete_form' => $deleteForm->createView(),
|
'delete_form' => $deleteForm->createView(),
|
||||||
'accompanyingCourse' => $accompanyingPeriod,
|
'accompanyingCourse' => $accompanyingPeriod,
|
||||||
|
'user' => $user,
|
||||||
'entity_json' => $entity_array
|
'entity_json' => $entity_array
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
@ -274,11 +316,11 @@ class CalendarController extends AbstractController
|
|||||||
[$user, $accompanyingPeriod] = $this->getEntity($request);
|
[$user, $accompanyingPeriod] = $this->getEntity($request);
|
||||||
|
|
||||||
if ($accompanyingPeriod instanceof AccompanyingPeriod) {
|
if ($accompanyingPeriod instanceof AccompanyingPeriod) {
|
||||||
$view = 'ChillCalendarBundle:Calendar:confirm_deleteAccompanyingCourse.html.twig';
|
$view = '@ChillCalendar/Calendar/confirm_deleteByAccompanyingCourse.html.twig';
|
||||||
|
}
|
||||||
|
elseif ($user instanceof User) {
|
||||||
|
$view = '@ChillCalendar/Calendar/confirm_deleteByUser.html.twig';
|
||||||
}
|
}
|
||||||
// elseif ($person instanceof Person) {
|
|
||||||
// $view = 'ChillCalendarBundle:Calendar:confirm_deletePerson.html.twig';
|
|
||||||
// }
|
|
||||||
|
|
||||||
/* @var $entity Calendar */
|
/* @var $entity Calendar */
|
||||||
$entity = $em->getRepository('ChillCalendarBundle:Calendar')->find($id);
|
$entity = $em->getRepository('ChillCalendarBundle:Calendar')->find($id);
|
||||||
@ -306,7 +348,7 @@ class CalendarController extends AbstractController
|
|||||||
->trans("The calendar item has been successfully removed."));
|
->trans("The calendar item has been successfully removed."));
|
||||||
|
|
||||||
$params = $this->buildParamsToUrl($user, $accompanyingPeriod);
|
$params = $this->buildParamsToUrl($user, $accompanyingPeriod);
|
||||||
return $this->redirectToRoute('chill_calendar_calendar', $params);
|
return $this->redirectToRoute('chill_calendar_calendar_list', $params);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -324,9 +366,9 @@ class CalendarController extends AbstractController
|
|||||||
/**
|
/**
|
||||||
* Creates a form to delete a Calendar entity by id.
|
* Creates a form to delete a Calendar entity by id.
|
||||||
*/
|
*/
|
||||||
private function createDeleteForm(int $id, ?Person $person, ?AccompanyingPeriod $accompanyingPeriod): Form
|
private function createDeleteForm(int $id, ?User $user, ?AccompanyingPeriod $accompanyingPeriod): Form
|
||||||
{
|
{
|
||||||
$params = $this->buildParamsToUrl($person, $accompanyingPeriod);
|
$params = $this->buildParamsToUrl($user, $accompanyingPeriod);
|
||||||
$params['id'] = $id;
|
$params['id'] = $id;
|
||||||
|
|
||||||
return $this->createFormBuilder()
|
return $this->createFormBuilder()
|
||||||
@ -350,7 +392,8 @@ class CalendarController extends AbstractController
|
|||||||
throw $this->createNotFoundException('User not found');
|
throw $this->createNotFoundException('User not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $user);
|
// TODO Add permission
|
||||||
|
// $this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $user);
|
||||||
} elseif ($request->query->has('accompanying_period_id')) {
|
} elseif ($request->query->has('accompanying_period_id')) {
|
||||||
$accompanying_period_id = $request->get('accompanying_period_id');
|
$accompanying_period_id = $request->get('accompanying_period_id');
|
||||||
$accompanyingPeriod = $em->getRepository(AccompanyingPeriod::class)->find($accompanying_period_id);
|
$accompanyingPeriod = $em->getRepository(AccompanyingPeriod::class)->find($accompanying_period_id);
|
||||||
|
@ -18,16 +18,19 @@ class CalendarRangeAPIController extends ApiController
|
|||||||
*/
|
*/
|
||||||
public function availableRanges(Request $request, string $_format): JsonResponse
|
public function availableRanges(Request $request, string $_format): JsonResponse
|
||||||
{
|
{
|
||||||
if ($request->query->has('user')) {
|
|
||||||
$user = $request->query->get('user');
|
|
||||||
}
|
|
||||||
|
|
||||||
$em = $this->getDoctrine()->getManager();
|
$em = $this->getDoctrine()->getManager();
|
||||||
|
|
||||||
$query = $em->createQuery(
|
$sql = 'SELECT c FROM ChillCalendarBundle:CalendarRange c
|
||||||
'SELECT c FROM ChillCalendarBundle:CalendarRange c
|
WHERE NOT EXISTS (SELECT cal.id FROM ChillCalendarBundle:Calendar cal WHERE cal.calendarRange = c.id)';
|
||||||
WHERE NOT EXISTS (SELECT cal.id FROM ChillCalendarBundle:Calendar cal WHERE cal.calendarRange = c.id)')
|
|
||||||
;
|
if ($request->query->has('user')) {
|
||||||
|
$user = $request->query->get('user');
|
||||||
|
$sql = $sql . ' AND c.user = :user';
|
||||||
|
$query = $em->createQuery($sql)
|
||||||
|
->setParameter('user', $user);
|
||||||
|
} else {
|
||||||
|
$query = $em->createQuery($sql);
|
||||||
|
}
|
||||||
|
|
||||||
$results = $query->getResult();
|
$results = $query->getResult();
|
||||||
|
|
||||||
|
@ -29,6 +29,7 @@ class ChillCalendarExtension extends Extension implements PrependExtensionInterf
|
|||||||
$loader->load('services/controller.yml');
|
$loader->load('services/controller.yml');
|
||||||
$loader->load('services/fixtures.yml');
|
$loader->load('services/fixtures.yml');
|
||||||
$loader->load('services/form.yml');
|
$loader->load('services/form.yml');
|
||||||
|
$loader->load('services/event.yml');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function prepend(ContainerBuilder $container)
|
public function prepend(ContainerBuilder $container)
|
||||||
@ -66,13 +67,16 @@ class ChillCalendarExtension extends Extension implements PrependExtensionInterf
|
|||||||
'_index' => [
|
'_index' => [
|
||||||
'methods' => [
|
'methods' => [
|
||||||
Request::METHOD_GET => true,
|
Request::METHOD_GET => true,
|
||||||
Request::METHOD_HEAD => true
|
Request::METHOD_HEAD => true,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
'_entity' => [
|
'_entity' => [
|
||||||
'methods' => [
|
'methods' => [
|
||||||
Request::METHOD_GET => true,
|
Request::METHOD_GET => true,
|
||||||
Request::METHOD_HEAD => true
|
Request::METHOD_HEAD => true,
|
||||||
|
Request::METHOD_POST => true,
|
||||||
|
Request::METHOD_PATCH => true,
|
||||||
|
Request::METHOD_DELETE => true,
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
]
|
]
|
||||||
|
@ -37,14 +37,16 @@ class Calendar
|
|||||||
* @ORM\Id
|
* @ORM\Id
|
||||||
* @ORM\GeneratedValue
|
* @ORM\GeneratedValue
|
||||||
* @ORM\Column(type="integer")
|
* @ORM\Column(type="integer")
|
||||||
|
* @Serializer\Groups({"calendar:read"})
|
||||||
*/
|
*/
|
||||||
private ?int $id;
|
private ?int $id;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\User")
|
* @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\User")
|
||||||
* @Groups({"read"})
|
* @Groups({"read"})
|
||||||
|
* @Serializer\Groups({"calendar:read"})
|
||||||
*/
|
*/
|
||||||
private User $user;
|
private ?User $user = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\ManyToOne(targetEntity="Chill\PersonBundle\Entity\AccompanyingPeriod")
|
* @ORM\ManyToOne(targetEntity="Chill\PersonBundle\Entity\AccompanyingPeriod")
|
||||||
@ -64,6 +66,7 @@ class Calendar
|
|||||||
* cascade={"persist", "remove", "merge", "detach"})
|
* cascade={"persist", "remove", "merge", "detach"})
|
||||||
* @ORM\JoinTable(name="chill_calendar.calendar_to_persons")
|
* @ORM\JoinTable(name="chill_calendar.calendar_to_persons")
|
||||||
* @Groups({"read"})
|
* @Groups({"read"})
|
||||||
|
* @Serializer\Groups({"calendar:read"})
|
||||||
*/
|
*/
|
||||||
private Collection $persons;
|
private Collection $persons;
|
||||||
|
|
||||||
@ -74,6 +77,7 @@ class Calendar
|
|||||||
* cascade={"persist", "remove", "merge", "detach"})
|
* cascade={"persist", "remove", "merge", "detach"})
|
||||||
* @ORM\JoinTable(name="chill_calendar.calendar_to_thirdparties")
|
* @ORM\JoinTable(name="chill_calendar.calendar_to_thirdparties")
|
||||||
* @Groups({"read"})
|
* @Groups({"read"})
|
||||||
|
* @Serializer\Groups({"calendar:read"})
|
||||||
*/
|
*/
|
||||||
private Collection $professionals;
|
private Collection $professionals;
|
||||||
|
|
||||||
@ -89,6 +93,7 @@ class Calendar
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\Embedded(class=CommentEmbeddable::class, columnPrefix="comment_")
|
* @ORM\Embedded(class=CommentEmbeddable::class, columnPrefix="comment_")
|
||||||
|
* @Serializer\Groups({"calendar:read"})
|
||||||
*/
|
*/
|
||||||
private CommentEmbeddable $comment;
|
private CommentEmbeddable $comment;
|
||||||
|
|
||||||
@ -96,20 +101,20 @@ class Calendar
|
|||||||
* @ORM\Column(type="datetimetz_immutable")
|
* @ORM\Column(type="datetimetz_immutable")
|
||||||
* @Serializer\Groups({"calendar:read"})
|
* @Serializer\Groups({"calendar:read"})
|
||||||
*/
|
*/
|
||||||
private \DateTimeImmutable $startDate;
|
private ?\DateTimeImmutable $startDate = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\Column(type="datetimetz_immutable")
|
* @ORM\Column(type="datetimetz_immutable")
|
||||||
* @Serializer\Groups({"calendar:read"})
|
* @Serializer\Groups({"calendar:read"})
|
||||||
*/
|
*/
|
||||||
private \DateTimeImmutable $endDate;
|
private ?\DateTimeImmutable $endDate = null;
|
||||||
|
|
||||||
//TODO Lieu
|
//TODO Lieu
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\Column(type="string", length=255)
|
* @ORM\Column(type="string", length=255)
|
||||||
*/
|
*/
|
||||||
private string $status;
|
private ?string $status = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\ManyToOne(targetEntity="CancelReason")
|
* @ORM\ManyToOne(targetEntity="CancelReason")
|
||||||
@ -124,7 +129,7 @@ class Calendar
|
|||||||
/**
|
/**
|
||||||
* @ORM\ManyToOne(targetEntity="Chill\ActivityBundle\Entity\Activity")
|
* @ORM\ManyToOne(targetEntity="Chill\ActivityBundle\Entity\Activity")
|
||||||
*/
|
*/
|
||||||
private Activity $activity;
|
private ?Activity $activity = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\Column(type="boolean", nullable=true)
|
* @ORM\Column(type="boolean", nullable=true)
|
||||||
|
@ -25,21 +25,21 @@ class CalendarRange
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\User")
|
* @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\User")
|
||||||
* @Groups({"read"})
|
* @groups({"read", "write"})
|
||||||
*/
|
*/
|
||||||
private User $user;
|
private ?User $user = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\Column(type="datetimetz_immutable")
|
* @ORM\Column(type="datetimetz_immutable")
|
||||||
* @groups({"read"})
|
* @groups({"read", "write"})
|
||||||
*/
|
*/
|
||||||
private \DateTimeImmutable $startDate;
|
private ?\DateTimeImmutable $startDate = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\Column(type="datetimetz_immutable")
|
* @ORM\Column(type="datetimetz_immutable")
|
||||||
* @groups({"read"})
|
* @groups({"read", "write"})
|
||||||
*/
|
*/
|
||||||
private \DateTimeImmutable $endDate;
|
private ?\DateTimeImmutable $endDate = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\OneToMany(targetEntity=Calendar::class,
|
* @ORM\OneToMany(targetEntity=Calendar::class,
|
||||||
|
@ -0,0 +1,45 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Chill\CalendarBundle\Event;
|
||||||
|
|
||||||
|
use Chill\ActivityBundle\Entity\Activity;
|
||||||
|
use Doctrine\Persistence\Event\LifecycleEventArgs;
|
||||||
|
use Symfony\Component\HttpFoundation\RequestStack;
|
||||||
|
|
||||||
|
class ListenToActivityCreate
|
||||||
|
{
|
||||||
|
|
||||||
|
private RequestStack $requestStack;
|
||||||
|
|
||||||
|
public function __construct(RequestStack $requestStack)
|
||||||
|
{
|
||||||
|
$this->requestStack = $requestStack;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function postPersist(Activity $activity, LifecycleEventArgs $event): void
|
||||||
|
{
|
||||||
|
// Get the calendarId from the request
|
||||||
|
$request = $this->requestStack->getCurrentRequest();
|
||||||
|
|
||||||
|
if (null === $request) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($request->query->has('activityData')) {
|
||||||
|
$activityData = $request->query->get('activityData');
|
||||||
|
if (array_key_exists('calendarId', $activityData)) {
|
||||||
|
$calendarId = $activityData['calendarId'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attach the activity to the calendar
|
||||||
|
$em = $event->getObjectManager();
|
||||||
|
|
||||||
|
$calendar = $em->getRepository(\Chill\CalendarBundle\Entity\Calendar::class)->find($calendarId);
|
||||||
|
$calendar->setActivity($activity);
|
||||||
|
|
||||||
|
$em->persist($calendar);
|
||||||
|
$em->flush();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -37,7 +37,7 @@ class AccompanyingCourseMenuBuilder implements LocalMenuBuilderInterface
|
|||||||
|
|
||||||
if (AccompanyingPeriod::STEP_DRAFT !== $period->getStep()) {
|
if (AccompanyingPeriod::STEP_DRAFT !== $period->getStep()) {
|
||||||
$menu->addChild($this->translator->trans('Calendar'), [
|
$menu->addChild($this->translator->trans('Calendar'), [
|
||||||
'route' => 'chill_calendar_calendar',
|
'route' => 'chill_calendar_calendar_list',
|
||||||
'routeParameters' => [
|
'routeParameters' => [
|
||||||
'accompanying_period_id' => $period->getId(),
|
'accompanying_period_id' => $period->getId(),
|
||||||
]])
|
]])
|
||||||
|
@ -3,7 +3,9 @@
|
|||||||
namespace Chill\CalendarBundle\Repository;
|
namespace Chill\CalendarBundle\Repository;
|
||||||
|
|
||||||
use Chill\CalendarBundle\Entity\Calendar;
|
use Chill\CalendarBundle\Entity\Calendar;
|
||||||
|
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||||
|
use Doctrine\ORM\EntityRepository;
|
||||||
use Doctrine\Persistence\ManagerRegistry;
|
use Doctrine\Persistence\ManagerRegistry;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -14,9 +16,13 @@ use Doctrine\Persistence\ManagerRegistry;
|
|||||||
*/
|
*/
|
||||||
class CalendarRepository extends ServiceEntityRepository
|
class CalendarRepository extends ServiceEntityRepository
|
||||||
{
|
{
|
||||||
|
|
||||||
|
// private EntityRepository $repository;
|
||||||
|
|
||||||
public function __construct(ManagerRegistry $registry)
|
public function __construct(ManagerRegistry $registry)
|
||||||
{
|
{
|
||||||
parent::__construct($registry, Calendar::class);
|
parent::__construct($registry, Calendar::class);
|
||||||
|
// $this->repository = $entityManager->getRepository(AccompanyingPeriodWork::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
// /**
|
// /**
|
||||||
|
@ -0,0 +1,10 @@
|
|||||||
|
services:
|
||||||
|
Chill\CalendarBundle\Event\ListenToActivityCreate:
|
||||||
|
autowire: true
|
||||||
|
autoconfigure: true
|
||||||
|
tags:
|
||||||
|
-
|
||||||
|
name: 'doctrine.orm.entity_listener'
|
||||||
|
event: 'postPersist'
|
||||||
|
entity: 'Chill\ActivityBundle\Entity\Activity'
|
||||||
|
|
@ -8,3 +8,13 @@ div#calendarControls {
|
|||||||
div#fullCalendar{
|
div#fullCalendar{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
span.calendarRangeItems {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-between;
|
||||||
|
a {
|
||||||
|
text-decoration: none;
|
||||||
|
padding: 3px;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,468 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<h2 class="chill-red">{{ $t('edit_your_calendar_range') }}</h2>
|
||||||
|
|
||||||
|
<div class="form-check">
|
||||||
|
<input type="checkbox" id="myCalendar" class="form-check-input" v-model="showMyCalendarWidget" />
|
||||||
|
<label class="form-check-label" for="myCalendar">{{ $t('show_my_calendar') }}</label>
|
||||||
|
</div>
|
||||||
|
<div class="form-check">
|
||||||
|
<input type="checkbox" id="weekends" class="form-check-input" @click="toggleWeekends" />
|
||||||
|
<label class="form-check-label" for="weekends">{{ $t('show_weekends') }}</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<FullCalendar ref="fullCalendar" :options="calendarOptions">
|
||||||
|
<template v-slot:eventContent='arg' >
|
||||||
|
<span class='calendarRangeItems'>
|
||||||
|
<b v-if="arg.event.extendedProps.myCalendar" style="text-decoration: underline" >{{ arg.timeText }}</b>
|
||||||
|
<b v-else-if="!arg.event.extendedProps.myCalendar && arg.event.extendedProps.toDelete" style="text-decoration: line-through red" >{{ arg.timeText }}</b>
|
||||||
|
<b v-else >{{ arg.timeText }}</b>
|
||||||
|
<i> {{ arg.event.title }}</i>
|
||||||
|
<a v-if=!arg.event.extendedProps.myCalendar class="fa fa-fw fa-times"
|
||||||
|
@click.prevent="onClickDelete(arg.event)">
|
||||||
|
</a>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</FullCalendar>
|
||||||
|
<div>
|
||||||
|
<ul class="record_actions">
|
||||||
|
<li>
|
||||||
|
<button class="btn btn-save" :disabled="!dirty"
|
||||||
|
@click.prevent="onClickSave">
|
||||||
|
{{ $t('action.save')}}
|
||||||
|
</button>
|
||||||
|
<span v-if="flag.loading" class="loading">
|
||||||
|
<i class="fa fa-circle-o-notch fa-spin fa-fw"></i>
|
||||||
|
<span class="sr-only">{{ $t('loading') }}</span>
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<button v-if="disableCopyDayButton" class="btn btn-action" disabled>
|
||||||
|
{{ $t('copy_range_to_next_day')}}
|
||||||
|
</button>
|
||||||
|
<button v-else class="btn btn-action"
|
||||||
|
@click.prevent="copyDay">
|
||||||
|
{{ $t('copy_range_from_day')}} {{this.lastNewDate.toLocaleDateString()}} {{ $t('to_the_next_day')}}
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div v-if="newCalendarRanges.length > 0">
|
||||||
|
<h4>{{ $t('new_range_to_save') }}</h4>
|
||||||
|
<ul>
|
||||||
|
<li v-for="i in newCalendarRanges" :key="i.start">
|
||||||
|
{{ i.start.toLocaleString() }} - {{ i.end.toLocaleString() }}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div v-if="updateCalendarRanges.length > 0">
|
||||||
|
<h4>{{ $t('update_range_to_save') }}</h4>
|
||||||
|
<ul>
|
||||||
|
<li v-for="i in updateCalendarRanges" :key="i.start">
|
||||||
|
{{ i.start.toLocaleString() }} - {{ i.end.toLocaleString() }}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div v-if="deleteCalendarRanges.length > 0">
|
||||||
|
<h4>{{ $t('delete_range_to_save') }}</h4>
|
||||||
|
<ul>
|
||||||
|
<li v-for="i in deleteCalendarRanges" :key="i.start">
|
||||||
|
{{ i.start.toLocaleString() }} - {{ i.end.toLocaleString() }}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<teleport to="body">
|
||||||
|
<modal v-if="modal.showModal"
|
||||||
|
:modalDialogClass="modal.modalDialogClass"
|
||||||
|
@close="modal.showModal = false">
|
||||||
|
|
||||||
|
<template v-slot:header>
|
||||||
|
<h2 class="modal-title">{{ this.renderEventDate() }}</h2>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template v-slot:body>
|
||||||
|
<p>{{ $t('by')}} {{this.myCalendarClickedEvent.user.username }}</p>
|
||||||
|
<p>{{ $t('main_user_concerned') }} : {{ this.myCalendarClickedEvent.mainUser.username }}</p>
|
||||||
|
<p v-if="myCalendarClickedEvent.comment.length > 0" >{{ this.myCalendarClickedEvent.comment }}</p>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template v-slot:footer>
|
||||||
|
<ul class="record_actions">
|
||||||
|
<li>
|
||||||
|
<a
|
||||||
|
class="btn btn-show"
|
||||||
|
:href=myCalendarEventShowLink() >
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a
|
||||||
|
class="btn btn-update"
|
||||||
|
:href=myCalendarEventUpdateLink() >
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a
|
||||||
|
class="btn btn-delete"
|
||||||
|
:href=myCalendarEventDeleteLink() >
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
</modal>
|
||||||
|
</teleport>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import '@fullcalendar/core/vdom'; // solves problem with Vite
|
||||||
|
import frLocale from '@fullcalendar/core/locales/fr';
|
||||||
|
import FullCalendar from '@fullcalendar/vue3';
|
||||||
|
import dayGridPlugin from '@fullcalendar/daygrid';
|
||||||
|
import interactionPlugin from '@fullcalendar/interaction';
|
||||||
|
import timeGridPlugin from '@fullcalendar/timegrid';
|
||||||
|
import Modal from 'ChillMainAssets/vuejs/_components/Modal';
|
||||||
|
import { deleteCalendarRange, fetchCalendar, fetchCalendarRangesByUser, patchCalendarRange, postCalendarRange } from '../_api/api';
|
||||||
|
import { mapState } from 'vuex';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "App",
|
||||||
|
components: {
|
||||||
|
FullCalendar,
|
||||||
|
Modal
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
errorMsg: [],
|
||||||
|
modal: {
|
||||||
|
showModal: false,
|
||||||
|
modalDialogClass: "modal-dialog-scrollable modal-m"
|
||||||
|
},
|
||||||
|
flag: {
|
||||||
|
loading: false
|
||||||
|
},
|
||||||
|
userId: window.userId,
|
||||||
|
showMyCalendar: true,
|
||||||
|
myCalendarClickedEvent: null,
|
||||||
|
calendarEvents: {
|
||||||
|
userCalendar: null,
|
||||||
|
userCalendarRange: null,
|
||||||
|
new: {
|
||||||
|
events: [],
|
||||||
|
color: "#3788d8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
lastNewDate: null,
|
||||||
|
disableCopyDayButton: true,
|
||||||
|
calendarOptions: {
|
||||||
|
locale: frLocale,
|
||||||
|
plugins: [ dayGridPlugin, interactionPlugin, timeGridPlugin ],
|
||||||
|
initialView: 'timeGridWeek',
|
||||||
|
initialDate: window.startDate !== undefined ? window.startDate : new Date(),
|
||||||
|
eventSource: [],
|
||||||
|
selectable: true,
|
||||||
|
select: this.onDateSelect,
|
||||||
|
eventChange: this.onEventChange,
|
||||||
|
eventDrop: this.onEventDropOrResize,
|
||||||
|
eventResize: this.onEventDropOrResize,
|
||||||
|
eventClick: this.onEventClick,
|
||||||
|
selectMirror: false,
|
||||||
|
editable: true,
|
||||||
|
weekends: false,
|
||||||
|
headerToolbar: {
|
||||||
|
left: 'prev,next today',
|
||||||
|
center: 'title',
|
||||||
|
right: 'dayGridMonth,timeGridWeek,timeGridDay'
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapState({
|
||||||
|
newCalendarRanges: state => state.newCalendarRanges,
|
||||||
|
updateCalendarRanges: state => state.updateCalendarRanges,
|
||||||
|
deleteCalendarRanges: state => state.deleteCalendarRanges,
|
||||||
|
dirty: state => state.newCalendarRanges.length > 0 || state.updateCalendarRanges.length > 0 || state.deleteCalendarRanges.length > 0
|
||||||
|
}),
|
||||||
|
showMyCalendarWidget: {
|
||||||
|
set(value) {
|
||||||
|
this.toggleMyCalendar(value);
|
||||||
|
this.updateEventsSource();
|
||||||
|
},
|
||||||
|
get() {
|
||||||
|
return this.showMyCalendar;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
init() {
|
||||||
|
this.fetchData();
|
||||||
|
},
|
||||||
|
openModal() {
|
||||||
|
this.modal.showModal = true;
|
||||||
|
},
|
||||||
|
myCalendarEventShowLink() {
|
||||||
|
return `/fr/calendar/calendar/${this.myCalendarClickedEvent.id}/show?user_id=${ this.userId }`
|
||||||
|
},
|
||||||
|
myCalendarEventUpdateLink() {
|
||||||
|
return `/fr/calendar/calendar/${this.myCalendarClickedEvent.id}/edit?user_id=${ this.userId }`
|
||||||
|
},
|
||||||
|
myCalendarEventDeleteLink() {
|
||||||
|
return `/fr/calendar/calendar/${this.myCalendarClickedEvent.id}/delete?user_id=${ this.userId }`
|
||||||
|
},
|
||||||
|
resetCalendar() {
|
||||||
|
this.fetchData();
|
||||||
|
this.calendarEvents.new = {
|
||||||
|
events: [],
|
||||||
|
color: "#3788d8"
|
||||||
|
};
|
||||||
|
this.updateEventsSource();
|
||||||
|
},
|
||||||
|
fetchData() {
|
||||||
|
this.flag.loading = true;
|
||||||
|
fetchCalendarRangesByUser(this.userId).then(calendarRanges => new Promise((resolve, reject) => {
|
||||||
|
let events = calendarRanges.results.map(i =>
|
||||||
|
({
|
||||||
|
start: i.startDate.datetime,
|
||||||
|
end: i.endDate.datetime,
|
||||||
|
calendarRangeId: i.id,
|
||||||
|
toDelete: false
|
||||||
|
})
|
||||||
|
);
|
||||||
|
let calendarRangeEvents = {
|
||||||
|
events: events,
|
||||||
|
borderColor: "#3788d8",
|
||||||
|
backgroundColor: '#ffffff',
|
||||||
|
textColor: '#444444',
|
||||||
|
};
|
||||||
|
this.calendarEvents.userCalendarRange = calendarRangeEvents;
|
||||||
|
|
||||||
|
fetchCalendar(this.userId).then(calendar => new Promise((resolve, reject) => {
|
||||||
|
let events = calendar.results.map(i =>
|
||||||
|
({
|
||||||
|
myCalendar: true,
|
||||||
|
calendarId: i.id,
|
||||||
|
start: i.startDate.datetime,
|
||||||
|
end: i.endDate.datetime,
|
||||||
|
user: i.user,
|
||||||
|
mainUser: i.mainUser,
|
||||||
|
persons: i.persons,
|
||||||
|
professionals: i.professionals,
|
||||||
|
comment: i.comment
|
||||||
|
})
|
||||||
|
);
|
||||||
|
let calendarEventsCurrentUser = {
|
||||||
|
events: events,
|
||||||
|
color: 'darkblue',
|
||||||
|
id: 1000,
|
||||||
|
editable: false
|
||||||
|
};
|
||||||
|
this.calendarEvents.userCalendar = calendarEventsCurrentUser;
|
||||||
|
this.updateEventsSource();
|
||||||
|
this.flag.loading = false;
|
||||||
|
resolve();
|
||||||
|
}));
|
||||||
|
|
||||||
|
resolve();
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
updateEventsSource() {
|
||||||
|
this.calendarOptions.eventSources = [];
|
||||||
|
this.calendarOptions.eventSources.push(this.calendarEvents.new);
|
||||||
|
this.calendarOptions.eventSources.push(this.calendarEvents.userCalendarRange);
|
||||||
|
if (this.showMyCalendar) {
|
||||||
|
this.calendarOptions.eventSources.push(this.calendarEvents.userCalendar);
|
||||||
|
}
|
||||||
|
console.log(this.calendarOptions.eventSources);
|
||||||
|
},
|
||||||
|
toggleMyCalendar(value) {
|
||||||
|
this.showMyCalendar = value;
|
||||||
|
},
|
||||||
|
toggleWeekends: function() {
|
||||||
|
this.calendarOptions.weekends = !this.calendarOptions.weekends;
|
||||||
|
},
|
||||||
|
onDateSelect(payload) {
|
||||||
|
let events = this.calendarEvents.new.events;
|
||||||
|
events.push({
|
||||||
|
start: payload.startStr,
|
||||||
|
end: payload.endStr
|
||||||
|
});
|
||||||
|
this.calendarEvents.new = {
|
||||||
|
events: events,
|
||||||
|
borderColor: "#3788d8",
|
||||||
|
backgroundColor: '#fffadf ',
|
||||||
|
textColor: '#444444',
|
||||||
|
};
|
||||||
|
this.disableCopyDayButton = false;
|
||||||
|
this.lastNewDate = new Date(payload.startStr);
|
||||||
|
this.updateEventsSource();
|
||||||
|
this.$store.dispatch('createRange', payload);
|
||||||
|
},
|
||||||
|
onEventChange(payload) {
|
||||||
|
},
|
||||||
|
onEventDropOrResize(payload) {
|
||||||
|
payload.event.setProp('borderColor', '#3788d8');
|
||||||
|
payload.event.setProp('backgroundColor', '#fffadf');
|
||||||
|
payload.event.setProp('textColor', '#444444');
|
||||||
|
this.$store.dispatch('updateRange', payload);
|
||||||
|
},
|
||||||
|
onEventClick(payload) {
|
||||||
|
if (payload.event.extendedProps.myCalendar) {
|
||||||
|
this.myCalendarClickedEvent = {
|
||||||
|
id: payload.event.extendedProps.calendarId,
|
||||||
|
start: payload.event.start,
|
||||||
|
end: payload.event.end,
|
||||||
|
user: payload.event.extendedProps.user,
|
||||||
|
mainUser: payload.event.extendedProps.mainUser,
|
||||||
|
persons: payload.event.extendedProps.persons,
|
||||||
|
professionals: payload.event.extendedProps.professionals,
|
||||||
|
comment: payload.event.extendedProps.comment
|
||||||
|
};
|
||||||
|
console.log(this.myCalendarClickedEvent)
|
||||||
|
this.openModal();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onClickSave(payload) {
|
||||||
|
this.flag.loading = true;
|
||||||
|
if (this.$store.state.newCalendarRanges.length > 0){
|
||||||
|
Promise.all(this.$store.state.newCalendarRanges.map(cr => {
|
||||||
|
postCalendarRange({
|
||||||
|
user: {
|
||||||
|
type: 'user',
|
||||||
|
id: window.userId,
|
||||||
|
},
|
||||||
|
startDate: {
|
||||||
|
datetime: `${cr.start.toISOString().split('.')[0]}+0000`, //should be like "2021-08-20T15:00:00+0200",
|
||||||
|
},
|
||||||
|
endDate: {
|
||||||
|
datetime: `${cr.end.toISOString().split('.')[0]}+0000`, // TODO check if OK with time zone
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
).then((_r) => this.resetCalendar());
|
||||||
|
|
||||||
|
this.$store.dispatch('clearNewCalendarRanges', payload);
|
||||||
|
}
|
||||||
|
if (this.$store.state.updateCalendarRanges.length > 0){
|
||||||
|
Promise.all(this.$store.state.updateCalendarRanges.map(cr => {
|
||||||
|
patchCalendarRange(cr.id,
|
||||||
|
{
|
||||||
|
startDate: {
|
||||||
|
datetime: `${cr.start.toISOString().split('.')[0]}+0000`, //should be like "2021-08-20T15:00:00+0200",
|
||||||
|
},
|
||||||
|
endDate: {
|
||||||
|
datetime: `${cr.end.toISOString().split('.')[0]}+0000`, // TODO check if OK with time zone
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
).then((_r) => this.resetCalendar());
|
||||||
|
this.$store.dispatch('clearUpdateCalendarRanges', payload);
|
||||||
|
}
|
||||||
|
if (this.$store.state.deleteCalendarRanges.length > 0){
|
||||||
|
Promise.all(this.$store.state.deleteCalendarRanges.map(cr => {
|
||||||
|
deleteCalendarRange(cr.id)
|
||||||
|
})
|
||||||
|
).then((_r) => this.resetCalendar());
|
||||||
|
this.$store.dispatch('clearDeleteCalendarRanges', payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
onClickDelete(payload) {
|
||||||
|
if (payload.extendedProps.hasOwnProperty("calendarRangeId")) {
|
||||||
|
if (payload.extendedProps.toDelete) {
|
||||||
|
payload.setExtendedProp('toDelete', false)
|
||||||
|
payload.setProp('borderColor', '#79bafc');
|
||||||
|
this.$store.dispatch('removeFromDeleteRange', payload);
|
||||||
|
} else {
|
||||||
|
payload.setExtendedProp('toDelete', true)
|
||||||
|
payload.setProp('borderColor', '#dddddd');
|
||||||
|
this.$store.dispatch('deleteRange', payload);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let newEvents = this.calendarEvents.new.events;
|
||||||
|
let filterEvents = newEvents.filter((e) =>
|
||||||
|
e.start !== payload.startStr && e.end !== payload.endStr
|
||||||
|
);
|
||||||
|
this.calendarEvents.new = {
|
||||||
|
events: filterEvents,
|
||||||
|
color: "#3788d8"
|
||||||
|
};
|
||||||
|
|
||||||
|
this.$store.dispatch('removeNewCalendarRanges', payload);
|
||||||
|
|
||||||
|
this.updateEventsSource();
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
isSameDay(date1, date2) {
|
||||||
|
return date1.getFullYear() === date2.getFullYear() &&
|
||||||
|
date1.getMonth() === date2.getMonth() &&
|
||||||
|
date1.getDate() === date2.getDate();
|
||||||
|
},
|
||||||
|
isFriday(date) {
|
||||||
|
return date.getDay() === 5
|
||||||
|
},
|
||||||
|
copyDay(_payload) {
|
||||||
|
console.log(this.calendarEvents.new);
|
||||||
|
if (this.calendarEvents.new.events.length > 0) {
|
||||||
|
// Create the copied events
|
||||||
|
let increment = !this.calendarOptions.weekends && this.isFriday(this.lastNewDate) ? 24*60*60*1000*3 : 24*60*60*1000;
|
||||||
|
let events = this.calendarEvents.new.events.filter(
|
||||||
|
i => this.isSameDay(new Date(i.start), this.lastNewDate)).map(
|
||||||
|
i => {
|
||||||
|
let startDate = new Date(new Date(i.start).getTime() + increment);
|
||||||
|
let endDate = new Date(new Date(i.end).getTime() + increment);
|
||||||
|
return ({
|
||||||
|
start: startDate.toISOString(),
|
||||||
|
end: endDate.toISOString()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
);
|
||||||
|
let copiedEvents = {
|
||||||
|
events: events,
|
||||||
|
color: "#3788d8"
|
||||||
|
};
|
||||||
|
console.log(copiedEvents);
|
||||||
|
|
||||||
|
// Add to the calendar
|
||||||
|
let newEvents = this.calendarEvents.new.events;
|
||||||
|
newEvents.push(...copiedEvents.events);
|
||||||
|
this.calendarEvents.new = {
|
||||||
|
events: newEvents,
|
||||||
|
color: "#3788d8"
|
||||||
|
};
|
||||||
|
this.updateEventsSource();
|
||||||
|
|
||||||
|
// Set the last new date
|
||||||
|
this.lastNewDate = new Date(copiedEvents.events[copiedEvents.events.length - 1].start);
|
||||||
|
|
||||||
|
// Dispatch in store for saving
|
||||||
|
for (let i = 0; i < copiedEvents.events.length; i++) {
|
||||||
|
let eventObj = {
|
||||||
|
start: new Date(copiedEvents.events[i].start),
|
||||||
|
end: new Date(copiedEvents.events[i].end)
|
||||||
|
}
|
||||||
|
this.$store.dispatch('createRange', eventObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
console.log('no new events to copy-paste!')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
renderEventDate() {
|
||||||
|
let start = this.myCalendarClickedEvent.start;
|
||||||
|
let end = this.myCalendarClickedEvent.end;
|
||||||
|
return start.getDate() === end.getDate() ?
|
||||||
|
`${start.toLocaleDateString()}, ${start.toLocaleTimeString()} - ${end.toLocaleTimeString()}` :
|
||||||
|
`${start.toLocaleString()} - ${end.toLocaleString()}`;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
@ -0,0 +1,21 @@
|
|||||||
|
const appMessages = {
|
||||||
|
fr: {
|
||||||
|
edit_your_calendar_range: "Planifiez vos plages de disponibilités",
|
||||||
|
show_my_calendar: "Afficher mon calendrier",
|
||||||
|
show_weekends: "Afficher les week-ends",
|
||||||
|
copy_range_to_next_day: "Copier les plages du jour au jour suivant",
|
||||||
|
copy_range_from_day: "Copier les plages du ",
|
||||||
|
to_the_next_day: " au jour suivant",
|
||||||
|
copy_range_to_next_week: "Copier les plages de la semaine à la semaine suivante",
|
||||||
|
copy_range_how_to: "Créez les plages de disponibilités durant une journée et copiez-les facilement au jour suivant avec ce bouton. Si les week-ends sont cachés, le jour suivant un vendredi sera le lundi.",
|
||||||
|
new_range_to_save: "Nouvelles plages à enregistrer",
|
||||||
|
update_range_to_save: "Plages à modifier",
|
||||||
|
delete_range_to_save: "Plages à supprimer",
|
||||||
|
by: "Par",
|
||||||
|
main_user_concerned: "Utilisateur concerné"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
appMessages
|
||||||
|
};
|
@ -0,0 +1,16 @@
|
|||||||
|
import { createApp } from 'vue';
|
||||||
|
import { _createI18n } from 'ChillMainAssets/vuejs/_js/i18n'
|
||||||
|
import { appMessages } from './i18n'
|
||||||
|
import store from './store'
|
||||||
|
|
||||||
|
import App from './App.vue';
|
||||||
|
|
||||||
|
const i18n = _createI18n(appMessages);
|
||||||
|
|
||||||
|
const app = createApp({
|
||||||
|
template: `<app></app>`,
|
||||||
|
})
|
||||||
|
.use(store)
|
||||||
|
.use(i18n)
|
||||||
|
.component('app', App)
|
||||||
|
.mount('#myCalendar');
|
@ -0,0 +1,89 @@
|
|||||||
|
import 'es6-promise/auto';
|
||||||
|
import { createStore } from 'vuex';
|
||||||
|
import { postCalendarRange, patchCalendarRange, deleteCalendarRange } from '../_api/api';
|
||||||
|
|
||||||
|
const debug = process.env.NODE_ENV !== 'production';
|
||||||
|
|
||||||
|
const store = createStore({
|
||||||
|
strict: debug,
|
||||||
|
state: {
|
||||||
|
newCalendarRanges: [],
|
||||||
|
updateCalendarRanges: [],
|
||||||
|
deleteCalendarRanges: []
|
||||||
|
},
|
||||||
|
mutations: {
|
||||||
|
updateRange(state, payload) {
|
||||||
|
state.updateCalendarRanges.push({
|
||||||
|
id: payload.event.extendedProps.calendarRangeId,
|
||||||
|
start: payload.event.start,
|
||||||
|
end: payload.event.end
|
||||||
|
});
|
||||||
|
},
|
||||||
|
addRange(state, payload) {
|
||||||
|
state.newCalendarRanges.push({
|
||||||
|
start: payload.start,
|
||||||
|
end: payload.end
|
||||||
|
});
|
||||||
|
},
|
||||||
|
deleteRange(state, payload) {
|
||||||
|
state.deleteCalendarRanges.push({
|
||||||
|
id: payload.extendedProps.calendarRangeId,
|
||||||
|
start: payload.start,
|
||||||
|
end: payload.end
|
||||||
|
});
|
||||||
|
},
|
||||||
|
clearNewCalendarRanges(state) {
|
||||||
|
state.newCalendarRanges = [];
|
||||||
|
},
|
||||||
|
clearUpdateCalendarRanges(state) {
|
||||||
|
state.updateCalendarRanges = [];
|
||||||
|
},
|
||||||
|
clearDeleteCalendarRanges(state) {
|
||||||
|
state.deleteCalendarRanges = [];
|
||||||
|
},
|
||||||
|
removeNewCalendarRanges(state, payload) {
|
||||||
|
let filteredCollection = state.newCalendarRanges.filter(
|
||||||
|
(e) => e.start.toString() !== payload.start.toString() && e.end.toString() !== payload.end.toString()
|
||||||
|
)
|
||||||
|
state.newCalendarRanges = filteredCollection;
|
||||||
|
},
|
||||||
|
removeFromDeleteRange(state, payload) {
|
||||||
|
let filteredCollection = state.deleteCalendarRanges.filter(
|
||||||
|
(e) => e.start.toString() !== payload.start.toString() && e.end.toString() !== payload.end.toString()
|
||||||
|
)
|
||||||
|
state.deleteCalendarRanges = filteredCollection;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
createRange({ commit }, payload) {
|
||||||
|
console.log('### action createRange', payload);
|
||||||
|
commit('addRange', payload);
|
||||||
|
},
|
||||||
|
updateRange({ commit }, payload) {
|
||||||
|
console.log('### action updateRange', payload);
|
||||||
|
commit('updateRange', payload);
|
||||||
|
},
|
||||||
|
deleteRange({ commit }, payload) {
|
||||||
|
console.log('### action deleteRange', payload);
|
||||||
|
commit('deleteRange', payload);
|
||||||
|
},
|
||||||
|
clearNewCalendarRanges({ commit }, payload) {
|
||||||
|
commit('clearNewCalendarRanges', payload);
|
||||||
|
},
|
||||||
|
clearUpdateCalendarRanges({ commit }, payload) {
|
||||||
|
commit('clearUpdateCalendarRanges', payload);
|
||||||
|
},
|
||||||
|
clearDeleteCalendarRanges({ commit }, payload) {
|
||||||
|
commit('clearDeleteCalendarRanges', payload);
|
||||||
|
},
|
||||||
|
removeNewCalendarRanges({ commit }, payload) {
|
||||||
|
commit('removeNewCalendarRanges', payload);
|
||||||
|
},
|
||||||
|
removeFromDeleteRange({ commit }, payload) {
|
||||||
|
commit('removeFromDeleteRange', payload);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
export default store;
|
@ -0,0 +1,100 @@
|
|||||||
|
/*
|
||||||
|
* Endpoint chill_api_single_calendar_range
|
||||||
|
* method GET, get Calendar ranges
|
||||||
|
* @returns {Promise} a promise containing all Calendar ranges objects
|
||||||
|
*/
|
||||||
|
const fetchCalendarRanges = () => {
|
||||||
|
const url = `/api/1.0/calendar/calendar-range-available.json`;
|
||||||
|
return fetch(url)
|
||||||
|
.then(response => {
|
||||||
|
if (response.ok) { return response.json(); }
|
||||||
|
throw Error('Error with request resource response');
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchCalendarRangesByUser = (userId) => {
|
||||||
|
const url = `/api/1.0/calendar/calendar-range-available.json?user=${userId}`;
|
||||||
|
return fetch(url)
|
||||||
|
.then(response => {
|
||||||
|
if (response.ok) { return response.json(); }
|
||||||
|
throw Error('Error with request resource response');
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Endpoint chill_api_single_calendar
|
||||||
|
* method GET, get Calendar events, can be filtered by mainUser
|
||||||
|
* @returns {Promise} a promise containing all Calendar objects
|
||||||
|
*/
|
||||||
|
const fetchCalendar = (mainUserId) => {
|
||||||
|
const url = `/api/1.0/calendar/calendar.json?main_user=${mainUserId}&item_per_page=1000`;
|
||||||
|
return fetch(url)
|
||||||
|
.then(response => {
|
||||||
|
if (response.ok) { return response.json(); }
|
||||||
|
throw Error('Error with request resource response');
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Endpoint chill_api_single_calendar_range__entity_create
|
||||||
|
* method POST, post CalendarRange entity
|
||||||
|
*/
|
||||||
|
const postCalendarRange = (body) => {
|
||||||
|
const url = `/api/1.0/calendar/calendar-range.json?`;
|
||||||
|
return fetch(url, {
|
||||||
|
method: 'POST',
|
||||||
|
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');
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Endpoint chill_api_single_calendar_range__entity
|
||||||
|
* method PATCH, patch CalendarRange entity
|
||||||
|
*/
|
||||||
|
const patchCalendarRange = (id, body) => {
|
||||||
|
console.log(body)
|
||||||
|
const url = `/api/1.0/calendar/calendar-range/${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');
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Endpoint chill_api_single_calendar_range__entity
|
||||||
|
* method DELETE, delete CalendarRange entity
|
||||||
|
*/
|
||||||
|
const deleteCalendarRange = (id) => {
|
||||||
|
const url = `/api/1.0/calendar/calendar-range/${id}.json`;
|
||||||
|
return fetch(url, {
|
||||||
|
method: 'DELETE',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json;charset=utf-8'
|
||||||
|
},
|
||||||
|
}).then(response => {
|
||||||
|
if (response.ok) { return response.json(); }
|
||||||
|
throw Error('Error with request resource response');
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export {
|
||||||
|
fetchCalendarRanges,
|
||||||
|
fetchCalendar,
|
||||||
|
fetchCalendarRangesByUser,
|
||||||
|
postCalendarRange,
|
||||||
|
patchCalendarRange,
|
||||||
|
deleteCalendarRange
|
||||||
|
};
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="calendar__controls">
|
<div>
|
||||||
<h2 class="chill-red">{{ $t('choose_your_calendar_user') }}</h2>
|
<h2 class="chill-red">{{ $t('choose_your_calendar_user') }}</h2>
|
||||||
<VueMultiselect
|
<VueMultiselect
|
||||||
name="field"
|
name="field"
|
||||||
@ -31,7 +31,7 @@
|
|||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
import { fetchCalendarRanges, fetchCalendar } from './js/api'
|
import { fetchCalendarRanges, fetchCalendar } from '../../_api/api'
|
||||||
import VueMultiselect from 'vue-multiselect';
|
import VueMultiselect from 'vue-multiselect';
|
||||||
import { whoami } from 'ChillPersonAssets/vuejs/AccompanyingCourse/api';
|
import { whoami } from 'ChillPersonAssets/vuejs/AccompanyingCourse/api';
|
||||||
|
|
||||||
@ -201,12 +201,3 @@ export default {
|
|||||||
|
|
||||||
<style src="vue-multiselect/dist/vue-multiselect.css"></style>
|
<style src="vue-multiselect/dist/vue-multiselect.css"></style>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
div.calendar__controls {
|
|
||||||
background-color: 'black';
|
|
||||||
height: 50%;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: flex-end;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
@ -1,32 +0,0 @@
|
|||||||
/*
|
|
||||||
* Endpoint chill_api_single_calendar_range
|
|
||||||
* method GET, get Calendar ranges
|
|
||||||
* @returns {Promise} a promise containing all Calendar ranges objects
|
|
||||||
*/
|
|
||||||
const fetchCalendarRanges = () => {
|
|
||||||
const url = `/api/1.0/calendar/calendar-range-available.json`;
|
|
||||||
return fetch(url)
|
|
||||||
.then(response => {
|
|
||||||
if (response.ok) { return response.json(); }
|
|
||||||
throw Error('Error with request resource response');
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Endpoint chill_api_single_calendar
|
|
||||||
* method GET, get Calendar events, can be filtered by mainUser
|
|
||||||
* @returns {Promise} a promise containing all Calendar objects
|
|
||||||
*/
|
|
||||||
const fetchCalendar = (mainUserId) => {
|
|
||||||
const url = `/api/1.0/calendar/calendar.json?main_user=${mainUserId}&item_per_page=1000`;
|
|
||||||
return fetch(url)
|
|
||||||
.then(response => {
|
|
||||||
if (response.ok) { return response.json(); }
|
|
||||||
throw Error('Error with request resource response');
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export {
|
|
||||||
fetchCalendarRanges,
|
|
||||||
fetchCalendar
|
|
||||||
};
|
|
@ -1,6 +1,6 @@
|
|||||||
{% extends "@ChillPerson/AccompanyingCourse/layout.html.twig" %}
|
{% extends "@ChillPerson/AccompanyingCourse/layout.html.twig" %}
|
||||||
|
|
||||||
{% set activeRouteKey = 'chill_calendar_calendar' %}
|
{% set activeRouteKey = 'chill_calendar_calendar_list' %}
|
||||||
|
|
||||||
{% block title 'Remove calendar item'|trans %}
|
{% block title 'Remove calendar item'|trans %}
|
||||||
|
|
||||||
@ -9,8 +9,8 @@
|
|||||||
{
|
{
|
||||||
'title' : 'Remove calendar item'|trans,
|
'title' : 'Remove calendar item'|trans,
|
||||||
'confirm_question' : 'Are you sure you want to remove the calendar item?'|trans,
|
'confirm_question' : 'Are you sure you want to remove the calendar item?'|trans,
|
||||||
'cancel_route' : 'chill_calendar_calendar',
|
'cancel_route' : 'chill_calendar_calendar_list',
|
||||||
'cancel_parameters' : { 'accompanying_course_id' : accompanyingCourse.id, 'id' : calendar.id },
|
'cancel_parameters' : { 'accompanying_period_id' : accompanyingCourse.id, 'id' : calendar.id },
|
||||||
'form' : delete_form
|
'form' : delete_form
|
||||||
} ) }}
|
} ) }}
|
||||||
{% endblock %}
|
{% endblock %}
|
@ -0,0 +1,18 @@
|
|||||||
|
{% extends "@ChillMain/layout.html.twig" %}
|
||||||
|
|
||||||
|
{% set user = calendar.user %}
|
||||||
|
|
||||||
|
{% set activeRouteKey = 'chill_calendar_calendar_list' %}
|
||||||
|
|
||||||
|
{% block title 'Remove activity'|trans %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
{{ include('@ChillMain/Util/confirmation_template.html.twig',
|
||||||
|
{
|
||||||
|
'title' : 'Remove calendar item'|trans,
|
||||||
|
'confirm_question' : 'Are you sure you want to remove the calendar item?'|trans,
|
||||||
|
'cancel_route' : 'chill_calendar_calendar_list',
|
||||||
|
'cancel_parameters' : { 'user_id' : calendar.user.id, 'id' : calendar.id },
|
||||||
|
'form' : delete_form
|
||||||
|
} ) }}
|
||||||
|
{% endblock %}
|
@ -1,17 +0,0 @@
|
|||||||
{% extends "@ChillPerson/Person/layout.html.twig" %}
|
|
||||||
|
|
||||||
{% set activeRouteKey = 'chill_activity_activity_list' %}
|
|
||||||
{% set person = activity.person %}
|
|
||||||
|
|
||||||
{% block title 'Remove activity'|trans %}
|
|
||||||
|
|
||||||
{% block personcontent %}
|
|
||||||
{{ include('@ChillMain/Util/confirmation_template.html.twig',
|
|
||||||
{
|
|
||||||
'title' : 'Remove activity'|trans,
|
|
||||||
'confirm_question' : 'Are you sure you want to remove the activity about "%name%" ?'|trans({ '%name%' : person.firstname ~ ' ' ~ person.lastname } ),
|
|
||||||
'cancel_route' : 'chill_activity_activity_list',
|
|
||||||
'cancel_parameters' : { 'person_id' : activity.person.id, 'id' : activity.id },
|
|
||||||
'form' : delete_form
|
|
||||||
} ) }}
|
|
||||||
{% endblock %}
|
|
@ -48,16 +48,20 @@
|
|||||||
{{ form_row(form.sendSMS) }}
|
{{ form_row(form.sendSMS) }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
{% if context == 'user' %}
|
||||||
|
<div id="calendarControls"></div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<div id="fullCalendar"></div>
|
<div id="fullCalendar"></div>
|
||||||
|
|
||||||
<ul class="record_actions sticky-form-buttons">
|
<ul class="record_actions sticky-form-buttons">
|
||||||
<li class="cancel">
|
<li class="cancel">
|
||||||
<a
|
<a
|
||||||
class="btn btn-cancel"
|
class="btn btn-cancel"
|
||||||
{%- if context == 'person' -%}
|
{%- if context == 'user' -%}
|
||||||
href="{{ chill_return_path_or('chill_calendar_calendar', { 'person_id': person.id } )}}"
|
href="{{ chill_return_path_or('chill_calendar_calendar_list', { 'user_id': user.id } )}}"
|
||||||
{%- else -%}
|
{%- elseif context == 'accompanyingCourse' -%}
|
||||||
href="{{ chill_return_path_or('chill_calendar_calendar', { 'accompanying_period_id': accompanyingCourse.id } )}}"
|
href="{{ chill_return_path_or('chill_calendar_calendar_list', { 'accompanying_period_id': accompanyingCourse.id } )}}"
|
||||||
{%- endif -%}
|
{%- endif -%}
|
||||||
>
|
>
|
||||||
{{ 'Cancel'|trans|chill_return_path_label }}
|
{{ 'Cancel'|trans|chill_return_path_label }}
|
||||||
|
@ -35,6 +35,7 @@
|
|||||||
{% block css %}
|
{% block css %}
|
||||||
{{ parent() }}
|
{{ parent() }}
|
||||||
{{ encore_entry_link_tags('vue_calendar') }}
|
{{ encore_entry_link_tags('vue_calendar') }}
|
||||||
|
{{ encore_entry_link_tags('page_calendar') }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block block_post_menu %}
|
{% block block_post_menu %}
|
@ -0,0 +1,36 @@
|
|||||||
|
{% extends "@ChillMain/layout.html.twig" %}
|
||||||
|
|
||||||
|
{% block title 'Update calendar'|trans %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="calendar-edit">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-md-10 col-xxl">
|
||||||
|
|
||||||
|
<div id="calendar"></div> {# <=== vue component #}
|
||||||
|
{% include 'ChillCalendarBundle:Calendar:edit.html.twig' with {'context': 'user'} %}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block js %}
|
||||||
|
{{ parent() }}
|
||||||
|
<script type="text/javascript">
|
||||||
|
window.addEventListener('DOMContentLoaded', function (e) {
|
||||||
|
chill.displayAlertWhenLeavingModifiedForm('form[name="{{ form.vars.form.vars.name }}"]',
|
||||||
|
'{{ "You are going to leave a page with unsubmitted data. Are you sure you want to leave ?"|trans }}');
|
||||||
|
});
|
||||||
|
window.entity = {{ entity_json|json_encode|raw }};
|
||||||
|
window.startDate = {{ entity.startDate|date('Y-m-d H:i:s')|json_encode|raw }};
|
||||||
|
window.endDate = {{ entity.endDate|date('Y-m-d H:i:s')|json_encode|raw }};
|
||||||
|
window.mainUser = {{ entity.mainUser.id }};
|
||||||
|
</script>
|
||||||
|
{{ encore_entry_script_tags('vue_calendar') }}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block css %}
|
||||||
|
{{ parent() }}
|
||||||
|
{{ encore_entry_link_tags('vue_calendar') }}
|
||||||
|
{% endblock %}
|
@ -1,141 +0,0 @@
|
|||||||
{% set user_id = null %}
|
|
||||||
{% if user %}
|
|
||||||
{% set user_id = user.id %}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% set accompanying_course_id = null %}
|
|
||||||
{% if accompanyingCourse %}
|
|
||||||
{% set accompanying_course_id = accompanyingCourse.id %}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<h2>{{ 'Calendar list' |trans }}</h2>
|
|
||||||
|
|
||||||
{% if calendarItems|length == 0 %}
|
|
||||||
<p class="chill-no-data-statement">
|
|
||||||
{{ "There is no calendar items."|trans }}
|
|
||||||
<a href="{{ path('chill_calendar_calendar_new', {'user_id': user_id, 'accompanying_period_id': accompanying_course_id}) }}" class="btn btn-create button-small"></a>
|
|
||||||
</p>
|
|
||||||
{% else %}
|
|
||||||
|
|
||||||
<div class="flex-table list-records context-{{ context }}">
|
|
||||||
|
|
||||||
{% for calendar in calendarItems %}
|
|
||||||
|
|
||||||
<div class="item-bloc">
|
|
||||||
<div class="item-row main">
|
|
||||||
<div class="item-col">
|
|
||||||
|
|
||||||
|
|
||||||
{% if calendar.startDate and calendar.endDate %}
|
|
||||||
{% if calendar.endDate.diff(calendar.startDate).days >= 1 %}
|
|
||||||
<h3>{{ "From the day"|trans }} {{ calendar.startDate|format_datetime('medium', 'short') }} </h3>
|
|
||||||
<h3>{{ "to the day"|trans }} {{ calendar.endDate|format_datetime('medium', 'short') }}</h3>
|
|
||||||
{% else %}
|
|
||||||
<h3>{{ calendar.startDate|format_date('full') }} </h3>
|
|
||||||
<h3>{{ calendar.startDate|format_datetime('none', 'short', locale='fr') }} - {{ calendar.endDate|format_datetime('none', 'short', locale='fr') }}</h3>
|
|
||||||
|
|
||||||
<div class="duration">
|
|
||||||
<p>
|
|
||||||
<i class="fa fa-fw fa-hourglass-end"></i>
|
|
||||||
{{ calendar.endDate.diff(calendar.startDate)|date("%H:%M")}}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if context == 'user' and calendar.accompanyingPeriod is not empty %}
|
|
||||||
<a class="btn btn-sm btn-outline-primary"
|
|
||||||
title="{{ 'Period number %number%'|trans({'%number%': calendar.accompanyingPeriod.id}) }}"
|
|
||||||
href="{{ chill_path_add_return_path(
|
|
||||||
"chill_user_accompanying_course_index",
|
|
||||||
{ 'accompanying_period_id': calendar.accompanyingPeriod.id }
|
|
||||||
) }}"><i class="fa fa-random"></i>
|
|
||||||
</a>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<div class="item-col">
|
|
||||||
<ul class="list-content">
|
|
||||||
{% if calendar.user %}
|
|
||||||
<li>
|
|
||||||
<b>{{ 'by'|trans }}{{ calendar.user.usernameCanonical }}</b>
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if calendar.mainUser is not empty %}
|
|
||||||
<li>
|
|
||||||
<b>{{ 'main user concerned'|trans }}: {{ calendar.mainUser.usernameCanonical }}</b>
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
|
|
||||||
<li>
|
|
||||||
{%- if calendar.comment.isEmpty -%}
|
|
||||||
<span class="chill-no-data-statement">{{ 'No comments'|trans }}</span>
|
|
||||||
{%- else -%}
|
|
||||||
{{ calendar.comment|chill_entity_render_box }}
|
|
||||||
{%- endif -%}
|
|
||||||
</li>
|
|
||||||
|
|
||||||
|
|
||||||
</ul>
|
|
||||||
<ul class="record_actions">
|
|
||||||
<li>
|
|
||||||
<a href="{{ path('chill_calendar_calendar_show', { 'id': calendar.id, 'user_id': user_id, 'accompanying_period_id': accompanying_course_id }) }}" class="btn btn-show "></a>
|
|
||||||
</li>
|
|
||||||
{# TOOD
|
|
||||||
{% if is_granted('CHILL_ACTIVITY_UPDATE', calendar) %}
|
|
||||||
#}
|
|
||||||
<li>
|
|
||||||
<a href="{{ path('chill_calendar_calendar_edit', { 'id': calendar.id, 'user_id': user_id, 'accompanying_period_id': accompanying_course_id }) }}" class="btn btn-update "></a>
|
|
||||||
</li>
|
|
||||||
{# TOOD
|
|
||||||
{% endif %}
|
|
||||||
{% if is_granted('CHILL_ACTIVITY_DELETE', calendar) %}
|
|
||||||
#}
|
|
||||||
<li>
|
|
||||||
<a href="{{ path('chill_calendar_calendar_delete', { 'id': calendar.id, 'user_id' : user_id, 'accompanying_period_id': accompanying_course_id } ) }}" class="btn btn-delete "></a>
|
|
||||||
</li>
|
|
||||||
{#
|
|
||||||
{% endif %}
|
|
||||||
#}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{%
|
|
||||||
if calendar.comment.comment is not empty
|
|
||||||
or calendar.users|length > 0
|
|
||||||
or calendar.thirdParties|length > 0
|
|
||||||
or calendar.users|length > 0
|
|
||||||
%}
|
|
||||||
<div class="item-row details">
|
|
||||||
<div class="item-col">
|
|
||||||
|
|
||||||
{% include 'ChillActivityBundle:Activity:concernedGroups.html.twig' with {'context': context, 'with_display': 'row', 'entity': calendar } %}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% if calendar.comment.comment is not empty %}
|
|
||||||
<div class="item-col comment">
|
|
||||||
{{ calendar.comment|chill_entity_render_box( { 'limit_lines': 3, 'metadata': false } ) }}
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if context != 'user' %}
|
|
||||||
{# TODO set this condition in configuration #}
|
|
||||||
<ul class="record_actions">
|
|
||||||
<li>
|
|
||||||
<a href="{{ path('chill_calendar_calendar_new', {'user_id': user_id, 'accompanying_period_id': accompanying_course_id}) }}" class="btn btn-create">
|
|
||||||
{{ 'Add a new calendar' | trans }}
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
{% endif %}
|
|
@ -4,6 +4,123 @@
|
|||||||
|
|
||||||
{% block title %}{{ 'Calendar list' |trans }}{% endblock title %}
|
{% block title %}{{ 'Calendar list' |trans }}{% endblock title %}
|
||||||
|
|
||||||
|
{% set user_id = null %}
|
||||||
|
{% set accompanying_course_id = accompanyingCourse.id %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
{% include 'ChillCalendarBundle:Calendar:list.html.twig' with {'context': 'accompanyingCourse'} %}
|
|
||||||
|
<h1>{{ 'Calendar list' |trans }}</h1>
|
||||||
|
|
||||||
|
{% if calendarItems|length == 0 %}
|
||||||
|
<p class="chill-no-data-statement">
|
||||||
|
{{ "There is no calendar items."|trans }}
|
||||||
|
<a href="{{ path('chill_calendar_calendar_new', {'user_id': user_id, 'accompanying_period_id': accompanying_course_id}) }}" class="btn btn-create button-small"></a>
|
||||||
|
</p>
|
||||||
|
{% else %}
|
||||||
|
|
||||||
|
<div class="flex-table list-records context-accompanyingCourse">
|
||||||
|
|
||||||
|
{% for calendar in calendarItems %}
|
||||||
|
|
||||||
|
<div class="item-bloc">
|
||||||
|
<div class="item-row main">
|
||||||
|
<div class="item-col">
|
||||||
|
|
||||||
|
{% if calendar.startDate and calendar.endDate %}
|
||||||
|
{% if calendar.endDate.diff(calendar.startDate).days >= 1 %}
|
||||||
|
<h3>{{ "From the day"|trans }} {{ calendar.startDate|format_datetime('medium', 'short') }} </h3>
|
||||||
|
<h3>{{ "to the day"|trans }} {{ calendar.endDate|format_datetime('medium', 'short') }}</h3>
|
||||||
|
{% else %}
|
||||||
|
<h3>{{ calendar.startDate|format_date('full') }} </h3>
|
||||||
|
<h3>{{ calendar.startDate|format_datetime('none', 'short', locale='fr') }} - {{ calendar.endDate|format_datetime('none', 'short', locale='fr') }}</h3>
|
||||||
|
|
||||||
|
<div class="duration">
|
||||||
|
<p>
|
||||||
|
<i class="fa fa-fw fa-hourglass-end"></i>
|
||||||
|
{{ calendar.endDate.diff(calendar.startDate)|date("%H:%M")}}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="item-col">
|
||||||
|
<ul class="list-content">
|
||||||
|
{% if calendar.user %}
|
||||||
|
<li>
|
||||||
|
<b>{{ 'by'|trans }}{{ calendar.user.usernameCanonical }}</b>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if calendar.mainUser is not empty %}
|
||||||
|
<li>
|
||||||
|
<b>{{ 'main user concerned'|trans }}: {{ calendar.mainUser.usernameCanonical }}</b>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
<ul class="record_actions">
|
||||||
|
<li>
|
||||||
|
<a href="{{ path('chill_calendar_calendar_show', { 'id': calendar.id, 'user_id': user_id, 'accompanying_period_id': accompanying_course_id }) }}" class="btn btn-show "></a>
|
||||||
|
</li>
|
||||||
|
{# TOOD
|
||||||
|
{% if is_granted('CHILL_ACTIVITY_UPDATE', calendar) %}
|
||||||
|
#}
|
||||||
|
<li>
|
||||||
|
<a href="{{ path('chill_calendar_calendar_edit', { 'id': calendar.id, 'user_id': user_id, 'accompanying_period_id': accompanying_course_id }) }}" class="btn btn-update "></a>
|
||||||
|
</li>
|
||||||
|
{# TOOD
|
||||||
|
{% endif %}
|
||||||
|
{% if is_granted('CHILL_ACTIVITY_DELETE', calendar) %}
|
||||||
|
#}
|
||||||
|
<li>
|
||||||
|
<a href="{{ path('chill_calendar_calendar_delete', { 'id': calendar.id, 'user_id' : user_id, 'accompanying_period_id': accompanying_course_id } ) }}" class="btn btn-delete "></a>
|
||||||
|
</li>
|
||||||
|
{#
|
||||||
|
{% endif %}
|
||||||
|
#}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{%
|
||||||
|
if calendar.comment.comment is not empty
|
||||||
|
or calendar.users|length > 0
|
||||||
|
or calendar.thirdParties|length > 0
|
||||||
|
or calendar.users|length > 0
|
||||||
|
%}
|
||||||
|
<div class="item-row details">
|
||||||
|
<div class="item-col">
|
||||||
|
|
||||||
|
{% include 'ChillActivityBundle:Activity:concernedGroups.html.twig' with {'context': accompanyingCourse, 'with_display': 'row', 'entity': calendar } %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% if calendar.comment.comment is not empty %}
|
||||||
|
<div class="item-col comment">
|
||||||
|
{{ calendar.comment|chill_entity_render_box( { 'limit_lines': 3, 'metadata': false } ) }}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
{% if calendarItems|length < paginator.getTotalItems %}
|
||||||
|
{{ chill_pagination(paginator) }}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
|
<ul class="record_actions">
|
||||||
|
<li>
|
||||||
|
<a href="{{ path('chill_calendar_calendar_new', {'user_id': user_id, 'accompanying_period_id': accompanying_course_id}) }}" class="btn btn-create">
|
||||||
|
{{ 'Add a new calendar' | trans }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
@ -0,0 +1,26 @@
|
|||||||
|
{% extends "@ChillMain/layout.html.twig" %}
|
||||||
|
|
||||||
|
{% set activeRouteKey = 'chill_calendar_calendar_list' %}
|
||||||
|
|
||||||
|
{% block title %}{{ 'My calendar list' |trans }}{% endblock title %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<h1>{{ 'My calendar list' |trans }}</h1>
|
||||||
|
<div id="myCalendar"></div>
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block js %}
|
||||||
|
{{ parent() }}
|
||||||
|
<script type="text/javascript">
|
||||||
|
window.userId = {{ user.id }};
|
||||||
|
</script>
|
||||||
|
{{ encore_entry_script_tags('vue_mycalendarrange') }}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block css %}
|
||||||
|
{{ parent() }}
|
||||||
|
{{ encore_entry_link_tags('vue_calendar') }}
|
||||||
|
{{ encore_entry_link_tags('page_calendar') }}
|
||||||
|
{% endblock %}
|
@ -51,9 +51,9 @@
|
|||||||
<a
|
<a
|
||||||
class="btn btn-cancel"
|
class="btn btn-cancel"
|
||||||
{%- if context == 'person' -%}
|
{%- if context == 'person' -%}
|
||||||
href="{{ chill_return_path_or('chill_calendar_calendar', { 'person_id': person.id } )}}"
|
href="{{ chill_return_path_or('chill_calendar_calendar_list', { 'person_id': person.id } )}}"
|
||||||
{%- else -%}
|
{%- else -%}
|
||||||
href="{{ chill_return_path_or('chill_calendar_calendar', { 'accompanying_period_id': accompanyingCourse.id } )}}"
|
href="{{ chill_return_path_or('chill_calendar_calendar_list', { 'accompanying_period_id': accompanyingCourse.id } )}}"
|
||||||
{%- endif -%}
|
{%- endif -%}
|
||||||
>
|
>
|
||||||
{{ 'Cancel'|trans|chill_return_path_label }}
|
{{ 'Cancel'|trans|chill_return_path_label }}
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
|
|
||||||
{% block css %}
|
{% block css %}
|
||||||
{{ parent() }}
|
{{ parent() }}
|
||||||
<link rel="stylesheet" href="{{ asset('build/vue_calendar.css') }}"/>
|
{{ encore_entry_link_tags('vue_calendar') }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block block_post_menu %}
|
{% block block_post_menu %}
|
@ -58,24 +58,45 @@
|
|||||||
{% set accompanying_course_id = accompanyingCourse.id %}
|
{% set accompanying_course_id = accompanyingCourse.id %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
{% set user_id = null %}
|
||||||
|
{% if user %}
|
||||||
|
{% set user_id = user.id %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<ul class="record_actions sticky-form-buttons">
|
<ul class="record_actions sticky-form-buttons">
|
||||||
<li class="cancel">
|
<li class="cancel">
|
||||||
<a class="btn btn-cancel" href="{{ path('chill_calendar_calendar', { 'accompanying_period_id': accompanying_course_id } ) }}">
|
<a class="btn btn-cancel" href="{{ path('chill_calendar_calendar_list',
|
||||||
|
{ 'accompanying_period_id': accompanying_course_id, 'user_id': user_id }) }}">
|
||||||
{{ 'Back to the list'|trans }}
|
{{ 'Back to the list'|trans }}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a class="btn btn-update" href="{{ path('chill_calendar_calendar_edit', { 'id': entity.id, 'accompanying_period_id': accompanying_course_id }) }}">
|
<a class="btn btn-create" href="{{ chill_path_add_return_path('chill_activity_activity_new',
|
||||||
|
{ 'accompanying_period_id': accompanying_course_id, 'activityData': activityData }) }}">
|
||||||
|
{{ 'Transform to activity'|trans }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% if accompanyingCourse %}
|
||||||
|
<li>
|
||||||
|
<a class="btn btn-update" href="{{ path('chill_calendar_calendar_edit',
|
||||||
|
{ 'id': entity.id, 'accompanying_period_id': accompanying_course_id }) }}">
|
||||||
{{ 'Edit'|trans }}
|
{{ 'Edit'|trans }}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
{% if user %}
|
||||||
|
<li>
|
||||||
|
<a class="btn btn-update" href="{{ path('chill_calendar_calendar_edit', { 'id': entity.id, 'user_id': user_id }) }}">
|
||||||
|
{{ 'Edit'|trans }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
{# TODO
|
{# TODO
|
||||||
{% if is_granted('CHILL_ACTIVITY_DELETE', entity) %}
|
{% if is_granted('CHILL_ACTIVITY_DELETE', entity) %}
|
||||||
#}
|
#}
|
||||||
|
|
||||||
<li>
|
<li>
|
||||||
<a href="{{ path('chill_calendar_calendar_delete', { 'id': entity.id, 'accompanying_period_id': accompanying_course_id } ) }}" class="btn btn-delete">
|
<a href="{{ path('chill_calendar_calendar_delete', { 'id': entity.id, 'accompanying_period_id': accompanying_course_id, 'user_id': user_id } ) }}" class="btn btn-delete">
|
||||||
{{ 'Delete'|trans }}
|
{{ 'Delete'|trans }}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
@ -0,0 +1,13 @@
|
|||||||
|
{% extends "@ChillMain/layout.html.twig" %}
|
||||||
|
|
||||||
|
{% block title 'Calendar'|trans %}
|
||||||
|
|
||||||
|
{% block content -%}
|
||||||
|
<div class="calendar-show">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-md-10 col-xxl">
|
||||||
|
{% include 'ChillCalendarBundle:Calendar:show.html.twig' with {'context': 'user'} %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock content %}
|
@ -0,0 +1,73 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Chill\CalendarBundle\Tests\Controller;
|
||||||
|
|
||||||
|
use Chill\PersonBundle\Repository\AccompanyingPeriodRepository;
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||||
|
|
||||||
|
class CalendarControllerTest extends WebTestCase
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup before each test method (see phpunit doc)
|
||||||
|
*/
|
||||||
|
public function setUp()
|
||||||
|
{
|
||||||
|
static::bootKernel();
|
||||||
|
$this->client = static::createClient(array(), array(
|
||||||
|
'PHP_AUTH_USER' => 'center a_social',
|
||||||
|
'PHP_AUTH_PW' => 'password',
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function provideAccompanyingPeriod(): iterable
|
||||||
|
{
|
||||||
|
static::bootKernel();
|
||||||
|
$em= static::$container->get(EntityManagerInterface::class);
|
||||||
|
|
||||||
|
$nb = $em->createQueryBuilder()
|
||||||
|
->from(AccompanyingPeriod::class, 'ac')
|
||||||
|
->select('COUNT(ac) AS nb')
|
||||||
|
->getQuery()
|
||||||
|
->getSingleScalarResult()
|
||||||
|
;
|
||||||
|
|
||||||
|
yield [ $em->createQueryBuilder()
|
||||||
|
->from(AccompanyingPeriod::class, 'ac')
|
||||||
|
->select('ac.id')
|
||||||
|
->setFirstResult(\random_int(0, $nb))
|
||||||
|
->setMaxResults(1)
|
||||||
|
->getQuery()
|
||||||
|
->getSingleScalarResult()
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider provideAccompanyingPeriod
|
||||||
|
*/
|
||||||
|
public function testList(int $accompanyingPeriodId)
|
||||||
|
{
|
||||||
|
$this->client->request(
|
||||||
|
Request::METHOD_GET,
|
||||||
|
sprintf('/fr/calendar/calendar/?accompanying_period_id=%d', $accompanyingPeriodId)
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertEquals(200, $this->client->getResponse()->getStatusCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider provideAccompanyingPeriod
|
||||||
|
*/
|
||||||
|
public function testNew(int $accompanyingPeriodId)
|
||||||
|
{
|
||||||
|
$this->client->request(
|
||||||
|
Request::METHOD_GET,
|
||||||
|
sprintf('/fr/calendar/calendar/new?accompanying_period_id=%d', $accompanyingPeriodId)
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertEquals(200, $this->client->getResponse()->getStatusCode());
|
||||||
|
}
|
||||||
|
}
|
@ -8,6 +8,28 @@ servers:
|
|||||||
- url: "/api"
|
- url: "/api"
|
||||||
description: "Your current dev server"
|
description: "Your current dev server"
|
||||||
|
|
||||||
|
components:
|
||||||
|
schemas:
|
||||||
|
Date:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
datetime:
|
||||||
|
type: string
|
||||||
|
format: date-time
|
||||||
|
User:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: integer
|
||||||
|
type:
|
||||||
|
type: string
|
||||||
|
enum:
|
||||||
|
- user
|
||||||
|
username:
|
||||||
|
type: string
|
||||||
|
text:
|
||||||
|
type: string
|
||||||
|
|
||||||
paths:
|
paths:
|
||||||
/1.0/calendar/calendar.json:
|
/1.0/calendar/calendar.json:
|
||||||
get:
|
get:
|
||||||
@ -48,6 +70,34 @@ paths:
|
|||||||
responses:
|
responses:
|
||||||
200:
|
200:
|
||||||
description: "ok"
|
description: "ok"
|
||||||
|
post:
|
||||||
|
tags:
|
||||||
|
- calendar
|
||||||
|
summary: create a new calendar range
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
user:
|
||||||
|
$ref: '#/components/schemas/User'
|
||||||
|
startDate:
|
||||||
|
$ref: '#/components/schemas/Date'
|
||||||
|
endDate:
|
||||||
|
$ref: '#/components/schemas/Date'
|
||||||
|
responses:
|
||||||
|
401:
|
||||||
|
description: "Unauthorized"
|
||||||
|
404:
|
||||||
|
description: "Not found"
|
||||||
|
200:
|
||||||
|
description: "OK"
|
||||||
|
422:
|
||||||
|
description: "Unprocessable entity (validation errors)"
|
||||||
|
400:
|
||||||
|
description: "transition cannot be applyed"
|
||||||
|
|
||||||
/1.0/calendar/calendar-range/{id}.json:
|
/1.0/calendar/calendar-range/{id}.json:
|
||||||
get:
|
get:
|
||||||
@ -70,6 +120,56 @@ paths:
|
|||||||
description: "not found"
|
description: "not found"
|
||||||
401:
|
401:
|
||||||
description: "Unauthorized"
|
description: "Unauthorized"
|
||||||
|
patch:
|
||||||
|
tags:
|
||||||
|
- calendar
|
||||||
|
summary: update a calendar range
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
user:
|
||||||
|
$ref: '#/components/schemas/User'
|
||||||
|
startDate:
|
||||||
|
$ref: '#/components/schemas/Date'
|
||||||
|
endDate:
|
||||||
|
$ref: '#/components/schemas/Date'
|
||||||
|
responses:
|
||||||
|
401:
|
||||||
|
description: "Unauthorized"
|
||||||
|
404:
|
||||||
|
description: "Not found"
|
||||||
|
200:
|
||||||
|
description: "OK"
|
||||||
|
422:
|
||||||
|
description: "Unprocessable entity (validation errors)"
|
||||||
|
400:
|
||||||
|
description: "transition cannot be applyed"
|
||||||
|
delete:
|
||||||
|
tags:
|
||||||
|
- calendar
|
||||||
|
summary: "Remove a calendar range"
|
||||||
|
parameters:
|
||||||
|
- name: id
|
||||||
|
in: path
|
||||||
|
required: true
|
||||||
|
description: The calendar range id
|
||||||
|
schema:
|
||||||
|
type: integer
|
||||||
|
format: integer
|
||||||
|
minimum: 1
|
||||||
|
responses:
|
||||||
|
401:
|
||||||
|
description: "Unauthorized"
|
||||||
|
404:
|
||||||
|
description: "Not found"
|
||||||
|
200:
|
||||||
|
description: "OK"
|
||||||
|
422:
|
||||||
|
description: "object with validation errors"
|
||||||
|
|
||||||
/1.0/calendar/calendar-range-available.json:
|
/1.0/calendar/calendar-range-available.json:
|
||||||
get:
|
get:
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
// this file loads all assets from the Chill calendar bundle
|
// this file loads all assets from the Chill calendar bundle
|
||||||
module.exports = function(encore, entries) {
|
module.exports = function(encore, entries) {
|
||||||
entries.push(__dirname + '/Resources/public/chill/index.js');
|
|
||||||
|
|
||||||
encore.addAliases({
|
encore.addAliases({
|
||||||
ChillCalendarAssets: __dirname + '/Resources/public'
|
ChillCalendarAssets: __dirname + '/Resources/public'
|
||||||
});
|
});
|
||||||
|
|
||||||
encore.addEntry('vue_calendar', __dirname + '/Resources/public/vuejs/Calendar/index.js');
|
encore.addEntry('vue_calendar', __dirname + '/Resources/public/vuejs/Calendar/index.js');
|
||||||
|
encore.addEntry('vue_mycalendarrange', __dirname + '/Resources/public/vuejs/MyCalendarRange/index.js');
|
||||||
|
encore.addEntry('page_calendar', __dirname + '/Resources/public/chill/index.js');
|
||||||
};
|
};
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
Calendar: Rendez-vous
|
Calendar: Rendez-vous
|
||||||
Calendar list: Liste des rendez-vous
|
Calendar list: Liste des rendez-vous
|
||||||
|
My calendar list: Mes rendez-vous
|
||||||
There is no calendar items.: Il n'y a pas de rendez-vous
|
There is no calendar items.: Il n'y a pas de rendez-vous
|
||||||
Remove calendar item: Supprimer le rendez-vous
|
Remove calendar item: Supprimer le rendez-vous
|
||||||
Are you sure you want to remove the calendar item?: Êtes-vous sûr de vouloir supprimer le rendez-vous?
|
Are you sure you want to remove the calendar item?: Êtes-vous sûr de vouloir supprimer le rendez-vous?
|
||||||
@ -23,3 +24,4 @@ Add a new calendar: Ajouter un nouveau rendez-vous
|
|||||||
The calendar item has been successfully removed.: Le rendez-vous a été supprimé
|
The calendar item has been successfully removed.: Le rendez-vous a été supprimé
|
||||||
From the day: Du
|
From the day: Du
|
||||||
to the day: au
|
to the day: au
|
||||||
|
Transform to activity: Transformer en échange
|
@ -23,6 +23,7 @@ use Chill\MainBundle\Security\Authorization\AbstractChillVoter;
|
|||||||
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
|
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
|
||||||
use Chill\MainBundle\Security\ProvideRoleHierarchyInterface;
|
use Chill\MainBundle\Security\ProvideRoleHierarchyInterface;
|
||||||
use Chill\DocStoreBundle\Entity\PersonDocument;
|
use Chill\DocStoreBundle\Entity\PersonDocument;
|
||||||
|
use Chill\MainBundle\Security\Resolver\CenterResolverDispatcher;
|
||||||
use Chill\PersonBundle\Entity\Person;
|
use Chill\PersonBundle\Entity\Person;
|
||||||
use Chill\MainBundle\Entity\User;
|
use Chill\MainBundle\Entity\User;
|
||||||
use Chill\PersonBundle\Security\Authorization\PersonVoter;
|
use Chill\PersonBundle\Security\Authorization\PersonVoter;
|
||||||
@ -42,30 +43,25 @@ class PersonDocumentVoter extends AbstractChillVoter implements ProvideRoleHiera
|
|||||||
const UPDATE = 'CHILL_PERSON_DOCUMENT_UPDATE';
|
const UPDATE = 'CHILL_PERSON_DOCUMENT_UPDATE';
|
||||||
const DELETE = 'CHILL_PERSON_DOCUMENT_DELETE';
|
const DELETE = 'CHILL_PERSON_DOCUMENT_DELETE';
|
||||||
|
|
||||||
/**
|
protected AuthorizationHelper $authorizationHelper;
|
||||||
* @var AuthorizationHelper
|
|
||||||
*/
|
|
||||||
protected $authorizationHelper;
|
|
||||||
|
|
||||||
/**
|
protected AccessDecisionManagerInterface $accessDecisionManager;
|
||||||
* @var AccessDecisionManagerInterface
|
|
||||||
*/
|
|
||||||
protected $accessDecisionManager;
|
|
||||||
|
|
||||||
/**
|
protected LoggerInterface $logger;
|
||||||
* @var LoggerInterface
|
|
||||||
*/
|
protected CenterResolverDispatcher $centerResolverDispatcher;
|
||||||
protected $logger;
|
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
AccessDecisionManagerInterface $accessDecisionManager,
|
AccessDecisionManagerInterface $accessDecisionManager,
|
||||||
AuthorizationHelper $authorizationHelper,
|
AuthorizationHelper $authorizationHelper,
|
||||||
LoggerInterface $logger
|
LoggerInterface $logger//,
|
||||||
|
//CenterResolverDispatcher $centerResolverDispatcher
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
$this->accessDecisionManager = $accessDecisionManager;
|
$this->accessDecisionManager = $accessDecisionManager;
|
||||||
$this->authorizationHelper = $authorizationHelper;
|
$this->authorizationHelper = $authorizationHelper;
|
||||||
$this->logger = $logger;
|
$this->logger = $logger;
|
||||||
|
//$this->centerResolverDispatcher = $centerResolverDispatcher;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getRoles()
|
public function getRoles()
|
||||||
@ -85,7 +81,8 @@ class PersonDocumentVoter extends AbstractChillVoter implements ProvideRoleHiera
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($subject instanceof Person && $attribute === self::CREATE) {
|
if ($subject instanceof Person
|
||||||
|
&& \in_array($attribute, [self::CREATE, self::SEE])) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,6 +104,8 @@ class PersonDocumentVoter extends AbstractChillVoter implements ProvideRoleHiera
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$center = $this->centerResolverDispatcher->resolveCenter($subject);
|
||||||
|
|
||||||
if ($subject instanceof PersonDocument) {
|
if ($subject instanceof PersonDocument) {
|
||||||
return $this->authorizationHelper->userHasAccess($token->getUser(), $subject, $attribute);
|
return $this->authorizationHelper->userHasAccess($token->getUser(), $subject, $attribute);
|
||||||
|
|
||||||
|
@ -87,6 +87,8 @@ class ApiController extends AbstractCRUDController
|
|||||||
return $this->entityPut('_entity', $request, $id, $_format);
|
return $this->entityPut('_entity', $request, $id, $_format);
|
||||||
case Request::METHOD_POST:
|
case Request::METHOD_POST:
|
||||||
return $this->entityPostAction('_entity', $request, $id, $_format);
|
return $this->entityPostAction('_entity', $request, $id, $_format);
|
||||||
|
case Request::METHOD_DELETE:
|
||||||
|
return $this->entityDelete('_entity', $request, $id, $_format);
|
||||||
default:
|
default:
|
||||||
throw new \Symfony\Component\HttpFoundation\Exception\BadRequestException("This method is not implemented");
|
throw new \Symfony\Component\HttpFoundation\Exception\BadRequestException("This method is not implemented");
|
||||||
}
|
}
|
||||||
@ -217,6 +219,54 @@ class ApiController extends AbstractCRUDController
|
|||||||
$this->getContextForSerializationPostAlter($action, $request, $_format, $entity)
|
$this->getContextForSerializationPostAlter($action, $request, $_format, $entity)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
public function entityDelete($action, Request $request, $id, string $_format): Response
|
||||||
|
{
|
||||||
|
$entity = $this->getEntity($action, $id, $request, $_format);
|
||||||
|
|
||||||
|
if (NULL === $entity) {
|
||||||
|
throw $this->createNotFoundException(sprintf("The %s with id %s "
|
||||||
|
. "is not found", $this->getCrudName(), $id));
|
||||||
|
}
|
||||||
|
|
||||||
|
$response = $this->checkACL($action, $request, $_format, $entity);
|
||||||
|
if ($response instanceof Response) {
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
$response = $this->onPostCheckACL($action, $request, $_format, $entity);
|
||||||
|
if ($response instanceof Response) {
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
$response = $this->onBeforeSerialize($action, $request, $_format, $entity);
|
||||||
|
if ($response instanceof Response) {
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
$errors = $this->validate($action, $request, $_format, $entity);
|
||||||
|
|
||||||
|
$response = $this->onAfterValidation($action, $request, $_format, $entity, $errors);
|
||||||
|
if ($response instanceof Response) {
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($errors->count() > 0) {
|
||||||
|
$response = $this->json($errors);
|
||||||
|
$response->setStatusCode(Response::HTTP_UNPROCESSABLE_ENTITY);
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->getDoctrine()->getManager()->remove($entity);
|
||||||
|
$this->getDoctrine()->getManager()->flush();
|
||||||
|
|
||||||
|
$response = $this->onAfterFlush($action, $request, $_format, $entity, $errors);
|
||||||
|
if ($response instanceof Response) {
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->json(Response::HTTP_OK);
|
||||||
|
}
|
||||||
|
|
||||||
protected function onAfterValidation(string $action, Request $request, string $_format, $entity, ConstraintViolationListInterface $errors, array $more = []): ?Response
|
protected function onAfterValidation(string $action, Request $request, string $_format, $entity, ConstraintViolationListInterface $errors, array $more = []): ?Response
|
||||||
{
|
{
|
||||||
|
@ -1141,7 +1141,7 @@ class CRUDController extends AbstractController
|
|||||||
*/
|
*/
|
||||||
protected function getPaginatorFactory(): PaginatorFactory
|
protected function getPaginatorFactory(): PaginatorFactory
|
||||||
{
|
{
|
||||||
return $this->container->get(PaginatorFactory::class);
|
return $this->container->get('chill_main.paginator_factory');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1196,7 +1196,7 @@ class CRUDController extends AbstractController
|
|||||||
return \array_merge(
|
return \array_merge(
|
||||||
parent::getSubscribedServices(),
|
parent::getSubscribedServices(),
|
||||||
[
|
[
|
||||||
PaginatorFactory::class => PaginatorFactory::class,
|
'chill_main.paginator_factory' => PaginatorFactory::class,
|
||||||
'translator' => TranslatorInterface::class,
|
'translator' => TranslatorInterface::class,
|
||||||
AuthorizationHelper::class => AuthorizationHelper::class,
|
AuthorizationHelper::class => AuthorizationHelper::class,
|
||||||
EventDispatcherInterface::class => EventDispatcherInterface::class,
|
EventDispatcherInterface::class => EventDispatcherInterface::class,
|
||||||
|
@ -2,6 +2,12 @@
|
|||||||
|
|
||||||
namespace Chill\MainBundle;
|
namespace Chill\MainBundle;
|
||||||
|
|
||||||
|
use Chill\MainBundle\Routing\LocalMenuBuilderInterface;
|
||||||
|
use Chill\MainBundle\Search\SearchInterface;
|
||||||
|
use Chill\MainBundle\Security\Authorization\ChillVoterInterface;
|
||||||
|
use Chill\MainBundle\Security\ProvideRoleInterface;
|
||||||
|
use Chill\MainBundle\Security\Resolver\CenterResolverInterface;
|
||||||
|
use Chill\MainBundle\Security\Resolver\ScopeResolverInterface;
|
||||||
use Symfony\Component\HttpKernel\Bundle\Bundle;
|
use Symfony\Component\HttpKernel\Bundle\Bundle;
|
||||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||||
use Chill\MainBundle\DependencyInjection\CompilerPass\SearchableServicesCompilerPass;
|
use Chill\MainBundle\DependencyInjection\CompilerPass\SearchableServicesCompilerPass;
|
||||||
@ -23,6 +29,16 @@ class ChillMainBundle extends Bundle
|
|||||||
public function build(ContainerBuilder $container)
|
public function build(ContainerBuilder $container)
|
||||||
{
|
{
|
||||||
parent::build($container);
|
parent::build($container);
|
||||||
|
|
||||||
|
$container->registerForAutoconfiguration(LocalMenuBuilderInterface::class)
|
||||||
|
->addTag('chill.menu_builder');
|
||||||
|
$container->registerForAutoconfiguration(ProvideRoleInterface::class)
|
||||||
|
->addTag('chill.role');
|
||||||
|
$container->registerForAutoconfiguration(CenterResolverInterface::class)
|
||||||
|
->addTag('chill_main.center_resolver');
|
||||||
|
$container->registerForAutoconfiguration(ScopeResolverInterface::class)
|
||||||
|
->addTag('chill_main.scope_resolver');
|
||||||
|
|
||||||
$container->addCompilerPass(new SearchableServicesCompilerPass());
|
$container->addCompilerPass(new SearchableServicesCompilerPass());
|
||||||
$container->addCompilerPass(new ConfigConsistencyCompilerPass());
|
$container->addCompilerPass(new ConfigConsistencyCompilerPass());
|
||||||
$container->addCompilerPass(new TimelineCompilerClass());
|
$container->addCompilerPass(new TimelineCompilerClass());
|
||||||
|
@ -19,6 +19,10 @@
|
|||||||
|
|
||||||
namespace Chill\MainBundle\DependencyInjection;
|
namespace Chill\MainBundle\DependencyInjection;
|
||||||
|
|
||||||
|
use Chill\MainBundle\Doctrine\DQL\STContains;
|
||||||
|
use Chill\MainBundle\Doctrine\DQL\StrictWordSimilarityOPS;
|
||||||
|
use Chill\MainBundle\Entity\UserJob;
|
||||||
|
use Chill\MainBundle\Form\UserJobType;
|
||||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||||
use Symfony\Component\Config\FileLocator;
|
use Symfony\Component\Config\FileLocator;
|
||||||
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
|
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
|
||||||
@ -183,6 +187,8 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface,
|
|||||||
'JSONB_EXISTS_IN_ARRAY' => JsonbExistsInArray::class,
|
'JSONB_EXISTS_IN_ARRAY' => JsonbExistsInArray::class,
|
||||||
'SIMILARITY' => Similarity::class,
|
'SIMILARITY' => Similarity::class,
|
||||||
'OVERLAPSI' => OverlapsI::class,
|
'OVERLAPSI' => OverlapsI::class,
|
||||||
|
'STRICT_WORD_SIMILARITY_OPS' => StrictWordSimilarityOPS::class,
|
||||||
|
'ST_CONTAINS' => STContains::class,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
'hydrators' => [
|
'hydrators' => [
|
||||||
@ -264,6 +270,27 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface,
|
|||||||
protected function prependCruds(ContainerBuilder $container)
|
protected function prependCruds(ContainerBuilder $container)
|
||||||
{
|
{
|
||||||
$container->prependExtensionConfig('chill_main', [
|
$container->prependExtensionConfig('chill_main', [
|
||||||
|
'cruds' => [
|
||||||
|
[
|
||||||
|
'class' => UserJob::class,
|
||||||
|
'name' => 'admin_user_job',
|
||||||
|
'base_path' => '/admin/main/user-job',
|
||||||
|
'base_role' => 'ROLE_ADMIN',
|
||||||
|
'form_class' => UserJobType::class,
|
||||||
|
'actions' => [
|
||||||
|
'index' => [
|
||||||
|
'role' => 'ROLE_ADMIN',
|
||||||
|
'template' => '@ChillMain/UserJob/index.html.twig',
|
||||||
|
],
|
||||||
|
'new' => [
|
||||||
|
'role' => 'ROLE_ADMIN'
|
||||||
|
],
|
||||||
|
'edit' => [
|
||||||
|
'role' => 'ROLE_ADMIN'
|
||||||
|
]
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
'apis' => [
|
'apis' => [
|
||||||
[
|
[
|
||||||
'class' => \Chill\MainBundle\Entity\Address::class,
|
'class' => \Chill\MainBundle\Entity\Address::class,
|
||||||
@ -371,6 +398,26 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface,
|
|||||||
],
|
],
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
'class' => \Chill\MainBundle\Entity\Scope::class,
|
||||||
|
'name' => 'scope',
|
||||||
|
'base_path' => '/api/1.0/main/scope',
|
||||||
|
'base_role' => 'ROLE_USER',
|
||||||
|
'actions' => [
|
||||||
|
'_index' => [
|
||||||
|
'methods' => [
|
||||||
|
Request::METHOD_GET => true,
|
||||||
|
Request::METHOD_HEAD => true
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'_entity' => [
|
||||||
|
'methods' => [
|
||||||
|
Request::METHOD_GET => true,
|
||||||
|
Request::METHOD_HEAD => true,
|
||||||
|
]
|
||||||
|
],
|
||||||
|
]
|
||||||
|
],
|
||||||
]
|
]
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
52
src/Bundle/ChillMainBundle/Doctrine/DQL/STContains.php
Normal file
52
src/Bundle/ChillMainBundle/Doctrine/DQL/STContains.php
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
* Copyright (C) 2018 Champs-Libres Coopérative <info@champs-libres.coop>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
namespace Chill\MainBundle\Doctrine\DQL;
|
||||||
|
|
||||||
|
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
|
||||||
|
use Doctrine\ORM\Query\Lexer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Geometry function 'ST_CONTAINS', added by postgis
|
||||||
|
*/
|
||||||
|
class STContains extends FunctionNode
|
||||||
|
{
|
||||||
|
private $firstPart;
|
||||||
|
|
||||||
|
private $secondPart;
|
||||||
|
|
||||||
|
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
|
||||||
|
{
|
||||||
|
return 'ST_CONTAINS('.$this->firstPart->dispatch($sqlWalker).
|
||||||
|
', ' . $this->secondPart->dispatch($sqlWalker) .")";
|
||||||
|
}
|
||||||
|
|
||||||
|
public function parse(\Doctrine\ORM\Query\Parser $parser)
|
||||||
|
{
|
||||||
|
$parser->match(Lexer::T_IDENTIFIER);
|
||||||
|
$parser->match(Lexer::T_OPEN_PARENTHESIS);
|
||||||
|
|
||||||
|
$this->firstPart = $parser->StringPrimary();
|
||||||
|
|
||||||
|
$parser->match(Lexer::T_COMMA);
|
||||||
|
|
||||||
|
$this->secondPart = $parser->StringPrimary();
|
||||||
|
|
||||||
|
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
|
||||||
|
}
|
||||||
|
}
|
@ -21,11 +21,6 @@ namespace Chill\MainBundle\Doctrine\DQL;
|
|||||||
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
|
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
|
||||||
use Doctrine\ORM\Query\Lexer;
|
use Doctrine\ORM\Query\Lexer;
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
class Similarity extends FunctionNode
|
class Similarity extends FunctionNode
|
||||||
{
|
{
|
||||||
private $firstPart;
|
private $firstPart;
|
||||||
|
@ -0,0 +1,34 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Chill\MainBundle\Doctrine\DQL;
|
||||||
|
|
||||||
|
use Doctrine\ORM\Query\Lexer;
|
||||||
|
use Doctrine\ORM\Query\Parser;
|
||||||
|
use Doctrine\ORM\Query\SqlWalker;
|
||||||
|
|
||||||
|
class StrictWordSimilarityOPS extends \Doctrine\ORM\Query\AST\Functions\FunctionNode
|
||||||
|
{
|
||||||
|
private $firstPart;
|
||||||
|
|
||||||
|
private $secondPart;
|
||||||
|
|
||||||
|
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
|
||||||
|
{
|
||||||
|
return $this->firstPart->dispatch($sqlWalker).
|
||||||
|
' <<% ' . $this->secondPart->dispatch($sqlWalker);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function parse(\Doctrine\ORM\Query\Parser $parser)
|
||||||
|
{
|
||||||
|
$parser->match(Lexer::T_IDENTIFIER);
|
||||||
|
$parser->match(Lexer::T_OPEN_PARENTHESIS);
|
||||||
|
|
||||||
|
$this->firstPart = $parser->StringPrimary();
|
||||||
|
|
||||||
|
$parser->match(Lexer::T_COMMA);
|
||||||
|
|
||||||
|
$this->secondPart = $parser->StringPrimary();
|
||||||
|
|
||||||
|
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
|
||||||
|
}
|
||||||
|
}
|
@ -21,7 +21,7 @@ class PointType extends Type {
|
|||||||
*
|
*
|
||||||
* @param array $fieldDeclaration
|
* @param array $fieldDeclaration
|
||||||
* @param AbstractPlatform $platform
|
* @param AbstractPlatform $platform
|
||||||
* @return type
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getSqlDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
|
public function getSqlDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
|
||||||
{
|
{
|
||||||
@ -32,7 +32,7 @@ class PointType extends Type {
|
|||||||
*
|
*
|
||||||
* @param type $value
|
* @param type $value
|
||||||
* @param AbstractPlatform $platform
|
* @param AbstractPlatform $platform
|
||||||
* @return Point
|
* @return ?Point
|
||||||
*/
|
*/
|
||||||
public function convertToPHPValue($value, AbstractPlatform $platform)
|
public function convertToPHPValue($value, AbstractPlatform $platform)
|
||||||
{
|
{
|
||||||
|
@ -383,6 +383,16 @@ class Address
|
|||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function createFromAddressReference(AddressReference $original): Address
|
||||||
|
{
|
||||||
|
return (new Address())
|
||||||
|
->setPoint($original->getPoint())
|
||||||
|
->setPostcode($original->getPostcode())
|
||||||
|
->setStreet($original->getStreet())
|
||||||
|
->setStreetNumber($original->getStreetNumber())
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
public function getStreet(): ?string
|
public function getStreet(): ?string
|
||||||
{
|
{
|
||||||
return $this->street;
|
return $this->street;
|
||||||
|
@ -0,0 +1,8 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Chill\MainBundle\Entity;
|
||||||
|
|
||||||
|
interface HasCentersInterface
|
||||||
|
{
|
||||||
|
public function getCenters(): ?iterable;
|
||||||
|
}
|
11
src/Bundle/ChillMainBundle/Entity/HasScopesInterface.php
Normal file
11
src/Bundle/ChillMainBundle/Entity/HasScopesInterface.php
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Chill\MainBundle\Entity;
|
||||||
|
|
||||||
|
interface HasScopesInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @return array|Scope[]
|
||||||
|
*/
|
||||||
|
public function getScopes(): iterable;
|
||||||
|
}
|
@ -5,6 +5,7 @@ namespace Chill\MainBundle\Entity;
|
|||||||
use Doctrine\ORM\Mapping as ORM;
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
use Doctrine\Common\Collections\Collection;
|
use Doctrine\Common\Collections\Collection;
|
||||||
use Doctrine\Common\Collections\ArrayCollection;
|
use Doctrine\Common\Collections\ArrayCollection;
|
||||||
|
use Chill\MainBundle\Entity\UserJob;
|
||||||
use Symfony\Component\Security\Core\User\AdvancedUserInterface;
|
use Symfony\Component\Security\Core\User\AdvancedUserInterface;
|
||||||
use Symfony\Component\Validator\Context\ExecutionContextInterface;
|
use Symfony\Component\Validator\Context\ExecutionContextInterface;
|
||||||
use Symfony\Component\Serializer\Annotation\DiscriminatorMap;
|
use Symfony\Component\Serializer\Annotation\DiscriminatorMap;
|
||||||
@ -43,10 +44,16 @@ class User implements AdvancedUserInterface {
|
|||||||
* @ORM\Column(
|
* @ORM\Column(
|
||||||
* type="string",
|
* type="string",
|
||||||
* length=80,
|
* length=80,
|
||||||
* unique=true)
|
* unique=true,
|
||||||
|
* nullable=true)
|
||||||
*/
|
*/
|
||||||
private $usernameCanonical;
|
private $usernameCanonical;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Column(type="string", length=200)
|
||||||
|
*/
|
||||||
|
private string $label = '';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string
|
* @var string
|
||||||
*
|
*
|
||||||
@ -113,6 +120,24 @@ class User implements AdvancedUserInterface {
|
|||||||
*/
|
*/
|
||||||
private $attributes;
|
private $attributes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Center|null
|
||||||
|
* @ORM\ManyToOne(targetEntity=Center::class)
|
||||||
|
*/
|
||||||
|
private ?Center $mainCenter = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Scope|null
|
||||||
|
* @ORM\ManyToOne(targetEntity=Scope::class)
|
||||||
|
*/
|
||||||
|
private ?Scope $mainScope = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var UserJob|null
|
||||||
|
* @ORM\ManyToOne(targetEntity=UserJob::class)
|
||||||
|
*/
|
||||||
|
private ?UserJob $userJob = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User constructor.
|
* User constructor.
|
||||||
*/
|
*/
|
||||||
@ -126,7 +151,7 @@ class User implements AdvancedUserInterface {
|
|||||||
*/
|
*/
|
||||||
public function __toString()
|
public function __toString()
|
||||||
{
|
{
|
||||||
return $this->getUsername();
|
return $this->getLabel();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -149,6 +174,10 @@ class User implements AdvancedUserInterface {
|
|||||||
{
|
{
|
||||||
$this->username = $name;
|
$this->username = $name;
|
||||||
|
|
||||||
|
if (empty($this->getLabel())) {
|
||||||
|
$this->setLabel($name);
|
||||||
|
}
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -384,4 +413,76 @@ class User implements AdvancedUserInterface {
|
|||||||
|
|
||||||
return $this->attributes;
|
return $this->attributes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getLabel(): string
|
||||||
|
{
|
||||||
|
return $this->label;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $label
|
||||||
|
* @return User
|
||||||
|
*/
|
||||||
|
public function setLabel(string $label): User
|
||||||
|
{
|
||||||
|
$this->label = $label;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Center|null
|
||||||
|
*/
|
||||||
|
public function getMainCenter(): ?Center
|
||||||
|
{
|
||||||
|
return $this->mainCenter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Center|null $mainCenter
|
||||||
|
* @return User
|
||||||
|
*/
|
||||||
|
public function setMainCenter(?Center $mainCenter): User
|
||||||
|
{
|
||||||
|
$this->mainCenter = $mainCenter;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Scope|null
|
||||||
|
*/
|
||||||
|
public function getMainScope(): ?Scope
|
||||||
|
{
|
||||||
|
return $this->mainScope;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Scope|null $mainScope
|
||||||
|
* @return User
|
||||||
|
*/
|
||||||
|
public function setMainScope(?Scope $mainScope): User
|
||||||
|
{
|
||||||
|
$this->mainScope = $mainScope;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return UserJob|null
|
||||||
|
*/
|
||||||
|
public function getUserJob(): ?UserJob
|
||||||
|
{
|
||||||
|
return $this->userJob;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param UserJob|null $userJob
|
||||||
|
* @return User
|
||||||
|
*/
|
||||||
|
public function setUserJob(?UserJob $userJob): User
|
||||||
|
{
|
||||||
|
$this->userJob = $userJob;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
76
src/Bundle/ChillMainBundle/Entity/UserJob.php
Normal file
76
src/Bundle/ChillMainBundle/Entity/UserJob.php
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Chill\MainBundle\Entity;
|
||||||
|
|
||||||
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Entity
|
||||||
|
* @ORM\Table("chill_main_user_job")
|
||||||
|
*/
|
||||||
|
class UserJob
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Id
|
||||||
|
* @ORM\Column(name="id", type="integer")
|
||||||
|
* @ORM\GeneratedValue(strategy="AUTO")
|
||||||
|
*/
|
||||||
|
protected ?int $id = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array|string[]A
|
||||||
|
* @ORM\Column(name="label", type="json")
|
||||||
|
*/
|
||||||
|
protected array $label = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var bool
|
||||||
|
* @ORM\Column(name="active", type="boolean")
|
||||||
|
*/
|
||||||
|
protected bool $active = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return int|null
|
||||||
|
*/
|
||||||
|
public function getId(): ?int
|
||||||
|
{
|
||||||
|
return $this->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array|string[]
|
||||||
|
*/
|
||||||
|
public function getLabel(): array
|
||||||
|
{
|
||||||
|
return $this->label;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array|string[] $label
|
||||||
|
* @return UserJob
|
||||||
|
*/
|
||||||
|
public function setLabel(array $label): UserJob
|
||||||
|
{
|
||||||
|
$this->label = $label;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isActive(): bool
|
||||||
|
{
|
||||||
|
return $this->active;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param bool $active
|
||||||
|
* @return UserJob
|
||||||
|
*/
|
||||||
|
public function setActive(bool $active): UserJob
|
||||||
|
{
|
||||||
|
$this->active = $active;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
}
|
36
src/Bundle/ChillMainBundle/Form/Event/CustomizeFormEvent.php
Normal file
36
src/Bundle/ChillMainBundle/Form/Event/CustomizeFormEvent.php
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Chill\MainBundle\Form\Event;
|
||||||
|
|
||||||
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
|
||||||
|
class CustomizeFormEvent extends \Symfony\Component\EventDispatcher\Event
|
||||||
|
{
|
||||||
|
const NAME = 'chill_main.customize_form';
|
||||||
|
|
||||||
|
protected string $type;
|
||||||
|
|
||||||
|
protected FormBuilderInterface $builder;
|
||||||
|
|
||||||
|
public function __construct(string $type, FormBuilderInterface $builder)
|
||||||
|
{
|
||||||
|
$this->type = $type;
|
||||||
|
$this->builder = $builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getType(): string
|
||||||
|
{
|
||||||
|
return $this->type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return FormBuilderInterface
|
||||||
|
*/
|
||||||
|
public function getBuilder(): FormBuilderInterface
|
||||||
|
{
|
||||||
|
return $this->builder;
|
||||||
|
}
|
||||||
|
}
|
@ -95,9 +95,12 @@ class CenterType extends AbstractType
|
|||||||
public function configureOptions(OptionsResolver $resolver)
|
public function configureOptions(OptionsResolver $resolver)
|
||||||
{
|
{
|
||||||
if (count($this->reachableCenters) > 1) {
|
if (count($this->reachableCenters) > 1) {
|
||||||
$resolver->setDefault('class', Center::class);
|
$resolver->setDefault('class', Center::class)
|
||||||
$resolver->setDefault('choices', $this->reachableCenters);
|
->setDefault('choices', $this->reachableCenters)
|
||||||
|
->setDefault('placeholder', 'Pick a center')
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -146,14 +146,7 @@ class ScopePickerType extends AbstractType
|
|||||||
->setParameter('center', $center->getId())
|
->setParameter('center', $center->getId())
|
||||||
// role constraints
|
// role constraints
|
||||||
->andWhere($qb->expr()->in('rs.role', ':roles'))
|
->andWhere($qb->expr()->in('rs.role', ':roles'))
|
||||||
->setParameter(
|
->setParameter('roles', $roles)
|
||||||
'roles', \array_map(
|
|
||||||
function (Role $role) {
|
|
||||||
return $role->getRole();
|
|
||||||
},
|
|
||||||
$roles
|
|
||||||
)
|
|
||||||
)
|
|
||||||
// user contraint
|
// user contraint
|
||||||
->andWhere(':user MEMBER OF gc.users')
|
->andWhere(':user MEMBER OF gc.users')
|
||||||
->setParameter('user', $this->tokenStorage->getToken()->getUser());
|
->setParameter('user', $this->tokenStorage->getToken()->getUser());
|
||||||
|
27
src/Bundle/ChillMainBundle/Form/UserJobType.php
Normal file
27
src/Bundle/ChillMainBundle/Form/UserJobType.php
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Chill\MainBundle\Form;
|
||||||
|
|
||||||
|
use Chill\MainBundle\Form\Type\TranslatableStringFormType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||||
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
|
||||||
|
class UserJobType extends \Symfony\Component\Form\AbstractType
|
||||||
|
{
|
||||||
|
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||||
|
{
|
||||||
|
$builder
|
||||||
|
->add('label', TranslatableStringFormType::class, [
|
||||||
|
'label' => 'Label',
|
||||||
|
'required' => true
|
||||||
|
])
|
||||||
|
->add('active', ChoiceType::class, [
|
||||||
|
'choices' => [
|
||||||
|
'Active' => true,
|
||||||
|
'Inactive' => false
|
||||||
|
]
|
||||||
|
])
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -2,7 +2,15 @@
|
|||||||
|
|
||||||
namespace Chill\MainBundle\Form;
|
namespace Chill\MainBundle\Form;
|
||||||
|
|
||||||
|
use Chill\MainBundle\Entity\Center;
|
||||||
|
use Chill\MainBundle\Entity\Scope;
|
||||||
|
use Chill\MainBundle\Entity\UserJob;
|
||||||
|
use Chill\MainBundle\Templating\TranslatableStringHelper;
|
||||||
|
use Doctrine\ORM\EntityRepository;
|
||||||
|
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
||||||
use Symfony\Component\Form\AbstractType;
|
use Symfony\Component\Form\AbstractType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\EmailType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||||
use Symfony\Component\Form\FormBuilderInterface;
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||||
@ -16,6 +24,16 @@ use Chill\MainBundle\Form\UserPasswordType;
|
|||||||
|
|
||||||
class UserType extends AbstractType
|
class UserType extends AbstractType
|
||||||
{
|
{
|
||||||
|
private TranslatableStringHelper $translatableStringHelper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param TranslatableStringHelper $translatableStringHelper
|
||||||
|
*/
|
||||||
|
public function __construct(TranslatableStringHelper $translatableStringHelper)
|
||||||
|
{
|
||||||
|
$this->translatableStringHelper = $translatableStringHelper;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param FormBuilderInterface $builder
|
* @param FormBuilderInterface $builder
|
||||||
* @param array $options
|
* @param array $options
|
||||||
@ -24,7 +42,40 @@ class UserType extends AbstractType
|
|||||||
{
|
{
|
||||||
$builder
|
$builder
|
||||||
->add('username')
|
->add('username')
|
||||||
->add('email')
|
->add('email', EmailType::class, [
|
||||||
|
'required' => true
|
||||||
|
])
|
||||||
|
->add('label', TextType::class)
|
||||||
|
->add('mainCenter', EntityType::class, [
|
||||||
|
'label' => 'main center',
|
||||||
|
'required' => false,
|
||||||
|
'placeholder' => 'choose a main center',
|
||||||
|
'class' => Center::class,
|
||||||
|
'query_builder' => function (EntityRepository $er) {
|
||||||
|
$qb = $er->createQueryBuilder('c');
|
||||||
|
$qb->addOrderBy('c.name');
|
||||||
|
|
||||||
|
return $qb;
|
||||||
|
}
|
||||||
|
])
|
||||||
|
->add('mainScope', EntityType::class, [
|
||||||
|
'label' => 'Choose a main scope',
|
||||||
|
'required' => false,
|
||||||
|
'placeholder' => 'choose a main scope',
|
||||||
|
'class' => Scope::class,
|
||||||
|
'choice_label' => function (Scope $c) {
|
||||||
|
return $this->translatableStringHelper->localize($c->getName());
|
||||||
|
},
|
||||||
|
])
|
||||||
|
->add('userJob', EntityType::class, [
|
||||||
|
'label' => 'Choose a job',
|
||||||
|
'required' => false,
|
||||||
|
'placeholder' => 'choose a job',
|
||||||
|
'class' => UserJob::class,
|
||||||
|
'choice_label' => function (UserJob $c) {
|
||||||
|
return $this->translatableStringHelper->localize($c->getLabel());
|
||||||
|
},
|
||||||
|
])
|
||||||
;
|
;
|
||||||
if ($options['is_creation']) {
|
if ($options['is_creation']) {
|
||||||
$builder->add('plainPassword', RepeatedType::class, array(
|
$builder->add('plainPassword', RepeatedType::class, array(
|
||||||
|
@ -36,6 +36,14 @@ final class AddressReferenceRepository implements ObjectRepository
|
|||||||
return $this->repository->findAll();
|
return $this->repository->findAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function countAll(): int
|
||||||
|
{
|
||||||
|
$qb = $this->repository->createQueryBuilder('ar');
|
||||||
|
$qb->select('count(ar.id)');
|
||||||
|
|
||||||
|
return $qb->getQuery()->getSingleScalarResult();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return AddressReference[]
|
* @return AddressReference[]
|
||||||
*/
|
*/
|
||||||
|
@ -207,7 +207,7 @@ footer.footer {
|
|||||||
/// titles
|
/// titles
|
||||||
h1, h2,
|
h1, h2,
|
||||||
.h1, .h2 {
|
.h1, .h2 {
|
||||||
font-weight: $headings-font-weight + 200;
|
font-weight: $headings-font-weight + 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// typography
|
/// typography
|
||||||
@ -276,6 +276,20 @@ div.metadata {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// chill help tooltip
|
||||||
|
|
||||||
|
.chill-help-tooltip {
|
||||||
|
&::before {
|
||||||
|
content: '\f05a';
|
||||||
|
color: $chill-pink;
|
||||||
|
font-family: ForkAwesome;
|
||||||
|
font-style: normal;
|
||||||
|
font-size: 120%;
|
||||||
|
cursor: pointer;
|
||||||
|
margin: auto 0.3em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// display definition list
|
/// display definition list
|
||||||
// with dt and dd on same line
|
// with dt and dd on same line
|
||||||
|
|
||||||
|
@ -19,6 +19,8 @@ $chill-theme-buttons: (
|
|||||||
"view": $chill-blue,
|
"view": $chill-blue,
|
||||||
"misc": $gray-300,
|
"misc": $gray-300,
|
||||||
"cancel": $gray-300,
|
"cancel": $gray-300,
|
||||||
|
"choose": $gray-300,
|
||||||
|
"unlink": $chill-red,
|
||||||
);
|
);
|
||||||
|
|
||||||
@each $button, $color in $chill-theme-buttons {
|
@each $button, $color in $chill-theme-buttons {
|
||||||
@ -44,6 +46,7 @@ $chill-theme-buttons: (
|
|||||||
&.btn-delete,
|
&.btn-delete,
|
||||||
&.btn-danger,
|
&.btn-danger,
|
||||||
&.btn-remove,
|
&.btn-remove,
|
||||||
|
&.btn-unlink,
|
||||||
&.btn-action,
|
&.btn-action,
|
||||||
&.btn-edit,
|
&.btn-edit,
|
||||||
&.btn-update {
|
&.btn-update {
|
||||||
@ -66,8 +69,10 @@ $chill-theme-buttons: (
|
|||||||
// &.btn-submit::before,
|
// &.btn-submit::before,
|
||||||
// &.btn-reset::before,
|
// &.btn-reset::before,
|
||||||
// &.btn-action::before,
|
// &.btn-action::before,
|
||||||
|
&.btn-unlink::before,
|
||||||
&.btn-delete::before,
|
&.btn-delete::before,
|
||||||
&.btn-remove::before,
|
&.btn-remove::before,
|
||||||
|
&.btn-choose::before,
|
||||||
&.btn-cancel::before {
|
&.btn-cancel::before {
|
||||||
font: normal normal normal 14px/1 ForkAwesome;
|
font: normal normal normal 14px/1 ForkAwesome;
|
||||||
margin-right: 0.5em;
|
margin-right: 0.5em;
|
||||||
@ -91,6 +96,8 @@ $chill-theme-buttons: (
|
|||||||
&.btn-delete::before { content: "\f1f8"; } // fa-trash
|
&.btn-delete::before { content: "\f1f8"; } // fa-trash
|
||||||
&.btn-remove::before { content: "\f00d"; } // fa-times
|
&.btn-remove::before { content: "\f00d"; } // fa-times
|
||||||
&.btn-cancel::before { content: "\f060"; } // fa-arrow-left
|
&.btn-cancel::before { content: "\f060"; } // fa-arrow-left
|
||||||
|
&.btn-choose::before { content: "\f00c"; } // fa-check // f046 fa-check-square-o
|
||||||
|
&.btn-unlink::before { content: "\f127"; } // fa-chain-broken
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
// See Assets Album page:
|
||||||
|
// http://localhost:8001/_dev/assets
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* __FLEX-TABLE_________
|
* __FLEX-TABLE_________
|
||||||
* FLEX RESPONSIVE TABLE/BLOCK PRESENTATION
|
* FLEX RESPONSIVE TABLE/BLOCK PRESENTATION
|
||||||
@ -175,13 +178,13 @@ div.wrap-list {
|
|||||||
border: 1px solid $black;
|
border: 1px solid $black;
|
||||||
|
|
||||||
div.wl-col.title {
|
div.wl-col.title {
|
||||||
background-color: $yellow;
|
background-color: yellow;
|
||||||
}
|
}
|
||||||
div.wl-col.list {
|
div.wl-col.list {
|
||||||
background-color: $green;
|
background-color: cyan;
|
||||||
|
|
||||||
p.wl-item {
|
p.wl-item {
|
||||||
background-color: $orange;
|
background-color: orange;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -256,3 +259,53 @@ div.wrap-header {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FLOATBUTTON
|
||||||
|
* p-ê pas convaincant: cet asset est toujours en observation
|
||||||
|
*/
|
||||||
|
|
||||||
|
div.float-button {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
div.box {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
div.action {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.top {
|
||||||
|
div.action {
|
||||||
|
padding: 0 0 1em 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
// avoid a position relative that make links unclickable
|
||||||
|
.fa-ul > li {
|
||||||
|
position: initial;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.bottom {
|
||||||
|
display: flex;
|
||||||
|
overflow: hidden;
|
||||||
|
div.action {
|
||||||
|
height: calc(100% - 0em);
|
||||||
|
shape-outside: inset(calc(100% - 2em) 0 0);
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-end;
|
||||||
|
padding: 0 0 0 1em;
|
||||||
|
* {
|
||||||
|
align-self: flex-end !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.debug {
|
||||||
|
padding: 1em;
|
||||||
|
border: 1px solid black;
|
||||||
|
background-color: yellow;
|
||||||
|
div.action {
|
||||||
|
background-color: transparentize(#00ffff, 0.4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -98,6 +98,9 @@ section.chill-entity {
|
|||||||
&.date-since {}
|
&.date-since {}
|
||||||
&.date-until {}
|
&.date-until {}
|
||||||
}
|
}
|
||||||
|
.address-more {
|
||||||
|
margin-bottom: 1em;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// used for comment-embeddable
|
// used for comment-embeddable
|
||||||
|
17
src/Bundle/ChillMainBundle/Resources/public/lib/api/scope.js
Normal file
17
src/Bundle/ChillMainBundle/Resources/public/lib/api/scope.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
const fetchScopes = () => {
|
||||||
|
return window.fetch('/api/1.0/main/scope.json').then(response => {
|
||||||
|
if (response.ok) {
|
||||||
|
return response.json();
|
||||||
|
}
|
||||||
|
}).then(data => {
|
||||||
|
console.log(data);
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
console.log(data);
|
||||||
|
resolve(data.results);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export {
|
||||||
|
fetchScopes
|
||||||
|
};
|
@ -479,7 +479,7 @@ $font-sizes: (
|
|||||||
$headings-margin-bottom: $spacer / 2 !default;
|
$headings-margin-bottom: $spacer / 2 !default;
|
||||||
$headings-font-family: null !default;
|
$headings-font-family: null !default;
|
||||||
$headings-font-style: null !default;
|
$headings-font-style: null !default;
|
||||||
$headings-font-weight: 500 !default;
|
$headings-font-weight: 600 !default;
|
||||||
$headings-line-height: 1.2 !default;
|
$headings-line-height: 1.2 !default;
|
||||||
$headings-color: null !default;
|
$headings-color: null !default;
|
||||||
// scss-docs-end headings-variables
|
// scss-docs-end headings-variables
|
||||||
|
@ -52,7 +52,7 @@ Fields.forEach(function(field) {
|
|||||||
ClassicEditor
|
ClassicEditor
|
||||||
.create( field )
|
.create( field )
|
||||||
.then( editor => {
|
.then( editor => {
|
||||||
console.log( 'CkEditor was initialized', editor );
|
//console.log( 'CkEditor was initialized', editor );
|
||||||
})
|
})
|
||||||
.catch( error => {
|
.catch( error => {
|
||||||
console.error( error.stack );
|
console.error( error.stack );
|
||||||
|
@ -1,85 +1,106 @@
|
|||||||
<template>
|
<template>
|
||||||
|
|
||||||
<div v-for="error in displayErrors" class="alert alert-danger my-2">
|
|
||||||
{{ error }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<add-address
|
<add-address
|
||||||
v-bind:key="context.entity.type"
|
v-bind:key="key"
|
||||||
v-bind:context="context"
|
v-bind:context="context"
|
||||||
v-bind:options="addAddress.options"
|
v-bind:options="options"
|
||||||
v-bind:result="addAddress.result"
|
v-bind:addressChangedCallback="submitAddress"
|
||||||
@submitAddress="submitAddress"
|
|
||||||
ref="addAddress">
|
ref="addAddress">
|
||||||
</add-address>
|
</add-address>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
/*
|
|
||||||
* Address component is a uniq component for many contexts.
|
|
||||||
* Allow to create/attach/edit an address to
|
|
||||||
* - a person (new or edit address),
|
|
||||||
* - a household (move or edit address)
|
|
||||||
*
|
|
||||||
* */
|
|
||||||
import AddAddress from './components/AddAddress.vue';
|
import AddAddress from './components/AddAddress.vue';
|
||||||
|
import { postAddressToHousehold, postAddressToPerson } from "ChillPersonAssets/vuejs/_api/AddAddress";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "App",
|
name: "App",
|
||||||
components: {
|
components: {
|
||||||
AddAddress
|
AddAddress
|
||||||
},
|
},
|
||||||
data() {
|
props: ['addAddress'],
|
||||||
return {
|
computed: {
|
||||||
context: {
|
context() {
|
||||||
edit: window.mode === 'edit',
|
return this.addAddress.context;
|
||||||
entity: {
|
|
||||||
type: window.entityType,
|
|
||||||
id: window.entityId
|
|
||||||
},
|
},
|
||||||
addressId: window.addressId | null,
|
options() {
|
||||||
backUrl: window.backUrl,
|
return this.addAddress.options;
|
||||||
},
|
},
|
||||||
addAddress: {
|
key() {
|
||||||
options: {
|
return (this.context.edit) ? 'address_' + this.context.addressId
|
||||||
|
: this.context.target.name + '_' + this.context.target.id ;
|
||||||
/// Options override default.
|
|
||||||
/// null value take default component value defined in AddAddress data()
|
|
||||||
button: {
|
|
||||||
text: {
|
|
||||||
create: window.buttonText || null,
|
|
||||||
edit: window.buttonText || null
|
|
||||||
},
|
|
||||||
size: window.buttonSize || null,
|
|
||||||
displayText: window.buttonDisplayText //boolean, default: true
|
|
||||||
},
|
|
||||||
|
|
||||||
/// Modal title text if create or edit address (trans chain, see i18n)
|
|
||||||
title: {
|
|
||||||
create: window.modalTitle || null,
|
|
||||||
edit: window.modalTitle || null
|
|
||||||
},
|
|
||||||
|
|
||||||
/// Display each step in page or Modal
|
|
||||||
bindModal: {
|
|
||||||
step1: window.binModalStep1, //boolean, default: true
|
|
||||||
step2: window.binModalStep2 //boolean, default: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
mounted() {
|
||||||
|
//console.log('AddAddress: data context', this.context);
|
||||||
|
//console.log('AddAddress: data options', this.options);
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
displayErrors() {
|
displayErrors() {
|
||||||
return this.$refs.addAddress.errorMsg;
|
return this.$refs.addAddress.errorMsg;
|
||||||
},
|
},
|
||||||
submitAddress() {
|
submitAddress(payload) {
|
||||||
console.log('@@@ click on Submit Address Button');
|
console.log('@@@ click on Submit Address Button', payload);
|
||||||
|
|
||||||
// Cast child method
|
// Existing address
|
||||||
this.$refs.addAddress.submitNewAddress();
|
if (this.context.edit) {
|
||||||
// it fetch post request only for person and household
|
|
||||||
// else get returned payload then dispatch from here (parent)
|
// address is already linked, just finish !
|
||||||
|
this.$refs.addAddress.afterLastPaneAction({});
|
||||||
|
|
||||||
|
// New created address
|
||||||
|
} else {
|
||||||
|
this.postAddressTo(payload);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Post new created address to targetEntity
|
||||||
|
*/
|
||||||
|
postAddressTo(payload) {
|
||||||
|
console.log('postAddress', payload.addressId, 'To', payload.target, payload.targetId);
|
||||||
|
switch (payload.target) {
|
||||||
|
case 'household':
|
||||||
|
postAddressToHousehold(payload.targetId, payload.addressId)
|
||||||
|
.then(address => new Promise((resolve, reject) => {
|
||||||
|
console.log('..household address', address);
|
||||||
|
this.$refs.addAddress.flag.loading = false;
|
||||||
|
this.$refs.addAddress.flag.success = true;
|
||||||
|
|
||||||
|
// finish
|
||||||
|
this.$refs.addAddress.afterLastPaneAction({ addressId: address.address_id });
|
||||||
|
|
||||||
|
resolve();
|
||||||
|
}))
|
||||||
|
.catch((error) => {
|
||||||
|
this.$refs.addAddress.errorMsg.push(error);
|
||||||
|
this.$refs.addAddress.flag.loading = false;
|
||||||
|
})
|
||||||
|
;
|
||||||
|
break;
|
||||||
|
case 'person':
|
||||||
|
postAddressToPerson(payload.targetId, payload.addressId)
|
||||||
|
.then(address => new Promise((resolve, reject) => {
|
||||||
|
console.log('..person address', address);
|
||||||
|
this.$refs.addAddress.flag.loading = false;
|
||||||
|
this.$refs.addAddress.flag.success = true;
|
||||||
|
|
||||||
|
// finish
|
||||||
|
this.$refs.addAddress.afterLastPaneAction({ addressId: address.address_id });
|
||||||
|
|
||||||
|
resolve();
|
||||||
|
}))
|
||||||
|
.catch((error) => {
|
||||||
|
this.$refs.addAddress.errorMsg.push(error);
|
||||||
|
this.$refs.addAddress.flag.loading = false;
|
||||||
|
})
|
||||||
|
;
|
||||||
|
break;
|
||||||
|
case 'thirdparty':
|
||||||
|
console.log('TODO write postAddressToThirdparty');
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
this.$refs.addAddress.errorMsg.push('That entity is not managed by address !');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -109,7 +109,7 @@ const patchAddress = (id, body) => {
|
|||||||
* method POST, post Postal Code Object
|
* method POST, post Postal Code Object
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
const postPostalCode = (postalCode) => {
|
const postPostalCode = (postalCode) => { //<--
|
||||||
const url = `/api/1.0/main/postal-code.json?`;
|
const url = `/api/1.0/main/postal-code.json?`;
|
||||||
const body = postalCode;
|
const body = postalCode;
|
||||||
|
|
||||||
|
@ -0,0 +1,31 @@
|
|||||||
|
<template>
|
||||||
|
<ul class="record_actions"
|
||||||
|
:class="{ 'sticky-form-buttons': isStickyForm }">
|
||||||
|
|
||||||
|
<li v-if="isStickyForm" class="cancel">
|
||||||
|
<slot name="before"></slot>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<slot name="action"></slot>
|
||||||
|
|
||||||
|
<li v-if="isStickyForm">
|
||||||
|
<slot name="after"></slot>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "ActionButtons",
|
||||||
|
props: ['options', 'defaultz'],
|
||||||
|
computed: {
|
||||||
|
isStickyForm() {
|
||||||
|
return (typeof this.options.stickyActions !== 'undefined') ?
|
||||||
|
this.options.stickyActions : this.defaultz.stickyActions;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
@ -1,18 +1,22 @@
|
|||||||
<template>
|
<template>
|
||||||
|
|
||||||
<!-- start with a button -->
|
<!-- step0 -->
|
||||||
<button v-if="step1WithModal"
|
<show-pane v-if="flag.showPane"
|
||||||
@click="openShowPane"
|
v-bind:context="this.context"
|
||||||
class="btn" :class="getClassButton"
|
v-bind:options="this.options"
|
||||||
type="button" name="button" :title="$t(getTextButton)">
|
v-bind:defaultz="this.defaultz"
|
||||||
<span v-if="displayTextButton">{{ $t(getTextButton) }}</span>
|
v-bind:entity="this.entity"
|
||||||
</button>
|
v-bind:flag="this.flag"
|
||||||
|
v-bind:useDatePane="this.useDatePane"
|
||||||
|
@openEditPane="openEditPane"
|
||||||
|
ref="showAddress">
|
||||||
|
</show-pane>
|
||||||
|
|
||||||
<!-- step 1 -->
|
<!-- step 1 -->
|
||||||
<teleport to="body" v-if="step1WithModal">
|
<teleport to="body" v-if="inModal">
|
||||||
<modal v-if="flag.showPane"
|
<modal v-if="flag.suggestPane"
|
||||||
modalDialogClass="modal-dialog-scrollable modal-xl"
|
modalDialogClass="modal-dialog-scrollable modal-xl"
|
||||||
@close="flag.showPane = false">
|
@close="resetPane">
|
||||||
|
|
||||||
<template v-slot:header>
|
<template v-slot:header>
|
||||||
<h2 class="modal-title">{{ $t(getTextTitle) }}
|
<h2 class="modal-title">{{ $t(getTextTitle) }}
|
||||||
@ -24,24 +28,86 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template v-slot:body>
|
<template v-slot:body>
|
||||||
<show-address-pane
|
<suggest-pane
|
||||||
v-bind:context="this.context"
|
v-bind:context="this.context"
|
||||||
v-bind:options="this.options"
|
v-bind:options="this.options"
|
||||||
v-bind:default="this.default"
|
v-bind:defaultz="this.defaultz"
|
||||||
v-bind:entity="this.entity"
|
v-bind:entity="this.entity"
|
||||||
v-bind:valid="this.valid"
|
|
||||||
v-bind:flag="this.flag"
|
v-bind:flag="this.flag"
|
||||||
ref="showAddress">
|
ref="suggestAddress">
|
||||||
</show-address-pane>
|
</suggest-pane>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template v-slot:footer>
|
<template v-slot:footer>
|
||||||
<button @click="openEditPane"
|
<button @click="openEditPane"
|
||||||
class="btn btn-update">
|
class="btn btn-create">
|
||||||
{{ $t('action.edit')}}
|
{{ $t('create_a_new_address')}}
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-save"
|
</template>
|
||||||
@click.prevent="$emit('submitAddress')">
|
|
||||||
|
</modal>
|
||||||
|
</teleport>
|
||||||
|
<div class="mt-4" v-else>
|
||||||
|
<suggest-pane v-if="flag.suggestPane"
|
||||||
|
v-bind:context="this.context"
|
||||||
|
v-bind:options="this.options"
|
||||||
|
v-bind:defaultz="this.defaultz"
|
||||||
|
v-bind:entity="this.entity"
|
||||||
|
v-bind:flag="this.flag"
|
||||||
|
v-bind:insideModal="false"
|
||||||
|
ref="suggestAddress">
|
||||||
|
|
||||||
|
<template v-slot:before v-if="!bypassFirstStep">
|
||||||
|
<a class="btn btn-cancel" @click="resetPane">
|
||||||
|
{{ $t('action.cancel') }}
|
||||||
|
</a>
|
||||||
|
</template>
|
||||||
|
<template v-slot:action>
|
||||||
|
<li>
|
||||||
|
<button @click="openEditPane"
|
||||||
|
class="btn btn-create">
|
||||||
|
{{ $t('create_a_new_address')}}
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
</suggest-pane>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- step 2 -->
|
||||||
|
<teleport to="body" v-if="inModal">
|
||||||
|
<modal v-if="flag.editPane"
|
||||||
|
modalDialogClass="modal-dialog-scrollable modal-xl"
|
||||||
|
@close="resetPane">
|
||||||
|
|
||||||
|
<template v-slot:header>
|
||||||
|
<h2 class="modal-title">{{ $t(getTextTitle) }}
|
||||||
|
<span v-if="flag.loading" class="loading">
|
||||||
|
<i class="fa fa-circle-o-notch fa-spin fa-fw"></i>
|
||||||
|
<span class="sr-only">{{ $t('loading') }}</span>
|
||||||
|
</span>
|
||||||
|
</h2>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template v-slot:body>
|
||||||
|
<edit-pane
|
||||||
|
v-bind:context="this.context"
|
||||||
|
v-bind:options="this.options"
|
||||||
|
v-bind:defaultz="this.defaultz"
|
||||||
|
v-bind:entity="this.entity"
|
||||||
|
v-bind:flag="this.flag"
|
||||||
|
@getCities="getCities"
|
||||||
|
@getReferenceAddresses="getReferenceAddresses">
|
||||||
|
</edit-pane>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template v-slot:footer>
|
||||||
|
<!--<button class="btn btn-cancel change-icon" @click="resetPane">{{ $t('action.cancel') }}</button>-->
|
||||||
|
<button v-if="!this.context.edit && this.useDatePane" class="btn btn-update change-icon" @click="closeEditPane">
|
||||||
|
{{ $t('nav.next')}}
|
||||||
|
<i class="fa fa-fw fa-arrow-right"></i>
|
||||||
|
</button>
|
||||||
|
<button v-else class="btn btn-save" @click="closeEditPane">
|
||||||
{{ $t('action.save')}}
|
{{ $t('action.save')}}
|
||||||
</button>
|
</button>
|
||||||
</template>
|
</template>
|
||||||
@ -49,25 +115,43 @@
|
|||||||
</modal>
|
</modal>
|
||||||
</teleport>
|
</teleport>
|
||||||
<div class="mt-4" v-else>
|
<div class="mt-4" v-else>
|
||||||
|
<edit-pane v-if="flag.editPane"
|
||||||
<show-address-pane v-if="flag.showPane"
|
|
||||||
v-bind:context="this.context"
|
v-bind:context="this.context"
|
||||||
v-bind:options="this.options"
|
v-bind:options="this.options"
|
||||||
v-bind:default="this.default"
|
v-bind:defaultz="this.defaultz"
|
||||||
v-bind:entity="this.entity"
|
v-bind:entity="this.entity"
|
||||||
v-bind:valid="this.valid"
|
|
||||||
v-bind:flag="this.flag"
|
v-bind:flag="this.flag"
|
||||||
ref="showAddress"
|
v-bind:insideModal="false"
|
||||||
v-bind:insideModal="false" @openEditPane="openEditPane"
|
@getCities="getCities"
|
||||||
@submitAddress="$emit('submitAddress')">
|
@getReferenceAddresses="getReferenceAddresses">
|
||||||
</show-address-pane>
|
|
||||||
|
<template v-slot:before>
|
||||||
|
<a class="btn btn-cancel" @click="resetPane">
|
||||||
|
{{ $t('action.cancel') }}
|
||||||
|
</a>
|
||||||
|
</template>
|
||||||
|
<template v-slot:action>
|
||||||
|
<li v-if="!this.context.edit && this.useDatePane">
|
||||||
|
<button class="btn btn-update change-icon" @click="closeEditPane">
|
||||||
|
{{ $t('nav.next')}}
|
||||||
|
<i class="fa fa-fw fa-arrow-right"></i>
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
<li v-else>
|
||||||
|
<button class="btn btn-save" @click="closeEditPane">
|
||||||
|
{{ $t('action.save')}}
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
</edit-pane>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- step 2 -->
|
<!-- step 3 -->
|
||||||
<teleport to="body" v-if="step2WithModal">
|
<teleport to="body" v-if="inModal">
|
||||||
<modal v-if="flag.editPane"
|
<modal v-if="flag.datePane"
|
||||||
modalDialogClass="modal-dialog-scrollable modal-xl"
|
modalDialogClass="modal-dialog-scrollable modal-xl"
|
||||||
@close="flag.editPane = false">
|
@close="resetPane">
|
||||||
|
|
||||||
<template v-slot:header>
|
<template v-slot:header>
|
||||||
<h2 class="modal-title">{{ $t(getTextTitle) }}
|
<h2 class="modal-title">{{ $t(getTextTitle) }}
|
||||||
@ -79,41 +163,54 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template v-slot:body>
|
<template v-slot:body>
|
||||||
<edit-address-pane
|
<date-pane
|
||||||
v-bind:context="this.context"
|
v-bind:context="this.context"
|
||||||
v-bind:options="this.options"
|
v-bind:options="this.options"
|
||||||
v-bind:default="this.default"
|
v-bind:defaultz="this.defaultz"
|
||||||
v-bind:entity="this.entity"
|
v-bind:entity="this.entity"
|
||||||
v-bind:flag="this.flag"
|
v-bind:flag="this.flag"
|
||||||
@getCities="getCities"
|
ref="dateAddress">
|
||||||
@getReferenceAddresses="getReferenceAddresses">
|
</date-pane>
|
||||||
</edit-address-pane>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template v-slot:footer>
|
<template v-slot:footer>
|
||||||
<button class="btn btn-cancel change-icon" @click="flag.showPane = true; flag.editPane = false;">
|
<button class="btn btn-misc" @click="openEditPane">
|
||||||
{{ $t('action.cancel') }}
|
<i class="fa fa-fw fa-arrow-left"></i>
|
||||||
|
{{ $t('nav.previous')}}
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-update"
|
<button class="btn btn-save" @click="closeDatePane">
|
||||||
@click="closeEditPane">
|
{{ $t('action.save')}}
|
||||||
{{ $t('action.valid')}}
|
|
||||||
</button>
|
</button>
|
||||||
|
<!-- -->
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
</modal>
|
</modal>
|
||||||
</teleport>
|
</teleport>
|
||||||
<div class="mt-4" v-else>
|
<div class="mt-4" v-else>
|
||||||
|
<date-pane v-if="flag.datePane"
|
||||||
<edit-address-pane v-if="flag.editPane"
|
|
||||||
v-bind:context="this.context"
|
v-bind:context="this.context"
|
||||||
v-bind:options="this.options"
|
v-bind:options="this.options"
|
||||||
v-bind:default="this.default"
|
v-bind:defaultz="this.defaultz"
|
||||||
v-bind:entity="this.entity"
|
v-bind:entity="this.entity"
|
||||||
v-bind:flag="this.flag"
|
v-bind:flag="this.flag"
|
||||||
v-bind:insideModal="false" @closeEditPane="closeEditPane"
|
v-bind:insideModal="false"
|
||||||
@getCities="getCities"
|
ref="dateAddress">
|
||||||
@getReferenceAddresses="getReferenceAddresses">
|
|
||||||
</edit-address-pane>
|
<template v-slot:before>
|
||||||
|
<button class="btn btn-misc" @click="openEditPane">
|
||||||
|
<i class="fa fa-fw fa-arrow-left"></i>
|
||||||
|
{{ $t('nav.previous')}}
|
||||||
|
</button>
|
||||||
|
</template>
|
||||||
|
<template v-slot:action>
|
||||||
|
<li>
|
||||||
|
<button class="btn btn-save" @click="closeDatePane">
|
||||||
|
{{ $t('action.save')}}
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
</date-pane>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
@ -122,37 +219,45 @@
|
|||||||
import Modal from 'ChillMainAssets/vuejs/_components/Modal';
|
import Modal from 'ChillMainAssets/vuejs/_components/Modal';
|
||||||
import { getAddress, fetchCountries, fetchCities, fetchReferenceAddresses, patchAddress, postAddress, postPostalCode } from '../api';
|
import { getAddress, fetchCountries, fetchCities, fetchReferenceAddresses, patchAddress, postAddress, postPostalCode } from '../api';
|
||||||
import { postAddressToPerson, postAddressToHousehold } from "ChillPersonAssets/vuejs/_api/AddAddress.js";
|
import { postAddressToPerson, postAddressToHousehold } from "ChillPersonAssets/vuejs/_api/AddAddress.js";
|
||||||
import ShowAddressPane from './ShowAddressPane.vue';
|
import ShowPane from './ShowPane.vue';
|
||||||
import EditAddressPane from './EditAddressPane.vue';
|
import SuggestPane from './SuggestPane.vue';
|
||||||
|
import EditPane from './EditPane.vue';
|
||||||
|
import DatePane from './DatePane.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "AddAddress",
|
name: "AddAddress",
|
||||||
props: ['context', 'options', 'result'],
|
props: ['context', 'options', 'addressChangedCallback'],
|
||||||
emits: ['submitAddress'],
|
|
||||||
components: {
|
components: {
|
||||||
Modal,
|
Modal,
|
||||||
ShowAddressPane,
|
ShowPane,
|
||||||
EditAddressPane,
|
SuggestPane,
|
||||||
|
EditPane,
|
||||||
|
DatePane
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
flag: {
|
flag: {
|
||||||
showPane: false,
|
showPane: true, // begin with showPane
|
||||||
|
suggestPane: false,
|
||||||
editPane: false,
|
editPane: false,
|
||||||
|
datePane: false,
|
||||||
loading: false,
|
loading: false,
|
||||||
success: false
|
success: false
|
||||||
},
|
},
|
||||||
default: {
|
defaultz: {
|
||||||
button: {
|
button: {
|
||||||
text: { create: 'add_an_address_title', edit: 'edit_address' },
|
text: { create: 'add_an_address_title', edit: 'edit_address' },
|
||||||
type: { create: 'btn-create', edit: 'btn-update'},
|
type: { create: 'btn-create', edit: 'btn-update'},
|
||||||
displayText: true
|
displayText: true
|
||||||
},
|
},
|
||||||
title: { create: 'add_an_address_title', edit: 'edit_address' },
|
title: { create: 'add_an_address_title', edit: 'edit_address' },
|
||||||
bindModal: {
|
openPanesInModal: true,
|
||||||
step1: true,
|
stickyActions: false,
|
||||||
step2: true,
|
useDate: {
|
||||||
|
validFrom: false,
|
||||||
|
validTo: false
|
||||||
},
|
},
|
||||||
|
hideAddress: false
|
||||||
},
|
},
|
||||||
entity: {
|
entity: {
|
||||||
address: {}, // <== loaded and returned
|
address: {}, // <== loaded and returned
|
||||||
@ -173,6 +278,10 @@ export default {
|
|||||||
writeNew: {
|
writeNew: {
|
||||||
address: false,
|
address: false,
|
||||||
postcode: false
|
postcode: false
|
||||||
|
},
|
||||||
|
valid: {
|
||||||
|
from: new Date(),
|
||||||
|
to: null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
addressMap: {
|
addressMap: {
|
||||||
@ -182,27 +291,32 @@ export default {
|
|||||||
zoom: 12
|
zoom: 12
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
valid: {
|
|
||||||
from: new Date(),
|
|
||||||
to: null
|
|
||||||
},
|
|
||||||
errorMsg: []
|
errorMsg: []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
step1WithModal() {
|
inModal() {
|
||||||
return (this.options.bindModal !== null && typeof this.options.bindModal.step1 !== 'undefined') ?
|
return (typeof this.options.openPanesInModal !== 'undefined') ?
|
||||||
this.options.bindModal.step1 : this.default.bindModal.step1;
|
this.options.openPanesInModal : this.defaultz.openPanesInModal;
|
||||||
},
|
},
|
||||||
step2WithModal() {
|
validFrom() {
|
||||||
let step2 = (this.options.bindModal !== null && typeof this.options.bindModal.step2 !== 'undefined') ?
|
return (typeof this.options.useDate !== 'undefined' && typeof this.options.useDate.validFrom !== 'undefined') ?
|
||||||
this.options.bindModal.step2 : this.default.bindModal.step2;
|
this.options.useDate.validFrom : this.defaultz.useDate.validFrom;
|
||||||
|
},
|
||||||
if (step2 === false && this.step1WithModal === true) {
|
validTo() {
|
||||||
console.log("step2 must open in a Modal");
|
return (typeof this.options.useDate !== 'undefined' && typeof this.options.useDate.validTo !== 'undefined') ?
|
||||||
return true;
|
this.options.useDate.validTo : this.defaultz.useDate.validTo ;
|
||||||
}
|
},
|
||||||
return step2;
|
useDatePane() {
|
||||||
|
return (this.validFrom || this.validTo) ? true : false;
|
||||||
|
},
|
||||||
|
hasSuggestions() {
|
||||||
|
// TODO
|
||||||
|
//return addressSuggestions.length > 0
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
displaySuggestions() {
|
||||||
|
return !this.context.edit && this.hasSuggestions;
|
||||||
},
|
},
|
||||||
getTextTitle() {
|
getTextTitle() {
|
||||||
if ( typeof this.options.title !== 'undefined'
|
if ( typeof this.options.title !== 'undefined'
|
||||||
@ -211,36 +325,29 @@ export default {
|
|||||||
)) {
|
)) {
|
||||||
return (this.context.edit) ? this.options.title.edit : this.options.title.create;
|
return (this.context.edit) ? this.options.title.edit : this.options.title.create;
|
||||||
}
|
}
|
||||||
return (this.context.edit) ? this.default.title.edit : this.default.title.create;
|
return (this.context.edit) ? this.defaultz.title.edit : this.defaultz.title.create;
|
||||||
},
|
},
|
||||||
getTextButton() {
|
bypassFirstStep() {
|
||||||
if ( typeof this.options.button.text !== 'undefined'
|
// exception: passing step0 if new address and pane are not in modal
|
||||||
&& ( this.options.button.text.edit !== null
|
return !this.context.edit && !this.inModal;
|
||||||
|| this.options.button.text.create !== null
|
|
||||||
)) {
|
|
||||||
return (this.context.edit) ? this.options.button.text.edit : this.options.button.text.create;
|
|
||||||
}
|
|
||||||
return (this.context.edit) ? this.default.button.text.edit : this.default.button.text.create;
|
|
||||||
},
|
},
|
||||||
getClassButton() {
|
forceRedirect() {
|
||||||
let type = (this.context.edit) ? this.default.button.type.edit : this.default.button.type.create;
|
return (!(this.context.backUrl === null || typeof this.context.backUrl === 'undefined'));
|
||||||
let size = (typeof this.options.button !== 'undefined' && this.options.button.size !== null) ?
|
|
||||||
`${this.options.button.size} ` : '';
|
|
||||||
return `${size}${type}`;
|
|
||||||
},
|
|
||||||
displayTextButton() {
|
|
||||||
return (typeof this.options.button !== 'undefined' && typeof this.options.button.displayText !== 'undefined') ?
|
|
||||||
this.options.button.displayText : this.default.button.displayText;
|
|
||||||
},
|
|
||||||
context() {
|
|
||||||
return this.context;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
if (!this.step1WithModal) {
|
|
||||||
//console.log('Mounted now !');
|
console.log('validFrom', this.validFrom);
|
||||||
this.openShowPane();
|
console.log('validTo', this.validTo);
|
||||||
|
console.log('useDatePane', this.useDatePane);
|
||||||
|
|
||||||
|
console.log('Mounted now !');
|
||||||
|
if (this.context.edit) {
|
||||||
|
console.log('getInitialAddress', this.context.addressId);
|
||||||
|
this.getInitialAddress(this.context.addressId);
|
||||||
}
|
}
|
||||||
|
this.openShowPane();
|
||||||
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|
||||||
@ -248,35 +355,89 @@ export default {
|
|||||||
* Opening and closing Panes when interacting with buttons
|
* Opening and closing Panes when interacting with buttons
|
||||||
*/
|
*/
|
||||||
openShowPane() {
|
openShowPane() {
|
||||||
console.log('open the Show Panel');
|
if (this.flag.editPane === false && this.bypassFirstStep) {
|
||||||
|
console.log('bypassFirstStep');
|
||||||
if (this.context.edit) {
|
this.closeShowPane();
|
||||||
this.getInitialAddress(this.context.addressId);
|
|
||||||
}
|
|
||||||
|
|
||||||
// when create new address, start first with editPane
|
|
||||||
if ( this.context.edit === false
|
|
||||||
&& this.flag.editPane === false
|
|
||||||
) {
|
|
||||||
this.openEditPane();
|
this.openEditPane();
|
||||||
this.flag.editPane = true;
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
this.flag.showPane = true;
|
this.flag.showPane = true;
|
||||||
|
console.log('step0: open the Show Panel');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
closeShowPane() {
|
||||||
|
// Show pane can be closed only when openPanesInModal is false
|
||||||
|
if (!this.inModal) {
|
||||||
|
this.flag.showPane = false;
|
||||||
|
console.log('step0: close the Show Panel');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
openSuggestPane() {
|
||||||
|
this.flag.suggestPane = true;
|
||||||
|
console.log('step1: open the Suggestion Panel');
|
||||||
|
},
|
||||||
|
closeSuggestPane() {
|
||||||
|
this.flag.suggestPane = false;
|
||||||
|
console.log('step1: close the Suggestion Panel');
|
||||||
|
},
|
||||||
openEditPane() {
|
openEditPane() {
|
||||||
console.log('open the Edit panel');
|
if (this.flag.suggestPane === false && this.displaySuggestions) {
|
||||||
this.initForm();
|
console.log('displaySuggestions');
|
||||||
this.getCountries();
|
this.openSuggestPane();
|
||||||
|
} else {
|
||||||
|
if (this.flag.datePane === false) {
|
||||||
|
this.initForm(); // reset form except if we come back from datePane
|
||||||
|
}
|
||||||
|
this.getCountries(); // will open editPane when resolve promise
|
||||||
|
}
|
||||||
|
},
|
||||||
|
closeEditPane() {
|
||||||
|
this.flag.editPane = false;
|
||||||
|
console.log('step2: close the Edit Panel');
|
||||||
|
if (!this.context.edit && this.useDatePane) {
|
||||||
|
this.openDatePane();
|
||||||
|
} else {
|
||||||
|
this.applyChanges();
|
||||||
|
if (!this.forceRedirect) {
|
||||||
|
this.openShowPane();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
openDatePane() {
|
||||||
|
this.flag.datePane = true;
|
||||||
|
console.log('step3: open the Date Panel');
|
||||||
|
},
|
||||||
|
closeDatePane() {
|
||||||
|
this.applyChanges();
|
||||||
|
this.flag.datePane = false;
|
||||||
|
console.log('step3: close the Date Panel');
|
||||||
|
},
|
||||||
|
resetPane() {
|
||||||
|
console.log('resetPane');
|
||||||
|
this.flag.suggestPane = false;
|
||||||
|
this.flag.editPane = false;
|
||||||
|
this.flag.datePane = false;
|
||||||
|
this.openShowPane();
|
||||||
},
|
},
|
||||||
|
|
||||||
closeEditPane() {
|
/*
|
||||||
console.log('close the Edit Panel');
|
* What happens when submitting last Pane:
|
||||||
this.applyChanges();
|
* - redirect or reset pane,
|
||||||
this.flag.showPane = true;
|
* - change context to editing
|
||||||
this.flag.editPane = false;
|
*/
|
||||||
|
afterLastPaneAction(params) {
|
||||||
|
this.initForm();
|
||||||
|
if (this.forceRedirect) {
|
||||||
|
console.log("redirect to backUrl");
|
||||||
|
window.location.assign(this.context.backUrl);
|
||||||
|
} else {
|
||||||
|
console.log("don't redirect");
|
||||||
|
this.resetPane();
|
||||||
|
if (!this.context.edit) {
|
||||||
|
this.context.edit = true;
|
||||||
|
this.context.addressId = params.addressId;
|
||||||
|
console.log("context is now edit, with address", params.addressId);
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -301,7 +462,16 @@ export default {
|
|||||||
fetchCountries().then(
|
fetchCountries().then(
|
||||||
countries => new Promise((resolve, reject) => {
|
countries => new Promise((resolve, reject) => {
|
||||||
this.entity.loaded.countries = countries.results;
|
this.entity.loaded.countries = countries.results;
|
||||||
this.flag.showPane = false;
|
if (this.flag.showPane === true) {
|
||||||
|
this.closeShowPane();
|
||||||
|
}
|
||||||
|
if (this.flag.suggestPane === true) {
|
||||||
|
this.closeSuggestPane();
|
||||||
|
}
|
||||||
|
if (this.flag.datePane === true) {
|
||||||
|
this.flag.datePane = false;
|
||||||
|
}
|
||||||
|
console.log('step2: open the Edit panel');
|
||||||
this.flag.editPane = true;
|
this.flag.editPane = true;
|
||||||
this.flag.loading = false;
|
this.flag.loading = false;
|
||||||
resolve()
|
resolve()
|
||||||
@ -369,6 +539,7 @@ export default {
|
|||||||
|
|
||||||
this.entity.selected.writeNew.address = this.context.edit;
|
this.entity.selected.writeNew.address = this.context.edit;
|
||||||
this.entity.selected.writeNew.postcode = this.context.edit;
|
this.entity.selected.writeNew.postcode = this.context.edit;
|
||||||
|
console.log('!! just set writeNew.postcode to', this.entity.selected.writeNew.postcode);
|
||||||
},
|
},
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -378,6 +549,8 @@ export default {
|
|||||||
*/
|
*/
|
||||||
applyChanges()
|
applyChanges()
|
||||||
{
|
{
|
||||||
|
console.log('apply changes');
|
||||||
|
|
||||||
let newAddress = {
|
let newAddress = {
|
||||||
'isNoAddress': this.entity.selected.isNoAddress,
|
'isNoAddress': this.entity.selected.isNoAddress,
|
||||||
'street': this.entity.selected.isNoAddress ? '' : this.entity.selected.address.street,
|
'street': this.entity.selected.isNoAddress ? '' : this.entity.selected.address.street,
|
||||||
@ -397,23 +570,43 @@ export default {
|
|||||||
'point': this.entity.selected.address.point.coordinates
|
'point': this.entity.selected.address.point.coordinates
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (this.validFrom) {
|
||||||
|
console.log('add validFrom in fetch body', this.entity.selected.valid.from);
|
||||||
|
newAddress = Object.assign(newAddress, {
|
||||||
|
'validFrom': {
|
||||||
|
datetime: `${this.entity.selected.valid.from.toISOString().split('T')[0]}T00:00:00+0100`
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (this.validTo && null !== this.entity.selected.valid.to) {
|
||||||
|
console.log('add validTo in fetch body', this.entity.selected.valid.to);
|
||||||
|
newAddress = Object.assign(newAddress, {
|
||||||
|
'validTo': {
|
||||||
|
datetime: `${this.entity.selected.valid.to.toISOString().split('T')[0]}T00:00:00+0100`
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
if (this.entity.selected.writeNew.postcode) {
|
if (this.entity.selected.writeNew.postcode) {
|
||||||
let newPostcode = this.entity.selected.postcode;
|
let newPostcode = this.entity.selected.postcode;
|
||||||
newPostcode = Object.assign(newPostcode, {
|
newPostcode = Object.assign(newPostcode, {
|
||||||
'country': {'id': this.entity.selected.country.id },
|
'country': {'id': this.entity.selected.country.id },
|
||||||
});
|
});
|
||||||
|
console.log('writeNew postcode is true! newPostcode: ', newPostcode);
|
||||||
newAddress = Object.assign(newAddress, {
|
newAddress = Object.assign(newAddress, {
|
||||||
'newPostcode': newPostcode
|
'newPostcode': newPostcode
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.context.edit) {
|
if (!this.context.edit) {
|
||||||
|
this.addNewAddress(newAddress)
|
||||||
|
.then(payload => this.addressChangedCallback(payload));
|
||||||
|
|
||||||
|
} else {
|
||||||
this.updateAddress({
|
this.updateAddress({
|
||||||
addressId: this.context.addressId,
|
addressId: this.context.addressId,
|
||||||
newAddress: newAddress
|
newAddress: newAddress
|
||||||
});
|
})
|
||||||
} else {
|
.then(payload => this.addressChangedCallback(payload));
|
||||||
this.addAddress(newAddress);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -421,46 +614,49 @@ export default {
|
|||||||
* Async POST transactions,
|
* Async POST transactions,
|
||||||
* creating new address, and receive backend datas when promise is resolved
|
* creating new address, and receive backend datas when promise is resolved
|
||||||
*/
|
*/
|
||||||
addAddress(payload)
|
addNewAddress(payload)
|
||||||
{
|
{
|
||||||
|
console.log('addNewAddress', payload);
|
||||||
this.flag.loading = true;
|
this.flag.loading = true;
|
||||||
|
|
||||||
if ('newPostcode' in payload) {
|
if ('newPostcode' in payload) {
|
||||||
|
|
||||||
let postcodeBody = payload.newPostcode;
|
let postcodeBody = payload.newPostcode;
|
||||||
if (this.context.entity.type === 'person') {
|
if (this.context.target.name === 'person') { // !!! maintain here ?
|
||||||
postcodeBody = Object.assign(postcodeBody, {'origin': 3});
|
postcodeBody = Object.assign(postcodeBody, {'origin': 3});
|
||||||
}
|
}
|
||||||
|
console.log('juste before post new postcode', postcodeBody);
|
||||||
postPostalCode(postcodeBody)
|
return postPostalCode(postcodeBody)
|
||||||
.then(postalCode => {
|
.then(postalCode => {
|
||||||
let body = payload;
|
console.log('new postcode created', postalCode.id);
|
||||||
body.postcode = {'id': postalCode.id },
|
payload.postcode = {'id': postalCode.id };
|
||||||
postAddress(body)
|
return this.postNewAddress(payload);
|
||||||
.then(address => new Promise((resolve, reject) => {
|
|
||||||
this.entity.address = address;
|
|
||||||
this.flag.loading = false;
|
|
||||||
this.flag.success = true;
|
|
||||||
resolve();
|
|
||||||
}))
|
|
||||||
.catch((error) => {
|
|
||||||
this.errorMsg.push(error);
|
|
||||||
this.flag.loading = false;
|
|
||||||
});
|
});
|
||||||
})
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
postAddress(payload)
|
return this.postNewAddress(payload);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
postNewAddress(payload)
|
||||||
|
{
|
||||||
|
console.log('postNewAddress', payload);
|
||||||
|
return postAddress(payload)
|
||||||
.then(address => new Promise((resolve, reject) => {
|
.then(address => new Promise((resolve, reject) => {
|
||||||
this.entity.address = address;
|
this.entity.address = address;
|
||||||
this.flag.loading = false;
|
this.flag.loading = false;
|
||||||
this.flag.success = true;
|
this.flag.success = true;
|
||||||
resolve();
|
resolve({
|
||||||
|
target: this.context.target.name,
|
||||||
|
targetId: this.context.target.id,
|
||||||
|
addressId: this.entity.address.address_id
|
||||||
|
}
|
||||||
|
);
|
||||||
}))
|
}))
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
this.errorMsg.push(error);
|
this.errorMsg.push(error);
|
||||||
this.flag.loading = false;
|
this.flag.loading = false;
|
||||||
});
|
});
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -469,89 +665,41 @@ export default {
|
|||||||
*/
|
*/
|
||||||
updateAddress(payload)
|
updateAddress(payload)
|
||||||
{
|
{
|
||||||
// TODO change the condition because it writes new postal code in edit mode now: !writeNewPostalCode
|
|
||||||
this.flag.loading = true;
|
this.flag.loading = true;
|
||||||
|
|
||||||
|
// TODO change the condition because it writes new postal code in edit mode now: !writeNewPostalCode
|
||||||
|
// BUG réécrit un postcode à chaque édition !
|
||||||
if ('newPostcode' in payload.newAddress) {
|
if ('newPostcode' in payload.newAddress) {
|
||||||
|
|
||||||
let postcodeBody = payload.newAddress.newPostcode;
|
let postcodeBody = payload.newAddress.newPostcode;
|
||||||
postcodeBody = Object.assign(postcodeBody, {'origin': 3});
|
postcodeBody = Object.assign(postcodeBody, {'origin': 3});
|
||||||
|
|
||||||
postPostalCode(postcodeBody)
|
console.log('juste before post new postcode', postcodeBody);
|
||||||
|
return postPostalCode(postcodeBody)
|
||||||
.then(postalCode => {
|
.then(postalCode => {
|
||||||
let body = payload.newAddress;
|
console.log('new postcode created', postalCode.id);
|
||||||
body.postcode = {'id': postalCode.id },
|
payload.newAddress.postcode = {'id': postalCode.id };
|
||||||
patchAddress(payload.addressId, body)
|
return this.patchExistingAddress(payload);
|
||||||
.then(address => new Promise((resolve, reject) => {
|
|
||||||
this.entity.address = address;
|
|
||||||
this.flag.loading = false;
|
|
||||||
this.flag.success = true;
|
|
||||||
resolve();
|
|
||||||
}))
|
|
||||||
.catch((error) => {
|
|
||||||
this.errorMsg.push(error);
|
|
||||||
this.flag.loading = false;
|
|
||||||
});
|
});
|
||||||
})
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
patchAddress(payload.addressId, payload.newAddress)
|
return this.patchExistingAddress(payload);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
patchExistingAddress(payload) {
|
||||||
|
console.log('patchExistingAddress', payload);
|
||||||
|
return patchAddress(payload.addressId, payload.newAddress)
|
||||||
.then(address => new Promise((resolve, reject) => {
|
.then(address => new Promise((resolve, reject) => {
|
||||||
this.entity.address = address;
|
this.entity.address = address;
|
||||||
this.flag.loading = false;
|
this.flag.loading = false;
|
||||||
this.flag.success = true;
|
this.flag.success = true;
|
||||||
resolve();
|
return resolve({
|
||||||
}))
|
target: this.context.target.name,
|
||||||
.catch((error) => {
|
targetId: this.context.target.id,
|
||||||
this.errorMsg.push(error);
|
addressId: this.entity.address.address_id
|
||||||
this.flag.loading = false;
|
|
||||||
});
|
});
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/*
|
|
||||||
* When submit address
|
|
||||||
* (get out step1 show pane, submit button)
|
|
||||||
*/
|
|
||||||
submitNewAddress()
|
|
||||||
{
|
|
||||||
let payload = {
|
|
||||||
entity: this.context.entity.type,
|
|
||||||
entityId: this.context.entity.id,
|
|
||||||
addressId: this.entity.address.address_id,
|
|
||||||
body: {
|
|
||||||
validFrom: {
|
|
||||||
datetime: `${this.valid.from.toISOString().split('T')[0]}T00:00:00+0100`
|
|
||||||
}
|
|
||||||
},
|
|
||||||
backUrl: this.context.backUrl
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( payload.entity !== 'person' && payload.entity !== 'household' ) {
|
|
||||||
|
|
||||||
// just return payload to parent
|
|
||||||
// (changes will be patched in parent store)
|
|
||||||
this.initForm();
|
|
||||||
this.flag.showPane = false;
|
|
||||||
return payload;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('submitNewAddress with', payload);
|
|
||||||
this.addDateToAddressAndAddressTo(payload);
|
|
||||||
|
|
||||||
this.initForm();
|
|
||||||
this.flag.showPane = false;
|
|
||||||
},
|
|
||||||
|
|
||||||
addDateToAddressAndAddressTo(payload)
|
|
||||||
{
|
|
||||||
console.log('addDateToAddressAndAddressTo', payload.entity)
|
|
||||||
this.flag.loading = true;
|
|
||||||
return patchAddress(payload.addressId, payload.body)
|
|
||||||
.then(address => new Promise((resolve, reject) => {
|
|
||||||
this.valid.from = address.validFrom;
|
|
||||||
resolve();
|
|
||||||
})
|
})
|
||||||
.then(this.postAddressTo(payload))
|
|
||||||
)
|
)
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
this.errorMsg.push(error);
|
this.errorMsg.push(error);
|
||||||
@ -559,50 +707,18 @@ export default {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
postAddressTo(payload)
|
/*
|
||||||
|
* Method just add closing pane to the callback method
|
||||||
|
* (get out step1 show pane, submit button)
|
||||||
|
closePaneAndCallbackSubmit(payload)
|
||||||
{
|
{
|
||||||
console.log('postAddressTo', payload.entity);
|
//this.initForm();
|
||||||
if (!this.context.edit) {
|
//this.resetPane(); // because parent callback will cast afterLastPaneAction()
|
||||||
switch (payload.entity) {
|
console.log('will call parent callback method', payload);
|
||||||
case 'household':
|
// callback props method from parent
|
||||||
postAddressToHousehold(payload.entityId, payload.addressId)
|
this.addressChangedCallback(payload);
|
||||||
.then(household => new Promise((resolve, reject) => {
|
|
||||||
console.log('postAddressToHousehold', household);
|
|
||||||
this.flag.loading = false;
|
|
||||||
this.flag.success = true;
|
|
||||||
window.location.assign(payload.backUrl);
|
|
||||||
resolve();
|
|
||||||
}))
|
|
||||||
.catch((error) => {
|
|
||||||
this.errorMsg.push(error);
|
|
||||||
this.flag.loading = false;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
break;
|
|
||||||
case 'person':
|
|
||||||
postAddressToPerson(payload.entityId, payload.addressId)
|
|
||||||
.then(person => new Promise((resolve, reject) => {
|
|
||||||
console.log('postAddressToPerson', person);
|
|
||||||
this.flag.loading = false;
|
|
||||||
this.flag.success = true;
|
|
||||||
window.location.assign(payload.backUrl);
|
|
||||||
resolve();
|
|
||||||
}))
|
|
||||||
.catch((error) => {
|
|
||||||
this.errorMsg.push(error);
|
|
||||||
this.flag.loading = false;
|
|
||||||
})
|
|
||||||
;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
this.errorMsg.push('That entity is not managed by address !');
|
|
||||||
}
|
}
|
||||||
} else {
|
*/
|
||||||
// address is already linked, just finish !
|
|
||||||
window.location.assign(payload.backUrl);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
@ -615,4 +731,7 @@ div.entity-address {
|
|||||||
right: 0; top: -55px;
|
right: 0; top: -55px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
h4.h3 {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user