feat: streamlined teamer info modals, internal teamer remarks
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DoctrineMigrations;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
/**
|
||||
* Auto-generated Migration: Please modify to your needs!
|
||||
*/
|
||||
final class Version20250210162751 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 teamer ADD remarks_internal LONGTEXT DEFAULT NULL');
|
||||
$this->addSql('ALTER TABLE user DROP hotel_code');
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
// this down() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('ALTER TABLE teamer DROP remarks_internal');
|
||||
$this->addSql('ALTER TABLE user ADD hotel_code VARCHAR(32) DEFAULT NULL');
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller\Admin\Application;
|
||||
|
||||
use App\Entity\Application;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
|
||||
class InfoController extends AbstractController
|
||||
{
|
||||
#[Route('/admin/application/info/{uuid}', name: 'app_admin_application_info')]
|
||||
public function index(Application $application): Response
|
||||
{
|
||||
return $this->render('admin/application/modal_info.html.twig', [
|
||||
'application' => $application,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller\Admin\Teamer;
|
||||
|
||||
use App\Controller\Traits\ReturnUrlTrait;
|
||||
use App\Entity\Teamer;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||
|
||||
class RemarksController extends AbstractController
|
||||
{
|
||||
use ReturnUrlTrait;
|
||||
|
||||
public function __construct(private readonly EntityManagerInterface $entityManager)
|
||||
{}
|
||||
|
||||
#[Route('/admin/teamer/remarks/{uuid}', name: 'app_admin_teamer_remarks_internal')]
|
||||
#[IsGranted('ROLE_ADMIN')]
|
||||
public function index(Teamer $teamer, Request $request): Response
|
||||
{
|
||||
$returnUrl = $this->getReturnUrl($request, 'app_administrative_teamer_index');
|
||||
|
||||
$form = $this
|
||||
->createFormBuilder([
|
||||
'remarks' => $teamer->getRemarksInternal(),
|
||||
], [
|
||||
'action' => $this->generateUrl('app_admin_teamer_remarks_internal', [
|
||||
'uuid' => $teamer->getUuid(),
|
||||
'r' => $returnUrl,
|
||||
])
|
||||
])
|
||||
->add('remarks', TextareaType::class, [
|
||||
'label' => 'Anmerkungen',
|
||||
'required' => true,
|
||||
'attr' => [
|
||||
'rows' => 10,
|
||||
],
|
||||
])
|
||||
->getForm()
|
||||
;
|
||||
|
||||
$form->handleRequest($request);
|
||||
|
||||
if ($form->isSubmitted() && $form->isValid()) {
|
||||
$teamer->setRemarksInternal($form->get('remarks')->getData());
|
||||
$this->entityManager->flush();
|
||||
|
||||
$this->addFlash('success', 'Die Anmerkungen wurden gespeichert.');
|
||||
|
||||
return $this->redirectToRoute('app_admin_teamer_remarks_internal', [
|
||||
'uuid' => $teamer->getUuid(),
|
||||
'r' => $returnUrl,
|
||||
]);
|
||||
}
|
||||
|
||||
return $this->render('admin/teamer/remarks_internal.html.twig', [
|
||||
'teamer' => $teamer,
|
||||
'form' => $form->createView(),
|
||||
'returnUrl' => $returnUrl,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -51,8 +51,18 @@ class CreateController extends AbstractController
|
||||
$yearFrom = (int) date('Y');
|
||||
$yearsRange = range($yearFrom + 1, $yearFrom - 10);
|
||||
|
||||
$returnUrl = $this->getReturnUrl($request, 'app_admin_teamer_skills', [
|
||||
'uuid' => $teamer->getUuid(),
|
||||
]);
|
||||
|
||||
$form = $this
|
||||
->createFormBuilder($attendance)
|
||||
->createFormBuilder($attendance, [
|
||||
'action' => $this->generateUrl('app_admin_teamer_skills_training_attendance_create', [
|
||||
'training_id' => $training->getId(),
|
||||
'teamer_id' => $teamer->getId(),
|
||||
'r' => $returnUrl,
|
||||
])
|
||||
])
|
||||
->add('date', AbbreviatedDateType::class, [
|
||||
'label' => 'Datum',
|
||||
'years' => $yearsRange,
|
||||
@@ -79,11 +89,7 @@ class CreateController extends AbstractController
|
||||
'training_name' => $training->getName(),
|
||||
]);
|
||||
|
||||
$redirectUrl = $this->getReturnUrl($request, 'app_admin_teamer_skills', [
|
||||
'uuid' => $teamer->getUuid(),
|
||||
]);
|
||||
|
||||
return new HxRedirectResponse($redirectUrl);
|
||||
return new HxRedirectResponse($returnUrl);
|
||||
}
|
||||
|
||||
return $this->render('admin/teamer/training_attendance/modal_create.html.twig', [
|
||||
|
||||
@@ -2,28 +2,35 @@
|
||||
|
||||
namespace App\Controller\Administrative\Teamer;
|
||||
|
||||
use App\Controller\Traits\ReturnUrlTrait;
|
||||
use App\Entity\Teamer;
|
||||
use App\Repository\DispositionRepository;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\ExpressionLanguage\Expression;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||
|
||||
class InfoController extends AbstractController
|
||||
{
|
||||
use ReturnUrlTrait;
|
||||
|
||||
public function __construct(private readonly DispositionRepository $dispositionRepository)
|
||||
{}
|
||||
|
||||
#[Route('/administrative/teamer/info/{uuid}', name: 'app_administrative_teamer_info')]
|
||||
#[IsGranted(new Expression('is_granted("ROLE_ADMINISTRATIVE") or is_granted("ROLE_HOUSE_MANAGER")'))]
|
||||
public function index(Teamer $teamer): Response
|
||||
public function index(Teamer $teamer, Request $request): Response
|
||||
{
|
||||
$returnUrl = $this->getReturnUrl($request, 'app_administrative_assignment_index');
|
||||
|
||||
$recentDispositions = $this->dispositionRepository->findRecentDispositionsByTeamer($teamer);
|
||||
|
||||
return $this->render('administrative/teamer/modal_info.html.twig', [
|
||||
'teamer' => $teamer,
|
||||
'recentDispositions' => $recentDispositions,
|
||||
'returnUrl' => $returnUrl,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -83,6 +83,9 @@ class Teamer implements TimestampableEntityInterface
|
||||
#[ORM\Column(type: Types::TEXT, nullable: true)]
|
||||
private ?string $remarks = null;
|
||||
|
||||
#[ORM\Column(type: Types::TEXT, nullable: true)]
|
||||
private ?string $remarksInternal = null;
|
||||
|
||||
#[ORM\ManyToMany(targetEntity: Availability::class, inversedBy: 'teamers')]
|
||||
#[ORM\OrderBy(['dateFrom' => 'ASC'])]
|
||||
private Collection $availabilities;
|
||||
@@ -388,6 +391,18 @@ class Teamer implements TimestampableEntityInterface
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getRemarksInternal(): ?string
|
||||
{
|
||||
return $this->remarksInternal;
|
||||
}
|
||||
|
||||
public function setRemarksInternal(?string $remarksInternal): static
|
||||
{
|
||||
$this->remarksInternal = $remarksInternal;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection<int, Availability>
|
||||
*/
|
||||
|
||||
@@ -285,6 +285,13 @@ class AdminMenuBuilder extends AbstractMenuBuilder
|
||||
'title' => 'Vergangene Einsätze',
|
||||
],
|
||||
]);
|
||||
$menu->addChild('Anmerkungen (intern)', [
|
||||
'route' => 'app_admin_teamer_remarks_internal',
|
||||
'routeParameters' => $this->getDefaultRouteParameters('uuid'),
|
||||
'linkAttributes' => [
|
||||
'title' => 'Anmerkungen (intern)',
|
||||
],
|
||||
]);
|
||||
|
||||
$this->addDivider($menu);
|
||||
|
||||
|
||||
@@ -64,7 +64,8 @@
|
||||
{% elseif item.extras.divider is defined %}
|
||||
<hr class="my-4 h-px bg-gray-200">
|
||||
{% else %}
|
||||
<div class="hover:bg-gray-50 group flex gap-x-3 rounded-md p-2 text-sm leading-5 font-semibold text-gray-700" role="button">
|
||||
<div class="hover:bg-gray-50 group flex gap-x-3 rounded-md p-2 text-sm leading-5 font-semibold text-gray-700"
|
||||
role="button">
|
||||
{{ block('label') }}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
{% extends 'htmx_modal.html.twig' %}
|
||||
|
||||
{% block title %}Teamer:inneninfo {{ application.teamer }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="flex items-start">
|
||||
<div class="flex-1 pr-8">
|
||||
{% include '_partials/_assignment_requirements_info.html.twig' with {
|
||||
'assignment': application.assignment,
|
||||
'teamer': application.teamer
|
||||
} %}
|
||||
<ul class="pb-8 divide-y divide-gray-200">
|
||||
{% for type in ['ski', 'snowboard'] %}
|
||||
<li class="py-2">
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="flex-1">{{ type|license_label }}</span>
|
||||
{% set license = application.teamer.licenseOfType(type) %}
|
||||
{% if license %}
|
||||
<div class="flex items-center space-x-2">
|
||||
<span>{{ license.date|date('m/Y') }}</span>
|
||||
{% if is_granted('DOWNLOAD', license.certificate) %}
|
||||
<a href="{{ path('app_common_download', { 'uuid': license.certificate.uuid, 'inline': true }) }}"
|
||||
target="_blank"
|
||||
title="Download Nachweis">
|
||||
{{ icon('download', 'w-4 h-4') }}
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% else %}
|
||||
{{ icon('minus', 'w-4 h-4') }}
|
||||
{% endif %}
|
||||
</div>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
{% set teamer = application.teamer %}
|
||||
{% if teamer.photo %}
|
||||
<img src="{{ asset(teamer.photo.filename | imagine_filter('profile')) }}"
|
||||
class="w-32 h-auto border-2 border-primary"
|
||||
alt="{{ teamer.firstName }}">
|
||||
{% else %}
|
||||
<div class="border-2 border-primary">
|
||||
{{ icon('user', 'w-32 h-32 text-gray-200') }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,25 @@
|
||||
{% extends 'admin/layout.html.twig' %}
|
||||
|
||||
{% block title %}Interne Anmerkungen zu {{ teamer }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="grid lg:grid-cols-3 gap-y-8 lg:gap-y-0 lg:gap-x-8">
|
||||
<div>
|
||||
{{ knp_menu_render(knp_menu_get('admin_teamer')) }}
|
||||
</div>
|
||||
<div class="lg:col-span-2">
|
||||
<h1 class="text-2xl font-bold pb-8">
|
||||
Interne Anmerkungen zu {{ teamer }}
|
||||
</h1>
|
||||
{{ form_start(form) }}
|
||||
<div class="pb-4">
|
||||
{{ form_row(form.remarks) }}
|
||||
</div>
|
||||
<button type="submit" class="btn">
|
||||
speichern
|
||||
</button>
|
||||
{{ form_rest(form) }}
|
||||
{{ form_end(form) }}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -27,7 +27,9 @@
|
||||
<button type="button"
|
||||
class="text-red-500"
|
||||
title="Ausbildung löschen"
|
||||
hx-get="{{ path('app_admin_teamer_skills_training_attendance_delete', { 'uuid': attendance.uuid, 'r': return_url() }) }}"
|
||||
hx-get="{{ path('app_admin_teamer_skills_training_attendance_delete', {
|
||||
'uuid': attendance.uuid, 'r': return_url()
|
||||
}) }}"
|
||||
hx-target="body"
|
||||
hx-swap="beforeend">
|
||||
{{ icon('delete') }}
|
||||
@@ -36,7 +38,11 @@
|
||||
{% else %}
|
||||
<button type="button"
|
||||
title="Teilnahme hinzufügen"
|
||||
hx-get="{{ path('app_admin_teamer_skills_training_attendance_create', { 'training_id': training.id, 'teamer_id': teamer.id, 'r': return_url() }) }}"
|
||||
hx-get="{{ path('app_admin_teamer_skills_training_attendance_create', {
|
||||
'training_id': training.id,
|
||||
'teamer_id': teamer.id,
|
||||
'r': return_url()
|
||||
}) }}"
|
||||
hx-target="body"
|
||||
hx-swap="beforeend">
|
||||
{{ icon('calendar', 'w-4 h-4') }}
|
||||
|
||||
@@ -41,7 +41,10 @@
|
||||
<button type="button"
|
||||
class="flex items-center space-x-1"
|
||||
title="Teamer:inneninfo {{ application.teamer }}"
|
||||
hx-get="{{ path('app_admin_application_info', { 'uuid': application.uuid }) }}"
|
||||
hx-get="{{ path('app_administrative_teamer_info', {
|
||||
'uuid': application.teamer.uuid,
|
||||
'r': return_url()
|
||||
}) }}"
|
||||
hx-target="body"
|
||||
hx-swap="beforeend">
|
||||
<span>{{ application.teamer }}</span>
|
||||
@@ -68,7 +71,9 @@
|
||||
<button type="button"
|
||||
class="text-green-500"
|
||||
title="einteilen"
|
||||
hx-get="{{ path('app_admin_application_dispose', { 'uuid': application.uuid }) }}"
|
||||
hx-get="{{ path('app_admin_application_dispose', {
|
||||
'uuid': application.uuid
|
||||
}) }}"
|
||||
hx-target="body"
|
||||
hx-swap="beforeend">
|
||||
{{ icon('check') }}
|
||||
@@ -78,7 +83,9 @@
|
||||
<button type="button"
|
||||
class="text-primary"
|
||||
title="Bewerbungsstatus bearbeiten"
|
||||
hx-get="{{ path('app_admin_application_status', { 'uuid': application.uuid }) }}"
|
||||
hx-get="{{ path('app_admin_application_status', {
|
||||
'uuid': application.uuid
|
||||
}) }}"
|
||||
hx-target="body"
|
||||
hx-swap="beforeend">
|
||||
{{ icon('edit') }}
|
||||
@@ -88,7 +95,9 @@
|
||||
<button type="button"
|
||||
class="text-red-500"
|
||||
title="Bewerbung löschen"
|
||||
hx-get="{{ path('app_admin_application_delete', { 'uuid': application.uuid }) }}"
|
||||
hx-get="{{ path('app_admin_application_delete', {
|
||||
'uuid': application.uuid
|
||||
}) }}"
|
||||
hx-target="body"
|
||||
hx-swap="beforeend">
|
||||
{{ icon('delete') }}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
{% extends 'htmx_modal.html.twig' %}
|
||||
|
||||
{% block title %}Teamer:inneninfo {{ teamer }}{% endblock %}
|
||||
{% block title %}
|
||||
Teamer:inneninfo <a href="{{ path('app_administrative_teamer_profile', { 'uuid': teamer.uuid, 'r': returnUrl }) }}">{{ teamer }}</a>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="flex items-start">
|
||||
@@ -10,7 +12,7 @@
|
||||
<h2 class="text-lg font-bold">
|
||||
Zustiege
|
||||
</h2>
|
||||
<ul class="pb-8 divide-y divide-gray-200">
|
||||
<ul class="pb-4 divide-y divide-gray-200">
|
||||
{% for pickup in teamer.pickups %}
|
||||
<li class="py-2">
|
||||
{{ pickup|bpn_pickup_label }}
|
||||
@@ -22,7 +24,7 @@
|
||||
{% endfor %}
|
||||
</ul>
|
||||
<h2 class="text-lg font-bold">
|
||||
Letzte Einsätze
|
||||
Einsätze
|
||||
</h2>
|
||||
<ul class="pb-4 divide-y divide-gray-200">
|
||||
{% for disposition in recentDispositions %}
|
||||
@@ -38,6 +40,12 @@
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% if is_granted('ROLE_ADMIN') %}
|
||||
<h2 class="text-lg font-bold">
|
||||
Interne Anmerkungen
|
||||
</h2>
|
||||
{{ teamer.remarksInternal | default('-') | nl2br }}
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="flex flex-col space-y-4">
|
||||
{% if teamer.photo %}
|
||||
|
||||
Reference in New Issue
Block a user