From 26239488bae167f28d14ab5b361e0715d1d5b48a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Fromme?= Date: Thu, 4 Apr 2024 13:06:35 +0200 Subject: [PATCH] feat: special agreements for disposition --- .../textarea_autosize_controller.js | 12 +++++ migrations/Version20240404091244.php | 31 ++++++++++++ .../Admin/Application/DisposeController.php | 8 ++- .../SpecialAgreementsController.php | 49 +++++++++++++++++++ .../Document/CheckController.php | 18 +++++-- src/Entity/Disposition.php | 15 ++++++ src/Form/AssignmentType.php | 3 +- src/Form/DocumentCheckType.php | 14 ++++++ src/Form/Extension/ModalSubmitExtension.php | 39 +++++++++++++++ src/Form/FaqType.php | 1 - src/Form/SpecialAgreementsType.php | 31 ++++++++++++ src/Htmx/HxTriggerResponse.php | 13 +++++ src/Model/DocumentCheckDto.php | 14 ++++++ .../admin/application/modal_dispose.html.twig | 20 ++++++-- templates/admin/index.html.twig | 13 +++-- .../assignment/detail.html.twig | 34 ++++++++----- .../modal_special_agreements.html.twig | 18 +++++++ .../document/modal_check.html.twig | 3 ++ templates/htmx_modal.html.twig | 5 +- 19 files changed, 310 insertions(+), 31 deletions(-) create mode 100644 assets/controllers/textarea_autosize_controller.js create mode 100644 migrations/Version20240404091244.php create mode 100644 src/Controller/Administrative/Disposition/SpecialAgreementsController.php create mode 100644 src/Form/Extension/ModalSubmitExtension.php create mode 100644 src/Form/SpecialAgreementsType.php create mode 100644 src/Htmx/HxTriggerResponse.php create mode 100644 templates/administrative/disposition/modal_special_agreements.html.twig diff --git a/assets/controllers/textarea_autosize_controller.js b/assets/controllers/textarea_autosize_controller.js new file mode 100644 index 0000000..582451c --- /dev/null +++ b/assets/controllers/textarea_autosize_controller.js @@ -0,0 +1,12 @@ +import { Controller } from '@hotwired/stimulus' + +export default class extends Controller { + connect() { + this.element.style.height = 'auto' + this.resize() + } + + resize() { + this.element.style.height = `${this.element.scrollHeight}px` + } +} diff --git a/migrations/Version20240404091244.php b/migrations/Version20240404091244.php new file mode 100644 index 0000000..0947f7b --- /dev/null +++ b/migrations/Version20240404091244.php @@ -0,0 +1,31 @@ +addSql('ALTER TABLE disposition ADD special_agreements LONGTEXT DEFAULT NULL'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('ALTER TABLE disposition DROP special_agreements'); + } +} diff --git a/src/Controller/Admin/Application/DisposeController.php b/src/Controller/Admin/Application/DisposeController.php index 7a17d8e..f6849bd 100644 --- a/src/Controller/Admin/Application/DisposeController.php +++ b/src/Controller/Admin/Application/DisposeController.php @@ -5,6 +5,7 @@ namespace App\Controller\Admin\Application; use App\Entity\Application; use App\Entity\Disposition; use App\Event\DispositionCreatedEvent; +use App\Form\SpecialAgreementsType; use App\Htmx\HxRedirectResponse; use Doctrine\ORM\EntityManagerInterface; use Psr\Log\LoggerInterface; @@ -29,9 +30,11 @@ class DisposeController extends AbstractController #[IsGranted('DISPOSE', subject: 'application')] public function index(Application $application, Request $request): Response { - if (true === $request->isMethod('POST')) { - $disposition = new Disposition($application); + $disposition = new Disposition($application); + $form = $this->createForm(SpecialAgreementsType::class, $disposition, ['hx_post' => $request->getUri()]); + $form->handleRequest($request); + if ($form->isSubmitted() && $form->isValid()) { $this->entityManager->persist($disposition); $this->entityManager->remove($application); $this->entityManager->flush(); @@ -53,6 +56,7 @@ class DisposeController extends AbstractController return $this->render('admin/application/modal_dispose.html.twig', [ 'application' => $application, + 'form' => $form->createView(), ]); } } \ No newline at end of file diff --git a/src/Controller/Administrative/Disposition/SpecialAgreementsController.php b/src/Controller/Administrative/Disposition/SpecialAgreementsController.php new file mode 100644 index 0000000..4e0f4de --- /dev/null +++ b/src/Controller/Administrative/Disposition/SpecialAgreementsController.php @@ -0,0 +1,49 @@ +createForm(SpecialAgreementsType::class, $disposition, ['hx_post' => $request->getUri()]); + $form->handleRequest($request); + + if ($form->isSubmitted() && $form->isValid()) { + $this->entityManager->flush(); + + $this->logger->info('Edit special agreements', [ + 'disposition' => $disposition->getUuid(), + 'special_agreements' => $disposition->getSpecialAgreements(), + ]); + + return new HxRedirectResponse($this->generateUrl('app_administrative_assignment_detail', [ + 'uuid' => $disposition->getAssignment()->getUuid(), + ])); + } + + return $this->render('administrative/disposition/modal_special_agreements.html.twig', [ + 'disposition' => $disposition, + 'form' => $form->createView(), + ]); + } +} diff --git a/src/Controller/Administrative/Document/CheckController.php b/src/Controller/Administrative/Document/CheckController.php index 8954aea..0745725 100644 --- a/src/Controller/Administrative/Document/CheckController.php +++ b/src/Controller/Administrative/Document/CheckController.php @@ -2,6 +2,7 @@ namespace App\Controller\Administrative\Document; +use App\Controller\Traits\ReturnUrlTrait; use App\Entity\Upload; use App\Event\DocumentRejectedEvent; use App\Form\DocumentCheckType; @@ -20,6 +21,8 @@ use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; class CheckController extends AbstractController { + use ReturnUrlTrait; + public function __construct( private readonly EntityManagerInterface $entityManager, #[Target('disposition')] @@ -42,14 +45,15 @@ class CheckController extends AbstractController if ($form->isSubmitted() && $form->isValid()) { switch ($formData->getStatus()) { case Upload::STATUS_CHECKED: - $this->confirmDocument($document, 'confirm_contract', Upload::STATUS_CHECKED); + $this->confirmDocument($document, 'confirm_contract', Upload::STATUS_CHECKED, $formData); break; case Upload::STATUS_PAID: - $this->confirmDocument($document, 'confirm_invoice', Upload::STATUS_PAID); + $this->confirmDocument($document, 'confirm_invoice', Upload::STATUS_PAID, $formData); break; case Upload::STATUS_REJECTED: $this->rejectDocument($document, $formData->getComment()); $this->eventDispatcher->dispatch(new DocumentRejectedEvent($formData), DocumentRejectedEvent::NAME); + break; default: $document ->setStatus($formData->getStatus()) @@ -65,7 +69,9 @@ class CheckController extends AbstractController ]); } - return new HxRedirectResponse($this->generateUrl('app_administrative_document_index')); + $returnUrl = $this->getReturnUrl($request, 'app_administrative_document_index'); + + return new HxRedirectResponse($returnUrl); } return $this->render('administrative/document/modal_check.html.twig', [ @@ -94,7 +100,7 @@ class CheckController extends AbstractController $this->entityManager->flush(); } - private function confirmDocument(Upload $document, string $transition, string $status): void + private function confirmDocument(Upload $document, string $transition, string $status, DocumentCheckDto $formData): void { $document->setStatus($status); $this->addFlash('success', 'Das Dokument wurde bestätigt'); @@ -113,6 +119,10 @@ class CheckController extends AbstractController } } + if (Upload::TYPE_INVOICE === $document->getType()) { + $document->getDisposition()->setSpecialAgreements($formData->getSpecialAgreements()); + } + $this->entityManager->flush(); } } diff --git a/src/Entity/Disposition.php b/src/Entity/Disposition.php index e3ae642..69b1e91 100644 --- a/src/Entity/Disposition.php +++ b/src/Entity/Disposition.php @@ -50,6 +50,9 @@ class Disposition implements BlameableEntityInterface, TimestampableEntityInterf #[ORM\Column(type: Types::TEXT, nullable: true)] private ?string $remarks; + #[ORM\Column(type: Types::TEXT, nullable: true)] + private ?string $specialAgreements; + #[ORM\OneToMany(mappedBy: 'disposition', targetEntity: Upload::class, cascade: ['persist', 'remove'])] private Collection $documents; @@ -137,6 +140,18 @@ class Disposition implements BlameableEntityInterface, TimestampableEntityInterf return $this; } + public function getSpecialAgreements(): ?string + { + return $this->specialAgreements; + } + + public function setSpecialAgreements(?string $specialAgreements): static + { + $this->specialAgreements = $specialAgreements; + + return $this; + } + /** * @return Collection */ diff --git a/src/Form/AssignmentType.php b/src/Form/AssignmentType.php index 68672e2..0788273 100644 --- a/src/Form/AssignmentType.php +++ b/src/Form/AssignmentType.php @@ -132,7 +132,8 @@ class AssignmentType extends AbstractType 'label' => 'Anmerkungen', 'required' => false, 'attr' => [ - 'rows' => 3, + 'data-controller' => 'textarea-autosize', + 'data-action' => 'textarea-autosize#resize' ], ]) ->add('pickup', ChoiceType::class, [ diff --git a/src/Form/DocumentCheckType.php b/src/Form/DocumentCheckType.php index b1c16c2..96a4705 100644 --- a/src/Form/DocumentCheckType.php +++ b/src/Form/DocumentCheckType.php @@ -8,6 +8,8 @@ use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\Form\Extension\Core\Type\TextareaType; use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\Form\FormEvent; +use Symfony\Component\Form\FormEvents; use Symfony\Component\OptionsResolver\OptionsResolver; class DocumentCheckType extends AbstractType @@ -26,6 +28,18 @@ class DocumentCheckType extends AbstractType 'rows' => 3, ], ]) + ->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) { + /** @var DocumentCheckDto $data */ + $data = $event->getData(); + $upload = $data->getUpload(); + + if (Upload::TYPE_INVOICE === $upload->getType()) { + $event->getForm()->add('specialAgreements', TextareaType::class, [ + 'label' => 'zusätzliche Absprache', + 'required' => false, + ]); + } + }) ; } diff --git a/src/Form/Extension/ModalSubmitExtension.php b/src/Form/Extension/ModalSubmitExtension.php new file mode 100644 index 0000000..fe61f93 --- /dev/null +++ b/src/Form/Extension/ModalSubmitExtension.php @@ -0,0 +1,39 @@ +setDefaults([ + 'hx_post' => null, + 'hx_target' => '#htmx-modal', + 'hx_swap' => 'outerHTML', + ]); + } + + public function buildView(FormView $view, FormInterface $form, array $options): void + { + if (null !== $options['hx_post']) { + $attr = [ + 'hx-post' => $options['hx_post'], + 'hx-target' => $options['hx_target'], + 'hx-swap' => $options['hx_swap'], + 'hx-indicator' => '#htmx-modal-indicator', + ]; + $view->vars['attr'] = array_merge($view->vars['attr'], $attr); + } + } + + public static function getExtendedTypes(): iterable + { + return [FormType::class]; + } +} diff --git a/src/Form/FaqType.php b/src/Form/FaqType.php index 4512cf6..7739cef 100644 --- a/src/Form/FaqType.php +++ b/src/Form/FaqType.php @@ -4,7 +4,6 @@ namespace App\Form; use App\Entity\Faq; use Symfony\Component\Form\AbstractType; -use Symfony\Component\Form\Extension\Core\Type\HiddenType; use Symfony\Component\Form\Extension\Core\Type\TextareaType; use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\FormBuilderInterface; diff --git a/src/Form/SpecialAgreementsType.php b/src/Form/SpecialAgreementsType.php new file mode 100644 index 0000000..ff18942 --- /dev/null +++ b/src/Form/SpecialAgreementsType.php @@ -0,0 +1,31 @@ +add('specialAgreements', TextareaType::class, [ + 'label' => 'zusätzliche Absprache', + 'required' => false, + 'attr' => [ + 'data-controller' => 'textarea-autosize', + 'data-action' => 'textarea-autosize#resize' + ] + ]); + } + + public function configureOptions(OptionsResolver $resolver): void + { + $resolver->setDefaults([ + 'data_class' => Disposition::class, + ]); + } +} \ No newline at end of file diff --git a/src/Htmx/HxTriggerResponse.php b/src/Htmx/HxTriggerResponse.php new file mode 100644 index 0000000..fc96535 --- /dev/null +++ b/src/Htmx/HxTriggerResponse.php @@ -0,0 +1,13 @@ + $trigger]); + } +} diff --git a/src/Model/DocumentCheckDto.php b/src/Model/DocumentCheckDto.php index 600f5d7..b997cb0 100644 --- a/src/Model/DocumentCheckDto.php +++ b/src/Model/DocumentCheckDto.php @@ -9,11 +9,13 @@ class DocumentCheckDto private Upload $upload; private ?string $status = null; private ?string $comment; + private ?string $specialAgreements; public function __construct(Upload $upload) { $this->upload = $upload; $this->comment = $upload->getComment(); + $this->specialAgreements = $upload->getDisposition()?->getSpecialAgreements(); } public function getUpload(): Upload @@ -44,4 +46,16 @@ class DocumentCheckDto return $this; } + + public function getSpecialAgreements(): ?string + { + return $this->specialAgreements; + } + + public function setSpecialAgreements(?string $specialAgreements): static + { + $this->specialAgreements = $specialAgreements; + + return $this; + } } \ No newline at end of file diff --git a/templates/admin/application/modal_dispose.html.twig b/templates/admin/application/modal_dispose.html.twig index e058299..8804856 100644 --- a/templates/admin/application/modal_dispose.html.twig +++ b/templates/admin/application/modal_dispose.html.twig @@ -1,7 +1,21 @@ -{% extends 'htmx_confirmation_modal.html.twig' %} +{% extends 'htmx_modal.html.twig' %} + +{% block title %}Einteilung{% endblock %} {% block content %} -
- Möchtest du {{ application.teamer }} wirklich einteilen? +
+ Möchtest du {{ application.teamer }} wirklich für den Einsatz {{ application.assignment.destination}} einteilen?
+ {{ form_start(form) }} + {{ form_row(form.specialAgreements) }} +
+ + +
+ {{ form_rest(form) }} + {{ form_end(form) }} {% endblock %} \ No newline at end of file diff --git a/templates/admin/index.html.twig b/templates/admin/index.html.twig index dd136b2..87fa392 100644 --- a/templates/admin/index.html.twig +++ b/templates/admin/index.html.twig @@ -48,17 +48,16 @@
    {% for document in documents %}
  • - {% if document.disposition %} - {% set url = path('app_administrative_assignment_detail', { 'uuid': document.disposition.assignment.uuid, 'r': return_url() }) %} - {% else %} - {% set url = path('app_administrative_teamer_profile', { 'uuid': document.owner.teamer.uuid, 'r': return_url() }) %} - {% endif %} - +
  • {% else %}
  • diff --git a/templates/administrative/assignment/detail.html.twig b/templates/administrative/assignment/detail.html.twig index d39c3e3..3d6418d 100644 --- a/templates/administrative/assignment/detail.html.twig +++ b/templates/administrative/assignment/detail.html.twig @@ -22,14 +22,14 @@ Name - - Zustieg + + Status Wünsche - Status + Zustieg @@ -49,15 +49,15 @@ + + {{ ('label.application.status.' ~ application.status)|trans }} + {{ application.pickup|bpn_pickup_label|default('-') }} {{ application.requests|nl2br|default('-') }} - - {{ ('label.application.status.' ~ application.status)|trans }} -
    {% if is_granted('DISPOSE', application) %} @@ -95,7 +95,7 @@ {% else %} - + Es liegen keine Bewerbungen vor... @@ -116,11 +116,14 @@ Name - + + Status + + Anmerkungen - Status + Absprachen @@ -140,11 +143,20 @@ + + {{ ('label.disposition.status.' ~ disposition.status)|trans }} + {{ disposition.remarks|nl2br|default('-') }} - {{ ('label.disposition.status.' ~ disposition.status)|trans }} +
    @@ -163,7 +175,7 @@ {% else %} - + Es gibt noch keine Einteilungen... diff --git a/templates/administrative/disposition/modal_special_agreements.html.twig b/templates/administrative/disposition/modal_special_agreements.html.twig new file mode 100644 index 0000000..0d6769f --- /dev/null +++ b/templates/administrative/disposition/modal_special_agreements.html.twig @@ -0,0 +1,18 @@ +{% extends 'htmx_modal.html.twig' %} + +{% block title %}Zusätzliche Abspsprachen{% endblock %} + +{% block content %} + {{ form_start(form) }} +

    + Teamer {{ disposition.teamer }} +

    +
    + {{ form_row(form.specialAgreements) }} +
    + + {{ form_rest(form) }} + {{ form_end(form) }} +{% endblock %} \ No newline at end of file diff --git a/templates/administrative/document/modal_check.html.twig b/templates/administrative/document/modal_check.html.twig index b31af19..7575bad 100644 --- a/templates/administrative/document/modal_check.html.twig +++ b/templates/administrative/document/modal_check.html.twig @@ -9,6 +9,9 @@
    {{ form_row(form.status) }} + {% if form.specialAgreements is defined %} + {{ form_row(form.specialAgreements) }} + {% endif %} {{ form_row(form.comment) }}
    {% block content %}{% endblock %} -
    +
    {% include '_partials/_spinner.html.twig' with { 'class': 'w-8 h-8'} %}