mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-09-20 13:44:58 +00:00
Compare commits
148 Commits
small_issu
...
optimize_a
Author | SHA1 | Date | |
---|---|---|---|
|
2d39fdb8ea | ||
|
cae3defedb | ||
|
78f66d4f14 | ||
ddbd6a9f23 | |||
b5eaea0e88 | |||
ed8a569fea | |||
c41bc7bef9 | |||
27dea97bc6 | |||
27125b838e | |||
4c55631297 | |||
cd6dec5082 | |||
152a7de1dc | |||
da19f68440 | |||
e895125d12 | |||
fe9b76a1fb | |||
baf9251000 | |||
665b38d166 | |||
9450d34af0 | |||
42301c9df7 | |||
eb1a7b2374 | |||
7f661f9022 | |||
178ffdf6bf | |||
5f0238f614 | |||
cfaa64884d | |||
faba2b67eb | |||
a981661ea5 | |||
3a3baa79c8 | |||
e35f002f2b | |||
fbd17a1de6 | |||
77d86d3836 | |||
eb11597f9c | |||
daa8b03c8b | |||
9ee679a3b3 | |||
8791c78426 | |||
abd60f7ddf | |||
75348f6ba7 | |||
75a06d6896 | |||
65782d3a6b | |||
1dc01fa8e2 | |||
db9a203df0 | |||
2a7e3c0334 | |||
ad72904aa9 | |||
0b57b3c74d | |||
8c0abbc5cd | |||
c42b7c014b | |||
0d5d4b3f05 | |||
a3e43fcaaa | |||
4047399b76 | |||
4c9d352c46 | |||
a316cb9568 | |||
14539f6f88 | |||
92e6506ecb | |||
59fed905e9 | |||
577d665f09 | |||
decc3c7463 | |||
1eb8d04a32 | |||
2f60ab4d17 | |||
3cf9920718 | |||
|
f1f13996f9 | ||
29838a4d8e | |||
e9b1f442bc | |||
e2feea15f9 | |||
14a13c7bd5 | |||
5a37bfd1a0 | |||
bd7f2d997e | |||
309fe40564 | |||
|
f8f019cfe6 | ||
460f0daf0a | |||
5de05c0ee9 | |||
|
7f721da08a | ||
|
9a34aa59bb | ||
|
00259dae20 | ||
|
fb8b8b354f | ||
d8c34c3089 | |||
74b649fb2c | |||
bac8e8d0b8 | |||
008a10dab8 | |||
a2df3c8144 | |||
d8444455c0 | |||
c793159593 | |||
26140de7de | |||
2c1d3d08c3 | |||
|
86c2a5c3e8 | ||
9420c34f58 | |||
d94fec3352 | |||
ba98283348 | |||
bfd95bff39 | |||
|
664fcd07ef | ||
a8df0070e8 | |||
440e21a83b | |||
8c2d211661 | |||
f2ebb1f33c | |||
c53636c40b | |||
0ec095b59a | |||
86c5376cc2 | |||
0e54b8cdf0 | |||
53e82f1b2a | |||
f4999548ac | |||
302f60e722 | |||
5b7484b1ce | |||
fc1dd499c4 | |||
3824a380ff | |||
315253589e | |||
af24637dc4 | |||
0fe248320d | |||
a26d278510 | |||
9641fd3fcc | |||
2b3c4b7af9 | |||
8853359405 | |||
704ec76ca4 | |||
|
6020ee2cb2 | ||
|
ba53ce40fa | ||
|
ab845d4569 | ||
|
dcb92b1378 | ||
|
59fcd1e96b | ||
|
0aec2fc1d1 | ||
|
e43ae56e73 | ||
3040ed9483 | |||
adc94aaeea | |||
c5fa1b883c | |||
644d0420ce | |||
e2230409b8 | |||
472866ce91 | |||
d5d12c4a17 | |||
e72ba4c940 | |||
|
ca7ba90717 | ||
f3ba3aeed9 | |||
c791c48248 | |||
5da332a06e | |||
eb89fa2cd4 | |||
82db55cfec | |||
349a0e69f1 | |||
4de106ec30 | |||
6301c4c10b | |||
b87c995d22 | |||
960db6aefc | |||
a28c996164 | |||
05c5eaa925 | |||
d4116a4659 | |||
15897b4f33 | |||
aa1f02ebd4 | |||
1672e873a3 | |||
544af59009 | |||
edc528ff92 | |||
62e70c0c36 | |||
f2e945dc0f | |||
d2ce4865c0 | |||
601c16ac27 |
@@ -7,6 +7,7 @@ charset = utf-8
|
||||
end_of_line = LF
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
indent_size = 4
|
||||
|
||||
[*.{php,html,twig}]
|
||||
indent_style = space
|
||||
|
45
CHANGELOG.md
Normal file
45
CHANGELOG.md
Normal file
@@ -0,0 +1,45 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to
|
||||
|
||||
* [Semantic Versioning](https://semver.org/spec/v2.0.0.html) for stable releases;
|
||||
* date versioning for test releases
|
||||
|
||||
## Unreleased
|
||||
|
||||
* Address: zoom on postal code geometry + fix origin of manually entered postal code
|
||||
|
||||
* [Aside activity] Fixes for aside activity
|
||||
|
||||
* categories with child
|
||||
* fast creation buttons
|
||||
* add ordering for types
|
||||
|
||||
|
||||
## Test releases
|
||||
|
||||
### test release 2021-10-04
|
||||
|
||||
* [Household editor][UI] Update how household suggestion and addresses are picked;
|
||||
* [AddAddress] Handle address suggestion;
|
||||
* [CenterType][Create a person] when overriding the ACL rules, allow to show a PickCenterType
|
||||
when no centers are reachable by the default ACL.
|
||||
* [Household] Show comment event if no address are associated with the household;
|
||||
* [Person results] Add requestor into search results:
|
||||
|
||||
* a badge "requestor" is shown into search results;
|
||||
* periods where the person is only requestor (without participating) are also shown;
|
||||
|
||||
Issues:
|
||||
|
||||
* https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/13
|
||||
* https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/199
|
||||
* [Person form] "accept sms" not required:
|
||||
|
||||
https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/37
|
||||
https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/221
|
||||
* On-The-Fly modale works for showing, editing and creating person and thirdparty ;
|
||||
* AccompanyingCourse Resume page: list associated persons by household, see household when hover, and show on-the-fly modale when clicking on person ;
|
@@ -22,6 +22,7 @@
|
||||
"league/csv": "^9.7.1",
|
||||
"nyholm/psr7": "^1.4",
|
||||
"phpoffice/phpspreadsheet": "^1.16",
|
||||
"ramsey/uuid-doctrine": "^1.7",
|
||||
"sensio/framework-extra-bundle": "^5.5",
|
||||
"symfony/asset": "4.*",
|
||||
"symfony/browser-kit": "^5.2",
|
||||
@@ -29,6 +30,7 @@
|
||||
"symfony/expression-language": "4.*",
|
||||
"symfony/form": "4.*",
|
||||
"symfony/intl": "4.*",
|
||||
"symfony/mime": "^4 || ^5",
|
||||
"symfony/monolog-bundle": "^3.5",
|
||||
"symfony/security-bundle": "4.*",
|
||||
"symfony/serializer": "^5.2",
|
||||
|
@@ -1,20 +0,0 @@
|
||||
<?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');
|
||||
}
|
||||
}
|
@@ -3,6 +3,9 @@
|
||||
namespace Chill\AsideActivityBundle\Controller;
|
||||
|
||||
use Chill\MainBundle\CRUD\Controller\CRUDController;
|
||||
use Chill\MainBundle\Pagination\PaginatorInterface;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
|
||||
/**
|
||||
@@ -10,5 +13,12 @@ use Chill\MainBundle\CRUD\Controller\CRUDController;
|
||||
*/
|
||||
class AsideActivityCategoryController extends CRUDController
|
||||
{
|
||||
protected function orderQuery(string $action, $query, Request $request, PaginatorInterface $paginator)
|
||||
{
|
||||
/** @var QueryBuilder $query */
|
||||
$query->addOrderBy('e.ordering', 'ASC');
|
||||
|
||||
}
|
||||
return $query;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -4,6 +4,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace Chill\AsideActivityBundle\Controller;
|
||||
|
||||
use Chill\AsideActivityBundle\Entity\AsideActivity;
|
||||
use Chill\AsideActivityBundle\Repository\AsideActivityCategoryRepository;
|
||||
use Chill\MainBundle\CRUD\Controller\CRUDController;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
@@ -12,12 +14,21 @@ use Doctrine\Common\Collections\Criteria;
|
||||
|
||||
final class AsideActivityController extends CRUDController
|
||||
{
|
||||
|
||||
private $categoryRepository;
|
||||
|
||||
public function __construct(AsideActivityCategoryRepository $categoryRepository)
|
||||
{
|
||||
$this->categoryRepository = $categoryRepository;
|
||||
}
|
||||
|
||||
protected function buildQueryEntities(string $action, Request $request)
|
||||
{
|
||||
$qb = parent::buildQueryEntities($action, $request);
|
||||
|
||||
if ('index' === $action) {
|
||||
$qb->andWhere($qb->expr()->eq('e.agent', ':user'));
|
||||
$qb->where($qb->expr()->eq('e.agent', ':user'));
|
||||
$qb->orWhere($qb->expr()->eq('e.createdBy', ':user'));
|
||||
$qb->setParameter('user', $this->getUser());
|
||||
}
|
||||
|
||||
@@ -37,5 +48,24 @@ final class AsideActivityController extends CRUDController
|
||||
return parent::orderQuery($action, $query, $request, $paginator);
|
||||
}
|
||||
|
||||
public function createEntity(string $action, Request $request): object
|
||||
{
|
||||
$asideActivity = new AsideActivity();
|
||||
|
||||
$duration = $request->query->get('duration', '300');
|
||||
$duration = \DateTime::createFromFormat('U', $duration);
|
||||
$asideActivity->setDuration($duration);
|
||||
|
||||
$categoryId = $request->query->get('type', 7);
|
||||
if($categoryId === null){
|
||||
return $this->createNotFoundException('You must give a valid category id');
|
||||
}
|
||||
$category = $this->categoryRepository->find($categoryId);
|
||||
$asideActivity->setType($category);
|
||||
|
||||
$note = $request->query->get('note', null);
|
||||
$asideActivity->setNote($note);
|
||||
|
||||
return $asideActivity;
|
||||
}
|
||||
}
|
||||
|
@@ -24,6 +24,12 @@ final class ChillAsideActivityExtension extends Extension implements PrependExte
|
||||
*/
|
||||
public function load(array $configs, ContainerBuilder $container): void
|
||||
{
|
||||
|
||||
$configuration = $this->getConfiguration($configs, $container);
|
||||
$config = $this->processConfiguration($configuration, $configs);
|
||||
|
||||
$container->setParameter('chill_aside_activity.form.time_duration', $config['form']['time_duration']);
|
||||
|
||||
$loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../config'));
|
||||
$loader->load('services.yaml');
|
||||
$loader->load('services/form.yaml');
|
||||
@@ -81,7 +87,7 @@ final class ChillAsideActivityExtension extends Extension implements PrependExte
|
||||
'controller' => \Chill\AsideActivityBundle\Controller\AsideActivityController::class,
|
||||
'actions' => [
|
||||
'index' => [
|
||||
'template' => '@ChillAsideActivity/asideActivity/list.html.twig',
|
||||
'template' => '@ChillAsideActivity/asideActivity/index.html.twig',
|
||||
'role' => 'ROLE_USER'
|
||||
],
|
||||
'new' => [
|
||||
|
@@ -0,0 +1,138 @@
|
||||
<?php
|
||||
|
||||
namespace Chill\AsideActivityBundle\DependencyInjection;
|
||||
|
||||
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
|
||||
use Symfony\Component\Config\Definition\ConfigurationInterface;
|
||||
|
||||
class Configuration implements ConfigurationInterface
|
||||
{
|
||||
public function getConfigTreeBuilder()
|
||||
{
|
||||
$treeBuilder = new TreeBuilder('chill_aside_activity');
|
||||
|
||||
$treeBuilder->getRootNode('chill_aside_activity')
|
||||
->children()
|
||||
->arrayNode('form')
|
||||
->canBeEnabled()
|
||||
->children()
|
||||
->arrayNode('time_duration')
|
||||
->isRequired()
|
||||
->defaultValue(
|
||||
[
|
||||
[ 'label' => '5 minutes', 'seconds' => 300],
|
||||
[ 'label' => '10 minutes', 'seconds' => 600],
|
||||
[ 'label' => '15 minutes', 'seconds' => 900],
|
||||
[ 'label' => '20 minutes', 'seconds' => 1200],
|
||||
[ 'label' => '25 minutes', 'seconds' => 1500],
|
||||
[ 'label' => '30 minutes', 'seconds' => 1800],
|
||||
[ 'label' => '45 minutes', 'seconds' => 2700],
|
||||
[ 'label' => '1 hour', 'seconds' => 3600],
|
||||
[ 'label' => '1 hour 15', 'seconds' => 4500],
|
||||
[ 'label' => '1 hour 30', 'seconds' => 5400],
|
||||
[ 'label' => '1 hour 45', 'seconds' => 6300],
|
||||
[ 'label' => '2 hours', 'seconds' => 7200],
|
||||
[ 'label' => '2 hours 30', 'seconds' => 9000],
|
||||
[ 'label' => '3 hours', 'seconds' => 10800],
|
||||
[ 'label' => '3 hours 30', 'seconds' => 12600],
|
||||
[ 'label' => '4 hours', 'seconds' => 14400],
|
||||
[ 'label' => '4 hours 30', 'seconds' => 16200],
|
||||
[ 'label' => '5 hours', 'seconds' => 18000],
|
||||
[ 'label' => '5 hours 30', 'seconds' => 19800],
|
||||
[ 'label' => '6 hours', 'seconds' => 21600],
|
||||
[ 'label' => '6 hours 30', 'seconds' => 23400],
|
||||
[ 'label' => '7 hours', 'seconds' => 25200],
|
||||
[ 'label' => '7 hours 30', 'seconds' => 27000],
|
||||
[ 'label' => '8 hours', 'seconds' => 28800],
|
||||
[ 'label' => '8 hours 30', 'seconds' => 30600],
|
||||
[ 'label' => '9 hours', 'seconds' => 32400],
|
||||
[ 'label' => '9 hours 30', 'seconds' => 34200],
|
||||
[ 'label' => '10 hours', 'seconds' => 36000],
|
||||
[ 'label' => '1/2 day', 'seconds' => 14040],
|
||||
[ 'label' => '1 day', 'seconds' => 28080],
|
||||
[ 'label' => '1 1/2 days', 'seconds' => 42120],
|
||||
[ 'label' => '2 days', 'seconds' => 56160],
|
||||
[ 'label' => '2 1/2 days', 'seconds' => 70200],
|
||||
[ 'label' => '3 days', 'seconds' => 84240],
|
||||
[ 'label' => '3 1/2 days', 'seconds' => 98280],
|
||||
[ 'label' => '4 days', 'seconds' => 112320],
|
||||
[ 'label' => '4 1/2 days', 'seconds' => 126360],
|
||||
[ 'label' => '5 days', 'seconds' => 140400],
|
||||
[ 'label' => '5 1/2 days', 'seconds' => 154440],
|
||||
[ 'label' => '6 days', 'seconds' => 168480],
|
||||
[ 'label' => '6 1/2 days', 'seconds' => 182520],
|
||||
[ 'label' => '7 days', 'seconds' => 196560],
|
||||
[ 'label' => '7 1/2 days', 'seconds' => 210600],
|
||||
[ 'label' => '8 days', 'seconds' => 224640],
|
||||
[ 'label' => '8 1/2 days', 'seconds' => 238680],
|
||||
[ 'label' => '9 days', 'seconds' => 252720],
|
||||
[ 'label' => '9 1/2 days', 'seconds' => 266760],
|
||||
[ 'label' => '10 days', 'seconds' => 280800],
|
||||
[ 'label' => '10 1/2days', 'seconds' => 294840],
|
||||
[ 'label' => '11 days', 'seconds' => 308880],
|
||||
[ 'label' => '11 1/2 days', 'seconds' => 322920],
|
||||
[ 'label' => '12 days', 'seconds' => 336960],
|
||||
[ 'label' => '12 1/2 days', 'seconds' => 351000],
|
||||
[ 'label' => '13 days', 'seconds' => 365040],
|
||||
[ 'label' => '13 1/2 days', 'seconds' => 379080],
|
||||
[ 'label' => '14 days', 'seconds' => 393120],
|
||||
[ 'label' => '14 1/2 days', 'seconds' => 407160],
|
||||
[ 'label' => '15 days', 'seconds' => 421200],
|
||||
[ 'label' => '15 1/2 days', 'seconds' => 435240],
|
||||
[ 'label' => '16 days', 'seconds' => 449280],
|
||||
[ 'label' => '16 1/2 days', 'seconds' => 463320],
|
||||
[ 'label' => '17 days', 'seconds' => 477360],
|
||||
[ 'label' => '17 1/2 days', 'seconds' => 491400],
|
||||
[ 'label' => '18 days', 'seconds' => 505440],
|
||||
[ 'label' => '18 1/2 days', 'seconds' => 519480],
|
||||
[ 'label' => '19 days', 'seconds' => 533520],
|
||||
[ 'label' => '19 1/2 days', 'seconds' => 547560],
|
||||
[ 'label' => '20 days', 'seconds' => 561600],
|
||||
[ 'label' => '20 1/2 days', 'seconds' => 575640],
|
||||
[ 'label' => '21 days', 'seconds' => 580680],
|
||||
[ 'label' => '21 1/2 days', 'seconds' => 603720],
|
||||
[ 'label' => '22 days', 'seconds' => 617760],
|
||||
[ 'label' => '22 1/2 days', 'seconds' => 631800],
|
||||
[ 'label' => '23 days', 'seconds' => 645840],
|
||||
[ 'label' => '23 1/2 days', 'seconds' => 659880],
|
||||
[ 'label' => '24 days', 'seconds' => 673920],
|
||||
[ 'label' => '24 1/2 days', 'seconds' => 687960],
|
||||
[ 'label' => '25 days', 'seconds' => 702000],
|
||||
[ 'label' => '25 1/2 days', 'seconds' => 716040],
|
||||
[ 'label' => '26 days', 'seconds' => 730080],
|
||||
[ 'label' => '26 1/2 days', 'seconds' => 744120],
|
||||
[ 'label' => '27 days', 'seconds' => 758160],
|
||||
[ 'label' => '27 1/2 days', 'seconds' => 772200],
|
||||
[ 'label' => '28 days', 'seconds' => 786240],
|
||||
[ 'label' => '28 1/2 days', 'seconds' => 800280],
|
||||
[ 'label' => '29 days', 'seconds' => 814320],
|
||||
[ 'label' => '29 1/2 days', 'seconds' => 828360],
|
||||
[ 'label' => '30 days', 'seconds' => 842400],
|
||||
]
|
||||
)
|
||||
->info('The intervals of time to show in activity form')
|
||||
|
||||
->prototype('array')
|
||||
->children()
|
||||
->scalarNode('seconds')
|
||||
->info("The number of seconds of this duration. Must be an integer.")
|
||||
->cannotBeEmpty()
|
||||
->validate()
|
||||
->ifTrue(function($data) {
|
||||
return !is_int($data);
|
||||
})->thenInvalid("The value %s is not a valid integer")
|
||||
->end()
|
||||
->end()
|
||||
->scalarNode('label')
|
||||
->cannotBeEmpty()
|
||||
->info("The label to show into fields")
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->end();
|
||||
|
||||
return $treeBuilder;
|
||||
}
|
||||
}
|
@@ -7,6 +7,8 @@ namespace Chill\AsideActivityBundle\Entity;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
use Symfony\Component\Validator\Context\ExecutionContextInterface;
|
||||
|
||||
/**
|
||||
* @ORM\Entity
|
||||
@@ -27,10 +29,33 @@ class AsideActivityCategory
|
||||
private array $title;
|
||||
|
||||
/**
|
||||
* @ORM\OneToMany(targetEntity=AsideActivityCategory::class, mappedBy="parent")
|
||||
* @ORM\Column(type="boolean")
|
||||
*/
|
||||
private bool $isActive = true;
|
||||
|
||||
/**
|
||||
* @var float
|
||||
* @ORM\Column(type="float", options={"default": 0.00})
|
||||
*/
|
||||
private float $ordering = 0.00;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity=AsideActivityCategory::class, inversedBy="children")
|
||||
* @ORM\JoinColumn(nullable=true)
|
||||
*/
|
||||
private $parent;
|
||||
|
||||
/**
|
||||
* @ORM\OneToMany(targetEntity=AsideActivityCategory::class, mappedBy="parent")
|
||||
*/
|
||||
private $children;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->children = new ArrayCollection();
|
||||
}
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
@@ -59,4 +84,85 @@ class AsideActivityCategory
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getParent(): ?self
|
||||
{
|
||||
return $this->parent;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @Assert\Callback()
|
||||
*/
|
||||
public function preventRecursiveParent(ExecutionContextInterface $context, $payload)
|
||||
{
|
||||
if (!$this->hasParent()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->getParent() === $this) {
|
||||
// replace parent with old parent. This prevent recursive loop
|
||||
// when displaying form
|
||||
$this->parent = $this->oldParent;
|
||||
$context->buildViolation('You must not add twice the same category in the parent tree (previous result returned)')
|
||||
->atPath('parent')
|
||||
->addViolation()
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
public function hasParent(): bool
|
||||
{
|
||||
return $this->parent !== null;
|
||||
}
|
||||
|
||||
public function setParent(?self $parent): self
|
||||
{
|
||||
// cache the old result for changing it during validaiton
|
||||
$this->oldParent = $this->parent;
|
||||
$this->parent = $parent;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection|self[]
|
||||
*/
|
||||
public function getChildren(): Collection
|
||||
{
|
||||
return $this->children;
|
||||
}
|
||||
|
||||
public function addChild(self $child): self
|
||||
{
|
||||
if (!$this->children->contains($child)) {
|
||||
$this->children[] = $child;
|
||||
$child->setParent($this);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function removeChild(self $child): self
|
||||
{
|
||||
if ($this->children->removeElement($child)) {
|
||||
// set the owning side to null (unless already changed)
|
||||
if ($child->getParent() === $this) {
|
||||
$child->setParent(null);
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getOrdering(): float
|
||||
{
|
||||
return $this->ordering;
|
||||
}
|
||||
|
||||
public function setOrdering(float $ordering): AsideActivityCategory
|
||||
{
|
||||
$this->ordering = $ordering;
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
@@ -3,21 +3,43 @@
|
||||
namespace Chill\AsideActivityBundle\Form;
|
||||
|
||||
use Chill\AsideActivityBundle\Entity\AsideActivityCategory;
|
||||
use Chill\AsideActivityBundle\Templating\Entity\CategoryRender;
|
||||
use Chill\MainBundle\Form\Type\TranslatableStringFormType;
|
||||
use Chill\MainBundle\Templating\TranslatableStringHelper;
|
||||
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||
|
||||
use Symfony\Component\Form\Extension\Core\Type\NumberType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
|
||||
final class AsideActivityCategoryType extends AbstractType
|
||||
{
|
||||
|
||||
protected $translatableStringHelper;
|
||||
|
||||
public function __construct(TranslatableStringHelper $translatableStringHelper, CategoryRender $categoryRender)
|
||||
{
|
||||
$this->translatableStringHelper = $translatableStringHelper;
|
||||
$this->categoryRender = $categoryRender;
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||
{
|
||||
$builder->add('title', TranslatableStringFormType::class,
|
||||
[
|
||||
'label' => 'Nom',
|
||||
])
|
||||
->add('isActive', ChoiceType::class,
|
||||
->add('parent', EntityType::class, [
|
||||
'class' => AsideActivityCategory::class,
|
||||
'required' => false,
|
||||
'label' => 'Parent',
|
||||
'choice_label' => function (AsideActivityCategory $category){
|
||||
$options = [];
|
||||
return $this->categoryRender->renderString($category, $options);
|
||||
}
|
||||
])
|
||||
->add('ordering', NumberType::class)
|
||||
->add('isActive', ChoiceType::class,
|
||||
[
|
||||
'choices' => [
|
||||
'Yes' => true,
|
||||
|
@@ -4,11 +4,13 @@ namespace Chill\AsideActivityBundle\Form;
|
||||
|
||||
use Chill\AsideActivityBundle\Entity\AsideActivity;
|
||||
use Chill\AsideActivityBundle\Entity\AsideActivityCategory;
|
||||
use Chill\AsideActivityBundle\Templating\Entity\CategoryRender;
|
||||
use Chill\MainBundle\Entity\User;
|
||||
use Chill\MainBundle\Form\Type\ChillDateType;
|
||||
use Chill\MainBundle\Form\Type\ChillTextareaType;
|
||||
use Chill\MainBundle\Templating\TranslatableStringHelper;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
||||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
@@ -16,26 +18,27 @@ use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToTimestampTra
|
||||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
|
||||
use Symfony\Component\Form\FormEvent;
|
||||
use Symfony\Component\Form\FormEvents;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
|
||||
use Symfony\Component\Security\Core\Security;
|
||||
use Symfony\Component\Templating\EngineInterface;
|
||||
|
||||
final class AsideActivityFormType extends AbstractType
|
||||
{
|
||||
protected array $timeChoices;
|
||||
private TranslatableStringHelper $translatableStringHelper;
|
||||
private TokenStorageInterface $storage;
|
||||
private CategoryRender $categoryRender;
|
||||
|
||||
public function __construct (
|
||||
TranslatableStringHelper $translatableStringHelper,
|
||||
ParameterBagInterface $parameterBag,
|
||||
TokenStorageInterface $storage
|
||||
TokenStorageInterface $storage,
|
||||
CategoryRender $categoryRender
|
||||
){
|
||||
$this->timeChoices = $parameterBag->get('chill_activity.form.time_duration');
|
||||
$this->timeChoices = $parameterBag->get('chill_aside_activity.form.time_duration');
|
||||
$this->translatableStringHelper = $translatableStringHelper;
|
||||
$this->storage = $storage;
|
||||
$this->categoryRender = $categoryRender;
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||
@@ -70,11 +73,6 @@ final class AsideActivityFormType extends AbstractType
|
||||
[
|
||||
'label' => 'date',
|
||||
'data' => new \DateTime(),
|
||||
//SETTING RANGE ONLY POSSIBLE WITH WIDGET 'CHOICE' AND NOT 'SINGLE_TEXT'?
|
||||
// 'widget' => 'choice',
|
||||
// 'years' => range(2020, date('Y')),
|
||||
// 'months' => range(1, date('m')),
|
||||
// 'days' => range(1, date('d')),
|
||||
'required' => true
|
||||
])
|
||||
->add('type', EntityType::class,
|
||||
@@ -83,9 +81,17 @@ final class AsideActivityFormType extends AbstractType
|
||||
'required' => true,
|
||||
'class' => AsideActivityCategory::class,
|
||||
'placeholder' => 'Choose the activity category',
|
||||
// 'choice_label' => 'title[""]'
|
||||
'query_builder' => function(EntityRepository $er) {
|
||||
$qb = $er->createQueryBuilder('ac');
|
||||
$qb->where($qb->expr()->eq('ac.isActive', 'TRUE'))
|
||||
->addOrderBy('ac.ordering', 'ASC')
|
||||
;
|
||||
|
||||
return $qb;
|
||||
},
|
||||
'choice_label' => function (AsideActivityCategory $asideActivityCategory) {
|
||||
return $this->translatableStringHelper->localize($asideActivityCategory->getTitle());
|
||||
$options = [];
|
||||
return $this->categoryRender->renderString($asideActivityCategory, $options);
|
||||
},
|
||||
])
|
||||
->add('duration', ChoiceType::class, $durationTimeOptions)
|
||||
|
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace Chill\AsideActivityBundle\Menu;
|
||||
|
||||
use Knp\Menu\MenuItem;
|
||||
use Symfony\Component\Security\Core\Security;
|
||||
|
||||
final class AdminMenuBuilder implements \Chill\MainBundle\Routing\LocalMenuBuilderInterface
|
||||
{
|
||||
private Security $security;
|
||||
|
||||
public function __construct(Security $security)
|
||||
{
|
||||
$this->security = $security;
|
||||
}
|
||||
|
||||
public static function getMenuIds(): array
|
||||
{
|
||||
return ['admin_index', 'admin_section', 'admin_aside_activity'];
|
||||
}
|
||||
|
||||
public function buildMenu($menuId, MenuItem $menu, array $parameters)
|
||||
{
|
||||
// all the entries below must have ROLE_ADMIN permissions
|
||||
if (!$this->security->isGranted('ROLE_ADMIN')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (in_array($menuId, ['admin_index', 'admin_section'])) {
|
||||
$menu->addChild('Aside activities', [
|
||||
'route' => 'chill_crud_aside_activity_category_index'
|
||||
])
|
||||
->setExtras([
|
||||
'order' => 900,
|
||||
'explain' => "Configure aside activities categories"
|
||||
]);
|
||||
} else {
|
||||
$menu
|
||||
->addChild('Aside activity categories', [
|
||||
'route' => 'chill_crud_aside_activity_category_index'
|
||||
])
|
||||
->setExtras([
|
||||
'order' => '50'
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@@ -4,6 +4,8 @@ namespace Chill\AsideActivityBundle\Menu;
|
||||
|
||||
use Chill\MainBundle\Routing\LocalMenuBuilderInterface;
|
||||
use Knp\Menu\MenuItem;
|
||||
use Symfony\Component\Security\Core\Authorization\AuthorizationChecker;
|
||||
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
|
||||
/**
|
||||
@@ -14,10 +16,12 @@ use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
class SectionMenuBuilder implements LocalMenuBuilderInterface
|
||||
{
|
||||
protected TranslatorInterface $translator;
|
||||
public AuthorizationCheckerInterface $authorizationChecker;
|
||||
|
||||
public function __construct(TranslatorInterface $translator)
|
||||
public function __construct(TranslatorInterface $translator, AuthorizationCheckerInterface $authorizationChecker)
|
||||
{
|
||||
$this->translator = $translator;
|
||||
$this->authorizationChecker = $authorizationChecker;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -27,13 +31,26 @@ class SectionMenuBuilder implements LocalMenuBuilderInterface
|
||||
*/
|
||||
public function buildMenu($menuId, MenuItem $menu, array $parameters)
|
||||
{
|
||||
$menu->addChild($this->translator->trans('Create an aside activity'), [
|
||||
'route' => 'chill_crud_aside_activity_new'
|
||||
if ($this->authorizationChecker->isGranted('ROLE_USER')){
|
||||
$menu->addChild($this->translator->trans('Create an aside activity'), [
|
||||
'route' => 'chill_crud_aside_activity_new'
|
||||
])
|
||||
->setExtras([
|
||||
'order' => 11,
|
||||
'icons' => [ 'plus' ]
|
||||
]);
|
||||
$menu->addChild($this->translator->trans('Phonecall'), [
|
||||
'route' => 'chill_crud_aside_activity_new',
|
||||
'routeParameters' => [
|
||||
'type' => 1,
|
||||
'duration' => 900,
|
||||
]
|
||||
])
|
||||
->setExtras([
|
||||
'order' => 11,
|
||||
'icons' => [ 'plus' ]
|
||||
'order' => 12,
|
||||
'icons' => ['plus']
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright (C) 2018 Champs Libres Cooperative <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\AsideActivityBundle\Menu;
|
||||
|
||||
use Chill\MainBundle\Routing\LocalMenuBuilderInterface;
|
||||
use Knp\Menu\MenuItem;
|
||||
use Chill\TaskBundle\Templating\UI\CountNotificationTask;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
|
||||
use Symfony\Component\Translation\TranslatorInterface;
|
||||
use Chill\MainBundle\Entity\User;
|
||||
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author Julien Fastré <julien.fastre@champs-libres.coop>
|
||||
*/
|
||||
class UserMenuBuilder implements LocalMenuBuilderInterface
|
||||
{
|
||||
|
||||
/**
|
||||
*
|
||||
* @var CountNotificationTask
|
||||
*/
|
||||
public $counter;
|
||||
|
||||
/*
|
||||
* @var TokenStorageInterface
|
||||
*/
|
||||
public $tokenStorage;
|
||||
|
||||
/**
|
||||
*
|
||||
* @var TranslatorInterface
|
||||
*/
|
||||
public $translator;
|
||||
|
||||
/**
|
||||
*
|
||||
* @var AuthorizationCheckerInterface
|
||||
*/
|
||||
public $authorizationChecker;
|
||||
|
||||
public function __construct(
|
||||
CountNotificationTask $counter,
|
||||
TokenStorageInterface $tokenStorage,
|
||||
TranslatorInterface $translator,
|
||||
AuthorizationCheckerInterface $authorizationChecker
|
||||
) {
|
||||
$this->counter = $counter;
|
||||
$this->tokenStorage = $tokenStorage;
|
||||
$this->translator = $translator;
|
||||
$this->authorizationChecker = $authorizationChecker;
|
||||
}
|
||||
|
||||
|
||||
public function buildMenu($menuId, MenuItem $menu, array $parameters)
|
||||
{
|
||||
if ($this->authorizationChecker->isGranted('ROLE_USER')){
|
||||
$menu->addChild("My aside activities", [
|
||||
'route' => 'chill_crud_aside_activity_index'
|
||||
])
|
||||
->setExtras([
|
||||
'order' => 10,
|
||||
'icon' => 'tasks'
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static function getMenuIds(): array
|
||||
{
|
||||
return [ 'user' ];
|
||||
}
|
||||
|
||||
}
|
@@ -1,14 +1,12 @@
|
||||
{% extends "@ChillMain/Admin/layoutWithVerticalMenu.html.twig" %}
|
||||
|
||||
{% block vertical_menu_content %}
|
||||
{{ chill_menu('admin_aside_activity', {
|
||||
'layout': '@ChillAsideActivity/Admin/menu_asideactivity.html.twig',
|
||||
}) }}
|
||||
{{ chill_menu('admin_aside_activity') }}
|
||||
{% endblock %}
|
||||
|
||||
{% block layout_wvm_content %}
|
||||
{% block admin_content %}
|
||||
<!-- block personcontent empty -->
|
||||
<h1>{{ 'Aside activity configuration' |trans }}</h1>
|
||||
<h1>{{ 'Aside activity configuration'|trans }}</h1>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
|
@@ -1,4 +0,0 @@
|
||||
{% extends "@ChillMain/Menu/verticalMenu.html.twig" %}
|
||||
{% block v_menu_title %}
|
||||
{{ 'Aside activity configuration menu'|trans }}
|
||||
{% endblock %}
|
@@ -0,0 +1,12 @@
|
||||
{% set reversed_parents = parents|reverse %}
|
||||
<span
|
||||
class="chill-entity entity-aside_activity-category">
|
||||
{%- for p in reversed_parents %}
|
||||
<span class="parent-{{ loop.revindex0 }}">
|
||||
{{ p.title|localize_translatable_string }}{{ options['default.separator'] }}
|
||||
</span>
|
||||
{%- endfor -%}
|
||||
<span class="child">
|
||||
{{ asideActivityCategory.title|localize_translatable_string }}
|
||||
</span>
|
||||
</span>
|
@@ -1,8 +1,91 @@
|
||||
{% extends '@ChillMain/layout.html.twig' %}
|
||||
{% extends "@ChillMain/layout.html.twig" %}
|
||||
|
||||
{% block title %}{{ ('crud.' ~ crud_name ~ '.index.title')|trans({'%crud_name%': crud_name}) }}{% endblock %}
|
||||
{% block title %}
|
||||
{{ 'Aside activity list'|trans }}
|
||||
{% endblock title %}
|
||||
|
||||
{% block content %}
|
||||
{% embed '@ChillAsideActivity/AsideActivity/_index.html.twig' %}
|
||||
{% endembed %}
|
||||
{% endblock content %}
|
||||
<div class="col-md-10 asideactivity-list">
|
||||
<h2>{{ 'My aside activities'|trans }}</h2>
|
||||
|
||||
{% if entities|length == 0 %}
|
||||
<p class="chill-no-data-statement">
|
||||
{{ "There aren't any aside activities."|trans }}
|
||||
<a href="{{ path('chill_crud_aside_activity_new') }}" class="btn btn-create button-small"></a>
|
||||
</p>
|
||||
{% else %}
|
||||
|
||||
<div class="flex-table">
|
||||
|
||||
{% for entity in entities %}
|
||||
|
||||
<div class="item-bloc">
|
||||
<div class="item-row wrap-header">
|
||||
|
||||
<div class="item-col">
|
||||
<h3>
|
||||
{{ entity.type|chill_entity_render_box }}
|
||||
</h3>
|
||||
<div>
|
||||
{% if entity.date %}
|
||||
<span>{{ entity.date|format_date('long') }}</span>
|
||||
{% endif %}
|
||||
{% if entity.date %}
|
||||
<span class="duration">
|
||||
|
||||
<i class="fa fa-fw fa-hourglass-end"></i>
|
||||
{{ entity.duration|date('H:i') }}
|
||||
|
||||
</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="item-col">
|
||||
<div class="box">
|
||||
<ul class="list-content fa-ul">
|
||||
<li>
|
||||
<span>
|
||||
<abbr class="referrer" title={{ 'Created by'|trans }}>{{ 'By'|trans }}:</abbr>
|
||||
<b>{{ entity.createdBy|chill_entity_render_box }}</b>
|
||||
</span>
|
||||
</li>
|
||||
<li>
|
||||
<span>
|
||||
<abbr class="referrer" title={{ 'Created for'|trans }}>{{ 'For'|trans }}:</abbr>
|
||||
<b>{{ entity.agent|chill_entity_render_box }}</b>
|
||||
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="action">
|
||||
<ul class="record_actions">
|
||||
<li>
|
||||
<a href="{{ chill_path_add_return_path('chill_crud_aside_activity_view', { 'id': entity.id } ) }}" class="btn btn-show btn-mini"></a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{{ chill_path_add_return_path('chill_crud_aside_activity_edit', { 'id': entity.id }) }}" class="btn btn-update btn-mini "></a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{{ chill_path_add_return_path('chill_crud_aside_activity_delete', { 'id': entity.id } ) }}" class="btn btn-delete btn-mini"></a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
{{ chill_pagination(paginator) }}
|
||||
|
||||
<ul class="record_actions">
|
||||
<li>
|
||||
<a href="{{ chill_path_add_return_path('chill_crud_aside_activity_new') }}" class="btn btn-create">
|
||||
{{ 'Create'|trans }}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
||||
|
@@ -1,97 +0,0 @@
|
||||
{% extends "@ChillMain/layout.html.twig" %}
|
||||
|
||||
{% block title %}
|
||||
{{ 'Aside activity list' |trans }}
|
||||
{% endblock title %}
|
||||
|
||||
{% block content %}
|
||||
<div class="col-md-10 col-xxl asideactivity-list">
|
||||
<h2>{{ 'My aside activities' |trans }}</h2>
|
||||
|
||||
{% if entities|length == 0 %}
|
||||
<p class="chill-no-data-statement">
|
||||
{{ "There aren't any aside activities."|trans }}
|
||||
<a href="{{ path('chill_crud_aside_activity_new') }}" class="btn btn-create button-small"></a>
|
||||
</p>
|
||||
{% else %}
|
||||
|
||||
<div
|
||||
class="flex-table my-4 list-records">
|
||||
{# Sort activities according to date in descending order #}
|
||||
{% for entity in entities %}
|
||||
{% set t = entity.type %}
|
||||
|
||||
<div class="item-bloc">
|
||||
<div class="item-row main">
|
||||
<div class="item-col">
|
||||
|
||||
<h3>
|
||||
<b>{{ entity.type.title | localize_translatable_string }}</b>
|
||||
</h3>
|
||||
|
||||
{% if entity.date %}
|
||||
<p>{{ entity.date|format_date('long') }}</p>
|
||||
{% endif %}
|
||||
|
||||
<div class="duration">
|
||||
<p>
|
||||
<i class="fa fa-fw fa-hourglass-end"></i>
|
||||
{{ entity.duration|date('H:i') }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="item-col">
|
||||
<ul class="list-content">
|
||||
{% if entity.createdBy %}
|
||||
<li>
|
||||
<b>{{ 'Created by: '|trans }}{{ entity.createdBy.usernameCanonical }}</b>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# {%
|
||||
if entity.note is not empty
|
||||
or entity.createdBy|length > 0
|
||||
%}
|
||||
<div class="item-row details">
|
||||
{% if entity.note is not empty %}
|
||||
<div class="item-col comment">
|
||||
{{ entity.note|chill_markdown_to_html }}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
{% endif %} #}
|
||||
<div class="item-col">
|
||||
<ul class="list-content">
|
||||
<ul class="record_actions">
|
||||
<li>
|
||||
<a href="{{ chill_path_add_return_path('chill_crud_aside_activity_edit', { 'id': entity.id }) }}" class="btn btn-update btn-mini "></a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{{ chill_path_add_return_path('chill_crud_aside_activity_delete', { 'id': entity.id } ) }}" class="btn btn-delete btn-mini"></a>
|
||||
</li>
|
||||
</ul>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
{{ chill_pagination(paginator) }}
|
||||
|
||||
<ul class="record_actions">
|
||||
<li>
|
||||
<a href="{{ chill_path_add_return_path('chill_crud_aside_activity_new') }}" class="btn btn-create">
|
||||
{{ 'Create' | trans }}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
@@ -3,13 +3,50 @@
|
||||
{% set activeRouteKey = '' %}
|
||||
|
||||
{% block title %}
|
||||
{% include('@ChillMain/CRUD/_view_title.html.twig') %}
|
||||
{% include('@ChillMain/CRUD/_view_title.html.twig') %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% embed '@ChillMain/CRUD/_view_content.html.twig' %}
|
||||
{% block crud_content_header %}
|
||||
<h1>{{ ('crud.' ~ crud_name ~ '.title_view')|trans }}</h1>
|
||||
{% endblock crud_content_header %}
|
||||
{% endembed %}
|
||||
{% endblock %}
|
||||
{% embed '@ChillMain/CRUD/_view_content.html.twig' %}
|
||||
{% block crud_content_header %}
|
||||
<h1>{{ ('crud.' ~ crud_name ~ '.title_view')|trans }}</h1>
|
||||
{% endblock crud_content_header %}
|
||||
{% block crud_content_view_details %}
|
||||
<dl class="chill_view_data">
|
||||
|
||||
<dt class="inline">{{ 'Type'|trans }}</dt>
|
||||
<dd>{{ entity.type|chill_entity_render_box }}</dd>
|
||||
|
||||
<dt class="inline">{{ 'Created by'|trans }}</dt>
|
||||
<dd>{{ entity.createdBy }}</dd>
|
||||
|
||||
<dt class="inline">{{ 'Created for'|trans }}</dt>
|
||||
<dd>{{ entity.agent }}</dd>
|
||||
|
||||
<h2 class="chill-red">{{ 'Activity data'|trans }}</h2>
|
||||
|
||||
<dt class="inline">{{ 'Date'|trans }}</dt>
|
||||
<dd>{{ entity.date|format_date('long') }}</dd>
|
||||
|
||||
<dt class="inline">{{ 'Duration'|trans }}</dt>
|
||||
<dd>{{ entity.duration|date('H:i') }}</dd>
|
||||
|
||||
<dt class="inline">{{ 'Remark'|trans }}</dt>
|
||||
{%- if entity.note is empty -%}
|
||||
<dd>
|
||||
<span class="chill-no-data-statement">{{ 'No comments'|trans }}</span>
|
||||
</dd>
|
||||
{%- else -%}
|
||||
<dd>
|
||||
<section class="chill-entity entity-comment-embeddable">
|
||||
<blockquote class="chill-user-quote">
|
||||
<p>{{ entity.note }}</p>
|
||||
</blockquote>
|
||||
</section>
|
||||
</dd>
|
||||
{%- endif -%}
|
||||
</dl>
|
||||
|
||||
{% endblock %}
|
||||
{% endembed %}
|
||||
{% endblock %}
|
||||
|
@@ -1,4 +1,4 @@
|
||||
{% extends "@ChillActivity/Admin/layout_activity.html.twig" %}
|
||||
{% extends "@ChillAsideActivity/Admin/layout_asideactivity.html.twig" %}
|
||||
|
||||
{% block title %}
|
||||
{% include('@ChillMain/CRUD/_edit_title.html.twig') %}
|
||||
|
@@ -1,11 +1,12 @@
|
||||
{% extends "@ChillAsideActivity/Admin/layout_asideactivity.html.twig" %}
|
||||
|
||||
{% block admin_content %}
|
||||
<h1>{{ 'ActivityType list'|trans }}</h1>
|
||||
<h1>{{ 'Aside Activity Type list'|trans }}</h1>
|
||||
|
||||
<table class="records_list table table-bordered border-dark">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ 'Ordering'|trans }}</th>
|
||||
<th>{{ 'Name'|trans }}</th>
|
||||
<th>{{ 'Active'|trans }}</th>
|
||||
<th>{{ 'Actions'|trans }}</th>
|
||||
@@ -14,7 +15,8 @@
|
||||
<tbody>
|
||||
{% for entity in entities %}
|
||||
<tr>
|
||||
<td>{{ entity.title|localize_translatable_string }}</td>
|
||||
<td>{{ entity.ordering }}</td>
|
||||
<td>{{ entity|chill_entity_render_box }}</td>
|
||||
<td style="text-align:center;">
|
||||
{%- if entity.isActive -%}
|
||||
<i class="fa fa-check-square-o"></i>
|
||||
|
@@ -1,4 +1,4 @@
|
||||
{% extends "@ChillActivity/Admin/layout_activity.html.twig" %}
|
||||
{% extends "@ChillAsideActivity/Admin/layout_asideactivity.html.twig" %}
|
||||
|
||||
{% block title %}
|
||||
{% include('@ChillMain/CRUD/_new_title.html.twig') %}
|
||||
|
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
namespace Chill\AsideActivityBundle\Templating\Entity;
|
||||
|
||||
use Chill\AsideActivityBundle\Entity\AsideActivityCategory;
|
||||
use Chill\MainBundle\Templating\Entity\ChillEntityRenderInterface;
|
||||
use Chill\MainBundle\Templating\TranslatableStringHelper;
|
||||
use Symfony\Component\Templating\EngineInterface;
|
||||
|
||||
final class CategoryRender implements ChillEntityRenderInterface
|
||||
{
|
||||
private TranslatableStringHelper $translatableStringHelper;
|
||||
private EngineInterface $engine;
|
||||
|
||||
public const SEPERATOR_KEY = 'default.separator';
|
||||
public const DEFAULT_ARGS = [
|
||||
self::SEPERATOR_KEY => ' > '
|
||||
];
|
||||
|
||||
public function __construct(TranslatableStringHelper $translatableStringHelper, EngineInterface $engine)
|
||||
{
|
||||
$this->translatableStringHelper = $translatableStringHelper;
|
||||
$this->engine = $engine;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param AsideActivityCategory $asideActivityCategory
|
||||
*/
|
||||
public function renderString($asideActivityCategory, array $options): string
|
||||
{
|
||||
$options = array_merge(self::DEFAULT_ARGS, $options);
|
||||
|
||||
$titles[] = $this->translatableStringHelper->localize($asideActivityCategory->getTitle());
|
||||
|
||||
while ($asideActivityCategory->hasParent()) {
|
||||
$asideActivityCategory = $asideActivityCategory->getParent();
|
||||
$titles[] = $this->translatableStringHelper->localize($asideActivityCategory->getTitle());
|
||||
}
|
||||
|
||||
$titles = array_reverse($titles);
|
||||
|
||||
return implode($options[self::SEPERATOR_KEY], $titles);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param AsideActivityCategory $asideActivityCategory
|
||||
*/
|
||||
public function supports($asideActivityCategory, array $options): bool
|
||||
{
|
||||
return $asideActivityCategory instanceof AsideActivityCategory;
|
||||
}
|
||||
|
||||
public function buildParents(AsideActivityCategory $asideActivityCategory)
|
||||
{
|
||||
$parents = [];
|
||||
|
||||
while($asideActivityCategory->hasParent()) {
|
||||
$asideActivityCategory = $parents[] = $asideActivityCategory->getParent();
|
||||
}
|
||||
|
||||
return $parents;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param AsideActivityCategory $asideActivityCategory
|
||||
*/
|
||||
public function renderBox($asideActivityCategory, array $options): string
|
||||
{
|
||||
$options = array_merge(self::DEFAULT_ARGS, $options);
|
||||
$parents = $this->buildParents($asideActivityCategory);
|
||||
|
||||
return $this->engine->render('@ChillAsideActivity/Entity/asideActivityCategory.html.twig',
|
||||
[
|
||||
'asideActivityCategory' => $asideActivityCategory,
|
||||
'parents' => $parents,
|
||||
'options' => $options
|
||||
]);
|
||||
}
|
||||
}
|
@@ -1,5 +1,22 @@
|
||||
services:
|
||||
Chill\AsideActivityBundle\DataFixtures\:
|
||||
resource: './../DataFixtures'
|
||||
autowire: true
|
||||
autoconfigure: true
|
||||
Chill\AsideActivityBundle\DataFixtures\:
|
||||
resource: "./../DataFixtures"
|
||||
autowire: true
|
||||
autoconfigure: true
|
||||
|
||||
Chill\AsideActivityBundle\Templating\Entity\:
|
||||
autowire: true
|
||||
autoconfigure: true
|
||||
resource: "../Templating/Entity"
|
||||
tags:
|
||||
- "chill.render_entity"
|
||||
|
||||
Chill\AsideActivityBundle\Repository\:
|
||||
resource: "../Repository"
|
||||
autowire: true
|
||||
autoconfigure: true
|
||||
|
||||
Chill\AsideActivityBundle\Controller\:
|
||||
resource: "../Controller"
|
||||
autowire: true
|
||||
autoconfigure: true
|
||||
|
@@ -1,5 +1,5 @@
|
||||
services:
|
||||
Chill\AsideActivityBundle\Menu\:
|
||||
resource: './../../Menu'
|
||||
resource: "./../../Menu"
|
||||
autowire: true
|
||||
autoconfigure: true
|
||||
|
@@ -7,14 +7,11 @@ namespace Chill\Migrations\AsideActivity;
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
/**
|
||||
* Auto-generated Migration: Please modify to your needs!
|
||||
*/
|
||||
final class Version20210706124644 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return '';
|
||||
return 'Aside activity category entity created';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
|
@@ -7,14 +7,11 @@ namespace Chill\Migrations\AsideActivity;
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
/**
|
||||
* Auto-generated Migration: Please modify to your needs!
|
||||
*/
|
||||
final class Version20210804082249 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return '';
|
||||
return 'Aside activity entity created';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
@@ -59,12 +56,12 @@ final class Version20210804082249 extends AbstractMigration
|
||||
$this->addSql('CREATE INDEX idx_e9fa219165ff1aec ON asideactivity (updatedby_id)');
|
||||
$this->addSql('CREATE INDEX idx_e9fa21913414710b ON asideactivity (agent_id)');
|
||||
$this->addSql('COMMENT ON COLUMN asideactivity.updatedat IS \'(DC2Type:datetime_immutable)\'');
|
||||
$this->addSql('CREATE TABLE chill_main_address_legacy (id INT DEFAULT NULL, postcode_id INT DEFAULT NULL, street VARCHAR(255) DEFAULT NULL, streetnumber VARCHAR(255) DEFAULT NULL, validfrom DATE DEFAULT NULL, isnoaddress BOOLEAN DEFAULT NULL, customs JSONB DEFAULT NULL, floor VARCHAR(16) DEFAULT NULL, corridor VARCHAR(16) DEFAULT NULL, steps VARCHAR(16) DEFAULT NULL, buildingname VARCHAR(255) DEFAULT NULL, flat VARCHAR(16) DEFAULT NULL, distribution VARCHAR(255) DEFAULT NULL, extra VARCHAR(255) DEFAULT NULL, validto DATE DEFAULT NULL, point VARCHAR(255) DEFAULT NULL, linkedtothirdparty_id INT DEFAULT NULL)');
|
||||
$this->addSql('ALTER TABLE asideactivity ADD CONSTRAINT fk_e9fa2191c54c8c93 FOREIGN KEY (type_id) REFERENCES asideactivitytype (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||
$this->addSql('ALTER TABLE asideactivity ADD CONSTRAINT fk_e9fa21913174800f FOREIGN KEY (createdby_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||
$this->addSql('ALTER TABLE asideactivity ADD CONSTRAINT fk_e9fa219165ff1aec FOREIGN KEY (updatedby_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||
$this->addSql('ALTER TABLE asideactivity ADD CONSTRAINT fk_e9fa21913414710b FOREIGN KEY (agent_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||
$this->addSql('DROP TABLE chill_asideactivity.AsideActivity');
|
||||
$this->addSql('DROP TABLE chill_asideactivity.AsideActivityCategory');
|
||||
$this->addSql('DROP SCHEMA chill_asideactivity');
|
||||
}
|
||||
}
|
||||
|
@@ -7,14 +7,11 @@ namespace Chill\Migrations\AsideActivity;
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
/**
|
||||
* Auto-generated Migration: Please modify to your needs!
|
||||
*/
|
||||
final class Version20210806140343 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return '';
|
||||
return 'Duration changed to type integer';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
|
@@ -7,14 +7,11 @@ namespace Chill\Migrations\AsideActivity;
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
/**
|
||||
* Auto-generated Migration: Please modify to your needs!
|
||||
*/
|
||||
final class Version20210806140710 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return '';
|
||||
return 'Duration changed back to timestamp';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
|
@@ -7,14 +7,11 @@ namespace Chill\Migrations\AsideActivity;
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
/**
|
||||
* Auto-generated Migration: Please modify to your needs!
|
||||
*/
|
||||
final class Version20210810084456 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return '';
|
||||
return 'createdat, updatedat and date given a type timestamp';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
|
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Chill\Migrations\AsideActivity;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
final class Version20210922182907 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'Parent and children added to aside activity category entity';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
$this->addSql('ALTER TABLE chill_asideactivity.asideactivitycategory ADD parent_id INT DEFAULT NULL');
|
||||
$this->addSql('ALTER TABLE chill_asideactivity.asideactivitycategory ADD CONSTRAINT FK_7BF90DBE727ACA70 FOREIGN KEY (parent_id) REFERENCES chill_asideactivity.AsideActivityCategory (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||
$this->addSql('CREATE INDEX IDX_7BF90DBE727ACA70 ON chill_asideactivity.asideactivitycategory (parent_id)');
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
$this->addSql('ALTER TABLE chill_asideactivity.AsideActivityCategory DROP parent');
|
||||
}
|
||||
}
|
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Chill\Migrations\AsideActivity;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
/**
|
||||
* allow to add an ordering to aside activity categories
|
||||
*/
|
||||
final class Version20211004134012 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'allow to add an ordering to aside activity categories';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
$this->addSql('ALTER TABLE chill_asideactivity.asideactivitycategory ADD ordering DOUBLE PRECISION NOT NULL DEFAULT 0.00');
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
$this->addSql('ALTER TABLE chill_asideactivity.asideactivitycategory DROP ordering');
|
||||
}
|
||||
}
|
@@ -14,11 +14,8 @@ present: présent
|
||||
not present: absent
|
||||
Delete: Supprimer
|
||||
Update: Mettre à jour
|
||||
Update activity: Modifier l'activité
|
||||
Aside activity data: Données de l'activité annexe
|
||||
No reason associated: Aucun sujet
|
||||
There aren't any aside activities.: Aucune activité annexe enregistrée.
|
||||
type_name: type de l'activité
|
||||
Type: Type
|
||||
Invisible: Invisible
|
||||
Optional: Optionnel
|
||||
@@ -43,14 +40,8 @@ crud:
|
||||
title_edit: Edition d'une catégorie de type d'activité
|
||||
|
||||
#forms
|
||||
Activity creation: Nouvelle activité annexe
|
||||
Create a new aside activity type: Nouvelle catégorie d'activité annexe
|
||||
Create: Créer
|
||||
Create a new aside activity type: Nouvelle categorie d'activité annexe
|
||||
Back to the list: Retour à la liste
|
||||
Save activity: Sauver l'activité
|
||||
Reset form: Remise à zéro du formulaire
|
||||
Choose the agent for whom this activity is created: Choisissez l'utilisateur pour qui l'activité est créée.
|
||||
Choose the activity category: Choisissez le type d'activité
|
||||
Choose the duration: Choisir la durée
|
||||
Choose a category: Choisir une catégorie
|
||||
Is active: Actif
|
||||
@@ -58,12 +49,106 @@ Agent: Utilisateur
|
||||
date: Date
|
||||
Duration: Durée
|
||||
Note: Note
|
||||
Choose the agent for whom this activity is created: Choisissez l'agent pour qui l'activité est créée
|
||||
Choose the activity category: Choisir la catégorie
|
||||
|
||||
#Duration
|
||||
minutes: minutes
|
||||
hour: heure
|
||||
hours: heures
|
||||
day: jour
|
||||
days: jours
|
||||
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
|
||||
2 hours 30: 2 heure 30
|
||||
3 hours: 3 heures
|
||||
3 hours 30: 3 heure 30
|
||||
4 hours: 4 heures
|
||||
4 hours 30: 4 heure 30
|
||||
5 hours: 5 heures
|
||||
5 hours 30: 5 heure 30
|
||||
6 hours: 6 heures
|
||||
6 hours 30: 6 heure 30
|
||||
7 hours: 7 heures
|
||||
7 hours 30: 7 heure 30
|
||||
8 hours: 8 heures
|
||||
8 hours 30: 8 heure 30
|
||||
9 hours: 9 heures
|
||||
9 hours 30: 9 heure 30
|
||||
10 hours: 10 heures
|
||||
1/2 day: 1/2 jour
|
||||
1 day: 1 jour
|
||||
1 1/2 days: 1 1/2 jours
|
||||
2 days: 2 jours
|
||||
2 1/2 days: 2 1/2 jours
|
||||
3 days: 3 jours
|
||||
3 1/2 days: 3 1/2 jours
|
||||
4 days: 4 jours
|
||||
4 1/2 days: 4 1/2 jours
|
||||
5 days: 5 jours
|
||||
5 1/2 days: 5 1/2 jours
|
||||
6 days: 6 jours
|
||||
6 1/2 days: 6 1/2 jours
|
||||
7 days: 7 jours
|
||||
7 1/2 days: 7 1/2 jours
|
||||
8 days: 8 jours
|
||||
8 1/2 days: 8 1/2 jours
|
||||
9 days: 9 jours
|
||||
9 1/2 days: 9 1/2 jours
|
||||
10 days: 10 jours
|
||||
10 1/2 days: 10 1/2 jours
|
||||
11 days: 11 jours
|
||||
11 1/2 days: 11 1/2 jours
|
||||
12 days: 12 jours
|
||||
12 1/2 days: 12 1/2 jours
|
||||
13 days: 13 jours
|
||||
13 1/2 days: 13 1/2 jours
|
||||
14 days: 14 jours
|
||||
14 1/2 days: 14 1/2 jours
|
||||
15 days: 15 jours
|
||||
15 1/2 days: 15 1/2 jours
|
||||
16 days: 16 jours
|
||||
16 1/2 days: 16 1/2 jours
|
||||
17 days: 17 jours
|
||||
17 1/2 days: 17 1/2 jours
|
||||
18 days: 18 jours
|
||||
18 1/2 days: 18 1/2 jours
|
||||
19 days: 19 jours
|
||||
19 1/2 days: 19 1/2 jours
|
||||
20 days: 20 jours
|
||||
20 1/2 days: 20 1/2 jours
|
||||
21 days: 21 jours
|
||||
21 1/2 days: 21 1/2 jours
|
||||
22 days: 22 jours
|
||||
22 1/2 days: 22 1/2 jours
|
||||
23 days: 23 jours
|
||||
23 1/2 days: 23 1/2 jours
|
||||
24 days: 24 jours
|
||||
24 1/2 days: 24 1/2 jours
|
||||
25 days: 25 jours
|
||||
25 1/2 days: 25 1/2 jours
|
||||
26 days: 26 jours
|
||||
26 1/2 days: 26 1/2 jours
|
||||
27 days: 27 jours
|
||||
27 1/2 days: 27 1/2 jours
|
||||
28 days: 28 jours
|
||||
28 1/2 days: 28 1/2 jours
|
||||
29 days: 29 jours
|
||||
29 1/2 days: 29 1/2 jours
|
||||
30 days: 30 jours
|
||||
|
||||
#list
|
||||
My aside activities: Mes activités annexes
|
||||
Date: Date
|
||||
Created by: Créée par
|
||||
|
||||
#Aside activity delete
|
||||
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%" ?
|
||||
@@ -73,3 +158,4 @@ The activity has been successfully removed.: L'activité a été supprimée.
|
||||
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"
|
||||
Phonecall: "Appel téléphonique"
|
||||
|
@@ -0,0 +1 @@
|
||||
You must not add twice the same category in the parent tree (previous result returned): Il est interdit d'indiquer la même entité dans l'arbre des parents. Le résultat précédent a été rétabli
|
@@ -29,17 +29,19 @@ class ListenToActivityCreate
|
||||
$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();
|
||||
}
|
||||
}
|
||||
|
||||
// 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();
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -41,7 +41,7 @@ class AccompanyingCourseMenuBuilder implements LocalMenuBuilderInterface
|
||||
'routeParameters' => [
|
||||
'accompanying_period_id' => $period->getId(),
|
||||
]])
|
||||
->setExtras(['order' => 41]);
|
||||
->setExtras(['order' => 35]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -138,7 +138,7 @@ class DocGeneratorTemplateController extends AbstractController
|
||||
$em->flush();
|
||||
|
||||
return $this->redirectToRoute('chill_wopi_file_edit', [
|
||||
'fileId' => $genDocName,
|
||||
'fileId' => $storedObject->getUuid(),
|
||||
'returnPath' => $request->query->get('returnPath', "/")
|
||||
]);
|
||||
}
|
||||
|
@@ -7,7 +7,10 @@ namespace Chill\DocStoreBundle\Entity;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use ChampsLibres\AsyncUploaderBundle\Model\AsyncFileInterface;
|
||||
use ChampsLibres\AsyncUploaderBundle\Validator\Constraints\AsyncFileExists;
|
||||
use ChampsLibres\WopiLib\Contract\Entity\Document;
|
||||
use DateTimeInterface;
|
||||
use Ramsey\Uuid\Uuid;
|
||||
use Ramsey\Uuid\UuidInterface;
|
||||
use Symfony\Component\Serializer\Annotation as Serializer;
|
||||
|
||||
/**
|
||||
@@ -19,7 +22,7 @@ use Symfony\Component\Serializer\Annotation as Serializer;
|
||||
* message="The file is not stored properly"
|
||||
* )
|
||||
*/
|
||||
class StoredObject implements AsyncFileInterface
|
||||
class StoredObject implements AsyncFileInterface, Document
|
||||
{
|
||||
/**
|
||||
* @ORM\Id()
|
||||
@@ -47,6 +50,12 @@ class StoredObject implements AsyncFileInterface
|
||||
*/
|
||||
private array $iv = [];
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="uuid", unique=true)
|
||||
* @Serializer\Groups({"read"})
|
||||
*/
|
||||
private UuidInterface $uuid;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="datetime", name="creation_date")
|
||||
* @Serializer\Groups({"read"})
|
||||
@@ -68,6 +77,7 @@ class StoredObject implements AsyncFileInterface
|
||||
public function __construct()
|
||||
{
|
||||
$this->creationDate = new \DateTime();
|
||||
$this->uuid = Uuid::uuid4();
|
||||
}
|
||||
|
||||
public function getId()
|
||||
@@ -155,5 +165,13 @@ class StoredObject implements AsyncFileInterface
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getUuid(): UuidInterface
|
||||
{
|
||||
return $this->uuid;
|
||||
}
|
||||
|
||||
public function getWopiDocId(): string
|
||||
{
|
||||
return (string) $this->uuid;
|
||||
}
|
||||
}
|
||||
|
@@ -3,9 +3,12 @@
|
||||
"description": "A Chill bundle to store documents",
|
||||
"type": "symfony-bundle",
|
||||
"autoload": {
|
||||
"psr-4": { "Chill\\DocStoreBundle\\" : "" }
|
||||
"psr-4": {
|
||||
"Chill\\DocStoreBundle\\": ""
|
||||
}
|
||||
},
|
||||
"require": {
|
||||
"symfony/mime": "^4 || ^5"
|
||||
},
|
||||
"license": "AGPL-3.0"
|
||||
}
|
||||
|
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Chill\Migrations\DocStore;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
final class Version20210928182542 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'Create UUID column on StoredObject table.';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
$this->addSql('CREATE EXTENSION IF NOT EXISTS "uuid-ossp"');
|
||||
$this->addSql('ALTER TABLE chill_doc.stored_object ADD uuid UUID DEFAULT NULL');
|
||||
$this->addSql('UPDATE chill_doc.stored_object SET uuid=uuid_generate_v4()');
|
||||
$this->addSql('ALTER TABLE chill_doc.stored_object ALTER uuid SET NOT NULL');
|
||||
$this->addSql('CREATE UNIQUE INDEX UNIQ_49604E36D17F50A6 ON chill_doc.stored_object (uuid)');
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
$this->addSql('ALTER TABLE chill_doc.stored_object DROP uuid');
|
||||
}
|
||||
}
|
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace Chill\MainBundle\Controller;
|
||||
|
||||
use Chill\MainBundle\CRUD\Controller\ApiController;
|
||||
use Chill\MainBundle\Entity\Address;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
|
||||
|
||||
class AddressApiController extends ApiController
|
||||
{
|
||||
/**
|
||||
* Duplicate an existing address
|
||||
*
|
||||
* @Route("/api/1.0/main/address/{id}/duplicate.json", name="chill_api_main_address_duplicate",
|
||||
* methods={"POST"})
|
||||
*
|
||||
* @param Address $address
|
||||
*/
|
||||
public function duplicate(Address $address): JsonResponse
|
||||
{
|
||||
$this->denyAccessUnlessGranted('ROLE_USER');
|
||||
$new = Address::createFromAddress($address);
|
||||
|
||||
$em = $this->getDoctrine()->getManager();
|
||||
|
||||
$em->persist($new);
|
||||
$em->flush();
|
||||
|
||||
return $this->json($new, Response::HTTP_OK, [], [
|
||||
AbstractNormalizer::GROUPS => ['read']
|
||||
]);
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -19,6 +19,7 @@
|
||||
|
||||
namespace Chill\MainBundle\DependencyInjection;
|
||||
|
||||
use Chill\MainBundle\Controller\AddressApiController;
|
||||
use Chill\MainBundle\Controller\UserController;
|
||||
use Chill\MainBundle\Doctrine\DQL\STContains;
|
||||
use Chill\MainBundle\Doctrine\DQL\StrictWordSimilarityOPS;
|
||||
@@ -319,6 +320,7 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface,
|
||||
'apis' => [
|
||||
[
|
||||
'class' => \Chill\MainBundle\Entity\Address::class,
|
||||
'controller' => AddressApiController::class,
|
||||
'name' => 'address',
|
||||
'base_path' => '/api/1.0/main/address',
|
||||
'base_role' => 'ROLE_USER',
|
||||
|
@@ -376,10 +376,22 @@ class Address
|
||||
public static function createFromAddress(Address $original) : Address
|
||||
{
|
||||
return (new Address())
|
||||
->setBuildingName($original->getBuildingName())
|
||||
->setCorridor($original->getCorridor())
|
||||
->setCustoms($original->getCustoms())
|
||||
->setDistribution($original->getDistribution())
|
||||
->setExtra($original->getExtra())
|
||||
->setFlat($original->getFlat())
|
||||
->setFloor($original->getFloor())
|
||||
->setIsNoAddress($original->getIsNoAddress())
|
||||
->setLinkedToThirdParty($original->getLinkedToThirdParty())
|
||||
->setPoint($original->getPoint())
|
||||
->setPostcode($original->getPostcode())
|
||||
->setStreetAddress1($original->getStreetAddress1())
|
||||
->setStreetAddress2($original->getStreetAddress2())
|
||||
->setSteps($original->getSteps())
|
||||
->setStreet($original->getStreet())
|
||||
->setStreetNumber($original->getStreetNumber())
|
||||
->setValidFrom($original->getValidFrom())
|
||||
->setValidTo($original->getValidTo())
|
||||
;
|
||||
}
|
||||
|
||||
@@ -506,7 +518,7 @@ class Address
|
||||
return $this->validTo;
|
||||
}
|
||||
|
||||
public function setValidTo(\DateTimeInterface $validTo): self
|
||||
public function setValidTo(?\DateTimeInterface $validTo = null): self
|
||||
{
|
||||
$this->validTo = $validTo;
|
||||
|
||||
|
@@ -76,10 +76,7 @@ class CenterType extends AbstractType
|
||||
{
|
||||
$nbReachableCenters = count($this->reachableCenters);
|
||||
|
||||
if ($nbReachableCenters === 0) {
|
||||
throw new \RuntimeException("The user is not associated with "
|
||||
. "any center. Associate user with a center");
|
||||
} elseif ($nbReachableCenters === 1) {
|
||||
if ($nbReachableCenters <= 1) {
|
||||
return HiddenType::class;
|
||||
} else {
|
||||
return EntityType::class;
|
||||
|
@@ -7,6 +7,7 @@ namespace Chill\MainBundle\Repository;
|
||||
use Chill\MainBundle\Entity\Address;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Doctrine\Persistence\ObjectRepository;
|
||||
|
||||
final class AddressRepository implements ObjectRepository
|
||||
@@ -47,4 +48,9 @@ final class AddressRepository implements ObjectRepository
|
||||
public function getClassName() {
|
||||
return Address::class;
|
||||
}
|
||||
|
||||
public function createQueryBuilder(string $alias, ?string $indexBy = null): QueryBuilder
|
||||
{
|
||||
return $this->repository->createQueryBuilder($alias, $indexBy);
|
||||
}
|
||||
}
|
||||
|
@@ -8,39 +8,45 @@
|
||||
|
||||
div.flex-bloc,
|
||||
div.flex-table {
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
align-content: stretch;
|
||||
box-sizing: border-box;
|
||||
margin: 1.5em 0;
|
||||
|
||||
div.item-bloc {
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
align-content: stretch;
|
||||
box-sizing: border-box;
|
||||
margin: 1.5em 0;
|
||||
@include border-collapse;
|
||||
padding: 1em;
|
||||
|
||||
div.item-bloc {
|
||||
div.item-row {
|
||||
display: flex;
|
||||
|
||||
div.item-col:last-child {
|
||||
display: flex;
|
||||
@include border-collapse;
|
||||
padding: 1em;
|
||||
|
||||
div.item-row {
|
||||
display: flex;
|
||||
|
||||
div.item-col:last-child {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
h2, h3, h4, dl, p {
|
||||
margin: 0;
|
||||
}
|
||||
h2, h3, h4 {
|
||||
color: $blue;
|
||||
}
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
dl,
|
||||
p {
|
||||
margin: 0;
|
||||
}
|
||||
h2,
|
||||
h3,
|
||||
h4 {
|
||||
color: $blue;
|
||||
}
|
||||
|
||||
ul.record_actions {
|
||||
margin: 0;
|
||||
li {
|
||||
margin-right: 5px;
|
||||
}
|
||||
ul.record_actions {
|
||||
margin: 0;
|
||||
li {
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -48,36 +54,43 @@ div.flex-table {
|
||||
*/
|
||||
|
||||
div.flex-bloc {
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
|
||||
div.item-bloc {
|
||||
flex-grow: 0; flex-shrink: 1; flex-basis: auto;
|
||||
flex-direction: column;
|
||||
margin: 0;
|
||||
hyphens: auto;
|
||||
div.item-bloc {
|
||||
flex-grow: 0;
|
||||
flex-shrink: 1;
|
||||
flex-basis: auto;
|
||||
flex-direction: column;
|
||||
margin: 0;
|
||||
hyphens: auto;
|
||||
|
||||
div.item-row {
|
||||
flex-grow: 1; flex-shrink: 1; flex-basis: auto;
|
||||
flex-direction: column;
|
||||
div.item-row {
|
||||
flex-grow: 1;
|
||||
flex-shrink: 1;
|
||||
flex-basis: auto;
|
||||
flex-direction: column;
|
||||
|
||||
div.item-col {
|
||||
|
||||
&:first-child {
|
||||
flex-grow: 0; flex-shrink: 0; flex-basis: auto;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
flex-grow: 1; flex-shrink: 1; flex-basis: auto;
|
||||
@include separator;
|
||||
|
||||
ul.record_actions {
|
||||
align-self: flex-end;
|
||||
}
|
||||
}
|
||||
}
|
||||
div.item-col {
|
||||
&:first-child {
|
||||
flex-grow: 0;
|
||||
flex-shrink: 0;
|
||||
flex-basis: auto;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
flex-grow: 1;
|
||||
flex-shrink: 1;
|
||||
flex-basis: auto;
|
||||
@include separator;
|
||||
|
||||
ul.record_actions {
|
||||
align-self: flex-end;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -85,53 +98,57 @@ div.flex-bloc {
|
||||
*/
|
||||
|
||||
div.flex-table {
|
||||
flex-direction: column;
|
||||
|
||||
div.item-bloc {
|
||||
flex-direction: column;
|
||||
|
||||
div.item-bloc {
|
||||
flex-direction: column;
|
||||
&:nth-child(even) {
|
||||
background-color: $gray-200;
|
||||
|
||||
&:nth-child(even) {
|
||||
background-color: $gray-200;
|
||||
|
||||
.chill-user-quote {
|
||||
background-color: shade-color($gray-200, 5%)
|
||||
}
|
||||
}
|
||||
|
||||
div.item-row {
|
||||
flex-direction: row;
|
||||
|
||||
div.item-col {
|
||||
&:first-child {
|
||||
flex-grow: 0; flex-shrink: 0; flex-basis: auto;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
flex-grow: 1; flex-shrink: 1; flex-basis: auto;
|
||||
justify-content: flex-end;
|
||||
|
||||
@include media-breakpoint-down(md) {
|
||||
@include separator;
|
||||
}
|
||||
|
||||
ul.record_actions {
|
||||
align-self: flex-start;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@include media-breakpoint-down(md) {
|
||||
flex-direction: column;
|
||||
div.item-col {
|
||||
&:last-child {
|
||||
ul.record_actions {
|
||||
align-self: flex-end;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.chill-user-quote {
|
||||
background-color: shade-color($gray-200, 5%);
|
||||
}
|
||||
}
|
||||
|
||||
div.item-row {
|
||||
flex-direction: row;
|
||||
|
||||
div.item-col {
|
||||
&:first-child {
|
||||
flex-grow: 0;
|
||||
flex-shrink: 0;
|
||||
flex-basis: auto;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
flex-grow: 1;
|
||||
flex-shrink: 1;
|
||||
flex-basis: auto;
|
||||
justify-content: flex-end;
|
||||
|
||||
@include media-breakpoint-down(md) {
|
||||
@include separator;
|
||||
}
|
||||
|
||||
ul.record_actions {
|
||||
align-self: flex-start;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@include media-breakpoint-down(md) {
|
||||
flex-direction: column;
|
||||
div.item-col {
|
||||
&:last-child {
|
||||
ul.record_actions {
|
||||
align-self: flex-end;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -140,54 +157,54 @@ div.flex-table {
|
||||
*/
|
||||
|
||||
div.wrap-list {
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
|
||||
div.wl-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
div.wl-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
|
||||
div.wl-col.title {
|
||||
width: auto;
|
||||
flex-shrink: 0;
|
||||
div.wl-col.title {
|
||||
width: auto;
|
||||
flex-shrink: 0;
|
||||
|
||||
@include media-breakpoint-up(md) {
|
||||
//margin-left: 1.5em;
|
||||
}
|
||||
@include media-breakpoint-up(md) {
|
||||
//margin-left: 1.5em;
|
||||
}
|
||||
|
||||
& > * {
|
||||
padding-right: 1em;
|
||||
}
|
||||
}
|
||||
|
||||
div.wl-col.list {
|
||||
width: 75%;
|
||||
margin: auto 0 0 auto;
|
||||
|
||||
.wl-item {
|
||||
margin: 0.1em;
|
||||
padding: 0em;
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
& > * {
|
||||
padding-right: 1em;
|
||||
}
|
||||
}
|
||||
|
||||
&.debug .wl-row {
|
||||
border: 1px solid $black;
|
||||
div.wl-col.list {
|
||||
width: 75%;
|
||||
margin: auto 0 0 auto;
|
||||
|
||||
div.wl-col.title {
|
||||
background-color: yellow;
|
||||
}
|
||||
div.wl-col.list {
|
||||
background-color: cyan;
|
||||
|
||||
p.wl-item {
|
||||
background-color: orange;
|
||||
}
|
||||
}
|
||||
.wl-item {
|
||||
margin: 0.1em;
|
||||
padding: 0em;
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.debug .wl-row {
|
||||
border: 1px solid $black;
|
||||
|
||||
div.wl-col.title {
|
||||
background-color: yellow;
|
||||
}
|
||||
div.wl-col.list {
|
||||
background-color: cyan;
|
||||
|
||||
p.wl-item {
|
||||
background-color: orange;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -196,43 +213,56 @@ div.wrap-list {
|
||||
*/
|
||||
|
||||
div.wrap-header {
|
||||
width: 100%;
|
||||
width: 100%;
|
||||
|
||||
div.wh-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
||||
&:first-child {
|
||||
align-items: baseline;
|
||||
}
|
||||
&:last-child {
|
||||
}
|
||||
|
||||
div.wh-col {
|
||||
&:first-child {
|
||||
flex-grow: 0;
|
||||
flex-shrink: 1;
|
||||
flex-basis: auto;
|
||||
}
|
||||
&:last-child {
|
||||
flex-grow: 1;
|
||||
flex-shrink: 1;
|
||||
flex-basis: auto;
|
||||
|
||||
div.wh-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.debug {
|
||||
border: 1px solid $black;
|
||||
div.wh-row {
|
||||
&:first-child div.wh-col {
|
||||
&:first-child {
|
||||
align-items: baseline;
|
||||
background-color: $yellow;
|
||||
}
|
||||
&:last-child {}
|
||||
|
||||
div.wh-col {
|
||||
&:first-child {
|
||||
flex-grow: 0; flex-shrink: 1; flex-basis: auto;
|
||||
}
|
||||
&:last-child {
|
||||
flex-grow: 1; flex-shrink: 1; flex-basis: auto;
|
||||
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.debug {
|
||||
border: 1px solid $black;
|
||||
div.wh-row {
|
||||
&:first-child div.wh-col {
|
||||
&:first-child { background-color: $yellow; }
|
||||
&:last-child { background-color: $beige; }
|
||||
}
|
||||
&:last-child div.wh-col {
|
||||
&:first-child { background-color: $orange; }
|
||||
&:last-child { background-color: $pink; }
|
||||
}
|
||||
&:last-child {
|
||||
background-color: $beige;
|
||||
}
|
||||
}
|
||||
&:last-child div.wh-col {
|
||||
&:first-child {
|
||||
background-color: $orange;
|
||||
}
|
||||
&:last-child {
|
||||
background-color: $pink;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -243,69 +273,67 @@ div.flex-bloc,
|
||||
div.flex-table,
|
||||
div.wrap-list,
|
||||
div.wrap-header {
|
||||
div.separator {
|
||||
@include separator;
|
||||
}
|
||||
|
||||
div.separator {
|
||||
@include separator;
|
||||
}
|
||||
|
||||
ul.record_actions {
|
||||
flex-grow: 1;
|
||||
flex-shrink: 0;
|
||||
flex-basis: auto;
|
||||
margin: 0;
|
||||
|
||||
li {
|
||||
margin-right: 5px;
|
||||
}
|
||||
ul.record_actions {
|
||||
flex-grow: 1;
|
||||
flex-shrink: 0;
|
||||
flex-basis: auto;
|
||||
margin: 0;
|
||||
|
||||
li {
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* FLOATBUTTON
|
||||
* p-ê pas convaincant: cet asset est toujours en observation
|
||||
*/
|
||||
|
||||
div.float-button {
|
||||
width: 100%;
|
||||
|
||||
div.box {
|
||||
width: 100%;
|
||||
|
||||
div.box {
|
||||
width: 100%;
|
||||
div.action {
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
&.top {
|
||||
div.action {
|
||||
padding: 0 0 1em 1em;
|
||||
}
|
||||
|
||||
div.action {
|
||||
float: right;
|
||||
}
|
||||
// avoid a position relative that make links unclickable
|
||||
.fa-ul > li {
|
||||
position: initial;
|
||||
}
|
||||
&.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;
|
||||
}
|
||||
}
|
||||
&.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);
|
||||
}
|
||||
}
|
||||
&.debug {
|
||||
padding: 1em;
|
||||
border: 1px solid black;
|
||||
background-color: yellow;
|
||||
div.action {
|
||||
background-color: transparentize(#00ffff, 0.4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -4,9 +4,9 @@ const fetchScopes = () => {
|
||||
return response.json();
|
||||
}
|
||||
}).then(data => {
|
||||
console.log(data);
|
||||
//console.log(data);
|
||||
return new Promise((resolve, reject) => {
|
||||
console.log(data);
|
||||
//console.log(data);
|
||||
resolve(data.results);
|
||||
});
|
||||
});
|
||||
|
@@ -1,4 +1,4 @@
|
||||
/*
|
||||
/**
|
||||
* Endpoint chill_api_single_country__index
|
||||
* method GET, get Country Object
|
||||
* @returns {Promise} a promise containing all Country object
|
||||
@@ -14,7 +14,7 @@ const fetchCountries = () => {
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
/**
|
||||
* Endpoint chill_api_single_postal_code__index
|
||||
* method GET, get Country Object
|
||||
* @returns {Promise} a promise containing all Postal Code objects filtered with country
|
||||
@@ -29,7 +29,7 @@ const fetchCities = (country) => {
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
/**
|
||||
* Endpoint chill_api_single_address_reference__index
|
||||
* method GET, get AddressReference Object
|
||||
* @returns {Promise} a promise containing all AddressReference objects filtered with postal code
|
||||
@@ -44,7 +44,7 @@ const fetchReferenceAddresses = (postalCode) => {
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
/**
|
||||
* Endpoint chill_api_single_address_reference__index
|
||||
* method GET, get AddressReference Object
|
||||
* @returns {Promise} a promise containing all AddressReference objects filtered with postal code
|
||||
@@ -60,7 +60,7 @@ const fetchAddresses = () => {
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
/**
|
||||
* Endpoint chill_api_single_address__entity__create
|
||||
* method POST, post Address Object
|
||||
* @returns {Promise}
|
||||
@@ -81,8 +81,28 @@ const postAddress = (address) => {
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param address
|
||||
* @returns {Promise<Response>}
|
||||
*/
|
||||
const duplicateAddress = (address) => {
|
||||
const url = `/api/1.0/main/address/${address.address_id}/duplicate.json`;
|
||||
return fetch(url, {
|
||||
'method': 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json;charset=utf-8'
|
||||
},
|
||||
}).then(response => {
|
||||
if (response.ok) {
|
||||
return response.json();
|
||||
}
|
||||
throw Error('Error with request resource response');
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
/**
|
||||
* Endpoint chill_api_single_address__entity__create
|
||||
* method PATCH, patch Address Instance
|
||||
*
|
||||
@@ -142,6 +162,7 @@ const getAddress = (id) => {
|
||||
};
|
||||
|
||||
export {
|
||||
duplicateAddress,
|
||||
fetchCountries,
|
||||
fetchCities,
|
||||
fetchReferenceAddresses,
|
||||
|
@@ -1,17 +1,18 @@
|
||||
<template>
|
||||
<ul class="record_actions"
|
||||
<ul class="record_actions" v-if="!options.onlyButton"
|
||||
:class="{ 'sticky-form-buttons': isStickyForm }">
|
||||
|
||||
<li v-if="isStickyForm" class="cancel">
|
||||
<slot name="before"></slot>
|
||||
</li>
|
||||
|
||||
<slot name="action"></slot>
|
||||
|
||||
<li>
|
||||
<slot name="action"></slot>
|
||||
</li>
|
||||
<li v-if="isStickyForm">
|
||||
<slot name="after"></slot>
|
||||
</li>
|
||||
</ul>
|
||||
<slot v-else name="action"></slot>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
@@ -23,9 +24,6 @@ export default {
|
||||
return (typeof this.options.stickyActions !== 'undefined') ?
|
||||
this.options.stickyActions : this.defaultz.stickyActions;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
@@ -34,6 +34,7 @@
|
||||
v-bind:defaultz="this.defaultz"
|
||||
v-bind:entity="this.entity"
|
||||
v-bind:flag="this.flag"
|
||||
@pick-address="this.pickAddress"
|
||||
ref="suggestAddress">
|
||||
</suggest-pane>
|
||||
</template>
|
||||
@@ -55,6 +56,7 @@
|
||||
v-bind:entity="this.entity"
|
||||
v-bind:flag="this.flag"
|
||||
v-bind:insideModal="false"
|
||||
@pick-address="this.pickAddress"
|
||||
ref="suggestAddress">
|
||||
|
||||
<template v-slot:before v-if="!bypassFirstStep">
|
||||
@@ -217,7 +219,16 @@
|
||||
|
||||
<script>
|
||||
import Modal from 'ChillMainAssets/vuejs/_components/Modal';
|
||||
import { getAddress, fetchCountries, fetchCities, fetchReferenceAddresses, patchAddress, postAddress, postPostalCode } from '../api';
|
||||
import {
|
||||
duplicateAddress,
|
||||
fetchCountries,
|
||||
fetchCities,
|
||||
fetchReferenceAddresses,
|
||||
getAddress,
|
||||
patchAddress,
|
||||
postAddress,
|
||||
postPostalCode,
|
||||
} from '../api';
|
||||
import { postAddressToPerson, postAddressToHousehold } from "ChillPersonAssets/vuejs/_api/AddAddress.js";
|
||||
import ShowPane from './ShowPane.vue';
|
||||
import SuggestPane from './SuggestPane.vue';
|
||||
@@ -234,6 +245,9 @@ export default {
|
||||
EditPane,
|
||||
DatePane
|
||||
},
|
||||
emits: {
|
||||
pickAddress: null
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
flag: {
|
||||
@@ -257,7 +271,7 @@ export default {
|
||||
validFrom: false,
|
||||
validTo: false
|
||||
},
|
||||
hideAddress: false
|
||||
onlyButton: false
|
||||
},
|
||||
entity: {
|
||||
address: {}, // <== loaded and returned
|
||||
@@ -311,8 +325,10 @@ export default {
|
||||
return (this.validFrom || this.validTo) ? true : false;
|
||||
},
|
||||
hasSuggestions() {
|
||||
// TODO
|
||||
//return addressSuggestions.length > 0
|
||||
if (typeof(this.context.suggestions) !== 'undefined') {
|
||||
console.log('hasSuggestions', this.context.suggestions);
|
||||
return this.context.suggestions.length > 0;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
displaySuggestions() {
|
||||
@@ -337,9 +353,9 @@ export default {
|
||||
},
|
||||
mounted() {
|
||||
|
||||
console.log('validFrom', this.validFrom);
|
||||
console.log('validTo', this.validTo);
|
||||
console.log('useDatePane', this.useDatePane);
|
||||
//console.log('validFrom', this.validFrom);
|
||||
//console.log('validTo', this.validTo);
|
||||
//console.log('useDatePane', this.useDatePane);
|
||||
|
||||
console.log('Mounted now !');
|
||||
if (this.context.edit) {
|
||||
@@ -590,7 +606,7 @@ export default {
|
||||
let newPostcode = this.entity.selected.postcode;
|
||||
newPostcode = Object.assign(newPostcode, {
|
||||
'country': {'id': this.entity.selected.country.id },
|
||||
});
|
||||
});//TODO why not assign postcodeBody here = Object.assign(postcodeBody, {'origin': 3}); ?
|
||||
console.log('writeNew postcode is true! newPostcode: ', newPostcode);
|
||||
newAddress = Object.assign(newAddress, {
|
||||
'newPostcode': newPostcode
|
||||
@@ -622,9 +638,7 @@ export default {
|
||||
if ('newPostcode' in payload) {
|
||||
|
||||
let postcodeBody = payload.newPostcode;
|
||||
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);
|
||||
return postPostalCode(postcodeBody)
|
||||
.then(postalCode => {
|
||||
@@ -647,9 +661,12 @@ export default {
|
||||
this.flag.loading = false;
|
||||
this.flag.success = true;
|
||||
resolve({
|
||||
address,
|
||||
targetOrigin: this.context.target,
|
||||
// for "legacy" use:
|
||||
target: this.context.target.name,
|
||||
targetId: this.context.target.id,
|
||||
addressId: this.entity.address.address_id
|
||||
addressId: this.entity.address.address_id,
|
||||
}
|
||||
);
|
||||
}))
|
||||
@@ -695,6 +712,9 @@ export default {
|
||||
this.flag.loading = false;
|
||||
this.flag.success = true;
|
||||
return resolve({
|
||||
address,
|
||||
targetOrigin: this.context.target,
|
||||
// for "legacy" use:
|
||||
target: this.context.target.name,
|
||||
targetId: this.context.target.id,
|
||||
addressId: this.entity.address.address_id
|
||||
@@ -707,18 +727,28 @@ export default {
|
||||
});
|
||||
},
|
||||
|
||||
/*
|
||||
* Method just add closing pane to the callback method
|
||||
* (get out step1 show pane, submit button)
|
||||
closePaneAndCallbackSubmit(payload)
|
||||
{
|
||||
//this.initForm();
|
||||
//this.resetPane(); // because parent callback will cast afterLastPaneAction()
|
||||
console.log('will call parent callback method', payload);
|
||||
// callback props method from parent
|
||||
this.addressChangedCallback(payload);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param address the address selected
|
||||
*/
|
||||
pickAddress(address) {
|
||||
console.log('pickAddress', address);
|
||||
duplicateAddress(address).then(newAddress => {
|
||||
this.entity.address = newAddress;
|
||||
this.flag.loading = false;
|
||||
this.flag.success = true;
|
||||
let payload = {
|
||||
address: newAddress,
|
||||
targetOrigin: this.context.target,
|
||||
// for "legacy" use:
|
||||
target: this.context.target.name,
|
||||
targetId: this.context.target.id,
|
||||
addressId: this.entity.address.address_id
|
||||
};
|
||||
this.addressChangedCallback(payload);
|
||||
this.closeSuggestPane();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
@@ -50,7 +50,7 @@ import VueMultiselect from 'vue-multiselect';
|
||||
export default {
|
||||
name: 'CitySelection',
|
||||
components: { VueMultiselect },
|
||||
props: ['entity', 'focusOnAddress'],
|
||||
props: ['entity', 'focusOnAddress', 'updateMapCenter'],
|
||||
emits: ['getReferenceAddresses'],
|
||||
data() {
|
||||
return {
|
||||
@@ -95,6 +95,7 @@ export default {
|
||||
return (value.code && value.name) ? `${value.code}-${value.name}` : '';
|
||||
},
|
||||
selectCity(value) {
|
||||
console.log(value)
|
||||
this.entity.selected.city = value;
|
||||
this.entity.selected.postcode.name = value.name;
|
||||
this.entity.selected.postcode.code = value.code;
|
||||
@@ -102,6 +103,7 @@ export default {
|
||||
console.log('writeNew.postcode false, in selectCity');
|
||||
this.$emit('getReferenceAddresses', value);
|
||||
this.focusOnAddress();
|
||||
this.updateMapCenter(value.center);
|
||||
},
|
||||
listenInputSearch(query) {
|
||||
//console.log('listenInputSearch', query, this.isCitySelectorOpen);
|
||||
|
@@ -31,6 +31,7 @@
|
||||
<city-selection
|
||||
v-bind:entity="entity"
|
||||
v-bind:focusOnAddress="focusOnAddress"
|
||||
v-bind:updateMapCenter="updateMapCenter"
|
||||
@getReferenceAddresses="$emit('getReferenceAddresses', selected.city)">
|
||||
</city-selection>
|
||||
|
||||
@@ -135,7 +136,7 @@ export default {
|
||||
}
|
||||
},
|
||||
updateMapCenter(point) {
|
||||
//console.log('point', point);
|
||||
console.log('point', point);
|
||||
this.addressMap.center[0] = point.coordinates[1]; // TODO use reverse()
|
||||
this.addressMap.center[1] = point.coordinates[0];
|
||||
this.$refs.addressMap.update(); // cast child methods
|
||||
|
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
|
||||
<div v-if="!hideAddress">
|
||||
<div v-if="!onlyButton">
|
||||
<div class="loading">
|
||||
<i v-if="flag.loading" class="fa fa-circle-o-notch fa-spin fa-2x fa-fw"></i>
|
||||
<span class="sr-only">{{ $t('loading') }}</span>
|
||||
@@ -28,13 +28,11 @@
|
||||
:options="this.options"
|
||||
:defaultz="this.defaultz">
|
||||
<template v-slot:action>
|
||||
<li>
|
||||
<button @click.prevent="$emit('openEditPane')"
|
||||
class="btn" :class="getClassButton"
|
||||
type="button" name="button" :title="$t(getTextButton)">
|
||||
<span v-if="displayTextButton">{{ $t(getTextButton) }}</span>
|
||||
</button>
|
||||
</li>
|
||||
<button @click.prevent="$emit('openEditPane')"
|
||||
class="btn" :class="getClassButton"
|
||||
type="button" name="button" :title="$t(getTextButton)">
|
||||
<span v-if="displayTextButton">{{ $t(getTextButton) }}</span>
|
||||
</button>
|
||||
</template>
|
||||
</action-buttons>
|
||||
|
||||
@@ -86,9 +84,9 @@ export default {
|
||||
getSuccessText() {
|
||||
return (this.context.edit) ? 'address_edit_success' : 'address_new_success';
|
||||
},
|
||||
hideAddress() {
|
||||
return (typeof this.options.hideAddress !== 'undefined') ?
|
||||
this.options.hideAddress : this.defaultz.hideAddress;
|
||||
onlyButton() {
|
||||
return (typeof this.options.onlyButton !== 'undefined') ?
|
||||
this.options.onlyButton : this.defaultz.onlyButton;
|
||||
},
|
||||
forceRedirect() {
|
||||
return (!(this.context.backUrl === null || typeof this.context.backUrl === 'undefined'));
|
||||
|
@@ -10,13 +10,14 @@
|
||||
<h4 class="h3">{{ $t('address_suggestions') }}</h4>
|
||||
|
||||
<div class="flex-table AddressSuggestionList">
|
||||
<div class="item-bloc">
|
||||
<div v-for="a in context.suggestions" class="item-bloc">
|
||||
<div class="float-button bottom">
|
||||
<div class="box">
|
||||
<div class="action">
|
||||
<!-- QUESTION normal que ça vienne avant l'adresse ? pourquoi pas après avoir affiché le address-render-box ? -->
|
||||
<ul class="record_actions">
|
||||
<li>
|
||||
<button class="btn btn-sm btn-choose">
|
||||
<button class="btn btn-sm btn-choose" @click="this.pickAddress(a)">
|
||||
{{ $t('use_this_address') }}
|
||||
</button>
|
||||
</li>
|
||||
@@ -25,9 +26,7 @@
|
||||
<ul class="list-content fa-ul">
|
||||
<li>
|
||||
<i class="fa fa-li fa-map-marker"></i>
|
||||
<!--
|
||||
<address-render-box></address-render-box>
|
||||
-->
|
||||
<address-render-box :address="a"></address-render-box>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
@@ -68,9 +67,14 @@ export default {
|
||||
'flag',
|
||||
'entity',
|
||||
'errorMsg',
|
||||
'insideModal'
|
||||
'insideModal',
|
||||
],
|
||||
computed: {},
|
||||
methods: {}
|
||||
methods: {
|
||||
pickAddress(address) {
|
||||
console.log('pickAddress in suggest pane', address);
|
||||
this.$emit('pickAddress', address);
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
@@ -53,7 +53,7 @@ containers.forEach((container) => {
|
||||
},
|
||||
|
||||
/// Don't display show renderbox Address: showPane display only a button
|
||||
hideAddress: container.dataset.hideAddress === 'true' //boolean, default: false
|
||||
onlyButton: container.dataset.onlyButton === 'true' //boolean, default: false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,41 @@
|
||||
<template>
|
||||
<on-the-fly
|
||||
:type="context.type"
|
||||
:id="context.id"
|
||||
:action="context.action"
|
||||
:buttonText="options.buttonText"
|
||||
:displayBadge="options.displayBadge === 'true'"
|
||||
@saveFormOnTheFly="saveFormOnTheFly">
|
||||
</on-the-fly>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import OnTheFly from './components/OnTheFly.vue';
|
||||
|
||||
export default {
|
||||
name: "App",
|
||||
components: {
|
||||
OnTheFly
|
||||
},
|
||||
props: ['onTheFly'],
|
||||
computed: {
|
||||
context() {
|
||||
return this.onTheFly.context;
|
||||
},
|
||||
options() {
|
||||
return this.onTheFly.options;
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
//console.log('OnTheFly mounted');
|
||||
//console.log('OnTheFly: data context', this.context);
|
||||
//console.log('OnTheFly: data options', this.options);
|
||||
},
|
||||
methods: {
|
||||
saveFormOnTheFly(payload) {
|
||||
console.log('saveFormOnTheFly', payload);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
@@ -3,7 +3,7 @@
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" :class="{ active: isActive('person') }">
|
||||
<label for="person">
|
||||
<input type="radio" name="person" v-model="radioType" value="person">
|
||||
<input type="radio" name="person" id="person" v-model="radioType" value="person">
|
||||
{{ $t('onthefly.create.person') }}
|
||||
</label>
|
||||
</a>
|
||||
@@ -11,7 +11,7 @@
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" :class="{ active: isActive('thirdparty') }">
|
||||
<label for="thirdparty">
|
||||
<input type="radio" name="thirdparty" v-model="radioType" value="thirdparty">
|
||||
<input type="radio" name="thirdparty" id="thirdparty" v-model="radioType" value="thirdparty">
|
||||
{{ $t('onthefly.create.thirdparty') }}
|
||||
</label>
|
||||
</a>
|
||||
@@ -56,6 +56,7 @@ export default {
|
||||
radioType: {
|
||||
set(type) {
|
||||
this.type = type;
|
||||
console.log('## type:', type, ', action:', this.action);
|
||||
},
|
||||
get() {
|
||||
return this.type;
|
||||
@@ -71,7 +72,10 @@ export default {
|
||||
case 'person':
|
||||
return this.$refs.castPerson.$data.person;
|
||||
case 'thirdparty':
|
||||
return this.$refs.castThirdparty.$data.thirdparty;
|
||||
let data = this.$refs.castThirdparty.$data.thirdparty;
|
||||
data.name = data.text;
|
||||
data.address = { id: data.address.address_id }
|
||||
return data;
|
||||
default:
|
||||
throw Error('Invalid type of entity')
|
||||
}
|
@@ -1,6 +1,11 @@
|
||||
<template>
|
||||
|
||||
<a class="btn btn-sm" target="_blank"
|
||||
<a v-if="isDisplayBadge" @click="openModal">
|
||||
<span class="chill-entity" :class="badgeType">
|
||||
{{ buttonText }}
|
||||
</span>
|
||||
</a>
|
||||
<a v-else class="btn btn-sm" target="_blank"
|
||||
:class="classAction"
|
||||
:title="$t(titleAction)"
|
||||
@click="openModal">
|
||||
@@ -42,16 +47,16 @@
|
||||
</template>
|
||||
|
||||
<template v-slot:footer>
|
||||
<button v-if="action === 'show'"
|
||||
@click="goToLocation(id, type)"
|
||||
<a v-if="action === 'show'"
|
||||
:href="buildLocation(id, type)"
|
||||
:title="$t(titleMessage)"
|
||||
class="btn btn-show">{{ $t(buttonMessage) }}
|
||||
</button>
|
||||
<button v-else
|
||||
</a>
|
||||
<a v-else
|
||||
class="btn btn-save"
|
||||
@click="saveAction">
|
||||
{{ $t('action.save')}}
|
||||
</button>
|
||||
</a>
|
||||
</template>
|
||||
|
||||
</modal>
|
||||
@@ -61,7 +66,7 @@
|
||||
|
||||
<script>
|
||||
import Modal from 'ChillMainAssets/vuejs/_components/Modal.vue';
|
||||
import OnTheFlyCreate from './OnTheFly/Create.vue';
|
||||
import OnTheFlyCreate from './Create.vue';
|
||||
import OnTheFlyPerson from 'ChillPersonAssets/vuejs/_components/OnTheFly/Person.vue';
|
||||
import OnTheFlyThirdparty from 'ChillThirdPartyAssets/vuejs/_components/OnTheFly/ThirdParty.vue';
|
||||
|
||||
@@ -73,7 +78,7 @@ export default {
|
||||
OnTheFlyThirdparty,
|
||||
OnTheFlyCreate
|
||||
},
|
||||
props: ['type', 'id', 'action', 'buttonText'],
|
||||
props: ['type', 'id', 'action', 'buttonText', 'displayBadge'],
|
||||
emits: ['saveFormOnTheFly'],
|
||||
data() {
|
||||
return {
|
||||
@@ -123,17 +128,25 @@ export default {
|
||||
return 'action.redirect.' + this.type;
|
||||
}
|
||||
},
|
||||
buttonMessage(){
|
||||
buttonMessage() {
|
||||
switch (this.type){
|
||||
case 'person':
|
||||
return 'onthefly.show.file_' + this.type;
|
||||
case 'thirdparty':
|
||||
return 'onthefly.show.file_' + this.type;
|
||||
}
|
||||
},
|
||||
isDisplayBadge() {
|
||||
return (this.displayBadge === true && this.buttonText !== null);
|
||||
},
|
||||
badgeType() {
|
||||
return 'entity-' + this.type + ' badge-' + this.type;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
openModal() {
|
||||
console.log('## OPEN ON THE FLY MODAL');
|
||||
console.log('## type:', this.type, ', action:', this.action);
|
||||
this.modal.showModal = true;
|
||||
this.$nextTick(function() {
|
||||
//this.$refs.search.focus();
|
||||
@@ -144,7 +157,6 @@ export default {
|
||||
},
|
||||
saveAction() {
|
||||
console.log('saveAction button: create/edit action with', this.type);
|
||||
|
||||
let
|
||||
type = this.type,
|
||||
data = {} ;
|
||||
@@ -159,10 +171,9 @@ export default {
|
||||
break;
|
||||
|
||||
default:
|
||||
if (typeof this.type === 'undefined') {
|
||||
if (typeof this.type === 'undefined') { // action=create
|
||||
type = this.$refs.castNew.radioType;
|
||||
data = this.$refs.castNew.castDataByType();
|
||||
|
||||
} else {
|
||||
throw 'error with object type';
|
||||
}
|
||||
@@ -173,11 +184,12 @@ export default {
|
||||
|
||||
this.modal.showModal = false;
|
||||
},
|
||||
goToLocation(id, type){
|
||||
if(type == 'person'){
|
||||
window.location = `../../person/${id}/general`
|
||||
} else if(type == 'thirdparty') {
|
||||
window.location = `../../thirdparty/thirdparty/${id}/show`
|
||||
buildLocation(id, type) {
|
||||
if (type === 'person') {
|
||||
// TODO i18n
|
||||
return `/fr/person/${id}/general`;
|
||||
} else if (type === 'thirdparty') {
|
||||
return `/fr/thirdparty/thirdparty/${id}/show`;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -188,5 +200,4 @@ export default {
|
||||
a {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
</style>
|
@@ -0,0 +1,24 @@
|
||||
const ontheflyMessages = {
|
||||
fr: {
|
||||
onthefly: {
|
||||
show: {
|
||||
person: "Détails de l'usager",
|
||||
thirdparty: "Détails du tiers",
|
||||
file_person: "Ouvrir la fiche de l'usager",
|
||||
file_thirdparty: "Voir le Tiers",
|
||||
},
|
||||
edit: {
|
||||
person: "Modifier un usager",
|
||||
thirdparty: "Modifier un tiers"
|
||||
},
|
||||
create: {
|
||||
button: "Créer \"{q}\"",
|
||||
title: "Création d'un nouvel usager ou d'un tiers professionnel",
|
||||
person: "un nouvel usager",
|
||||
thirdparty: "un nouveau tiers professionnel"
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export { ontheflyMessages };
|
@@ -0,0 +1,35 @@
|
||||
import { createApp } from "vue";
|
||||
import { _createI18n } from 'ChillMainAssets/vuejs/_js/i18n';
|
||||
import { ontheflyMessages } from './i18n.js';
|
||||
import App from "./App.vue";
|
||||
|
||||
const i18n = _createI18n( ontheflyMessages );
|
||||
|
||||
let containers = document.querySelectorAll('.onthefly-container');
|
||||
|
||||
containers.forEach((container) => {
|
||||
|
||||
const app = createApp({
|
||||
template: `<app :onTheFly="this.onTheFly" ></app>`,
|
||||
data() {
|
||||
return {
|
||||
onTheFly: {
|
||||
context: {
|
||||
action: container.dataset.action,
|
||||
type: container.dataset.targetName,
|
||||
id: parseInt(container.dataset.targetId),
|
||||
},
|
||||
options: {
|
||||
buttonText: container.dataset.buttonText || null,
|
||||
displayBadge: container.dataset.displayBadge || false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.use(i18n)
|
||||
.component('app', App)
|
||||
.mount(container);
|
||||
|
||||
//console.log('container dataset', container.dataset);
|
||||
});
|
@@ -53,24 +53,6 @@ const messages = {
|
||||
top: "Haut",
|
||||
bottom: "Bas",
|
||||
},
|
||||
onthefly: {
|
||||
show: {
|
||||
person: "Détails de l'usager",
|
||||
thirdparty: "Détails du tiers",
|
||||
file_person: "Ouvrir la fiche de l'usager",
|
||||
file_thirdparty: "Voir le Tiers",
|
||||
},
|
||||
edit: {
|
||||
person: "Modifier un usager",
|
||||
thirdparty: "Modifier un tiers"
|
||||
},
|
||||
create: {
|
||||
button: "Créer \"{q}\"",
|
||||
title: "Création d'un nouvel usager ou d'un tiers professionnel",
|
||||
person: "un nouvel usager",
|
||||
thirdparty: "un nouveau tiers professionnel"
|
||||
},
|
||||
},
|
||||
renderbox: {
|
||||
person: "Usager",
|
||||
birthday: {
|
||||
|
@@ -18,7 +18,7 @@
|
||||
* stickyActions bool (default: false)
|
||||
* useValidFrom bool (default: false)
|
||||
* useValidTo bool (default: false)
|
||||
* hideAddress bool (default: false)
|
||||
* onlyButton bool (default: false)
|
||||
#}
|
||||
<div class="address-container"
|
||||
|
||||
@@ -69,7 +69,7 @@
|
||||
data-use-valid-to="true"
|
||||
{% endif %}
|
||||
|
||||
{% if hideAddress is defined and hideAddress == 1 %}
|
||||
{% if onlyButton is defined and onlyButton == 1 %}
|
||||
data-hide-address="true"
|
||||
{% endif %}
|
||||
></div>
|
||||
|
@@ -1,5 +1,5 @@
|
||||
{#
|
||||
* Copyright (C) 2014-2015, Champs Libres Cooperative SCRLFS,
|
||||
* Copyright (C) 2014-2015, Champs Libres Cooperative SCRLFS,
|
||||
<info@champs-libres.coop> / <http://www.champs-libres.coop>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
@@ -17,7 +17,7 @@
|
||||
#}
|
||||
|
||||
<ul>
|
||||
{% for route in routes %}
|
||||
<li><a href="{{ path(route.key, args ) }}" class="{%- if activeRouteKey == route.key -%}active{%- endif -%}">{{ route.label }}</a></li>
|
||||
{% for menu in menus %}
|
||||
<li><a href="{{ menu.uri }}">{{ menu.label }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</ul>
|
||||
|
@@ -0,0 +1,37 @@
|
||||
{#
|
||||
This Twig template include load vue_onthefly component.
|
||||
It push all variables from context in OnTheFly/App.vue.
|
||||
|
||||
OPTIONS
|
||||
* targetEntity {
|
||||
name: string 'person', 'thirdparty'
|
||||
id: integer
|
||||
}
|
||||
* action string 'show', 'edit', 'create'
|
||||
* buttonText string
|
||||
* displayBadge boolean (default: false) replace button by badge, need to define buttonText for content
|
||||
|
||||
#}
|
||||
<span class="onthefly-container"
|
||||
|
||||
data-target-name="{{ targetEntity.name|e('html_attr') }}"
|
||||
data-target-id="{{ targetEntity.id|e('html_attr') }}"
|
||||
|
||||
{% if action is defined %}
|
||||
data-action="{{ action|e('html_attr') }}"
|
||||
{% else %}
|
||||
data-action="show"
|
||||
{% endif %}
|
||||
|
||||
{% if buttonText is defined %}
|
||||
data-button-text="{{ buttonText|e('html_attr') }}"
|
||||
{% endif %}
|
||||
|
||||
{% if displayBadge is defined and displayBadge == 1 %}
|
||||
data-display-badge="true"
|
||||
{% endif %}
|
||||
|
||||
></span>
|
||||
|
||||
{{ encore_entry_script_tags('vue_onthefly') }}
|
||||
{{ encore_entry_link_tags('vue_onthefly') }}
|
@@ -10,7 +10,7 @@
|
||||
{% endblock %}
|
||||
{% block table_entities_tbody %}
|
||||
{% for entity in entities %}
|
||||
<tr>
|
||||
<tr data-username="{{ entity.username|e('html_attr') }}">
|
||||
<td>
|
||||
{% if entity.isEnabled %}
|
||||
<i class="fa fa-check chill-green"></i>
|
||||
|
@@ -70,6 +70,9 @@
|
||||
</center>
|
||||
</form>
|
||||
</div>
|
||||
<div class="col-8">
|
||||
<a href="{{ path('chill_crud_aside_activity_new', {'type' : 7, 'duration' : '600', 'note' : 'Pas des remarques' }) }}"><div class="bloc btn btn-success btn-md btn-block">Appel téléphonique</div></a>
|
||||
</div>
|
||||
|
||||
{{ chill_widget('homepage', {} ) }}
|
||||
{% endblock %}
|
||||
|
@@ -17,32 +17,31 @@
|
||||
*/
|
||||
namespace Chill\MainBundle\Test;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\KernelBrowser;
|
||||
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||
|
||||
/**
|
||||
* Prepare a client authenticated with a user
|
||||
*
|
||||
* @author Julien Fastré <julien.fastre@champs-libres.coop>
|
||||
* Prepare a client authenticated with a user
|
||||
*/
|
||||
trait PrepareClientTrait
|
||||
{
|
||||
/**
|
||||
* Create a new client with authentication information.
|
||||
*
|
||||
*
|
||||
* @param string $username the username (default 'center a_social')
|
||||
* @param string $password the password (default 'password')
|
||||
* @return \Symfony\Component\BrowserKit\Client
|
||||
* @throws \LogicException
|
||||
*/
|
||||
public function getClientAuthenticated(
|
||||
$username = 'center a_social',
|
||||
$username = 'center a_social',
|
||||
$password = 'password'
|
||||
) {
|
||||
): KernelBrowser {
|
||||
if (!$this instanceof WebTestCase) {
|
||||
throw new \LogicException(sprintf("The current class does not "
|
||||
. "implements %s", WebTestCase::class));
|
||||
}
|
||||
|
||||
|
||||
return static::createClient(array(), array(
|
||||
'PHP_AUTH_USER' => $username,
|
||||
'PHP_AUTH_PW' => $password,
|
||||
|
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace Controller;
|
||||
|
||||
use Chill\MainBundle\Entity\Address;
|
||||
use Chill\MainBundle\Repository\AddressRepository;
|
||||
use Chill\MainBundle\Test\PrepareClientTrait;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\KernelBrowser;
|
||||
|
||||
class AddressControllerTest extends \Symfony\Bundle\FrameworkBundle\Test\WebTestCase
|
||||
{
|
||||
private KernelBrowser $client;
|
||||
|
||||
use PrepareClientTrait;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
self::bootKernel();
|
||||
$this->client = $this->getClientAuthenticated();
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider generateAddressIds
|
||||
* @param int $addressId
|
||||
*/
|
||||
public function testDuplicate(int $addressId)
|
||||
{
|
||||
$this->client->request('POST', "/api/1.0/main/address/$addressId/duplicate.json");
|
||||
|
||||
$this->assertResponseIsSuccessful('test that duplicate is successful');
|
||||
}
|
||||
|
||||
public function generateAddressIds()
|
||||
{
|
||||
self::bootKernel();
|
||||
$em = self::$container->get(EntityManagerInterface::class);
|
||||
|
||||
$qb = $em->createQueryBuilder();
|
||||
$addresses = $qb->select('a')->from(Address::class, 'a')
|
||||
->setMaxResults(2)
|
||||
->getQuery()
|
||||
->getResult();
|
||||
|
||||
foreach ($addresses as $a) {
|
||||
yield [ $a->getId() ];
|
||||
}
|
||||
}
|
||||
}
|
@@ -2,12 +2,17 @@
|
||||
|
||||
namespace Chill\MainBundle\Tests\Controller;
|
||||
|
||||
use Chill\MainBundle\Entity\User;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
|
||||
|
||||
class UserControllerTest extends WebTestCase
|
||||
{
|
||||
private $client;
|
||||
|
||||
private array $toDelete = [];
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
self::bootKernel();
|
||||
@@ -22,18 +27,14 @@ class UserControllerTest extends WebTestCase
|
||||
public function testList()
|
||||
{
|
||||
// get the list
|
||||
$crawler = $this->client->request('GET', '/fr/admin/user/');
|
||||
$crawler = $this->client->request('GET', '/fr/admin/main/user');
|
||||
$this->assertEquals(200, $this->client->getResponse()->getStatusCode(),
|
||||
"Unexpected HTTP status code for GET /admin/user/");
|
||||
|
||||
$link = $crawler->selectLink('Ajouter un nouvel utilisateur')->link();
|
||||
$this->assertInstanceOf('Symfony\Component\DomCrawler\Link', $link);
|
||||
$this->assertRegExp('|/fr/admin/user/new$|', $link->getUri());
|
||||
"Unexpected HTTP status code for GET /admin/main/user");
|
||||
}
|
||||
|
||||
public function testNew()
|
||||
{
|
||||
$crawler = $this->client->request('GET', '/fr/admin/user/new');
|
||||
$crawler = $this->client->request('GET', '/fr/admin/main/user/new');
|
||||
|
||||
$username = 'Test_user'. uniqid();
|
||||
$password = 'Password1234!';
|
||||
@@ -54,22 +55,15 @@ class UserControllerTest extends WebTestCase
|
||||
$this->assertGreaterThan(0, $crawler->filter('td:contains("Test_user")')->count(),
|
||||
'Missing element td:contains("Test user")');
|
||||
|
||||
$update = $crawler->selectLink('Modifier')->link();
|
||||
|
||||
$this->assertInstanceOf('Symfony\Component\DomCrawler\Link', $update);
|
||||
$this->assertRegExp('|/fr/admin/user/[0-9]{1,}/edit$|', $update->getUri());
|
||||
|
||||
//test the auth of the new client
|
||||
$this->isPasswordValid($username, $password);
|
||||
|
||||
return $update;
|
||||
}
|
||||
|
||||
protected function isPasswordValid($username, $password)
|
||||
{
|
||||
/* @var $passwordEncoder \Symfony\Component\Security\Core\Encoder\UserPasswordEncoder */
|
||||
$passwordEncoder = self::$kernel->getContainer()
|
||||
->get('security.password_encoder');
|
||||
$passwordEncoder = self::$container
|
||||
->get(UserPasswordEncoderInterface::class);
|
||||
|
||||
$user = self::$kernel->getContainer()
|
||||
->get('doctrine.orm.entity_manager')
|
||||
@@ -81,46 +75,33 @@ class UserControllerTest extends WebTestCase
|
||||
|
||||
/**
|
||||
*
|
||||
* @param \Symfony\Component\DomCrawler\Link $update
|
||||
* @depends testNew
|
||||
* @dataProvider dataGenerateUserId
|
||||
*/
|
||||
public function testUpdate(\Symfony\Component\DomCrawler\Link $update)
|
||||
public function testUpdate(int $userId, string $username)
|
||||
{
|
||||
$crawler = $this->client->click($update);
|
||||
$crawler = $this->client->request('GET', "/fr/admin/main/user/$userId/edit");
|
||||
|
||||
$username = 'Foo bar '.uniqid();
|
||||
$form = $crawler->selectButton('Mettre à jour')->form(array(
|
||||
$form = $crawler->selectButton('Enregistrer & fermer')->form(array(
|
||||
'chill_mainbundle_user[username]' => $username,
|
||||
));
|
||||
|
||||
$this->client->submit($form);
|
||||
$crawler = $this->client->followRedirect();
|
||||
// Check the element contains an attribute with value equals "Foo"
|
||||
$this->assertGreaterThan(0, $crawler->filter('[value="'.$username.'"]')->count(),
|
||||
'Missing element [value="Foo bar"]');
|
||||
|
||||
$updatePassword = $crawler->selectLink('Modifier le mot de passe')->link();
|
||||
|
||||
$this->assertInstanceOf('Symfony\Component\DomCrawler\Link', $updatePassword);
|
||||
$this->assertRegExp('|/fr/admin/user/[0-9]{1,}/edit_password$|',
|
||||
$updatePassword->getUri());
|
||||
|
||||
return array('link' => $updatePassword, 'username' => $username);
|
||||
$this->assertGreaterThan(0, $crawler->filter('[data-username="'.$username.'"]')->count(),
|
||||
'Missing element [data-username="Foo bar"]');
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param \Symfony\Component\DomCrawler\Link $updatePassword
|
||||
* @depends testUpdate
|
||||
* @dataProvider dataGenerateUserId
|
||||
*/
|
||||
public function testUpdatePassword(array $params)
|
||||
public function testUpdatePassword(int $userId, $username)
|
||||
{
|
||||
$link = $params['link'];
|
||||
$username = $params['username'];
|
||||
$crawler = $this->client->request('GET', "/fr/admin/user/$userId/edit_password");
|
||||
$newPassword = '1234Password!';
|
||||
|
||||
$crawler = $this->client->click($link);
|
||||
|
||||
$form = $crawler->selectButton('Changer le mot de passe')->form(array(
|
||||
'chill_mainbundle_user_password[new_password][first]' => $newPassword,
|
||||
'chill_mainbundle_user_password[new_password][second]' => $newPassword,
|
||||
@@ -130,10 +111,38 @@ class UserControllerTest extends WebTestCase
|
||||
|
||||
$this->assertTrue($this->client->getResponse()->isRedirect(),
|
||||
"the response is a redirection");
|
||||
$this->client->followRedirect();
|
||||
|
||||
$this->isPasswordValid($username, $newPassword);
|
||||
}
|
||||
|
||||
protected function tearDown()
|
||||
{
|
||||
self::bootKernel();
|
||||
$em = self::$container->get(EntityManagerInterface::class);
|
||||
|
||||
foreach ($this->toDelete as list($class, $id)) {
|
||||
$obj = $em->getRepository($class)->find($id);
|
||||
$em->remove($obj);
|
||||
}
|
||||
|
||||
$em->flush();
|
||||
}
|
||||
|
||||
public function dataGenerateUserId()
|
||||
{
|
||||
self::bootKernel();
|
||||
$em = self::$container->get(EntityManagerInterface::class);
|
||||
|
||||
$user = new User();
|
||||
$user->setUsername('Test_user '.uniqid());
|
||||
$user->setPassword(self::$container->get(UserPasswordEncoderInterface::class)->encodePassword($user,
|
||||
'password'));
|
||||
|
||||
$em->persist($user);
|
||||
$em->flush();
|
||||
|
||||
$this->toDelete[] = [User::class, $user->getId()];
|
||||
|
||||
yield [ $user->getId(), $user->getUsername() ];
|
||||
}
|
||||
}
|
||||
|
@@ -1,54 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* <one line to give the program's name and a brief idea of what it does.>
|
||||
* Copyright (C) 2014, Champs Libres Cooperative SCRLFS, <http://www.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\Tests\Services;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
|
||||
use Symfony\Component\DomCrawler\Crawler;
|
||||
|
||||
/**
|
||||
* Test the Twig function 'chill_menu'
|
||||
*
|
||||
* @author Julien Fastré <julien.fastre@champs-libres.coop>
|
||||
*/
|
||||
class ChillMenuTwigFunctionTest extends KernelTestCase
|
||||
{
|
||||
|
||||
private static $templating;
|
||||
|
||||
public static function setUpBeforeClass()
|
||||
{
|
||||
self::bootKernel(array('environment' => 'test'));
|
||||
static::$templating = static::$container
|
||||
->get('templating');
|
||||
$pathToBundle = static::$container->getParameter('kernel.bundles_metadata')['ChillMainBundle']['path'];
|
||||
//load templates in Tests/Resources/views
|
||||
static::$container->get('twig.loader')
|
||||
->addPath($pathToBundle.'/Resources/test/views/', $namespace = 'tests');
|
||||
}
|
||||
|
||||
public function testNormalMenu()
|
||||
{
|
||||
$content = static::$templating->render('@tests/menus/normalMenu.html.twig');
|
||||
$this->assertContains('ul', $content,
|
||||
"test that the file contains an ul tag"
|
||||
);
|
||||
}
|
||||
}
|
@@ -293,6 +293,32 @@ paths:
|
||||
401:
|
||||
description: "Unauthorized"
|
||||
|
||||
/1.0/main/address/{id}/duplicate.json:
|
||||
post:
|
||||
tags:
|
||||
- address
|
||||
summary: Duplicate an existing address
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
required: true
|
||||
description: The address id that will be duplicated
|
||||
schema:
|
||||
type: integer
|
||||
format: integer
|
||||
minimum: 1
|
||||
responses:
|
||||
200:
|
||||
description: "ok"
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Address'
|
||||
404:
|
||||
description: "not found"
|
||||
401:
|
||||
description: "Unauthorized"
|
||||
|
||||
/1.0/main/address-reference.json:
|
||||
get:
|
||||
tags:
|
||||
|
@@ -61,5 +61,6 @@ module.exports = function(encore, entries)
|
||||
|
||||
// Vue entrypoints
|
||||
encore.addEntry('vue_address', __dirname + '/Resources/public/vuejs/Address/index.js');
|
||||
encore.addEntry('vue_onthefly', __dirname + '/Resources/public/vuejs/OnTheFly/index.js');
|
||||
|
||||
};
|
||||
|
@@ -1,7 +1,7 @@
|
||||
"This program is free software: you can redistribute it and/or modify it under the terms of the <strong>GNU Affero General Public License</strong>": "Ce programme est un logiciel libre: vous pouvez le redistribuer et/ou le modifier selon les termes de la licence <strong>GNU Affero GPL</strong>"
|
||||
User manual: Manuel d'utilisation
|
||||
Search: Rechercher
|
||||
'Search persons, ...': 'Recherche des personnes, ...'
|
||||
"Search persons, ...": "Recherche des personnes, ..."
|
||||
Person name: Nom / Prénom de la personne
|
||||
Login: Connexion
|
||||
Logout: Se déconnecter
|
||||
@@ -33,7 +33,7 @@ Cancel: Annuler
|
||||
Save: Enregistrer
|
||||
This form contains errors: Ce formulaire contient des erreurs
|
||||
Choose an user: Choisir un utilisateur
|
||||
'You are going to leave a page with unsubmitted data. Are you sure you want to leave ?': "Vous allez quitter la page alors que des données n'ont pas été enregistrées. Êtes vous sûr de vouloir partir ?"
|
||||
"You are going to leave a page with unsubmitted data. Are you sure you want to leave ?": "Vous allez quitter la page alors que des données n'ont pas été enregistrées. Êtes vous sûr de vouloir partir ?"
|
||||
No value: Aucune information
|
||||
Last updated by: Dernière mise à jour par
|
||||
Last updated on: Dernière mise à jour le
|
||||
@@ -71,24 +71,24 @@ Postal code: Code postal
|
||||
Valid from: Valide à partir du
|
||||
Choose a postal code: Choisir un code postal
|
||||
address:
|
||||
address_homeless: L'adresse est-elle celle d'un domicile fixe ?
|
||||
real address: Adresse d'un domicile
|
||||
consider homeless: N'est pas l'adresse d'un domicile (SDF)
|
||||
address_homeless: L'adresse est-elle celle d'un domicile fixe ?
|
||||
real address: Adresse d'un domicile
|
||||
consider homeless: N'est pas l'adresse d'un domicile (SDF)
|
||||
address more:
|
||||
floor: ét
|
||||
corridor: coul
|
||||
steps: esc
|
||||
flat: appart
|
||||
buildingName: résidence
|
||||
extra: ''
|
||||
distribution: cedex
|
||||
floor: ét
|
||||
corridor: coul
|
||||
steps: esc
|
||||
flat: appart
|
||||
buildingName: résidence
|
||||
extra: ""
|
||||
distribution: cedex
|
||||
Create a new address: Créer une nouvelle adresse
|
||||
|
||||
#serach
|
||||
Your search is empty. Please provide search terms.: La recherche est vide. Merci de fournir des termes de recherche.
|
||||
The domain %domain% is unknow. Please check your search.: Le domaine de recherche "%domain%" est inconnu. Merci de vérifier votre recherche.
|
||||
Invalid terms : Recherche invalide
|
||||
You should not have more than one domain. : Vous ne devriez pas avoir plus d'un domaine de recherche.
|
||||
Invalid terms: Recherche invalide
|
||||
You should not have more than one domain.: Vous ne devriez pas avoir plus d'un domaine de recherche.
|
||||
#used for page title
|
||||
Search %pattern%: Recherche de "%pattern%"
|
||||
Results %start%-%end% of %total%: Résultats %start%-%end% sur %total%
|
||||
@@ -113,9 +113,9 @@ Permissions Menu: Gestion des droits
|
||||
Permissions management of your chill installation: Gestion des permissions de votre instance
|
||||
|
||||
#admin section
|
||||
'Administration interface': Interface d'administration
|
||||
"Administration interface": Interface d'administration
|
||||
Welcome to the admin section !: >
|
||||
Bienvenue dans l'interface d'administration !
|
||||
Bienvenue dans l'interface d'administration !
|
||||
|
||||
#admin section for center's administration
|
||||
Create a new center: Créer un nouveau centre
|
||||
@@ -210,7 +210,6 @@ Problem during download: Problème durant le téléchargement
|
||||
# sans valeur
|
||||
without data: sans valeur
|
||||
|
||||
|
||||
#CSV List Formatter
|
||||
Add a number on first column: La première colonne est un numéro
|
||||
Number: Numéro
|
||||
@@ -228,9 +227,9 @@ Comma separated values (CSV): Valeurs séparées par des virgules (CSV - tableur
|
||||
Choose the format: Choisir le format
|
||||
|
||||
# select2
|
||||
'select2.no_results': Aucun résultat
|
||||
'select2.error_loading': Erreur de chargement des résultats
|
||||
'select2.searching': Recherche en cours...
|
||||
"select2.no_results": Aucun résultat
|
||||
"select2.error_loading": Erreur de chargement des résultats
|
||||
"select2.searching": Recherche en cours...
|
||||
|
||||
# change password
|
||||
Change my password: Modification du mot de passe
|
||||
@@ -258,38 +257,35 @@ Impersonate: Incarner l'utilisateur
|
||||
Impersonate mode: Mode fantôme
|
||||
|
||||
crud:
|
||||
# general items
|
||||
new:
|
||||
button_action_form: Créer
|
||||
link_edit: Modifier
|
||||
save_and_close: Créer & fermer
|
||||
save_and_show: Créer & voir
|
||||
save_and_new: Créer & nouveau
|
||||
success: Les données ont été créées
|
||||
edit:
|
||||
button_action_form: Enregistrer
|
||||
back_to_view: Voir
|
||||
save_and_close: Enregistrer & fermer
|
||||
save_and_show: Enregistrer & voir
|
||||
success: Les données ont été modifiées
|
||||
delete:
|
||||
success: Les données ont été supprimées
|
||||
link_to_form: Supprimer
|
||||
default:
|
||||
success: Les données ont été enregistrées
|
||||
view:
|
||||
link_duplicate: Dupliquer
|
||||
## admin for users
|
||||
admin_user:
|
||||
index:
|
||||
title: Utilisateurs
|
||||
add_new: "Créer"
|
||||
is_active: "Actif ?"
|
||||
usernames: "Identifiants"
|
||||
mains: "Champs principaux"
|
||||
title_new: "Nouvel utilisateur"
|
||||
title_edit: Modifier un utilisateur
|
||||
# general items
|
||||
new:
|
||||
button_action_form: Créer
|
||||
link_edit: Modifier
|
||||
save_and_close: Créer & fermer
|
||||
save_and_show: Créer & voir
|
||||
save_and_new: Créer & nouveau
|
||||
success: Les données ont été créées
|
||||
edit:
|
||||
button_action_form: Enregistrer
|
||||
back_to_view: Voir
|
||||
save_and_close: Enregistrer & fermer
|
||||
save_and_show: Enregistrer & voir
|
||||
success: Les données ont été modifiées
|
||||
delete:
|
||||
success: Les données ont été supprimées
|
||||
link_to_form: Supprimer
|
||||
default:
|
||||
success: Les données ont été enregistrées
|
||||
view:
|
||||
link_duplicate: Dupliquer
|
||||
No entities: Aucun élément
|
||||
|
||||
CHILL_FOO_SEE: Voir un élément
|
||||
CHILL_FOO_EDIT: Modifier un élément
|
||||
|
||||
#Show templates
|
||||
Date: Date
|
||||
By: Par
|
||||
For: Pour
|
||||
Created for: Créé pour
|
||||
Created by: Créé par
|
||||
|
@@ -118,6 +118,7 @@ class AccompanyingCourseController extends Controller
|
||||
return $this->render('@ChillPerson/AccompanyingCourse/index.html.twig', [
|
||||
'accompanyingCourse' => $accompanyingCourse,
|
||||
'withoutHousehold' => $withoutHousehold,
|
||||
'participationsByHousehold' => $accompanyingCourse->actualParticipationsByHousehold(),
|
||||
'works' => $works,
|
||||
'activities' => $activities
|
||||
]);
|
||||
|
@@ -45,9 +45,9 @@ class PersonApiController extends ApiController
|
||||
$person = parent::createEntity($action, $request);
|
||||
|
||||
// TODO temporary hack to allow creation of person with fake center
|
||||
$centers = $this->authorizationHelper->getReachableCenters($this->getUser(),
|
||||
/* $centers = $this->authorizationHelper->getReachableCenters($this->getUser(),
|
||||
new Role(PersonVoter::CREATE));
|
||||
$person->setCenter($centers[0]);
|
||||
$person->setCenter($centers[0]); */
|
||||
|
||||
return $person;
|
||||
}
|
||||
|
@@ -247,7 +247,6 @@ class LoadPeople extends AbstractFixture implements OrderedFixtureInterface, Con
|
||||
if (\random_int(0, 10) > 3) {
|
||||
// always add social scope:
|
||||
$accompanyingPeriod->addScope($this->getReference('scope_social'));
|
||||
var_dump(count($accompanyingPeriod->getScopes()));
|
||||
|
||||
$accompanyingPeriod->setAddressLocation($this->createAddress());
|
||||
$manager->persist($accompanyingPeriod->getAddressLocation());
|
||||
|
@@ -640,12 +640,13 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac
|
||||
Request::METHOD_GET => true,
|
||||
Request::METHOD_HEAD => true,
|
||||
Request::METHOD_POST=> true,
|
||||
Request::METHOD_PATCH => true
|
||||
],
|
||||
'roles' => [
|
||||
Request::METHOD_GET => \Chill\PersonBundle\Security\Authorization\PersonVoter::SEE,
|
||||
Request::METHOD_HEAD => \Chill\PersonBundle\Security\Authorization\PersonVoter::SEE,
|
||||
Request::METHOD_POST => \Chill\PersonBundle\Security\Authorization\PersonVoter::CREATE,
|
||||
|
||||
Request::METHOD_PATCH => \Chill\PersonBundle\Security\Authorization\PersonVoter::CREATE,
|
||||
],
|
||||
],
|
||||
'address' => [
|
||||
|
@@ -213,7 +213,7 @@ class AccompanyingPeriod implements TrackCreationInterface, TrackUpdateInterface
|
||||
private $scopes;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity=Person::class)
|
||||
* @ORM\ManyToOne(targetEntity=Person::class, inversedBy="accompanyingPeriodRequested")
|
||||
* @ORM\JoinColumn(nullable=true)
|
||||
*/
|
||||
private $requestorPerson;
|
||||
@@ -513,6 +513,44 @@ class AccompanyingPeriod implements TrackCreationInterface, TrackUpdateInterface
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array with open participations sorted by household
|
||||
* [
|
||||
* [
|
||||
* "household" => Household x,
|
||||
* "members" => [
|
||||
* Participation y , Participation z, ...
|
||||
* ]
|
||||
* ],
|
||||
* ]
|
||||
*
|
||||
*/
|
||||
public function actualParticipationsByHousehold(): array
|
||||
{
|
||||
$participations = $this->getOPenParticipations()->toArray();
|
||||
|
||||
$households = [];
|
||||
foreach ($participations as $p) {
|
||||
$households[] = $p->getPerson()->getCurrentHousehold();
|
||||
}
|
||||
$households = array_unique($households, SORT_REGULAR);
|
||||
|
||||
$array = [];
|
||||
foreach ($households as $household) {
|
||||
$members = [];
|
||||
foreach ($participations as $p) {
|
||||
if ($household === $p->getPerson()->getCurrentHousehold()) {
|
||||
$members[] = array_shift($participations);
|
||||
} else {
|
||||
$participations[] = array_shift($participations);
|
||||
}
|
||||
}
|
||||
$array[] = [ 'household' => $household, 'members' => $members ];
|
||||
}
|
||||
|
||||
return $array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the accompanying period contains a person.
|
||||
*
|
||||
|
@@ -47,86 +47,91 @@ class AccompanyingPeriodParticipation
|
||||
* @Groups({"read"})
|
||||
*/
|
||||
private $id;
|
||||
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity=Person::class, inversedBy="accompanyingPeriodParticipations")
|
||||
* @ORM\JoinColumn(name="person_id", referencedColumnName="id", nullable=false)
|
||||
* @Groups({"read"})
|
||||
*/
|
||||
private $person;
|
||||
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity=AccompanyingPeriod::class, inversedBy="participations", cascade={"persist"})
|
||||
* @ORM\JoinColumn(name="accompanyingperiod_id", referencedColumnName="id", nullable=false)
|
||||
*/
|
||||
private $accompanyingPeriod;
|
||||
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="date", nullable=false)
|
||||
* @Groups({"read"})
|
||||
*/
|
||||
private $startDate;
|
||||
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="date", nullable=true)
|
||||
* @Groups({"read"})
|
||||
*/
|
||||
private $endDate = null;
|
||||
|
||||
|
||||
public function __construct(AccompanyingPeriod $accompanyingPeriod, Person $person)
|
||||
{
|
||||
$this->startDate = new \DateTimeImmutable('now');
|
||||
$this->accompanyingPeriod = $accompanyingPeriod;
|
||||
$this->person = $person;
|
||||
}
|
||||
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
|
||||
public function getPerson(): ?Person
|
||||
{
|
||||
return $this->person;
|
||||
}
|
||||
|
||||
|
||||
public function setPerson(?Person $person): self
|
||||
{
|
||||
$this->person = $person;
|
||||
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
public function getAccompanyingPeriod(): ?AccompanyingPeriod
|
||||
{
|
||||
return $this->accompanyingPeriod;
|
||||
}
|
||||
|
||||
|
||||
public function setAccompanyingPeriod(?AccompanyingPeriod $accompanyingPeriod): self
|
||||
{
|
||||
$this->accompanyingPeriod = $accompanyingPeriod;
|
||||
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
public function getStartDate(): ?\DateTimeInterface
|
||||
{
|
||||
return $this->startDate;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* public function setStartDate(\DateTimeInterface $startDate): self { $this->startDate = $startDate; return $this; }
|
||||
*/
|
||||
|
||||
|
||||
public function getEndDate(): ?\DateTimeInterface
|
||||
{
|
||||
return $this->endDate;
|
||||
}
|
||||
|
||||
|
||||
public function setEndDate(?\DateTimeInterface $endDate): self
|
||||
{
|
||||
$this->endDate = $endDate;
|
||||
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isOpen(): bool
|
||||
{
|
||||
return $this->endDate === null;
|
||||
}
|
||||
}
|
||||
|
@@ -229,7 +229,7 @@ class Household
|
||||
))
|
||||
->andWhere($expr->orX(
|
||||
$expr->isNull('endDate'),
|
||||
$expr->gte('endDate', $date)
|
||||
$expr->gt('endDate', $date)
|
||||
));
|
||||
|
||||
return $criteria;
|
||||
@@ -306,7 +306,7 @@ class Household
|
||||
)
|
||||
->orWhere(
|
||||
$expr->andX(
|
||||
$expr->lt('endDate', $date),
|
||||
$expr->lte('endDate', $date),
|
||||
$expr->neq('endDate', null)
|
||||
)
|
||||
);
|
||||
|
@@ -28,9 +28,9 @@ use Chill\MainBundle\Doctrine\Model\TrackUpdateInterface;
|
||||
use Chill\MainBundle\Entity\Center;
|
||||
use Chill\MainBundle\Entity\Country;
|
||||
use Chill\MainBundle\Entity\User;
|
||||
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||
use Chill\PersonBundle\Entity\Household\Household;
|
||||
use Chill\PersonBundle\Entity\MaritalStatus;
|
||||
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||
use Chill\PersonBundle\Entity\Household\HouseholdMember;
|
||||
use Chill\MainBundle\Entity\HasCenterInterface;
|
||||
use Chill\MainBundle\Entity\Address;
|
||||
@@ -329,6 +329,15 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
|
||||
*/
|
||||
private $accompanyingPeriodParticipations;
|
||||
|
||||
/**
|
||||
* The accompanying period requested by the Person
|
||||
*
|
||||
* @ORM\OneToMany(targetEntity=AccompanyingPeriod::class,
|
||||
* mappedBy="requestorPerson")
|
||||
* @var Collection|AccompanyingPeriod[]
|
||||
*/
|
||||
private Collection $accompanyingPeriodRequested;
|
||||
|
||||
/**
|
||||
* A remark over the person
|
||||
* @var string
|
||||
@@ -478,6 +487,7 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
|
||||
$this->genderComment = new CommentEmbeddable();
|
||||
$this->maritalStatusComment = new CommentEmbeddable();
|
||||
$this->periodLocatedOn = new ArrayCollection();
|
||||
$this->accompanyingPeriodRequested = new ArrayCollection();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -605,6 +615,8 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
|
||||
|
||||
/**
|
||||
* Get AccompanyingPeriodParticipations Collection
|
||||
*
|
||||
* @return AccompanyingPeriodParticipation[]|Collection
|
||||
*/
|
||||
public function getAccompanyingPeriodParticipations(): Collection
|
||||
{
|
||||
@@ -614,6 +626,8 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
|
||||
/**
|
||||
* Return a collection of participation, where the participation
|
||||
* is still opened, not a draft, and the period is still opened
|
||||
*
|
||||
* @return AccompanyingPeriodParticipation[]|Collection
|
||||
*/
|
||||
public function getOpenedParticipations(): Collection
|
||||
{
|
||||
@@ -1650,6 +1664,84 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return AccompanyingPeriod[]|Collection
|
||||
*/
|
||||
public function getAccompanyingPeriodRequested(): Collection
|
||||
{
|
||||
return $this->accompanyingPeriodRequested;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of all accompanying period where the person is involved:
|
||||
*
|
||||
* * as requestor;
|
||||
* * as participant, only for opened participation;
|
||||
*
|
||||
* @param bool $asParticipantOpen add participation which are still opened
|
||||
* @param bool $asRequestor add accompanying period where the person is requestor
|
||||
* @return AccompanyingPeriod[]|Collection
|
||||
*/
|
||||
public function getAccompanyingPeriodInvolved(
|
||||
bool $asParticipantOpen = true,
|
||||
bool $asRequestor = true
|
||||
): Collection
|
||||
{
|
||||
$result = new ArrayCollection();
|
||||
|
||||
if ($asParticipantOpen) {
|
||||
foreach ($this->getOpenedParticipations()
|
||||
->map(fn (AccompanyingPeriodParticipation $app) =>
|
||||
$app->getAccompanyingPeriod())
|
||||
as $period
|
||||
) {
|
||||
if (!$result->contains($period)) {
|
||||
$result->add($period);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($asRequestor) {
|
||||
foreach ($this->accompanyingPeriodRequested as $period) {
|
||||
if (!$result->contains($period)) {
|
||||
$result->add($period);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handy method to get the AccompanyingPeriodParticipation
|
||||
* matching a given AccompanyingPeriod.
|
||||
*
|
||||
* Used in template, to find the participation when iterating on a list
|
||||
* of period.
|
||||
*
|
||||
* @param \Chill\PersonBundle\Entity\AccompanyingPeriod $period
|
||||
* @return AccompanyingPeriodParticipation
|
||||
*/
|
||||
public function findParticipationForPeriod(AccompanyingPeriod $period): ?AccompanyingPeriodParticipation
|
||||
{
|
||||
$closeCandidates = [];
|
||||
|
||||
foreach ($this->getAccompanyingPeriodParticipations() as $participation) {
|
||||
if ($participation->getAccompanyingPeriod() === $period) {
|
||||
if ($participation->isOpen()) {
|
||||
return $participation;
|
||||
}
|
||||
$closeCandidates[] = $participation;
|
||||
}
|
||||
}
|
||||
|
||||
if (0 < count($closeCandidates)) {
|
||||
return $closeCandidates[0];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getCreatedBy(): ?User
|
||||
{
|
||||
return $this->createdBy;
|
||||
|
@@ -129,8 +129,7 @@ class PersonType extends AbstractType
|
||||
$builder
|
||||
->add('mobilenumber', TelType::class, array('required' => false))
|
||||
->add('acceptSMS', CheckboxType::class, array(
|
||||
'value' => false,
|
||||
'required' => true
|
||||
'required' => false
|
||||
));
|
||||
}
|
||||
|
||||
|
@@ -199,7 +199,7 @@ final class PersonACLAwareRepository implements PersonACLAwareRepositoryInterfac
|
||||
}
|
||||
|
||||
if (NULL !== $birthdate) {
|
||||
$qb->andWhere($qb->expr()->eq('s.birthdate', ':birthdate'))
|
||||
$qb->andWhere($qb->expr()->eq('p.birthdate', ':birthdate'))
|
||||
->setParameter('birthdate', $birthdate);
|
||||
}
|
||||
|
||||
|
@@ -247,3 +247,28 @@ span.fa-holder {
|
||||
font-family: "Open Sans Extrabold";
|
||||
}
|
||||
}
|
||||
|
||||
div.accompanyingcourse-resume {
|
||||
div.associated-persons {
|
||||
span.household {
|
||||
display: inline-block;
|
||||
border-radius: 8px;
|
||||
border: 1px solid $white;
|
||||
&:hover {
|
||||
border: 1px solid $chill-beige;
|
||||
i {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
&.no-household:hover {
|
||||
border: 1px solid $white;
|
||||
}
|
||||
i {
|
||||
color: $chill-beige;
|
||||
display: none;
|
||||
}
|
||||
padding: 0.3em;
|
||||
margin-right: 2px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -6,7 +6,7 @@ div.accompanying_course_work-list {
|
||||
flex-direction: row;
|
||||
width: 100%;
|
||||
color: $dark;
|
||||
height: 40px;
|
||||
//height: 40px;
|
||||
|
||||
span.title_label {
|
||||
border-radius: 0.35rem 0 0 0.35rem;
|
||||
|
@@ -87,8 +87,8 @@ export default {
|
||||
}
|
||||
padding: 0em 0em;
|
||||
margin: 1em 0;
|
||||
border: 1px dotted tint-color($chill-accourse-context, 10%);
|
||||
border-radius: 5px;
|
||||
border: 1px dotted tint-color($chill-accourse-context, 10%);
|
||||
border-left: 1px dotted tint-color($chill-accourse-context, 10%);
|
||||
border-right: 1px dotted tint-color($chill-accourse-context, 10%);
|
||||
dd {
|
||||
@@ -96,10 +96,15 @@ export default {
|
||||
}
|
||||
& > div {
|
||||
margin: 1em 3em 0;
|
||||
|
||||
&.flex-table,
|
||||
&.flex-bloc {
|
||||
margin: 1em 0 0;
|
||||
}
|
||||
&.alert.to-confirm {
|
||||
margin: 1em 0 0;
|
||||
padding: 1em 3em;
|
||||
}
|
||||
}
|
||||
|
||||
div.flex-table {
|
||||
|
@@ -91,7 +91,7 @@ export default {
|
||||
},
|
||||
scopes: {
|
||||
msg: 'confirm.set_a_scope',
|
||||
anchor: '#section-65'
|
||||
anchor: '#section-60'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -27,19 +27,34 @@
|
||||
</div>
|
||||
|
||||
<div v-if="isTemporaryAddress" class="alert alert-warning separator">
|
||||
<p>{{ $t('courselocation.temporary_address_must_be_changed') }}</p>
|
||||
<p>
|
||||
{{ $t('courselocation.temporary_address_must_be_changed') }}
|
||||
<i class="fa fa-fw fa-map-marker"></i>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="hasNoPersonLocation" class="alert alert-danger no-person-location">
|
||||
<i class="fa fa-warning fa-2x"></i>
|
||||
<div>
|
||||
<p>
|
||||
{{ $t('courselocation.associate_at_least_one_person_with_one_household_with_address') }}
|
||||
<a href="#section-10">
|
||||
<i class="fa fa-level-up fa-fw"></i>
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<ul class="record_actions">
|
||||
<li>
|
||||
<add-address
|
||||
v-if="!isPersonLocation"
|
||||
:key="key"
|
||||
:context="context"
|
||||
:key="addAddress.type"
|
||||
:options="addAddress.options"
|
||||
:options="options"
|
||||
:addressChangedCallback="submitTemporaryAddress"
|
||||
ref="addAddress">
|
||||
</add-address>
|
||||
@@ -55,11 +70,15 @@
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div v-if="!isLocationValid" class="alert alert-warning to-confirm">
|
||||
{{ $t('courselocation.not_valid') }}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from "vuex";
|
||||
import {mapGetters, mapState} from "vuex";
|
||||
import AddAddress from 'ChillMainAssets/vuejs/Address/components/AddAddress.vue';
|
||||
import AddressRenderBox from 'ChillMainAssets/vuejs/_components/Entity/AddressRenderBox.vue';
|
||||
|
||||
@@ -72,10 +91,7 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
addAddress: {
|
||||
type: 'accompanying_course_location',
|
||||
options: {
|
||||
/// Options override default.
|
||||
/// null value take default component value
|
||||
button: {
|
||||
text: {
|
||||
create: 'courselocation.add_temporary_address',
|
||||
@@ -86,13 +102,7 @@ export default {
|
||||
create: 'courselocation.add_temporary_address',
|
||||
edit: 'courselocation.edit_temporary_address'
|
||||
},
|
||||
/// Display each step in page or Modal
|
||||
openPanesInModal: true,
|
||||
// Use Date fields
|
||||
//useDate: {
|
||||
// validFrom: true
|
||||
//},
|
||||
hideAddress: true
|
||||
onlyButton: true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -102,6 +112,16 @@ export default {
|
||||
accompanyingCourse: state => state.accompanyingCourse,
|
||||
context: state => state.addressContext
|
||||
}),
|
||||
...mapGetters([
|
||||
'isLocationValid'
|
||||
]),
|
||||
options() {
|
||||
return this.addAddress.options;
|
||||
},
|
||||
key() {
|
||||
return (this.context.edit) ? 'address_' + this.context.addressId
|
||||
: this.accompanyingCourse.type + '_' + this.accompanyingCourse.id ;
|
||||
},
|
||||
isTemporaryAddress() {
|
||||
return this.accompanyingCourse.locationStatus === 'address';
|
||||
},
|
||||
@@ -111,11 +131,40 @@ export default {
|
||||
hasNoLocation() {
|
||||
return this.accompanyingCourse.locationStatus === 'none';
|
||||
},
|
||||
currentParticipations() {
|
||||
return this.accompanyingCourse.participations.filter(p => p.enddate !== null);
|
||||
},
|
||||
hasNoPersonLocation() {
|
||||
|
||||
let addressInParticipations_ = []
|
||||
this.currentParticipations.forEach(p => {
|
||||
addressInParticipations_.push(this.checkHouseholdAddressForParticipation(p));
|
||||
});
|
||||
|
||||
const booleanReducer = (previousValue, currentValue) => previousValue || currentValue;
|
||||
|
||||
let addressInParticipations = (addressInParticipations_.length > 0) ?
|
||||
addressInParticipations_.reduce(booleanReducer) : false;
|
||||
|
||||
//console.log(addressInParticipations_, addressInParticipations);
|
||||
return (
|
||||
this.accompanyingCourse.step !== 'DRAFT'
|
||||
&& this.isTemporaryAddress
|
||||
&& !addressInParticipations
|
||||
)
|
||||
;
|
||||
},
|
||||
isContextEdit() {
|
||||
return this.context.edit;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
checkHouseholdAddressForParticipation(participation) {
|
||||
if (participation.person.current_household_id === null) {
|
||||
return false;
|
||||
}
|
||||
return participation.person.current_household_address !== null;
|
||||
},
|
||||
initAddressContext() {
|
||||
let context = {
|
||||
target: {
|
||||
@@ -153,20 +202,44 @@ export default {
|
||||
created() {
|
||||
this.initAddressContext();
|
||||
|
||||
console.log('ac.locationStatus', this.accompanyingCourse.locationStatus);
|
||||
console.log('ac.location (temporary location)', this.accompanyingCourse.location);
|
||||
console.log('ac.personLocation', this.accompanyingCourse.personLocation);
|
||||
//console.log('ac.locationStatus', this.accompanyingCourse.locationStatus);
|
||||
//console.log('ac.location (temporary location)', this.accompanyingCourse.location);
|
||||
//console.log('ac.personLocation', this.accompanyingCourse.personLocation);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
|
||||
div.flex-table {
|
||||
div.item-bloc {
|
||||
div.alert {
|
||||
margin: 0 -0.9em -1em;
|
||||
div#accompanying-course {
|
||||
div.vue-component {
|
||||
& > div.alert.no-person-location {
|
||||
margin: 1px 0 0;
|
||||
}
|
||||
div.no-person-location {
|
||||
padding-top: 1.5em;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
& > i {
|
||||
flex-basis: 1.5em; flex-grow: 0; flex-shrink: 0;
|
||||
padding-top: 0.2em;
|
||||
opacity: 0.75;
|
||||
}
|
||||
& > div {
|
||||
flex-basis: auto;
|
||||
div.action {
|
||||
button.btn-update {
|
||||
margin-right: 2em;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
div.flex-table {
|
||||
div.item-bloc {
|
||||
div.alert {
|
||||
margin: 0 -0.9em -1em;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
@@ -26,7 +26,7 @@
|
||||
:id="p.person.id"
|
||||
:value="p.person.id"
|
||||
/>
|
||||
<label class="form-check-label" for="hasNoHousehold">
|
||||
<label class="form-check-label">
|
||||
{{ p.person.text }}
|
||||
</label>
|
||||
</div>
|
||||
@@ -58,11 +58,14 @@
|
||||
</add-persons>
|
||||
</div>
|
||||
|
||||
<div v-if="!isParticipationValid" class="alert alert-warning to-confirm">
|
||||
{{ $t('persons_associated.participation_not_valid') }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'vuex';
|
||||
import {mapGetters, mapState} from 'vuex';
|
||||
import ParticipationItem from "./PersonsAssociated/ParticipationItem.vue"
|
||||
import AddPersons from 'ChillPersonAssets/vuejs/_components/AddPersons.vue'
|
||||
|
||||
@@ -89,6 +92,9 @@ export default {
|
||||
courseId: state => state.accompanyingCourse.id,
|
||||
participations: state => state.accompanyingCourse.participations
|
||||
}),
|
||||
...mapGetters([
|
||||
'isParticipationValid'
|
||||
]),
|
||||
currentParticipations() {
|
||||
return this.participations.filter(p => p.endDate === null)
|
||||
},
|
||||
@@ -126,7 +132,7 @@ export default {
|
||||
<style lang="scss" scoped>
|
||||
div#accompanying-course {
|
||||
div.vue-component {
|
||||
& > div.alert {
|
||||
& > div.alert.no-household {
|
||||
margin: 0 0 -1em;
|
||||
}
|
||||
div.no-household {
|
||||
|
@@ -19,20 +19,8 @@
|
||||
v-if="hasCurrentHouseholdAddress"
|
||||
v-bind:person="participation.person">
|
||||
</button-location>
|
||||
<li>
|
||||
<on-the-fly
|
||||
v-bind:type="participation.person.type"
|
||||
v-bind:id="participation.person.id"
|
||||
action="show">
|
||||
</on-the-fly>
|
||||
</li>
|
||||
<li>
|
||||
<on-the-fly
|
||||
v-bind:type="participation.person.type"
|
||||
v-bind:id="participation.person.id"
|
||||
action="edit">
|
||||
</on-the-fly>
|
||||
</li>
|
||||
<li><on-the-fly :type="participation.person.type" :id="participation.person.id" action="show"></on-the-fly></li>
|
||||
<li><on-the-fly :type="participation.person.type" :id="participation.person.id" action="edit" @saveFormOnTheFly="saveFormOnTheFly"></on-the-fly></li>
|
||||
<!-- <li>
|
||||
<button class="btn btn-delete"
|
||||
:title="$t('action.delete')"
|
||||
@@ -69,7 +57,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import OnTheFly from 'ChillMainAssets/vuejs/_components/OnTheFly.vue';
|
||||
import OnTheFly from 'ChillMainAssets/vuejs/OnTheFly/components/OnTheFly.vue';
|
||||
import ButtonLocation from '../ButtonLocation.vue';
|
||||
import PersonRenderBox from 'ChillPersonAssets/vuejs/_components/Entity/PersonRenderBox.vue';
|
||||
import Modal from 'ChillMainAssets/vuejs/_components/Modal';
|
||||
@@ -112,22 +100,13 @@ export default {
|
||||
getAccompanyingCourseReturnPath() {
|
||||
return `fr/parcours/${this.$store.state.accompanyingCourse.id}/edit#section-10`;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
saveFormOnTheFly(payload) {
|
||||
console.log('saveFormOnTheFly: type', payload.type, ', data', payload.data);
|
||||
payload.target = 'participation';
|
||||
this.$store.dispatch('patchOnTheFly', payload);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* dates of participation
|
||||
*
|
||||
*
|
||||
*
|
||||
* <tr>
|
||||
* <td><span v-if="participation.startDate">
|
||||
* {{ $d(participation.startDate.datetime, 'short') }}</span>
|
||||
* </td>
|
||||
* <td><span v-if="participation.endDate">
|
||||
* {{ $d(participation.endDate.datetime, 'short') }}</span>
|
||||
* </td>
|
||||
* </tr>
|
||||
*
|
||||
*/
|
||||
</script>
|
||||
|
@@ -10,7 +10,7 @@
|
||||
{{ $t('requestor.is_anonymous') }}
|
||||
</label>
|
||||
|
||||
<third-party-render-box v-if="accompanyingCourse.requestor.type == 'thirdparty'"
|
||||
<third-party-render-box v-if="accompanyingCourse.requestor.type === 'thirdparty'"
|
||||
:thirdparty="accompanyingCourse.requestor"
|
||||
:options="{
|
||||
addLink: false,
|
||||
@@ -23,14 +23,13 @@
|
||||
>
|
||||
<template v-slot:record-actions>
|
||||
<ul class="record_actions">
|
||||
<button-location v-if="hasCurrentHouseholdAddress" :thirdparty="accompanyingCourse.requestor"></button-location>
|
||||
<li><on-the-fly :type="accompanyingCourse.requestor.type" :id="accompanyingCourse.requestor.id" action="show"></on-the-fly></li>
|
||||
<li><on-the-fly :type="accompanyingCourse.requestor.type" :id="accompanyingCourse.requestor.id" action="edit"></on-the-fly></li>
|
||||
<li><on-the-fly :type="accompanyingCourse.requestor.type" :id="accompanyingCourse.requestor.id" action="edit" @saveFormOnTheFly="saveFormOnTheFly"></on-the-fly></li>
|
||||
</ul>
|
||||
</template>
|
||||
</third-party-render-box>
|
||||
|
||||
<person-render-box render="bloc" v-else-if="accompanyingCourse.requestor.type == 'person'"
|
||||
<person-render-box render="bloc" v-else-if="accompanyingCourse.requestor.type === 'person'"
|
||||
:person="accompanyingCourse.requestor"
|
||||
:options="{
|
||||
addLink: false,
|
||||
@@ -44,9 +43,8 @@
|
||||
>
|
||||
<template v-slot:record-actions>
|
||||
<ul class="record_actions">
|
||||
<button-location v-if="hasCurrentHouseholdAddress" :person="accompanyingCourse.requestor"></button-location>
|
||||
<li><on-the-fly :type="accompanyingCourse.requestor.type" :id="accompanyingCourse.requestor.id" action="show"></on-the-fly></li>
|
||||
<li><on-the-fly :type="accompanyingCourse.requestor.type" :id="accompanyingCourse.requestor.id" action="edit"></on-the-fly></li>
|
||||
<li><on-the-fly :type="accompanyingCourse.requestor.type" :id="accompanyingCourse.requestor.id" action="edit" @saveFormOnTheFly="saveFormOnTheFly"></on-the-fly></li>
|
||||
</ul>
|
||||
</template>
|
||||
</person-render-box>
|
||||
@@ -81,7 +79,7 @@
|
||||
|
||||
<script>
|
||||
import AddPersons from 'ChillPersonAssets/vuejs/_components/AddPersons.vue';
|
||||
import OnTheFly from 'ChillMainAssets/vuejs/_components/OnTheFly.vue';
|
||||
import OnTheFly from 'ChillMainAssets/vuejs/OnTheFly/components/OnTheFly.vue';
|
||||
import PersonRenderBox from '../../_components/Entity/PersonRenderBox.vue';
|
||||
import ThirdPartyRenderBox from 'ChillThirdPartyAssets/vuejs/_components/Entity/ThirdPartyRenderBox.vue';
|
||||
|
||||
@@ -129,6 +127,11 @@ export default {
|
||||
this.$store.dispatch('addRequestor', selected.shift());
|
||||
this.$refs.addPersons.resetSearch(); // to cast child method
|
||||
modal.showModal = false;
|
||||
},
|
||||
saveFormOnTheFly(payload) {
|
||||
console.log('saveFormOnTheFly: type', payload.type, ', data', payload.data);
|
||||
payload.target = 'requestor';
|
||||
this.$store.dispatch('patchOnTheFly', payload);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -6,9 +6,11 @@
|
||||
>
|
||||
<template v-slot:record-actions>
|
||||
<ul class="record_actions">
|
||||
<!--
|
||||
<button-location v-if="hasCurrentHouseholdAddress" :person="resource.resource"></button-location>
|
||||
-->
|
||||
<li><on-the-fly :type="resource.resource.type" :id="resource.resource.id" action="show"></on-the-fly></li>
|
||||
<li><on-the-fly :type="resource.resource.type" :id="resource.resource.id" action="edit"></on-the-fly></li>
|
||||
<li><on-the-fly :type="resource.resource.type" :id="resource.resource.id" action="edit" @saveFormOnTheFly="saveFormOnTheFly"></on-the-fly></li>
|
||||
<li><button class="btn btn-sm btn-remove" :title="$t('action.remove')" @click.prevent="$emit('remove', resource)"></button></li>
|
||||
</ul>
|
||||
</template>
|
||||
@@ -22,7 +24,7 @@
|
||||
<template v-slot:record-actions>
|
||||
<ul class="record_actions">
|
||||
<li><on-the-fly :type="resource.resource.type" :id="resource.resource.id" action="show"></on-the-fly></li>
|
||||
<li><on-the-fly :type="resource.resource.type" :id="resource.resource.id" action="edit"></on-the-fly></li>
|
||||
<li><on-the-fly :type="resource.resource.type" :id="resource.resource.id" action="edit" @saveFormOnTheFly="saveFormOnTheFly"></on-the-fly></li>
|
||||
<li><button class="btn btn-sm btn-remove" :title="$t('action.remove')" @click.prevent="$emit('remove', resource)"></button></li>
|
||||
</ul>
|
||||
</template>
|
||||
@@ -31,7 +33,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import OnTheFly from 'ChillMainAssets/vuejs/_components/OnTheFly.vue';
|
||||
import OnTheFly from 'ChillMainAssets/vuejs/OnTheFly/components/OnTheFly.vue';
|
||||
import ButtonLocation from '../ButtonLocation.vue';
|
||||
import PersonRenderBox from 'ChillPersonAssets/vuejs/_components/Entity/PersonRenderBox.vue';
|
||||
import ThirdPartyRenderBox from 'ChillThirdPartyAssets/vuejs/_components/Entity/ThirdPartyRenderBox.vue';
|
||||
@@ -53,6 +55,13 @@ export default {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
saveFormOnTheFly(payload) {
|
||||
console.log('saveFormOnTheFly: type', payload.type, ', data', payload.data);
|
||||
payload.target = 'resource';
|
||||
this.$store.dispatch('patchOnTheFly', payload);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
@@ -1,18 +1,20 @@
|
||||
<template>
|
||||
<div class="vue-component">
|
||||
<h2><a id="section-60"></a>{{ $t('scopes.title') }}</h2>
|
||||
<h2><a id="section-60"></a>{{ $t('scopes.title') }}</h2>
|
||||
|
||||
<ul>
|
||||
<li v-for="s in scopes">
|
||||
<input type="checkbox" v-model="checkedScopes" :value="s" />
|
||||
{{ s.name.fr }}
|
||||
</li>
|
||||
</ul>
|
||||
<div class="mb-4">
|
||||
<div class="form-check" v-for="s in scopes">
|
||||
<input class="form-check-input" type="checkbox" v-model="checkedScopes" :value="s" />
|
||||
<label class="form-check-label">
|
||||
{{ s.name.fr }}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="!isScopeValid" class="alert alert-warning separator">
|
||||
<div v-if="!isScopeValid" class="alert alert-warning to-confirm">
|
||||
{{ $t('scopes.add_at_least_one') }}
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@@ -21,13 +21,17 @@
|
||||
</VueMultiselect>
|
||||
</div>
|
||||
|
||||
<div v-if="!isSocialIssueValid" class="alert alert-warning to-confirm">
|
||||
{{ $t('social_issue.not_valid') }}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import VueMultiselect from 'vue-multiselect';
|
||||
import { getSocialIssues } from '../api';
|
||||
import { mapState } from 'vuex';
|
||||
import {mapGetters, mapState} from 'vuex';
|
||||
|
||||
export default {
|
||||
name: "SocialIssue",
|
||||
@@ -41,6 +45,9 @@ export default {
|
||||
...mapState({
|
||||
value: state => state.accompanyingCourse.socialIssues,
|
||||
}),
|
||||
...mapGetters([
|
||||
'isSocialIssueValid'
|
||||
])
|
||||
},
|
||||
mounted() {
|
||||
this.getOptions();
|
||||
|
@@ -1,5 +1,7 @@
|
||||
import { personMessages } from 'ChillPersonAssets/vuejs/_js/i18n'
|
||||
import { personMessages } from 'ChillPersonAssets/vuejs/_js/i18n';
|
||||
import { thirdpartyMessages } from 'ChillThirdPartyAssets/vuejs/_js/i18n';
|
||||
import { addressMessages } from 'ChillMainAssets/vuejs/Address/i18n';
|
||||
import { ontheflyMessages } from 'ChillMainAssets/vuejs/OnTheFly/i18n';
|
||||
|
||||
const appMessages = {
|
||||
fr: {
|
||||
@@ -48,8 +50,9 @@ const appMessages = {
|
||||
ok: "Oui, l'usager quitte le parcours",
|
||||
show_household_number: "Voir le ménage (n° {id})",
|
||||
show_household: "Voir le ménage",
|
||||
person_without_household_warning: "Certaines personnes n'appartiennent à aucun ménage actuellement. Renseignez leur appartenance à un ménage dès que possible.",
|
||||
person_without_household_warning: "Certaines usagers n'appartiennent actuellement à aucun ménage. Renseignez leur appartenance dès que possible.",
|
||||
update_household: "Modifier l'appartenance",
|
||||
participation_not_valid: "Sélectionnez ou créez au minimum 1 usager",
|
||||
},
|
||||
requestor: {
|
||||
title: "Demandeur",
|
||||
@@ -72,6 +75,7 @@ const appMessages = {
|
||||
social_issue: {
|
||||
title: "Problématiques sociales",
|
||||
label: "Choisir les problématiques sociales",
|
||||
not_valid: "Sélectionnez au minimum une problématique sociale",
|
||||
},
|
||||
courselocation: {
|
||||
title: "Localisation du parcours",
|
||||
@@ -79,11 +83,13 @@ const appMessages = {
|
||||
edit_temporary_address: "Modifier l'adresse temporaire",
|
||||
assign_course_address: "Désigner comme l'adresse du parcours",
|
||||
remove_button: "Enlever l'adresse",
|
||||
temporary_address_must_be_changed: "Cette adresse est temporaire et devrait être remplacée par celle d'un usager de référence.",
|
||||
temporary_address_must_be_changed: "Cette adresse est temporaire. Le parcours devrait être localisé auprès d'un usager concerné.",
|
||||
associate_at_least_one_person_with_one_household_with_address: "Commencez d'abord par associer un membre du parcours à un ménage, et indiquez une adresse à ce ménage.",
|
||||
sure: "Êtes-vous sûr ?",
|
||||
sure_description: "Voulez-vous faire de cette adresse l'adresse du parcours ?",
|
||||
ok: "Désigner comme adresse du parcours",
|
||||
person_locator: "Parcours localisé auprès de {0}",
|
||||
not_valid: "Indiquez au minimum une localisation temporaire du parcours",
|
||||
no_address: "Il n'y a pas d'adresse associée au parcours"
|
||||
},
|
||||
scopes: {
|
||||
@@ -137,7 +143,7 @@ const appMessages = {
|
||||
}
|
||||
};
|
||||
|
||||
Object.assign(appMessages.fr, personMessages.fr, addressMessages.fr);
|
||||
Object.assign(appMessages.fr, personMessages.fr, thirdpartyMessages.fr, addressMessages.fr, ontheflyMessages.fr);
|
||||
|
||||
export {
|
||||
appMessages
|
||||
|
@@ -11,6 +11,8 @@ import { getAccompanyingCourse,
|
||||
addScope,
|
||||
removeScope,
|
||||
} from '../api';
|
||||
import { patchPerson } from "ChillPersonAssets/vuejs/_api/OnTheFly";
|
||||
import { patchThirdparty } from "ChillThirdPartyAssets/vuejs/_api/OnTheFly";
|
||||
|
||||
|
||||
const debug = process.env.NODE_ENV !== 'production';
|
||||
@@ -48,7 +50,7 @@ let initPromise = Promise.all([scopesPromise, accompanyingCoursePromise])
|
||||
return state.accompanyingCourse.location !== null;
|
||||
},
|
||||
isScopeValid(state) {
|
||||
console.log('is scope valid', state.accompanyingCourse.scopes.length > 0);
|
||||
//console.log('is scope valid', state.accompanyingCourse.scopes.length > 0);
|
||||
return state.accompanyingCourse.scopes.length > 0;
|
||||
},
|
||||
validationKeys(state, getters) {
|
||||
@@ -107,6 +109,36 @@ let initPromise = Promise.all([scopesPromise, accompanyingCoursePromise])
|
||||
//console.log('### mutation: addResource', resource);
|
||||
state.accompanyingCourse.resources.push(resource);
|
||||
},
|
||||
updatePerson(state, payload) {
|
||||
console.log('### mutation: updatePerson', payload);
|
||||
let i = null;
|
||||
switch (payload.target) {
|
||||
case 'participation':
|
||||
i = state.accompanyingCourse.participations.findIndex(e => e.person.id === payload.person.id );
|
||||
state.accompanyingCourse.participations[i].person = payload.person;
|
||||
break;
|
||||
case 'requestor':
|
||||
state.accompanyingCourse.requestor = payload.person;
|
||||
break;
|
||||
case 'resource':
|
||||
i = state.accompanyingCourse.resources.findIndex(e => e.resource.id === payload.person.id );
|
||||
state.accompanyingCourse.resources[i].resource = payload.person;
|
||||
break;
|
||||
}
|
||||
},
|
||||
updateThirdparty(state, payload) {
|
||||
console.log('### mutation: updateThirdparty', payload);
|
||||
let i = null;
|
||||
switch (payload.target) {
|
||||
case 'requestor':
|
||||
state.accompanyingCourse.requestor = payload.thirdparty;
|
||||
break;
|
||||
case 'resource':
|
||||
i = state.accompanyingCourse.resources.findIndex(e => e.resource.id === payload.thirdparty.id );
|
||||
state.accompanyingCourse.resources[i].resource = payload.thirdparty;
|
||||
break;
|
||||
}
|
||||
},
|
||||
toggleIntensity(state, value) {
|
||||
state.accompanyingCourse.intensity = value;
|
||||
},
|
||||
@@ -239,6 +271,38 @@ let initPromise = Promise.all([scopesPromise, accompanyingCoursePromise])
|
||||
resolve();
|
||||
})).catch((error) => { commit('catchError', error) });
|
||||
},
|
||||
patchOnTheFly({ commit }, payload) {
|
||||
console.log('## action: patch OnTheFly', payload);
|
||||
let body = { type: payload.type };
|
||||
if (payload.type === 'person') {
|
||||
body.firstName = payload.data.firstName;
|
||||
body.lastName = payload.data.lastName;
|
||||
if (payload.data.birthdate !== null) { body.birthdate = payload.data.birthdate; }
|
||||
body.phonenumber = payload.data.phonenumber;
|
||||
body.mobilenumber = payload.data.mobilenumber;
|
||||
body.gender = payload.data.gender;
|
||||
console.log('id', payload.data.id, 'and body', body);
|
||||
patchPerson(payload.data.id, body)
|
||||
.then(person => new Promise((resolve, reject) => {
|
||||
console.log('patch person', person);
|
||||
commit('updatePerson', { target: payload.target, person: person });
|
||||
resolve();
|
||||
}));
|
||||
}
|
||||
else if (payload.type === 'thirdparty') {
|
||||
body.name = payload.data.text;
|
||||
body.email = payload.data.email;
|
||||
body.telephone = payload.data.phonenumber;
|
||||
body.address = { id: payload.data.address.address_id };
|
||||
console.log('id', payload.data.id, 'and body', body);
|
||||
patchThirdparty(payload.data.id, body)
|
||||
.then(thirdparty => new Promise((resolve, reject) => {
|
||||
console.log('patch thirdparty', thirdparty);
|
||||
commit('updateThirdparty', { target: payload.target, thirdparty: thirdparty });
|
||||
resolve();
|
||||
}));
|
||||
}
|
||||
},
|
||||
toggleIntensity({ commit }, payload) {
|
||||
//console.log(payload);
|
||||
patchAccompanyingCourse(id, { type: "accompanying_period", intensity: payload })
|
||||
|
@@ -109,7 +109,7 @@ export default {
|
||||
this.toggleEditEvaluation();
|
||||
},
|
||||
buildEditLink(storedObject) {
|
||||
return `/fr/chill_wopi/edit/${storedObject.filename}?returnPath=` + encodeURIComponent(
|
||||
return `/edit/${storedObject.uuid}?returnPath=` + encodeURIComponent(
|
||||
window.location.pathname + window.location.search + window.location.hash);
|
||||
},
|
||||
}
|
||||
|
@@ -2,171 +2,126 @@
|
||||
|
||||
<h2 class="mt-4">{{ $t('household_members_editor.household_part') }}</h2>
|
||||
|
||||
<div v-if="hasHousehold">
|
||||
<div v-if="mode == null">
|
||||
|
||||
<div class="flex-table">
|
||||
<div class="item-bloc">
|
||||
<household-render-box :household="household" :isAddressMultiline="true"></household-render-box>
|
||||
</div>
|
||||
</div>
|
||||
<div class="alert alert-info">{{ $t('household_members_editor.household.no_household_choose_one') }}</div>
|
||||
|
||||
<div v-if="isHouseholdNew && !hasHouseholdAddress">
|
||||
|
||||
<div v-if="hasAddressSuggestion" class="householdAddressSuggestion my-5">
|
||||
<h4 class="mb-3">
|
||||
{{ $t('household_members_editor.household.where_live_the_household') }}
|
||||
</h4>
|
||||
<div class="accordion" id="addressSuggestions">
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header" id="heading_address_suggestions">
|
||||
<button v-if="!showAddressSuggestion"
|
||||
class="accordion-button collapsed"
|
||||
type="button"
|
||||
data-bs-toggle="collapse"
|
||||
aria-expanded="false"
|
||||
@click="toggleAddressSuggestion">
|
||||
{{ $tc('household_members_editor.show_household_suggestion', countAddressSuggestion) }}
|
||||
</button>
|
||||
<button v-if="showAddressSuggestion"
|
||||
class="accordion-button"
|
||||
type="button"
|
||||
data-bs-toggle="collapse"
|
||||
aria-expanded="true"
|
||||
@click="toggleAddressSuggestion">
|
||||
{{ $t('household_members_editor.hide_household_suggestion') }}
|
||||
</button>
|
||||
</h2>
|
||||
<div class="accordion-collapse" id="collapse_address_suggestions"
|
||||
aria-labelledby="heading_address_suggestions" data-bs-parent="#addressSuggestions">
|
||||
<div v-if="showAddressSuggestion">
|
||||
<div class="flex-table householdAddressSuggestionList">
|
||||
<div v-for="a in filterAddressesSuggestion" class="item-bloc">
|
||||
<div class="float-button bottom">
|
||||
<div class="box">
|
||||
<div class="action">
|
||||
<ul class="record_actions">
|
||||
<li>
|
||||
<button class="btn btn-sm btn-choose" @click="setHouseholdAddress(a)">
|
||||
{{ $t('household_members_editor.household.household_live_to_this_address') }}
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<ul class="list-content fa-ul">
|
||||
<li>
|
||||
<i class="fa fa-li fa-map-marker"></i>
|
||||
<address-render-box :address="a"></address-render-box>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-table householdSuggestionList">
|
||||
<div v-if="isModeNewAllowed" class="item-bloc">
|
||||
<div>
|
||||
<section>
|
||||
<div class="item-row">
|
||||
<div class="item-col">
|
||||
<div class="h4">
|
||||
<i class="fa fa-home"></i> {{ $t('household_members_editor.household.new_household') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<ul class="record_actions">
|
||||
<li>
|
||||
<button @click="setModeNew" class="btn btn-sm btn-create">{{ $t('household_members_editor.household.create_household') }}</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- if allow leave household -->
|
||||
<div v-if="isModeLeaveAllowed" class="item-bloc">
|
||||
<div>
|
||||
<section>
|
||||
<div class="item-row">
|
||||
<div class="item-col">
|
||||
<div class="h4">
|
||||
<span class="fa-stack fa-lg">
|
||||
<i class="fa fa-home fa-stack-1x"></i>
|
||||
<i class="fa fa-ban fa-stack-2x text-danger"></i>
|
||||
</span>
|
||||
{{ $t('household_members_editor.household.leave_without_household') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item-row">
|
||||
{{ $t('household_members_editor.household.will_leave_any_household_explanation')}}
|
||||
</div>
|
||||
</section>
|
||||
<ul class="record_actions">
|
||||
<li>
|
||||
<button @click="setModeLeave" class="btn btn-sm">
|
||||
<i class="fa fa-sign-out"></i>
|
||||
{{ $t('household_members_editor.household.leave') }}
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-for="item in getSuggestions">
|
||||
<div class="item-bloc">
|
||||
<household-render-box :household="item.household"></household-render-box>
|
||||
<ul class="record_actions">
|
||||
<li>
|
||||
<button class="btn btn-sm btn-choose" @click="selectHousehold(item.household)">
|
||||
{{ $t('household_members_editor.select_household') }}
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ul class="record_actions">
|
||||
<li >
|
||||
<add-address
|
||||
:context="addAddress.context"
|
||||
<div v-else>
|
||||
<div class="flex-table">
|
||||
<div class="item-bloc">
|
||||
<template v-if="isModeLeave">
|
||||
<section>
|
||||
<div class="item-row">
|
||||
<div class="item-col">
|
||||
<div class="h4">
|
||||
<span class="fa-stack fa-lg">
|
||||
<i class="fa fa-home fa-stack-1x"></i>
|
||||
<i class="fa fa-ban fa-stack-2x text-danger"></i>
|
||||
</span>
|
||||
{{ $t('household_members_editor.household.leave_without_household') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item-row">
|
||||
{{ $t('household_members_editor.household.will_leave_any_household_explanation')}}
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
<template v-else>
|
||||
<household-render-box :household="household" :isAddressMultiline="true"></household-render-box>
|
||||
<ul class="record_actions">
|
||||
<li>
|
||||
<add-address
|
||||
:context="getAddressContext"
|
||||
:key="addAddress.key"
|
||||
:options="addAddress.options"
|
||||
:result="addAddress.result"
|
||||
@addressChangedCallback="setHouseholdCreatedAddress"
|
||||
ref="addAddress">
|
||||
</add-address>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div v-if="isHouseholdNew && hasHouseholdAddress">
|
||||
<ul class="record_actions">
|
||||
<li >
|
||||
<button class="btn btn-misc" @click="removeHouseholdAddress">
|
||||
{{ $t('household_members_editor.household.delete_this_address') }}
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div v-else-if="isForceLeaveWithoutHousehold">
|
||||
{{ $t('household_members_editor.household.will_leave_any_household') }}
|
||||
</div>
|
||||
<div v-else class="alert alert-info">{{ $t('household_members_editor.household.no_household_choose_one') }}</div>
|
||||
|
||||
<ul v-if="allowChangeHousehold" class="record_actions">
|
||||
<li v-if="allowHouseholdCreate">
|
||||
<button class="btn btn-create" @click="createHousehold">
|
||||
{{ $t('household_members_editor.household.create_household') }}
|
||||
</button>
|
||||
</li>
|
||||
<li v-if="allowHouseholdSearch">
|
||||
<button class="btn btn-misc">
|
||||
<i class="fa fa-search"></i>{{ $t('household_members_editor.household.search_household') }}
|
||||
</button>
|
||||
</li>
|
||||
<li v-if="allowLeaveWithoutHousehold" >
|
||||
<button @click="forceLeaveWithoutHousehold" class="btn btn-orange">
|
||||
<i class="fa fa-sign-out"></i>{{ $t('household_members_editor.household.leave_without_household') }}
|
||||
</button>
|
||||
</li>
|
||||
<li v-if="allowRemoveHousehold">
|
||||
<button @click="removeHousehold" class="btn">
|
||||
{{ $t('household_members_editor.household.change') }}
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div v-if="hasHouseholdSuggestion" class="householdSuggestions my-5">
|
||||
<h4 class="mb-3">
|
||||
{{ $t('household_members_editor.household_for_participants_accompanying_period') }} :
|
||||
</h4>
|
||||
<div class="accordion" id="householdSuggestions">
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header" id="heading_household_suggestions">
|
||||
<button v-if="!showHouseholdSuggestion"
|
||||
class="accordion-button collapsed"
|
||||
type="button"
|
||||
data-bs-toggle="collapse"
|
||||
aria-expanded="false"
|
||||
@click="toggleHouseholdSuggestion">
|
||||
{{ $tc('household_members_editor.show_household_suggestion', countHouseholdSuggestion) }}
|
||||
</button>
|
||||
<button v-if="showHouseholdSuggestion"
|
||||
class="accordion-button"
|
||||
type="button"
|
||||
data-bs-toggle="collapse"
|
||||
aria-expanded="true"
|
||||
@click="toggleHouseholdSuggestion">
|
||||
{{ $t('household_members_editor.hide_household_suggestion') }}
|
||||
</button>
|
||||
<!-- disabled bootstrap behaviour: data-bs-target="#collapse_household_suggestions" aria-controls="collapse_household_suggestions" -->
|
||||
</h2>
|
||||
<div class="accordion-collapse" id="collapse_household_suggestions"
|
||||
aria-labelledby="heading_household_suggestions" data-bs-parent="#householdSuggestions">
|
||||
<div v-if="showHouseholdSuggestion">
|
||||
<div class="flex-table householdSuggestionList">
|
||||
<div v-for="h in filterHouseholdSuggestionByAccompanyingPeriod" class="item-bloc">
|
||||
<household-render-box :household="h"></household-render-box>
|
||||
<ul class="record_actions">
|
||||
<li>
|
||||
<button class="btn btn-sm btn-choose" @click="selectHousehold(h)">
|
||||
{{ $t('household_members_editor.select_household') }}
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
:addressChangedCallback="addressChanged"
|
||||
></add-address>
|
||||
</li>
|
||||
<li v-if="hasHouseholdAddress">
|
||||
<button class="btn btn-remove"
|
||||
@click="removeHouseholdAddress">
|
||||
{{ $t('household_members_editor.household.remove_address') }}
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ul v-if="isModeNewAllowed || isModeLeaveAllowed || getModeSuggestions.length > 0" class="record_actions">
|
||||
<li>
|
||||
<button class="btn btn-sm btn-chill-beige" @click="resetMode">
|
||||
{{ $t('household_members_editor.household.reset_mode') }}
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
@@ -185,35 +140,32 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
addAddress: {
|
||||
context: {
|
||||
target: {
|
||||
name: 'household_create',
|
||||
id: 0
|
||||
},
|
||||
edit: false,
|
||||
addressId: null
|
||||
},
|
||||
key: 'household_new',
|
||||
options: {
|
||||
useDate: {
|
||||
validFrom: true
|
||||
validFrom: false,
|
||||
validTo: false,
|
||||
},
|
||||
onlyButton: true,
|
||||
button: {
|
||||
text: {
|
||||
create: 'household_members_editor.household.or_create_new_address',
|
||||
edit: null,
|
||||
create: 'household_members_editor.household.set_address',
|
||||
edit: 'household_members_editor.household.update_address',
|
||||
}
|
||||
},
|
||||
title: {
|
||||
create: 'household_members_editor.household.create_new_address',
|
||||
edit: null,
|
||||
edit: 'household_members_editor.household.update_address_title',
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'isModeNewAllowed',
|
||||
'isModeLeaveAllowed',
|
||||
'getSuggestions',
|
||||
'hasHousehold',
|
||||
'isHouseholdNew',
|
||||
'hasHouseholdSuggestion',
|
||||
@@ -223,68 +175,38 @@ export default {
|
||||
'countAddressSuggestion',
|
||||
'filterAddressesSuggestion',
|
||||
'hasHouseholdAddress',
|
||||
'isModeLeave',
|
||||
'getAddressContext',
|
||||
]),
|
||||
...mapState([
|
||||
'showHouseholdSuggestion',
|
||||
'showAddressSuggestion'
|
||||
'showAddressSuggestion',
|
||||
'mode',
|
||||
]),
|
||||
household() {
|
||||
return this.$store.state.household;
|
||||
},
|
||||
allowHouseholdCreate() {
|
||||
return this.$store.state.allowHouseholdCreate && !this.$store.getters.hasHousehold;
|
||||
},
|
||||
allowHouseholdSearch() {
|
||||
return false;
|
||||
return this.$store.state.allowHouseholdSearch && !this.$store.getters.hasHousehold;
|
||||
},
|
||||
allowLeaveWithoutHousehold() {
|
||||
return this.$store.state.allowLeaveWithoutHousehold && !this.$store.getters.hasHousehold;
|
||||
},
|
||||
allowRemoveHousehold() {
|
||||
return this.$store.getters.hasHousehold &&
|
||||
(
|
||||
this.allowHouseholdCreate || this.allowHouseholdSearch ||
|
||||
this.allowLeaveWithoutHousehold
|
||||
)
|
||||
;
|
||||
},
|
||||
allowChangeHousehold() {
|
||||
return this.allowHouseholdCreate || this.allowHouseholdSearch ||
|
||||
this.allowLeaveWithoutHousehold;
|
||||
},
|
||||
isForceLeaveWithoutHousehold() {
|
||||
return this.$store.state.forceLeaveWithoutHousehold;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
createHousehold() {
|
||||
setModeNew() {
|
||||
this.$store.dispatch('createHousehold');
|
||||
},
|
||||
forceLeaveWithoutHousehold() {
|
||||
setModeLeave() {
|
||||
this.$store.dispatch('forceLeaveWithoutHousehold');
|
||||
},
|
||||
toggleHouseholdSuggestion() {
|
||||
this.$store.commit('toggleHouseholdSuggestion');
|
||||
resetMode() {
|
||||
this.$store.commit('resetMode');
|
||||
},
|
||||
toggleAddressSuggestion() {
|
||||
this.$store.commit('toggleAddressSuggestion');
|
||||
addressChanged(payload) {
|
||||
console.log("addressChanged", payload);
|
||||
this.$store.dispatch('setHouseholdNewAddress', payload.address);
|
||||
},
|
||||
selectHousehold(h) {
|
||||
this.$store.dispatch('selectHousehold', h);
|
||||
this.toggleHouseholdSuggestion();
|
||||
},
|
||||
removeHousehold() {
|
||||
this.$store.dispatch('removeHousehold');
|
||||
},
|
||||
setHouseholdAddress(a) {
|
||||
let payload = this.$refs.addAddress.submitNewAddress();
|
||||
console.log('setHouseholdAddress', a);
|
||||
this.$store.commit('setHouseholdAddress', a);
|
||||
},
|
||||
setHouseholdCreatedAddress(payload) {
|
||||
console.log('setHouseholdAddress', payload);
|
||||
this.$store.dispatch('setHouseholdNewAddress', payload);
|
||||
},
|
||||
removeHouseholdAddress() {
|
||||
this.$store.commit('removeHouseholdAddress');
|
||||
@@ -310,28 +232,4 @@ div.householdSuggestionList {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
div.householdAddressSuggestionList {
|
||||
display: flex;
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
& > li {}
|
||||
}
|
||||
.householdSuggestionList {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
& > .item {
|
||||
margin-bottom: 0.8rem;
|
||||
width: calc(50% - 1rem);
|
||||
border: 1px solid var(--chill-light-gray);
|
||||
padding: 0.5rem 0.5rem 0 0.5rem;
|
||||
ul.record_actions {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
</style>
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user