Compare commits

..

39 Commits

Author SHA1 Message Date
6554552d0e update app 2021-09-13 11:30:49 +02:00
1539ace138 update app 2021-09-13 11:26:33 +02:00
nobohan
e6051978fa rdv: hook i18n translations into the App.vue 2021-07-23 16:42:43 +02:00
nobohan
8f2f8a285f rdv: change type of date to datetime in calendarRange 2021-07-23 16:31:36 +02:00
nobohan
9d0589d455 rdv: use datetime instead of date fields 2021-07-23 16:25:05 +02:00
nobohan
0458398a5f rdv: connect fullcalendar vue component to startDate and endDate fields 2021-07-23 15:54:30 +02:00
nobohan
4a0186a791 rdv: minor corrections following MR review 2021-07-23 10:14:20 +02:00
4770a3cf47 rdv: MR comment 2021-07-23 08:13:21 +00:00
76098e02e6 rdv: MR comment 2021-07-23 08:13:04 +00:00
301c8237c4 rdv: MR comment 2021-07-23 08:12:57 +00:00
ce126573ec rdv: MR comment 2021-07-23 08:12:50 +00:00
9c136d80d0 rdv: MR comment 2021-07-23 08:12:36 +00:00
00598b3fb4 rdv: MR comment 2021-07-23 08:12:25 +00:00
nobohan
5a50dbf495 rdv: fullcalendar: add 3 buttons 'month - week - day' 2021-07-23 10:00:27 +02:00
nobohan
551e85c0f4 rdv: adapt calendar entities: drop useless field and change field type 2021-07-23 09:59:20 +02:00
nobohan
2062cb01d8 rdv: add translations 2021-07-22 07:58:36 +02:00
nobohan
78f9f6ffc7 rdv: fullcalendar vue: use store and add an event on date select 2021-07-21 13:59:31 +02:00
nobohan
9b793bd6d1 rdv: add fullcalendar.js as a vuejs component (POC) 2021-07-20 22:01:43 +02:00
nobohan
6f147850bd rdv: correct edit page 2021-07-20 14:57:45 +02:00
nobohan
0e1f34ef87 rdv: delete a rdv 2021-07-20 14:52:58 +02:00
nobohan
d55e5344c0 rdv: others pages: edit, list 2021-07-19 17:18:56 +02:00
nobohan
95ff5f4147 rdv: add validation 2021-07-19 16:15:52 +02:00
nobohan
44a5955f40 rdv: allow null concerned persons in form 2021-07-19 15:22:36 +02:00
nobohan
db06a64a2b rdv: add show calendar 2021-07-19 13:59:50 +02:00
nobohan
620b79d17f rdv: add default status on rdv when creating a new rdv 2021-07-19 12:06:21 +02:00
nobohan
b894596304 rdv: fix adding thirdparty when creating a rdv 2021-07-19 11:30:06 +02:00
nobohan
450025c145 rdv: add entity to serialize (WIP) 2021-07-19 11:07:29 +02:00
nobohan
d84877e3b9 rdv: can add thirdparty to a rdv 2021-07-19 10:26:44 +02:00
nobohan
5a3b18984a rdv: simplify the vuejs component (removed not used parts) 2021-07-19 10:13:08 +02:00
nobohan
019a97b1fc rdv: add thirdParty in concerned persons (WIP) 2021-07-19 10:08:43 +02:00
nobohan
19f330fc4c rdv: add the concernedGroup vuejs component in add a new rdv 2021-07-16 18:21:27 +02:00
nobohan
c89fa79c49 rdv: some fixes for the new rdv 2021-07-16 17:00:21 +02:00
nobohan
0fd30160ac rdv: add new rdv form 2021-07-16 12:57:11 +02:00
nobohan
e820f63f99 rdv: add route, twig for listing and creating calendar items 2021-07-16 11:58:30 +02:00
nobohan
6f601c7526 rdv: adapt entities + add fixtures 2021-07-16 09:55:07 +02:00
nobohan
33ca9f5d99 rdv: add first migration 2021-07-15 16:36:37 +02:00
nobohan
856801a081 rdv: correct entities with FQCN 2021-07-15 16:36:37 +02:00
nobohan
7ef004adbb calendar: add entities 2021-07-15 16:36:37 +02:00
nobohan
8c589e0086 init Calendar bundle 2021-07-15 16:36:37 +02:00
599 changed files with 20237 additions and 5761 deletions

View File

@@ -3,10 +3,7 @@
"license": "AGPL-3.0-only",
"type": "library",
"description": "Most used bundles for chill-project",
"keywords": [
"chill",
"social worker"
],
"keywords": ["chill", "social worker"],
"autoload": {
"psr-4": {
"Chill\\ActivityBundle\\": "src/Bundle/ChillActivityBundle",
@@ -20,7 +17,7 @@
"Chill\\ReportBundle\\": "src/Bundle/ChillReportBundle",
"Chill\\TaskBundle\\": "src/Bundle/ChillTaskBundle",
"Chill\\ThirdPartyBundle\\": "src/Bundle/ChillThirdPartyBundle",
"Chill\\AsideActivityBundle\\": "src/Bundle/ChillAsideActivityBundle/src"
"Chill\\CalendarBundle\\": "src/Bundle/ChillCalendarBundle"
}
},
"autoload-dev": {
@@ -56,7 +53,7 @@
"knplabs/knp-time-bundle": "^1.12",
"symfony/intl": "4.*",
"symfony/swiftmailer-bundle": "^3.5",
"league/csv": "^9.7.1",
"league/csv": "^9.6",
"phpoffice/phpspreadsheet": "^1.16",
"symfony/browser-kit": "^5.2",
"symfony/css-selector": "^5.2",
@@ -88,6 +85,7 @@
}
},
"config": {
"vendor-dir": "tests/app/vendor",
"bin-dir": "bin"
}
}

View File

@@ -22,7 +22,6 @@ class LoadActivityNotifications extends AbstractFixture implements DependentFixt
'entityRef' => 'activity_gerard depardieu',
'sender' => 'center a_social',
'addressees' => [
'center a_social',
'center a_administrative',
'center a_direction',
'multi_center'

View File

@@ -1,24 +0,0 @@
<?php
namespace Chill\ActivityBundle\Notification;
use Chill\MainBundle\Entity\Notification;
use Chill\ActivityBundle\Entity\Activity;
final class ActivityNotificationRenderer
{
public function supports(Notification $notification, array $options = []): bool
{
return $notification->getRelatedEntityClass() == Activity::class;
}
public function getTemplate()
{
return '@ChillActivity/Activity/showInNotification.html.twig';
}
public function getTemplateData(Notification $notification)
{
return ['notification' => $notification];
}
}

View File

@@ -1 +0,0 @@
require('./chillactivity.scss');

View File

@@ -0,0 +1 @@
require('./scss/chillactivity.scss');

View File

@@ -1,6 +1,4 @@
// Access to Bootstrap variables and mixins
@import '~ChillMainAssets/module/bootstrap/shared';
@import '~ChillMainAssets/modules/bootstrap/bootstrap';
//@import '~ChillMainSass/custom/mixins/entity';
//.chill-entity.chill-entity__activity-reason {
@@ -8,7 +6,7 @@
//}
.activity {
//color: $chill-green;
color: $chill-green;
}
// exceptions for flex-bloc in concerned-groups

View File

@@ -60,7 +60,7 @@
<li>
<a href="{{ _self.href(bloc.path, bloc.key, item.id) }}">
<span class="badge bg-primary">
{{ item|chill_entity_render_box({'render': 'raw'}) }}
{{ item|chill_entity_render_box({'only_denomination': true}) }}
</span>
</a>
</li>

View File

@@ -6,16 +6,20 @@
{% block content %}
<div class="activity-edit">
<div class="row justify-content-center">
<div class="col-md-10 col-xxl">
<div id="activity"></div> {# <=== vue component #}
{% include 'ChillActivityBundle:Activity:edit.html.twig' %}
</div>
</div>
</div>
{% endblock %}
{% block js %}
{{ parent() }}
{{ encore_entry_link_tags('mod_async_upload') }}
{{ encore_entry_link_tags('async_upload') }}
<script type="text/javascript">
window.addEventListener('DOMContentLoaded', function (e) {
chill.displayAlertWhenLeavingModifiedForm('form[name="{{ edit_form.vars.form.vars.name }}"]',
@@ -28,6 +32,6 @@
{% block css %}
{{ parent() }}
{{ encore_entry_link_tags('mod_async_upload') }}
{{ encore_entry_link_tags('async_upload') }}
{{ encore_entry_link_tags('vue_activity') }}
{% endblock %}

View File

@@ -22,15 +22,19 @@
{% block personcontent %}
<div class="activity-edit">
<div class="row justify-content-center">
<div class="col-md-10 col-xxl">
<div id="activity"></div> {# <=== vue component #}
{% include 'ChillActivityBundle:Activity:edit.html.twig' %}
</div>
</div>
</div>
{% endblock %}
{% block js %}
{{ encore_entry_link_tags('mod_async_upload') }}
{{ encore_entry_link_tags('async_upload') }}
<script type="text/javascript">
window.addEventListener('DOMContentLoaded', function (e) {
chill.displayAlertWhenLeavingModifiedForm('form[name="{{ edit_form.vars.form.vars.name }}"]',
@@ -42,6 +46,6 @@
{% endblock %}
{% block css %}
{{ encore_entry_link_tags('mod_async_upload') }}
{{ encore_entry_link_tags('async_upload') }}
{{ encore_entry_link_tags('vue_activity') }}
{% endblock %}

View File

@@ -18,7 +18,17 @@
{% else %}
<div class="flex-table list-records context-{{ context }}">
<!--
<thead>
<tr>
<th class="chill-red">{{'Date' | trans }}</th>
<th class="chill-green">{{'Duration Time' | trans }}</th>
<th class="chill-orange">{{'Reasons' | trans}}</th>
<th>{{'Type' | trans}}</th>
<th>&nbsp;</th>
</tr>
</thead>
-->
{% for activity in activities %}
{% set t = activity.type %}
<div class="item-bloc">
@@ -36,6 +46,7 @@
{{ activity.durationTime|date('H:i') }}
</p>
{% endif %}
{% if activity.travelTime and t.travelTimeVisible %}
<p>
<i class="fa fa-fw fa-car"></i>
@@ -46,10 +57,12 @@
{% if context == 'person' and activity.accompanyingPeriod is not empty %}
<div class="accompanyingPeriodLink" style="margin-top: 1rem">
<a href="{{ chill_path_add_return_path(
<a
href="{{ chill_path_add_return_path(
"chill_person_accompanying_course_index",
{ 'accompanying_period_id': activity.accompanyingPeriod.id }
) }}">
) }}"
>
<i class="fa fa-random"></i>
{{ activity.accompanyingPeriod.id }}
</a>

View File

@@ -6,16 +6,20 @@
{% block content %}
<div class="activity-new">
<div class="row justify-content-center">
<div class="col-md-10 col-xxl">
<div id="activity"></div> {# <=== vue component #}
{% include 'ChillActivityBundle:Activity:new.html.twig' with {'context': 'accompanyingCourse'} %}
</div>
</div>
</div>
{% endblock %}
{% block js %}
{{ parent() }}
{{ encore_entry_script_tags('mod_async_upload') }}
{{ encore_entry_script_tags('async_upload') }}
<script type="text/javascript">
window.addEventListener('DOMContentLoaded', function (e) {
chill.displayAlertWhenLeavingUnsubmittedForm('form[name="{{ form.vars.form.vars.name }}"]',
@@ -28,6 +32,6 @@
{% block css %}
{{ parent() }}
{{ encore_entry_link_tags('mod_async_upload') }}
<link rel="stylesheet" href="{{ asset('build/async_upload.css') }}"/>
{{ encore_entry_link_tags('vue_activity') }}
{% endblock %}

View File

@@ -6,15 +6,19 @@
{% block personcontent %}
<div class="activity-new">
<div class="row justify-content-center">
<div class="col-md-10 col-xxl">
<div id="activity"></div> {# <=== vue component #}
{% include 'ChillActivityBundle:Activity:new.html.twig' with {'context': 'person'} %}
</div>
</div>
</div>
{% endblock %}
{% block js %}
{{ encore_entry_link_tags('mod_async_upload') }}
{{ encore_entry_link_tags('async_upload') }}
<script type="text/javascript">
window.addEventListener('DOMContentLoaded', function (e) {
chill.displayAlertWhenLeavingUnsubmittedForm('form[name="{{ form.vars.form.vars.name }}"]',
@@ -26,6 +30,6 @@
{% endblock %}
{% block css %}
{{ encore_entry_link_tags('mod_async_upload') }}
{{ encore_entry_link_tags('async_upload') }}
{{ encore_entry_link_tags('vue_activity') }}
{% endblock %}

View File

@@ -8,8 +8,12 @@
{% block content -%}
<div class="activity-show">
<div class="row justify-content-center">
<div class="col-md-10 col-xxl">
{% include 'ChillActivityBundle:Activity:show.html.twig' with {'context': 'accompanyingCourse'} %}
</div>
</div>
</div>
{% endblock content %}

View File

@@ -1,4 +0,0 @@
{{ dump(notification) }}
<a href="{{ path('chill_activity_activity_show', {'id': notification.relatedEntityId }) }}">Go to Activity</a>

View File

@@ -8,8 +8,12 @@
{% block personcontent -%}
<div class="activity-show">
<div class="row justify-content-center">
<div class="col-md-10 col-xxl">
{% include 'ChillActivityBundle:Activity:show.html.twig' with {'context': 'person'} %}
</div>
</div>
</div>
{% endblock personcontent %}

View File

@@ -1,7 +1,6 @@
// this file loads all assets from the Chill person bundle
module.exports = function(encore, entries)
{
entries.push(__dirname + '/Resources/public/chill/index.js');
module.exports = function(encore, entries) {
entries.push(__dirname + '/Resources/public/index.js');
encore.addAliases({
ChillActivityAssets: __dirname + '/Resources/public'

View File

@@ -33,8 +33,3 @@ services:
autoconfigure: true
resource: '../Menu/'
tags: ['chill.menu_builder']
Chill\ActivityBundle\Notification\:
autowire: true
autoconfigure: true
resource: '../Notification'

View File

@@ -1,3 +0,0 @@
# Aside activities module
This module offers the possibility to add extra curricular activities per user (eg. administrative tasks, formation, meetings) not immediately related to client support.

View File

@@ -1,11 +0,0 @@
<?php
declare(strict_types=1);
namespace Chill\AsideActivityBundle;
use Symfony\Component\HttpKernel\Bundle\Bundle;
class ChillAsideActivityBundle extends Bundle
{
}

View File

@@ -1,20 +0,0 @@
<?php
namespace Chill\AsideActivityBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
/**
* Controller for activity configuration
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
* @author Champs Libres <info@champs-libres.coop>
*/
class AdminController extends AbstractController
{
public function redirectToAdminIndexAction()
{
return $this->redirectToRoute('chill_main_admin_central');
}
}

View File

@@ -1,14 +0,0 @@
<?php
namespace Chill\AsideActivityBundle\Controller;
use Chill\MainBundle\CRUD\Controller\CRUDController;
/**
* Class AsideActivityBundle
*/
class AsideActivityCategoryController extends CRUDController
{
}

View File

@@ -1,29 +0,0 @@
<?php
declare(strict_types=1);
namespace Chill\AsideActivityBundle\Controller;
use Chill\MainBundle\CRUD\Controller\CRUDController;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\HttpFoundation\Request;
use Chill\MainBundle\Pagination\PaginatorInterface;
use Doctrine\Common\Collections\Criteria;
final class AsideActivityController extends CRUDController
{
/**
* @param QueryBuilder $query
*/
protected function onPostIndexBuildQuery(string $action, Request $request, int $totalItems, PaginatorInterface $paginator, $query) {
$usr = $this->getUser();
$id = $usr->getId();
$criteria = Criteria::create()->andWhere(Criteria::expr()->eq('agent', $id));
$query
->addCriteria($criteria);
}
}

View File

@@ -1,91 +0,0 @@
<?php
namespace Chill\ActivityBundle\DataFixtures\ORM;
use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
use Doctrine\Persistence\ObjectManager;
use Faker\Factory as FakerFactory;
use Chill\MainBundle\DataFixtures\ORM\LoadUsers;
use Chill\AsideActivityBundle\DataFixtures\LoadAsideActivityCategory;
use Chill\AsideActivityBundle\Entity\AsideActivity;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
/**
* Load reports into DB
*
* @author Champs-Libres Coop
*/
class LoadActivity extends AbstractFixture implements OrderedFixtureInterface, ContainerAwareInterface
{
use \Symfony\Component\DependencyInjection\ContainerAwareTrait;
/**
* @var \Faker\Generator
*/
private $faker;
public function __construct()
{
$this->faker = FakerFactory::create('fr_FR');
}
public function getOrder()
{
return 16400;
}
/**
* Return a random asideActivityCategory
*
* @return \Chill\AsideActivityBundle\Entity\AsideActivityCategory
*/
private function getRandomAsideActivityCategory()
{
$catRef = LoadAsideActivityCategory::$references[array_rand(LoadAsideActivityCategory::$references)];
return $this->getReference($catRef);
}
/**
* Return a random user
*
* @return \Chill\MainBundle\Entity\User
*/
private function getRandomUser()
{
$userRef = array_rand(LoadUsers::$refs);
return $this->getReference($userRef);
}
public function newRandomActivity()
{
$asideactivity = (new AsideActivity())
->setAgent($this->getRandomUser())
->setDate($this->faker->dateTimeThisYear())
->setDuration($this->faker->dateTime(36000))
->setType($this->getRandomAsideActivityCategory());
return $asideactivity;
}
public function load(ObjectManager $manager)
{
$users = $this->container->get('doctrine.orm.entity_manager')
->getRepository('ChillMainBundle:User')
->findAll();
foreach($users as $user) {
$activityNbr = rand(0,3);
$ref = 'activity_'.$user->getUsernameCanonical();
for($i = 0; $i < $activityNbr; $i ++) {
print "Creating an aside activity for : ".$user." (ref: ".$ref.") \n";
$asideactivity = $this->newRandomActivity($user);
$manager->persist($asideactivity);
}
$this->setReference($ref, $asideactivity);
}
$manager->flush();
}
}

View File

@@ -1,53 +0,0 @@
<?php
Namespace Chill\AsideActivityBundle\DataFixtures;
use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
use Doctrine\Persistence\ObjectManager;
use Chill\ActivityBundle\Entity\ActivityTypeCategory;
use Chill\AsideActivityBundle\Entity\AsideActivityCategory;
/**
* Fixtures for AsideActivityCategory
*
* @author Champs-Libres Coop
*/
class LoadAsideActivityCategory extends Fixture implements OrderedFixtureInterface
{
public static $references = array();
public function getOrder()
{
return 16050;
}
public function load(ObjectManager $manager)
{
$categories = [
[
'title' => ['fr' => 'Formation', 'en' => 'Training'],
'ref' => 'training',
],
[
'title' => ['fr' => 'Team building', 'en' => 'Team building'],
'ref' => 'teambuilding',
],
];
foreach ($categories as $cat) {
print "Creating aside activity type category : " . $cat['ref'] . "\n";
$newCat = (new AsideActivityCategory())
->setTitle(($cat['title']));
$manager->persist($newCat);
$reference = 'activity_type_cat_'.$cat['ref'];
$this->addReference($reference, $newCat);
static::$references[] = $reference;
}
$manager->flush();
}
}

View File

@@ -1,102 +0,0 @@
<?php
namespace Chill\AsideActivityBundle\DataFixtures\ORM;
use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
use Doctrine\Persistence\ObjectManager;
use Faker\Factory as FakerFactory;
use Chill\MainBundle\DataFixtures\ORM\LoadUsers;
use Chill\AsideActivityBundle\DataFixtures\ORM\LoadAsideActivityCategory;
use Chill\AsideActivityBundle\Entity\AsideActivity;
use Chill\AsideActivityBundle\Entity\AsideActivityCategory;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Repository\UserRepository;
use DateTime;
use Doctrine\Bundle\FixturesBundle\FixtureGroupInterface;
use Doctrine\Common\DataFixtures\DependentFixtureInterface;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
/**
* Load reports into DB
*
* @author Champs-Libres Coop
*/
class LoadAsideActivity extends AbstractFixture implements DependentFixtureInterface, ContainerAwareInterface
{
use \Symfony\Component\DependencyInjection\ContainerAwareTrait;
/**
* @var \Faker\Generator
*/
private $faker;
private array $cacheUsers = [];
private UserRepository $userRepository;
public function __construct(UserRepository $userRepository)
{
$this->faker = FakerFactory::create('fr_FR');
$this->userRepository = $userRepository;
}
public function getDependencies()
{
return [
LoadAsideActivityCategory::class,
LoadUsers::class,
];
}
/**
* Return a random asideActivityCategory
*
* @return \Chill\AsideActivityBundle\Entity\AsideActivityCategory
*/
private function getRandomAsideActivityCategory(): AsideActivityCategory
{
$catRef = LoadAsideActivityCategory::$references[array_rand(LoadAsideActivityCategory::$references)];
return $this->getReference($catRef);
}
/**
* Return a random user
*
* @return \Chill\MainBundle\Entity\User
*/
private function getRandomUser(): User
{
if (0 === count($this->cacheUsers)){
$this->cacheUsers = $this->container->get('doctrine.orm.entity_manager')
->getRepository('ChillMainBundle:User')
->findAll();
}
return $this->cacheUsers[array_rand($this->cacheUsers)];
}
public function newRandomActivity()
{
$asideactivity = ($activity = new AsideActivity())
->setAgent($this->getRandomUser())
->setDate($this->faker->dateTimeThisYear())
->setCreatedAt(new DateTime())
->setCreatedBy($activity->getAgent())
//->setDuration(3600)
->setType($this->getRandomAsideActivityCategory());
return $asideactivity;
}
public function load(ObjectManager $manager)
{
for($i = 0; $i < 100; $i ++) {
$asideactivity = $this->newRandomActivity();
$manager->persist($asideactivity);
}
$manager->flush();
}
}

View File

@@ -1,50 +0,0 @@
<?php
Namespace Chill\AsideActivityBundle\DataFixtures\ORM;
use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
use Doctrine\Persistence\ObjectManager;
use Chill\ActivityBundle\Entity\ActivityTypeCategory;
use Chill\AsideActivityBundle\Entity\AsideActivityCategory;
use Doctrine\Bundle\FixturesBundle\FixtureGroupInterface;
use Doctrine\Common\DataFixtures\DependentFixtureInterface;
/**
* Fixtures for AsideActivityCategory
*
* @author Champs-Libres Coop
*/
class LoadAsideActivityCategory extends Fixture
{
public static $references = array();
public function load(ObjectManager $manager)
{
$categories = [
[
'title' => ['fr' => 'Formation', 'en' => 'Training'],
'ref' => 'training',
],
[
'title' => ['fr' => 'Team building', 'en' => 'Team building'],
'ref' => 'teambuilding',
],
];
foreach ($categories as $cat) {
print "Creating aside activity type category : " . $cat['ref'] . "\n";
$newCat = (new AsideActivityCategory())
->setTitle(($cat['title']));
$manager->persist($newCat);
$reference = 'activity_type_cat_'.$cat['ref'];
$this->addReference($reference, $newCat);
static::$references[] = $reference;
}
$manager->flush();
}
}

View File

@@ -1,108 +0,0 @@
<?php
/**
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
declare(strict_types=1);
namespace Chill\AsideActivityBundle\DependencyInjection;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\Extension;
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
use Symfony\Component\DependencyInjection\Loader;
final class ChillAsideActivityExtension extends Extension implements PrependExtensionInterface
{
/**
* {@inheritdoc}
*
* @phpstan-ignore-next-line
*/
public function load(array $configs, ContainerBuilder $container): void
{
$loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../config'));
$loader->load('services.yaml');
$loader->load('services/form.yaml');
$loader->load('services/menu.yaml');
}
public function prepend(ContainerBuilder $container)
{
$this->prependRoute($container);
$this->prependCruds($container);
}
protected function prependRoute(ContainerBuilder $container)
{
//declare routes for task bundle
$container->prependExtensionConfig('chill_main', array(
'routing' => array(
'resources' => array(
'@ChillAsideActivityBundle/config/routes.yaml',
)
)
));
}
protected function prependCruds(ContainerBuilder $container)
{
$container->prependExtensionConfig('chill_main', [
'cruds' => [
[
'class' => \Chill\AsideActivityBundle\Entity\AsideActivityCategory::class,
'name' => 'aside_activity_category',
'base_path' => '/admin/asideactivity/category',
'form_class' => \Chill\AsideActivityBundle\Form\AsideActivityCategoryType::class,
'controller' => \Chill\AsideActivityBundle\Controller\AsideActivityCategoryController::class,
'actions' => [
'index' => [
'template' => '@ChillAsideActivity/asideActivityCategory/index.html.twig',
'role' => 'ROLE_ADMIN'
],
'new' => [
'role' => 'ROLE_ADMIN',
'template' => '@ChillAsideActivity/asideActivityCategory/new.html.twig',
],
'edit' => [
'role' => 'ROLE_ADMIN',
'template' => '@ChillAsideActivity/asideActivityCategory/edit.html.twig',
]
]
],
[
'class' => \Chill\AsideActivityBundle\Entity\AsideActivity::class,
'name' => 'aside_activity',
'base_path' => '/asideactivity',
'form_class' => \Chill\AsideActivityBundle\Form\AsideActivityFormType::class,
'controller' => \Chill\AsideActivityBundle\Controller\AsideActivityController::class,
'actions' => [
'index' => [
'template' => '@ChillAsideActivity/asideActivity/list.html.twig',
'role' => 'ROLE_USER'
],
'new' => [
'role' => 'ROLE_USER',
'template' => '@ChillAsideActivity/asideActivity/new.html.twig',
],
'view' => [
'role' => 'ROLE_USER',
'template' => '@ChillAsideActivity/asideActivity/view.html.twig',
],
'edit' => [
'role' => 'ROLE_USER',
'template' => '@ChillAsideActivity/asideActivity/edit.html.twig',
],
'delete' => [
'role' => 'ROLE_USER',
'template' => '@ChillAsideActivity/asideActivity/delete.html.twig',
]
]
],
]
]);
}
}

View File

@@ -1,203 +0,0 @@
<?php
declare(strict_types=1);
namespace Chill\AsideActivityBundle\Entity;
use Chill\MainBundle\Doctrine\Model\TrackCreationInterface;
use Chill\MainBundle\Doctrine\Model\TrackUpdateInterface;
use Chill\MainBundle\Entity\User;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* @ORM\Entity
* @ORM\Table(schema="chill_asideactivity")
*/
class AsideActivity implements TrackUpdateInterface, TrackCreationInterface
{
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private ?int $id;
/**
* @ORM\ManyToOne(targetEntity=AsideActivityCategory::class, inversedBy="asideActivities")
* @ORM\JoinColumn(nullable=false)
*/
private $type;
/**
* @ORM\ManyToOne(targetEntity=User::class)
* @ORM\JoinColumn(nullable=false)
*/
private \Chill\MainBundle\Entity\User $createdBy;
/**
* @ORM\Column(type="datetime")
*/
private $createdAt;
/**
* @ORM\ManyToOne(targetEntity=User::class)
*/
private \Chill\MainBundle\Entity\User $updatedBy;
/**
* @ORM\Column(type="datetime", nullable=true)
*/
private $updatedAt;
/**
* @ORM\ManyToOne(targetEntity=User::class)
* @ORM\JoinColumn(nullable=false)
* @Assert\NotBlank()
*/
private \Chill\MainBundle\Entity\User $agent;
/**
* @ORM\Column(type="datetime")
*/
private $date;
/**
* @ORM\Column(type="time", nullable=true)
*/
private ?\DateTimeInterface $duration = null;
/**
* @ORM\Column(type="string", length=100, nullable=true)
*/
private $location;
/**
* @ORM\Column(type="text", nullable=true)
*/
private $note;
public function getId(): ?int
{
return $this->id;
}
public function getType(): ?AsideActivityCategory
{
return $this->type;
}
public function setType(?AsideActivityCategory $type): self
{
$this->type = $type;
return $this;
}
public function getCreatedBy(): ?User
{
return $this->createdBy;
}
public function setCreatedBy(?User $createdBy): self
{
$this->createdBy = $createdBy;
return $this;
}
public function getCreatedAt(): ?\DateTimeInterface
{
return $this->createdAt;
}
public function setCreatedAt(\DateTimeInterface $createdAt): self
{
$this->createdAt = $createdAt;
return $this;
}
public function getUpdatedBy(): ?User
{
return $this->updatedBy;
}
public function setUpdatedBy(?User $updatedBy): self
{
$this->updatedBy = $updatedBy;
return $this;
}
public function getUpdatedAt(): ?\DateTimeInterface
{
return $this->updatedAt;
}
public function setUpdatedAt(\DateTimeInterface $updatedAt): self
{
$this->updatedAt = $updatedAt;
return $this;
}
public function getAgent(): ?User
{
return $this->agent;
}
public function setAgent(?User $agent): self
{
$this->agent = $agent;
return $this;
}
public function getDate(): ?\DateTimeInterface
{
return $this->date;
}
public function setDate(\DateTimeInterface $date): self
{
$this->date = $date;
return $this;
}
public function getDuration(): ?\DateTimeInterface
{
return $this->duration;
}
public function setDuration(?\DateTimeInterface $duration): self
{
$this->duration = $duration;
return $this;
}
public function getLocation(): ?string
{
return $this->location;
}
public function setLocation(?string $location): self
{
$this->location = $location;
return $this;
}
public function getNote(): ?string
{
return $this->note;
}
public function setNote(?string $note): self
{
$this->note = $note;
return $this;
}
}

View File

@@ -1,62 +0,0 @@
<?php
declare(strict_types=1);
namespace Chill\AsideActivityBundle\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
* @ORM\Table(schema="chill_asideactivity")
*/
class AsideActivityCategory
{
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private int $id;
/**
* @ORM\Column(type="json", length=255)
*/
private array $title;
/**
* @ORM\Column(type="boolean")
*/
private bool $isActive = true;
public function getId(): ?int
{
return $this->id;
}
public function getTitle(): ?array
{
return $this->title;
}
public function setTitle(array $title): self
{
$this->title = $title;
return $this;
}
public function getIsActive(): bool
{
return $this->isActive;
}
public function setIsActive(bool $isActive): self
{
$this->isActive = $isActive;
return $this;
}
}

View File

@@ -1,29 +0,0 @@
<?php
namespace Chill\AsideActivityBundle\Form;
use Chill\AsideActivityBundle\Entity\AsideActivityCategory;
use Chill\MainBundle\Form\Type\TranslatableStringFormType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\FormBuilderInterface;
final class AsideActivityCategoryType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('title', TranslatableStringFormType::class,
[
'label' => 'Nom',
])
->add('isActive', ChoiceType::class,
[
'choices' => [
'Yes' => true,
'No' => false
],
'expanded' => true
]);
}
}

View File

@@ -1,146 +0,0 @@
<?php
namespace Chill\AsideActivityBundle\Form;
use Chill\AsideActivityBundle\Entity\AsideActivity;
use Chill\AsideActivityBundle\Entity\AsideActivityCategory;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Form\Type\ChillDateType;
use Chill\MainBundle\Form\Type\ChillTextareaType;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Doctrine\ORM\EntityRepository;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToTimestampTransformer;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Security;
final class AsideActivityFormType extends AbstractType
{
protected array $timeChoices;
private TranslatableStringHelper $translatableStringHelper;
private TokenStorageInterface $storage;
public function __construct (TranslatableStringHelper $translatableStringHelper, array $timeChoices, TokenStorageInterface $storage){
$this->timeChoices = $timeChoices;
$this->translatableStringHelper = $translatableStringHelper;
$this->storage = $storage;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
dump($options);
$timeChoices = [];
foreach ($this->timeChoices as $e) {
$timeChoices[$e['label']] = $e['seconds'];
}
$durationTimeTransformer = new DateTimeToTimestampTransformer('GMT', 'GMT');
$durationTimeOptions = [
'choices' => $timeChoices,
'placeholder' => 'Choose the duration',
];
$builder
->add('agent', EntityType::class,
[
'label' => 'Agent',
'required' => true,
'class' => User::class,
'data' => $this->storage->getToken()->getUser(),
'query_builder' => function(EntityRepository $er){
return $er->createQueryBuilder('u')->where('u.enabled = true');
},
'attr' => array('class' => 'select2 '),
'placeholder' => 'Choose the agent for whom this activity is created',
'choice_label' => 'username'
])
->add('date', ChillDateType::class,
[
'label' => 'date',
'data' => new \DateTime(),
//SETTING RANGE ONLY POSSIBLE WITH WIDGET 'CHOICE' AND NOT 'SINGLE_TEXT'?
// 'widget' => 'choice',
// 'years' => range(2020, date('Y')),
// 'months' => range(1, date('m')),
// 'days' => range(1, date('d')),
'required' => true
])
->add('type', EntityType::class,
[
'label' => 'Type',
'required' => true,
'class' => AsideActivityCategory::class,
'placeholder' => 'Choose the activity category',
// 'choice_label' => 'title[""]'
'choice_label' => function (AsideActivityCategory $asideActivityCategory) {
return $this->translatableStringHelper->localize($asideActivityCategory->getTitle());
},
])
->add('duration', ChoiceType::class, $durationTimeOptions)
->add('note', ChillTextareaType::class, [
'label' => 'Note',
'required' => false,
]);
foreach (['duration'] as $fieldName)
{
$builder->get($fieldName)
->addModelTransformer($durationTimeTransformer);
$builder->get($fieldName)
->addEventListener(FormEvents::PRE_SET_DATA, function(FormEvent $formEvent) use (
$timeChoices,
$builder,
$durationTimeTransformer,
$durationTimeOptions,
$fieldName
) {
// set the timezone to GMT, and fix the difference between current and GMT
// the datetimetransformer will then handle timezone as GMT
$timezoneUTC = new \DateTimeZone('GMT');
/* @var $data \DateTimeImmutable */
$data = $formEvent->getData() === NULL ?
\DateTime::createFromFormat('U', 300) :
$formEvent->getData();
$seconds = $data->getTimezone()->getOffset($data);
$data->setTimeZone($timezoneUTC);
$data->add(new \DateInterval('PT'.$seconds.'S'));
// test if the timestamp is in the choices.
// If not, recreate the field with the new timestamp
if (!in_array($data->getTimestamp(), $timeChoices)) {
// the data are not in the possible values. add them
$timeChoices[$data->format('H:i')] = $data->getTimestamp();
$form = $builder->create($fieldName, ChoiceType::class, array_merge(
$durationTimeOptions, [
'choices' => $timeChoices,
'auto_initialize' => false
]
));
$form->addModelTransformer($durationTimeTransformer);
$formEvent->getForm()->getParent()->add($form->getForm());
}
});
}
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => AsideActivity::class,
]);
}
public function getBlockPrefix(): string
{
return 'chill_asideactivitybundle_asideactivity';
}
}

View File

@@ -1,47 +0,0 @@
<?php
namespace Chill\AsideActivityBundle\Menu;
use Chill\MainBundle\Routing\LocalMenuBuilderInterface;
use Knp\Menu\MenuItem;
use Symfony\Contracts\Translation\TranslatorInterface;
/**
* Class SectionMenuBuilder
*
* @package Chill\AsideActivityBundle\Menu
*/
class SectionMenuBuilder implements LocalMenuBuilderInterface
{
protected TranslatorInterface $translator;
public function __construct(TranslatorInterface $translator)
{
$this->translator = $translator;
}
/**
* @param $menuId
* @param MenuItem $menu
* @param array $parameters
*/
public function buildMenu($menuId, MenuItem $menu, array $parameters)
{
$menu->addChild($this->translator->trans('Create an aside activity'), [
'route' => 'chill_crud_aside_activity_new'
])
->setExtras([
'order' => 11,
'icons' => [ 'plus' ]
]);
}
/**
* @return array
*/
public static function getMenuIds(): array
{
return [ 'section' ];
}
}

View File

@@ -1,52 +0,0 @@
<?php
declare(strict_types=1);
namespace Chill\AsideActivityBundle\Repository;
use Chill\AsideActivityBundle\Entity\AsideActivityCategory;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository;
use Doctrine\Persistence\ObjectRepository;
class AsideActivityCategoryRepository implements ObjectRepository
{
private EntityRepository $repository;
public function __construct(EntityManagerInterface $entityManager)
{
$this->repository = $entityManager->getRepository(AsideActivityCategory::class);
}
public function find($id): ?AsideActivityCategory
{
return $this->repository->find($id);
}
/**
* @return AsideActivityCategory[]
*/
public function findAll(): array
{
return $this->repository->findAll();
}
/**
* @return AsideActivityCategory[]
*/
public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $offset = null): array
{
return $this->repository->findBy($criteria, $orderBy, $limit, $offset);
}
public function findOneBy(array $criteria): ?AsideActivityCategory
{
return $this->repository->findOneBy($criteria);
}
public function getClassName(): string
{
return AsideActivityCategory::class;
}
}

View File

@@ -1,52 +0,0 @@
<?php
declare(strict_types=1);
namespace Chill\AsideActivityBundle\Repository;
use Chill\AsideActivityBundle\Entity\AsideActivity;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository;
use Doctrine\Persistence\ObjectRepository;
final class AsideActivityRepository implements ObjectRepository
{
private EntityRepository $repository;
public function __construct(EntityManagerInterface $entityManager)
{
$this->repository = $entityManager->getRepository(AsideActivity::class);
}
public function find($id): ?AsideActivity
{
return $this->repository->find($id);
}
/**
* @return AsideActivity[]
*/
public function findAll(): array
{
return $this->repository->findAll();
}
/**
* @return AsideActivity[]
*/
public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $offset = null): array
{
return $this->repository->findBy($criteria, $orderBy, $limit, $offset);
}
public function findOneBy(array $criteria): ?AsideActivity
{
return $this->repository->findOneBy($criteria);
}
public function getClassName(): string
{
return AsideActivity::class;
}
}

View File

@@ -1,14 +0,0 @@
{% extends "@ChillMain/Admin/layoutWithVerticalMenu.html.twig" %}
{% block vertical_menu_content %}
{{ chill_menu('admin_aside_activity', {
'layout': '@ChillAsideActivity/Admin/menu_asideactivity.html.twig',
}) }}
{% endblock %}
{% block layout_wvm_content %}
{% block admin_content %}
<!-- block personcontent empty -->
<h1>{{ 'Aside activity configuration' |trans }}</h1>
{% endblock %}
{% endblock %}

View File

@@ -1,4 +0,0 @@
{% extends "@ChillMain/Menu/verticalMenu.html.twig" %}
{% block v_menu_title %}
{{ 'Aside activity configuration menu'|trans }}
{% endblock %}

View File

@@ -1,28 +0,0 @@
<div class="{% block crud_content_main_div_class %}col-10 centered{% endblock %}">
{% block crud_content_header %}
<h1>{{ ('crud.'~crud_name~'.title_delete')|trans({ '%as_string%': 'Aside Activity' }) }}</h1>
{% endblock crud_content_header %}
<p class="message-confirm">{{ ('crud.'~crud_name~'.confirm_message_delete')|trans({ '%as_string%': 'Aside Activity' }) }}</p>
{{ form_start(form) }}
<ul class="record_actions">
{% block content_form_actions_back %}
<li class="cancel">
<a class="btn btn-cancel" href="{{ chill_return_path_or('chill_crud_'~crud_name~'_index') }}">
{{ 'Cancel'|trans }}
</a>
</li>
{% endblock %}
{% block content_form_actions_before %}{% endblock %}
{% block content_form_actions_confirm_delete %}
<li>
<button type="submit" class="btn btn-delete" value="delete-and-close">{{ ('crud.'~crud_name~'.button_delete')|trans }}</button>
</li>
{% endblock content_form_actions_confirm_delete %}
{% block content_form_actions_after %}{% endblock %}
</ul>
{{ form_end(form) }}
</div>

View File

@@ -1,8 +0,0 @@
{% extends '@ChillMain/layout.html.twig' %}
{# {% block title %}{{ ('crud.' ~ crud_name ~ '.delete.title')|trans({'%crud_name%': crud_name}) }}{% endblock %} #}
{% block content %}
{% embed '@ChillAsideActivity/AsideActivity/_delete.html.twig' %}
{% endembed %}
{% endblock content %}

View File

@@ -1,13 +0,0 @@
{% extends '@ChillMain/Admin/layout.html.twig' %}
{% block title %}
{% include('@ChillMain/CRUD/_edit_title.html.twig') %}
{% endblock %}
{% block admin_content %}
{# {% as we are in the admin layout, we override the admin content with the CRUD content %} #}
{% embed '@ChillMain/CRUD/_edit_content.html.twig' %}
{# we do not have "view" page. We empty the corresponding block #}
{% block content_form_actions_view %}{% endblock %}
{% endembed %}
{% endblock %}

View File

@@ -1,8 +0,0 @@
{% extends '@ChillMain/layout.html.twig' %}
{% block title %}{{ ('crud.' ~ crud_name ~ '.index.title')|trans({'%crud_name%': crud_name}) }}{% endblock %}
{% block content %}
{% embed '@ChillAsideActivity/AsideActivity/_index.html.twig' %}
{% endembed %}
{% endblock content %}

View File

@@ -1,106 +0,0 @@
{% extends "@ChillMain/layout.html.twig" %}
{% block title %}
{{ 'Aside activity list' |trans }}
{% endblock title %}
{% block content %}
<div class="col-md-10 col-xxl asideactivity-list">
<h2>{{ 'My aside activities' |trans }}</h2>
{% if entities|length == 0 %}
<p class="chill-no-data-statement">
{{ "There aren't any aside activities."|trans }}
<a href="{{ path('chill_crud_aside_activity_new') }}" class="btn btn-create button-small"></a>
</p>
{% else %}
<div
class="flex-table my-4 list-records">
{# Sort activities according to date in descending order #}
{% for entity in entities|sort ((a, b) => b.date <=> a.date) %}
{% set t = entity.type %}
<div class="item-bloc">
<div class="item-row main">
<div class="item-col">
<h3>
<b>{{ entity.type.title | localize_translatable_string }}</b>
</h3>
{% if entity.date %}
<p>{{ entity.date|format_date('long') }}</p>
{% endif %}
<div class="duration">
<p>
<i class="fa fa-fw fa-hourglass-end"></i>
{{ entity.duration|date('H:i') }}
</p>
</div>
</div>
<div class="item-col">
<ul class="list-content">
{% if entity.createdBy %}
<li>
<b>{{ 'Created by: '|trans }}{{ entity.createdBy.usernameCanonical }}</b>
</li>
{% endif %}
</ul>
</div>
</div>
{# {%
if entity.note is not empty
or entity.createdBy|length > 0
%}
<div class="item-row details">
{% if entity.note is not empty %}
<div class="item-col comment">
{{ entity.note|chill_markdown_to_html }}
</div>
{% endif %}
</div>
{% endif %} #}
<div class="item-col">
<ul class="list-content">
<ul class="record_actions">
{# <li>
<a href="{{ path('chill_crud_aside_activity_view', { 'id': entity.id} ) }}" class="btn btn-show "></a>
</li> #}
{# TOOD
{% if is_granted('CHILL_ACTIVITY_UPDATE', activity) %}
#}
<li><a href="{{ path('chill_crud_aside_activity_edit', { 'id': entity.id }) }}" class="btn btn-update "> </a>
</li>
{# TOOD
{% endif %}
{% if is_granted('CHILL_ACTIVITY_DELETE', activity) %}
#}
<li>
<a href="{{ path('chill_crud_aside_activity_delete', { 'id': entity.id } ) }}" class="btn btn-delete "></a>
</li>
{#
{% endif %}
#}
</ul>
</ul>
</div>
</div>
{% endfor %}
</div>
<ul class="record_actions">
<li>
<a href="{{ path('chill_crud_aside_activity_new') }}" class="btn btn-create">
{{ 'Add a new aside activity' | trans }}
</a>
</li>
</ul>
</div>
{% endif %}
{% endblock %}

View File

@@ -1,11 +0,0 @@
{% extends '@ChillMain/Admin/layout.html.twig' %}
{% block title %}
{% include('@ChillMain/CRUD/_new_title.html.twig') %}
{% endblock %}
{% block admin_content %}
{% embed '@ChillMain/CRUD/_new_content.html.twig' %}
{% block content_form_actions_save_and_show %}{% endblock %}
{% endembed %}
{% endblock %}

View File

@@ -1,15 +0,0 @@
{% extends '@ChillMain/layout.html.twig' %}
{% set activeRouteKey = '' %}
{% block title %}
{% include('@ChillMain/CRUD/_view_title.html.twig') %}
{% endblock %}
{% block content %}
{% embed '@ChillMain/CRUD/_view_content.html.twig' %}
{% block crud_content_header %}
<h1>{{ ('crud.' ~ crud_name ~ '.title_view')|trans }}</h1>
{% endblock crud_content_header %}
{% endembed %}
{% endblock %}

View File

@@ -1,12 +0,0 @@
{% extends "@ChillActivity/Admin/layout_activity.html.twig" %}
{% block title %}
{% include('@ChillMain/CRUD/_edit_title.html.twig') %}
{% endblock %}
{% block layout_wvm_content %}
{% embed '@ChillMain/CRUD/_edit_content.html.twig' %}
{% block content_form_actions_view %}{% endblock %}
{% block content_form_actions_save_and_show %}{% endblock %}
{% endembed %}
{% endblock %}

View File

@@ -1,44 +0,0 @@
{% extends "@ChillAsideActivity/Admin/layout_asideactivity.html.twig" %}
{% block admin_content %}
<h1>{{ 'ActivityType list'|trans }}</h1>
<table class="records_list table table-bordered border-dark">
<thead>
<tr>
<th>{{ 'Name'|trans }}</th>
<th>{{ 'Active'|trans }}</th>
<th>{{ 'Actions'|trans }}</th>
</tr>
</thead>
<tbody>
{% for entity in entities %}
<tr>
<td>{{ entity.title|localize_translatable_string }}</td>
<td style="text-align:center;">
{%- if entity.isActive -%}
<i class="fa fa-check-square-o"></i>
{%- else -%}
<i class="fa fa-square-o"></i>
{%- endif -%}
</td>
<td>
<ul class="record_actions">
<li>
<a href="{{ path('chill_crud_aside_activity_category_edit', { 'id': entity.id }) }}" class="btn btn-edit" title="{{ 'edit'|trans }}"></a>
</li>
</ul>
</td>
</tr>
{% endfor %}
</tbody>
</table>
<ul class="record_actions">
<li>
<a href="{{ path('chill_crud_aside_activity_category_new') }}" class="btn btn-create">
{{ 'Create a new aside activity type'|trans }}
</a>
</li>
</ul>
{% endblock %}

View File

@@ -1,11 +0,0 @@
{% extends "@ChillActivity/Admin/layout_activity.html.twig" %}
{% block title %}
{% include('@ChillMain/CRUD/_new_title.html.twig') %}
{% endblock %}
{% block layout_wvm_content %}
{% embed '@ChillMain/CRUD/_new_content.html.twig' %}
{% block content_form_actions_save_and_show %}{% endblock %}
{% endembed %}
{% endblock %}

View File

@@ -1,73 +0,0 @@
<?php
namespace Chill\AsideActivityBundle\Tests\Controller;
use Chill\MainBundle\Test\PrepareClientTrait;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use Chill\AsideActivityBundle\Entity\AsideActivity;
use Doctrine\ORM\EntityManagerInterface;
class AccompanyingCourseControllerTest extends WebTestCase
{
use PrepareClientTrait;
public function setUp()
{
parent::setUp();
self::bootKernel();
$this->client = $this->getClientAuthenticated();
}
public function testIndexWithoutUsers()
{
$this->client->request('GET', '/fr/asideactivity');
$this->assertEquals(200, $this->client->getResponse()->getStatusCode());
}
public function testNewWithoutUsers()
{
$this->client->request('GET', '/fr/asideactivity/new');
$this->assertEquals(200, $this->client->getResponse()->getStatusCode());
}
/**
* @dataProvider generateAsideActivityId
*/
public function testEditWithoutUsers(int $asideActivityId)
{
$this->client->request('GET', "/fr/asideactivity/{$asideActivityId}/edit");
$this->assertEquals(200, $this->client->getResponse()->getStatusCode());
}
public function generateAsideActivityId()
{
self::bootKernel();
$qb = self::$container->get(EntityManagerInterface::class)
->createQueryBuilder();
$asideActivityIds = $qb
->select('DISTINCT asideactivity.id')
->from(AsideActivity::class, 'asideactivity')
->innerJoin('asideactivity.agent', 'agent')
->where($qb->expr()->eq('agent.username', ':center_name'))
->setParameter('center_name', 'center a_social')
->setMaxResults(100)
->getQuery()
->getResult()
;
\shuffle($asideActivityIds);
yield [ \array_pop($asideActivityIds)['id'] ];
yield [ \array_pop($asideActivityIds)['id'] ];
yield [ \array_pop($asideActivityIds)['id'] ];
}
}

View File

@@ -1,12 +0,0 @@
chill_asideactivities_controllers:
resource: "@ChillAsideActivityBundle/Controller"
type: annotation
chill_admin_aside_activity_redirect_to_admin_index:
path: /{_locale}/admin/activity_redirect_to_main
controller: Chill\ActivityBundle\Controller\AdminController::redirectToAdminIndexAction
options:
menus:
admin_aside_activity:
order: 0
label: Main admin menu

View File

@@ -1,10 +0,0 @@
---
services:
chill.asideactivity.form.type.asideactivity:
class: Chill\AsideActivityBundle\Form\AsideActivityFormType
arguments:
- "@chill.main.helper.translatable_string"
- "%chill_activity.form.time_duration%"
- "@security.token_storage"
tags:
- { name: form.type, alias: chill_asideactivitybundle_asideactivity }

View File

@@ -1,6 +0,0 @@
services:
Chill\AsideActivityBundle\Menu\SectionMenuBuilder:
arguments:
$translator: '@Symfony\Component\Translation\TranslatorInterface'
tags:
- { name: "chill.menu_builder" }

View File

@@ -1,48 +0,0 @@
<?php
declare(strict_types=1);
namespace Chill\Migrations\AsideActivity;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20210706124644 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
$this->addSql('CREATE SEQUENCE AsideActivity_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
$this->addSql('CREATE SEQUENCE AsideActivityType_id_seq INCREMENT BY 1 MINVALUE 1 START 1000');
$this->addSql('CREATE TABLE AsideActivity (id INT NOT NULL, type_id INT NOT NULL, agent_id INT NOT NULL, createdAt TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, updatedAt TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL, date TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, duration TIME(0) WITHOUT TIME ZONE DEFAULT NULL, location VARCHAR(100) DEFAULT NULL, note TEXT DEFAULT NULL, createdBy_id INT NOT NULL, updatedBy_id INT DEFAULT NULL, PRIMARY KEY(id))');
$this->addSql('CREATE INDEX IDX_E9FA2191C54C8C93 ON AsideActivity (type_id)');
$this->addSql('CREATE INDEX IDX_E9FA21913174800F ON AsideActivity (createdBy_id)');
$this->addSql('CREATE INDEX IDX_E9FA219165FF1AEC ON AsideActivity (updatedBy_id)');
$this->addSql('CREATE INDEX IDX_E9FA21913414710B ON AsideActivity (agent_id)');
$this->addSql('COMMENT ON COLUMN AsideActivity.updatedAt IS \'(DC2Type:datetime_immutable)\'');
$this->addSql('CREATE TABLE AsideActivityType (id INT NOT NULL, title VARCHAR(255) NOT NULL, isActive BOOLEAN NOT NULL, PRIMARY KEY(id))');
$this->addSql('ALTER TABLE AsideActivity ADD CONSTRAINT FK_E9FA2191C54C8C93 FOREIGN KEY (type_id) REFERENCES AsideActivityType (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('ALTER TABLE AsideActivity ADD CONSTRAINT FK_E9FA21913174800F FOREIGN KEY (createdBy_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('ALTER TABLE AsideActivity ADD CONSTRAINT FK_E9FA219165FF1AEC FOREIGN KEY (updatedBy_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('ALTER TABLE AsideActivity ADD CONSTRAINT FK_E9FA21913414710B FOREIGN KEY (agent_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
// this up() migration is auto-generated, please modify it to your needs
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE AsideActivity DROP CONSTRAINT FK_E9FA2191C54C8C93');
$this->addSql('DROP SEQUENCE AsideActivity_id_seq CASCADE');
$this->addSql('DROP SEQUENCE AsideActivityType_id_seq CASCADE');
$this->addSql('DROP TABLE AsideActivity');
$this->addSql('DROP TABLE AsideActivityType');
}
}

View File

@@ -1,70 +0,0 @@
<?php
declare(strict_types=1);
namespace Application\Migrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20210804082249 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE SCHEMA chill_asideactivity');
$this->addSql('ALTER TABLE asideactivity DROP CONSTRAINT fk_e9fa2191c54c8c93');
$this->addSql('DROP SEQUENCE asideactivity_id_seq CASCADE');
$this->addSql('DROP SEQUENCE asideactivitytype_id_seq CASCADE');
$this->addSql('CREATE SEQUENCE chill_asideactivity.AsideActivity_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
$this->addSql('CREATE SEQUENCE chill_asideactivity.AsideActivityCategory_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
$this->addSql('CREATE TABLE chill_asideactivity.AsideActivity (id INT NOT NULL, type_id INT NOT NULL, agent_id INT NOT NULL, createdAt TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, updatedAt TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL, date TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, duration INT DEFAULT NULL, location VARCHAR(100) DEFAULT NULL, note TEXT DEFAULT NULL, createdBy_id INT NOT NULL, updatedBy_id INT DEFAULT NULL, PRIMARY KEY(id))');
$this->addSql('CREATE INDEX IDX_A866DA0EC54C8C93 ON chill_asideactivity.AsideActivity (type_id)');
$this->addSql('CREATE INDEX IDX_A866DA0E3174800F ON chill_asideactivity.AsideActivity (createdBy_id)');
$this->addSql('CREATE INDEX IDX_A866DA0E65FF1AEC ON chill_asideactivity.AsideActivity (updatedBy_id)');
$this->addSql('CREATE INDEX IDX_A866DA0E3414710B ON chill_asideactivity.AsideActivity (agent_id)');
$this->addSql('COMMENT ON COLUMN chill_asideactivity.AsideActivity.createdAt IS \'(DC2Type:datetime_immutable)\'');
$this->addSql('COMMENT ON COLUMN chill_asideactivity.AsideActivity.updatedAt IS \'(DC2Type:datetime_immutable)\'');
$this->addSql('COMMENT ON COLUMN chill_asideactivity.AsideActivity.date IS \'(DC2Type:datetime_immutable)\'');
$this->addSql('CREATE TABLE chill_asideactivity.AsideActivityCategory (id INT NOT NULL, title JSON NOT NULL, isActive BOOLEAN NOT NULL, PRIMARY KEY(id))');
$this->addSql('ALTER TABLE chill_asideactivity.AsideActivity ADD CONSTRAINT FK_A866DA0EC54C8C93 FOREIGN KEY (type_id) REFERENCES chill_asideactivity.AsideActivityCategory (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('ALTER TABLE chill_asideactivity.AsideActivity ADD CONSTRAINT FK_A866DA0E3174800F FOREIGN KEY (createdBy_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('ALTER TABLE chill_asideactivity.AsideActivity ADD CONSTRAINT FK_A866DA0E65FF1AEC FOREIGN KEY (updatedBy_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('ALTER TABLE chill_asideactivity.AsideActivity ADD CONSTRAINT FK_A866DA0E3414710B FOREIGN KEY (agent_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('DROP TABLE asideactivitytype');
$this->addSql('DROP TABLE asideactivity');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE SCHEMA public');
$this->addSql('ALTER TABLE chill_asideactivity.AsideActivity DROP CONSTRAINT FK_A866DA0EC54C8C93');
$this->addSql('DROP SEQUENCE chill_asideactivity.AsideActivity_id_seq CASCADE');
$this->addSql('DROP SEQUENCE chill_asideactivity.AsideActivityCategory_id_seq CASCADE');
$this->addSql('CREATE SEQUENCE asideactivity_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
$this->addSql('CREATE SEQUENCE asideactivitytype_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
$this->addSql('CREATE TABLE asideactivitytype (id INT NOT NULL, title VARCHAR(255) NOT NULL, isactive BOOLEAN NOT NULL, PRIMARY KEY(id))');
$this->addSql('CREATE TABLE asideactivity (id INT NOT NULL, type_id INT NOT NULL, agent_id INT NOT NULL, createdby_id INT NOT NULL, updatedby_id INT DEFAULT NULL, createdat TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, updatedat TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL, date TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, duration TIME(0) WITHOUT TIME ZONE DEFAULT NULL, location VARCHAR(100) DEFAULT NULL, note TEXT DEFAULT NULL, PRIMARY KEY(id))');
$this->addSql('CREATE INDEX idx_e9fa21913174800f ON asideactivity (createdby_id)');
$this->addSql('CREATE INDEX idx_e9fa2191c54c8c93 ON asideactivity (type_id)');
$this->addSql('CREATE INDEX idx_e9fa219165ff1aec ON asideactivity (updatedby_id)');
$this->addSql('CREATE INDEX idx_e9fa21913414710b ON asideactivity (agent_id)');
$this->addSql('COMMENT ON COLUMN asideactivity.updatedat IS \'(DC2Type:datetime_immutable)\'');
$this->addSql('CREATE TABLE chill_main_address_legacy (id INT DEFAULT NULL, postcode_id INT DEFAULT NULL, street VARCHAR(255) DEFAULT NULL, streetnumber VARCHAR(255) DEFAULT NULL, validfrom DATE DEFAULT NULL, isnoaddress BOOLEAN DEFAULT NULL, customs JSONB DEFAULT NULL, floor VARCHAR(16) DEFAULT NULL, corridor VARCHAR(16) DEFAULT NULL, steps VARCHAR(16) DEFAULT NULL, buildingname VARCHAR(255) DEFAULT NULL, flat VARCHAR(16) DEFAULT NULL, distribution VARCHAR(255) DEFAULT NULL, extra VARCHAR(255) DEFAULT NULL, validto DATE DEFAULT NULL, point VARCHAR(255) DEFAULT NULL, linkedtothirdparty_id INT DEFAULT NULL)');
$this->addSql('ALTER TABLE asideactivity ADD CONSTRAINT fk_e9fa2191c54c8c93 FOREIGN KEY (type_id) REFERENCES asideactivitytype (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('ALTER TABLE asideactivity ADD CONSTRAINT fk_e9fa21913174800f FOREIGN KEY (createdby_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('ALTER TABLE asideactivity ADD CONSTRAINT fk_e9fa219165ff1aec FOREIGN KEY (updatedby_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('ALTER TABLE asideactivity ADD CONSTRAINT fk_e9fa21913414710b FOREIGN KEY (agent_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('DROP TABLE chill_asideactivity.AsideActivity');
$this->addSql('DROP TABLE chill_asideactivity.AsideActivityCategory');
}
}

View File

@@ -1,31 +0,0 @@
<?php
declare(strict_types=1);
namespace Application\Migrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20210806140343 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE chill_asideactivity.asideactivity DROP duration');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE chill_asideactivity.AsideActivity ADD duration INT DEFAULT NULL');
}
}

View File

@@ -1,32 +0,0 @@
<?php
declare(strict_types=1);
namespace Application\Migrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20210806140710 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE chill_asideactivity.asideactivity ADD duration TIME(0) WITHOUT TIME ZONE DEFAULT NULL');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE chill_asideactivity.AsideActivity DROP duration');
}
}

View File

@@ -1,48 +0,0 @@
<?php
declare(strict_types=1);
namespace Application\Migrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20210810084456 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE chill_asideactivity.asideactivity ALTER createdat TYPE TIMESTAMP(0) WITHOUT TIME ZONE');
$this->addSql('ALTER TABLE chill_asideactivity.asideactivity ALTER createdat DROP DEFAULT');
$this->addSql('ALTER TABLE chill_asideactivity.asideactivity ALTER updatedat TYPE TIMESTAMP(0) WITHOUT TIME ZONE');
$this->addSql('ALTER TABLE chill_asideactivity.asideactivity ALTER updatedat DROP DEFAULT');
$this->addSql('ALTER TABLE chill_asideactivity.asideactivity ALTER date TYPE TIMESTAMP(0) WITHOUT TIME ZONE');
$this->addSql('ALTER TABLE chill_asideactivity.asideactivity ALTER date DROP DEFAULT');
$this->addSql('COMMENT ON COLUMN chill_asideactivity.asideactivity.createdAt IS NULL');
$this->addSql('COMMENT ON COLUMN chill_asideactivity.asideactivity.updatedAt IS NULL');
$this->addSql('COMMENT ON COLUMN chill_asideactivity.asideactivity.date IS NULL');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE chill_asideactivity.AsideActivity ALTER createdAt TYPE TIMESTAMP(0) WITHOUT TIME ZONE');
$this->addSql('ALTER TABLE chill_asideactivity.AsideActivity ALTER createdAt DROP DEFAULT');
$this->addSql('ALTER TABLE chill_asideactivity.AsideActivity ALTER updatedAt TYPE TIMESTAMP(0) WITHOUT TIME ZONE');
$this->addSql('ALTER TABLE chill_asideactivity.AsideActivity ALTER updatedAt DROP DEFAULT');
$this->addSql('ALTER TABLE chill_asideactivity.AsideActivity ALTER date TYPE TIMESTAMP(0) WITHOUT TIME ZONE');
$this->addSql('ALTER TABLE chill_asideactivity.AsideActivity ALTER date DROP DEFAULT');
$this->addSql('COMMENT ON COLUMN chill_asideactivity.AsideActivity.createdat IS \'(DC2Type:datetime_immutable)\'');
$this->addSql('COMMENT ON COLUMN chill_asideactivity.AsideActivity.updatedat IS \'(DC2Type:datetime_immutable)\'');
$this->addSql('COMMENT ON COLUMN chill_asideactivity.AsideActivity.date IS \'(DC2Type:datetime_immutable)\'');
}
}

View File

@@ -1,87 +0,0 @@
#general
Show the aside activity: Voir l'activité annexe
Edit the aside activity: Modifier l'activité annexe
Remove aside activity: Supprimer l'activité annexe
Aside activity: Activité annexe
Duration time: Durée
durationTime: durée
user_username: nom de l'utilisateur
Remark: Commentaire
No comments: Aucun commentaire
Add a new aside activity: Ajouter une nouvelle activité annexe
Aside activity list: Activités annexes
present: présent
not present: absent
Delete: Supprimer
Update: Mettre à jour
Update activity: Modifier l'activité
Aside activity data: Données de l'activité annexe
No reason associated: Aucun sujet
There aren't any aside activities.: Aucune activité annexe enregistrée.
type_name: type de l'activité
Type: Type
Invisible: Invisible
Optional: Optionnel
Required: Obligatoire
Persons: Personnes
Users: Utilisateurs
Emergency: Urgent
by: "Par "
location: Lieu
# Crud
crud:
aside_activity:
title_view: Détail de l'activité annexe
title_new: Nouvelle activité annexe
title_edit: Edition d'une activité annexe
title_delete: Supprimation d'une activité annexe
button_delete: Supprimer
confirm_message_delete: Êtes-vous sûr de vouloir supprimer cet activité annexe?
aside_activity_category:
title_new: Nouvelle catégorie d'activité annexe
title_edit: Edition d'une catégorie de type d'activité
#forms
Activity creation: Nouvelle activité annexe
Create a new aside activity type: Nouvelle categorie d'activité annexe
Create: Créer
Back to the list: Retour à la liste
Save activity: Sauver l'activité
Reset form: Remise à zéro du formulaire
Choose the agent for whom this activity is created: Choissisez l'utilisateur pour qui l'activité est creéé.
Choose the activity category: Choissisez le type d'activité
Choose the duration: Choisir la durée
Choose a category: Choisir un categorie
Is active: Actif
Agent: Utilisateur
date: Date
Duration: Durée
Note: Note
5 minutes: 5 minutes
10 minutes: 10 minutes
15 minutes: 15 minutes
20 minutes: 20 minutes
25 minutes: 25 minutes
30 minutes: 30 minutes
45 minutes: 45 minutes
1 hour: 1 heure
1 hour 15: 1 heure 15
1 hour 30: 1 heure 30
1 hour 45: 1 heure 45
2 hours: 2 heures
#list
My aside activities: Mes activités annexes
Date: Date
Created by: Creér par
#Aside activity delete
Delete aside activity: Supprimer une activité annexe
Are you sure you want to remove the aside activity concerning "%name%" ?: Êtes-vous sûr de vouloir supprimer une activité annexe qui concerne "%name%" ?
The activity has been successfully removed.: L'activité a été supprimée.
#Menu
Create an aside activity: "Creér une activité annexe"
Aside activity configuration menu: "Menu de configuration des activités annexes"
Aside activity configuration: "Configuration des activités annexes"

View File

@@ -0,0 +1,11 @@
composer.lock
vendor/*
parameters.yml
*~
*.DS_Store
*.sass-cache
Resources/node_modules/
Tests/Fixtures/App/app/config/parameters.yml
/nbproject/private/
Resources/test/Fixtures/App/bootstrap.php.cache

View File

@@ -0,0 +1,9 @@
<?php
namespace Chill\CalendarBundle;
use Symfony\Component\HttpKernel\Bundle\Bundle;
class ChillCalendarBundle extends Bundle
{
}

View File

@@ -0,0 +1,390 @@
<?php
/*
* Chill is a software for social workers
*
* Copyright (C) 2014-2015, Champs Libres Cooperative SCRLFS,
* <http://www.champs-libres.coop>, <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\CalendarBundle\Controller;
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\Person;
use Chill\PersonBundle\Privacy\PrivacyEvent;
use Psr\Log\LoggerInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Form\Form;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Role\Role;
use Chill\CalendarBundle\Entity\Calendar;
use Chill\CalendarBundle\Form\CalendarType;
use Chill\MainBundle\Entity\User;
use Symfony\Component\Serializer\SerializerInterface;
use Symfony\Component\Routing\Annotation\Route;
/**
* Class CalendarController
*
* @package Chill\CalendarBundle\Controller
*/
class CalendarController extends AbstractController
{
protected EventDispatcherInterface $eventDispatcher;
protected AuthorizationHelper $authorizationHelper;
protected LoggerInterface $logger;
protected SerializerInterface $serializer;
public function __construct(
EventDispatcherInterface $eventDispatcher,
AuthorizationHelper $authorizationHelper,
LoggerInterface $logger,
SerializerInterface $serializer
) {
$this->eventDispatcher = $eventDispatcher;
$this->authorizationHelper = $authorizationHelper;
$this->logger = $logger;
$this->serializer = $serializer;
}
/**
* Lists all Calendar entities.
* @Route("/{_locale}/calendar/", name="chill_calendar_calendar")
*/
public function listAction(Request $request): Response
{
$em = $this->getDoctrine()->getManager();
$view = null;
[$user, $accompanyingPeriod] = $this->getEntity($request);
if ($user instanceof User) {
// $calendar = $em->getRepository(Calendar::class)
// ->findByUser($user)
// ;
// $view = 'ChillCalendarBundle:Calendar:listByUser.html.twig';
} elseif ($accompanyingPeriod instanceof AccompanyingPeriod) {
$calendarItems = $em->getRepository(Calendar::class)->findBy(
['accompanyingPeriod' => $accompanyingPeriod]
);
$view = 'ChillCalendarBundle:Calendar:listByAccompanyingCourse.html.twig';
}
return $this->render($view, [
'calendarItems' => $calendarItems,
'user' => $user,
'accompanyingCourse' => $accompanyingPeriod,
]);
}
/**
* Create a new calendar item
* @Route("/{_locale}/calendar/new", name="chill_calendar_calendar_new")
*/
public function newAction(Request $request): Response
{
$em = $this->getDoctrine()->getManager();
[$user, $accompanyingPeriod] = $this->getEntity($request);
if ($accompanyingPeriod instanceof AccompanyingPeriod) {
$view = 'ChillCalendarBundle:Calendar:newAccompanyingCourse.html.twig';
}
// elseif ($user instanceof User) {
// $view = 'ChillCalendarBundle:Calendar:newUser.html.twig';
// }
$entity = new Calendar();
$entity->setUser($this->getUser());
$entity->setStatus($entity::STATUS_VALID);
// if ($user instanceof User) {
// $entity->setPerson($user);
// }
if ($accompanyingPeriod instanceof AccompanyingPeriod) {
$entity->setAccompanyingPeriod($accompanyingPeriod);
}
$form = $this->createForm(CalendarType::class, $entity, [
'accompanyingPeriod' => $accompanyingPeriod,
])->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em->persist($entity);
$em->flush();
$this->addFlash('success', $this->get('translator')->trans('Success : calendar item created!'));
$params = $this->buildParamsToUrl($user, $accompanyingPeriod); //TODO useful?
$params['id'] = $entity->getId();
return $this->redirectToRoute('chill_calendar_calendar_show', $params);
} elseif ($form->isSubmitted() and !$form->isValid()) {
$this->addFlash('error', $this->get('translator')->trans('This form contains errors'));
}
if ($view === null) {
throw $this->createNotFoundException('Template not found');
}
$entity_array = $this->serializer->normalize($entity, 'json', ['groups' => 'read']);
return $this->render($view, [
'user' => $user,
'accompanyingCourse' => $accompanyingPeriod,
'entity' => $entity,
'form' => $form->createView(),
'entity_json' => $entity_array
]);
}
/**
* Show a calendar item
* @Route("/{_locale}/calendar/{id}/show", name="chill_calendar_calendar_show")
*/
public function showAction(Request $request, $id): Response
{
$em = $this->getDoctrine()->getManager();
[$user, $accompanyingPeriod] = $this->getEntity($request);
if ($accompanyingPeriod instanceof AccompanyingPeriod) {
$view = 'ChillCalendarBundle:Calendar:showAccompanyingCourse.html.twig';
}
// elseif ($person instanceof Person) {
// $view = 'ChillCalendarBundle:Calendar:showPerson.html.twig';
// }
$entity = $em->getRepository('ChillCalendarBundle:Calendar')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find Calendar entity.');
}
if (null !== $accompanyingPeriod) {
$entity->personsAssociated = $entity->getPersonsAssociated();
$entity->personsNotAssociated = $entity->getPersonsNotAssociated();
}
// $deleteForm = $this->createDeleteForm($id, $accompanyingPeriod);
if ($view === null) {
throw $this->createNotFoundException('Template not found');
}
return $this->render($view, [
//'person' => $person,
'accompanyingCourse' => $accompanyingPeriod,
'entity' => $entity,
//'delete_form' => $deleteForm->createView(),
]);
}
/**
* Edit a calendar item
* @Route("/{_locale}/calendar/{id}/edit", name="chill_calendar_calendar_edit")
*/
public function editAction($id, Request $request): Response
{
$em = $this->getDoctrine()->getManager();
[$user, $accompanyingPeriod] = $this->getEntity($request);
if ($accompanyingPeriod instanceof AccompanyingPeriod) {
$view = 'ChillCalendarBundle:Calendar:editAccompanyingCourse.html.twig';
}
// elseif ($person instanceof Person) {
// $view = 'ChillCalendarBundle:Calendar:editPerson.html.twig';
// }
$entity = $em->getRepository('ChillCalendarBundle:Calendar')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find Calendar entity.');
}
$form = $this->createForm(CalendarType::class, $entity, [
'accompanyingPeriod' => $accompanyingPeriod,
])->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em->persist($entity);
$em->flush();
$this->addFlash('success', $this->get('translator')->trans('Success : calendar item updated!'));
$params = $this->buildParamsToUrl($user, $accompanyingPeriod);
$params['id'] = $id;
return $this->redirectToRoute('chill_calendar_calendar_show', $params);
} elseif ($form->isSubmitted() and !$form->isValid()) {
$this->addFlash('error', $this->get('translator')->trans('This form contains errors'));
}
$deleteForm = $this->createDeleteForm($id, $user, $accompanyingPeriod);
if ($view === null) {
throw $this->createNotFoundException('Template not found');
}
$entity_array = $this->serializer->normalize($entity, 'json', ['groups' => 'read']);
return $this->render($view, [
'entity' => $entity,
'form' => $form->createView(),
'delete_form' => $deleteForm->createView(),
'accompanyingCourse' => $accompanyingPeriod,
'entity_json' => $entity_array
]);
}
/**
* Delete a calendar item
* @Route("/{_locale}/calendar/{id}/delete", name="chill_calendar_calendar_delete")
*/
public function deleteAction(Request $request, $id)
{
$em = $this->getDoctrine()->getManager();
[$user, $accompanyingPeriod] = $this->getEntity($request);
if ($accompanyingPeriod instanceof AccompanyingPeriod) {
$view = 'ChillCalendarBundle:Calendar:confirm_deleteAccompanyingCourse.html.twig';
}
// elseif ($person instanceof Person) {
// $view = 'ChillCalendarBundle:Calendar:confirm_deletePerson.html.twig';
// }
/* @var $entity Calendar */
$entity = $em->getRepository('ChillCalendarBundle:Calendar')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find Calendar entity.');
}
$form = $this->createDeleteForm($id, $user, $accompanyingPeriod);
if ($request->getMethod() === Request::METHOD_DELETE) {
$form->handleRequest($request);
if ($form->isValid()) {
$this->logger->notice("A calendar event has been removed", [
'by_user' => $this->getUser()->getUsername(),
'calendar_id' => $entity->getId()
]);
$em->remove($entity);
$em->flush();
$this->addFlash('success', $this->get('translator')
->trans("The calendar has been successfully removed."));
$params = $this->buildParamsToUrl($user, $accompanyingPeriod);
return $this->redirectToRoute('chill_calendar_calendar', $params);
}
}
if ($view === null) {
throw $this->createNotFoundException('Template not found');
}
return $this->render($view, [
'calendar' => $entity,
'delete_form' => $form->createView(),
'accompanyingCourse' => $accompanyingPeriod,
]);
}
/**
* Creates a form to delete a Calendar entity by id.
*/
private function createDeleteForm(int $id, ?Person $person, ?AccompanyingPeriod $accompanyingPeriod): Form
{
$params = $this->buildParamsToUrl($person, $accompanyingPeriod);
$params['id'] = $id;
return $this->createFormBuilder()
->setAction($this->generateUrl('chill_calendar_calendar_delete', $params))
->setMethod('DELETE')
->add('submit', SubmitType::class, ['label' => 'Delete'])
->getForm()
;
}
private function getEntity(Request $request): array
{
$em = $this->getDoctrine()->getManager();
$user = $accompanyingPeriod = null;
if ($request->query->has('user_id')) {
$user_id = $request->get('user_id');
$user = $em->getRepository(User::class)->find($user_id);
if ($user === null) {
throw $this->createNotFoundException('User not found');
}
$this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $user);
} elseif ($request->query->has('accompanying_period_id')) {
$accompanying_period_id = $request->get('accompanying_period_id');
$accompanyingPeriod = $em->getRepository(AccompanyingPeriod::class)->find($accompanying_period_id);
if ($accompanyingPeriod === null) {
throw $this->createNotFoundException('Accompanying Period not found');
}
// TODO Add permission
// $this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person);
} else {
throw $this->createNotFoundException("Person or Accompanying Period not found");
}
return [
$user, $accompanyingPeriod
];
}
private function buildParamsToUrl(
?User $user,
?AccompanyingPeriod $accompanyingPeriod
): array {
$params = [];
if ($user) {
$params['user_id'] = $user->getId();
}
if ($accompanyingPeriod) {
$params['accompanying_period_id'] = $accompanyingPeriod->getId();
}
return $params;
}
}

View File

@@ -0,0 +1,46 @@
<?php
namespace Chill\CalendarBundle\DataFixtures\ORM;
use Chill\CalendarBundle\Entity\CancelReason;
use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Bundle\FixturesBundle\FixtureGroupInterface;
use Doctrine\Persistence\ObjectManager;
class LoadCancelReason extends Fixture implements FixtureGroupInterface
{
public function getOrder(): int
{
return 40001;
}
public static function getGroups(): array
{
return ['calendar'];
}
public static $references = [];
public function load(ObjectManager $manager): void
{
$arr = [
['name' => CancelReason::CANCELEDBY_USER],
['name' => CancelReason::CANCELEDBY_PERSON],
['name' => CancelReason::CANCELEDBY_DONOTCOUNT],
];
foreach ($arr as $a) {
print "Creating calendar cancel reason : " . $a['name'] . "\n";
$cancelReason= (new CancelReason())
->setCanceledBy($a['name'])
->setActive(true);
$manager->persist($cancelReason);
$reference = 'CancelReason_'.$a['name'];
$this->addReference($reference, $cancelReason);
static::$references[] = $reference;
}
$manager->flush();
}
}

View File

@@ -0,0 +1,44 @@
<?php
namespace Chill\CalendarBundle\DataFixtures\ORM;
use Chill\CalendarBundle\Entity\Invite;
use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Bundle\FixturesBundle\FixtureGroupInterface;
use Doctrine\Persistence\ObjectManager;
class LoadInvite extends Fixture implements FixtureGroupInterface
{
public function getOrder(): int
{
return 40002;
}
public static function getGroups(): array
{
return ['calendar'];
}
public static $references = [];
public function load(ObjectManager $manager): void
{
$arr = [
['name' => ['fr' => 'Rendez-vous décliné']],
['name' => ['fr' => 'Rendez-vous accepté']],
];
foreach ($arr as $a) {
print "Creating calendar invite : " . $a['name']['fr'] . "\n";
$invite= (new Invite())
->setStatus($a['name']);
$manager->persist($invite);
$reference = 'Invite_'.$a['name']['fr'];
$this->addReference($reference, $invite);
static::$references[] = $reference;
}
$manager->flush();
}
}

View File

@@ -0,0 +1,51 @@
<?php
namespace Chill\CalendarBundle\DependencyInjection;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Symfony\Component\DependencyInjection\Loader;
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
/**
* This is the class that loads and manages your bundle configuration.
*
* @link http://symfony.com/doc/current/cookbook/bundles/extension.html
*/
class ChillCalendarExtension extends Extension implements PrependExtensionInterface
{
/**
* {@inheritdoc}
*/
public function load(array $configs, ContainerBuilder $container)
{
$configuration = new Configuration();
$config = $this->processConfiguration($configuration, $configs);
$loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
$loader->load('services.yml');
$loader->load('services/controller.yml');
$loader->load('services/fixtures.yml');
$loader->load('services/form.yml');
}
public function prepend(ContainerBuilder $container)
{
$this->preprendRoutes($container);
}
protected function preprendRoutes(ContainerBuilder $container)
{
$container->prependExtensionConfig('chill_main', [
'routing' => [
'resources' => [
'@ChillCalendarBundle/Resources/config/routing.yml'
]
]
]);
}
}

View File

@@ -0,0 +1,29 @@
<?php
namespace Chill\CalendarBundle\DependencyInjection;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;
/**
* This is the class that validates and merges configuration from your app/config files.
*
* To learn more see {@link http://symfony.com/doc/current/cookbook/bundles/configuration.html}
*/
class Configuration implements ConfigurationInterface
{
/**
* {@inheritdoc}
*/
public function getConfigTreeBuilder()
{
$treeBuilder = new TreeBuilder('chill_calendar');
$rootNode = $treeBuilder->getRootNode('chill_calendar');
// Here you should define the parameters that are allowed to
// configure your bundle. See the documentation linked above for
// more information on that topic.
return $treeBuilder;
}
}

View File

@@ -0,0 +1,401 @@
<?php
namespace Chill\CalendarBundle\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\Collection;
use Symfony\Component\Serializer\Annotation\Groups;
use Chill\MainBundle\Entity\User;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\Person;
use Chill\ThirdPartyBundle\Entity\ThirdParty;
use Chill\MainBundle\Entity\Embeddable\CommentEmbeddable;
use Chill\CalendarBundle\Entity\CancelReason;
use Chill\CalendarBundle\Entity\CalendarRange;
use Chill\CalendarBundle\Entity\Invite;
use Chill\ActivityBundle\Entity\Activity;
use Chill\CalendarBundle\Repository\CalendarRepository;
use DateInterval;
use DateTimeImmutable;
use Symfony\Component\Validator\Constraints\NotBlank;
use Symfony\Component\Validator\Constraints\Range;
use Symfony\Component\Validator\Mapping\ClassMetadata;
/**
* @ORM\Table(name="chill_calendar.calendar")
* @ORM\Entity(repositoryClass=CalendarRepository::class)
*/
class Calendar
{
const STATUS_VALID = 'valid';
const STATUS_CANCELED = 'canceled';
const STATUS_MOVED = 'moved';
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private ?int $id;
/**
* @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\User")
*/
private User $user;
/**
* @ORM\ManyToOne(targetEntity="Chill\PersonBundle\Entity\AccompanyingPeriod")
* @Groups({"read"})
*/
private AccompanyingPeriod $accompanyingPeriod;
/**
* @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\User")
*/
private ?User $mainUser;
/**
*
* @ORM\ManyToMany(
* targetEntity="Chill\PersonBundle\Entity\Person",
* cascade={"persist", "remove", "merge", "detach"})
* @ORM\JoinTable(name="chill_calendar.calendar_to_persons")
* @Groups({"read"})
*/
private Collection $persons;
/**
*
* @ORM\ManyToMany(
* targetEntity="Chill\ThirdPartyBundle\Entity\ThirdParty",
* cascade={"persist", "remove", "merge", "detach"})
* @ORM\JoinTable(name="chill_calendar.calendar_to_thirdparties")
* @Groups({"read"})
*/
private Collection $professionals;
/**
*
* @ORM\ManyToMany(
* targetEntity="Invite",
* cascade={"persist", "remove", "merge", "detach"})
* @ORM\JoinTable(name="chill_calendar.calendar_to_invites")
* @Groups({"read"})
*/
private Collection $invites;
/**
* @ORM\Embedded(class=CommentEmbeddable::class, columnPrefix="comment_")
*/
private CommentEmbeddable $comment;
/**
* @ORM\Column(type="datetimetz_immutable")
*/
private \DateTimeImmutable $startDate;
/**
* @ORM\Column(type="datetimetz_immutable")
*/
private \DateTimeImmutable $endDate;
//TODO Lieu
/**
* @ORM\Column(type="string", length=255)
*/
private string $status;
/**
* @ORM\ManyToOne(targetEntity="CancelReason")
*/
private ?CancelReason $cancelReason = null;
/**
* @ORM\ManyToOne(targetEntity="CalendarRange")
*/
private ?CalendarRange $calendarRange = null;
/**
* @ORM\ManyToOne(targetEntity="Chill\ActivityBundle\Entity\Activity")
*/
private Activity $activity;
/**
* @ORM\Column(type="boolean", nullable=true)
*/
private ?bool $sendSMS;
public function __construct()
{
$this->comment = new CommentEmbeddable();
$this->persons = new ArrayCollection();
$this->professionals = new ArrayCollection();
$this->invites = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
public function getSendSMS(): ?bool
{
return $this->sendSMS;
}
public function setSendSMS(?bool $sendSMS): self
{
$this->sendSMS = $sendSMS;
return $this;
}
public function getComment(): CommentEmbeddable
{
return $this->comment;
}
public function setComment(CommentEmbeddable $comment): self
{
$this->comment = $comment;
return $this;
}
public function getStartDate(): ?\DateTimeImmutable
{
return $this->startDate;
}
public function setStartDate(\DateTimeImmutable $startDate): self
{
$this->startDate = $startDate;
return $this;
}
public function getEndDate(): ?\DateTimeImmutable
{
return $this->endDate;
}
public function setEndDate(\DateTimeImmutable $endDate): self
{
$this->endDate = $endDate;
return $this;
}
public function getStatus(): ?string
{
return $this->status;
}
public function setStatus(string $status): self
{
$this->status = $status;
return $this;
}
public function getUser(): ?User
{
return $this->user;
}
public function setUser(?User $user): self
{
$this->user = $user;
return $this;
}
public function getAccompanyingPeriod(): ?AccompanyingPeriod
{
return $this->accompanyingPeriod;
}
public function setAccompanyingPeriod(?AccompanyingPeriod $accompanyingPeriod): self
{
$this->accompanyingPeriod = $accompanyingPeriod;
return $this;
}
public function getMainUser(): ?User
{
return $this->mainUser;
}
public function setMainUser(?User $mainUser): self
{
$this->mainUser = $mainUser;
return $this;
}
/**
* @return Collection|Person[]
*/
public function getPersons(): Collection
{
return $this->persons;
}
public function addPerson(?Person $person): self
{
if (null !== $person) {
$this->persons[] = $person;
}
return $this;
}
public function removePerson(Person $person): self
{
$this->persons->removeElement($person);
return $this;
}
/**
* @return Collection|ThirdParty[]
*/
public function getProfessionals(): Collection
{
return $this->professionals;
}
public function addProfessional(?ThirdParty $professional): self
{
if (null !== $professional) {
$this->professionals[] = $professional;
}
return $this;
}
public function removeProfessional(ThirdParty $professional): self
{
$this->professionals->removeElement($professional);
return $this;
}
/**
* @return Collection|Invite[]
*/
public function getInvites(): Collection
{
return $this->invites;
}
public function addInvite(?Invite $invite): self
{
if (null !== $invite) {
$this->invites[] = $invite;
}
return $this;
}
public function removeInvite(Invite $invite): self
{
$this->invites->removeElement($invite);
return $this;
}
public function getCancelReason(): ?CancelReason
{
return $this->cancelReason;
}
public function setCancelReason(?CancelReason $cancelReason): self
{
$this->cancelReason = $cancelReason;
return $this;
}
public function getCalendarRange(): ?CalendarRange
{
return $this->calendarRange;
}
public function setCalendarRange(?CalendarRange $calendarRange): self
{
$this->calendarRange = $calendarRange;
return $this;
}
public function getActivity(): ?Activity
{
return $this->activity;
}
public function setActivity(?Activity $activity): self
{
$this->activity = $activity;
return $this;
}
public function getPersonsAssociated(): array
{
if (null !== $this->accompanyingPeriod) {
$personsAssociated = [];
foreach ($this->accompanyingPeriod->getParticipations() as $participation) {
if ($this->persons->contains($participation->getPerson())) {
$personsAssociated[] = $participation->getPerson();
}
}
return $personsAssociated;
}
return [];
}
public function getPersonsNotAssociated(): array
{
if (null !== $this->accompanyingPeriod) {
$personsNotAssociated = [];
foreach ($this->persons as $person) {
if (!in_array($person, $this->getPersonsAssociated())) {
$personsNotAssociated[] = $person;
}
}
return $personsNotAssociated;
}
return [];
}
public function getThirdParties(): Collection
{
return $this->getProfessionals();
}
public function getusers(): Collection
{
return $this->getInvites(); //TODO get users of the invite
}
public static function loadValidatorMetadata(ClassMetadata $metadata): void
{
$metadata->addPropertyConstraint('startDate', new NotBlank());
$metadata->addPropertyConstraint('startDate', new Range([
'min' => '2 years ago',
'max' => '+ 2 years',
]));
$metadata->addPropertyConstraint('endDate', new NotBlank());
$metadata->addPropertyConstraint('endDate', new Range([
'min' => '2 years ago',
'max' => '+ 2 years',
]));
}
}

View File

@@ -0,0 +1,81 @@
<?php
namespace Chill\CalendarBundle\Entity;
use Chill\CalendarBundle\Repository\CalendarRangeRepository;
use Chill\MainBundle\Entity\User;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Table(name="chill_calendar.calendar_range")
* @ORM\Entity(repositoryClass=CalendarRangeRepository::class)
*/
class CalendarRange
{
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\User")
*/
private User $user;
/**
* @ORM\Column(type="datetimetz_immutable")
*/
private \DateTimeImmutable $startDate;
/**
* @ORM\Column(type="datetimetz_immutable")
*/
private \DateTimeImmutable $endDate;
//TODO Lieu
public function getId(): ?int
{
return $this->id;
}
public function getStartDate(): ?\DateTimeImmutable
{
return $this->startDate;
}
public function setStartDate(\DateTimeImmutable $startDate): self
{
$this->startDate = $startDate;
return $this;
}
public function getEndDate(): ?\DateTimeImmutable
{
return $this->endDate;
}
public function setEndDate(\DateTimeImmutable $endDate): self
{
$this->endDate = $endDate;
return $this;
}
public function getUser(): ?User
{
return $this->user;
}
public function setUser(?User $user): self
{
$this->user = $user;
return $this;
}
}

View File

@@ -0,0 +1,81 @@
<?php
namespace Chill\CalendarBundle\Entity;
use Chill\CalendarBundle\Repository\CancelReasonRepository;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Table(name="chill_calendar.cancel_reason")
* @ORM\Entity(repositoryClass=CancelReasonRepository::class)
*/
class CancelReason
{
const CANCELEDBY_USER = 'CANCELEDBY_USER';
const CANCELEDBY_PERSON = 'CANCELEDBY_PERSON';
const CANCELEDBY_DONOTCOUNT = 'CANCELEDBY_DONOTCOUNT';
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\Column(type="boolean")
*/
private $active;
/**
* @ORM\Column(type="string", length=255)
*/
private $canceledBy;
/**
* @ORM\Column(type="json_array")
*/
private $name = [];
public function getId(): ?int
{
return $this->id;
}
public function getActive(): ?bool
{
return $this->active;
}
public function setActive(bool $active): self
{
$this->active = $active;
return $this;
}
public function getCanceledBy(): ?string
{
return $this->canceledBy;
}
public function setCanceledBy(string $canceledBy): self
{
$this->canceledBy = $canceledBy;
return $this;
}
public function getName(): ?array
{
return $this->name;
}
public function setName(array $name): self
{
$this->name = $name;
return $this;
}
}

View File

@@ -0,0 +1,60 @@
<?php
namespace Chill\CalendarBundle\Entity;
use Chill\CalendarBundle\Repository\InviteRepository;
use Chill\MainBundle\Entity\User;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Table(name="chill_calendar.invite")
* @ORM\Entity(repositoryClass=InviteRepository::class)
*/
class Invite
{
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\User")
*/
private User $user;
/**
* @ORM\Column(type="json_array")
*/
private array $status = [];
public function getId(): ?int
{
return $this->id;
}
public function getStatus(): ?array
{
return $this->status;
}
public function setStatus(array $status): self
{
$this->status = $status;
return $this;
}
public function getUser(): ?User
{
return $this->user;
}
public function setUser(?User $user): self
{
$this->user = $user;
return $this;
}
}

View File

@@ -0,0 +1,194 @@
<?php
namespace Chill\CalendarBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\DateType;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Doctrine\Persistence\ObjectManager;
use Symfony\Component\Form\CallbackTransformer;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Chill\MainBundle\Form\Type\CommentType;
use Chill\CalendarBundle\Entity\Calendar;
use Chill\CalendarBundle\Entity\CancelReason;
use Chill\CalendarBundle\Entity\Invite;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Chill\PersonBundle\Entity\Person;
use Chill\ThirdPartyBundle\Entity\ThirdParty;
use DateTimeImmutable;
class CalendarType extends AbstractType
{
protected TranslatableStringHelper $translatableStringHelper;
protected ObjectManager $om;
public function __construct(
TranslatableStringHelper $translatableStringHelper,
ObjectManager $om
)
{
$this->translatableStringHelper = $translatableStringHelper;
$this->om = $om;
}
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('mainUser', EntityType::class, [
'required' => true,
'class' => User::class,
'choice_label' => function (User $entity) {
return $entity->getUsernameCanonical();
},
// TODO 'empty_data' =>
])
->add('comment', CommentType::class, [
'required' => false
])
->add('cancelReason', EntityType::class, [
'required' => false,
'class' => CancelReason::class,
'choice_label' => function (CancelReason $entity) {
return $entity->getCanceledBy();
},
])
->add('sendSMS', ChoiceType::class, [
'required' => false,
'choices' => [
'Oui' => true,
'Non' => false
],
'expanded' => true
])
;
$builder->add('startDate', HiddenType::class);
$builder->get('startDate')
->addModelTransformer(new CallbackTransformer(
function (?DateTimeImmutable $dateTimeImmutable): string {
if (NULL !== $dateTimeImmutable) {
$res = date_format($dateTimeImmutable, 'Y-m-d H:i:s');
} else {
$res = '';
}
return $res;
},
function (?string $dateAsString): DateTimeImmutable {
dump($dateAsString);
return new DateTimeImmutable($dateAsString);
}
))
;
$builder->add('endDate', HiddenType::class);
$builder->get('endDate')
->addModelTransformer(new CallbackTransformer(
function (?DateTimeImmutable $dateTimeImmutable): string {
if (NULL !== $dateTimeImmutable) {
$res = date_format($dateTimeImmutable, 'Y-m-d H:i:s');
} else {
$res = '';
}
return $res;
},
function (?string $dateAsString): DateTimeImmutable {
return new DateTimeImmutable($dateAsString);
}
))
;
$builder->add('persons', HiddenType::class);
$builder->get('persons')
->addModelTransformer(new CallbackTransformer(
function (iterable $personsAsIterable): string {
$personIds = [];
foreach ($personsAsIterable as $value) {
$personIds[] = $value->getId();
}
return implode(',', $personIds);
},
function (?string $personsAsString): array {
return array_map(
fn(string $id): ?Person => $this->om->getRepository(Person::class)->findOneBy(['id' => (int) $id]),
explode(',', $personsAsString)
);
}
))
;
$builder->add('professionals', HiddenType::class);
$builder->get('professionals')
->addModelTransformer(new CallbackTransformer(
function (iterable $thirdpartyAsIterable): string {
$thirdpartyIds = [];
foreach ($thirdpartyAsIterable as $value) {
$thirdpartyIds[] = $value->getId();
}
return implode(',', $thirdpartyIds);
},
function (?string $thirdpartyAsString): array {
return array_map(
fn(string $id): ?ThirdParty => $this->om->getRepository(ThirdParty::class)->findOneBy(['id' => (int) $id]),
explode(',', $thirdpartyAsString)
);
}
))
;
// $builder->add('invites', HiddenType::class);
// $builder->get('invites')
// ->addModelTransformer(new CallbackTransformer(
// function (iterable $usersAsIterable): string {
// $userIds = [];
// foreach ($usersAsIterable as $value) {
// $userIds[] = $value->getId();
// }
// return implode(',', $userIds);
// },
// function (?string $usersAsString): array {
// return array_map(
// fn(string $id): ?Invite => $this->om->getRepository(Invite::class)->findOneBy(['id' => (int) $id]),
// explode(',', $usersAsString)
// );
// }
// ))
// ;
}/**
* {@inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Calendar::class
]);
$resolver
->setRequired(['accompanyingPeriod'])
->setAllowedTypes('accompanyingPeriod', [\Chill\PersonBundle\Entity\AccompanyingPeriod::class, 'null'])
;
}
/**
* {@inheritdoc}
*/
public function getBlockPrefix()
{
return 'chill_calendarbundle_calendar';
}
}

View File

@@ -0,0 +1,6 @@
Calendar bundle
===============
This bundle adds a calendar to chill.

View File

@@ -0,0 +1,50 @@
<?php
namespace Chill\CalendarBundle\Repository;
use Chill\CalendarBundle\Entity\CalendarRange;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @method CalendarRange|null find($id, $lockMode = null, $lockVersion = null)
* @method CalendarRange|null findOneBy(array $criteria, array $orderBy = null)
* @method CalendarRange[] findAll()
* @method CalendarRange[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*/
class CalendarRangeRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, CalendarRange::class);
}
// /**
// * @return CalendarRange[] Returns an array of CalendarRange objects
// */
/*
public function findByExampleField($value)
{
return $this->createQueryBuilder('c')
->andWhere('c.exampleField = :val')
->setParameter('val', $value)
->orderBy('c.id', 'ASC')
->setMaxResults(10)
->getQuery()
->getResult()
;
}
*/
/*
public function findOneBySomeField($value): ?CalendarRange
{
return $this->createQueryBuilder('c')
->andWhere('c.exampleField = :val')
->setParameter('val', $value)
->getQuery()
->getOneOrNullResult()
;
}
*/
}

View File

@@ -0,0 +1,50 @@
<?php
namespace Chill\CalendarBundle\Repository;
use Chill\CalendarBundle\Entity\Calendar;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @method Calendar|null find($id, $lockMode = null, $lockVersion = null)
* @method Calendar|null findOneBy(array $criteria, array $orderBy = null)
* @method Calendar[] findAll()
* @method Calendar[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*/
class CalendarRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, Calendar::class);
}
// /**
// * @return Calendar[] Returns an array of Calendar objects
// */
/*
public function findByExampleField($value)
{
return $this->createQueryBuilder('c')
->andWhere('c.exampleField = :val')
->setParameter('val', $value)
->orderBy('c.id', 'ASC')
->setMaxResults(10)
->getQuery()
->getResult()
;
}
*/
/*
public function findOneBySomeField($value): ?Calendar
{
return $this->createQueryBuilder('c')
->andWhere('c.exampleField = :val')
->setParameter('val', $value)
->getQuery()
->getOneOrNullResult()
;
}
*/
}

View File

@@ -0,0 +1,50 @@
<?php
namespace Chill\CalendarBundle\Repository;
use Chill\CalendarBundle\Entity\CancelReason;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @method CancelReason|null find($id, $lockMode = null, $lockVersion = null)
* @method CancelReason|null findOneBy(array $criteria, array $orderBy = null)
* @method CancelReason[] findAll()
* @method CancelReason[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*/
class CancelReasonRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, CancelReason::class);
}
// /**
// * @return CancelReason[] Returns an array of CancelReason objects
// */
/*
public function findByExampleField($value)
{
return $this->createQueryBuilder('c')
->andWhere('c.exampleField = :val')
->setParameter('val', $value)
->orderBy('c.id', 'ASC')
->setMaxResults(10)
->getQuery()
->getResult()
;
}
*/
/*
public function findOneBySomeField($value): ?CancelReason
{
return $this->createQueryBuilder('c')
->andWhere('c.exampleField = :val')
->setParameter('val', $value)
->getQuery()
->getOneOrNullResult()
;
}
*/
}

View File

@@ -0,0 +1,50 @@
<?php
namespace Chill\CalendarBundle\Repository;
use Chill\CalendarBundle\Entity\Invite;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @method Invite|null find($id, $lockMode = null, $lockVersion = null)
* @method Invite|null findOneBy(array $criteria, array $orderBy = null)
* @method Invite[] findAll()
* @method Invite[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*/
class InviteRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, Invite::class);
}
// /**
// * @return Invite[] Returns an array of Invite objects
// */
/*
public function findByExampleField($value)
{
return $this->createQueryBuilder('i')
->andWhere('i.exampleField = :val')
->setParameter('val', $value)
->orderBy('i.id', 'ASC')
->setMaxResults(10)
->getQuery()
->getResult()
;
}
*/
/*
public function findOneBySomeField($value): ?Invite
{
return $this->createQueryBuilder('i')
->andWhere('i.exampleField = :val')
->setParameter('val', $value)
->getQuery()
->getOneOrNullResult()
;
}
*/
}

View File

@@ -0,0 +1,3 @@
chill_calendar_controllers:
resource: '../../Controller/'
type: annotation

View File

@@ -0,0 +1,8 @@
---
services:
Chill\CalendarBundle\Repository\:
autowire: true
resource: '../../Repository/'
tags:
- { name: 'doctrine.repository_service' }

View File

@@ -0,0 +1,5 @@
services:
Chill\CalendarBundle\Controller\:
autowire: true
resource: '../../../Controller'
tags: ['controller.service_arguments']

View File

@@ -0,0 +1,8 @@
---
services:
Chill\CalendarBundle\DataFixtures\ORM\LoadCancelReason:
tags:
- { 'name': doctrine.fixture.orm }
Chill\CalendarBundle\DataFixtures\ORM\LoadInvite:
tags:
- { 'name': doctrine.fixture.orm }

View File

@@ -0,0 +1,10 @@
---
services:
chill.calendar.form.type.calendar:
class: Chill\CalendarBundle\Form\CalendarType
arguments:
- "@chill.main.helper.translatable_string"
- "@doctrine.orm.entity_manager"
tags:
- { name: form.type, alias: chill_calendarbundle_calendar }

View File

@@ -0,0 +1,17 @@
<template>
<concerned-groups></concerned-groups>
<calendar-range></calendar-range>
</template>
<script>
import ConcernedGroups from 'ChillActivityAssets/vuejs/Activity/components/ConcernedGroups.vue';
import CalendarRange from '../_components/CalendarRange/CalendarRange.vue';
export default {
name: "App",
components: {
ConcernedGroups,
CalendarRange
}
}
</script>

View File

@@ -0,0 +1,22 @@
import { personMessages } from 'ChillPersonAssets/vuejs/_js/i18n'
import { calendarRangeMessages } from '../_components/CalendarRange/js/i18n'
const appMessages = {
fr: {
activity: {
add_persons: "Ajouter des personnes concernées",
bloc_persons: "Usagers",
bloc_persons_associated: "Usagers du parcours",
bloc_persons_not_associated: "Tiers non-pro.",
bloc_thirdparty: "Tiers professionnels",
bloc_users: "T(M)S",
}
}
}
Object.assign(appMessages.fr, personMessages.fr);
Object.assign(appMessages.fr, calendarRangeMessages.fr);
export {
appMessages
};

View File

@@ -0,0 +1,16 @@
import { createApp } from 'vue';
import { _createI18n } from 'ChillMainAssets/vuejs/_js/i18n'
import { appMessages } from './i18n'
import store from './store'
import App from './App.vue';
const i18n = _createI18n(appMessages);
const app = createApp({
template: `<app></app>`,
})
.use(store)
.use(i18n)
.component('app', App)
.mount('#calendar');

View File

@@ -0,0 +1,121 @@
import 'es6-promise/auto';
import { createStore } from 'vuex';
const debug = process.env.NODE_ENV !== 'production';
const addIdToValue = (string, id) => {
let array = string ? string.split(',') : [];
array.push(id.toString());
let str = array.join();
return str;
};
const removeIdFromValue = (string, id) => {
let array = string.split(',');
array = array.filter(el => el !== id.toString());
let str = array.join();
return str;
};
/*
* Assign missing keys for the ConcernedGroups component
*/
const mapEntity = (entity) => {
Object.assign(entity, {thirdParties: entity.professionals, users: entity.invites});
return entity;
};
const store = createStore({
strict: debug,
state: {
activity: mapEntity(window.entity),
events: []
},
mutations: {
// ConcernedGroups
addPersonsInvolved(state, payload) {
//console.log('### mutation addPersonsInvolved', payload.result.type);
switch (payload.result.type) {
case 'person':
state.activity.persons.push(payload.result);
break;
case 'thirdparty':
state.activity.thirdParties.push(payload.result);
break;
case 'user':
state.activity.users.push(payload.result);
break;
};
},
removePersonInvolved(state, payload) {
//console.log('### mutation removePersonInvolved', payload.type);
switch (payload.type) {
case 'person':
state.activity.persons = state.activity.persons.filter(person => person !== payload);
break;
case 'thirdparty':
state.activity.thirdParties = state.activity.thirdParties.filter(thirdparty => thirdparty !== payload);
break;
case 'user':
state.activity.users = state.activity.users.filter(user => user !== payload);
break;
};
},
// Calendar
setEvents(state, payload) {
console.log(payload)
state.events.push( {start: payload.start, end: payload.end})
}
},
actions: {
addPersonsInvolved({ commit }, payload) {
console.log('### action addPersonsInvolved', payload.result.type);
switch (payload.result.type) {
case 'person':
let aPersons = document.getElementById("chill_calendarbundle_calendar_persons");
aPersons.value = addIdToValue(aPersons.value, payload.result.id);
break;
case 'thirdparty':
let aThirdParties = document.getElementById("chill_calendarbundle_calendar_professionals");
aThirdParties.value = addIdToValue(aThirdParties.value, payload.result.id);
break;
case 'user':
let aUsers = document.getElementById("chill_calendarbundle_calendar_invites");
aUsers.value = addIdToValue(aUsers.value, payload.result.id);
break;
};
commit('addPersonsInvolved', payload);
},
removePersonInvolved({ commit }, payload) {
//console.log('### action removePersonInvolved', payload);
switch (payload.type) {
case 'person':
let aPersons = document.getElementById("chill_calendarbundle_calendar_persons");
aPersons.value = removeIdFromValue(aPersons.value, payload.id);
break;
case 'thirdparty':
let aThirdParties = document.getElementById("chill_calendarbundle_calendar_professionals");
aThirdParties.value = removeIdFromValue(aThirdParties.value, payload.id);
break;
case 'user':
let aUsers = document.getElementById("chill_calendarbundle_calendar_invites");
aUsers.value = removeIdFromValue(aUsers.value, payload.id);
break;
};
commit('removePersonInvolved', payload);
},
// Calendar
setDateRange({ commit }, payload) {
console.log('### action setDateRange', payload);
let startDateInput = document.getElementById("chill_calendarbundle_calendar_startDate");
startDateInput.value = payload.startStr;
let endDateInput = document.getElementById("chill_calendarbundle_calendar_endDate");
endDateInput.value = payload.endStr;
commit('setEvents', payload);
}
}
});
export default store;

View File

@@ -0,0 +1,37 @@
<template>
<h2 class="chill-red">{{ $t('choose_your_date') }}</h2>
<FullCalendar :options="calendarOptions" />
</template>
<script>
import '@fullcalendar/core/vdom' // solves problem with Vite
import FullCalendar from '@fullcalendar/vue3'
import dayGridPlugin from '@fullcalendar/daygrid'
import interactionPlugin from '@fullcalendar/interaction'
import timeGridPlugin from '@fullcalendar/timegrid'
export default {
components: {
FullCalendar
},
data() {
return {
calendarOptions: {
plugins: [ dayGridPlugin, interactionPlugin, timeGridPlugin ],
initialView: 'dayGridMonth',
selectable: true,
select: this.onDateSelect,
headerToolbar: {
left: 'prev,next today',
center: 'title',
right: 'dayGridMonth,timeGridWeek,timeGridDay'
},
}
}
},
methods: {
onDateSelect(payload) {
this.$store.dispatch('setDateRange', payload);
}
}
}
</script>

View File

@@ -0,0 +1,10 @@
const calendarRangeMessages = {
fr: {
choose_your_date: 'Sélectionnez vos dates',
}
};
export {
calendarRangeMessages
};

View File

@@ -0,0 +1,16 @@
{% extends "@ChillPerson/AccompanyingCourse/layout.html.twig" %}
{% set activeRouteKey = 'chill_calendar_calendar' %}
{% block title 'Remove calendar item'|trans %}
{% block content %}
{{ include('@ChillMain/Util/confirmation_template.html.twig',
{
'title' : 'Remove calendar item'|trans,
'confirm_question' : 'Are you sure you want to remove the calendar item?'|trans,
'cancel_route' : 'chill_calendar_calendar',
'cancel_parameters' : { 'accompanying_course_id' : accompanyingCourse.id, 'id' : calendar.id },
'form' : delete_form
} ) }}
{% endblock %}

View File

@@ -0,0 +1,17 @@
{% extends "@ChillPerson/Person/layout.html.twig" %}
{% set activeRouteKey = 'chill_activity_activity_list' %}
{% set person = activity.person %}
{% block title 'Remove activity'|trans %}
{% block personcontent %}
{{ include('@ChillMain/Util/confirmation_template.html.twig',
{
'title' : 'Remove activity'|trans,
'confirm_question' : 'Are you sure you want to remove the activity about "%name%" ?'|trans({ '%name%' : person.firstname ~ ' ' ~ person.lastname } ),
'cancel_route' : 'chill_activity_activity_list',
'cancel_parameters' : { 'person_id' : activity.person.id, 'id' : activity.id },
'form' : delete_form
} ) }}
{% endblock %}

View File

@@ -0,0 +1,76 @@
<h1>{{ "Update calendar"|trans }}</h1>
{{ form_start(form) }}
{{ form_errors(form) }}
{%- if form.mainUser is defined -%}
{{ form_row(form.mainUser) }}
{% endif %}
<h2 class="chill-red">{{ 'Concerned groups'|trans }}</h2>
{%- if form.persons is defined -%}
{{ form_widget(form.persons) }}
{% endif %}
{%- if form.professionals is defined -%}
{{ form_widget(form.professionals) }}
{% endif %}
{%- if form.nonProfessionals is defined -%}
{{ form_widget(form.nonProfessionals) }}
{% endif %}
{%- if form.users is defined -%}
{{ form_widget(form.users) }}
{% endif %}
<div id="add-persons"></div>
<h2 class="chill-red">{{ 'Calendar data'|trans }}</h2>
{%- if form.startDate is defined -%}
{{ form_row(form.startDate) }}
{% endif %}
{%- if form.endDate is defined -%}
{{ form_row(form.endDate) }}
{% endif %}
.. location
{%- if form.cancelReason is defined -%}
{{ form_row(form.cancelReason) }}
{% endif %}
{%- if form.comment is defined -%}
{{ form_row(form.comment) }}
{% endif %}
{%- if form.sendSMS is defined -%}
{{ form_row(form.sendSMS) }}
{% endif %}
..calendarRange
<ul class="record_actions sticky-form-buttons">
<li class="cancel">
<a
class="btn btn-cancel"
{%- if context == 'person' -%}
href="{{ chill_return_path_or('chill_calendar_calendar', { 'person_id': person.id } )}}"
{%- else -%}
href="{{ chill_return_path_or('chill_calendar_calendar', { 'accompanying_period_id': accompanyingCourse.id } )}}"
{%- endif -%}
>
{{ 'Cancel'|trans|chill_return_path_label }}
</a>
</li>
<li>
<button class="btn btn-create" type="submit">
{{ 'Update'|trans }}
</button>
</li>
</ul>
{{ form_end(form) }}

View File

@@ -0,0 +1,35 @@
{% extends "@ChillPerson/AccompanyingCourse/layout.html.twig" %}
{% set activeRouteKey = 'chill_calendar_calendar_list' %}
{% block title 'Update calendar'|trans %}
{% block content %}
<div class="calendar-edit">
<div class="row justify-content-center">
<div class="col-md-10 col-xxl">
<div id="calendar"></div> {# <=== vue component #}
{% include 'ChillCalendarBundle:Calendar:edit.html.twig' with {'context': 'accompanyingCourse'} %}
</div>
</div>
</div>
{% endblock %}
{% block js %}
{{ parent() }}
<script type="text/javascript">
window.addEventListener('DOMContentLoaded', function (e) {
chill.displayAlertWhenLeavingModifiedForm('form[name="{{ form.vars.form.vars.name }}"]',
'{{ "You are going to leave a page with unsubmitted data. Are you sure you want to leave ?"|trans }}');
});
window.entity = {{ entity_json|json_encode|raw }};
</script>
{{ encore_entry_script_tags('vue_calendar') }}
{% endblock %}
{% block css %}
{{ parent() }}
{{ encore_entry_link_tags('vue_calendar') }}
{% endblock %}

View File

@@ -0,0 +1,136 @@
{% set user_id = null %}
{% if user %}
{% set user_id = user.id %}
{% endif %}
{% set accompanying_course_id = null %}
{% if accompanyingCourse %}
{% set accompanying_course_id = accompanyingCourse.id %}
{% endif %}
<h2>{{ 'Calendar list' |trans }}</h2>
{% if calendarItems|length == 0 %}
<p class="chill-no-data-statement">
{{ "There is no calendar items."|trans }}
<a href="{{ path('chill_calendar_calendar_new', {'user_id': user_id, 'accompanying_period_id': accompanying_course_id}) }}" class="btn btn-create button-small"></a>
</p>
{% else %}
<div class="flex-table list-records context-{{ context }}">
{% for calendar in calendarItems %}
<div class="item-bloc">
<div class="item-row main">
<div class="item-col">
{% if calendar.startDate %}
<h3>{{ calendar.startDate|format_date('long') }} </h3>
{% endif %}
{% if calendar.endDate %}
<h3>{{ calendar.endDate|format_date('long') }}</h3>
{% endif %}
<h3>{{ calendar.endDate.diff(calendar.startDate)|date("%Y%m%d%h") }}</h3>
{% if context == 'user' and calendar.accompanyingPeriod is not empty %}
<div class="accompanyingPeriodLink" style="margin-top: 1rem">
<a
href="{{ chill_path_add_return_path(
"chill_user_accompanying_course_index",
{ 'accompanying_period_id': calendar.accompanyingPeriod.id }
) }}"
>
<i class="fa fa-random"></i>
{{ calendar.accompanyingPeriod.id }}
</a>
</div>
{% endif %}
</div>
<div class="item-col">
<ul class="list-content">
{% if calendar.user %}
<li>
<b>{{ 'by'|trans }}{{ calendar.user.usernameCanonical }}</b>
</li>
{% endif %}
{% if calendar.mainUser is not empty %}
<li>
<b>{{ 'main user concerned'|trans }}{{ calendar.mainUser.usernameCanonical }}</b>
</li>
{% endif %}
<li>
{%- if calendar.comment.isEmpty -%}
<span class="chill-no-data-statement">{{ 'No comments'|trans }}</span>
{%- else -%}
{{ calendar.comment|chill_entity_render_box }}
{%- endif -%}
</li>
</ul>
<ul class="record_actions">
<li>
<a href="{{ path('chill_calendar_calendar_show', { 'id': calendar.id, 'user_id': user_id, 'accompanying_period_id': accompanying_course_id }) }}" class="btn btn-show "></a>
</li>
{# TOOD
{% if is_granted('CHILL_ACTIVITY_UPDATE', calendar) %}
#}
<li>
<a href="{{ path('chill_calendar_calendar_edit', { 'id': calendar.id, 'user_id': user_id, 'accompanying_period_id': accompanying_course_id }) }}" class="btn btn-update "></a>
</li>
{# TOOD
{% endif %}
{% if is_granted('CHILL_ACTIVITY_DELETE', calendar) %}
#}
<li>
<a href="{{ path('chill_calendar_calendar_delete', { 'id': calendar.id, 'user_id' : user_id, 'accompanying_period_id': accompanying_course_id } ) }}" class="btn btn-delete "></a>
</li>
{#
{% endif %}
#}
</ul>
</div>
</div>
{%
if calendar.comment.comment is not empty
or calendar.users|length > 0
or calendar.thirdParties|length > 0
or calendar.users|length > 0
%}
<div class="item-row details">
<div class="item-col">
{% include 'ChillActivityBundle:Activity:concernedGroups.html.twig' with {'context': context, 'with_display': 'row', 'entity': calendar } %}
</div>
{% if calendar.comment.comment is not empty %}
<div class="item-col comment">
{{ calendar.comment|chill_entity_render_box( { 'limit_lines': 3, 'metadata': false } ) }}
</div>
{% endif %}
</div>
{% endif %}
</div>
{% endfor %}
</div>
{% endif %}
{% if context != 'user' %}
{# TODO set this condition in configuration #}
<ul class="record_actions">
<li>
<a href="{{ path('chill_calendar_calendar_new', {'user_id': user_id, 'accompanying_period_id': accompanying_course_id}) }}" class="btn btn-create">
{{ 'Add a new calendar' | trans }}
</a>
</li>
</ul>
{% endif %}

View File

@@ -0,0 +1,9 @@
{% extends "@ChillPerson/AccompanyingCourse/layout.html.twig" %}
{% set activeRouteKey = 'chill_calendar_calendar_list' %}
{% block title %}{{ 'Calendar list' |trans }}{% endblock title %}
{% block content %}
{% include 'ChillCalendarBundle:Calendar:list.html.twig' with {'context': 'accompanyingCourse'} %}
{% endblock %}

View File

@@ -0,0 +1,75 @@
<h1>{{ "Calendar item creation"|trans ~ ' :' }}</h1>
{{ form_start(form) }}
{{ form_errors(form) }}
{%- if form.mainUser is defined -%}
{{ form_row(form.mainUser) }}
{% endif %}
<h2 class="chill-red">{{ 'Concerned groups'|trans }}</h2>
{%- if form.persons is defined -%}
{{ form_widget(form.persons) }}
{% endif %}
{%- if form.professionals is defined -%}
{{ form_widget(form.professionals) }}
{% endif %}
{%- if form.nonProfessionals is defined -%}
{{ form_widget(form.nonProfessionals) }}
{% endif %}
{%- if form.users is defined -%}
{{ form_widget(form.users) }}
{% endif %}
<div id="add-persons"></div>
<h2 class="chill-red">{{ 'Calendar data'|trans }}</h2>
{%- if form.startDate is defined -%}
{{ form_row(form.startDate) }}
{% endif %}
{%- if form.endDate is defined -%}
{{ form_row(form.endDate) }}
{% endif %}
.. location
{%- if form.cancelReason is defined -%}
{{ form_row(form.cancelReason) }}
{% endif %}
{%- if form.comment is defined -%}
{{ form_row(form.comment) }}
{% endif %}
{%- if form.sendSMS is defined -%}
{{ form_row(form.sendSMS) }}
{% endif %}
..calendarRange
<ul class="record_actions sticky-form-buttons">
<li class="cancel">
<a
class="btn btn-cancel"
{%- if context == 'person' -%}
href="{{ chill_return_path_or('chill_activity_activity_list', { 'person_id': person.id } )}}"
{%- else -%}
href="{{ chill_return_path_or('chill_activity_activity_list', { 'accompanying_period_id': accompanyingCourse.id } )}}"
{%- endif -%}
>
{{ 'Cancel'|trans|chill_return_path_label }}
</a>
</li>
<li>
<button class="btn btn-create" type="submit">
{{ 'Create'|trans }}
</button>
</li>
</ul>
{{ form_end(form) }}

View File

@@ -0,0 +1,37 @@
{% extends "@ChillPerson/AccompanyingCourse/layout.html.twig" %}
{% set activeRouteKey = 'chill_calendar_calendar_new' %}
{% block title 'Calendar item creation' |trans %}
{% block content %}
<div class="calendar-new">
<div class="row justify-content-center">
<div class="col-md-10 col-xxl">
<div id="calendar"></div> {# <=== vue component #}
{% include 'ChillCalendarBundle:Calendar:new.html.twig' with {'context': 'accompanyingCourse'} %}
</div>
</div>
</div>
{% endblock %}
{% block js %}
{{ parent() }}
<script type="text/javascript">
window.addEventListener('DOMContentLoaded', function (e) {
chill.displayAlertWhenLeavingUnsubmittedForm('form[name="{{ form.vars.form.vars.name }}"]',
'{{ "You are going to leave a page with unsubmitted data. Are you sure you want to leave ?"|trans }}');
});
window.entity = {{ entity_json|json_encode|raw }};
</script>
{{ encore_entry_script_tags('vue_calendar') }}
{% endblock %}
{% block css %}
{{ parent() }}
<link rel="stylesheet" href="{{ asset('build/vue_calendar.css') }}"/>
{% endblock %}

View File

@@ -0,0 +1,79 @@
<h1>{{ "Calendar"|trans }}</h1>
<dl class="chill_view_data">
<dt class="inline">{{ 'main user concerned'|trans }}</dt>
<dd>{{ entity.mainUser }}</dd>
</dl>
<h2 class="chill-red">{{ 'Concerned groups'|trans }}</h2>
{% include 'ChillActivityBundle:Activity:concernedGroups.html.twig' with {'context': context, 'with_display': 'bloc' } %}
<h2 class="chill-red">{{ 'Calendar data'|trans }}</h2>
<dt class="inline">{{ 'start date'|trans }}</dt>
<dd>{{ entity.startDate|format_datetime('long') }}</dd>
<dt class="inline">{{ 'end date'|trans }}</dt>
<dd>{{ entity.endDate|format_datetime('long') }}</dd>
<dt class="inline">{{ 'cancel reason'|trans }}</dt>
<dd>
{% if entity.cancelReason is not null %}
{{ entity.cancelReason.canceledBy|localize_translatable_string }}
{% else %}
<span class="chill-no-data-statement">{{ 'Unknown'|trans }}</span>
{% endif %}
</dd>
<dt class="inline">{{ 'status'|trans }}</dt>
<dd>{{ entity.status }}</dd>
{% if not entity.comment.isEmpty %}
<dt class="inline">{{ 'calendar comment'|trans }}</dt>
<dd>{{ entity.comment|chill_entity_render_box }}</dd>
{% endif %}
<dt class="inline">{{ 'sendSMS'|trans }}</dt>
<dd>
{% if entity.sendSMS is not null %}
{% if entity.sendSMS %}{{ 'Yes'|trans }}{% else %}{{ 'No'|trans }}{% endif %}
{% else %}
<span class="chill-no-data-statement">{{ 'Unknown'|trans }}</span>
{% endif %}
</dd>
</dl>
{% set accompanying_course_id = null %}
{% if accompanyingCourse %}
{% set accompanying_course_id = accompanyingCourse.id %}
{% endif %}
<ul class="record_actions sticky-form-buttons">
<li class="cancel">
<a class="btn btn-cancel" href="{{ path('chill_calendar_calendar', { 'accompanying_period_id': accompanying_course_id } ) }}">
{{ 'Back to the list'|trans }}
</a>
</li>
<li>
<a class="btn btn-update" href="{{ path('chill_calendar_calendar_edit', { 'id': entity.id, 'accompanying_period_id': accompanying_course_id }) }}">
{{ 'Edit'|trans }}
</a>
</li>
{# TODO
{% if is_granted('CHILL_ACTIVITY_DELETE', entity) %}
#}
<li>
<a href="{{ path('chill_calendar_calendar_delete', { 'id': entity.id, 'accompanying_period_id': accompanying_course_id } ) }}" class="btn btn-delete">
{{ 'Delete'|trans }}
</a>
</li>
{#
{% endif %}
#}
</ul>

View File

@@ -0,0 +1,15 @@
{% extends "@ChillPerson/AccompanyingCourse/layout.html.twig" %}
{% set activeRouteKey = 'chill_calendar_calendar_list' %}
{% block title 'Calendar'|trans %}
{% block content -%}
<div class="calendar-show">
<div class="row justify-content-center">
<div class="col-md-10 col-xxl">
{% include 'ChillCalendarBundle:Calendar:show.html.twig' with {'context': 'accompanyingCourse'} %}
</div>
</div>
</div>
{% endblock content %}

View File

@@ -0,0 +1,10 @@
// this file loads all assets from the Chill calendar bundle
module.exports = function(encore, entries) {
//entries.push(__dirname + '/Resources/public/index.js');
encore.addAliases({
ChillCalendarAssets: __dirname + '/Resources/public'
});
encore.addEntry('vue_calendar', __dirname + '/Resources/public/vuejs/Calendar/index.js');
};

View File

@@ -0,0 +1,30 @@
{
"name": "chill-project/calendar",
"description": "This bundle extends chill for managing a calendar",
"type": "symfony-bundle",
"license": "AGPL-3.0-or-later",
"keywords" : ["chill", "social work"],
"homepage" : "hhttps://gitlab.com/Chill-Projet/chill-bundles/",
"autoload": {
"psr-4": { "Chill\\CalendarBundle\\": "" }
},
"autoload-dev": {
"classmap": [ "Resources/test/Fixtures/App/app/AppKernel.php" ]
},
"authors": [
{
"name": "Champs-Libres",
"email": "info@champs-libres.coop"
}
],
"require": {
},
"require-dev": {
},
"extra": {
"app-migrations-dir": "Resources/test/Fixtures/App/app/DoctrineMigrations",
"symfony-app-dir": "Test/Fixtures/App/app/"
},
"minimum-stability": "dev",
"prefer-stable": true
}

Some files were not shown because too many files have changed in this diff Show More