WIP Impelement more stuff
This commit is contained in:
@@ -26,6 +26,9 @@
|
||||
<symbol id="icon-plus" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M12 4.5v15m7.5-7.5h-15" />
|
||||
</symbol>
|
||||
<symbol id="icon-minus" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M19.5 12h-15" />
|
||||
</symbol>
|
||||
<symbol id="icon-search" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M21 21l-5.197-5.197m0 0A7.5 7.5 0 105.196 5.196a7.5 7.5 0 0010.607 10.607z" />
|
||||
</symbol>
|
||||
|
||||
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
@@ -63,6 +63,9 @@ services:
|
||||
- name: knp_menu.menu_builder
|
||||
method: createMainMenu
|
||||
alias: admin_main
|
||||
- name: knp_menu.menu_builder
|
||||
method: createTeamerMenu
|
||||
alias: admin_teamer
|
||||
|
||||
App\Menu\ManagerMenuBuilder:
|
||||
arguments:
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
<?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 Version20231004073716 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('DROP TABLE period');
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
// this down() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('CREATE TABLE period (id INT AUTO_INCREMENT NOT NULL, date_from DATE NOT NULL COMMENT \'(DC2Type:date_immutable)\', date_to DATE NOT NULL COMMENT \'(DC2Type:date_immutable)\', created_by VARCHAR(255) CHARACTER SET utf8mb4 DEFAULT NULL COLLATE `utf8mb4_unicode_ci`, updated_by VARCHAR(255) CHARACTER SET utf8mb4 DEFAULT NULL COLLATE `utf8mb4_unicode_ci`, created_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', updated_at DATETIME DEFAULT NULL COMMENT \'(DC2Type:datetime_immutable)\', PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB COMMENT = \'\' ');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?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 Version20231004074116 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 CHANGE language language VARCHAR(255) DEFAULT NULL');
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
// this down() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('ALTER TABLE teamer CHANGE language language VARCHAR(255) NOT NULL');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?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 Version20231004074136 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 CHANGE size size VARCHAR(2) DEFAULT NULL');
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
// this down() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('ALTER TABLE teamer CHANGE size size VARCHAR(2) NOT NULL');
|
||||
}
|
||||
}
|
||||
@@ -32,8 +32,8 @@ class Countries
|
||||
return $countries;
|
||||
}
|
||||
|
||||
public function get(int $id): ?Country
|
||||
public function get(string $token): ?Country
|
||||
{
|
||||
return $this->getAll()[$id] ?? null;
|
||||
return $this->getAll()[$token] ?? null;
|
||||
}
|
||||
}
|
||||
@@ -176,15 +176,15 @@ class ResponseParser
|
||||
$countries = [];
|
||||
|
||||
foreach ($xml->xpath('laender/land') as $item) {
|
||||
$id = (int) $item->attributes()['id'];
|
||||
$token = (string) $item->attributes()['kuerzel'];
|
||||
$country = new Country();
|
||||
$country
|
||||
->setId($id)
|
||||
->setId((int) $item->attributes()['id'])
|
||||
->setName((string) $item->attributes()['bezeichnung'])
|
||||
->setToken((string) $item->attributes()['kuerzel'])
|
||||
->setNationality((string) $item->attributes()['nationalitaet'])
|
||||
;
|
||||
$countries[$id] = $country;
|
||||
$countries[$token] = $country;
|
||||
}
|
||||
|
||||
$response = new BaseDataResponse();
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller\Admin\Teamer;
|
||||
|
||||
use App\Entity\Teamer;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||
|
||||
class AvailabilityController extends AbstractController
|
||||
{
|
||||
#[Route('/admin/teamer/availability/{uuid}', name: 'app_admin_teamer_availability')]
|
||||
#[IsGranted('ROLE_ADMINISTRATIVE')]
|
||||
public function index(Teamer $teamer): Response
|
||||
{
|
||||
return $this->render('admin/teamer/availability.html.twig', [
|
||||
'teamer' => $teamer,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller\Admin\Teamer;
|
||||
|
||||
use App\Entity\Teamer;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||
|
||||
class CrmSelectionsController extends AbstractController
|
||||
{
|
||||
#[Route('/admin/teamer/crm-selections/{uuid}', name: 'app_admin_teamer_crm_selections')]
|
||||
#[IsGranted('ROLE_ADMINISTRATIVE')]
|
||||
public function index(Teamer $teamer): Response
|
||||
{
|
||||
return $this->render('admin/teamer/crm_selections.html.twig', [
|
||||
'teamer' => $teamer,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller\Admin\Teamer;
|
||||
|
||||
use App\Entity\Teamer;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||
|
||||
class ProfileController extends AbstractController
|
||||
{
|
||||
#[Route('/admin/teamer/profile/{uuid}', name: 'app_admin_teamer_profile')]
|
||||
#[IsGranted('ROLE_ADMINISTRATIVE')]
|
||||
public function index(Teamer $teamer): Response
|
||||
{
|
||||
return $this->render('admin/teamer/profile.html.twig', [
|
||||
'teamer' => $teamer,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller\Admin\Teamer;
|
||||
|
||||
use App\Entity\Teamer;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||
|
||||
class RecentAssignmentsController extends AbstractController
|
||||
{
|
||||
#[Route('/admin/teamer/recent-assignments/{uuid}', name: 'app_admin_teamer_recent_assignments')]
|
||||
#[IsGranted('ROLE_ADMINISTRATIVE')]
|
||||
public function index(Teamer $teamer): Response
|
||||
{
|
||||
return $this->render('admin/teamer/recent_assignments.html.twig', [
|
||||
'teamer' => $teamer,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller\Admin\Teamer;
|
||||
|
||||
use App\Entity\Teamer;
|
||||
use App\Repository\TrainingRepository;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||
|
||||
class SkillsController extends AbstractController
|
||||
{
|
||||
public function __construct(private readonly TrainingRepository $trainingRepository)
|
||||
{}
|
||||
|
||||
#[Route('/admin/teamer/skills/{uuid}', name: 'app_admin_teamer_skills')]
|
||||
#[IsGranted('ROLE_ADMINISTRATIVE')]
|
||||
public function index(Teamer $teamer): Response
|
||||
{
|
||||
$trainings = $this->trainingRepository->getList();
|
||||
|
||||
return $this->render('admin/teamer/skills.html.twig', [
|
||||
'teamer' => $teamer,
|
||||
'trainings' => $trainings,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller\Admin\Teamer\TrainingAttendance;
|
||||
|
||||
use App\Entity\Teamer;
|
||||
use App\Entity\Training;
|
||||
use App\Entity\TrainingAttendance;
|
||||
use App\Form\AbbreviatedDateType;
|
||||
use App\Form\FeeType;
|
||||
use App\Model\AjaxModalResponseDto;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Bridge\Doctrine\Attribute\MapEntity;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||
|
||||
class CreateController extends AbstractController
|
||||
{
|
||||
public function __construct(
|
||||
private readonly EntityManagerInterface $entityManager,
|
||||
private readonly LoggerInterface $logger
|
||||
) {
|
||||
}
|
||||
|
||||
#[Route('/admin/teamer/skills/training-attendance/create/{training_id}/{teamer_id}', name: 'app_admin_teamer_skills_training_attendance_create')]
|
||||
#[IsGranted('ROLE_ADMIN')]
|
||||
public function index(
|
||||
#[MapEntity(mapping: ['training_id' => 'id'])]
|
||||
Training $training,
|
||||
#[MapEntity(mapping: ['teamer_id' => 'id'])]
|
||||
Teamer $teamer,
|
||||
Request $request
|
||||
): JsonResponse {
|
||||
$response = new AjaxModalResponseDto();
|
||||
$action = $this->generateUrl('app_admin_teamer_skills_training_attendance_create', [
|
||||
'training_id' => $training->getId(),
|
||||
'teamer_id' => $teamer->getId(),
|
||||
]);
|
||||
|
||||
$attendance = new TrainingAttendance();
|
||||
$attendance
|
||||
->setTeamer($teamer)
|
||||
->setTraining($training)
|
||||
;
|
||||
|
||||
$form = $this
|
||||
->createFormBuilder($attendance, ['action' => $action, 'ajax_submit' => true])
|
||||
->add('date', AbbreviatedDateType::class, [
|
||||
'label' => 'Datum',
|
||||
])
|
||||
->getForm()
|
||||
;
|
||||
$form->handleRequest($request);
|
||||
|
||||
if ($form->isSubmitted() && $form->isValid()) {
|
||||
$this->entityManager->persist($attendance);
|
||||
$this->entityManager->flush();
|
||||
|
||||
$this->addFlash('success', 'Die Teilnahme wurde hinzugefügt');
|
||||
$this->logger->info('Create training attendance', [
|
||||
'teamer' => $teamer->getUuid(),
|
||||
'training' => $training->getName(),
|
||||
]);
|
||||
|
||||
$redirectUrl = $this->generateUrl('app_admin_teamer_skills', ['uuid' => $teamer->getUuid()]);
|
||||
$response->setCloseAndRedirect($redirectUrl);
|
||||
} else {
|
||||
$content = $this->renderView('admin/teamer/training_attendance/create.html.twig', [
|
||||
'form' => $form
|
||||
]);
|
||||
$response->setContent($content);
|
||||
}
|
||||
|
||||
return $this->json($response);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller\Admin\Teamer\TrainingAttendance;
|
||||
|
||||
use App\Entity\TrainingAttendance;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||
|
||||
class DeleteController extends AbstractController
|
||||
{
|
||||
public function __construct(
|
||||
private readonly EntityManagerInterface $entityManager,
|
||||
private readonly LoggerInterface $logger
|
||||
) {
|
||||
}
|
||||
|
||||
#[Route('/admin/teamer/skills/training-attendance/delete/{uuid}', name: 'app_admin_teamer_skills_training_attendance_delete', methods: ['POST'])]
|
||||
#[IsGranted('ROLE_ADMIN')]
|
||||
public function index(TrainingAttendance $attendance): Response
|
||||
{
|
||||
$teamer = $attendance->getTeamer();
|
||||
|
||||
$this->entityManager->remove($attendance);
|
||||
$this->entityManager->flush();
|
||||
|
||||
$this->addFlash('success', 'Die Teilnahme an der Fortbilundg wurde gelöscht');
|
||||
$this->logger->info('Delete training attendance', [
|
||||
'teamer' => $teamer->getUuid(),
|
||||
]);
|
||||
|
||||
return $this->redirectToRoute('app_admin_teamer_skills', ['uuid' => $teamer->getUuid()]);
|
||||
}
|
||||
}
|
||||
@@ -2,17 +2,31 @@
|
||||
|
||||
namespace App\Controller\Teamer;
|
||||
|
||||
use App\Entity\User;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
||||
|
||||
class IndexController extends AbstractController
|
||||
{
|
||||
public function __construct(private readonly ValidatorInterface $validator)
|
||||
{}
|
||||
|
||||
#[Route('/teamer', name: 'app_teamer_index')]
|
||||
#[IsGranted('ROLE_TEAMER')]
|
||||
public function index(): Response
|
||||
{
|
||||
return $this->render('teamer/index.html.twig');
|
||||
/** @var User $user */
|
||||
$user = $this->getUser();
|
||||
$teamer = $user->getTeamer();
|
||||
|
||||
// Validate teamer data to show missing data right away
|
||||
$errors = $this->validator->validate($teamer, null, ['profile_preflight']);
|
||||
|
||||
return $this->render('teamer/index.html.twig', [
|
||||
'errors' => $errors,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -35,11 +35,11 @@ class SkillsController extends AbstractController
|
||||
|
||||
foreach ($jobProfiles as $profile) {
|
||||
$selectableJobProfiles[$profile->getId()] = true;
|
||||
if (null !== $profile->getRequiredTraining() && false === $teamer->hasTraining($profile->getRequiredTraining())) {
|
||||
if (null !== $profile->getRequiredTraining() && null === $teamer->getTrainingAttendance($profile->getRequiredTraining())) {
|
||||
$selectableJobProfiles[$profile->getId()] = false;
|
||||
}
|
||||
foreach ($profile->getRequiredLicenses() as $license) {
|
||||
if (false === $teamer->hasLicenseOfType($license)) {
|
||||
if (null === $teamer->getLicenseOfType($license)) {
|
||||
$selectableJobProfiles[$profile->getId()] = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use App\Entity\Traits\BlameableEntity;
|
||||
use App\Entity\Traits\TimestampableEntity;
|
||||
use App\Repository\PeriodRepository;
|
||||
use Doctrine\DBAL\Types\Types;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
#[ORM\Entity(repositoryClass: PeriodRepository::class)]
|
||||
class Period implements BlameableEntityInterface, TimestampableEntityInterface
|
||||
{
|
||||
use BlameableEntity;
|
||||
use TimestampableEntity;
|
||||
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue]
|
||||
#[ORM\Column]
|
||||
private ?int $id = null;
|
||||
|
||||
#[ORM\Column(type: Types::DATE_IMMUTABLE)]
|
||||
private ?\DateTimeImmutable $dateFrom = null;
|
||||
|
||||
#[ORM\Column(type: Types::DATE_IMMUTABLE)]
|
||||
private ?\DateTimeImmutable $dateTo = null;
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getDateFrom(): ?\DateTimeImmutable
|
||||
{
|
||||
return $this->dateFrom;
|
||||
}
|
||||
|
||||
public function setDateFrom(\DateTimeImmutable $dateFrom): static
|
||||
{
|
||||
$this->dateFrom = $dateFrom;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDateTo(): ?\DateTimeImmutable
|
||||
{
|
||||
return $this->dateTo;
|
||||
}
|
||||
|
||||
public function setDateTo(\DateTimeImmutable $dateTo): static
|
||||
{
|
||||
$this->dateTo = $dateTo;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
+22
-8
@@ -121,11 +121,11 @@ class Teamer implements TimestampableEntityInterface
|
||||
#[ORM\Column]
|
||||
private array $pickups = [];
|
||||
|
||||
#[ORM\Column(length: 255)]
|
||||
#[ORM\Column(length: 255, nullable: true)]
|
||||
#[Assert\NotBlank(message: 'Bitte gib deine Sprache(n) an', groups: ['profile', 'profile_preflight'])]
|
||||
private ?string $language = null;
|
||||
|
||||
#[ORM\Column(length: 2)]
|
||||
#[ORM\Column(length: 2, nullable: true)]
|
||||
private ?string $size = null;
|
||||
|
||||
public function __construct()
|
||||
@@ -143,6 +143,11 @@ class Teamer implements TimestampableEntityInterface
|
||||
$this->customAvailabilities = new ArrayCollection();
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
return $this->getFullName();
|
||||
}
|
||||
|
||||
public function toPayload(): array
|
||||
{
|
||||
// Transform gender value
|
||||
@@ -224,6 +229,15 @@ class Teamer implements TimestampableEntityInterface
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getFullName(bool $formal = false): string
|
||||
{
|
||||
if (true === $formal) {
|
||||
return sprintf('%s, %s', $this->getLastName(), $this->getFirstName());
|
||||
}
|
||||
|
||||
return sprintf('%s %s', $this->getFirstName(), $this->getLastName());
|
||||
}
|
||||
|
||||
public function getGender(): ?string
|
||||
{
|
||||
return $this->gender;
|
||||
@@ -494,15 +508,15 @@ class Teamer implements TimestampableEntityInterface
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function hasTraining(Training $training): bool
|
||||
public function getTrainingAttendance(Training $training): ?TrainingAttendance
|
||||
{
|
||||
foreach ($this->getTrainingAttendances() as $attendance) {
|
||||
if ($attendance->getTraining() === $training) {
|
||||
return true;
|
||||
return $attendance;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -535,15 +549,15 @@ class Teamer implements TimestampableEntityInterface
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function hasLicenseOfType(string $type): bool
|
||||
public function getLicenseOfType(string $type): ?License
|
||||
{
|
||||
foreach ($this->getLicenses() as $license) {
|
||||
if ($type === $license->getType()) {
|
||||
return true;
|
||||
return $license;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -29,7 +29,7 @@ class TeamerJobProfileType extends AbstractType
|
||||
$requirements[].= $training->getName();
|
||||
}
|
||||
foreach ($choice->getRequiredLicenses() as $license) {
|
||||
$requirements[] = sprintf('Offizielle %slehrer*innenlizenz', ucfirst($license));
|
||||
$requirements[] = sprintf('Offizielle %slehrer*innenlizenz', ucfirst(strtolower($license)));
|
||||
}
|
||||
|
||||
if ($requirements) {
|
||||
|
||||
@@ -6,9 +6,9 @@ use Knp\Menu\ItemInterface;
|
||||
|
||||
class AdminMenuBuilder extends AbstractMenuBuilder
|
||||
{
|
||||
public function createMainMenu(array $options): ItemInterface
|
||||
private function getMainMenuItems(): array
|
||||
{
|
||||
$menuItems = [
|
||||
return [
|
||||
[
|
||||
'route' => 'app_admin_index',
|
||||
'title' => 'Dashboard',
|
||||
@@ -34,7 +34,7 @@ class AdminMenuBuilder extends AbstractMenuBuilder
|
||||
'title' => 'Teamerübersicht',
|
||||
'icon' => 'users',
|
||||
'hideChildren' => true,
|
||||
'children' => [],
|
||||
'children' => $this->getTeamerMenuItems(),
|
||||
],
|
||||
[
|
||||
'route' => false,
|
||||
@@ -86,8 +86,42 @@ class AdminMenuBuilder extends AbstractMenuBuilder
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
$menu = $this->createMenu($menuItems);
|
||||
private function getTeamerMenuItems(): array
|
||||
{
|
||||
return [
|
||||
[
|
||||
'route' => 'app_admin_teamer_profile',
|
||||
'title' => 'Stammdaten & Foto',
|
||||
'routeParameters' => $this->getDefaultRouteParameters('uuid'),
|
||||
],
|
||||
[
|
||||
'route' => 'app_admin_teamer_skills',
|
||||
'title' => 'Jobprofile & Skills',
|
||||
'routeParameters' => $this->getDefaultRouteParameters('uuid'),
|
||||
],
|
||||
[
|
||||
'route' => 'app_admin_teamer_availability',
|
||||
'title' => 'Verfügbarkeit',
|
||||
'routeParameters' => $this->getDefaultRouteParameters('uuid'),
|
||||
],
|
||||
[
|
||||
'route' => 'app_admin_teamer_crm_selections',
|
||||
'title' => 'Selektionsmerkmale',
|
||||
'routeParameters' => $this->getDefaultRouteParameters('uuid'),
|
||||
],
|
||||
[
|
||||
'route' => 'app_admin_teamer_recent_assignments',
|
||||
'title' => 'Vergangene Einsätze',
|
||||
'routeParameters' => $this->getDefaultRouteParameters('uuid'),
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
public function createMainMenu(array $options): ItemInterface
|
||||
{
|
||||
$menu = $this->createMenu($this->getMainMenuItems());
|
||||
|
||||
$this->addDivider($menu);
|
||||
|
||||
@@ -100,4 +134,18 @@ class AdminMenuBuilder extends AbstractMenuBuilder
|
||||
|
||||
return $menu;
|
||||
}
|
||||
|
||||
public function createTeamerMenu(array $options): ItemInterface
|
||||
{
|
||||
$menu = $this->createMenu($this->getTeamerMenuItems());
|
||||
|
||||
$this->addDivider($menu);
|
||||
|
||||
$menu->addChild('zurück zur Übersicht', [
|
||||
'route' => 'app_admin_teamer_index',
|
||||
'icon' => 'back',
|
||||
]);
|
||||
|
||||
return $menu;
|
||||
}
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Repository;
|
||||
|
||||
use App\Entity\Period;
|
||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||
use Doctrine\Persistence\ManagerRegistry;
|
||||
|
||||
/**
|
||||
* @extends ServiceEntityRepository<Period>
|
||||
*
|
||||
* @method Period|null find($id, $lockMode = null, $lockVersion = null)
|
||||
* @method Period|null findOneBy(array $criteria, array $orderBy = null)
|
||||
* @method Period[] findAll()
|
||||
* @method Period[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
|
||||
*/
|
||||
class PeriodRepository extends ServiceEntityRepository
|
||||
{
|
||||
public function __construct(ManagerRegistry $registry)
|
||||
{
|
||||
parent::__construct($registry, Period::class);
|
||||
}
|
||||
|
||||
public function save(Period $entity, bool $flush = false): void
|
||||
{
|
||||
$this->getEntityManager()->persist($entity);
|
||||
|
||||
if ($flush) {
|
||||
$this->getEntityManager()->flush();
|
||||
}
|
||||
}
|
||||
|
||||
public function remove(Period $entity, bool $flush = false): void
|
||||
{
|
||||
$this->getEntityManager()->remove($entity);
|
||||
|
||||
if ($flush) {
|
||||
$this->getEntityManager()->flush();
|
||||
}
|
||||
}
|
||||
|
||||
// /**
|
||||
// * @return Period[] Returns an array of Period objects
|
||||
// */
|
||||
// public function findByExampleField($value): array
|
||||
// {
|
||||
// return $this->createQueryBuilder('p')
|
||||
// ->andWhere('p.exampleField = :val')
|
||||
// ->setParameter('val', $value)
|
||||
// ->orderBy('p.id', 'ASC')
|
||||
// ->setMaxResults(10)
|
||||
// ->getQuery()
|
||||
// ->getResult()
|
||||
// ;
|
||||
// }
|
||||
|
||||
// public function findOneBySomeField($value): ?Period
|
||||
// {
|
||||
// return $this->createQueryBuilder('p')
|
||||
// ->andWhere('p.exampleField = :val')
|
||||
// ->setParameter('val', $value)
|
||||
// ->getQuery()
|
||||
// ->getOneOrNullResult()
|
||||
// ;
|
||||
// }
|
||||
}
|
||||
@@ -15,6 +15,10 @@ class AppExtension extends AbstractExtension
|
||||
new TwigFilter('file_icon', [AppRuntime::class, 'fileIconFilter'], ['is_safe' => ['html']]),
|
||||
new TwigFilter('date_diff', [AppRuntime::class, 'dateDiffForHumans']),
|
||||
new TwigFilter('format_money', [AppRuntime::class, 'formatMoney']),
|
||||
new TwigFilter('license_label', [AppRuntime::class, 'licenseLabel']),
|
||||
new TwigFilter('teamer_status_label', [AppRuntime::class, 'teamerStatusLabel']),
|
||||
new TwigFilter('bpn_country_label', [AppRuntime::class, 'bpnCountryLabel']),
|
||||
new TwigFilter('bpn_pickup_label', [AppRuntime::class, 'bpnPickupLabel']),
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
|
||||
namespace App\Twig;
|
||||
|
||||
use App\BusProNet\DataProvider\Countries;
|
||||
use App\BusProNet\DataProvider\Pickups;
|
||||
use App\BusProNet\Model\Country;
|
||||
use App\Entity\Teamer;
|
||||
use Carbon\Carbon;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
use Twig\Environment;
|
||||
@@ -13,10 +17,48 @@ class AppRuntime implements RuntimeExtensionInterface
|
||||
public function __construct(
|
||||
private readonly RequestStack $requestStack,
|
||||
private readonly IntlExtension $intlExtension,
|
||||
private readonly Countries $countries,
|
||||
private readonly Pickups $pickups,
|
||||
private readonly string $environment
|
||||
) {
|
||||
}
|
||||
|
||||
public function teamerStatusLabel(string $status): string
|
||||
{
|
||||
if (Teamer::STATUS_NEW === $status) {
|
||||
return 'Neuteamer';
|
||||
}
|
||||
|
||||
return 'Bestandsteamer';
|
||||
}
|
||||
|
||||
public function licenseLabel(string $type): string
|
||||
{
|
||||
return sprintf('Offizielle %slehrer*innenlizenz', ucfirst(strtolower($type)));
|
||||
}
|
||||
|
||||
public function bpnCountryLabel(string $token, string $property = 'name'): string
|
||||
{
|
||||
$country = $this->countries->get($token);
|
||||
|
||||
if (null === $country) {
|
||||
return 'unbekannt';
|
||||
}
|
||||
|
||||
return 'nationality' === $property ? $country->getNationality() : $country->getName();
|
||||
}
|
||||
|
||||
public function bpnPickupLabel(int $id): string
|
||||
{
|
||||
$pickup = $this->pickups->get($id);
|
||||
|
||||
if (null === $pickup) {
|
||||
return 'unbekannt';
|
||||
}
|
||||
|
||||
return $pickup->getCity();
|
||||
}
|
||||
|
||||
public function fileIconFilter(Environment $environment, string $mimeType, ?string $classes = 'w-4 h-4'): string
|
||||
{
|
||||
$icon = match ($mimeType) {
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
{% block list %}
|
||||
{% if item.hasChildren and options.depth is not same as(0) and item.displayChildren %}
|
||||
{% if item.level == 0 %}
|
||||
<div class="min-h-full flex grow flex-col gap-y-5 overflow-y-scroll lg:border-r border-gray-200 bg-white md:pr-6">
|
||||
<nav class="flex flex-1 flex-col">
|
||||
<ul role="list" class="space-y-1">
|
||||
{{ block('children') }}
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
<div class="min-h-full flex grow flex-col gap-y-5 overflow-y-scroll lg:border-r border-gray-200 bg-white md:pr-6">
|
||||
<nav class="flex flex-1 flex-col">
|
||||
<ul role="list" class="space-y-1">
|
||||
{{ block('children') }}
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
{% else %}
|
||||
<ul class="{{ html_classes('mt-1 px-2', { 'hidden': not matcher.isCurrent(item) }) }}" {{ stimulus_target('sidebar-menu', 'submenu') }}>
|
||||
{{ block('children') }}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
{% extends 'admin/layout.html.twig' %}
|
||||
|
||||
{% block title %}Verfügbarkeit {{ 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">
|
||||
Verfügbarkeit {{ teamer }}
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,16 @@
|
||||
{% extends 'admin/layout.html.twig' %}
|
||||
|
||||
{% block title %}Selektionsmerkmale {{ 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">
|
||||
Selektionsmerkmale {{ teamer }}
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -43,7 +43,7 @@
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
{{ teamer.status }}
|
||||
{{ teamer.status|teamer_status_label }}
|
||||
</td>
|
||||
<td>
|
||||
{{ teamer.communication.email }}
|
||||
@@ -57,6 +57,9 @@
|
||||
</td>
|
||||
<td>
|
||||
<div class="flex items-center space-x-1 justify-end">
|
||||
<a href="{{ path('app_admin_teamer_profile', { 'uuid': teamer.uuid }) }}" title="Teamerprofil {{ teamer }}">
|
||||
{{ icon('user') }}
|
||||
</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -0,0 +1,230 @@
|
||||
{% extends 'admin/layout.html.twig' %}
|
||||
|
||||
{% block title %}Stammdaten und Foto {{ 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">
|
||||
Stammdaten und Foto {{ teamer }}
|
||||
</h1>
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
|
||||
<div>
|
||||
<h2 class="text-lg font-bold pb-2">
|
||||
Persönliche Daten
|
||||
</h2>
|
||||
<div class="flex flex-col space-y-3">
|
||||
<div>
|
||||
<div class="font-bold">
|
||||
Gender:
|
||||
</div>
|
||||
<div>
|
||||
{{ teamer.gender }}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="font-bold">
|
||||
Titel:
|
||||
</div>
|
||||
<div>
|
||||
{{ teamer.academicTitle|default('-') }}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="font-bold">
|
||||
Vorname:
|
||||
</div>
|
||||
<div>
|
||||
{{ teamer.firstName }}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="font-bold">
|
||||
Nachname:
|
||||
</div>
|
||||
<div>
|
||||
{{ teamer.lastName }}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="font-bold">
|
||||
Geburtsdatum:
|
||||
</div>
|
||||
<div>
|
||||
{{ teamer.dateOfBirth|date('d.m.Y') }}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="font-bold">
|
||||
Staatsangehörigkeit:
|
||||
</div>
|
||||
<div>
|
||||
{{ teamer.nationality|bpn_country_label('nationality') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
{% if teamer.photo %}
|
||||
<div class="pb-8">
|
||||
<img src="{{ asset(teamer.photo.filename | imagine_filter('profile')) }}"
|
||||
class="w-48 h-auto border-2 border-primary"
|
||||
alt="{{ teamer.firstName }}">
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h2 class="text-lg font-bold pb-2">
|
||||
Adressdaten
|
||||
</h2>
|
||||
<div class="flex flex-col space-y-3">
|
||||
<div>
|
||||
<div class="font-bold">
|
||||
Straße, Hausnummer:
|
||||
</div>
|
||||
<div>
|
||||
{{ teamer.address.street }}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="font-bold">
|
||||
PLZ:
|
||||
</div>
|
||||
<div>
|
||||
{{ teamer.address.postCode }}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="font-bold">
|
||||
Ort:
|
||||
</div>
|
||||
<div>
|
||||
{{ teamer.address.city }}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="font-bold">
|
||||
Land:
|
||||
</div>
|
||||
<div>
|
||||
{{ teamer.address.country|bpn_country_label }}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="font-bold">
|
||||
E-Mail:
|
||||
</div>
|
||||
<div>
|
||||
{{ teamer.communication.email|default('-') }}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="font-bold">
|
||||
Mobilnummer:
|
||||
</div>
|
||||
<div>
|
||||
{{ teamer.communication.mobile|default('-') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h2 class="text-lg font-bold pb-2">
|
||||
Buszustiege
|
||||
</h2>
|
||||
<ul class="list-disc pl-4">
|
||||
{% for pickup in teamer.pickups %}
|
||||
<li>
|
||||
{{ pickup|bpn_pickup_label }}
|
||||
</li>
|
||||
{% else %}
|
||||
<li>
|
||||
<span class="text-sm">Keine Daten</span>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h2 class="text-lg font-bold pb-2">
|
||||
Honorardaten
|
||||
</h2>
|
||||
<div class="flex flex-col space-y-3">
|
||||
<div>
|
||||
<div class="font-bold">
|
||||
Steuer-ID:
|
||||
</div>
|
||||
<div>
|
||||
{{ teamer.taxId|default('-') }}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="font-bold">
|
||||
IBAN:
|
||||
</div>
|
||||
<div>
|
||||
{{ teamer.bankAccount.iban|default('-') }}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="font-bold">
|
||||
BIC:
|
||||
</div>
|
||||
<div>
|
||||
{{ teamer.bankAccount.bic|default('-') }}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="font-bold">
|
||||
Bank/Kreditinstitut:
|
||||
</div>
|
||||
<div>
|
||||
{{ teamer.bankAccount.bank|default('-') }}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="font-bold">
|
||||
Krankenversicherung:
|
||||
</div>
|
||||
<div>
|
||||
{{ teamer.healthInsuranceCompany|default('-') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h2 class="text-lg font-bold pb-2">
|
||||
Sonstiges
|
||||
</h2>
|
||||
<div class="flex flex-col space-y-3">
|
||||
<div>
|
||||
<div class="font-bold">
|
||||
Sprache(n):
|
||||
</div>
|
||||
<div>
|
||||
{{ teamer.language|default('-') }}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="font-bold">
|
||||
Klamottengröße:
|
||||
</div>
|
||||
<div>
|
||||
{{ teamer.size|default('-') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,16 @@
|
||||
{% extends 'admin/layout.html.twig' %}
|
||||
|
||||
{% block title %}Vergangene Einsätze & Feeback {{ 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">
|
||||
Vergangene Einsätze & Feeback {{ teamer }}
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,118 @@
|
||||
{% extends 'admin/layout.html.twig' %}
|
||||
|
||||
{% block title %}Jobprofile & Skills {{ 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">
|
||||
Jobprofile & Skills {{ teamer }}
|
||||
</h1>
|
||||
|
||||
<h2 class="text-xl font-bold pb-2">
|
||||
Ausbildung
|
||||
</h2>
|
||||
<ul class="pb-2 divide-y divide-gray-200">
|
||||
{% for training in trainings %}
|
||||
<li class="py-2">
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="flex-1">{{ training.name }}</span>
|
||||
{% set attendance = teamer.trainingAttendance(training) %}
|
||||
{% if attendance %}
|
||||
<div class="flex items-center space-x-2">
|
||||
<span>{{ attendance.date|date('m/Y') }}</span>
|
||||
<button type="button"
|
||||
class="text-red-500"
|
||||
title="Ausbildung löschen"
|
||||
{{ stimulus_controller('modal-button', [], [], {'confirmation-modal': '#confirmation-modal'}) }}
|
||||
{{ stimulus_action('modal-button', 'confirmation', null, {
|
||||
'title': 'Bist du sicher?',
|
||||
'content': 'Möchtest du die Teilnahme an dieser Schulung wirklich löschen?',
|
||||
'target-url': path('app_admin_teamer_skills_training_attendance_delete', { 'uuid': attendance.uuid })
|
||||
}) }}>
|
||||
{{ icon('delete') }}
|
||||
</button>
|
||||
</div>
|
||||
{% else %}
|
||||
<button type="button"
|
||||
{{ stimulus_controller('modal-button', [], [], {'ajax-modal': '#ajax-modal'}) }}
|
||||
{{ stimulus_action('modal-button', 'ajax', null, {
|
||||
'title': 'Teilnahme hinzufügen',
|
||||
'url': path('app_admin_teamer_skills_training_attendance_create', { 'training_id': training.id, 'teamer_id': teamer.id })
|
||||
}) }}>
|
||||
{{ icon('calendar', 'w-4 h-4') }}
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
<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 = 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 }) }}"
|
||||
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 class="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<h2 class="text-lg font-bold pb-2">
|
||||
Mögliche Jobprofile
|
||||
</h2>
|
||||
<ul class="list-disc pl-4">
|
||||
{% for profile in teamer.jobProfiles %}
|
||||
<li>
|
||||
{{ profile.name }}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<h2 class="text-lg font-bold pb-2">
|
||||
Sonstiges
|
||||
</h2>
|
||||
<div class="flex flex-col space-y-3">
|
||||
<div>
|
||||
<div class="font-bold">
|
||||
Status:
|
||||
</div>
|
||||
<div>
|
||||
{{ teamer.status|teamer_status_label }}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="font-bold">
|
||||
Wünsche:
|
||||
</div>
|
||||
<div>
|
||||
{{ teamer.remarks|nl2br|default('-') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,9 @@
|
||||
{{ form_start(form) }}
|
||||
<div class="flex flex-col space-y-4 pb-8">
|
||||
{{ form_row(form.date) }}
|
||||
</div>
|
||||
<button type="submit" class="btn">
|
||||
Speichern
|
||||
</button>
|
||||
{{ form_rest(form) }}
|
||||
{{ form_end(form) }}
|
||||
@@ -14,7 +14,7 @@
|
||||
{{ encore_entry_script_tags('app') }}
|
||||
{% endblock %}
|
||||
</head>
|
||||
<body class="bg-white text-gray-700 font-sans antialiased">
|
||||
<body class="bg-white text-gray-700 font-sans antialiased text-sm">
|
||||
{% block body %}{% endblock %}
|
||||
{% include '_partials/_flashes.html.twig' %}
|
||||
</body>
|
||||
|
||||
@@ -3,4 +3,15 @@
|
||||
{% block title %}Mein Dashboard{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% if errors|length %}
|
||||
<div class="border border-red-500 rounded-md p-4 text-red-500 mb-8">
|
||||
<ul>
|
||||
{% for error in errors %}
|
||||
<li>
|
||||
{{ error.message }}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
@@ -20,9 +20,6 @@
|
||||
<div {{ stimulus_controller('tabs', {}, { 'buttonActive': 'bg-gray-50' }) }}>
|
||||
<div class="grid lg:grid-cols-3 gap-y-8 lg:gap-y-0 lg:gap-x-16">
|
||||
<div>
|
||||
<h1 class="text-2xl font-bold pb-8">
|
||||
Mein Profil
|
||||
</h1>
|
||||
<ul role="list" class="space-y-1">
|
||||
<li>
|
||||
<button type="button" class="hover:bg-gray-50 block rounded-md py-2 pr-2 pl-10 w-full text-left text-sm leading-6 font-semibold text-gray-700" {{ stimulus_target('tabs', 'button') }} {{ stimulus_action('tabs', 'select', null, { 'tab': 0 }) }}>
|
||||
@@ -52,6 +49,9 @@
|
||||
</ul>
|
||||
</div>
|
||||
<div class="lg:col-span-2">
|
||||
<h1 class="text-2xl font-bold pb-8">
|
||||
Mein Profil
|
||||
</h1>
|
||||
{% if not form.vars.valid %}
|
||||
<div class="border border-red-500 rounded-md p-4 text-red-500 mb-8">
|
||||
{% include '_partials/_form_errors.html.twig' with { 'form': form } %}
|
||||
@@ -59,7 +59,7 @@
|
||||
{% include '_partials/_form_errors.html.twig' with { 'form': form.communication } %}
|
||||
{% include '_partials/_form_errors.html.twig' with { 'form': form.bankAccount } %}
|
||||
</div>
|
||||
{% elseif errors|length > 0 %}
|
||||
{% elseif errors|length %}
|
||||
<div class="border border-red-500 rounded-md p-4 text-red-500 mb-8">
|
||||
<ul>
|
||||
{% for error in errors %}
|
||||
@@ -121,27 +121,26 @@
|
||||
<h2 class="text-xl font-bold pb-2">
|
||||
Sonstiges
|
||||
</h2>
|
||||
<div class="flex flex-col space-y-4 pb-8">
|
||||
<div class="flex flex-col space-y-4">
|
||||
{{ form_row(form.taxId) }}
|
||||
{{ form_row(form.healthInsuranceCompany) }}
|
||||
{{ form_row(form.language) }}
|
||||
{{ form_row(form.size) }}
|
||||
</div>
|
||||
|
||||
<div {{ stimulus_controller('form-collection', { 'prototype': _self.collectionRow(form.pickups.vars.prototype)|json_encode }) }}>
|
||||
<h4 class="font-bold">
|
||||
Buszustiege
|
||||
</h4>
|
||||
<div {{ stimulus_target('form-collection', 'fields')}} class="flex flex-col space-y-4 mb-4">
|
||||
{% do form.pickups.setRendered %}
|
||||
{%- for pickup in form.pickups -%}{{- _self.collectionRow(pickup) -}}{%- endfor -%}
|
||||
</div>
|
||||
<div class="flex justify-end">
|
||||
<button type="button"
|
||||
{{ stimulus_action('form-collection', 'addItem') }}
|
||||
title="Zustieg hinzufügen">
|
||||
{{ icon('plus', 'w-4 h-4 pointer-events-none') }}
|
||||
</button>
|
||||
<div {{ stimulus_controller('form-collection', { 'prototype': _self.collectionRow(form.pickups.vars.prototype)|json_encode }) }}>
|
||||
<h4 class="font-bold pb-2">
|
||||
Buszustiege
|
||||
</h4>
|
||||
<div {{ stimulus_target('form-collection', 'fields')}} class="flex flex-col space-y-4 mb-4">
|
||||
{% do form.pickups.setRendered %}
|
||||
{%- for pickup in form.pickups -%}{{- _self.collectionRow(pickup) -}}{%- endfor -%}
|
||||
</div>
|
||||
<div class="flex justify-end">
|
||||
<button type="button"
|
||||
{{ stimulus_action('form-collection', 'addItem') }}
|
||||
title="Zustieg hinzufügen">
|
||||
{{ icon('plus', 'w-4 h-4 pointer-events-none') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
{% block title %}Meine Jobprofile & Skills{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1 class="text-2xl font-bold pb-4">
|
||||
Meine Jobprofile & Skills
|
||||
</h1>
|
||||
<h2 class="text-xl font-bold pb-2">
|
||||
Ausbildung
|
||||
</h2>
|
||||
@@ -26,16 +29,19 @@
|
||||
{% for license in teamer.licenses %}
|
||||
<li>
|
||||
<div class="flex items-center space-x-4">
|
||||
{{ icon(license.type, 'w-5 h-5') }}
|
||||
<span>{{ license.type|license_label }}</span>
|
||||
<span>{{ license.date|date('m/Y') }}</span>
|
||||
{% if is_granted('DOWNLOAD', license.certificate) %}
|
||||
<a href="{{ path('app_common_download', { 'uuid': license.certificate.uuid }) }}" target="_blank">
|
||||
<a href="{{ path('app_common_download', { 'uuid': license.certificate.uuid }) }}"
|
||||
target="_blank"
|
||||
title="Download Nachweis">
|
||||
{{ icon('download', 'w-4 h-4') }}
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if is_granted('DELETE', license) %}
|
||||
<button type="button"
|
||||
class="text-red-500"
|
||||
title="Lizenz löschen"
|
||||
{{ stimulus_controller('modal-button', [], [], {'confirmation-modal': '#confirmation-modal'}) }}
|
||||
{{ stimulus_action('modal-button', 'confirmation', null, {
|
||||
'title': 'Bist du sicher?',
|
||||
@@ -48,9 +54,9 @@
|
||||
</div>
|
||||
</li>
|
||||
{% else %}
|
||||
<div class="text-sm">
|
||||
<li class="text-sm">
|
||||
Du hast bisher keine Lizenzen hinterlegt
|
||||
</div>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
<button type="button"
|
||||
|
||||
Reference in New Issue
Block a user