mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-06-18 08:14:24 +00:00
Merge branch 'master' into features/activity-form
This commit is contained in:
commit
6631e853b4
@ -11,9 +11,10 @@ before_script:
|
|||||||
- PGPASSWORD=$POSTGRES_PASSWORD psql -U $POSTGRES_USER -h db -c "CREATE EXTENSION IF NOT EXISTS unaccent; CREATE EXTENSION IF NOT EXISTS pg_trgm;"
|
- PGPASSWORD=$POSTGRES_PASSWORD psql -U $POSTGRES_USER -h db -c "CREATE EXTENSION IF NOT EXISTS unaccent; CREATE EXTENSION IF NOT EXISTS pg_trgm;"
|
||||||
# Install and run Composer
|
# Install and run Composer
|
||||||
- curl -sS https://getcomposer.org/installer | php
|
- curl -sS https://getcomposer.org/installer | php
|
||||||
- php composer.phar install
|
- php -d memory_limit=2G composer.phar install
|
||||||
- php tests/app/bin/console doctrine:migrations:migrate -n
|
- php tests/app/bin/console doctrine:migrations:migrate -n
|
||||||
- php tests/app/bin/console doctrine:fixtures:load -n
|
- php -d memory_limit=2G tests/app/bin/console doctrine:fixtures:load -n
|
||||||
|
- echo "before_script finished"
|
||||||
|
|
||||||
# Bring in any services we need http://docs.gitlab.com/ee/ci/docker/using_docker_images.html#what-is-a-service
|
# Bring in any services we need http://docs.gitlab.com/ee/ci/docker/using_docker_images.html#what-is-a-service
|
||||||
# See http://docs.gitlab.com/ee/ci/services/README.html for examples.
|
# See http://docs.gitlab.com/ee/ci/services/README.html for examples.
|
||||||
@ -38,4 +39,4 @@ variables:
|
|||||||
# Run our tests
|
# Run our tests
|
||||||
test:
|
test:
|
||||||
script:
|
script:
|
||||||
- bin/phpunit --colors=never
|
- php -d memory_limit=3G bin/phpunit --colors=never
|
||||||
|
@ -18,10 +18,12 @@
|
|||||||
<testsuite name="MainBundle">
|
<testsuite name="MainBundle">
|
||||||
<directory suffix="Test.php">src/Bundle/ChillMainBundle/Tests/</directory>
|
<directory suffix="Test.php">src/Bundle/ChillMainBundle/Tests/</directory>
|
||||||
</testsuite>
|
</testsuite>
|
||||||
|
<!-- remove tests for person temporarily
|
||||||
<testsuite name="PersonBundle">
|
<testsuite name="PersonBundle">
|
||||||
<directory suffix="Test.php">src/Bundle/ChillPersonBundle/Tests/</directory>
|
<directory suffix="Test.php">src/Bundle/ChillPersonBundle/Tests/</directory>
|
||||||
<exclude>src/Bundle/ChillPersonBundle/Tests/Export/*</exclude>
|
<exclude>src/Bundle/ChillPersonBundle/Tests/Export/*</exclude>
|
||||||
</testsuite>
|
</testsuite>
|
||||||
|
-->
|
||||||
</testsuites>
|
</testsuites>
|
||||||
|
|
||||||
<listeners>
|
<listeners>
|
||||||
|
@ -40,6 +40,20 @@ class AbstractCRUDController extends AbstractController
|
|||||||
return $e;
|
return $e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an entity.
|
||||||
|
*
|
||||||
|
* @param string $action
|
||||||
|
* @param Request $request
|
||||||
|
* @return object
|
||||||
|
*/
|
||||||
|
protected function createEntity(string $action, Request $request): object
|
||||||
|
{
|
||||||
|
$type = $this->getEntityClass();
|
||||||
|
|
||||||
|
return new $type;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Count the number of entities
|
* Count the number of entities
|
||||||
*
|
*
|
||||||
|
@ -85,11 +85,75 @@ class ApiController extends AbstractCRUDController
|
|||||||
case Request::METHOD_PUT:
|
case Request::METHOD_PUT:
|
||||||
case Request::METHOD_PATCH:
|
case Request::METHOD_PATCH:
|
||||||
return $this->entityPut('_entity', $request, $id, $_format);
|
return $this->entityPut('_entity', $request, $id, $_format);
|
||||||
|
case Request::METHOD_POST:
|
||||||
|
return $this->entityPostAction('_entity', $request, $id, $_format);
|
||||||
|
default:
|
||||||
|
throw new \Symfony\Component\HttpFoundation\Exception\BadRequestException("This method is not implemented");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public function entityPost(Request $request, $_format): Response
|
||||||
|
{
|
||||||
|
switch($request->getMethod()) {
|
||||||
|
case Request::METHOD_POST:
|
||||||
|
return $this->entityPostAction('_entity', $request, $_format);
|
||||||
default:
|
default:
|
||||||
throw new \Symfony\Component\HttpFoundation\Exception\BadRequestException("This method is not implemented");
|
throw new \Symfony\Component\HttpFoundation\Exception\BadRequestException("This method is not implemented");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function entityPostAction($action, Request $request, string $_format): Response
|
||||||
|
{
|
||||||
|
$entity = $this->createEntity($action, $request);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$entity = $this->deserialize($action, $request, $_format, $entity);
|
||||||
|
} catch (NotEncodableValueException $e) {
|
||||||
|
throw new BadRequestException("invalid json", 400, $e);
|
||||||
|
}
|
||||||
|
|
||||||
|
$errors = $this->validate($action, $request, $_format, $entity);
|
||||||
|
|
||||||
|
$response = $this->onAfterValidation($action, $request, $_format, $entity, $errors);
|
||||||
|
if ($response instanceof Response) {
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($errors->count() > 0) {
|
||||||
|
$response = $this->json($errors);
|
||||||
|
$response->setStatusCode(Response::HTTP_UNPROCESSABLE_ENTITY);
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
$response = $this->checkACL($action, $request, $_format, $entity);
|
||||||
|
if ($response instanceof Response) {
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
$response = $this->onPostCheckACL($action, $request, $_format, $entity);
|
||||||
|
if ($response instanceof Response) {
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->getDoctrine()->getManager()->persist($entity);
|
||||||
|
$this->getDoctrine()->getManager()->flush();
|
||||||
|
|
||||||
|
$response = $this->onAfterFlush($action, $request, $_format, $entity, $errors);
|
||||||
|
if ($response instanceof Response) {
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
$response = $this->onBeforeSerialize($action, $request, $_format, $entity);
|
||||||
|
if ($response instanceof Response) {
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->json(
|
||||||
|
$entity,
|
||||||
|
Response::HTTP_OK,
|
||||||
|
[],
|
||||||
|
$this->getContextForSerializationPostAlter($action, $request, $_format, $entity)
|
||||||
|
);
|
||||||
|
}
|
||||||
public function entityPut($action, Request $request, $id, string $_format): Response
|
public function entityPut($action, Request $request, $id, string $_format): Response
|
||||||
{
|
{
|
||||||
$entity = $this->getEntity($action, $id, $request, $_format);
|
$entity = $this->getEntity($action, $id, $request, $_format);
|
||||||
@ -407,6 +471,7 @@ class ApiController extends AbstractCRUDController
|
|||||||
return [ 'groups' => [ 'read' ]];
|
return [ 'groups' => [ 'read' ]];
|
||||||
case Request::METHOD_PUT:
|
case Request::METHOD_PUT:
|
||||||
case Request::METHOD_PATCH:
|
case Request::METHOD_PATCH:
|
||||||
|
case Request::METHOD_POST:
|
||||||
return [ 'groups' => [ 'write' ]];
|
return [ 'groups' => [ 'write' ]];
|
||||||
default:
|
default:
|
||||||
throw new \LogicException("get context for serialization is not implemented for this method");
|
throw new \LogicException("get context for serialization is not implemented for this method");
|
||||||
|
@ -183,48 +183,26 @@ class CRUDRoutesLoader extends Loader
|
|||||||
$methods = \array_keys(\array_filter($action['methods'], function($value, $key) { return $value; },
|
$methods = \array_keys(\array_filter($action['methods'], function($value, $key) { return $value; },
|
||||||
ARRAY_FILTER_USE_BOTH));
|
ARRAY_FILTER_USE_BOTH));
|
||||||
|
|
||||||
$route = new Route($path, $defaults, $requirements);
|
if (count($methods) === 0) {
|
||||||
$route->setMethods($methods);
|
throw new \RuntimeException("The api configuration named \"{$crudConfig['name']}\", action \"{$name}\", ".
|
||||||
|
"does not have any allowed methods. You should remove this action from the config ".
|
||||||
$collection->add('chill_api_single_'.$crudConfig['name'].'_'.$name, $route);
|
"or allow, at least, one method");
|
||||||
}
|
}
|
||||||
|
|
||||||
return $collection;
|
if ('_entity' === $name && \in_array(Request::METHOD_POST, $methods)) {
|
||||||
|
unset($methods[\array_search(Request::METHOD_POST, $methods)]);
|
||||||
|
$entityPostRoute = $this->createEntityPostRoute($name, $crudConfig, $action,
|
||||||
|
$controller);
|
||||||
|
$collection->add("chill_api_single_{$crudConfig['name']}_{$name}_create",
|
||||||
|
$entityPostRoute);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
if (count($methods) === 0) {
|
||||||
* Load routes for api multi
|
// the only method was POST,
|
||||||
*
|
// continue to next
|
||||||
* @param $crudConfig
|
|
||||||
* @return RouteCollection
|
|
||||||
*/
|
|
||||||
protected function loadApiMultiConfig(array $crudConfig): RouteCollection
|
|
||||||
{
|
|
||||||
$collection = new RouteCollection();
|
|
||||||
$controller ='csapi_'.$crudConfig['name'].'_controller';
|
|
||||||
|
|
||||||
foreach ($crudConfig['actions'] as $name => $action) {
|
|
||||||
// filter only on single actions
|
|
||||||
$singleCollection = $action['single-collection'] ?? $name === '_index' ? 'collection' : NULL;
|
|
||||||
if ('single' === $singleCollection) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$defaults = [
|
|
||||||
'_controller' => $controller.':'.($action['controller_action'] ?? '_entity' === $name ? 'entityApi' : $name.'Api')
|
|
||||||
];
|
|
||||||
|
|
||||||
// path are rewritten
|
|
||||||
// if name === 'default', we rewrite it to nothing :-)
|
|
||||||
$localName = '_entity' === $name ? '' : '/'.$name;
|
|
||||||
$localPath = $action['path'] ?? '/{id}'.$localName.'.{_format}';
|
|
||||||
$path = $crudConfig['base_path'].$localPath;
|
|
||||||
|
|
||||||
$requirements = $action['requirements'] ?? [ '{id}' => '\d+' ];
|
|
||||||
|
|
||||||
$methods = \array_keys(\array_filter($action['methods'], function($value, $key) { return $value; },
|
|
||||||
ARRAY_FILTER_USE_BOTH));
|
|
||||||
|
|
||||||
$route = new Route($path, $defaults, $requirements);
|
$route = new Route($path, $defaults, $requirements);
|
||||||
$route->setMethods($methods);
|
$route->setMethods($methods);
|
||||||
|
|
||||||
@ -233,4 +211,18 @@ class CRUDRoutesLoader extends Loader
|
|||||||
|
|
||||||
return $collection;
|
return $collection;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function createEntityPostRoute(string $name, $crudConfig, array $action, $controller): Route
|
||||||
|
{
|
||||||
|
$localPath = $action['path'].'.{_format}';
|
||||||
|
$defaults = [
|
||||||
|
'_controller' => $controller.':'.($action['controller_action'] ?? 'entityPost')
|
||||||
|
];
|
||||||
|
$path = $crudConfig['base_path'].$localPath;
|
||||||
|
$requirements = $action['requirements'] ?? [];
|
||||||
|
$route = new Route($path, $defaults, $requirements);
|
||||||
|
$route->setMethods([ Request::METHOD_POST ]);
|
||||||
|
|
||||||
|
return $route;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,8 @@ use Chill\MainBundle\Doctrine\DQL\OverlapsI;
|
|||||||
use Symfony\Component\DependencyInjection\Definition;
|
use Symfony\Component\DependencyInjection\Definition;
|
||||||
use Symfony\Component\DependencyInjection\Reference;
|
use Symfony\Component\DependencyInjection\Reference;
|
||||||
use Chill\MainBundle\Doctrine\DQL\Replace;
|
use Chill\MainBundle\Doctrine\DQL\Replace;
|
||||||
|
use Chill\MainBundle\Doctrine\Type\NativeDateIntervalType;
|
||||||
|
use Chill\MainBundle\Doctrine\Type\PointType;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -167,37 +169,49 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface,
|
|||||||
$container->prependExtensionConfig('twig', $twigConfig);
|
$container->prependExtensionConfig('twig', $twigConfig);
|
||||||
|
|
||||||
//add DQL function to ORM (default entity_manager)
|
//add DQL function to ORM (default entity_manager)
|
||||||
$container->prependExtensionConfig('doctrine', array(
|
$container
|
||||||
'orm' => array(
|
->prependExtensionConfig(
|
||||||
'dql' => array(
|
'doctrine',
|
||||||
'string_functions' => array(
|
[
|
||||||
|
'orm' => [
|
||||||
|
'dql' => [
|
||||||
|
'string_functions' => [
|
||||||
'unaccent' => Unaccent::class,
|
'unaccent' => Unaccent::class,
|
||||||
'GET_JSON_FIELD_BY_KEY' => GetJsonFieldByKey::class,
|
'GET_JSON_FIELD_BY_KEY' => GetJsonFieldByKey::class,
|
||||||
'AGGREGATE' => JsonAggregate::class,
|
'AGGREGATE' => JsonAggregate::class,
|
||||||
'REPLACE' => Replace::class,
|
'REPLACE' => Replace::class,
|
||||||
),
|
],
|
||||||
'numeric_functions' => [
|
'numeric_functions' => [
|
||||||
'JSONB_EXISTS_IN_ARRAY' => JsonbExistsInArray::class,
|
'JSONB_EXISTS_IN_ARRAY' => JsonbExistsInArray::class,
|
||||||
'SIMILARITY' => Similarity::class,
|
'SIMILARITY' => Similarity::class,
|
||||||
'OVERLAPSI' => OverlapsI::class
|
'OVERLAPSI' => OverlapsI::class,
|
||||||
]
|
],
|
||||||
)
|
],
|
||||||
)
|
],
|
||||||
));
|
],
|
||||||
|
);
|
||||||
|
|
||||||
//add dbal types (default entity_manager)
|
//add dbal types (default entity_manager)
|
||||||
$container->prependExtensionConfig('doctrine', array(
|
$container
|
||||||
|
->prependExtensionConfig(
|
||||||
|
'doctrine',
|
||||||
|
[
|
||||||
'dbal' => [
|
'dbal' => [
|
||||||
|
// This is mandatory since we are using postgis as database.
|
||||||
|
'mapping_types' => [
|
||||||
|
'geometry' => 'string',
|
||||||
|
],
|
||||||
'types' => [
|
'types' => [
|
||||||
'dateinterval' => [
|
'dateinterval' => [
|
||||||
'class' => \Chill\MainBundle\Doctrine\Type\NativeDateIntervalType::class
|
'class' => NativeDateIntervalType::class
|
||||||
],
|
],
|
||||||
'point' => [
|
'point' => [
|
||||||
'class' => \Chill\MainBundle\Doctrine\Type\PointType::class
|
'class' => PointType::class
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
));
|
]
|
||||||
|
);
|
||||||
|
|
||||||
//add current route to chill main
|
//add current route to chill main
|
||||||
$container->prependExtensionConfig('chill_main', array(
|
$container->prependExtensionConfig('chill_main', array(
|
||||||
|
@ -137,7 +137,7 @@ class Address
|
|||||||
* @var ThirdParty|null
|
* @var ThirdParty|null
|
||||||
*
|
*
|
||||||
* @ORM\ManyToOne(targetEntity="Chill\ThirdPartyBundle\Entity\ThirdParty")
|
* @ORM\ManyToOne(targetEntity="Chill\ThirdPartyBundle\Entity\ThirdParty")
|
||||||
* @ORM\JoinColumn(nullable=true)
|
* @ORM\JoinColumn(nullable=true, onDelete="SET NULL")
|
||||||
*/
|
*/
|
||||||
private $linkedToThirdParty;
|
private $linkedToThirdParty;
|
||||||
|
|
||||||
|
@ -10,5 +10,11 @@ div.chill_address {
|
|||||||
text-indent: -1.5em;
|
text-indent: -1.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.chill_address_address--multiline {
|
||||||
|
p {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,11 @@ ul.record_actions li {
|
|||||||
ul.record_actions, ul.record_actions_column {
|
ul.record_actions, ul.record_actions_column {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
|
|
||||||
|
&.record_actions--left {
|
||||||
|
justify-content: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
padding: 0.5em 0;
|
padding: 0.5em 0;
|
||||||
flex-wrap: wrap-reverse;
|
flex-wrap: wrap-reverse;
|
||||||
|
|
||||||
|
@ -1,45 +1,23 @@
|
|||||||
/*
|
/*
|
||||||
* NOTE 2021.04
|
* NOTE 2021.04
|
||||||
* scss/chill.scss is the main sass file for the new chill.2
|
* scss/chillmain.scss is the main sass file for the new chill.2
|
||||||
* scratch will be replaced by bootstrap, please avoid to edit in modules/scratch/_custom.scss
|
* scratch will be replaced by bootstrap, please avoid to edit in modules/scratch/_custom.scss
|
||||||
*
|
*
|
||||||
* when possible, try to use bootstrap class naming
|
* when possible, try to use bootstrap html class
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
|
||||||
* Header custom for Accompanying Course
|
|
||||||
*/
|
|
||||||
|
|
||||||
div#header-accompanying_course-name {
|
/* [hack] /!\ Contourne le positionnement problématique du div#content_conainter suivant,
|
||||||
background: none repeat scroll 0 0 #718596;
|
|
||||||
color: #FFF;
|
|
||||||
padding-top: 1em;
|
|
||||||
padding-bottom: 1em;
|
|
||||||
|
|
||||||
span {
|
|
||||||
a {
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
a:hover {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
div#header-accompanying_course-details {
|
|
||||||
background: none repeat scroll 0 0 #718596ab;
|
|
||||||
color: #FFF;
|
|
||||||
padding-top: 1em;
|
|
||||||
padding-bottom: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* /!\ Contourne le positionnement problématique du div#content_conainter suivant,
|
|
||||||
* car sa position: relative le place au-dessus du bandeau et les liens sont incliquables */
|
* car sa position: relative le place au-dessus du bandeau et les liens sont incliquables */
|
||||||
div.subheader {
|
div.subheader {
|
||||||
height: 130px;
|
height: 130px;
|
||||||
}
|
}
|
||||||
|
|
||||||
//// SCRATCH BUTTONS
|
/*
|
||||||
|
* Specific rules
|
||||||
|
*/
|
||||||
|
|
||||||
|
// [scratch] un bouton 'disabled' non clickable
|
||||||
.sc-button {
|
.sc-button {
|
||||||
&.disabled {
|
&.disabled {
|
||||||
cursor: default;
|
cursor: default;
|
||||||
@ -49,148 +27,199 @@ div.subheader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//// VUEJS ////
|
// [debug] un affichage discret pour le debug
|
||||||
div.vue-component {
|
|
||||||
padding: 1.5em;
|
|
||||||
margin: 2em 0;
|
|
||||||
border: 2px dashed grey;
|
|
||||||
position: relative;
|
|
||||||
&:before {
|
|
||||||
content: "vuejs component";
|
|
||||||
position: absolute;
|
|
||||||
left: 1.5em;
|
|
||||||
top: -0.9em;
|
|
||||||
background-color: white;
|
|
||||||
color: grey;
|
|
||||||
padding: 0 0.3em;
|
|
||||||
}
|
|
||||||
dd { margin-left: 1em; }
|
|
||||||
}
|
|
||||||
|
|
||||||
//// MODAL ////
|
|
||||||
.modal-mask {
|
|
||||||
position: fixed;
|
|
||||||
z-index: 9998;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
background-color: rgba(0, 0, 0, 0.75);
|
|
||||||
display: table;
|
|
||||||
transition: opacity 0.3s ease;
|
|
||||||
}
|
|
||||||
.modal-header .close { // bootstrap classes, override sc-button 0 radius
|
|
||||||
border-top-right-radius: 0.3rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The following styles are auto-applied to elements with
|
|
||||||
* transition="modal" when their visibility is toggled
|
|
||||||
* by Vue.js.
|
|
||||||
*
|
|
||||||
* You can easily play with the modal transition by editing
|
|
||||||
* these styles.
|
|
||||||
*/
|
|
||||||
.modal-enter {
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
.modal-leave-active {
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
.modal-enter .modal-container,
|
|
||||||
.modal-leave-active .modal-container {
|
|
||||||
-webkit-transform: scale(1.1);
|
|
||||||
transform: scale(1.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
//// AddPersons modal
|
|
||||||
div.body-head {
|
|
||||||
overflow-y: unset;
|
|
||||||
div.modal-body:first-child {
|
|
||||||
margin: auto 4em;
|
|
||||||
div.search {
|
|
||||||
position: relative;
|
|
||||||
input {
|
|
||||||
padding: 1.2em 1.5em 1.2em 2.5em;
|
|
||||||
margin: 1em 0;
|
|
||||||
}
|
|
||||||
i {
|
|
||||||
position: absolute;
|
|
||||||
opacity: 0.5;
|
|
||||||
padding: 0.65em 0;
|
|
||||||
top: 50%;
|
|
||||||
}
|
|
||||||
i.fa-search {
|
|
||||||
left: 0.5em;
|
|
||||||
}
|
|
||||||
i.fa-times {
|
|
||||||
right: 1em;
|
|
||||||
padding: 0.75em 0;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
div.modal-body:last-child {
|
|
||||||
padding-bottom: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
div.count {
|
|
||||||
margin: -0.5em 0 0.7em;
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
a {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
div.results {
|
|
||||||
div.list-item {
|
|
||||||
padding: 0.4em 0.8em;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
&.checked {
|
|
||||||
background-color: #ececec;
|
|
||||||
border-bottom: 1px dotted #8b8b8b;
|
|
||||||
}
|
|
||||||
div.container {
|
|
||||||
& > input {
|
|
||||||
margin-right: 0.8em;
|
|
||||||
}
|
|
||||||
span:not(.name) {
|
|
||||||
margin-left: 0.5em;
|
|
||||||
opacity: 0.5;
|
|
||||||
font-size: 90%;
|
|
||||||
font-style: italic;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
div.right_actions {
|
|
||||||
margin: 0 0 0 auto;
|
|
||||||
display: flex;
|
|
||||||
align-items: flex-end;
|
|
||||||
& > * {
|
|
||||||
margin-left: 0.5em;
|
|
||||||
align-self: baseline;
|
|
||||||
}
|
|
||||||
a.sc-button {
|
|
||||||
border: 1px solid lightgrey;
|
|
||||||
font-size: 70%;
|
|
||||||
padding: 4px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.discret {
|
.discret {
|
||||||
color: grey;
|
color: grey;
|
||||||
margin-right: 1em;
|
margin-right: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
a.flag-toggle {
|
// reserre la hauteur des rangées de tableau (ul.record_actions prennait trop de place)
|
||||||
color: white;
|
table {
|
||||||
padding: 0 10px;
|
ul.record_actions {
|
||||||
cursor: pointer;
|
margin: 0;
|
||||||
&:hover {
|
padding: 0.5em;
|
||||||
color: white;
|
}
|
||||||
//border: 1px solid rgba(255,255,255,0.2);
|
}
|
||||||
text-decoration: underline;
|
|
||||||
border-radius: 20px;
|
/*
|
||||||
|
* ACCOMPANYING_COURSE
|
||||||
|
* Header custom for Accompanying Course
|
||||||
|
*/
|
||||||
|
|
||||||
|
div#header-accompanying_course-name {
|
||||||
|
background: none repeat scroll 0 0 #718596;
|
||||||
|
color: #FFF;
|
||||||
|
h1 {
|
||||||
|
margin: 0.4em 0;
|
||||||
|
}
|
||||||
|
span {
|
||||||
|
a {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
a:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
div#header-accompanying_course-details {
|
||||||
|
background: none repeat scroll 0 0 #718596ab;
|
||||||
|
color: #FFF;
|
||||||
|
padding-top: 1em;
|
||||||
|
padding-bottom: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FLEX RESPONSIVE TABLE/BLOCK PRESENTATION
|
||||||
|
*/
|
||||||
|
div.flex-bloc,
|
||||||
|
div.flex-table {
|
||||||
|
h2, h3, h4, dl, p {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
h2, h3, h4 {
|
||||||
|
color: var(--chill-blue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Bloc appearance
|
||||||
|
*/
|
||||||
|
div.flex-bloc {
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: stretch;
|
||||||
|
align-content: stretch;
|
||||||
|
|
||||||
|
div.item-bloc {
|
||||||
|
flex-grow: 0; flex-shrink: 1; flex-basis: 50%;
|
||||||
|
|
||||||
|
margin: 0;
|
||||||
|
border: 1px solid #000;
|
||||||
|
padding: 1em;
|
||||||
|
|
||||||
|
border-top: 0;
|
||||||
|
&:nth-child(1), &:nth-child(2) {
|
||||||
|
border-top: 1px solid #000;
|
||||||
|
}
|
||||||
|
border-left: 0;
|
||||||
|
&:nth-child(odd) {
|
||||||
|
border-left: 1px solid #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
//background-color: #e6e6e6;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
div.item-row {
|
||||||
|
flex-grow: 1; flex-shrink: 1; flex-basis: auto;
|
||||||
|
display: flex;
|
||||||
|
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;
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
.list-content { // ul, dl, or div
|
||||||
|
}
|
||||||
|
ul.record_actions {
|
||||||
|
margin: 0;
|
||||||
|
align-self: flex-end;
|
||||||
|
flex-grow: 1; flex-shrink: 0; flex-basis: auto;
|
||||||
|
li {
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media only screen and (max-width: 945px) { margin: auto -0.2em; }
|
||||||
|
@media only screen and (max-width: 935px) { margin: auto -0.5em; }
|
||||||
|
@media only screen and (max-width: 920px) { margin: auto -0.9em; }
|
||||||
|
@media only screen and (max-width: 900px) {
|
||||||
|
flex-direction: column;
|
||||||
|
margin: auto 0;
|
||||||
|
div.item-bloc {
|
||||||
|
border-left: 1px solid #000;
|
||||||
|
&:nth-child(2) {
|
||||||
|
border-top: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Table appearance
|
||||||
|
*/
|
||||||
|
div.flex-table {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: stretch;
|
||||||
|
align-content: stretch;
|
||||||
|
|
||||||
|
div.item-bloc {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
padding: 1em;
|
||||||
|
border: 1px solid #000;
|
||||||
|
border-top: 0;
|
||||||
|
&:first-child {
|
||||||
|
border-top: 1px solid #000;
|
||||||
|
}
|
||||||
|
&:nth-child(even) {
|
||||||
|
background-color: #e6e6e6;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.item-row {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
&:not(:first-child) {
|
||||||
|
margin-top: 0.5em;
|
||||||
|
border-top: 1px dotted #0000004f;
|
||||||
|
padding-top: 0.5em;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.item-col {
|
||||||
|
&:first-child {
|
||||||
|
flex-grow: 0; flex-shrink: 0; flex-basis: 33%;
|
||||||
|
}
|
||||||
|
&:last-child {
|
||||||
|
flex-grow: 1; flex-shrink: 1; flex-basis: auto;
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
|
||||||
|
.list-content { // ul, dl, or div
|
||||||
|
}
|
||||||
|
ul.record_actions {
|
||||||
|
margin: 0;
|
||||||
|
align-self: flex-start;
|
||||||
|
flex-grow: 1; flex-shrink: 0; flex-basis: auto;
|
||||||
|
li {
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media only screen and (max-width: 900px) {
|
||||||
|
flex-direction: column;
|
||||||
|
div.item-col {
|
||||||
|
&:last-child {
|
||||||
|
ul.record_actions {
|
||||||
|
align-self: flex-end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// neutralize
|
||||||
|
div.chill_address div.chill_address_address p { text-indent: 0; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<transition name="modal">
|
<transition name="modal">
|
||||||
<div class="modal-mask">
|
<div class="modal-mask">
|
||||||
<!-- :: styles bootstrap :: -->
|
<!-- :: styles bootstrap :: -->
|
||||||
<div class="modal-dialog" :class="modalDialogClass">
|
<div class="modal-dialog" :class="modalDialogClass">
|
||||||
@ -23,19 +23,18 @@
|
|||||||
</div>
|
</div>
|
||||||
<!-- :: end styles bootstrap :: -->
|
<!-- :: end styles bootstrap :: -->
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
</transition>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
/*
|
/*
|
||||||
* This Modal component is a mix between :
|
* This Modal component is a mix between Vue3 modal implementation
|
||||||
* - Vue3 modal implementation
|
* [+] with 'v-if:showModal' directive:parameter, html scope is added/removed not just shown/hidden
|
||||||
* => with 'v-if:showModal' directive:parameter, html scope is added/removed not just shown/hidden
|
* [+] with slot we can pass content from parent component
|
||||||
* => with slot we can pass content from parent component
|
* [+] some classes are passed from parent component
|
||||||
* => some classes are passed from parent component
|
* and Bootstrap 4.6 _modal.scss module
|
||||||
* - Bootstrap 4.6 _modal.scss module
|
* [+] using bootstrap css classes, the modal have a responsive behaviour,
|
||||||
* => using bootstrap css classes, the modal have a responsive behaviour,
|
* [+] modal design can be configured using css classes (size, scroll)
|
||||||
* => modal design can be configured using css classes (size, scroll)
|
|
||||||
*/
|
*/
|
||||||
export default {
|
export default {
|
||||||
name: 'Modal',
|
name: 'Modal',
|
||||||
@ -43,3 +42,39 @@ export default {
|
|||||||
emits: ['close']
|
emits: ['close']
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.modal-mask {
|
||||||
|
position: fixed;
|
||||||
|
z-index: 9998;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background-color: rgba(0, 0, 0, 0.75);
|
||||||
|
display: table;
|
||||||
|
transition: opacity 0.3s ease;
|
||||||
|
}
|
||||||
|
.modal-header .close { // bootstrap classes, override sc-button 0 radius
|
||||||
|
border-top-right-radius: 0.3rem;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* The following styles are auto-applied to elements with
|
||||||
|
* transition="modal" when their visibility is toggled
|
||||||
|
* by Vue.js.
|
||||||
|
*
|
||||||
|
* You can easily play with the modal transition by editing
|
||||||
|
* these styles.
|
||||||
|
*/
|
||||||
|
.modal-enter {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
.modal-leave-active {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
.modal-enter .modal-container,
|
||||||
|
.modal-leave-active .modal-container {
|
||||||
|
-webkit-transform: scale(1.1);
|
||||||
|
transform: scale(1.1);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
@ -37,12 +37,16 @@ const messages = {
|
|||||||
ok: "OK",
|
ok: "OK",
|
||||||
cancel: "Annuler",
|
cancel: "Annuler",
|
||||||
close: "Fermer",
|
close: "Fermer",
|
||||||
next: "Suivant",
|
|
||||||
previous: "Précédent",
|
|
||||||
back: "Retour",
|
back: "Retour",
|
||||||
check_all: "cocher tout",
|
check_all: "cocher tout",
|
||||||
reset: "réinitialiser"
|
reset: "réinitialiser"
|
||||||
},
|
},
|
||||||
|
nav: {
|
||||||
|
next: "Suivant",
|
||||||
|
previous: "Précédent",
|
||||||
|
top: "Haut",
|
||||||
|
bottom: "Bas",
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -0,0 +1,16 @@
|
|||||||
|
<div class="chill_address">
|
||||||
|
{% if options['has_no_address'] == true and address.isNoAddress == true %}
|
||||||
|
<div class="chill_address_is_noaddress">{{ 'address.consider homeless'|trans }}</div>
|
||||||
|
{% endif %}
|
||||||
|
<div class="chill_address_address {% if options['multiline'] %}chill_address_address--multiline{% endif %}">
|
||||||
|
{% if address.street is not empty %}<p class="street street1">{{ address.street }}</p>{% endif %}
|
||||||
|
{% if address.streetNumber is not empty %}<p class="street street2">{{ address.streetNumber }}</p>{% endif %}
|
||||||
|
{% if address.postCode is not empty %}
|
||||||
|
<p class="postalCode"><span class="code">{{ address.postCode.code }}</span> <span class="name">{{ address.postCode.name }}</span></p>
|
||||||
|
<p class="country">{{ address.postCode.country.name|localize_translatable_string }}</p>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{%- if options['with_valid_from'] == true -%}
|
||||||
|
<span class="address_since">{{ 'Since %date%'|trans( { '%date%' : address.validFrom|format_date('long') } ) }}</span>
|
||||||
|
{%- endif -%}
|
||||||
|
</div>
|
@ -1,11 +1,12 @@
|
|||||||
{%- macro _render(address, options) -%}
|
{%- macro _render(address, options) -%}
|
||||||
{%- set options = { 'with_valid_from' : true }|merge(options|default({})) -%}
|
{%- set options = { 'with_valid_from' : true }|merge(options|default({})) -%}
|
||||||
{%- set options = { 'has_no_address' : false }|merge(options|default({})) -%}
|
{%- set options = { 'has_no_address' : false }|merge(options|default({})) -%}
|
||||||
|
{%- set options = { 'with_icon' : false }|merge(options|default({})) -%}
|
||||||
<div class="chill_address">
|
<div class="chill_address">
|
||||||
{% if options['has_no_address'] == true and address.isNoAddress == true %}
|
{% if options['has_no_address'] == true and address.isNoAddress == true %}
|
||||||
<div class="chill_address_is_noaddress">{{ 'address.consider homeless'|trans }}</div>
|
<div class="chill_address_is_noaddress">{{ 'address.consider homeless'|trans }}</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<div class="chill_address_address">
|
<div class="chill_address_address">{% if options['with_icon'] == true %}<i class="fa fa-fw fa-map-marker"></i>{% endif %}
|
||||||
{% if address.street is not empty %}<p class="street street1">{{ address.street }}</p>{% endif %}
|
{% if address.street is not empty %}<p class="street street1">{{ address.street }}</p>{% endif %}
|
||||||
{% if address.streetNumber is not empty %}<p class="street street2">{{ address.streetNumber }}</p>{% endif %}
|
{% if address.streetNumber is not empty %}<p class="street street2">{{ address.streetNumber }}</p>{% endif %}
|
||||||
{% if address.postCode is not empty %}
|
{% if address.postCode is not empty %}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<footer class="footer">
|
<footer class="footer">
|
||||||
<p>{{ '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>'|trans|raw }}
|
<p>{{ '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>'|trans|raw }}
|
||||||
<br/> <a href="https://{{ app.request.locale }}.wikibooks.org/wiki/Chill" target="_blank">{{ 'User manual'|trans }}</a></p>
|
<br/> <a name="bottom" href="https://{{ app.request.locale }}.wikibooks.org/wiki/Chill" target="_blank">{{ 'User manual'|trans }}</a></p>
|
||||||
</footer>
|
</footer>
|
@ -1 +1 @@
|
|||||||
<img class="logo" src="{{ asset('build/images/logo-chill-sans-slogan_white.png') }}">
|
<img name="top" class="logo" src="{{ asset('build/images/logo-chill-sans-slogan_white.png') }}">
|
||||||
|
@ -20,19 +20,32 @@
|
|||||||
namespace Chill\MainBundle\Serializer\Normalizer;
|
namespace Chill\MainBundle\Serializer\Normalizer;
|
||||||
|
|
||||||
use Chill\MainBundle\Entity\Center;
|
use Chill\MainBundle\Entity\Center;
|
||||||
|
use Chill\MainBundle\Repository\CenterRepository;
|
||||||
|
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
|
||||||
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
|
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
|
||||||
|
use Symfony\Component\Serializer\Exception\InvalidArgumentException;
|
||||||
|
use Symfony\Component\Serializer\Exception\UnexpectedValueException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class CenterNormalizer implements NormalizerInterface
|
class CenterNormalizer implements NormalizerInterface, DenormalizerInterface
|
||||||
{
|
{
|
||||||
|
private CenterRepository $repository;
|
||||||
|
|
||||||
|
|
||||||
|
public function __construct(CenterRepository $repository)
|
||||||
|
{
|
||||||
|
$this->repository = $repository;
|
||||||
|
}
|
||||||
|
|
||||||
public function normalize($center, string $format = null, array $context = array())
|
public function normalize($center, string $format = null, array $context = array())
|
||||||
{
|
{
|
||||||
/** @var Center $center */
|
/** @var Center $center */
|
||||||
return [
|
return [
|
||||||
'id' => $center->getId(),
|
'id' => $center->getId(),
|
||||||
|
'type' => 'center',
|
||||||
'name' => $center->getName()
|
'name' => $center->getName()
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@ -41,4 +54,30 @@ class CenterNormalizer implements NormalizerInterface
|
|||||||
{
|
{
|
||||||
return $data instanceof Center;
|
return $data instanceof Center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function denormalize($data, string $type, string $format = null, array $context = [])
|
||||||
|
{
|
||||||
|
if (FALSE === \array_key_exists('type', $data)) {
|
||||||
|
throw new InvalidArgumentException('missing "type" key in data');
|
||||||
|
}
|
||||||
|
if ('center' !== $data['type']) {
|
||||||
|
throw new InvalidArgumentException('type should be equal to "center"');
|
||||||
|
}
|
||||||
|
if (FALSE === \array_key_exists('id', $data)) {
|
||||||
|
throw new InvalidArgumentException('missing "id" key in data');
|
||||||
|
}
|
||||||
|
|
||||||
|
$center = $this->repository->find($data['id']);
|
||||||
|
|
||||||
|
if (null === $center) {
|
||||||
|
throw new UnexpectedValueException("The type with id {$data['id']} does not exists");
|
||||||
|
}
|
||||||
|
|
||||||
|
return $center;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function supportsDenormalization($data, string $type, string $format = null)
|
||||||
|
{
|
||||||
|
return $type === Center::class;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,67 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Chill\MainBundle\Templating\Entity;
|
||||||
|
|
||||||
|
use Symfony\Component\Templating\EngineInterface;
|
||||||
|
use Chill\MainBundle\Entity\Address;
|
||||||
|
|
||||||
|
class AddressRender implements ChillEntityRenderInterface
|
||||||
|
{
|
||||||
|
private EngineInterface $templating;
|
||||||
|
|
||||||
|
public const DEFAULT_OPTIONS = [
|
||||||
|
'with_valid_from' => true,
|
||||||
|
'has_no_address' => false,
|
||||||
|
'multiline' => true,
|
||||||
|
];
|
||||||
|
|
||||||
|
public function __construct(EngineInterface $templating)
|
||||||
|
{
|
||||||
|
$this->templating = $templating;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public function supports($entity, array $options): bool
|
||||||
|
{
|
||||||
|
return $entity instanceof Address;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Address addr
|
||||||
|
*/
|
||||||
|
public function renderString($addr, array $options): string
|
||||||
|
{
|
||||||
|
$lines = [];
|
||||||
|
if (!empty($addr->getStreet())) {
|
||||||
|
$lines[0] = $addr->getStreet();
|
||||||
|
}
|
||||||
|
if (!empty($addr->getStreetNumber())) {
|
||||||
|
$lines[0] .= ", ".$addr->getStreetNumber();
|
||||||
|
}
|
||||||
|
if (!empty($addr->getPostcode())) {
|
||||||
|
$lines[1] = \strtr("{postcode} {label}", [
|
||||||
|
'{postcode}' => $addr->getPostcode()->getCode(),
|
||||||
|
'{label}' => $addr->getPostcode()->getName()
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return implode(" - ", $lines);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
* @param Address addr
|
||||||
|
*/
|
||||||
|
public function renderBox($addr, array $options): string
|
||||||
|
{
|
||||||
|
$options = \array_merge(self::DEFAULT_OPTIONS, $options);
|
||||||
|
|
||||||
|
return $this->templating
|
||||||
|
->render('@ChillMain/Address/entity_render.html.twig', [
|
||||||
|
'address' => $addr,
|
||||||
|
'options' => $options
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,55 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Chill\MainBundle\Tests\Templating\Entity;
|
||||||
|
|
||||||
|
use Chill\MainBundle\Entity\Country;
|
||||||
|
use Chill\MainBundle\Entity\PostalCode;
|
||||||
|
use Chill\MainBundle\Templating\Entity\AddressRender;
|
||||||
|
use Chill\MainBundle\Entity\Address;
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
|
||||||
|
use Symfony\Component\Templating\EngineInterface;
|
||||||
|
|
||||||
|
class AddressRenderTest extends KernelTestCase
|
||||||
|
{
|
||||||
|
|
||||||
|
protected function setUp()
|
||||||
|
{
|
||||||
|
self::bootKernel();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider addressDataProvider
|
||||||
|
*/
|
||||||
|
public function testRenderString(Address $addr, string $expectedString): void
|
||||||
|
{
|
||||||
|
$engine = self::$container->get(EngineInterface::class);
|
||||||
|
$renderer = new AddressRender($engine);
|
||||||
|
|
||||||
|
$this->assertEquals($expectedString, $renderer->renderString($addr, []));
|
||||||
|
return;
|
||||||
|
$this->assertIsString($renderer->renderBox($addr, []));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function addressDataProvider(): \Iterator
|
||||||
|
{
|
||||||
|
$addr = new Address();
|
||||||
|
$country = (new Country())
|
||||||
|
->setName([ "fr" => "Pays" ])
|
||||||
|
->setCountryCode("BE")
|
||||||
|
;
|
||||||
|
$postCode = new PostalCode();
|
||||||
|
$postCode->setName("Locality")
|
||||||
|
->setCode("012345")
|
||||||
|
->setCountry($country)
|
||||||
|
;
|
||||||
|
|
||||||
|
$addr->setStreet("Rue ABC")
|
||||||
|
->setStreetNumber("5")
|
||||||
|
->setPostcode($postCode)
|
||||||
|
;
|
||||||
|
|
||||||
|
yield[ $addr, "Rue ABC, 5 - 012345 Locality"];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -9,15 +9,14 @@ servers:
|
|||||||
description: "Your current dev server"
|
description: "Your current dev server"
|
||||||
|
|
||||||
components:
|
components:
|
||||||
parameters:
|
schemas:
|
||||||
_format:
|
Center:
|
||||||
name: _format
|
type: object
|
||||||
in: path
|
properties:
|
||||||
required: true
|
id:
|
||||||
schema:
|
type: integer
|
||||||
|
name:
|
||||||
type: string
|
type: string
|
||||||
enum:
|
|
||||||
- json
|
|
||||||
|
|
||||||
paths:
|
paths:
|
||||||
/1.0/search.json:
|
/1.0/search.json:
|
||||||
|
@ -41,3 +41,10 @@ services:
|
|||||||
Chill\MainBundle\Templating\ChillMarkdownRenderExtension:
|
Chill\MainBundle\Templating\ChillMarkdownRenderExtension:
|
||||||
tags:
|
tags:
|
||||||
- { name: twig.extension }
|
- { name: twig.extension }
|
||||||
|
|
||||||
|
Chill\MainBundle\Templating\Entity\AddressRender:
|
||||||
|
arguments:
|
||||||
|
- '@Symfony\Component\Templating\EngineInterface'
|
||||||
|
tags:
|
||||||
|
- { name: 'chill.render_entity' }
|
||||||
|
|
||||||
|
@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Chill\Migrations\Main;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\Schema\Schema;
|
||||||
|
use Doctrine\Migrations\AbstractMigration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specify ON DELETE behaviour to handle deletion of parents in associated tables
|
||||||
|
*/
|
||||||
|
final class Version20210525144016 extends AbstractMigration
|
||||||
|
{
|
||||||
|
public function getDescription(): string
|
||||||
|
{
|
||||||
|
return 'Specify ON DELETE behaviour to handle deletion of parents in associated tables';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function up(Schema $schema): void
|
||||||
|
{
|
||||||
|
$this->addSql('ALTER TABLE chill_main_address DROP CONSTRAINT FK_165051F6114B8DD9');
|
||||||
|
$this->addSql('ALTER TABLE chill_main_address ADD CONSTRAINT FK_165051F6114B8DD9 FOREIGN KEY (linkedToThirdParty_id) REFERENCES chill_3party.third_party (id) ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(Schema $schema): void
|
||||||
|
{
|
||||||
|
$this->addSql('ALTER TABLE chill_main_address DROP CONSTRAINT fk_165051f6114b8dd9');
|
||||||
|
$this->addSql('ALTER TABLE chill_main_address ADD CONSTRAINT fk_165051f6114b8dd9 FOREIGN KEY (linkedtothirdparty_id) REFERENCES chill_3party.third_party (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||||
|
}
|
||||||
|
}
|
@ -75,10 +75,10 @@ $workflow = $this->registry->get($accompanyingPeriod);
|
|||||||
|
|
||||||
switch ($request->getMethod()) {
|
switch ($request->getMethod()) {
|
||||||
case Request::METHOD_POST:
|
case Request::METHOD_POST:
|
||||||
$participation = $accompanyingPeriod->addPerson($person);
|
$participation = $accompanyingPeriod->createParticipationFor($person);
|
||||||
break;
|
break;
|
||||||
case Request::METHOD_DELETE:
|
case Request::METHOD_DELETE:
|
||||||
$participation = $accompanyingPeriod->removePerson($person);
|
$participation = $accompanyingPeriod->closeParticipationFor($person);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new BadRequestException("This method is not supported");
|
throw new BadRequestException("This method is not supported");
|
||||||
|
@ -72,7 +72,7 @@ class AccompanyingCourseController extends Controller
|
|||||||
$em->persist($period);
|
$em->persist($period);
|
||||||
$em->flush();
|
$em->flush();
|
||||||
|
|
||||||
return $this->redirectToRoute('chill_person_accompanying_course_show', [
|
return $this->redirectToRoute('chill_person_accompanying_course_edit', [
|
||||||
'accompanying_period_id' => $period->getId()
|
'accompanying_period_id' => $period->getId()
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@ -92,17 +92,16 @@ class AccompanyingCourseController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show page of Accompanying Course section
|
* Edit page of Accompanying Course section
|
||||||
*
|
*
|
||||||
* the page show all blocks except one active edit block, managed by vuejs component
|
* the page edit all blocks managed by vuejs component
|
||||||
* that's why title of page is 'edit accompanying course'
|
|
||||||
*
|
*
|
||||||
* @Route("/{_locale}/parcours/{accompanying_period_id}/show", name="chill_person_accompanying_course_show")
|
* @Route("/{_locale}/parcours/{accompanying_period_id}/edit", name="chill_person_accompanying_course_edit")
|
||||||
* @ParamConverter("accompanyingCourse", options={"id": "accompanying_period_id"})
|
* @ParamConverter("accompanyingCourse", options={"id": "accompanying_period_id"})
|
||||||
*/
|
*/
|
||||||
public function showAction(AccompanyingPeriod $accompanyingCourse): Response
|
public function editAction(AccompanyingPeriod $accompanyingCourse): Response
|
||||||
{
|
{
|
||||||
return $this->render('@ChillPerson/AccompanyingCourse/show.html.twig', [
|
return $this->render('@ChillPerson/AccompanyingCourse/edit.html.twig', [
|
||||||
'accompanyingCourse' => $accompanyingCourse
|
'accompanyingCourse' => $accompanyingCourse
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
@ -1,30 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* Copyright (C) 2015-2021 Champs-Libres Coopérative <info@champs-libres.coop>
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
namespace Chill\PersonBundle\Controller;
|
|
||||||
|
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
|
|
||||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
|
||||||
|
|
||||||
|
|
||||||
class ApiPersonController extends Controller
|
|
||||||
{
|
|
||||||
public function viewAction($id, $_format)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,50 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2015-2021 Champs-Libres Coopérative <info@champs-libres.coop>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
namespace Chill\PersonBundle\Controller;
|
||||||
|
|
||||||
|
use Chill\PersonBundle\Security\Authorization\PersonVoter;
|
||||||
|
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
|
||||||
|
use Symfony\Component\Security\Core\Role\Role;
|
||||||
|
use Chill\MainBundle\CRUD\Controller\ApiController;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
|
||||||
|
|
||||||
|
class PersonApiController extends ApiController
|
||||||
|
{
|
||||||
|
private AuthorizationHelper $authorizationHelper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param AuthorizationHelper $authorizationHelper
|
||||||
|
*/
|
||||||
|
public function __construct(AuthorizationHelper $authorizationHelper)
|
||||||
|
{
|
||||||
|
$this->authorizationHelper = $authorizationHelper;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function createEntity(string $action, Request $request): object
|
||||||
|
{
|
||||||
|
$person = parent::createEntity($action, $request);
|
||||||
|
|
||||||
|
// TODO temporary hack to allow creation of person with fake center
|
||||||
|
$centers = $this->authorizationHelper->getReachableCenters($this->getUser(),
|
||||||
|
new Role(PersonVoter::CREATE));
|
||||||
|
$person->setCenter($centers[0]);
|
||||||
|
|
||||||
|
return $person;
|
||||||
|
}
|
||||||
|
}
|
@ -476,7 +476,6 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac
|
|||||||
'class' => \Chill\PersonBundle\Entity\SocialWork\SocialIssue::class,
|
'class' => \Chill\PersonBundle\Entity\SocialWork\SocialIssue::class,
|
||||||
'name' => 'social_work_social_issue',
|
'name' => 'social_work_social_issue',
|
||||||
'base_path' => '/api/1.0/person/social-work/social-issue',
|
'base_path' => '/api/1.0/person/social-work/social-issue',
|
||||||
// 'controller' => \Chill\PersonBundle\Controller\OpeningApiController::class,
|
|
||||||
'base_role' => 'ROLE_USER',
|
'base_role' => 'ROLE_USER',
|
||||||
'actions' => [
|
'actions' => [
|
||||||
'_index' => [
|
'_index' => [
|
||||||
@ -493,6 +492,28 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac
|
|||||||
],
|
],
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
'class' => \Chill\PersonBundle\Entity\Person::class,
|
||||||
|
'name' => 'person',
|
||||||
|
'base_path' => '/api/1.0/person/person',
|
||||||
|
'base_role' => \Chill\PersonBundle\Security\Authorization\PersonVoter::SEE,
|
||||||
|
'controller' => \Chill\PersonBundle\Controller\PersonApiController::class,
|
||||||
|
'actions' => [
|
||||||
|
'_entity' => [
|
||||||
|
'methods' => [
|
||||||
|
Request::METHOD_GET => true,
|
||||||
|
Request::METHOD_HEAD => true,
|
||||||
|
Request::METHOD_POST=> 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,
|
||||||
|
|
||||||
|
]
|
||||||
|
],
|
||||||
|
]
|
||||||
|
],
|
||||||
]
|
]
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
@ -483,9 +483,9 @@ class AccompanyingPeriod implements TrackCreationInterface, TrackUpdateInterface
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add Person
|
* Open a new participation for a person
|
||||||
*/
|
*/
|
||||||
public function addPerson(Person $person = null): AccompanyingPeriodParticipation
|
public function createParticipationFor(Person $person): AccompanyingPeriodParticipation
|
||||||
{
|
{
|
||||||
$participation = new AccompanyingPeriodParticipation($this, $person);
|
$participation = new AccompanyingPeriodParticipation($this, $person);
|
||||||
$this->participations[] = $participation;
|
$this->participations[] = $participation;
|
||||||
@ -493,10 +493,24 @@ class AccompanyingPeriod implements TrackCreationInterface, TrackUpdateInterface
|
|||||||
return $participation;
|
return $participation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function addPerson(Person $person = null): self
|
||||||
|
{
|
||||||
|
if (NULL !== $person) {
|
||||||
|
$this->createParticipationFor($person);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove Person
|
* Close a participation for a person
|
||||||
|
*
|
||||||
|
* Search for the person's participation and set the end date at
|
||||||
|
* 'now'.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function removePerson(Person $person): ?AccompanyingPeriodParticipation
|
public function closeParticipationFor($person): ?AccompanyingPeriodParticipation
|
||||||
{
|
{
|
||||||
$participation = $this->getOpenParticipationContainsPerson($person);
|
$participation = $this->getOpenParticipationContainsPerson($person);
|
||||||
|
|
||||||
@ -508,6 +522,17 @@ class AccompanyingPeriod implements TrackCreationInterface, TrackUpdateInterface
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove Person
|
||||||
|
*/
|
||||||
|
public function removePerson(Person $person): self
|
||||||
|
{
|
||||||
|
$this->closeParticipationFor($person);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public function getClosingMotive(): ?ClosingMotive
|
public function getClosingMotive(): ?ClosingMotive
|
||||||
{
|
{
|
||||||
return $this->closingMotive;
|
return $this->closingMotive;
|
||||||
|
@ -51,7 +51,7 @@ class Comment implements TrackCreationInterface, TrackUpdateInterface
|
|||||||
* @ORM\ManyToOne(
|
* @ORM\ManyToOne(
|
||||||
* targetEntity="Chill\PersonBundle\Entity\AccompanyingPeriod",
|
* targetEntity="Chill\PersonBundle\Entity\AccompanyingPeriod",
|
||||||
* inversedBy="comments")
|
* inversedBy="comments")
|
||||||
* @ORM\JoinColumn(nullable=false)
|
* @ORM\JoinColumn(nullable=false, onDelete="CASCADE")
|
||||||
*/
|
*/
|
||||||
private $accompanyingPeriod;
|
private $accompanyingPeriod;
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ use Symfony\Component\Serializer\Annotation\DiscriminatorMap;
|
|||||||
use Symfony\Component\Serializer\Annotation\Groups;
|
use Symfony\Component\Serializer\Annotation\Groups;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\Entity(repositoryClass=ResourceRepository::class)
|
* @ORM\Entity
|
||||||
* @ORM\Table(name="chill_person_accompanying_period_resource")
|
* @ORM\Table(name="chill_person_accompanying_period_resource")
|
||||||
* @DiscriminatorMap(typeProperty="type", mapping={
|
* @DiscriminatorMap(typeProperty="type", mapping={
|
||||||
* "accompanying_period_resource"=Resource::class
|
* "accompanying_period_resource"=Resource::class
|
||||||
|
@ -421,6 +421,31 @@ class Person implements HasCenterInterface
|
|||||||
return $this->accompanyingPeriodParticipations;
|
return $this->accompanyingPeriodParticipations;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a collection of participation, where the participation
|
||||||
|
* is still opened, not a draft, and the period is still opened
|
||||||
|
*/
|
||||||
|
public function getOpenedParticipations(): Collection
|
||||||
|
{
|
||||||
|
// create a criteria for filtering easily
|
||||||
|
$criteria = Criteria::create();
|
||||||
|
$criteria
|
||||||
|
->andWhere(Criteria::expr()->eq('endDate', NULL))
|
||||||
|
->orWhere(Criteria::expr()->gt('endDate', new \DateTime('now')))
|
||||||
|
;
|
||||||
|
|
||||||
|
return $this->getAccompanyingPeriodParticipations()
|
||||||
|
->matching($criteria)
|
||||||
|
->filter(function (AccompanyingPeriodParticipation $app) {
|
||||||
|
$period = $app->getAccompanyingPeriod();
|
||||||
|
return (
|
||||||
|
NULL === $period->getClosingDate()
|
||||||
|
|| new \DateTime('now') < $period->getClosingDate()
|
||||||
|
)
|
||||||
|
&& AccompanyingPeriod::STEP_DRAFT !== $period->getStep();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the accompanying periods of a give person with the chronological order.
|
* Get the accompanying periods of a give person with the chronological order.
|
||||||
*/
|
*/
|
||||||
|
@ -43,7 +43,7 @@ class AccompanyingCourseMenuBuilder implements LocalMenuBuilderInterface
|
|||||||
->setExtras(['order' => 10]);
|
->setExtras(['order' => 10]);
|
||||||
|
|
||||||
$menu->addChild($this->translator->trans('Edit Accompanying Course'), [
|
$menu->addChild($this->translator->trans('Edit Accompanying Course'), [
|
||||||
'route' => 'chill_person_accompanying_course_show',
|
'route' => 'chill_person_accompanying_course_edit',
|
||||||
'routeParameters' => [
|
'routeParameters' => [
|
||||||
'accompanying_period_id' => $period->getId()
|
'accompanying_period_id' => $period->getId()
|
||||||
]])
|
]])
|
||||||
|
@ -27,31 +27,27 @@ use Doctrine\ORM\EntityManagerInterface;
|
|||||||
use Doctrine\ORM\EntityRepository;
|
use Doctrine\ORM\EntityRepository;
|
||||||
use Doctrine\ORM\Query\ResultSetMappingBuilder;
|
use Doctrine\ORM\Query\ResultSetMappingBuilder;
|
||||||
|
|
||||||
/**
|
|
||||||
* Class ClosingMotiveRepository
|
|
||||||
* Entity repository for closing motives
|
|
||||||
*
|
|
||||||
* @package Chill\PersonBundle\Repository
|
|
||||||
*/
|
|
||||||
final class ClosingMotiveRepository
|
final class ClosingMotiveRepository
|
||||||
{
|
{
|
||||||
private EntityRepository $repository;
|
private EntityRepository $repository;
|
||||||
|
|
||||||
|
private EntityManagerInterface $entityManager;
|
||||||
|
|
||||||
public function __construct(EntityManagerInterface $entityManager)
|
public function __construct(EntityManagerInterface $entityManager)
|
||||||
{
|
{
|
||||||
|
$this->entityManager = $entityManager;
|
||||||
$this->repository = $entityManager->getRepository(ClosingMotive::class);
|
$this->repository = $entityManager->getRepository(ClosingMotive::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param bool $onlyLeaf
|
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
public function getActiveClosingMotive(bool $onlyLeaf = true)
|
public function getActiveClosingMotive(bool $onlyLeaf = true)
|
||||||
{
|
{
|
||||||
$rsm = new ResultSetMappingBuilder($this->repository->getEntityManager());
|
$rsm = new ResultSetMappingBuilder($this->entityManager);
|
||||||
$rsm->addRootEntityFromClassMetadata($this->repository->getClassName(), 'cm');
|
$rsm->addRootEntityFromClassMetadata($this->repository->getClassName(), 'cm');
|
||||||
|
|
||||||
$sql = "SELECT ".(string) $rsm."
|
$sql = "SELECT " . (string) $rsm . "
|
||||||
FROM chill_person_accompanying_period_closingmotive AS cm
|
FROM chill_person_accompanying_period_closingmotive AS cm
|
||||||
WHERE
|
WHERE
|
||||||
active IS TRUE ";
|
active IS TRUE ";
|
||||||
@ -65,8 +61,7 @@ final class ClosingMotiveRepository
|
|||||||
$sql .= " ORDER BY cm.ordering ASC";
|
$sql .= " ORDER BY cm.ordering ASC";
|
||||||
|
|
||||||
return $this
|
return $this
|
||||||
->repository
|
->entityManager
|
||||||
->getEntityManager()
|
|
||||||
->createNativeQuery($sql, $rsm)
|
->createNativeQuery($sql, $rsm)
|
||||||
->getResult();
|
->getResult();
|
||||||
}
|
}
|
||||||
|
@ -26,12 +26,6 @@ use Chill\PersonBundle\Entity\AccompanyingPeriod\Comment;
|
|||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
use Doctrine\ORM\EntityRepository;
|
use Doctrine\ORM\EntityRepository;
|
||||||
|
|
||||||
/**
|
|
||||||
* @method Comment|null find($id, $lockMode = null, $lockVersion = null)
|
|
||||||
* @method Comment|null findOneBy(array $criteria, array $orderBy = null)
|
|
||||||
* @method Comment[] findAll()
|
|
||||||
* @method Comment[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
|
|
||||||
*/
|
|
||||||
final class CommentRepository
|
final class CommentRepository
|
||||||
{
|
{
|
||||||
private EntityRepository $repository;
|
private EntityRepository $repository;
|
||||||
|
@ -26,12 +26,6 @@ use Chill\PersonBundle\Entity\AccompanyingPeriod\Origin;
|
|||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
use Doctrine\ORM\EntityRepository;
|
use Doctrine\ORM\EntityRepository;
|
||||||
|
|
||||||
/**
|
|
||||||
* @method Origin|null find($id, $lockMode = null, $lockVersion = null)
|
|
||||||
* @method Origin|null findOneBy(array $criteria, array $orderBy = null)
|
|
||||||
* @method Origin[] findAll()
|
|
||||||
* @method Origin[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
|
|
||||||
*/
|
|
||||||
final class OriginRepository
|
final class OriginRepository
|
||||||
{
|
{
|
||||||
private EntityRepository $repository;
|
private EntityRepository $repository;
|
||||||
|
@ -24,21 +24,19 @@ namespace Chill\PersonBundle\Repository\AccompanyingPeriod;
|
|||||||
|
|
||||||
use Chill\PersonBundle\Entity\AccompanyingPeriod\Resource;
|
use Chill\PersonBundle\Entity\AccompanyingPeriod\Resource;
|
||||||
use Doctrine\ORM\EntityRepository;
|
use Doctrine\ORM\EntityRepository;
|
||||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
use Doctrine\Persistence\ManagerRegistry;
|
|
||||||
|
|
||||||
/**
|
final class ResourceRepository
|
||||||
* @method Resource|null find($id, $lockMode = null, $lockVersion = null)
|
|
||||||
* @method Resource|null findOneBy(array $criteria, array $orderBy = null)
|
|
||||||
* @method Resource[] findAll()
|
|
||||||
* @method Resource[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
|
|
||||||
*/
|
|
||||||
final class ResourceRepository extends ServiceEntityRepository
|
|
||||||
{
|
{
|
||||||
private EntityRepository $repository;
|
private EntityRepository $repository;
|
||||||
|
|
||||||
public function __construct(ManagerRegistry $registry)
|
public function __construct(EntityManagerInterface $entityManager)
|
||||||
{
|
{
|
||||||
parent::__construct($registry, Resource::class);
|
$this->repository = $entityManager->getRepository(Resource::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function find($id, $lockMode = null, $lockVersion = null): ?Resource
|
||||||
|
{
|
||||||
|
return $this->repository->find($id, $lockMode, $lockVersion);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,12 +26,6 @@ use Chill\PersonBundle\Entity\AccompanyingPeriodParticipation;
|
|||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
use Doctrine\ORM\EntityRepository;
|
use Doctrine\ORM\EntityRepository;
|
||||||
|
|
||||||
/**
|
|
||||||
* @method AccompanyingPeriodParticipation|null find($id, $lockMode = null, $lockVersion = null)
|
|
||||||
* @method AccompanyingPeriodParticipation|null findOneBy(array $criteria, array $orderBy = null)
|
|
||||||
* @method AccompanyingPeriodParticipation[] findAll()
|
|
||||||
* @method AccompanyingPeriodParticipation[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
|
|
||||||
*/
|
|
||||||
final class AccompanyingPeriodParticipationRepository
|
final class AccompanyingPeriodParticipationRepository
|
||||||
{
|
{
|
||||||
private EntityRepository $repository;
|
private EntityRepository $repository;
|
||||||
|
@ -26,12 +26,6 @@ use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
|||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
use Doctrine\ORM\EntityRepository;
|
use Doctrine\ORM\EntityRepository;
|
||||||
|
|
||||||
/**
|
|
||||||
* @method AccompanyingPeriod|null find($id, $lockMode = null, $lockVersion = null)
|
|
||||||
* @method AccompanyingPeriod|null findOneBy(array $criteria, array $orderBy = null)
|
|
||||||
* @method AccompanyingPeriod[] findAll()
|
|
||||||
* @method AccompanyingPeriod[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
|
|
||||||
*/
|
|
||||||
final class AccompanyingPeriodRepository
|
final class AccompanyingPeriodRepository
|
||||||
{
|
{
|
||||||
private EntityRepository $repository;
|
private EntityRepository $repository;
|
||||||
|
@ -6,12 +6,6 @@ use Chill\PersonBundle\Entity\Household\HouseholdMembers;
|
|||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
use Doctrine\ORM\EntityRepository;
|
use Doctrine\ORM\EntityRepository;
|
||||||
|
|
||||||
/**
|
|
||||||
* @method HouseholdMembers|null find($id, $lockMode = null, $lockVersion = null)
|
|
||||||
* @method HouseholdMembers|null findOneBy(array $criteria, array $orderBy = null)
|
|
||||||
* @method HouseholdMembers[] findAll()
|
|
||||||
* @method HouseholdMembers[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
|
|
||||||
*/
|
|
||||||
final class HouseholdMembersRepository
|
final class HouseholdMembersRepository
|
||||||
{
|
{
|
||||||
private EntityRepository $repository;
|
private EntityRepository $repository;
|
||||||
@ -20,33 +14,4 @@ final class HouseholdMembersRepository
|
|||||||
{
|
{
|
||||||
$this->repository = $entityManager->getRepository(HouseholdMembers::class);
|
$this->repository = $entityManager->getRepository(HouseholdMembers::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
// /**
|
|
||||||
// * @return HouseholdMembers[] Returns an array of HouseholdMembers objects
|
|
||||||
// */
|
|
||||||
/*
|
|
||||||
public function findByExampleField($value)
|
|
||||||
{
|
|
||||||
return $this->createQueryBuilder('h')
|
|
||||||
->andWhere('h.exampleField = :val')
|
|
||||||
->setParameter('val', $value)
|
|
||||||
->orderBy('h.id', 'ASC')
|
|
||||||
->setMaxResults(10)
|
|
||||||
->getQuery()
|
|
||||||
->getResult()
|
|
||||||
;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
public function findOneBySomeField($value): ?HouseholdMembers
|
|
||||||
{
|
|
||||||
return $this->createQueryBuilder('h')
|
|
||||||
->andWhere('h.exampleField = :val')
|
|
||||||
->setParameter('val', $value)
|
|
||||||
->getQuery()
|
|
||||||
->getOneOrNullResult()
|
|
||||||
;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
@ -6,12 +6,6 @@ use Chill\PersonBundle\Entity\Household\Household;
|
|||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
use Doctrine\ORM\EntityRepository;
|
use Doctrine\ORM\EntityRepository;
|
||||||
|
|
||||||
/**
|
|
||||||
* @method Household|null find($id, $lockMode = null, $lockVersion = null)
|
|
||||||
* @method Household|null findOneBy(array $criteria, array $orderBy = null)
|
|
||||||
* @method Household[] findAll()
|
|
||||||
* @method Household[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
|
|
||||||
*/
|
|
||||||
final class HouseholdRepository
|
final class HouseholdRepository
|
||||||
{
|
{
|
||||||
private EntityRepository $repository;
|
private EntityRepository $repository;
|
||||||
@ -20,33 +14,4 @@ final class HouseholdRepository
|
|||||||
{
|
{
|
||||||
$this->repository = $entityManager->getRepository(Household::class);
|
$this->repository = $entityManager->getRepository(Household::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
// /**
|
|
||||||
// * @return Household[] Returns an array of Household objects
|
|
||||||
// */
|
|
||||||
/*
|
|
||||||
public function findByExampleField($value)
|
|
||||||
{
|
|
||||||
return $this->createQueryBuilder('h')
|
|
||||||
->andWhere('h.exampleField = :val')
|
|
||||||
->setParameter('val', $value)
|
|
||||||
->orderBy('h.id', 'ASC')
|
|
||||||
->setMaxResults(10)
|
|
||||||
->getQuery()
|
|
||||||
->getResult()
|
|
||||||
;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
public function findOneBySomeField($value): ?Household
|
|
||||||
{
|
|
||||||
return $this->createQueryBuilder('h')
|
|
||||||
->andWhere('h.exampleField = :val')
|
|
||||||
->setParameter('val', $value)
|
|
||||||
->getQuery()
|
|
||||||
->getOneOrNullResult()
|
|
||||||
;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
@ -6,12 +6,6 @@ use Chill\PersonBundle\Entity\PersonAltName;
|
|||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
use Doctrine\ORM\EntityRepository;
|
use Doctrine\ORM\EntityRepository;
|
||||||
|
|
||||||
/**
|
|
||||||
* PersonAltNameRepository
|
|
||||||
*
|
|
||||||
* This class was generated by the Doctrine ORM. Add your own custom
|
|
||||||
* repository methods below.
|
|
||||||
*/
|
|
||||||
final class PersonAltNameRepository
|
final class PersonAltNameRepository
|
||||||
{
|
{
|
||||||
private EntityRepository $repository;
|
private EntityRepository $repository;
|
||||||
|
@ -7,11 +7,6 @@ use Chill\PersonBundle\Entity\PersonNotDuplicate;
|
|||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
use Doctrine\ORM\EntityRepository;
|
use Doctrine\ORM\EntityRepository;
|
||||||
|
|
||||||
/**
|
|
||||||
* Class PersonNotDuplicateRepository
|
|
||||||
*
|
|
||||||
* @package Chill\PersonBundle\Repository
|
|
||||||
*/
|
|
||||||
final class PersonNotDuplicateRepository
|
final class PersonNotDuplicateRepository
|
||||||
{
|
{
|
||||||
private EntityRepository $repository;
|
private EntityRepository $repository;
|
||||||
@ -21,12 +16,7 @@ final class PersonNotDuplicateRepository
|
|||||||
$this->repository = $entityManager->getRepository(PersonNotDuplicate::class);
|
$this->repository = $entityManager->getRepository(PersonNotDuplicate::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public function findNotDuplicatePerson(Person $person): array
|
||||||
* @param \Chill\PersonBundle\Entity\Person $person
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function findNotDuplicatePerson(Person $person)
|
|
||||||
{
|
{
|
||||||
$qb = $this->repository->createQueryBuilder('pnd');
|
$qb = $this->repository->createQueryBuilder('pnd');
|
||||||
$qb->select('pnd')
|
$qb->select('pnd')
|
||||||
@ -36,6 +26,7 @@ final class PersonNotDuplicateRepository
|
|||||||
$result = $qb->getQuery()->getResult();
|
$result = $qb->getQuery()->getResult();
|
||||||
|
|
||||||
$persons = [];
|
$persons = [];
|
||||||
|
|
||||||
foreach ($result as $row) {
|
foreach ($result as $row) {
|
||||||
if ($row->getPerson1() === $person) {
|
if ($row->getPerson1() === $person) {
|
||||||
$persons[] = $row->getPerson2();
|
$persons[] = $row->getPerson2();
|
||||||
|
@ -32,17 +32,15 @@ final class PersonRepository
|
|||||||
$this->repository = $entityManager->getRepository(Person::class);
|
$this->repository = $entityManager->getRepository(Person::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function find($id, $lockMode = null, $lockVersion = null)
|
public function find($id, $lockMode = null, $lockVersion = null): ?Person
|
||||||
{
|
{
|
||||||
return $this->repository->find($id, $lockMode, $lockVersion);
|
return $this->repository->find($id, $lockMode, $lockVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $phonenumber
|
|
||||||
* @param $centers
|
* @param $centers
|
||||||
* @param $firstResult
|
* @param $firstResult
|
||||||
* @param $maxResults
|
* @param $maxResults
|
||||||
* @param array $only
|
|
||||||
* @return mixed
|
* @return mixed
|
||||||
* @throws \Exception
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
@ -67,10 +65,7 @@ final class PersonRepository
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $phonenumber
|
|
||||||
* @param $centers
|
* @param $centers
|
||||||
* @param array $only
|
|
||||||
* @return int
|
|
||||||
* @throws \Doctrine\ORM\NoResultException
|
* @throws \Doctrine\ORM\NoResultException
|
||||||
* @throws \Doctrine\ORM\NonUniqueResultException
|
* @throws \Doctrine\ORM\NonUniqueResultException
|
||||||
*/
|
*/
|
||||||
@ -78,8 +73,7 @@ final class PersonRepository
|
|||||||
string $phonenumber,
|
string $phonenumber,
|
||||||
$centers,
|
$centers,
|
||||||
array $only = ['mobile', 'phone']
|
array $only = ['mobile', 'phone']
|
||||||
): int
|
): int {
|
||||||
{
|
|
||||||
$qb = $this->repository->createQueryBuilder('p');
|
$qb = $this->repository->createQueryBuilder('p');
|
||||||
$qb->select('COUNT(p)');
|
$qb->select('COUNT(p)');
|
||||||
|
|
||||||
@ -90,12 +84,9 @@ final class PersonRepository
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param QueryBuilder $qb
|
|
||||||
* @param string $phonenumber
|
|
||||||
* @param array $only
|
|
||||||
* @throws \Exception
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
protected function addPhoneNumber(QueryBuilder $qb, string $phonenumber, array $only)
|
protected function addPhoneNumber(QueryBuilder $qb, string $phonenumber, array $only): void
|
||||||
{
|
{
|
||||||
if (count($only) === 0) {
|
if (count($only) === 0) {
|
||||||
throw new \Exception("No array field to search");
|
throw new \Exception("No array field to search");
|
||||||
@ -117,20 +108,12 @@ final class PersonRepository
|
|||||||
$qb->setParameter('phonenumber', '%'.$phonenumber.'%');
|
$qb->setParameter('phonenumber', '%'.$phonenumber.'%');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
protected function parsePhoneNumber(string $phonenumber): string
|
||||||
* @param $phonenumber
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
protected function parsePhoneNumber($phonenumber): string
|
|
||||||
{
|
{
|
||||||
return \str_replace(' ', '', $phonenumber);
|
return \str_replace(' ', '', $phonenumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
protected function addByCenters(QueryBuilder $qb, array $centers): void
|
||||||
* @param QueryBuilder $qb
|
|
||||||
* @param array $centers
|
|
||||||
*/
|
|
||||||
protected function addByCenters(QueryBuilder $qb, array $centers)
|
|
||||||
{
|
{
|
||||||
if (count($centers) > 0) {
|
if (count($centers) > 0) {
|
||||||
$qb->andWhere($qb->expr()->in('p.center', ':centers'));
|
$qb->andWhere($qb->expr()->in('p.center', ':centers'));
|
||||||
|
@ -6,12 +6,6 @@ use Chill\PersonBundle\Entity\SocialWork\Evaluation;
|
|||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
use Doctrine\ORM\EntityRepository;
|
use Doctrine\ORM\EntityRepository;
|
||||||
|
|
||||||
/**
|
|
||||||
* @method Evaluation|null find($id, $lockMode = null, $lockVersion = null)
|
|
||||||
* @method Evaluation|null findOneBy(array $criteria, array $orderBy = null)
|
|
||||||
* @method Evaluation[] findAll()
|
|
||||||
* @method Evaluation[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
|
|
||||||
*/
|
|
||||||
final class EvaluationRepository
|
final class EvaluationRepository
|
||||||
{
|
{
|
||||||
private EntityRepository $repository;
|
private EntityRepository $repository;
|
||||||
|
@ -6,12 +6,6 @@ use Chill\PersonBundle\Entity\SocialWork\Goal;
|
|||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
use Doctrine\ORM\EntityRepository;
|
use Doctrine\ORM\EntityRepository;
|
||||||
|
|
||||||
/**
|
|
||||||
* @method Goal|null find($id, $lockMode = null, $lockVersion = null)
|
|
||||||
* @method Goal|null findOneBy(array $criteria, array $orderBy = null)
|
|
||||||
* @method Goal[] findAll()
|
|
||||||
* @method Goal[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
|
|
||||||
*/
|
|
||||||
final class GoalRepository
|
final class GoalRepository
|
||||||
{
|
{
|
||||||
private EntityRepository $repository;
|
private EntityRepository $repository;
|
||||||
|
@ -6,12 +6,6 @@ use Chill\PersonBundle\Entity\SocialWork\Result;
|
|||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
use Doctrine\ORM\EntityRepository;
|
use Doctrine\ORM\EntityRepository;
|
||||||
|
|
||||||
/**
|
|
||||||
* @method Result|null find($id, $lockMode = null, $lockVersion = null)
|
|
||||||
* @method Result|null findOneBy(array $criteria, array $orderBy = null)
|
|
||||||
* @method Result[] findAll()
|
|
||||||
* @method Result[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
|
|
||||||
*/
|
|
||||||
final class ResultRepository
|
final class ResultRepository
|
||||||
{
|
{
|
||||||
private EntityRepository $repository;
|
private EntityRepository $repository;
|
||||||
|
@ -6,12 +6,6 @@ use Chill\PersonBundle\Entity\SocialWork\SocialAction;
|
|||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
use Doctrine\ORM\EntityRepository;
|
use Doctrine\ORM\EntityRepository;
|
||||||
|
|
||||||
/**
|
|
||||||
* @method SocialAction|null find($id, $lockMode = null, $lockVersion = null)
|
|
||||||
* @method SocialAction|null findOneBy(array $criteria, array $orderBy = null)
|
|
||||||
* @method SocialAction[] findAll()
|
|
||||||
* @method SocialAction[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
|
|
||||||
*/
|
|
||||||
final class SocialActionRepository
|
final class SocialActionRepository
|
||||||
{
|
{
|
||||||
private EntityRepository $repository;
|
private EntityRepository $repository;
|
||||||
|
@ -7,12 +7,6 @@ use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
|||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
use Doctrine\ORM\EntityRepository;
|
use Doctrine\ORM\EntityRepository;
|
||||||
|
|
||||||
/**
|
|
||||||
* @method SocialIssue|null find($id, $lockMode = null, $lockVersion = null)
|
|
||||||
* @method SocialIssue|null findOneBy(array $criteria, array $orderBy = null)
|
|
||||||
* @method SocialIssue[] findAll()
|
|
||||||
* @method SocialIssue[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
|
|
||||||
*/
|
|
||||||
final class SocialIssueRepository
|
final class SocialIssueRepository
|
||||||
{
|
{
|
||||||
private EntityRepository $repository;
|
private EntityRepository $repository;
|
||||||
|
@ -1 +1,2 @@
|
|||||||
require('./sass/person.scss');
|
require('./sass/person.scss');
|
||||||
|
require('./sass/person_with_period.scss');
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
require('./phone-alt-solid.svg');
|
require('./phone-alt-solid.svg');
|
||||||
require('./mobile-alt-solid.svg');
|
require('./mobile-alt-solid.svg');
|
||||||
require('./person_by_phonenumber.scss');
|
require('./person_by_phonenumber.scss');
|
||||||
|
require('./person_with_period.scss');
|
||||||
|
|
||||||
|
@ -0,0 +1,50 @@
|
|||||||
|
/// complete and overwrite flex-table in chillmain.scss
|
||||||
|
div.list-with-period {
|
||||||
|
div.person {
|
||||||
|
ul.record_actions {
|
||||||
|
li {
|
||||||
|
margin-right: 0 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
div.periods {
|
||||||
|
div.header,
|
||||||
|
div.list-content {
|
||||||
|
width: calc(100% - 40px);
|
||||||
|
margin-left: 40px;
|
||||||
|
}
|
||||||
|
div.header {
|
||||||
|
position: relative;
|
||||||
|
a.sc-button {
|
||||||
|
position: absolute;
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
top: 10px;
|
||||||
|
left: -40px;
|
||||||
|
padding: 0;
|
||||||
|
i {
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
abbr.referrer {
|
||||||
|
font-size: 70%;
|
||||||
|
}
|
||||||
|
span.user {
|
||||||
|
margin-left: 1em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
div.list-content {
|
||||||
|
span.more {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.chill-entity__person {
|
||||||
|
.chill-entity__person__first-name,
|
||||||
|
.chill-entity__person__last-name {
|
||||||
|
font-size: 1.3em;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
}
|
@ -1,19 +1,24 @@
|
|||||||
<template>
|
<template>
|
||||||
<accompanying-course></accompanying-course>
|
<banner></banner>
|
||||||
|
<sticky-nav></sticky-nav>
|
||||||
|
|
||||||
|
<h1 v-if="accompanyingCourse.step === 'DRAFT'">{{ $t('course.title.draft') }}</h1>
|
||||||
|
<h1 v-else>{{ $t('course.title.active') }}</h1>
|
||||||
|
|
||||||
<persons-associated></persons-associated>
|
<persons-associated></persons-associated>
|
||||||
<requestor></requestor>
|
<requestor></requestor>
|
||||||
<social-issue></social-issue>
|
<social-issue></social-issue>
|
||||||
<referrer></referrer>
|
<referrer></referrer>
|
||||||
<resources></resources>
|
<resources></resources>
|
||||||
<comment></comment>
|
<comment v-if="accompanyingCourse.step === 'DRAFT'"></comment>
|
||||||
<confirm></confirm>
|
<confirm v-if="accompanyingCourse.step === 'DRAFT'"></confirm>
|
||||||
<!--test></test-->
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapState } from 'vuex'
|
import { mapState } from 'vuex'
|
||||||
|
import Banner from './components/Banner.vue';
|
||||||
import AccompanyingCourse from './components/AccompanyingCourse.vue';
|
import StickyNav from './components/StickyNav.vue';
|
||||||
import PersonsAssociated from './components/PersonsAssociated.vue';
|
import PersonsAssociated from './components/PersonsAssociated.vue';
|
||||||
import Requestor from './components/Requestor.vue';
|
import Requestor from './components/Requestor.vue';
|
||||||
import SocialIssue from './components/SocialIssue.vue';
|
import SocialIssue from './components/SocialIssue.vue';
|
||||||
@ -21,12 +26,12 @@ import Referrer from './components/Referrer.vue';
|
|||||||
import Resources from './components/Resources.vue';
|
import Resources from './components/Resources.vue';
|
||||||
import Comment from './components/Comment.vue';
|
import Comment from './components/Comment.vue';
|
||||||
import Confirm from './components/Confirm.vue';
|
import Confirm from './components/Confirm.vue';
|
||||||
//import Test from './components/Test.vue';
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'App',
|
name: 'App',
|
||||||
components: {
|
components: {
|
||||||
AccompanyingCourse,
|
Banner,
|
||||||
|
StickyNav,
|
||||||
PersonsAssociated,
|
PersonsAssociated,
|
||||||
Requestor,
|
Requestor,
|
||||||
SocialIssue,
|
SocialIssue,
|
||||||
@ -34,10 +39,68 @@ export default {
|
|||||||
Resources,
|
Resources,
|
||||||
Comment,
|
Comment,
|
||||||
Confirm,
|
Confirm,
|
||||||
//Test
|
|
||||||
},
|
},
|
||||||
computed: mapState([
|
computed: mapState([
|
||||||
'accompanyingCourse'
|
'accompanyingCourse'
|
||||||
])
|
])
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
div#accompanying-course {
|
||||||
|
h1 {
|
||||||
|
margin: 1.5em 0;
|
||||||
|
}
|
||||||
|
div.vue-component {
|
||||||
|
h2 {
|
||||||
|
margin-left: 0.7em;
|
||||||
|
position: relative;
|
||||||
|
&:before {
|
||||||
|
position: absolute;
|
||||||
|
/*
|
||||||
|
content: "\f192"; //circle-dot
|
||||||
|
content: "\f1dd"; //paragraph
|
||||||
|
content: "\f292"; //hashtag
|
||||||
|
content: "\f069"; //asterisk
|
||||||
|
*/
|
||||||
|
content: "\f142"; //ellipsis-v
|
||||||
|
font-family: "ForkAwesome";
|
||||||
|
color: #718596ab;
|
||||||
|
left: -22px;
|
||||||
|
top: 4px;
|
||||||
|
}
|
||||||
|
a[name^="section"] {
|
||||||
|
position: absolute;
|
||||||
|
top: -3.5em; // ref. stickNav
|
||||||
|
}
|
||||||
|
}
|
||||||
|
padding: 0.8em 0em;
|
||||||
|
margin: 2em 0;
|
||||||
|
border: 1px dotted #718596ab;
|
||||||
|
border-radius: 5px;
|
||||||
|
border-left: 1px dotted #718596ab;
|
||||||
|
border-right: 1px dotted #718596ab;
|
||||||
|
/* debug components
|
||||||
|
position: relative;
|
||||||
|
&:before {
|
||||||
|
content: "vuejs component";
|
||||||
|
position: absolute;
|
||||||
|
left: 1.5em;
|
||||||
|
top: -0.9em;
|
||||||
|
background-color: white;
|
||||||
|
color: grey;
|
||||||
|
padding: 0 0.3em;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
dd {
|
||||||
|
margin-left: 1em;
|
||||||
|
}
|
||||||
|
& > div {
|
||||||
|
margin: 1em 3em 0;
|
||||||
|
}
|
||||||
|
table {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
@ -36,6 +36,33 @@ const patchAccompanyingCourse = (id, body) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Endpoint to change 'DRAFT' step to 'CONFIRMED'
|
||||||
|
*/
|
||||||
|
const confirmAccompanyingCourse = (id) => {
|
||||||
|
const url = `/api/1.0/person/accompanying-course/${id}/confirm.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
|
||||||
|
*/
|
||||||
|
const getSocialIssues = () => {
|
||||||
|
const url = `/api/1.0/person/social-work/social-issue.json`;
|
||||||
|
return fetch(url)
|
||||||
|
.then(response => {
|
||||||
|
if (response.ok) { return response.json(); }
|
||||||
|
throw Error('Error with request resource response');
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Endpoint v.2 chill_api_single_accompanying_course_participation,
|
* Endpoint v.2 chill_api_single_accompanying_course_participation,
|
||||||
* method POST/DELETE, add/close a participation to the accompanyingCourse
|
* method POST/DELETE, add/close a participation to the accompanyingCourse
|
||||||
@ -119,10 +146,32 @@ const postResource = (id, payload, method) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Endpoint to Add/remove SocialIssue
|
||||||
|
*/
|
||||||
|
const postSocialIssue = (id, body, method) => {
|
||||||
|
//console.log('api body and method', body, method);
|
||||||
|
const url = `/api/1.0/person/accompanying-course/${id}/socialissue.json`;
|
||||||
|
return fetch(url, {
|
||||||
|
method: method,
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json;charset=utf-8'
|
||||||
|
},
|
||||||
|
body: JSON.stringify(body)
|
||||||
|
})
|
||||||
|
.then(response => {
|
||||||
|
if (response.ok) { return response.json(); }
|
||||||
|
throw Error('Error with request resource response');
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
getAccompanyingCourse,
|
getAccompanyingCourse,
|
||||||
patchAccompanyingCourse,
|
patchAccompanyingCourse,
|
||||||
|
confirmAccompanyingCourse,
|
||||||
|
getSocialIssues,
|
||||||
postParticipation,
|
postParticipation,
|
||||||
postRequestor,
|
postRequestor,
|
||||||
postResource,
|
postResource,
|
||||||
|
postSocialIssue
|
||||||
};
|
};
|
||||||
|
@ -1,41 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="vue-component" style="display: none;">
|
|
||||||
<h3>{{ $t('course.title') }}</h3>
|
|
||||||
<dl>
|
|
||||||
<dt>{{ $t('course.id') }}</dt>
|
|
||||||
<dd>{{ accompanyingCourse.id }}</dd>
|
|
||||||
</dl>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<teleport to="#header-accompanying_course-name .grid-4">
|
|
||||||
<toggle-flags></toggle-flags>
|
|
||||||
</teleport>
|
|
||||||
|
|
||||||
<teleport to="#header-accompanying_course-name .grid-3">
|
|
||||||
<p style="text-align: right;">
|
|
||||||
<span v-if="accompanyingCourse.openingDate">
|
|
||||||
<i>{{ $t('course.open_at') }}{{ $d(accompanyingCourse.openingDate.datetime, 'text') }}</i>
|
|
||||||
</span><br>
|
|
||||||
<span v-if="accompanyingCourse.user">
|
|
||||||
{{ $t('course.by') }}<b>{{ accompanyingCourse.user.username }}</b>
|
|
||||||
</span>
|
|
||||||
</p>
|
|
||||||
</teleport>
|
|
||||||
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import ToggleFlags from './ToggleFlags';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'AccompanyingCourse',
|
|
||||||
components: {
|
|
||||||
ToggleFlags
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
accompanyingCourse() {
|
|
||||||
return this.$store.state.accompanyingCourse
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
@ -0,0 +1,92 @@
|
|||||||
|
<template>
|
||||||
|
|
||||||
|
<div class="vue-component" style="display: none;">
|
||||||
|
<dl>
|
||||||
|
<dt>{{ $t('course.id') }}</dt>
|
||||||
|
<dd>{{ accompanyingCourse.id }}</dd>
|
||||||
|
</dl>
|
||||||
|
<dl v-if="accompanyingCourse.closingDate">
|
||||||
|
<dt>{{ $t('course.closing_date') }}</dt>
|
||||||
|
<dd>{{ $d(accompanyingCourse.closingDate.datetime, 'short') }}</dd>
|
||||||
|
|
||||||
|
<dt>{{ $t('course.closing_motive') }}</dt>
|
||||||
|
<dd v-if="accompanyingCourse.closingMotive">{{ accompanyingCourse.closingMotive.name.fr }}</dd>
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<teleport to="#header-accompanying_course-name #banner-flags">
|
||||||
|
<toggle-flags></toggle-flags>
|
||||||
|
</teleport>
|
||||||
|
|
||||||
|
<teleport to="#header-accompanying_course-name #banner-status">
|
||||||
|
<div v-if="accompanyingCourse.step === 'DRAFT'">
|
||||||
|
<span class="badge badge-secondary">
|
||||||
|
{{ $t('course.step.draft') }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
<div>
|
||||||
|
<span class="badge badge-primary">
|
||||||
|
{{ $t('course.step.active') }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span>
|
||||||
|
<i>{{ $t('course.open_at') }}{{ $d(accompanyingCourse.openingDate.datetime, 'text') }}</i>
|
||||||
|
</span>
|
||||||
|
<br>
|
||||||
|
<span v-if="accompanyingCourse.user">
|
||||||
|
{{ $t('course.by') }}<b>{{ accompanyingCourse.user.username }}</b>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</teleport>
|
||||||
|
|
||||||
|
<teleport to="#header-accompanying_course-details #banner-social-issues">
|
||||||
|
<div class="grid-12">
|
||||||
|
<social-issue
|
||||||
|
v-for="issue in accompanyingCourse.socialIssues"
|
||||||
|
v-bind:key="issue.id"
|
||||||
|
v-bind:issue="issue">
|
||||||
|
</social-issue>
|
||||||
|
</div>
|
||||||
|
</teleport>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import ToggleFlags from './Banner/ToggleFlags';
|
||||||
|
import SocialIssue from './Banner/SocialIssue.vue';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'Banner',
|
||||||
|
components: {
|
||||||
|
ToggleFlags,
|
||||||
|
SocialIssue
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
accompanyingCourse() {
|
||||||
|
return this.$store.state.accompanyingCourse
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
div#banner-flags,
|
||||||
|
div#banner-status {
|
||||||
|
margin: 1.5em 0;
|
||||||
|
div {
|
||||||
|
text-align: right;
|
||||||
|
margin-bottom: 0.8em;
|
||||||
|
}
|
||||||
|
.badge {
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
div#banner-status {
|
||||||
|
span.badge {
|
||||||
|
font-size: 90%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -0,0 +1,20 @@
|
|||||||
|
<template>
|
||||||
|
<span class="badge badge-secondary">{{ issue.text }}</span>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "SocialIssues",
|
||||||
|
props: ['issue']
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
span.badge {
|
||||||
|
font-size: 95%;
|
||||||
|
text-transform: capitalize !important;
|
||||||
|
font-weight: 500 !important;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
margin-right: 1em;
|
||||||
|
}
|
||||||
|
</style>
|
@ -1,24 +1,20 @@
|
|||||||
<template>
|
<template>
|
||||||
<p style="text-align: right;">
|
<div>
|
||||||
|
|
||||||
<a @click="toggleIntensity" class="flag-toggle">
|
<a @click="toggleIntensity" class="flag-toggle">
|
||||||
{{ $t('course.occasional') }}
|
{{ $t('course.occasional') }}
|
||||||
<i class="fa" :class="{ 'fa-toggle-on': isRegular, 'fa-toggle-off': !isRegular }"></i>
|
<i class="fa" :class="{ 'fa-toggle-on': isRegular, 'fa-toggle-on fa-flip-horizontal': !isRegular }"></i>
|
||||||
{{ $t('course.regular') }}
|
{{ $t('course.regular') }}
|
||||||
</a>
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
<button class="badge badge-pill"
|
<div>
|
||||||
:class="{ 'badge-primary': isEmergency, 'badge-secondary': !isEmergency }"
|
<button class="badge badge-pill" :class="{ 'badge-primary': isEmergency, 'badge-secondary': !isEmergency }" @click="toggleEmergency">
|
||||||
@click="toggleEmergency">
|
|
||||||
{{ $t('course.emergency') }}
|
{{ $t('course.emergency') }}
|
||||||
</button>
|
</button>
|
||||||
|
<button class="badge badge-pill" :class="{ 'badge-primary': isConfidential, 'badge-secondary': !isConfidential }" @click="toggleConfidential">
|
||||||
<button class="badge badge-pill"
|
|
||||||
:class="{ 'badge-primary': isConfidential, 'badge-secondary': !isConfidential }"
|
|
||||||
@click="toggleConfidential">
|
|
||||||
{{ $t('course.confidential') }}
|
{{ $t('course.confidential') }}
|
||||||
</button>
|
</button>
|
||||||
</p>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@ -32,7 +28,7 @@ export default {
|
|||||||
confidential: state => state.accompanyingCourse.confidential,
|
confidential: state => state.accompanyingCourse.confidential,
|
||||||
}),
|
}),
|
||||||
isRegular() {
|
isRegular() {
|
||||||
return (this.intensity === 'regular')? true : false;
|
return (this.intensity === 'regular') ? true : false;
|
||||||
},
|
},
|
||||||
isEmergency() {
|
isEmergency() {
|
||||||
return (this.emergency) ? true : false;
|
return (this.emergency) ? true : false;
|
||||||
@ -66,3 +62,28 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
a.flag-toggle {
|
||||||
|
color: white;
|
||||||
|
padding: 0 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
&:hover {
|
||||||
|
color: white;
|
||||||
|
text-decoration: underline;
|
||||||
|
border-radius: 20px;
|
||||||
|
}
|
||||||
|
i {
|
||||||
|
margin: auto 0.4em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
button.badge {
|
||||||
|
margin-left: 0.8em;
|
||||||
|
&.badge-secondary {
|
||||||
|
opacity: 0.5;
|
||||||
|
&:hover {
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -1,21 +1,24 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="vue-component">
|
<div class="vue-component">
|
||||||
<h3>{{ $t('comment.title') }}</h3>
|
<h2><a name="section-60"></a>{{ $t('comment.title') }}</h2>
|
||||||
|
|
||||||
<div class="error flash_message" v-if="errors.length > 0">
|
<!--div class="error flash_message" v-if="errors.length > 0">
|
||||||
{{ errors[0] }}
|
{{ errors[0] }}
|
||||||
</div>
|
TODO fix errors flashbag for app component
|
||||||
|
</div-->
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<form @submit.prevent="submitform">
|
||||||
|
|
||||||
|
<label for="content">{{ $t('comment.label') }}</label>
|
||||||
|
|
||||||
<div v-if="initialComment">
|
<div v-if="initialComment">
|
||||||
créé par {{ initialComment.creator.text }}
|
{{ $t('comment.created_by', [
|
||||||
le {{ $d(initialComment.createdAt.datetime, 'long') }}
|
initialComment.creator.text,
|
||||||
<div v-if="initialComment.updatedAt.datetime !== initialComment.createdAt.datetime">
|
$d(initialComment.createdAt.datetime, 'long')
|
||||||
modifié par {{ initialComment.updatedBy.text }}
|
]) }}
|
||||||
le {{ $d(initialComment.updatedAt.datetime, 'long') }}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form @submit.prevent="submitform">
|
|
||||||
<textarea
|
<textarea
|
||||||
name="content"
|
name="content"
|
||||||
v-bind:placeholder="$t('comment.content')"
|
v-bind:placeholder="$t('comment.content')"
|
||||||
@ -24,20 +27,21 @@
|
|||||||
ckeditor="ckeditor"
|
ckeditor="ckeditor"
|
||||||
v-model="content">
|
v-model="content">
|
||||||
</textarea>
|
</textarea>
|
||||||
|
|
||||||
<ul class="record_actions">
|
<ul class="record_actions">
|
||||||
<li>
|
<li>
|
||||||
<button type="submit" class="sc-button bt-save">{{ $t('action.save') }}</button>
|
<button type="submit" class="sc-button bt-save">{{ $t('action.save') }}</button>
|
||||||
</li>
|
</li>
|
||||||
<li id="xyz">
|
<li v-if="initialComment !== null">
|
||||||
</li>
|
<a class="sc-button bt-delete"
|
||||||
</ul>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<button v-if="initialComment !== null"
|
|
||||||
class="sc-button bt-delete"
|
|
||||||
@click="removeComment">
|
@click="removeComment">
|
||||||
{{ $t('action.delete') }}
|
{{ $t('action.delete') }}
|
||||||
</button>
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -82,9 +86,14 @@ export default {
|
|||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* TODO
|
* TODO
|
||||||
* - patch endpoint to update Content
|
* - [x] delete button in ul record_actions, but not in form
|
||||||
* - delete/reset button ?
|
* - [ ] display updatedAt => initialComment fetch PATCH content changes MUST NOT change object id !!
|
||||||
* - manage flash messages => specific component ?
|
* - [ ] ckeditor integration
|
||||||
* - ckeditor
|
|
||||||
*/
|
*/
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
div.vue-component > div {
|
||||||
|
//margin: 1em;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
@ -1,42 +1,63 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="vue-component">
|
<div class="vue-component">
|
||||||
<h3>
|
<h2><a name="section-70"></a>
|
||||||
{{ $t('confirm.title') }}
|
{{ $t('confirm.title') }}
|
||||||
<span v-if="accompanyingCourse.step !== 'DRAFT'"
|
</h2>
|
||||||
class="badge badge-pill badge-primary">
|
|
||||||
{{ $t('course.step.active') }}
|
|
||||||
</span>
|
|
||||||
<span v-else class="badge badge-pill badge-secondary">
|
|
||||||
{{ $t('course.step.draft') }}
|
|
||||||
</span>
|
|
||||||
</h3>
|
|
||||||
|
|
||||||
<p v-if="accompanyingCourse.step === 'DRAFT'">
|
<div>
|
||||||
|
<p>
|
||||||
{{ $t('confirm.text_draft') }}
|
{{ $t('confirm.text_draft') }}
|
||||||
|
<span class="badge badge-secondary">{{ $t('course.step.draft') }}</span>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
{{ $t('confirm.text_active') }}
|
||||||
|
<span class="badge badge-primary">{{ $t('course.step.active') }}</span>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<dl v-if="accompanyingCourse.closingDate">
|
|
||||||
<dt>{{ $t('course.closing_date') }}</dt>
|
|
||||||
<dd>{{ $d(accompanyingCourse.closingDate.datetime, 'short') }}</dd>
|
|
||||||
|
|
||||||
<dt>{{ $t('course.closing_motive') }}</dt>
|
|
||||||
<dd v-if="accompanyingCourse.closingMotive">{{ accompanyingCourse.closingMotive.name.fr }}</dd>
|
|
||||||
</dl>
|
|
||||||
|
|
||||||
<ul class="record_actions">
|
<ul class="record_actions">
|
||||||
<li>
|
<li>
|
||||||
<button class="sc-button bt-save"
|
<button class="sc-button bt-save" @click="modal.showModal = true">
|
||||||
@click="confirmCourse">
|
|
||||||
{{ $t('confirm.ok') }}
|
{{ $t('confirm.ok') }}
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<teleport to="body">
|
||||||
|
<modal v-if="modal.showModal" :modalDialogClass="modal.modalDialogClass" @close="modal.showModal = false">
|
||||||
|
<template v-slot:header>
|
||||||
|
<h2 class="modal-title">{{ $t('confirm.sure') }}</h2>
|
||||||
|
</template>
|
||||||
|
<template v-slot:body>
|
||||||
|
<p>{{ $t('confirm.sure_description') }}</p>
|
||||||
|
</template>
|
||||||
|
<template v-slot:footer>
|
||||||
|
<button class="sc-button red" @click="confirmCourse">
|
||||||
|
{{ $t('confirm.ok') }}
|
||||||
|
</button>
|
||||||
|
</template>
|
||||||
|
</modal>
|
||||||
|
</teleport>
|
||||||
|
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import Modal from 'ChillMainAssets/vuejs/_components/Modal';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "Confirm",
|
name: "Confirm",
|
||||||
|
components: {
|
||||||
|
Modal,
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
modal: {
|
||||||
|
showModal: false,
|
||||||
|
modalDialogClass: "modal-dialog-centered modal-md"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
computed: {
|
computed: {
|
||||||
accompanyingCourse() {
|
accompanyingCourse() {
|
||||||
return this.$store.state.accompanyingCourse
|
return this.$store.state.accompanyingCourse
|
||||||
@ -44,8 +65,16 @@ export default {
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
confirmCourse() {
|
confirmCourse() {
|
||||||
console.log('confirmCourse');
|
console.log('@@ CLICK confirmCourse');
|
||||||
|
this.$store.dispatch('confirmAccompanyingCourse');
|
||||||
|
console.log('confirm last');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
div.vue-component > div {
|
||||||
|
//margin: 1em;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
@ -1,8 +1,12 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="vue-component">
|
<div class="vue-component">
|
||||||
<h3>{{ $t('persons_associated.title')}}</h3>
|
<h2><a name="section-10"></a>{{ $t('persons_associated.title')}}</h2>
|
||||||
|
|
||||||
|
<div>
|
||||||
<label>{{ $tc('persons_associated.counter', counter) }}</label>
|
<label>{{ $tc('persons_associated.counter', counter) }}</label>
|
||||||
<table class="rounded">
|
</div>
|
||||||
|
|
||||||
|
<table class="rounded" v-if="participations.length > 0">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="chill-orange">{{ $t('persons_associated.firstname') }}</th>
|
<th class="chill-orange">{{ $t('persons_associated.firstname') }}</th>
|
||||||
@ -23,6 +27,7 @@
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
<div>
|
||||||
<add-persons
|
<add-persons
|
||||||
buttonTitle="persons_associated.add_persons"
|
buttonTitle="persons_associated.add_persons"
|
||||||
modalTitle="add_persons.title"
|
modalTitle="add_persons.title"
|
||||||
@ -31,13 +36,14 @@
|
|||||||
@addNewPersons="addNewPersons"
|
@addNewPersons="addNewPersons"
|
||||||
ref="addPersons"> <!-- to cast child method -->
|
ref="addPersons"> <!-- to cast child method -->
|
||||||
</add-persons>
|
</add-persons>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapState } from 'vuex';
|
import { mapState } from 'vuex';
|
||||||
import PersonItem from "./PersonItem.vue"
|
import PersonItem from "./PersonsAssociated/PersonItem.vue"
|
||||||
import AddPersons from 'ChillPersonAssets/vuejs/_components/AddPersons.vue'
|
import AddPersons from 'ChillPersonAssets/vuejs/_components/AddPersons.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@ -1,11 +1,77 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="vue-component">
|
<div class="vue-component">
|
||||||
<h3>{{ $t('referrer.title') }}</h3>
|
<h2><a name="section-40"></a>{{ $t('referrer.title') }}</h2>
|
||||||
|
|
||||||
|
<div class="my-4">
|
||||||
|
<label for="" class="">
|
||||||
|
{{ $t('referrer.label') }}
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<VueMultiselect
|
||||||
|
track-by="id"
|
||||||
|
label="text"
|
||||||
|
:multiple="false"
|
||||||
|
:searchable="true"
|
||||||
|
:placeholder="$t('referrer.placeholder')"
|
||||||
|
@update:model-value="updateReferrer"
|
||||||
|
:model-value="value"
|
||||||
|
:options="options">
|
||||||
|
</VueMultiselect>
|
||||||
|
|
||||||
|
<ul class="record_actions">
|
||||||
|
<li>
|
||||||
|
<button
|
||||||
|
class="sc-button bt-create"
|
||||||
|
type="button"
|
||||||
|
name="button"
|
||||||
|
@click="assignMe">
|
||||||
|
{{ $t('referrer.assign_me') }}
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import VueMultiselect from 'vue-multiselect';
|
||||||
|
//import { getUsers } from '../api';
|
||||||
|
import { mapState } from 'vuex';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "Referrer",
|
name: "Referrer",
|
||||||
|
components: { VueMultiselect },
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
options: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapState({
|
||||||
|
value: state => state.accompanyingCourse.user,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.getOptions();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getOptions() {
|
||||||
|
//getUsers().then(response => new Promise((resolve, reject) => {
|
||||||
|
// console.log(response);
|
||||||
|
// resolve();
|
||||||
|
//})).catch(er => this.$store.commit('catchError'), error));
|
||||||
|
},
|
||||||
|
updateReferrer(value) {
|
||||||
|
//this.$store.dispatch('updateReferrer', this.transformValue(value));
|
||||||
|
},
|
||||||
|
transformValue(value) {
|
||||||
|
let payload = value;
|
||||||
|
return { payload, body, method };
|
||||||
|
},
|
||||||
|
assignMe() {
|
||||||
|
console.log('assign me');
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,56 +1,67 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="vue-component">
|
<div class="vue-component">
|
||||||
|
|
||||||
<h3>{{ $t('requestor.title') }}</h3>
|
<h2><a name="section-20"></a>{{ $t('requestor.title') }}</h2>
|
||||||
|
|
||||||
|
<div v-if="accompanyingCourse.requestor" class="flex-table">
|
||||||
|
|
||||||
<div v-if="accompanyingCourse.requestor">
|
|
||||||
<label>
|
<label>
|
||||||
<input type="checkbox" v-model="isAnonymous" :value="value" />
|
<input type="checkbox" v-model="isAnonymous" :value="value" />
|
||||||
{{ $t('requestor.is_anonymous') }}
|
{{ $t('requestor.is_anonymous') }}
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<dt>{{ $t('requestor.type') }}</dt>
|
<div class="item-bloc">
|
||||||
<dd>{{ accompanyingCourse.requestor.type }}</dd>
|
<h4>
|
||||||
<dt>{{ $t('requestor.text') }}</dt>
|
<span class="badge badge-pill badge-secondary">{{ accompanyingCourse.requestor.type }}</span>
|
||||||
<dd>{{ accompanyingCourse.requestor.text }}</dd>
|
{{ accompanyingCourse.requestor.text }}
|
||||||
<dt>{{ $t('requestor.is_anonymous') }}</dt>
|
</h4>
|
||||||
<dd>{{ accompanyingCourse.requestorAnonymous }}</dd>
|
|
||||||
|
<dl class="content-bloc" v-if="accompanyingCourse.requestor.type === 'person'">
|
||||||
|
|
||||||
<div v-if="accompanyingCourse.requestor.type === 'person'">
|
|
||||||
<dt>{{ $t('requestor.person_id') }}</dt>
|
|
||||||
<dd>{{ accompanyingCourse.requestor.person_id }}</dd>
|
|
||||||
<dt>{{ $t('requestor.birthdate') }}</dt>
|
<dt>{{ $t('requestor.birthdate') }}</dt>
|
||||||
<dd>{{ $d(accompanyingCourse.requestor.birthdate.datetime, 'short') }}</dd>
|
<dd>{{ $d(accompanyingCourse.requestor.birthdate.datetime, 'short') }}</dd>
|
||||||
|
|
||||||
<dt>{{ $t('requestor.center') }}</dt>
|
<dt>{{ $t('requestor.center') }}</dt>
|
||||||
<dd>{{ accompanyingCourse.requestor.center.name }}</dd>
|
<dd>{{ accompanyingCourse.requestor.center.name }}</dd>
|
||||||
<dt>{{ $t('requestor.firstName') }}</dt>
|
|
||||||
<dd>{{ accompanyingCourse.requestor.firstName }}</dd>
|
|
||||||
<dt>{{ $t('requestor.lastName') }}</dt>
|
|
||||||
<dd>{{ accompanyingCourse.requestor.lastName }}</dd>
|
|
||||||
<dt>{{ $t('requestor.phonenumber') }}</dt>
|
<dt>{{ $t('requestor.phonenumber') }}</dt>
|
||||||
<dd>{{ accompanyingCourse.requestor.phonenumber }}</dd>
|
<dd>{{ accompanyingCourse.requestor.phonenumber }}</dd>
|
||||||
<dt>{{ $t('requestor.mobilenumber') }}</dt>
|
<dt>{{ $t('requestor.mobilenumber') }}</dt>
|
||||||
<dd>{{ accompanyingCourse.requestor.mobilenumber }}</dd>
|
<dd>{{ accompanyingCourse.requestor.mobilenumber }}</dd>
|
||||||
<dt>{{ $t('requestor.altNames') }}</dt>
|
</dl>
|
||||||
<dd>{{ accompanyingCourse.requestor.altNames }}</dd>
|
|
||||||
</div>
|
<dl class="content-bloc" v-if="accompanyingCourse.requestor.type === 'thirdparty'">
|
||||||
|
|
||||||
<div v-if="accompanyingCourse.requestor.type === 'thirdparty'">
|
|
||||||
<dt>{{ $t('requestor.person_id') }}</dt>
|
|
||||||
<dd>{{ accompanyingCourse.requestor.thirdparty_id }}</dd>
|
|
||||||
<dt>{{ $t('requestor.address') }}</dt>
|
<dt>{{ $t('requestor.address') }}</dt>
|
||||||
<dd>{{ accompanyingCourse.requestor.address.text }}</dd>
|
<dd>{{ accompanyingCourse.requestor.address.text }}</dd>
|
||||||
|
|
||||||
<dt>{{ $t('requestor.location') }}</dt>
|
<dt>{{ $t('requestor.location') }}</dt>
|
||||||
<dd>{{ accompanyingCourse.requestor.address.postcode.name }}</dd>
|
<dd>{{ accompanyingCourse.requestor.address.postcode.name }}</dd>
|
||||||
</div>
|
</dl>
|
||||||
|
|
||||||
|
<ul class="record_actions">
|
||||||
|
<li>
|
||||||
|
<a class="sc-button bt-show" :title="$t('action.show')" target="_blank" :href="url.show"></a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button v-if="accompanyingCourse.requestor !== null"
|
<ul class="record_actions">
|
||||||
class="sc-button bt-remove"
|
<li>
|
||||||
|
<button class="sc-button bt-remove"
|
||||||
:title="$t('action.remove')"
|
:title="$t('action.remove')"
|
||||||
@click="removeRequestor">
|
@click="removeRequestor">
|
||||||
|
{{ $t('action.remove') }}
|
||||||
</button>
|
</button>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
<label>{{ $t('requestor.counter') }}</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
<add-persons v-if="accompanyingCourse.requestor === null"
|
<add-persons v-if="accompanyingCourse.requestor === null"
|
||||||
buttonTitle="requestor.add_requestor"
|
buttonTitle="requestor.add_requestor"
|
||||||
modalTitle="requestor.add_requestor"
|
modalTitle="requestor.add_requestor"
|
||||||
@ -59,6 +70,7 @@
|
|||||||
@addNewPersons="addNewPersons"
|
@addNewPersons="addNewPersons"
|
||||||
ref="addPersons"> <!-- to cast child method -->
|
ref="addPersons"> <!-- to cast child method -->
|
||||||
</add-persons>
|
</add-persons>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -95,6 +107,13 @@ export default {
|
|||||||
get() {
|
get() {
|
||||||
return this.$store.state.accompanyingCourse.requestorAnonymous;
|
return this.$store.state.accompanyingCourse.requestorAnonymous;
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
url() {
|
||||||
|
return (this.accompanyingCourse.requestor.type === 'person') ? {
|
||||||
|
show: `/fr/person/${this.accompanyingCourse.requestor.id}/general`,
|
||||||
|
} : {
|
||||||
|
show: `/fr/thirdparty/thirdparty/${this.accompanyingCourse.requestor.id}/show`,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@ -111,3 +130,28 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
|
||||||
|
div.flex-table {
|
||||||
|
margin: 1em 0 0 !important;
|
||||||
|
& > label,
|
||||||
|
& > ul.record_actions {
|
||||||
|
margin: 1em 3em 0 !important;
|
||||||
|
}
|
||||||
|
div.item-bloc {
|
||||||
|
background-color: white !important;
|
||||||
|
border: 1px solid #000;
|
||||||
|
padding: 1em;
|
||||||
|
margin-top: 1em;
|
||||||
|
.content-bloc {
|
||||||
|
font-size: 100%;
|
||||||
|
}
|
||||||
|
ul.record_actions {
|
||||||
|
margin-right: 2em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="vue-component">
|
<div class="vue-component">
|
||||||
|
|
||||||
<h3>{{ $t('resources.title')}}</h3>
|
<h2><a name="section-50"></a>{{ $t('resources.title')}}</h2>
|
||||||
|
|
||||||
|
<div>
|
||||||
<label>{{ $tc('resources.counter', counter) }}</label>
|
<label>{{ $tc('resources.counter', counter) }}</label>
|
||||||
<table class="rounded">
|
</div>
|
||||||
|
|
||||||
|
<table class="rounded" v-if="resources.length > 0">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="chill-orange">{{ $t('resources.text') }}</th>
|
<th class="chill-orange">{{ $t('resources.text') }}</th>
|
||||||
@ -22,6 +25,7 @@
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
<div>
|
||||||
<add-persons
|
<add-persons
|
||||||
buttonTitle="resources.add_resources"
|
buttonTitle="resources.add_resources"
|
||||||
modalTitle="resources.add_resources"
|
modalTitle="resources.add_resources"
|
||||||
@ -30,6 +34,7 @@
|
|||||||
@addNewPersons="addNewPersons"
|
@addNewPersons="addNewPersons"
|
||||||
ref="addPersons"> <!-- to cast child method -->
|
ref="addPersons"> <!-- to cast child method -->
|
||||||
</add-persons>
|
</add-persons>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -37,7 +42,7 @@
|
|||||||
<script>
|
<script>
|
||||||
import { mapState } from 'vuex';
|
import { mapState } from 'vuex';
|
||||||
import AddPersons from 'ChillPersonAssets/vuejs/_components/AddPersons.vue';
|
import AddPersons from 'ChillPersonAssets/vuejs/_components/AddPersons.vue';
|
||||||
import ResourceItem from './ResourceItem.vue';
|
import ResourceItem from './Resources/ResourceItem.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Resources',
|
name: 'Resources',
|
||||||
|
@ -1,11 +1,80 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="vue-component">
|
<div class="vue-component">
|
||||||
<h3>{{ $t('social_issue.title') }}</h3>
|
<h2><a name="section-30"></a>{{ $t('social_issue.title') }}</h2>
|
||||||
|
|
||||||
|
<div class="my-4">
|
||||||
|
<!--label for="field">{{ $t('social_issue.label') }}</label
|
||||||
|
-->
|
||||||
|
<VueMultiselect
|
||||||
|
name="field"
|
||||||
|
:close-on-select="false"
|
||||||
|
:allow-empty="true"
|
||||||
|
:show-labels="false"
|
||||||
|
track-by="id"
|
||||||
|
label="text"
|
||||||
|
:multiple="true"
|
||||||
|
:searchable="false"
|
||||||
|
:placeholder="$t('social_issue.label')"
|
||||||
|
@update:model-value="updateSocialIssues"
|
||||||
|
:model-value="value"
|
||||||
|
:options="options">
|
||||||
|
</VueMultiselect>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import VueMultiselect from 'vue-multiselect';
|
||||||
|
import { getSocialIssues } from '../api';
|
||||||
|
import { mapState } from 'vuex';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "SocialIssue",
|
name: "SocialIssue",
|
||||||
|
components: { VueMultiselect },
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
options: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapState({
|
||||||
|
value: state => state.accompanyingCourse.socialIssues,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.getOptions();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getOptions() {
|
||||||
|
getSocialIssues().then(response => new Promise((resolve, reject) => {
|
||||||
|
//console.log('get socialIssues', response.results);
|
||||||
|
this.options = response.results;
|
||||||
|
resolve();
|
||||||
|
})).catch(error => this.$store.commit('catchError', error));
|
||||||
|
},
|
||||||
|
updateSocialIssues(value) {
|
||||||
|
this.$store.dispatch('updateSocialIssues', this.transformValue(value));
|
||||||
|
},
|
||||||
|
transformValue(updated) {
|
||||||
|
let stored = this.value;
|
||||||
|
let added = updated.filter(x => stored.indexOf(x) === -1).shift();
|
||||||
|
let removed = stored.filter(x => updated.indexOf(x) === -1).shift();
|
||||||
|
let method = (typeof removed === 'undefined') ? 'POST' : 'DELETE';
|
||||||
|
let changed = (typeof removed === 'undefined') ? added : removed;
|
||||||
|
let body = { type: "social_issue", id: changed.id };
|
||||||
|
//console.log('body', body);
|
||||||
|
//console.log('@@@', method, changed.text);
|
||||||
|
let payload = updated;
|
||||||
|
return { payload, body, method };
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style src="vue-multiselect/dist/vue-multiselect.css"></style>
|
||||||
|
<style lang="scss">
|
||||||
|
span.multiselect__tag {
|
||||||
|
background: #e2793d;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
@ -0,0 +1,191 @@
|
|||||||
|
<template>
|
||||||
|
<teleport to="#content_conainter .container.content .container">
|
||||||
|
<div id="navmap">
|
||||||
|
<nav>
|
||||||
|
<a class="top" href="#top">
|
||||||
|
<i class="fa fa-fw fa-square"></i>
|
||||||
|
<span>{{ $t('nav.top') }}</span>
|
||||||
|
</a>
|
||||||
|
<item
|
||||||
|
v-for="item of items"
|
||||||
|
:key="item.key"
|
||||||
|
:item="item"
|
||||||
|
:step="step">
|
||||||
|
</item>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
</teleport>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Item from './StickyNav/Item.vue';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "StickyNav",
|
||||||
|
components: {
|
||||||
|
Item
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
header: document.querySelector("header.navigation.container"),
|
||||||
|
bannerName: document.querySelector("#header-accompanying_course-name"),
|
||||||
|
bannerDetails: document.querySelector("#header-accompanying_course-details"),
|
||||||
|
container: null,
|
||||||
|
heightSum: null,
|
||||||
|
stickyNav: null,
|
||||||
|
limit: 25,
|
||||||
|
anchors: null,
|
||||||
|
items: [],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
accompanyingCourse() {
|
||||||
|
return this.$store.state.accompanyingCourse;
|
||||||
|
},
|
||||||
|
step() {
|
||||||
|
return this.accompanyingCourse.step;
|
||||||
|
},
|
||||||
|
top() {
|
||||||
|
return parseInt(window.getComputedStyle(this.stickyNav).getPropertyValue('top').slice(0, -2));
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.ready();
|
||||||
|
window.addEventListener('scroll', this.handleScroll);
|
||||||
|
},
|
||||||
|
destroyed() {
|
||||||
|
window.removeEventListener('scroll', this.handleScroll);
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
ready() {
|
||||||
|
|
||||||
|
// load datas DOM when mounted ready
|
||||||
|
this.container = document.querySelector("#content_conainter .container.content .container");
|
||||||
|
this.stickyNav = document.querySelector('#navmap');
|
||||||
|
this.anchors = document.querySelectorAll("h2 a[name^='section']");
|
||||||
|
this.initItemsMap();
|
||||||
|
|
||||||
|
// TODO resizeObserver not supports IE !
|
||||||
|
// Listen when elements change size, then recalculate heightSum and initItemsMap
|
||||||
|
const resizeObserver = new ResizeObserver(entries => {
|
||||||
|
this.refreshPos();
|
||||||
|
});
|
||||||
|
|
||||||
|
resizeObserver.observe(this.header);
|
||||||
|
resizeObserver.observe(this.bannerName);
|
||||||
|
resizeObserver.observe(this.bannerDetails);
|
||||||
|
resizeObserver.observe(this.container);
|
||||||
|
},
|
||||||
|
initItemsMap() {
|
||||||
|
|
||||||
|
this.anchors.forEach(anchor => {
|
||||||
|
this.items.push({
|
||||||
|
pos: null,
|
||||||
|
active: false,
|
||||||
|
key: parseInt(anchor.name.slice(8).slice(0, -1)),
|
||||||
|
name: '#' + anchor.name
|
||||||
|
})
|
||||||
|
});
|
||||||
|
},
|
||||||
|
refreshPos() {
|
||||||
|
|
||||||
|
//console.log('refreshPos');
|
||||||
|
this.heightSum = this.header.offsetHeight + this.bannerName.offsetHeight + this.bannerDetails.offsetHeight;
|
||||||
|
|
||||||
|
this.anchors.forEach((anchor, i) => {
|
||||||
|
this.items[i].pos = this.findPos(anchor)['y'];
|
||||||
|
});
|
||||||
|
},
|
||||||
|
findPos(element) {
|
||||||
|
|
||||||
|
let posX = 0, posY = 0;
|
||||||
|
do {
|
||||||
|
posX += element.offsetLeft;
|
||||||
|
posY += element.offsetTop;
|
||||||
|
element = element.offsetParent;
|
||||||
|
}
|
||||||
|
while( element != null );
|
||||||
|
|
||||||
|
let pos = [];
|
||||||
|
pos['x'] = posX;
|
||||||
|
pos['y'] = posY;
|
||||||
|
|
||||||
|
return pos;
|
||||||
|
},
|
||||||
|
handleScroll(event) {
|
||||||
|
|
||||||
|
let pos = this.findPos(this.stickyNav);
|
||||||
|
let top = this.heightSum + this.top - window.scrollY;
|
||||||
|
//console.log(window.scrollY);
|
||||||
|
|
||||||
|
if (top > this.limit) {
|
||||||
|
this.stickyNav.style.position = 'absolute';
|
||||||
|
this.stickyNav.style.left = '-60px';
|
||||||
|
} else {
|
||||||
|
this.stickyNav.style.position = 'fixed';
|
||||||
|
this.stickyNav.style.left = pos['x'] + 'px';
|
||||||
|
}
|
||||||
|
|
||||||
|
this.switchActive();
|
||||||
|
},
|
||||||
|
switchActive() {
|
||||||
|
|
||||||
|
this.items.forEach((item, i) => {
|
||||||
|
let next = (this.items[i+1]) ? this.items[i+1].pos : '100000';
|
||||||
|
item.active =
|
||||||
|
(window.scrollY >= item.pos & window.scrollY < next) ? true : false;
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
// last item never switch active because scroll reach bottom of page
|
||||||
|
if (document.body.scrollHeight == window.scrollY + window.innerHeight) {
|
||||||
|
this.items[this.items.length-1].active = true;
|
||||||
|
this.items[this.items.length-2].active = false;
|
||||||
|
} else {
|
||||||
|
this.items[this.items.length-1].active = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
div#navmap {
|
||||||
|
position: absolute;
|
||||||
|
top: 30px;
|
||||||
|
left: -60px; //-10%;
|
||||||
|
nav {
|
||||||
|
font-size: small;
|
||||||
|
a {
|
||||||
|
display: block;
|
||||||
|
box-sizing: border-box;
|
||||||
|
margin-bottom: -3px;
|
||||||
|
color: #71859669;
|
||||||
|
&.top {
|
||||||
|
color: #718596;
|
||||||
|
}
|
||||||
|
span {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
&:hover,
|
||||||
|
&.active {
|
||||||
|
span {
|
||||||
|
display: inline;
|
||||||
|
padding-left: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&:hover {
|
||||||
|
color: #718596b5;
|
||||||
|
}
|
||||||
|
&.active {
|
||||||
|
color: #e2793d; //orange
|
||||||
|
//color: #eec84a; //jaune
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media only screen and (max-width: 768px) {
|
||||||
|
div#navmap {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -0,0 +1,30 @@
|
|||||||
|
<template>
|
||||||
|
<a
|
||||||
|
v-if="item.key <= 5"
|
||||||
|
:href="item.name"
|
||||||
|
:class="{ 'active': isActive }"
|
||||||
|
>
|
||||||
|
<i class="fa fa-fw fa-square"></i>
|
||||||
|
<span>{{ item.key }}</span>
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
v-else-if="step === 'DRAFT'"
|
||||||
|
:href="item.name"
|
||||||
|
:class="{ 'active': isActive }"
|
||||||
|
>
|
||||||
|
<i class="fa fa-fw fa-square"></i>
|
||||||
|
<span>{{ item.key }}</span>
|
||||||
|
</a>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "Item",
|
||||||
|
props: ['item', 'step'],
|
||||||
|
computed: {
|
||||||
|
isActive() {
|
||||||
|
return this.item.active;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="vue-component">
|
<div class="vue-component">
|
||||||
<h3>Tests</h3>
|
<h2></a>Tests</h2>
|
||||||
|
|
||||||
<!-- Modal -->
|
<!-- Modal -->
|
||||||
<ul class="record_actions">
|
<ul class="record_actions">
|
||||||
@ -19,7 +19,7 @@
|
|||||||
<teleport to="body">
|
<teleport to="body">
|
||||||
<modal v-if="modal1.showModal" :modalDialogClass="modal1.modalDialogClass" @close="modal1.showModal = false">
|
<modal v-if="modal1.showModal" :modalDialogClass="modal1.modalDialogClass" @close="modal1.showModal = false">
|
||||||
<template v-slot:header>
|
<template v-slot:header>
|
||||||
<h3 class="modal-title">Le titre de ma modale</h3>
|
<h2 class="modal-title">Le titre de ma modale</h2>
|
||||||
</template>
|
</template>
|
||||||
<template v-slot:body>
|
<template v-slot:body>
|
||||||
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus luctus facilisis suscipit. Cras pulvinar, purus sagittis pulvinar porta, enim ex posuere lacus, in pulvinar lectus magna in odio. Nullam iaculis congue lorem ac suscipit. Proin ut rutrum augue. Ut vehicula risus nec hendrerit ullamcorper. Ut volutpat eu mi eget viverra. Morbi dictum placerat suscipit. </p>
|
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus luctus facilisis suscipit. Cras pulvinar, purus sagittis pulvinar porta, enim ex posuere lacus, in pulvinar lectus magna in odio. Nullam iaculis congue lorem ac suscipit. Proin ut rutrum augue. Ut vehicula risus nec hendrerit ullamcorper. Ut volutpat eu mi eget viverra. Morbi dictum placerat suscipit. </p>
|
||||||
@ -39,7 +39,7 @@
|
|||||||
<teleport to="body">
|
<teleport to="body">
|
||||||
<modal v-if="modal2.showModal" :modalDialogClass="modal2.modalDialogClass" @close="modal2.showModal = false">
|
<modal v-if="modal2.showModal" :modalDialogClass="modal2.modalDialogClass" @close="modal2.showModal = false">
|
||||||
<template v-slot:header>
|
<template v-slot:header>
|
||||||
<h3 class="modal-title">Une autre modale</h3>
|
<h2 class="modal-title">Une autre modale</h2>
|
||||||
</template>
|
</template>
|
||||||
<template v-slot:body>
|
<template v-slot:body>
|
||||||
<p>modal 2</p>
|
<p>modal 2</p>
|
||||||
|
@ -4,11 +4,16 @@ import { appMessages } from './js/i18n'
|
|||||||
import { initPromise } from './store'
|
import { initPromise } from './store'
|
||||||
|
|
||||||
import App from './App.vue';
|
import App from './App.vue';
|
||||||
|
import Banner from './components/Banner.vue';
|
||||||
|
|
||||||
initPromise.then(store => {
|
const root = window.vueRootComponent;
|
||||||
|
|
||||||
//console.log('store in create_store', store);
|
/*
|
||||||
//console.log('store accompanyingCourse', store.state.accompanyingCourse);
|
* Load all App component, for AccompanyingCourse edition page
|
||||||
|
*/
|
||||||
|
if (root === 'app') {
|
||||||
|
|
||||||
|
initPromise.then(store => {
|
||||||
|
|
||||||
const i18n = _createI18n(appMessages);
|
const i18n = _createI18n(appMessages);
|
||||||
|
|
||||||
@ -20,4 +25,26 @@ initPromise.then(store => {
|
|||||||
.component('app', App)
|
.component('app', App)
|
||||||
.mount('#accompanying-course');
|
.mount('#accompanying-course');
|
||||||
|
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Load only Banner sub-component, for all others AccompanyingCourse page
|
||||||
|
*/
|
||||||
|
if (root === 'banner') {
|
||||||
|
|
||||||
|
initPromise.then(store => {
|
||||||
|
|
||||||
|
const i18n = _createI18n(appMessages);
|
||||||
|
|
||||||
|
const app = createApp({
|
||||||
|
template: `<banner></banner>`,
|
||||||
|
})
|
||||||
|
.use(store)
|
||||||
|
.use(i18n)
|
||||||
|
.component('banner', Banner)
|
||||||
|
.mount('#accompanying-course');
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
@ -4,7 +4,10 @@ const appMessages = {
|
|||||||
fr: {
|
fr: {
|
||||||
course: {
|
course: {
|
||||||
id: "id",
|
id: "id",
|
||||||
title: "Parcours",
|
title: {
|
||||||
|
draft: "Création d'un nouveau parcours",
|
||||||
|
active: "Modification du parcours"
|
||||||
|
},
|
||||||
opening_date: "Date d'ouverture",
|
opening_date: "Date d'ouverture",
|
||||||
closing_date: "Date de clôture",
|
closing_date: "Date de clôture",
|
||||||
remark: "Commentaire",
|
remark: "Commentaire",
|
||||||
@ -14,7 +17,6 @@ const appMessages = {
|
|||||||
status: "État",
|
status: "État",
|
||||||
step: {
|
step: {
|
||||||
draft: "Brouillon",
|
draft: "Brouillon",
|
||||||
open: "Ouvert",
|
|
||||||
active: "En file active"
|
active: "En file active"
|
||||||
},
|
},
|
||||||
open_at: "ouvert le ",
|
open_at: "ouvert le ",
|
||||||
@ -26,7 +28,7 @@ const appMessages = {
|
|||||||
},
|
},
|
||||||
persons_associated: {
|
persons_associated: {
|
||||||
title: "Usagers concernés",
|
title: "Usagers concernés",
|
||||||
counter: "Pas d'usager | 1 usager | {count} usagers",
|
counter: "Il n'y a pas encore d'usager | 1 usager | {count} usagers",
|
||||||
firstname: "Prénom",
|
firstname: "Prénom",
|
||||||
lastname: "Nom",
|
lastname: "Nom",
|
||||||
startdate: "Date d'entrée",
|
startdate: "Date d'entrée",
|
||||||
@ -37,6 +39,7 @@ const appMessages = {
|
|||||||
title: "Demandeur",
|
title: "Demandeur",
|
||||||
add_requestor: "Ajouter un demandeur",
|
add_requestor: "Ajouter un demandeur",
|
||||||
is_anonymous: "Le demandeur est anonyme",
|
is_anonymous: "Le demandeur est anonyme",
|
||||||
|
counter: "Il n'y a pas encore de demandeur",
|
||||||
type: "Type",
|
type: "Type",
|
||||||
person_id: "id",
|
person_id: "id",
|
||||||
text: "Dénomination",
|
text: "Dénomination",
|
||||||
@ -52,25 +55,34 @@ const appMessages = {
|
|||||||
},
|
},
|
||||||
social_issue: {
|
social_issue: {
|
||||||
title: "Problématiques sociales",
|
title: "Problématiques sociales",
|
||||||
|
label: "Choisir les problématiques sociales",
|
||||||
},
|
},
|
||||||
referrer: {
|
referrer: {
|
||||||
title: "Référent",
|
title: "Référent du parcours",
|
||||||
|
label: "Vous pouvez choisir un TMS ou vous assigner directement comme référent",
|
||||||
|
placeholder: "Choisir un TMS",
|
||||||
|
assign_me: "M'assigner comme référent",
|
||||||
},
|
},
|
||||||
resources: {
|
resources: {
|
||||||
title: "Interlocuteurs privilégiés",
|
title: "Interlocuteurs privilégiés",
|
||||||
counter: "Pas d'interlocuteur | 1 interlocuteur | {count} interlocuteurs",
|
counter: "Il n'y a pas encore d'interlocuteur | 1 interlocuteur | {count} interlocuteurs",
|
||||||
text: "Dénomination",
|
text: "Dénomination",
|
||||||
description: "Description",
|
description: "Description",
|
||||||
add_resources: "Ajouter des interlocuteurs",
|
add_resources: "Ajouter des interlocuteurs",
|
||||||
},
|
},
|
||||||
comment: {
|
comment: {
|
||||||
title: "Ajout d'une note",
|
title: "Observations",
|
||||||
content: "Rédigez une première note..."
|
label: "Ajout d'une note",
|
||||||
|
content: "Rédigez une première note...",
|
||||||
|
created_by: "créé par {0}, le {1}"
|
||||||
},
|
},
|
||||||
confirm: {
|
confirm: {
|
||||||
title: "Confirmation",
|
title: "Confirmation",
|
||||||
text_draft: "Le parcours est actuellement au statut de brouillon. En validant cette étape, vous lui donnez le statut actif.",
|
text_draft: "Le parcours est actuellement à l'état de ",
|
||||||
ok: "Activer le parcours"
|
text_active: "En validant cette étape, vous lui donnez le statut ",
|
||||||
|
sure: "Êtes-vous sûr ?",
|
||||||
|
sure_description: "Une fois le changement confirmé, il n'est plus possible de le remettre à l'état de brouillon !",
|
||||||
|
ok: "Confirmer le parcours"
|
||||||
},
|
},
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2,9 +2,11 @@ import 'es6-promise/auto';
|
|||||||
import { createStore } from 'vuex';
|
import { createStore } from 'vuex';
|
||||||
import { getAccompanyingCourse,
|
import { getAccompanyingCourse,
|
||||||
patchAccompanyingCourse,
|
patchAccompanyingCourse,
|
||||||
|
confirmAccompanyingCourse,
|
||||||
postParticipation,
|
postParticipation,
|
||||||
postRequestor,
|
postRequestor,
|
||||||
postResource } from '../api';
|
postResource,
|
||||||
|
postSocialIssue } from '../api';
|
||||||
|
|
||||||
const debug = process.env.NODE_ENV !== 'production';
|
const debug = process.env.NODE_ENV !== 'production';
|
||||||
const id = window.accompanyingCourseId;
|
const id = window.accompanyingCourseId;
|
||||||
@ -73,8 +75,15 @@ let initPromise = getAccompanyingCourse(id)
|
|||||||
state.accompanyingCourse.confidential = value;
|
state.accompanyingCourse.confidential = value;
|
||||||
},
|
},
|
||||||
postFirstComment(state, comment) {
|
postFirstComment(state, comment) {
|
||||||
console.log('### mutation: postFirstComment', comment);
|
//console.log('### mutation: postFirstComment', comment);
|
||||||
state.accompanyingCourse.initialComment = comment;
|
state.accompanyingCourse.initialComment = comment;
|
||||||
|
},
|
||||||
|
updateSocialIssues(state, value) {
|
||||||
|
state.accompanyingCourse.socialIssues = value;
|
||||||
|
},
|
||||||
|
confirmAccompanyingCourse(state, response) {
|
||||||
|
//console.log('### mutation: confirmAccompanyingCourse: response', response);
|
||||||
|
state.accompanyingCourse.step = response.step;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
@ -140,7 +149,7 @@ let initPromise = getAccompanyingCourse(id)
|
|||||||
})).catch((error) => { commit('catchError', error) });
|
})).catch((error) => { commit('catchError', error) });
|
||||||
},
|
},
|
||||||
toggleIntensity({ commit }, payload) {
|
toggleIntensity({ commit }, payload) {
|
||||||
console.log(payload);
|
//console.log(payload);
|
||||||
patchAccompanyingCourse(id, { type: "accompanying_period", intensity: payload })
|
patchAccompanyingCourse(id, { type: "accompanying_period", intensity: payload })
|
||||||
.then(course => new Promise((resolve, reject) => {
|
.then(course => new Promise((resolve, reject) => {
|
||||||
commit('toggleIntensity', course.intensity);
|
commit('toggleIntensity', course.intensity);
|
||||||
@ -162,12 +171,31 @@ let initPromise = getAccompanyingCourse(id)
|
|||||||
})).catch((error) => { commit('catchError', error) });
|
})).catch((error) => { commit('catchError', error) });
|
||||||
},
|
},
|
||||||
postFirstComment({ commit }, payload) {
|
postFirstComment({ commit }, payload) {
|
||||||
console.log('## action: postFirstComment: payload', payload);
|
//console.log('## action: postFirstComment: payload', payload);
|
||||||
patchAccompanyingCourse(id, { type: "accompanying_period", initialComment: payload })
|
patchAccompanyingCourse(id, { type: "accompanying_period", initialComment: payload })
|
||||||
.then(course => new Promise((resolve, reject) => {
|
.then(course => new Promise((resolve, reject) => {
|
||||||
commit('postFirstComment', course.initialComment);
|
commit('postFirstComment', course.initialComment);
|
||||||
resolve();
|
resolve();
|
||||||
})).catch((error) => { commit('catchError', error) });
|
})).catch((error) => { commit('catchError', error) });
|
||||||
|
},
|
||||||
|
updateSocialIssues({ commit }, { payload, body, method }) {
|
||||||
|
//console.log('## action: payload', { payload, body, method });
|
||||||
|
postSocialIssue(id, body, method)
|
||||||
|
.then(response => new Promise((resolve, reject) => {
|
||||||
|
//console.log('response', response);
|
||||||
|
commit('updateSocialIssues', payload);
|
||||||
|
resolve();
|
||||||
|
})).catch((error) => { commit('catchError', error) });
|
||||||
|
},
|
||||||
|
confirmAccompanyingCourse({ commit }) {
|
||||||
|
//console.log('## action: confirmAccompanyingCourse');
|
||||||
|
confirmAccompanyingCourse(id)
|
||||||
|
.then(response => new Promise((resolve, reject) => {
|
||||||
|
window.location.replace(`/fr/parcours/${id}`);
|
||||||
|
console.log('fetch resolve');
|
||||||
|
commit('confirmAccompanyingCourse', response);
|
||||||
|
resolve();
|
||||||
|
})).catch((error) => { commit('catchError', error) });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<button class="sc-button bt-create centered mt-4" @click="openModal">
|
<ul class="record_actions">
|
||||||
|
<li>
|
||||||
|
<button class="sc-button bt-create" @click="openModal">
|
||||||
{{ $t(buttonTitle) }}
|
{{ $t(buttonTitle) }}
|
||||||
</button>
|
</button>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
<teleport to="body">
|
<teleport to="body">
|
||||||
<modal v-if="modal.showModal"
|
<modal v-if="modal.showModal"
|
||||||
@ -207,3 +211,44 @@ export default {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
div.body-head {
|
||||||
|
overflow-y: unset;
|
||||||
|
div.modal-body:first-child {
|
||||||
|
margin: auto 4em;
|
||||||
|
div.search {
|
||||||
|
position: relative;
|
||||||
|
input {
|
||||||
|
padding: 1.2em 1.5em 1.2em 2.5em;
|
||||||
|
margin: 1em 0;
|
||||||
|
}
|
||||||
|
i {
|
||||||
|
position: absolute;
|
||||||
|
opacity: 0.5;
|
||||||
|
padding: 0.65em 0;
|
||||||
|
top: 50%;
|
||||||
|
}
|
||||||
|
i.fa-search {
|
||||||
|
left: 0.5em;
|
||||||
|
}
|
||||||
|
i.fa-times {
|
||||||
|
right: 1em;
|
||||||
|
padding: 0.75em 0;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
div.modal-body:last-child {
|
||||||
|
padding-bottom: 0;
|
||||||
|
}
|
||||||
|
div.count {
|
||||||
|
margin: -0.5em 0 0.7em;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
a {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
v-model="selected"
|
v-model="selected"
|
||||||
name="item"
|
name="item"
|
||||||
v-bind:id="item"
|
v-bind:id="item"
|
||||||
v-bind:value="setValueIfType(item, type)" />
|
v-bind:value="setValueByType(item, type)" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<suggestion-person
|
<suggestion-person
|
||||||
@ -54,9 +54,48 @@ export default {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
setValueIfType(value, type) {
|
setValueByType(value, type) {
|
||||||
return (type === 'radio')? [value] : value;
|
return (type === 'radio')? [value] : value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
div.results {
|
||||||
|
div.list-item {
|
||||||
|
padding: 0.4em 0.8em;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
&.checked {
|
||||||
|
background-color: #ececec;
|
||||||
|
border-bottom: 1px dotted #8b8b8b;
|
||||||
|
}
|
||||||
|
div.container {
|
||||||
|
& > input {
|
||||||
|
margin-right: 0.8em;
|
||||||
|
}
|
||||||
|
span:not(.name) {
|
||||||
|
margin-left: 0.5em;
|
||||||
|
opacity: 0.5;
|
||||||
|
font-size: 90%;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
div.right_actions {
|
||||||
|
margin: 0 0 0 auto;
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-end;
|
||||||
|
& > * {
|
||||||
|
margin-left: 0.5em;
|
||||||
|
align-self: baseline;
|
||||||
|
}
|
||||||
|
a.sc-button {
|
||||||
|
border: 1px solid lightgrey;
|
||||||
|
font-size: 70%;
|
||||||
|
padding: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
@ -2,39 +2,24 @@
|
|||||||
<div class="grid-12 parent" id="header-accompanying_course-name" >
|
<div class="grid-12 parent" id="header-accompanying_course-name" >
|
||||||
<div class="grid-10 push-1 grid-mobile-12 grid-tablet-12 push-mobile-0 push-tablet-0 parent">
|
<div class="grid-10 push-1 grid-mobile-12 grid-tablet-12 push-mobile-0 push-tablet-0 parent">
|
||||||
|
|
||||||
<div class="grid-5">{% set title = title %}
|
<div class="grid-6">{% set title = title %}
|
||||||
<h1>
|
<h1>
|
||||||
<i class="fa fa-random fa-fw"></i>
|
<i class="fa fa-random fa-fw"></i>
|
||||||
{{ 'Accompanying Course'|trans }}{# ou défini en amont
|
{{ 'Accompanying Course'|trans }}
|
||||||
{{ title|default('Accompanying Course'|trans)|raw }} #}
|
<span style="font-weight: lighter; font-size: 50%;">(n°{{ accompanyingCourse.id }})</span>
|
||||||
<span style="font-weight: lighter; font-size: 65%;">(n°{{ accompanyingCourse.id }})</span>
|
|
||||||
</h1>
|
</h1>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="grid-4">
|
<div class="grid-3" id="banner-flags"></div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="grid-3">
|
<div class="grid-3" id="banner-status"></div>
|
||||||
<p style="text-align: right;">
|
|
||||||
{% if 'DRAFT' == accompanyingCourse.getStep() %}
|
|
||||||
Brouillon
|
|
||||||
{% else %}
|
|
||||||
<i>{{ 'Started on %date%'|trans({'%date%': accompanyingCourse.openingDate|format_date('short') } ) }}</i><br>
|
|
||||||
{% if accompanyingCourse.user is not null %}
|
|
||||||
par <b>{{ accompanyingCourse.user.username }}</b>
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid-12 parent" id="header-accompanying_course-details" >
|
<div class="grid-12 parent" id="header-accompanying_course-details" >
|
||||||
<div class="grid-10 push-1 grid-mobile-12 grid-tablet-12 push-mobile-0 push-tablet-0 parent">
|
<div class="grid-10 push-1 grid-mobile-12 grid-tablet-12 push-mobile-0 push-tablet-0 parent">
|
||||||
|
|
||||||
<div class="grid-4">Problématiques sociales</div>
|
<div id="banner-social-issues"></div>
|
||||||
<div class="grid-4">_</div>
|
|
||||||
<div class="grid-4">_</div>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -7,13 +7,13 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h1>{{ block('title') }}</h1>
|
<div id="accompanying-course"></div> {# <== insert accompanyingCourse vue component #}
|
||||||
<div id="accompanying-course"></div>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block js %}
|
{% block js %}
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
window.accompanyingCourseId = {{ accompanyingCourse.id|e('js') }};
|
window.accompanyingCourseId = {{ accompanyingCourse.id|e('js') }};
|
||||||
|
window.vueRootComponent = 'app';
|
||||||
</script>
|
</script>
|
||||||
{{ encore_entry_script_tags('accompanying_course') }}
|
{{ encore_entry_script_tags('accompanying_course') }}
|
||||||
{% endblock %}
|
{% endblock %}
|
@ -8,19 +8,59 @@
|
|||||||
|
|
||||||
<h1>{{ block('title') }}</h1>
|
<h1>{{ block('title') }}</h1>
|
||||||
|
|
||||||
<pre>
|
{# start test flex-table #}
|
||||||
{{ accompanyingCourse.id }}
|
<div class="flex-table">
|
||||||
{{ accompanyingCourse.openingDate|format_date('short') }}
|
{% for p in accompanyingCourse.participations %}
|
||||||
{{ accompanyingCourse.closingDate|format_date('short') }}
|
<div class="item-bloc">
|
||||||
{{ accompanyingCourse.closingMotive|chill_entity_render_box }}
|
<div class="item-row">
|
||||||
{{ accompanyingCourse.remark|raw }}
|
<div class="item-col">
|
||||||
{{ accompanyingCourse.user }}
|
<h3>
|
||||||
usagers:
|
<a href="{{ path('chill_person_accompanying_period_list', { person_id: p.person.id }) }}">
|
||||||
{% for p in accompanyingCourse.participations %}
|
{{ p.person.firstname ~ ' ' ~ p.person.lastname }}
|
||||||
{{ p.person.id }} | <a href="{{ path('chill_person_accompanying_period_list', { person_id: p.person.id }) }}">{{ p.person.fullnamecanonical }}</a> | {{ p.startdate|format_date('short') }} | {{ p.enddate|format_date('short') }}
|
</a>
|
||||||
{% endfor %}
|
</h3>
|
||||||
</pre>
|
<p>
|
||||||
|
<i class="fa fa-fw fa-venus" title="Femme"></i>
|
||||||
|
{{ 'Née le ' ~ p.person.birthdate|format_date('short') }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="item-col">
|
||||||
|
<ul class="list-content fa-ul">
|
||||||
|
<li><i class="fa fa-li fa-calendar"></i>
|
||||||
|
{{ p.startdate|format_date('short') }} → {{ p.enddate|format_date('short') }}
|
||||||
|
</li>
|
||||||
|
<li><i class="fa fa-li fa-mobile"></i>
|
||||||
|
+32 488 660 685
|
||||||
|
</li>
|
||||||
|
<li><i class="fa fa-li fa-envelope-o"></i>
|
||||||
|
robert@brisefeuille.fake.co
|
||||||
|
</li>
|
||||||
|
<li><i class="fa fa-li fa-map-marker"></i>
|
||||||
|
59, avenue Fernandez 79, boulevard Laurence Levy 1210 Saint-josse-ten-noode Belgique
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<ul class="record_actions">
|
||||||
|
<li><button type="button" class="sc-button bt-show"></button></li>
|
||||||
|
<li><button type="button" class="sc-button bt-edit"></button></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
{{ dump() }}
|
</div>
|
||||||
|
<div class="item-row">
|
||||||
|
Lorem ipsum dolor sit amet, incididunt ut labore et dolore magna aliqua.
|
||||||
|
</div>
|
||||||
|
<div class="item-row">
|
||||||
|
Rhoncus est pellentesque elit eu ultrices vitae auctor.
|
||||||
|
</div>
|
||||||
|
<div class="item-row">
|
||||||
|
Facilisis gravida neque convallis a cras semper auctor neque.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{# end test flex-table #}
|
||||||
|
|
||||||
|
|
||||||
|
{# ==> insert accompanyingCourse vue component #}
|
||||||
|
<div id="accompanying-course"></div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
{% extends 'ChillPersonBundle:AccompanyingCourse:layout.html.twig' %}
|
{% extends 'ChillPersonBundle:AccompanyingCourse:layout.html.twig' %}
|
||||||
|
{% import '@ChillMain/Address/macro.html.twig' as address %}
|
||||||
|
|
||||||
{% block title %}
|
{% block title %}
|
||||||
{{ 'Resume Accompanying Course'|trans }}
|
{{ 'Resume Accompanying Course'|trans }}
|
||||||
@ -10,19 +11,168 @@
|
|||||||
<div class="grid-8 centered error flash_message">
|
<div class="grid-8 centered error flash_message">
|
||||||
<span>
|
<span>
|
||||||
{{ 'This accompanying course is still a draft'|trans }}
|
{{ 'This accompanying course is still a draft'|trans }}
|
||||||
<a href="{{ path('chill_person_accompanying_course_show', { 'accompanying_period_id': accompanyingCourse.id } ) }}">
|
<a href="{{ path('chill_person_accompanying_course_edit', { 'accompanying_period_id': accompanyingCourse.id } ) }}">
|
||||||
{{ 'Edit & activate accompanying course'|trans }}
|
{{ 'Edit & activate accompanying course'|trans }}
|
||||||
</a>
|
</a>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<h1>{{ 'Associated peoples'|trans }}</h1>
|
<h2>{{ 'Associated peoples'|trans }}</h2>
|
||||||
|
<div class="flex-table">
|
||||||
|
{% for p in accompanyingCourse.participations %}
|
||||||
|
{% if p.enddate is null %}
|
||||||
|
<div class="item-bloc">
|
||||||
|
<div class="item-row">
|
||||||
|
<div class="item-col">
|
||||||
|
<h3>{{ p.person.firstname ~ ' ' ~ p.person.lastname }}</h3>
|
||||||
|
<p>
|
||||||
|
{% set born = (p.person.gender == 'woman') ? 'née': 'né' %}
|
||||||
|
{% set gender = (p.person.gender == 'woman') ? 'fa-venus' :
|
||||||
|
(p.person.gender == 'man') ? 'fa-mars' : 'fa-neuter' %}
|
||||||
|
{% set genderTitle = (p.person.gender == 'woman') ? 'femme' :
|
||||||
|
(p.person.gender == 'homme') ? 'fa-mars' : 'neutre' %}
|
||||||
|
<i class="fa fa-fw {{ gender }}" title="{{ genderTitle }}"></i>{{ born ~ ' le ' ~ p.person.birthdate|format_date('short') }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="item-col">
|
||||||
|
<ul class="list-content fa-ul">
|
||||||
|
<li>
|
||||||
|
{% if p.person.mobilenumber %}
|
||||||
|
<i class="fa fa-li fa-mobile"></i><a href="{{ 'tel:' ~ p.person.mobilenumber }}">{{ p.person.mobilenumber }}</a>
|
||||||
|
{% else %}
|
||||||
|
<i class="fa fa-li fa-phone"></i>
|
||||||
|
{% if p.person.phonenumber %}
|
||||||
|
<a href="{{ 'tel:' ~ p.person.phonenumber }}">{{ p.person.phonenumber }}</a>
|
||||||
|
{% else %}
|
||||||
|
<span class="chill-no-data-statement">{{ 'No data given'|trans }}</span>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<i class="fa fa-li fa-map-marker"></i>
|
||||||
|
{%- if p.person.lastAddress is not empty -%}
|
||||||
|
{{ p.person.getLastAddress|chill_entity_render_box({'with_valid_from': false}) }}
|
||||||
|
{%- else -%}
|
||||||
|
<span class="chill-no-data-statement">{{ 'No address given'|trans }}</span>
|
||||||
|
{%- endif -%}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<ul class="record_actions">
|
||||||
|
<li>
|
||||||
|
<a href="{{ path('chill_person_view', { person_id: p.person.id }) }}" class="sc-button bt-show" target="_blank" title="Voir"></a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
|
||||||
<h1>{{ 'Resources'|trans }}</h1>
|
|
||||||
|
|
||||||
<h1>{{ 'Social actions'|trans }}</h1>
|
<h2>{{ 'Resources'|trans }}</h2>
|
||||||
|
<div class="flex-bloc">
|
||||||
|
{% for r in accompanyingCourse.resources %}
|
||||||
|
<div class="item-bloc">
|
||||||
|
{% if r.person %}
|
||||||
|
|
||||||
<h1>{{ 'Last events on accompanying course'|trans }}</h1>
|
<div class="item-row">
|
||||||
|
<div class="item-col">
|
||||||
|
<h3>
|
||||||
|
{{ r.person.firstname ~ ' ' ~ r.person.lastname }}
|
||||||
|
<span class="badge badge-pill badge-secondary">{{ 'Usager' }}</span>
|
||||||
|
</h3>
|
||||||
|
<p>
|
||||||
|
{% set born = (r.person.gender == 'woman') ? 'née': 'né' %}
|
||||||
|
{% set gender = (r.person.gender == 'woman') ? 'fa-venus' :
|
||||||
|
(r.person.gender == 'man') ? 'fa-mars' : 'fa-neuter' %}
|
||||||
|
{% set genderTitle = (r.person.gender == 'woman') ? 'femme' :
|
||||||
|
(r.person.gender == 'homme') ? 'fa-mars' : 'neutre' %}
|
||||||
|
<i class="fa fa-fw {{ gender }}" title="{{ genderTitle }}"></i>{{ born ~ ' le ' ~ r.person.birthdate|format_date('short') }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="item-col">
|
||||||
|
<ul class="list-content fa-ul">
|
||||||
|
<li>
|
||||||
|
{% if r.person.mobilenumber %}
|
||||||
|
<i class="fa fa-li fa-mobile"></i><a href="{{ 'tel:' ~ r.person.mobilenumber }}">{{ r.person.mobilenumber }}</a>
|
||||||
|
{% else %}
|
||||||
|
<i class="fa fa-li fa-phone"></i>
|
||||||
|
{% if r.person.phonenumber %}
|
||||||
|
<a href="{{ 'tel:' ~ r.person.phonenumber }}">{{ r.person.phonenumber }}</a>
|
||||||
|
{% else %}
|
||||||
|
<span class="chill-no-data-statement">{{ 'No data given'|trans }}</span>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<i class="fa fa-li fa-map-marker"></i>
|
||||||
|
{%- if r.person.lastAddress is not empty -%}
|
||||||
|
{{ r.person.getLastAddress|chill_entity_render_box({'with_valid_from': false}) }}
|
||||||
|
{%- else -%}
|
||||||
|
<span class="chill-no-data-statement">{{ 'No address given'|trans }}</span>
|
||||||
|
{%- endif -%}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<ul class="record_actions">
|
||||||
|
<li>
|
||||||
|
<a href="{{ path('chill_person_view', { person_id: r.person.id }) }}" class="sc-button bt-show" target="_blank" title="Voir"></a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
{% if r.thirdParty %}
|
||||||
|
|
||||||
|
<div class="item-row">
|
||||||
|
<div class="item-col">
|
||||||
|
<h3>
|
||||||
|
{{ r.thirdParty.name }}
|
||||||
|
<span class="badge badge-pill badge-secondary">{{ 'Tiers' }}</span>
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
<div class="item-col">
|
||||||
|
<ul class="list-content fa-ul">
|
||||||
|
<li><i class="fa fa-li fa-envelope-o"></i>
|
||||||
|
<a href="{{ 'mailto:' ~ r.thirdParty.email }}">
|
||||||
|
{{ r.thirdParty.email|chill_print_or_message("thirdparty.No_email") }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li><i class="fa fa-li fa-phone"></i>
|
||||||
|
{% if r.thirdParty.telephone %}
|
||||||
|
<a href="{{ 'tel:' ~ r.thirdParty.telephone }}">{{ r.thirdParty.telephone }}</a>
|
||||||
|
{% else %}
|
||||||
|
<span class="chill-no-data-statement">{{ 'thirdparty.No_phonenumber'|trans }}</span>
|
||||||
|
{% endif %}
|
||||||
|
</li>
|
||||||
|
<li><i class="fa fa-li fa-map-marker"></i>
|
||||||
|
{%- if r.thirdParty.address is not empty -%}
|
||||||
|
{{ r.thirdParty.getAddress|chill_entity_render_box({'with_valid_from': false}) }}
|
||||||
|
{%- else -%}
|
||||||
|
<span class="chill-no-data-statement">{{ 'No address given'|trans }}</span>
|
||||||
|
{%- endif -%}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<ul class="record_actions">
|
||||||
|
<li>
|
||||||
|
<a href="{{ path('chill_3party_3party_show', { thirdparty_id: r.thirdParty.id }) }}" class="sc-button bt-show" target="_blank" title="Voir"></a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2>{{ 'Social actions'|trans }}</h2>
|
||||||
|
|
||||||
|
<h2>{{ 'Last events on accompanying course'|trans }}</h2>
|
||||||
|
|
||||||
|
|
||||||
|
{# ==> insert accompanyingCourse vue component #}
|
||||||
|
<div id="accompanying-course"></div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -16,7 +16,13 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block css %}
|
{% block css %}
|
||||||
|
{{ encore_entry_link_tags('accompanying_course') }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block js %}
|
{% block js %}
|
||||||
|
<script type="text/javascript">
|
||||||
|
window.accompanyingCourseId = {{ accompanyingCourse.id|e('js') }};
|
||||||
|
window.vueRootComponent = 'banner';
|
||||||
|
</script>
|
||||||
|
{{ encore_entry_script_tags('accompanying_course') }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -0,0 +1,15 @@
|
|||||||
|
<span class="chill-entity chill-entity__person">
|
||||||
|
{%- if addLink and is_granted('CHILL_PERSON_SEE', person) -%}
|
||||||
|
{%- set showLink = true -%}<a href="{{ chill_path_add_return_path('chill_person_view', { 'person_id': person.id }) }}">{%- endif -%}
|
||||||
|
<span class="chill-entity__person__first-name">{{ person.firstName }}</span>
|
||||||
|
<span class="chill-entity__person__last-name">{{ person.lastName }}</span>
|
||||||
|
{%- if addAltNames -%}
|
||||||
|
{%- for n in person.altNames -%}
|
||||||
|
{%- if loop.first -%}({% else %} {%- endif -%}
|
||||||
|
<span class="chill-entity__person__alt-name chill-entity__person__altname--{{ n.key }}">
|
||||||
|
{{ n.label }}
|
||||||
|
</span>
|
||||||
|
{%- if loop.last %}) {% endif -%}
|
||||||
|
{%- endfor -%}
|
||||||
|
{%- endif -%}
|
||||||
|
{%- if showLink is defined -%}</a>{%- endif -%}</span>
|
@ -0,0 +1,13 @@
|
|||||||
|
{% set reversed_parents = parents|reverse %}
|
||||||
|
<span class="chill-entity chill-entity__social-issue">
|
||||||
|
<span class="badge badge-primary">
|
||||||
|
{%- for p in reversed_parents %}
|
||||||
|
<span class="chill-entity__social-issue__parent--{{ loop.revindex0 }}">
|
||||||
|
{{ p.title|localize_translatable_string }}{{ options['default.separator'] }}
|
||||||
|
</span>
|
||||||
|
{%- endfor -%}
|
||||||
|
<span class="chill-entity__social-issue__child">
|
||||||
|
{{ socialIssue.title|localize_translatable_string }}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</span>
|
@ -0,0 +1,178 @@
|
|||||||
|
<h2>{{ title|default('Person search results')|trans }}</h2>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
{{ '%total% persons matching the search pattern:'|transchoice( total, { '%total%' : total}) }}
|
||||||
|
<a href="{{ path('chill_main_advanced_search', { "name": search_name, "q": pattern } ) }}" class="sc-button button-small">
|
||||||
|
<i class="fa fa-fw fa-search" aria-hidden="true"></i> {{ pattern }}
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>{{ 'Results %start%-%end% of %total%'|trans({ '%start%' : start, '%end%': start + persons|length, '%total%' : total } ) }}</p>
|
||||||
|
|
||||||
|
<ul class="record_actions">
|
||||||
|
{% if is_granted('CHILL_PERSON_CREATE') %}
|
||||||
|
<li>
|
||||||
|
<a href="{{ path('chill_person_new') }}" class="sc-button bt-create">
|
||||||
|
{{ 'Add a person'|trans }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
{% if search_name != "person_similarity" %}
|
||||||
|
<li>
|
||||||
|
<a href="{{ path('chill_main_advanced_search', { "name": search_name, "q": pattern } ) }}" class="sc-button bt-action">
|
||||||
|
<i class="fa fa-fw fa-search" aria-hidden="true"></i>
|
||||||
|
{{ 'Advanced search'|trans }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
{% if preview == true and persons | length < total %}
|
||||||
|
<li>
|
||||||
|
<a href="{{ path('chill_main_search', { "name": search_name|default('abcd'), "q" : pattern }) }}" class="sc-button">
|
||||||
|
{{ 'See all results'|trans }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
{% if persons|length > 0 %}
|
||||||
|
|
||||||
|
<div class="flex-table list-with-period">
|
||||||
|
{% for person in persons %}
|
||||||
|
|
||||||
|
<div class="item-bloc">
|
||||||
|
<div class="item-row person">
|
||||||
|
|
||||||
|
<div class="item-col box-person">
|
||||||
|
<div>{{ person|chill_entity_render_box({'addLink': true}) }}</div>
|
||||||
|
<div>{{ 'Born the %date%'|transchoice(person.genderNumeric, { '%date%': person.birthdate|format_date("medium") }) }}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="item-col box-where">
|
||||||
|
<ul class="list-content fa-ul">
|
||||||
|
<li><i class="fa fa-li fa-long-arrow-right"></i>
|
||||||
|
{{ person.center }}
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li>
|
||||||
|
{% if person.mobilenumber is not empty %}
|
||||||
|
<i class="fa fa-li fa-mobile"></i> <a href="{{ 'tel:' ~ person.mobilenumber }}">{{ person.mobilenumber|chill_format_phonenumber }}</a>
|
||||||
|
{% else %}
|
||||||
|
<i class="fa fa-li fa-phone"></i>
|
||||||
|
{% if person.phonenumber is not empty %}
|
||||||
|
<a href="{{ 'tel:' ~ person.phonenumber }}">{{ person.phonenumber|chill_format_phonenumber }}</a>
|
||||||
|
{% else %}
|
||||||
|
<span class="chill-no-data-statement">{{ 'No data given'|trans }}</span>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li>
|
||||||
|
<i class="fa fa-li fa-map-marker"></i>
|
||||||
|
{% if person.getLastAddress is not null %}
|
||||||
|
{{ person.getLastAddress|chill_entity_render_box({'with_valid_from': false}) }}
|
||||||
|
{% else %}
|
||||||
|
<span class="chill-no-data-statement">{{ 'No address'|trans }}</span>
|
||||||
|
{% endif %}
|
||||||
|
</li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
<ul class="record_actions">
|
||||||
|
<li>
|
||||||
|
<a href="{{ path('chill_person_view', { 'person_id' : person.id }) }}" class="sc-button blue" />
|
||||||
|
<i class="fa fa-folder-open-o"></i> {{ 'Open person file'|trans }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="{{ path('chill_person_accompanying_period_list', { 'person_id' : person.id }) }}" class="sc-button green" title="{{ 'See accompanying periods'|trans }}"/>
|
||||||
|
<i class="fa fa-random"></i></a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{#- 'apps' is for AccompanyingPeriodParticipationS #}
|
||||||
|
{#- filter using acl -#}
|
||||||
|
{%- set apps = [] %}
|
||||||
|
{%- for app in person.openedParticipations %}
|
||||||
|
{%- if is_granted('CHILL_PERSON_ACCOMPANYING_PERIOD_SEE', app.accompanyingPeriod) %}
|
||||||
|
{%- set apps = apps|merge([app]) %}
|
||||||
|
{%- endif %}
|
||||||
|
{%- endfor %}
|
||||||
|
|
||||||
|
{% if apps|length > 0 %}
|
||||||
|
{% for app in apps %}
|
||||||
|
<div class="item-row periods">
|
||||||
|
|
||||||
|
<div class="header">
|
||||||
|
<a href="{{ path('chill_person_accompanying_course_index', { 'accompanying_period_id': app.accompanyingPeriod.id }) }}"
|
||||||
|
class="sc-button green" title="{{ 'See accompanying period'|trans }}">
|
||||||
|
<i class="fa fa-fw fa-random"></i>
|
||||||
|
</a>
|
||||||
|
<span>{{ 'Since %date%'|trans({'%date%': app.startDate|format_date('medium') }) }}</span>
|
||||||
|
{% if app.accompanyingPeriod.user is not null %}
|
||||||
|
<span class="user">
|
||||||
|
<abbr class="referrer" title="{{ 'Referrer'|trans }}">ref:</abbr>
|
||||||
|
{{ app.accompanyingPeriod.user|chill_entity_render_box }}
|
||||||
|
</span>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="list-content">
|
||||||
|
{% for issue in app.accompanyingPeriod.socialIssues|slice(0,2) %}
|
||||||
|
<span>{{ issue|chill_entity_render_box }}</span>
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
{% if app.accompanyingPeriod.socialIssues|length > 2 %}
|
||||||
|
<span class="more">{{ 'and %number% other'|transchoice(app.accompanyingPeriod.socialIssues|length-2) }}</span>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ul class="record_actions">
|
||||||
|
{% if is_granted('CHILL_PERSON_CREATE') %}
|
||||||
|
<li>
|
||||||
|
<a href="{{ path('chill_person_new') }}" class="sc-button bt-create">
|
||||||
|
{{ 'Add a person'|trans }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
{% if search_name != "person_similarity" %}
|
||||||
|
<li>
|
||||||
|
<a href="{{ path('chill_main_advanced_search', { "name": search_name, "q": pattern } ) }}" class="sc-button bt-action">
|
||||||
|
<i class="fa fa-fw fa-search" aria-hidden="true"></i> {{ 'Advanced search'|trans }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
{% if preview == true and persons|length < total %}
|
||||||
|
<li>
|
||||||
|
<a href="{{ path('chill_main_search', { "name": search_name|default('abcd'), "q" : pattern }) }}" class="sc-button">
|
||||||
|
{{ 'See all results'|trans }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
{% else %}
|
||||||
|
<ul class="record_actions">
|
||||||
|
<li>
|
||||||
|
<a href="{{ path('chill_main_advanced_search', { "name": search_name, "q": pattern } ) }}" class="sc-button bt-action">
|
||||||
|
<i class="fa fa-fw fa-search" aria-hidden="true"></i> {{ 'Advanced search'|trans }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if preview == false %}
|
||||||
|
{{ chill_pagination(paginator) }}
|
||||||
|
{% endif %}
|
@ -120,7 +120,7 @@ class PersonSearch extends AbstractSearch implements ContainerAwareInterface,
|
|||||||
$paginator = $this->paginatorFactory->create($total);
|
$paginator = $this->paginatorFactory->create($total);
|
||||||
|
|
||||||
if ($format === 'html') {
|
if ($format === 'html') {
|
||||||
return $this->container->get('templating')->render('ChillPersonBundle:Person:list.html.twig',
|
return $this->container->get('templating')->render('@ChillPerson/Person/list_with_period.html.twig',
|
||||||
array(
|
array(
|
||||||
'persons' => $this->search($terms, $start, $limit, $options),
|
'persons' => $this->search($terms, $start, $limit, $options),
|
||||||
'pattern' => $this->recomposePattern($terms, array('nationality',
|
'pattern' => $this->recomposePattern($terms, array('nationality',
|
||||||
|
@ -18,7 +18,11 @@
|
|||||||
*/
|
*/
|
||||||
namespace Chill\PersonBundle\Serializer\Normalizer;
|
namespace Chill\PersonBundle\Serializer\Normalizer;
|
||||||
|
|
||||||
|
use Chill\MainBundle\Entity\Center;
|
||||||
use Chill\PersonBundle\Entity\Person;
|
use Chill\PersonBundle\Entity\Person;
|
||||||
|
use Symfony\Component\Serializer\Normalizer\DenormalizerAwareInterface;
|
||||||
|
use Symfony\Component\Serializer\Normalizer\DenormalizerAwareTrait;
|
||||||
|
use Symfony\Component\Serializer\Normalizer\NormalizerAwareTrait;
|
||||||
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
|
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
|
||||||
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
|
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
|
||||||
use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface;
|
use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface;
|
||||||
@ -27,6 +31,7 @@ use Symfony\Component\Serializer\Exception\RuntimeException;
|
|||||||
use Symfony\Component\Serializer\Exception\UnexpectedValueException;
|
use Symfony\Component\Serializer\Exception\UnexpectedValueException;
|
||||||
use Chill\MainBundle\Templating\Entity\ChillEntityRenderExtension;
|
use Chill\MainBundle\Templating\Entity\ChillEntityRenderExtension;
|
||||||
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
|
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
|
||||||
|
use Symfony\Component\Serializer\Normalizer\ObjectToPopulateTrait;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Serialize a Person entity
|
* Serialize a Person entity
|
||||||
@ -34,16 +39,24 @@ use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
|
|||||||
*/
|
*/
|
||||||
class PersonNormalizer implements
|
class PersonNormalizer implements
|
||||||
NormalizerInterface,
|
NormalizerInterface,
|
||||||
NormalizerAwareInterface
|
NormalizerAwareInterface,
|
||||||
|
DenormalizerInterface,
|
||||||
|
DenormalizerAwareInterface
|
||||||
{
|
{
|
||||||
|
|
||||||
protected NormalizerInterface $normalizer;
|
|
||||||
|
|
||||||
private ChillEntityRenderExtension $render;
|
private ChillEntityRenderExtension $render;
|
||||||
|
|
||||||
public function __construct(ChillEntityRenderExtension $render)
|
private PersonRepository $repository;
|
||||||
|
|
||||||
|
use NormalizerAwareTrait;
|
||||||
|
|
||||||
|
use ObjectToPopulateTrait;
|
||||||
|
|
||||||
|
use DenormalizerAwareTrait;
|
||||||
|
|
||||||
|
public function __construct(ChillEntityRenderExtension $render, PersonRepository $repository)
|
||||||
{
|
{
|
||||||
$this->render = $render;
|
$this->render = $render;
|
||||||
|
$this->repository = $repository;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function normalize($person, string $format = null, array $context = array())
|
public function normalize($person, string $format = null, array $context = array())
|
||||||
@ -59,7 +72,9 @@ class PersonNormalizer implements
|
|||||||
'center' => $this->normalizer->normalize($person->getCenter()),
|
'center' => $this->normalizer->normalize($person->getCenter()),
|
||||||
'phonenumber' => $person->getPhonenumber(),
|
'phonenumber' => $person->getPhonenumber(),
|
||||||
'mobilenumber' => $person->getMobilenumber(),
|
'mobilenumber' => $person->getMobilenumber(),
|
||||||
'altNames' => $this->normalizeAltNames($person->getAltNames())
|
'altNames' => $this->normalizeAltNames($person->getAltNames()),
|
||||||
|
'gender' => $person->getGender(),
|
||||||
|
'gender_numeric' => $person->getGenderNumeric(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,9 +95,50 @@ class PersonNormalizer implements
|
|||||||
return $data instanceof Person;
|
return $data instanceof Person;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function denormalize($data, string $type, string $format = null, array $context = [])
|
||||||
public function setNormalizer(NormalizerInterface $normalizer)
|
|
||||||
{
|
{
|
||||||
$this->normalizer = $normalizer;
|
$person = $this->extractObjectToPopulate($type, $context);
|
||||||
|
|
||||||
|
if (\array_key_exists('id', $data)) {
|
||||||
|
$person = $this->repository->find($data['id']);
|
||||||
|
|
||||||
|
if (null === $person) {
|
||||||
|
throw new UnexpectedValueException("The person with id \"{$data['id']}\" does ".
|
||||||
|
"not exists");
|
||||||
|
}
|
||||||
|
// currently, not allowed to update a person through api
|
||||||
|
// if instantiated with id
|
||||||
|
return $person;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null === $person) {
|
||||||
|
$person = new Person();
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (['firstName', 'lastName', 'phonenumber', 'mobilenumber', 'gender']
|
||||||
|
as $item) {
|
||||||
|
if (\array_key_exists($item, $data)) {
|
||||||
|
$person->{'set'.\ucfirst($item)}($data[$item]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ([
|
||||||
|
'birthdate' => \DateTime::class,
|
||||||
|
'center' => Center::class
|
||||||
|
] as $item => $class) {
|
||||||
|
if (\array_key_exists($item, $data)) {
|
||||||
|
$object = $this->denormalizer->denormalize($data[$item], $class, $format, $context);
|
||||||
|
if ($object instanceof $class) {
|
||||||
|
$person->{'set'.\ucfirst($item)}($object);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $person;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function supportsDenormalization($data, string $type, string $format = null)
|
||||||
|
{
|
||||||
|
return $type === Person::class && ($data['type'] ?? NULL) === 'person';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,10 +5,12 @@ namespace Chill\PersonBundle\Templating\Entity;
|
|||||||
use Chill\MainBundle\Templating\Entity\ChillEntityRenderInterface;
|
use Chill\MainBundle\Templating\Entity\ChillEntityRenderInterface;
|
||||||
use Chill\PersonBundle\Entity\SocialWork\SocialIssue;
|
use Chill\PersonBundle\Entity\SocialWork\SocialIssue;
|
||||||
use Chill\MainBundle\Templating\TranslatableStringHelper;
|
use Chill\MainBundle\Templating\TranslatableStringHelper;
|
||||||
|
use Symfony\Component\Templating\EngineInterface;
|
||||||
|
|
||||||
class SocialIssueRender implements ChillEntityRenderInterface
|
class SocialIssueRender implements ChillEntityRenderInterface
|
||||||
{
|
{
|
||||||
private TranslatableStringHelper $translatableStringHelper;
|
private TranslatableStringHelper $translatableStringHelper;
|
||||||
|
private EngineInterface $engine;
|
||||||
|
|
||||||
public const SEPARATOR_KEY = 'default.separator';
|
public const SEPARATOR_KEY = 'default.separator';
|
||||||
|
|
||||||
@ -16,14 +18,15 @@ class SocialIssueRender implements ChillEntityRenderInterface
|
|||||||
self::SEPARATOR_KEY => ' > ',
|
self::SEPARATOR_KEY => ' > ',
|
||||||
];
|
];
|
||||||
|
|
||||||
public function __construct(TranslatableStringHelper $translatableStringHelper)
|
public function __construct(TranslatableStringHelper $translatableStringHelper, EngineInterface $engine)
|
||||||
{
|
{
|
||||||
$this->translatableStringHelper = $translatableStringHelper;
|
$this->translatableStringHelper = $translatableStringHelper;
|
||||||
|
$this->engine = $engine;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function supports($entity, array $options): bool
|
public function supports($entity, array $options): bool
|
||||||
{
|
{
|
||||||
return $entity instanceof SocialIssueRender;
|
return $entity instanceof SocialIssue;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function renderString($socialIssue, array $options): string
|
public function renderString($socialIssue, array $options): string
|
||||||
@ -43,8 +46,26 @@ class SocialIssueRender implements ChillEntityRenderInterface
|
|||||||
return $str;
|
return $str;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function renderBox($entity, array $options): string
|
protected function buildParents($socialIssue): array
|
||||||
{
|
{
|
||||||
return "renderBox not implemented for social issue";
|
$parents = [];
|
||||||
|
while ($socialIssue->hasParent()) {
|
||||||
|
$socialIssue = $parents[] = $socialIssue->getParent();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $parents;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function renderBox($socialIssue, array $options): string
|
||||||
|
{
|
||||||
|
$options = \array_merge(self::DEFAULT_ARGS, $options);
|
||||||
|
// give some help to twig: an array of parents
|
||||||
|
$parents = $this->buildParents($socialIssue);
|
||||||
|
|
||||||
|
return $this->engine->render('@ChillPerson/Entity/social_issue.html.twig', [
|
||||||
|
'socialIssue' => $socialIssue,
|
||||||
|
'parents' => $parents,
|
||||||
|
'options' => $options
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,83 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Chill\PersonBundle\Tests\Controller;
|
||||||
|
|
||||||
|
use Chill\MainBundle\Test\PrepareClientTrait;
|
||||||
|
use Chill\PersonBundle\Entity\Person;
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||||
|
|
||||||
|
class PersonApiControllerTest extends WebTestCase
|
||||||
|
{
|
||||||
|
use PrepareClientTrait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider dataGetPersonFromCenterB
|
||||||
|
*/
|
||||||
|
public function testPersonGetUnauthorized($personId): void
|
||||||
|
{
|
||||||
|
$client = $this->getClientAuthenticated();
|
||||||
|
|
||||||
|
$client->request(Request::METHOD_GET, "/api/1.0/person/person/{$personId}.json");
|
||||||
|
$response = $client->getResponse();
|
||||||
|
|
||||||
|
$this->assertEquals(403, $response->getStatusCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider dataGetPersonFromCenterA
|
||||||
|
*/
|
||||||
|
public function testPersonGet($personId): void
|
||||||
|
{
|
||||||
|
$client = $this->getClientAuthenticated();
|
||||||
|
|
||||||
|
$client->request(Request::METHOD_GET, "/api/1.0/person/person/{$personId}.json");
|
||||||
|
$response = $client->getResponse();
|
||||||
|
|
||||||
|
$this->assertResponseIsSuccessful();
|
||||||
|
|
||||||
|
$data = \json_decode($client->getResponse()->getContent(), true);
|
||||||
|
|
||||||
|
$this->assertArrayHasKey('type', $data);
|
||||||
|
$this->assertArrayHasKey('id', $data);
|
||||||
|
$this->assertEquals('person', $data['type']);
|
||||||
|
$this->assertEquals($personId, $data['id']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function dataGetPersonFromCenterA(): \Iterator
|
||||||
|
{
|
||||||
|
self::bootKernel();
|
||||||
|
$em = self::$container->get(EntityManagerInterface::class);
|
||||||
|
$personIds= $em->createQuery("SELECT p.id FROM ".Person::class." p ".
|
||||||
|
"JOIN p.center c ".
|
||||||
|
"WHERE c.name = :center")
|
||||||
|
->setParameter('center', 'Center A')
|
||||||
|
->setMaxResults(100)
|
||||||
|
->getScalarResult()
|
||||||
|
;
|
||||||
|
|
||||||
|
\shuffle($personIds);
|
||||||
|
|
||||||
|
yield \array_pop($personIds);
|
||||||
|
yield \array_pop($personIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function dataGetPersonFromCenterB(): \Iterator
|
||||||
|
{
|
||||||
|
self::bootKernel();
|
||||||
|
$em = self::$container->get(EntityManagerInterface::class);
|
||||||
|
$personIds= $em->createQuery("SELECT p.id FROM ".Person::class." p ".
|
||||||
|
"JOIN p.center c ".
|
||||||
|
"WHERE c.name = :center")
|
||||||
|
->setParameter('center', 'Center B')
|
||||||
|
->setMaxResults(100)
|
||||||
|
->getScalarResult()
|
||||||
|
;
|
||||||
|
|
||||||
|
\shuffle($personIds);
|
||||||
|
|
||||||
|
yield \array_pop($personIds);
|
||||||
|
yield \array_pop($personIds);
|
||||||
|
}
|
||||||
|
}
|
@ -23,6 +23,7 @@
|
|||||||
namespace Chill\PersonBundle\Tests\Entity;
|
namespace Chill\PersonBundle\Tests\Entity;
|
||||||
|
|
||||||
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||||
|
use Chill\PersonBundle\Entity\AccompanyingPeriodParticipation;
|
||||||
use Chill\PersonBundle\Entity\Person;
|
use Chill\PersonBundle\Entity\Person;
|
||||||
use Chill\ThirdPartyBundle\Entity\ThirdParty;
|
use Chill\ThirdPartyBundle\Entity\ThirdParty;
|
||||||
use Chill\PersonBundle\Entity\AccompanyingPeriod\Comment;
|
use Chill\PersonBundle\Entity\AccompanyingPeriod\Comment;
|
||||||
@ -85,10 +86,11 @@ class AccompanyingPeriodTest extends \PHPUnit\Framework\TestCase
|
|||||||
$person3 = new Person();
|
$person3 = new Person();
|
||||||
$period = new AccompanyingPeriod(new \DateTime());
|
$period = new AccompanyingPeriod(new \DateTime());
|
||||||
|
|
||||||
$period->addPerson($person);
|
$participation0 = $period->createParticipationFor($person);
|
||||||
$period->addPerson($person2);
|
$period->createParticipationFor($person2);
|
||||||
$period->addPerson($person3);
|
$period->createParticipationFor($person3);
|
||||||
|
|
||||||
|
$this->assertNotNull($participation0);
|
||||||
$this->assertEquals(3, $period->getParticipations()->count());
|
$this->assertEquals(3, $period->getParticipations()->count());
|
||||||
$this->assertTrue($period->containsPerson($person));
|
$this->assertTrue($period->containsPerson($person));
|
||||||
$this->assertFalse($period->containsPerson(new Person()));
|
$this->assertFalse($period->containsPerson(new Person()));
|
||||||
@ -97,14 +99,28 @@ class AccompanyingPeriodTest extends \PHPUnit\Framework\TestCase
|
|||||||
$participations = $period->getParticipationsContainsPerson($person);
|
$participations = $period->getParticipationsContainsPerson($person);
|
||||||
$this->assertNotNull($participation);
|
$this->assertNotNull($participation);
|
||||||
$this->assertSame($person, $participation->getPerson());
|
$this->assertSame($person, $participation->getPerson());
|
||||||
|
$this->assertSame($participation, $participation0);
|
||||||
$this->assertEquals(1, $participations->count());
|
$this->assertEquals(1, $participations->count());
|
||||||
|
|
||||||
$participationL = $period->removePerson($person);
|
$participationL = $period->closeParticipationFor($person);
|
||||||
$this->assertSame($participationL, $participation);
|
$this->assertSame($participationL, $participation);
|
||||||
$this->assertTrue($participation->getEndDate() instanceof \DateTimeInterface);
|
$this->assertTrue($participation->getEndDate() instanceof \DateTimeInterface);
|
||||||
|
|
||||||
$participation = $period->getOpenParticipationContainsPerson($person);
|
$participation = $period->getOpenParticipationContainsPerson($person);
|
||||||
$this->assertNull($participation);
|
$this->assertNull($participation);
|
||||||
|
|
||||||
|
$person4 = new Person();
|
||||||
|
$participations4 = $period->getParticipationsContainsPerson($person4);
|
||||||
|
$this->assertEquals(0, $participations4->count());
|
||||||
|
$participation4 = $period->getOpenParticipationContainsPerson($person4);
|
||||||
|
$this->assertNull($participation4);
|
||||||
|
|
||||||
|
$period->addPerson($person4);
|
||||||
|
$this->assertInstanceOf(AccompanyingPeriodParticipation::class, $period->getOpenParticipationContainsPerson($person4));
|
||||||
|
$this->assertEquals(1, $period->getParticipationsContainsPerson($person4)->count());
|
||||||
|
$period->removePerson($person4);
|
||||||
|
$this->assertNull($period->getOpenParticipationContainsPerson($person4));
|
||||||
|
$this->assertEquals(1, $period->getParticipationsContainsPerson($person4)->count());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testRequestor()
|
public function testRequestor()
|
||||||
|
@ -41,6 +41,11 @@ components:
|
|||||||
properties:
|
properties:
|
||||||
id:
|
id:
|
||||||
type: integer
|
type: integer
|
||||||
|
readOnly: true
|
||||||
|
type:
|
||||||
|
type: string
|
||||||
|
enum:
|
||||||
|
- 'person'
|
||||||
firstName:
|
firstName:
|
||||||
type: string
|
type: string
|
||||||
lastName:
|
lastName:
|
||||||
@ -48,12 +53,23 @@ components:
|
|||||||
text:
|
text:
|
||||||
type: string
|
type: string
|
||||||
description: a canonical representation for the person name
|
description: a canonical representation for the person name
|
||||||
|
readOnly: true
|
||||||
birthdate:
|
birthdate:
|
||||||
$ref: '#/components/schemas/Date'
|
$ref: '#/components/schemas/Date'
|
||||||
phonenumber:
|
phonenumber:
|
||||||
type: string
|
type: string
|
||||||
mobilenumber:
|
mobilenumber:
|
||||||
type: string
|
type: string
|
||||||
|
gender:
|
||||||
|
type: string
|
||||||
|
enum:
|
||||||
|
- man
|
||||||
|
- woman
|
||||||
|
- both
|
||||||
|
gender_numeric:
|
||||||
|
type: integer
|
||||||
|
description: a numerical representation of gender
|
||||||
|
readOnly: true
|
||||||
PersonById:
|
PersonById:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
@ -178,6 +194,53 @@ components:
|
|||||||
readOnly: true
|
readOnly: true
|
||||||
|
|
||||||
paths:
|
paths:
|
||||||
|
/1.0/person/person/{id}.json:
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- person
|
||||||
|
summary: Get a single person
|
||||||
|
parameters:
|
||||||
|
- name: id
|
||||||
|
in: path
|
||||||
|
required: true
|
||||||
|
description: The person's id
|
||||||
|
schema:
|
||||||
|
type: integer
|
||||||
|
format: integer
|
||||||
|
minimum: 1
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: "OK"
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/Person"
|
||||||
|
403:
|
||||||
|
description: "Unauthorized"
|
||||||
|
/1.0/person/person.json:
|
||||||
|
post:
|
||||||
|
tags:
|
||||||
|
- person
|
||||||
|
summary: Create a single person
|
||||||
|
requestBody:
|
||||||
|
description: "A person"
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Person'
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: "OK"
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/Person"
|
||||||
|
403:
|
||||||
|
description: "Unauthorized"
|
||||||
|
422:
|
||||||
|
description: "Invalid data: the data is a valid json, could be deserialized, but does not pass validation"
|
||||||
|
|
||||||
/1.0/person/social-work/social-issue.json:
|
/1.0/person/social-work/social-issue.json:
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
|
@ -53,3 +53,9 @@ services:
|
|||||||
$validator: '@Symfony\Component\Validator\Validator\ValidatorInterface'
|
$validator: '@Symfony\Component\Validator\Validator\ValidatorInterface'
|
||||||
$registry: '@Symfony\Component\Workflow\Registry'
|
$registry: '@Symfony\Component\Workflow\Registry'
|
||||||
tags: ['controller.service_arguments']
|
tags: ['controller.service_arguments']
|
||||||
|
|
||||||
|
Chill\PersonBundle\Controller\PersonApiController:
|
||||||
|
arguments:
|
||||||
|
$authorizationHelper: '@Chill\MainBundle\Security\Authorization\AuthorizationHelper'
|
||||||
|
tags: ['controller.service_arguments']
|
||||||
|
|
||||||
|
@ -13,7 +13,12 @@ services:
|
|||||||
Chill\PersonBundle\Templating\Entity\ClosingMotiveRender:
|
Chill\PersonBundle\Templating\Entity\ClosingMotiveRender:
|
||||||
arguments:
|
arguments:
|
||||||
$translatableStringHelper: '@Chill\MainBundle\Templating\TranslatableStringHelper'
|
$translatableStringHelper: '@Chill\MainBundle\Templating\TranslatableStringHelper'
|
||||||
|
tags:
|
||||||
|
- 'chill.render_entity'
|
||||||
|
|
||||||
Chill\PersonBundle\Templating\Entity\SocialIssueRender:
|
Chill\PersonBundle\Templating\Entity\SocialIssueRender:
|
||||||
arguments:
|
arguments:
|
||||||
$translatableStringHelper: '@Chill\MainBundle\Templating\TranslatableStringHelper'
|
$translatableStringHelper: '@Chill\MainBundle\Templating\TranslatableStringHelper'
|
||||||
|
$engine: '@Symfony\Component\Templating\EngineInterface'
|
||||||
|
tags:
|
||||||
|
- 'chill.render_entity'
|
||||||
|
@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Chill\Migrations\Person;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\Schema\Schema;
|
||||||
|
use Doctrine\Migrations\AbstractMigration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specify ON DELETE behaviour to handle deletion of parents in associated tables
|
||||||
|
*/
|
||||||
|
final class Version20210525211214 extends AbstractMigration
|
||||||
|
{
|
||||||
|
public function getDescription(): string
|
||||||
|
{
|
||||||
|
return 'Specify ON DELETE behaviour to handle deletion of parents in associated tables';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function up(Schema $schema): void
|
||||||
|
{
|
||||||
|
$this->addSql('ALTER TABLE chill_person_accompanying_period_comment DROP CONSTRAINT FK_CD960EF3D7FA8EF0');
|
||||||
|
$this->addSql('ALTER TABLE chill_person_accompanying_period_comment ADD CONSTRAINT FK_CD960EF3D7FA8EF0 FOREIGN KEY (accompanyingPeriod_id) REFERENCES chill_person_accompanying_period (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(Schema $schema): void
|
||||||
|
{
|
||||||
|
$this->addSql('ALTER TABLE chill_person_accompanying_period_comment DROP CONSTRAINT fk_cd960ef3d7fa8ef0');
|
||||||
|
$this->addSql('ALTER TABLE chill_person_accompanying_period_comment ADD CONSTRAINT fk_cd960ef3d7fa8ef0 FOREIGN KEY (accompanyingperiod_id) REFERENCES chill_person_accompanying_period (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||||
|
}
|
||||||
|
}
|
@ -46,7 +46,7 @@ Add new phone: Ajouter un numéro de téléphone
|
|||||||
Remove phone: Supprimer
|
Remove phone: Supprimer
|
||||||
'Notes on contact information': 'Remarques sur les informations de contact'
|
'Notes on contact information': 'Remarques sur les informations de contact'
|
||||||
'Remarks': 'Remarques'
|
'Remarks': 'Remarques'
|
||||||
'{0} Born the %date% | {1} Born the %date%': '{0} Né le %date% | {1} Née le %date%'
|
'Born the %date%': '{0} Né le %date% | {1} Née le %date%'
|
||||||
'Spoken languages': 'Langues parlées'
|
'Spoken languages': 'Langues parlées'
|
||||||
'Unknown spoken languages': 'Langues parlées inconnues'
|
'Unknown spoken languages': 'Langues parlées inconnues'
|
||||||
Male: Homme
|
Male: Homme
|
||||||
@ -125,6 +125,8 @@ Reset: 'Remise à zéro'
|
|||||||
'Person search results': 'Recherche de personnes'
|
'Person search results': 'Recherche de personnes'
|
||||||
Person search results by phonenumber: Recherche de personnes par numéro de téléphone
|
Person search results by phonenumber: Recherche de personnes par numéro de téléphone
|
||||||
'Search within persons': 'Recherche parmi les personnes'
|
'Search within persons': 'Recherche parmi les personnes'
|
||||||
|
Open person file: Ouvrir
|
||||||
|
and %number% other: '{0} et aucun autre| {1} et une autre |]1, Inf] et %number% autres'
|
||||||
'%total% persons matching the search pattern:': '{0} Aucune personne ne correspond aux termes de recherche : | {1} Une personne a été trouvée par la recherche : | ]1,Inf] %total% personnes correspondent aux termes de recherche :'
|
'%total% persons matching the search pattern:': '{0} Aucune personne ne correspond aux termes de recherche : | {1} Une personne a été trouvée par la recherche : | ]1,Inf] %total% personnes correspondent aux termes de recherche :'
|
||||||
'Last opening since %last_opening%': 'Dernière ouverture le %last_opening%.'
|
'Last opening since %last_opening%': 'Dernière ouverture le %last_opening%.'
|
||||||
'Person accompanying period - %name%': 'Historique du dossier - %name%'
|
'Person accompanying period - %name%': 'Historique du dossier - %name%'
|
||||||
@ -170,6 +172,9 @@ Resources: Interlocuteurs privilégiés
|
|||||||
Social actions: Actions d'accompagnement
|
Social actions: Actions d'accompagnement
|
||||||
Last events on accompanying course: Dernières actions de suivi
|
Last events on accompanying course: Dernières actions de suivi
|
||||||
Edit & activate accompanying course: Modifier et valider
|
Edit & activate accompanying course: Modifier et valider
|
||||||
|
See accompanying periods: Voir les périodes d'accompagnement
|
||||||
|
See accompanying period: Voir cette période d'accompagnement
|
||||||
|
Referrer: Référent
|
||||||
|
|
||||||
# pickAPersonType
|
# pickAPersonType
|
||||||
Pick a person: Choisir une personne
|
Pick a person: Choisir une personne
|
||||||
|
@ -113,6 +113,7 @@ class ThirdParty
|
|||||||
* @var Address|null
|
* @var Address|null
|
||||||
* @ORM\ManyToOne(targetEntity="\Chill\MainBundle\Entity\Address",
|
* @ORM\ManyToOne(targetEntity="\Chill\MainBundle\Entity\Address",
|
||||||
* cascade={"persist", "remove"})
|
* cascade={"persist", "remove"})
|
||||||
|
* @ORM\JoinColumn(nullable=true, onDelete="SET NULL")
|
||||||
*/
|
*/
|
||||||
private $address;
|
private $address;
|
||||||
|
|
||||||
|
@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Chill\Migrations\ThirdParty;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\Schema\Schema;
|
||||||
|
use Doctrine\Migrations\AbstractMigration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specify ON DELETE behaviour to handle deletion of parents in associated tables
|
||||||
|
*/
|
||||||
|
final class Version20210525211216 extends AbstractMigration
|
||||||
|
{
|
||||||
|
public function getDescription(): string
|
||||||
|
{
|
||||||
|
return 'Specify ON DELETE behaviour to handle deletion of parents in associated tables';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function up(Schema $schema): void
|
||||||
|
{
|
||||||
|
$this->addSql('ALTER TABLE chill_3party.third_party DROP CONSTRAINT FK_D952467BF5B7AF75');
|
||||||
|
$this->addSql('ALTER TABLE chill_3party.third_party ADD CONSTRAINT FK_D952467BF5B7AF75 FOREIGN KEY (address_id) REFERENCES chill_main_address (id) ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(Schema $schema): void
|
||||||
|
{
|
||||||
|
$this->addSql('ALTER TABLE chill_3party.third_party DROP CONSTRAINT fk_d952467bf5b7af75');
|
||||||
|
$this->addSql('ALTER TABLE chill_3party.third_party ADD CONSTRAINT fk_d952467bf5b7af75 FOREIGN KEY (address_id) REFERENCES chill_main_address (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||||
|
}
|
||||||
|
}
|
72
src/Bundle/parcours.html
Normal file
72
src/Bundle/parcours.html
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
Controleur:
|
||||||
|
|
||||||
|
activity_json = $this->serializer->serialize($activity, 'json', []);
|
||||||
|
|
||||||
|
return render('@ChillActivity/...', [
|
||||||
|
'activity' => $activity,
|
||||||
|
'activity_json' => $activity_json
|
||||||
|
])
|
||||||
|
|
||||||
|
|
||||||
|
{# template twig de activity #}
|
||||||
|
|
||||||
|
{{ form(activity) }}
|
||||||
|
|
||||||
|
{% block js %}
|
||||||
|
<script>
|
||||||
|
{# window.activity = {{ activity_json|e('json') }}; #}
|
||||||
|
window.activity = {
|
||||||
|
"type": "activity",
|
||||||
|
"persons": [
|
||||||
|
{ type: person, id: xxx, ...}
|
||||||
|
{ ...}
|
||||||
|
],
|
||||||
|
""
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
{{ encore_entry_script_tags('activity_form') }}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
|
{# -----
|
||||||
|
dans le fichier app.js: #}
|
||||||
|
<script type="text/javascript">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const store = createStore({
|
||||||
|
strict: debug,
|
||||||
|
state(): return {
|
||||||
|
activity: window.activity
|
||||||
|
},
|
||||||
|
getters: {
|
||||||
|
|
||||||
|
},
|
||||||
|
mutations: {
|
||||||
|
addPerson(state, payload) {
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
addPerson() {
|
||||||
|
let el = document.getElementById('form['activity']['xxx']['xxxx']');
|
||||||
|
let option = document.createElement('option');
|
||||||
|
option.value = person.id;
|
||||||
|
el.appendChild(option);
|
||||||
|
commit('addPerson', payload)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const i18n = _createI18n(appMessages);
|
||||||
|
|
||||||
|
const app = createApp({
|
||||||
|
template: `<app></app>`,
|
||||||
|
})
|
||||||
|
.use(store)
|
||||||
|
.use(i18n)
|
||||||
|
.component('app', App)
|
||||||
|
.mount('#activity');
|
||||||
|
|
||||||
|
|
||||||
|
</script>
|
Loading…
x
Reference in New Issue
Block a user