Skip to content

Commit

Permalink
Add user to mission modal (#392)
Browse files Browse the repository at this point in the history
  • Loading branch information
mRoca committed May 7, 2020
1 parent 8435725 commit 8d051dc
Show file tree
Hide file tree
Showing 25 changed files with 231 additions and 47 deletions.
6 changes: 6 additions & 0 deletions assets/css/availability-table.scss
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,12 @@ table.availability-table {
.engaged {
background-color: $colorMission;
color: $colorMissionText;

&.btn-outline-light {
background-color: white;
border-color: $colorMission;
color: $colorMissionOutlineText;
}
}

.locked {
Expand Down
1 change: 1 addition & 0 deletions assets/css/variables.scss
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ $colorBooked: #67a2d3;
$colorLocked: #7a7a7a;
$colorMission: #f9d948;
$colorMissionText: #333;
$colorMissionOutlineText: #a7912e;

$footerColor: #f7f7f7;

Expand Down
65 changes: 62 additions & 3 deletions assets/js/_planning-missions.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,14 @@ function displayMissionModal($modal, id) {
return;
}

const url = window.location.pathname.indexOf('organizations') >= 0 ? `/organizations/missions/${id}/modal` : `/user/availability/missions/${id}/modal`;
displayAjaxModal($modal, url);
}

function displayAjaxModal($modal, url) {
const $loading = $modal.find('.loading').show();
const $content = $modal.find('.content').html('');

const url = window.location.pathname.indexOf('organizations') >= 0 ? `/organizations/missions/${id}/modal` : `/user/availability/missions/${id}/modal`;

$.ajax({
method: 'GET',
url,
Expand All @@ -96,7 +99,33 @@ function displayMissionModal($modal, id) {
$modal.modal('show');
}

export function fetchMissions(url) {
function addUserToMission(url) {
$('.mission-choose').prop('disabled', true);

$.ajax({
method: 'POST',
dataType: 'json',
url,
success: function () {
$('#modal-add-mission').modal('hide');
fetchMissions();
},
error: function () {
window.alert('Une erreur est survenue pendant la requête');
$('.mission-choose').prop('disabled', false);
},
});
}

export function fetchMissions() {
let url;

if ($('.planning').length) {
url = '/organizations/missions/find' + window.location.search;
} else {
url = window.location.pathname + '/missions';
}

$.ajax({
method: 'GET',
dataType: 'json',
Expand All @@ -122,4 +151,34 @@ export function initMissionsEvents() {
$modal.find('.loading').show();
$modal.find('.content').html('');
});

$('#modal-add-mission')
.on('show.bs.modal', function (event) {
const $modal = $(this);
const $link = $(event.relatedTarget);
const url = $link.data('href');

displayAjaxModal($modal, url);
})
.on('hidden.bs.modal', function () {
const $modal = $(this);
$modal.find('.loading').show();
$modal.find('.content').html('');
});

$(document).on('click', '.mission-choose', function () {
addUserToMission($(this).data('href'));
});

// Allow modals stacking
$(document).on('show.bs.modal', '.modal', function () {
const zIndex = 1040 + 10 * $('.modal:visible').length;
$(this).css('z-index', zIndex);
setTimeout(function () {
$('.modal-backdrop')
.not('.modal-stack')
.css('z-index', zIndex - 1)
.addClass('modal-stack');
});
});
}
2 changes: 1 addition & 1 deletion assets/js/availability-form.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,5 +59,5 @@ $(document).ready(function () {

addPopovers($table);
initMissionsEvents();
fetchMissions(window.location.pathname + '/missions');
fetchMissions();
});
2 changes: 1 addition & 1 deletion assets/js/planning.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ $(document).ready(function () {

initUpdateEvents();
initMissionsEvents();
fetchMissions('/organizations/missions/find' + window.location.search);
fetchMissions();

$('#hideUsers').on('change', hideUselessFilters);
$('#hideAssets').on('change', hideUselessFilters);
Expand Down
6 changes: 6 additions & 0 deletions config/routes.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ _organizations_planning:
type: annotation
prefix: /organizations/planning

_organizations_missions:
resource: ../src/Controller/Organization/Mission
type: annotation
# TODO Use organization ID
prefix: /organizations/missions

_organizations_assets:
resource: ../src/Controller/Organization/CommissionableAsset
type: annotation
Expand Down
29 changes: 29 additions & 0 deletions src/Controller/Organization/Mission/AddUserAjaxController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

declare(strict_types=1);

namespace App\Controller\Organization\Mission;

use App\Entity\Mission;
use App\Entity\User;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;

/**
* @Route("/{mission<\d+>}/users/add/{userToAdd<\d+>}", name="app_organization_mission_add_user", methods={"POST"})
*/
class AddUserAjaxController extends AbstractController
{
public function __invoke(Mission $mission, User $userToAdd): Response
{
if (!$mission->users->contains($userToAdd)) {
$mission->users->add($userToAdd);
}

$this->getDoctrine()->getManager()->flush();

return new JsonResponse();
}
}
2 changes: 1 addition & 1 deletion src/Controller/Organization/Mission/MissionController.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
use Symfony\Component\Routing\Annotation\Route;

/**
* @Route("/missions")
* @Route("/")
* @Security("is_granted('ROLE_PARENT_ORGANIZATION')")
*/
class MissionController extends AbstractController
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
use Symfony\Component\Routing\Annotation\Route;

/**
* @Route("/missions/{id<\d+>}/modal", name="app_organization_mission_modal", methods={"GET"})
* @Route("/{id<\d+>}/modal", name="app_organization_mission_modal", methods={"GET"})
*/
class MissionModalController extends AbstractController
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
use Symfony\Component\Serializer\SerializerInterface;

/**
* @Route("/missions/find", name="app_organization_mission_find_by_filters", methods={"GET"})
* @Route("/find", name="app_organization_mission_find_by_filters", methods={"GET"})
*/
class MissionsFindByFiltersController
{
Expand Down
41 changes: 41 additions & 0 deletions src/Controller/Organization/User/AddToMissionModalController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php

declare(strict_types=1);

namespace App\Controller\Organization\User;

use App\Domain\PlanningDomain;
use App\Entity\User;
use App\Form\Type\MissionsSearchType;
use App\Repository\MissionRepository;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;

/**
* @Route("/{userToAdd<\d+>}/missions/add/modal", name="app_organization_user_add_to_mission_modal", methods={"GET"})
*/
class AddToMissionModalController extends AbstractController
{
private PlanningDomain $planningDomain;
private MissionRepository $missionRepository;

public function __construct(PlanningDomain $planningDomain, MissionRepository $missionRepository)
{
$this->planningDomain = $planningDomain;
$this->missionRepository = $missionRepository;
}

public function __invoke(User $userToAdd): Response
{
$form = $this->planningDomain->generateForm(MissionsSearchType::class);
$filters = $form->getData();

return $this->render('organization/mission/add-to-mission-modal-content.html.twig', [
'userToAdd' => $userToAdd,
'filters' => $filters,
'form' => $form->createView(),
'missions' => $this->missionRepository->findByFilters($filters),
]);
}
}
5 changes: 1 addition & 4 deletions src/Form/Type/MissionType.php
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,7 @@ public function buildForm(FormBuilderInterface $builder, array $options): void
'required' => false,
'choice_attr' => function (User $user) {
return [
'data-content' => $user.' '.implode('', array_map(
fn (string $skill) => $this->userExtension->formatBadge($skill),
$this->userExtension->filterInludedSkills($user->skillSet)
)),
'data-content' => $user.' '.$this->userExtension->userBadges($user),
];
},
'attr' => [
Expand Down
16 changes: 9 additions & 7 deletions src/ParamConverter/UserParamConverter.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,18 @@ public function __construct(UserRepository $userRepository)
public function apply(Request $request, ParamConverter $configuration): bool
{
$name = $configuration->getName();
$userId = $request->attributes->getInt($name);
$search = ['id' => $userId];

$user = $this->userRepository->findOneBy(
[
'id' => $assetId = $request->attributes->getInt($name),
'organization' => $organizationId = $request->attributes->getInt('organization'),
]
);
$organizationId = $request->attributes->get('organization', null);
if (null !== $organizationId) {
$search += ['organization' => $organizationId];
}

$user = $this->userRepository->findOneBy($search);

if (null === $user) {
throw new NotFoundHttpException(sprintf('User with id "%d" and organization id "%d" does not exist.', $assetId, $organizationId));
throw new NotFoundHttpException(sprintf('User with id "%d" and organization id "%d" does not exist.', $userId, $organizationId));
}

$request->attributes->set($name, $user);
Expand Down
2 changes: 1 addition & 1 deletion src/Repository/MissionRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,6 @@ private function addFromToFilter(QueryBuilder $qb, array $filters): QueryBuilder
'm.startTime <= :end and m.endTime >= :end',
))
->setParameter('start', $filters['from'])
->setParameter('end', $filters['to']);
->setParameter('end', $filters['to']->modify('tomorrow'));
}
}
12 changes: 1 addition & 11 deletions src/Twig/Extension/PlanningExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,18 @@

use App\Domain\DatePeriodCalculator;
use App\Domain\PlanningDomain;
use App\Domain\SkillSetDomain;
use App\Entity\User;
use Twig\Extension\AbstractExtension;
use Twig\TwigFilter;
use Twig\TwigFunction;

final class PlanningExtension extends AbstractExtension
{
private PlanningDomain $planningDomain;
private SkillSetDomain $skillSetDomain;
private string $slotInterval;

public function __construct(PlanningDomain $planningDomain, SkillSetDomain $skillSetDomain, string $slotInterval)
public function __construct(PlanningDomain $planningDomain, string $slotInterval)
{
$this->planningDomain = $planningDomain;
$this->skillSetDomain = $skillSetDomain;
$this->slotInterval = $slotInterval;
}

Expand All @@ -33,7 +29,6 @@ public function getFunctions(): array
return [
new TwigFunction('renderPlanningTable', [$this, 'renderTable']),
new TwigFunction('getAvailabilities', [$this, 'getAvailabilities']),
new TwigFunction('getDisplayableSkillsInPlanning', [$this, 'getDisplayableSkills']),
];
}

Expand All @@ -57,11 +52,6 @@ public function getAvailabilities(DatePeriodCalculator $periodCalculator, array
return $this->planningDomain->generateAvailabilities($filters, $periodCalculator->getPeriod());
}

public function getDisplayableSkills(User $user): array
{
return $this->skillSetDomain->filterIncludedSkills($user->skillSet);
}

public function renderTable(array $availabilities, bool $displayActions): string
{
$res = '';
Expand Down
9 changes: 9 additions & 0 deletions src/Twig/Extension/UserExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ public function getFilters(): array
{
return [
new TwigFilter('skillBadge', [$this, 'formatBadge'], ['is_safe' => ['html']]),
new TwigFilter('userBadges', [$this, 'userBadges'], ['is_safe' => ['html']]),
new TwigFilter('sortBySkills', [$this, 'sortBySkills']),
new TwigFilter('filterSkillsToDisplay', [$this, 'filterSkillsToDisplay']),
new TwigFilter('filterInludedSkills', [$this, 'filterInludedSkills']),
Expand All @@ -41,6 +42,14 @@ public function filterInludedSkills(array $skills): array
return $this->skillSetDomain->filterIncludedSkills($skills);
}

public function userBadges(User $user): string
{
return implode('', array_map(
fn (string $skill) => $this->formatBadge($skill),
$this->filterInludedSkills($user->skillSet)
));
}

public function formatBadge(string $skill): string
{
$importantSkills = $this->skillSetDomain->getImportantSkills();
Expand Down
13 changes: 12 additions & 1 deletion templates/organization/mission/_list.html.twig
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,18 @@
<td>{{ mission.assets | length }}</td>
<td>{{ mission.comment | truncate }}</td>
<td>
<a class="btn btn-primary" href="{{ path('app_organization_mission_show', {'id': mission.id}) }}">{{ 'action.show' | trans }}</a>
{% if userToAdd is defined %}
<button class="btn btn-danger mission-choose" data-href="{{ path('app_organization_mission_add_user', {mission: mission.id, userToAdd: userToAdd.id}) }}">
{{ 'organization.asset.engageThis' | trans }}
</button>
{% endif %}

{% if modalLinks is not defined or modalLinks %}
<button type="button" class="btn btn-outline-primary" data-toggle="modal" data-target="#modal-mission" data-mission-id="{{ mission.id }}">{{ 'action.show' | trans }}</button>
{% else %}
<a class="btn btn-primary" href="{{ path('app_organization_mission_show', {'id': mission.id}) }}">{{ 'action.show' | trans }}</a>
{% endif %}

{% if showActions is not defined or showActions %}
<a class="btn btn-secondary" href="{{ path('app_organization_mission_edit', {'id': mission.id}) }}">{{ 'action.edit' | trans }}</a>
<a class="btn btn-outline-danger trigger-delete" data-display-name="{{ mission.name }}" href="#" data-href="{{ path('app_organization_mission_delete', { id: mission.id }) }}">{{ 'action.delete' | trans }}</a>
Expand Down
6 changes: 1 addition & 5 deletions templates/organization/mission/_list_full.html.twig
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,7 @@
<td colspan="3"></td>
<td>{{ user.organization.name }}</td>
<td>{{ user.fullName }}</td>
<td>
{% for skill in getDisplayableSkillsInPlanning(user) -%}
{{ skill|skillBadge }}
{%- endfor %}
</td>
<td>{{ user|userBadges }}</td>
<td><small>{{ user.identificationNumber }}</small></td>
<td>
<a href="mailto:{{ user.emailAddress }}" class="small">{{ user.emailAddress }}</a>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<div>
<h3>{{ userToAdd }} {{ userToAdd|userBadges }}</h3>
<h5 class="mt-3">{{ 'organization.mission.periodList' | trans({ '%from%' : filters.from | format_date('long'), '%to%' : filters.to | format_date('long') }) }}</h5>

<div class="text-right mb-3">
<a class="btn btn-link" href="{{ path('app_organization_mission_new') }}" role="button">{{ 'organization.mission.addNewNewPage' | trans }}</a>
</div>
{% include 'organization/mission/_list.html.twig' with {showActions: false, modalLinks: true} %}
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,5 @@
{% endif %}
</td>
{% endfor %}
<td></td>
{% endblock itemDataDetails %}

0 comments on commit 8d051dc

Please sign in to comment.