Skip to content

Commit 80cbf46

Browse files
authored
Merge pull request #106 from crf-devs/display-planning-without-search-#97
Display planning without search #97
2 parents 9d719dc + f66165e commit 80cbf46

File tree

7 files changed

+82
-85
lines changed

7 files changed

+82
-85
lines changed

assets/js/planning.js

Lines changed: 27 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,13 @@ function selectTableBox ($tableBox) {
1919
colorTableBox($tableBox);
2020
}
2121

22-
function initDatesRange($picker, $from, $to, withTime)
23-
{
24-
function displayDate() {
25-
$picker.val($picker.data('daterangepicker').startDate.format('DD/MM/YYYY HH:mm') + ' à ' + $picker.data('daterangepicker').endDate.format('DD/MM/YYYY HH:mm'));
22+
function initDatesRange ($picker, $from, $to, withTime) {
23+
function displayDate () {
24+
if(withTime) {
25+
$picker.val($picker.data('daterangepicker').startDate.format('DD/MM/YYYY HH:mm') + ' à ' + $picker.data('daterangepicker').endDate.format('DD/MM/YYYY HH:mm'));
26+
} else {
27+
$picker.val($picker.data('daterangepicker').startDate.format('DD/MM/YYYY') + ' au ' + $picker.data('daterangepicker').endDate.format('DD/MM/YYYY'));
28+
}
2629
}
2730

2831
$picker.daterangepicker({
@@ -35,19 +38,19 @@ function initDatesRange($picker, $from, $to, withTime)
3538
cancelClass: 'btn-sm btn-default',
3639
locale: {
3740
cancelLabel: 'Supprimer',
38-
format: 'DD/MM/YYYY hh:mm',
41+
format: 'DD/MM/YYYY HH:mm',
3942
separator: ' - ',
4043
applyLabel: 'Valider',
4144
fromLabel: 'De',
4245
toLabel: 'à',
4346
customRangeLabel: 'Custom',
44-
daysOfWeek: [ 'Dim', 'Lun', 'Mar', 'Mer', 'Jeu', 'Ven', 'Sam' ],
45-
monthNames: [ 'Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Août', 'Septembre', 'Octobre', 'Novembre', 'Décembre' ],
47+
daysOfWeek: ['Dim', 'Lun', 'Mar', 'Mer', 'Jeu', 'Ven', 'Sam'],
48+
monthNames: ['Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Août', 'Septembre', 'Octobre', 'Novembre', 'Décembre'],
4649
firstDay: 1
4750
}
4851
});
4952

50-
if($from.val() !== '' && $to.val() !== '') {
53+
if ($from.val() !== '' && $to.val() !== '') {
5154
$picker.data('daterangepicker').setStartDate(new Date($from.val()));
5255
$picker.data('daterangepicker').setEndDate(new Date($to.val()));
5356
displayDate();
@@ -66,9 +69,9 @@ function initDatesRange($picker, $from, $to, withTime)
6669
});
6770
}
6871

69-
function triggerUpdate(url, newStatus, $planning) {
72+
function triggerUpdate (url, newStatus, $planning) {
7073
var payload = generatePayload($planning);
71-
if(!Object.keys(payload.assets).length && !Object.keys(payload.users).length) {
74+
if (!Object.keys(payload.assets).length && !Object.keys(payload.users).length) {
7275
return;
7376
}
7477

@@ -83,32 +86,32 @@ function triggerUpdate(url, newStatus, $planning) {
8386
updatePlanningFromPayload($planning, newStatus, payload);
8487
$('.planning-actions-container .btn').prop('disabled', false);
8588
},
86-
error: function(data) {
89+
error: function (data) {
8790
window.alert('Une erreur est survenue, merci de vérifier vos paramètres.');
8891
$('.planning-actions-container .btn').prop('disabled', false);
8992
}
9093
});
9194
}
9295

93-
function updatePlanningFromPayload($planning, newStatus, payload) {
96+
function updatePlanningFromPayload ($planning, newStatus, payload) {
9497
['users', 'assets'].forEach(ownerType => {
9598
var currentObjects = payload[ownerType] || {};
9699
Object.keys(currentObjects).forEach(objectId => {
97-
payload[ownerType][objectId].forEach(schedule => {
98-
var [from,to] = schedule;
99-
$td = $planning.find('tr[data-type="'+ownerType+'"][data-id="'+objectId+'"] td[data-from="'+from+'"][data-to="'+to+'"]');
100-
$td
101-
.removeClass($td.data('status'))
102-
.addClass(newStatus)
103-
.data('status', newStatus);
104-
});
100+
payload[ownerType][objectId].forEach(schedule => {
101+
var [from, to] = schedule;
102+
$td = $planning.find('tr[data-type="' + ownerType + '"][data-id="' + objectId + '"] td[data-from="' + from + '"][data-to="' + to + '"]');
103+
$td
104+
.removeClass($td.data('status'))
105+
.addClass(newStatus)
106+
.data('status', newStatus);
107+
});
105108
});
106109
});
107110

108111
$planning.find('.checked').removeClass('checked').find('input:checkbox').prop('checked', false);
109112
}
110113

111-
function generatePayload($planning) {
114+
function generatePayload ($planning) {
112115
var payload = {
113116
users: {},
114117
assets: {}
@@ -120,7 +123,7 @@ function generatePayload($planning) {
120123
var type = $owner.data('type');
121124
var $parent = $(this).closest('td');
122125

123-
if(!payload[type][ownerId]) {
126+
if (!payload[type][ownerId]) {
124127
payload[type][ownerId] = [];
125128
}
126129
payload[type][ownerId].push([$parent.data('from'), $parent.data('to')]);
@@ -146,10 +149,10 @@ $(document).ready(function () {
146149
triggerUpdate($(this).data('href'), $(this).data('status'), $planning);
147150
});
148151

149-
$planning.find('input[type=checkbox]:checked').closest('.slot-box').addClass('checked');
150-
151152
// Datepickers
152153
initDatesRange($('#fromToRange'), $('#from'), $('#to'));
153154
initDatesRange($('#availableRange'), $('#availableFrom'), $('#availableTo'), true);
155+
156+
$planning.find('input[type=checkbox]:checked').closest('.slot-box').addClass('checked');
154157
});
155158

src/Controller/Organization/PlanningController.php

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -38,29 +38,30 @@ public function __construct(UserRepository $userRepository, CommissionableAssetR
3838

3939
public function __invoke(Request $request): Response
4040
{
41-
$data = [
42-
'from' => new \DateTimeImmutable('monday'),
43-
'to' => (new \DateTimeImmutable('monday'))->add(new \DateInterval('P1W')),
44-
'volunteer' => true,
45-
'volunteerEquipped' => true,
46-
'volunteerHideVulnerable' => true,
47-
'asset' => true,
48-
];
49-
50-
$form = $this->container->get('form.factory')->createNamed('', PlanningSearchType::class, $data, ['method' => 'GET', 'attr' => ['autocomplete' => 'off']]);
51-
$form->handleRequest($request);
41+
if (!$request->query->has('from')) {
42+
$request->query->set('from', (new \DateTimeImmutable('monday this week'))->format('Y-m-d\T00:00:00'));
43+
}
5244

53-
$from = $form->get('from')->getData();
54-
$to = $form->get('to')->getData();
45+
if (!$request->query->has('to')) {
46+
$from = new \DateTimeImmutable($request->query->get('from', 'monday this week'));
47+
$request->query->set('to', $from->add(new \DateInterval('P1W'))->format('Y-m-d\T00:00:00'));
48+
}
5549

56-
$periodCalculator = DatePeriodCalculator::createRoundedToDay($from, new \DateInterval('PT2H'), $to);
50+
$form = $this->container->get('form.factory')->createNamed('', PlanningSearchType::class, [], ['method' => 'GET', 'attr' => ['autocomplete' => 'off']]);
51+
$form->handleRequest($request);
5752

58-
if ($form->isSubmitted() && $form->isValid()) {
59-
[$users, $assets] = $this->searchEntities($form->getData());
60-
$usersAvailabilities = $this->prepareAvailabilities($this->userAvailabilityRepository, $users, $periodCalculator);
61-
$assetsAvailabilities = $this->prepareAvailabilities($this->assetAvailabilityRepository, $assets, $periodCalculator);
53+
$data = $form->getData();
54+
if (!isset($data['from'], $data['to'])) {
55+
// This may happen if the passed date is invalid. TODO check it before, the format must be 2020-03-30T00:00:00
56+
throw $this->createNotFoundException();
6257
}
6358

59+
$periodCalculator = DatePeriodCalculator::createRoundedToDay($data['from'], new \DateInterval('PT2H'), $data['to']);
60+
61+
[$users, $assets] = $this->searchEntities($data);
62+
$usersAvailabilities = $this->prepareAvailabilities($this->userAvailabilityRepository, $users, $periodCalculator);
63+
$assetsAvailabilities = $this->prepareAvailabilities($this->assetAvailabilityRepository, $assets, $periodCalculator);
64+
6465
return $this->render('organization/planning.html.twig', [
6566
'form' => $form->createView(),
6667
'periodCalculator' => $periodCalculator,
@@ -71,8 +72,8 @@ public function __invoke(Request $request): Response
7172

7273
private function searchEntities(array $formData): array
7374
{
74-
$users = $this->userRepository->findByFilters($formData);
75-
$assets = $this->assetRepository->findByFilters($formData);
75+
$users = $formData['hideUsers'] ?? false ? [] : $this->userRepository->findByFilters($formData);
76+
$assets = $formData['hideAssets'] ?? false ? [] : $this->assetRepository->findByFilters($formData);
7677

7778
return [$users, $assets];
7879
}

src/Form/Type/PlanningSearchType.php

Lines changed: 15 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,8 @@
1212
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
1313
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
1414
use Symfony\Component\Form\Extension\Core\Type\DateTimeType;
15-
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
1615
use Symfony\Component\Form\FormBuilderInterface;
17-
use Symfony\Component\Form\FormEvent;
18-
use Symfony\Component\Form\FormEvents;
16+
use Symfony\Component\OptionsResolver\OptionsResolver;
1917

2018
class PlanningSearchType extends AbstractType
2119
{
@@ -64,27 +62,27 @@ public function buildForm(FormBuilderInterface $builder, array $options): void
6462
'required' => false,
6563
'attr' => ['class' => 'selectpicker'],
6664
])
67-
->add('volunteer', CheckboxType::class, [
68-
'label' => 'Bénévoles',
65+
->add('hideUsers', CheckboxType::class, [
66+
'label' => 'Cacher les bénévoles',
6967
'required' => false,
7068
])
71-
->add('volunteerSkills', ChoiceType::class, [
69+
->add('userSkills', ChoiceType::class, [
7270
'label' => 'Compétences',
7371
'choices' => array_flip($this->availableSkillSets),
7472
'multiple' => true,
7573
'required' => false,
7674
'attr' => ['class' => 'selectpicker'],
7775
])
78-
->add('volunteerEquipped', CheckboxType::class, [
76+
->add('onlyFullyEquiped', CheckboxType::class, [
7977
'label' => 'Avec uniforme seulement',
8078
'required' => false,
8179
])
82-
->add('volunteerHideVulnerable', CheckboxType::class, [
83-
'label' => 'Cacher les personnes signalées comme vulnérables',
80+
->add('displayVulnerables', CheckboxType::class, [
81+
'label' => 'Afficher aussi les personnes signalées comme vulnérables',
8482
'required' => false,
8583
])
86-
->add('asset', CheckboxType::class, [
87-
'label' => 'Véhicules',
84+
->add('hideAssets', CheckboxType::class, [
85+
'label' => 'Cacher les véhicules',
8886
'required' => false,
8987
])
9088
->add('assetTypes', ChoiceType::class, [
@@ -94,15 +92,13 @@ public function buildForm(FormBuilderInterface $builder, array $options): void
9492
'required' => false,
9593
'attr' => ['class' => 'selectpicker'],
9694
])
97-
->add('submit', SubmitType::class, ['label' => 'Filtrer'])
9895
;
96+
}
9997

100-
// Cannot use contraint in upper types, because it's not bound to an entity (therefore PropertyAccessor cannot succeed)
101-
$builder->addEventListener(FormEvents::PRE_SUBMIT, static function (FormEvent $event) {
102-
$data = $event->getData() ?? [];
103-
if (array_key_exists('from', $data) && array_key_exists('to', $data) && $data['from'] >= $data['to']) {
104-
throw new \InvalidArgumentException('Invalid payload'); // TODO Put a better error
105-
}
106-
});
98+
public function configureOptions(OptionsResolver $resolver): void
99+
{
100+
$resolver->setDefaults([
101+
'csrf_protection' => false,
102+
]);
107103
}
108104
}

src/Repository/CommissionableAssetRepository.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,11 @@ public function findByFilters(array $formData)
3636
{
3737
$qb = $this->createQueryBuilder('a');
3838

39-
if (0 < count($formData['assetTypes'])) {
39+
if (count($formData['assetTypes'] ?? []) > 0) {
4040
$qb->andWhere('a.type IN (:types)')->setParameter('types', $formData['assetTypes']);
4141
}
4242

43-
if (0 < $formData['organizations']->count()) {
43+
if (count($formData['organizations'] ?? []) > 0) {
4444
$qb->andWhere('a.organization IN (:organisations)')->setParameter('organisations', $formData['organizations']);
4545
}
4646

src/Repository/UserRepository.php

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -51,27 +51,21 @@ public function findByFilters(array $formData)
5151
{
5252
$qb = $this->createQueryBuilder('u');
5353

54-
$skillsQueries = [];
55-
foreach (array_values($formData['volunteerSkills']) as $key => $skill) {
56-
$skillsQueries[] = sprintf('CONTAINS(u.skillSet, ARRAY(:skill%d)) = TRUE', $key);
57-
$qb->setParameter(sprintf('skill%d', $key), $skill);
58-
}
59-
60-
if (0 < $formData['organizations']->count()) {
54+
if (count($formData['organizations'] ?? []) > 0) {
6155
$qb->andWhere('u.organization IN (:organisations)')->setParameter('organisations', $formData['organizations']);
6256
}
6357

64-
if ($formData['volunteerEquipped']) {
58+
if ($formData['onlyFullyEquiped'] ?? false) {
6559
$qb->andWhere('u.fullyEquipped = TRUE');
6660
}
6761

68-
if ($formData['volunteerHideVulnerable']) {
62+
if ($formData['displayVulnerables'] ?? false) {
6963
$qb->andWhere('u.vulnerable = FALSE');
7064
}
7165

72-
if (0 < count($formData['volunteerSkills'])) {
66+
if (count($formData['userSkills'] ?? []) > 0) {
7367
$skillsQueries = [];
74-
foreach (array_values($formData['volunteerSkills']) as $key => $skill) {
68+
foreach (array_values($formData['userSkills']) as $key => $skill) {
7569
$skillsQueries[] = sprintf('CONTAINS(u.skillSet, ARRAY(:skill%d)) = TRUE', $key);
7670
$qb->setParameter(sprintf('skill%d', $key), $skill);
7771
}

templates/organization/home.html.twig

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@
88
<h1>{{ app.user }}</h1>
99

1010
<p>Semaine actuelle : du {{ 'this week' | date('d/m/Y') }} au {{ 'sunday this week' | date('d/m/Y') }}</p>
11-
<p><button class="btn btn-primary" role="button" disabled>Afficher les disponibilités de mes bénévoles pour la semaine actuelle</button></p>
11+
<p><a class="btn btn-primary" role="button" href="{{ path('planning', {'organization[]': app.user.id}) }}">Afficher les disponibilités de mes bénévoles pour la semaine actuelle</a></p>
1212

1313
<p>Semaine prochaine : du {{ 'next week' | date('d/m/Y') }} au {{ 'sunday next week' | date('d/m/Y') }}</p>
14-
<p><button class="btn btn-primary" role="button" disabled>Afficher les disponibilités de mes bénévoles pour la semaine prochaine</button></p>
14+
<p><a class="btn btn-primary" role="button" href="{{ path('planning', {'organization[]': app.user.id, 'from': 'monday next week' | date('Y-m-d\\T00:00:00')}) }}">Afficher les disponibilités de mes bénévoles pour la semaine prochaine</a></p>
1515

1616
<hr>
1717

templates/organization/planning/_search_type.html.twig

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<div class="search shadow-sm p-3 mb-5 bg-white rounded">
2-
{{ form_start(form) }}
2+
{{ form_start(form, {'attr': {'id': 'planning-form'}}) }}
33
<div class="row">
44
<div class="col-12 col-md-6">
55
<label for="fromToRange">Période affichée: </label><input type="text" id="fromToRange" class="form-control" readonly>
@@ -27,36 +27,39 @@
2727
</div>
2828
</div>
2929
<div class="col-12 col-md-6">
30-
{{ form_row(form.volunteerHideVulnerable) }}
30+
{{ form_row(form.displayVulnerables) }}
3131
</div>
3232
</div>
3333

3434
<div class="row mt-md-2">
3535
<div class="col-12 col-md-2">
36-
{{ form_row(form.volunteer) }}
36+
{{ form_row(form.hideUsers) }}
3737
</div>
3838
<div class="col-12 col-md-6 row">
39-
{{ form_label(form.volunteerSkills, null, {'label_attr': {'class': 'col-12 col-md-3'}}) }}
39+
{{ form_label(form.userSkills, null, {'label_attr': {'class': 'col-12 col-md-3'}}) }}
4040
<div class="col-12 col-md-9">
41-
{{ form_widget(form.volunteerSkills) }}
41+
{{ form_widget(form.userSkills) }}
4242
</div>
4343
</div>
4444

4545
<div class="col-12 col-md-4">
46-
{{ form_row(form.volunteerEquipped) }}
46+
{{ form_row(form.onlyFullyEquiped) }}
4747
</div>
4848
</div>
4949

5050
<div class="row mt-md-2">
5151
<div class="col-12 col-md-2">
52-
{{ form_row(form.asset) }}
52+
{{ form_row(form.hideAssets) }}
5353
</div>
5454
<div class="col-12 col-md-6 row">
5555
{{ form_label(form.assetTypes, null, {'label_attr': {'class': 'col-12 col-md-3'}}) }}
5656
<div class="col-12 col-md-9">
5757
{{ form_widget(form.assetTypes) }}
5858
</div>
5959
</div>
60+
<div class="col-12 col-md-4 row">
61+
<button class="btn btn-outline-primary btn-block" type="submit">Rechercher</button>
62+
</div>
6063
</div>
6164
{{ form_end(form) }}
6265
</div>

0 commit comments

Comments
 (0)