From ac498f90402957c54e9167a099dfb29569987b85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Fromme?= Date: Thu, 27 Feb 2025 19:21:12 +0100 Subject: [PATCH] wip --- assets/controllers/tooltip_controller.js | 6 +- assets/styles/components/typography.css | 2 +- .../DataProcessor/BookingDataProcessor.php | 9 +- src/BusProNet/Model/Service.php | 6 +- src/Form/Model/ParticipantData.php | 9 +- src/Form/ParticipantType.php | 50 +++- src/Form/PersonalDataType.php | 27 +- src/Twig/AppExtension.php | 3 + src/Twig/AppRuntime.php | 39 ++- tailwind.config.js | 11 +- .../_partials/_loading_indicator.html.twig | 2 +- templates/booking/edit.html.twig | 248 ++++++++++-------- templates/booking/index.html.twig | 18 +- templates/forms.html.twig | 18 +- templates/personal_data/index.html.twig | 48 +++- 15 files changed, 311 insertions(+), 185 deletions(-) diff --git a/assets/controllers/tooltip_controller.js b/assets/controllers/tooltip_controller.js index a95ecd7..b7d9139 100644 --- a/assets/controllers/tooltip_controller.js +++ b/assets/controllers/tooltip_controller.js @@ -31,6 +31,10 @@ export default class extends Controller { } else { element = this.element } - tippy(element, options) + this.tooltip = tippy(element, options) + } + + disconnect() { + this.tooltip.destroy() } } diff --git a/assets/styles/components/typography.css b/assets/styles/components/typography.css index 422e22a..5d9a6c7 100644 --- a/assets/styles/components/typography.css +++ b/assets/styles/components/typography.css @@ -15,7 +15,7 @@ h3, h4, .headline--4 { - @apply block md:text-lg font-bold; + @apply block font-semibold; } .headline--underlined:after { diff --git a/src/BusProNet/DataProcessor/BookingDataProcessor.php b/src/BusProNet/DataProcessor/BookingDataProcessor.php index ef2c958..4652edf 100644 --- a/src/BusProNet/DataProcessor/BookingDataProcessor.php +++ b/src/BusProNet/DataProcessor/BookingDataProcessor.php @@ -78,6 +78,13 @@ class BookingDataProcessor $bookingData->participants[$participant->index]->communication->mobile = $participant->mobile; } + // Update applicant's data with personal data of first participant + if (false !== $firstParticipant = reset($bookingData->participants)) { + $bookingData->applicant->height = $firstParticipant->height; + $bookingData->applicant->weight = $firstParticipant->weight; + $bookingData->applicant->shoeSize = $firstParticipant->shoeSize; + } + $payload = [ 'idbuchung' => $bookingData->id, 'status' => $bookingData->status, @@ -153,4 +160,4 @@ class BookingDataProcessor return $payload; } -} \ No newline at end of file +} diff --git a/src/BusProNet/Model/Service.php b/src/BusProNet/Model/Service.php index eddc638..175be4b 100644 --- a/src/BusProNet/Model/Service.php +++ b/src/BusProNet/Model/Service.php @@ -20,6 +20,10 @@ class Service public const TOKEN_BOARD = 'VPF'; public const TOKEN_RENTALS = ['VER', 'VE2', 'VE3', 'VE4', 'VE5', 'VE6', 'VE7', 'VE8']; + public const STATUS_AVAILABLE = 'Frei'; + public const STATUS_BLOCKED = 'Buchungsstop'; + public const STATUS_ON_REQUEST = 'Anfrage'; + #[Groups(['api:single', 'api:list'])] public ?int $id = null; @@ -69,4 +73,4 @@ class Service #[Groups(['api:single', 'api:list'])] public ?string $direction = null; -} \ No newline at end of file +} diff --git a/src/Form/Model/ParticipantData.php b/src/Form/Model/ParticipantData.php index 0676ef4..9ed5a8d 100644 --- a/src/Form/Model/ParticipantData.php +++ b/src/Form/Model/ParticipantData.php @@ -24,20 +24,13 @@ class ParticipantData public ?string $title = null; public ?string $gender = null; public ?string $nationality = null; - - #[Assert\Range(notInRangeMessage: 'Bitte einen Wert im Bereich {{ min }}-{{ max }}cm angeben', min: 150, max: 210)] public ?string $height = null; - - #[Assert\Range(notInRangeMessage: 'Bitte einen Wert im Bereich {{ min }}-{{ max }} angeben', min: 37, max: 49)] public ?string $shoeSize = null; - - #[Assert\Range(notInRangeMessage: 'Bitte einen Wert im Bereich {{ min }}-{{ max }}kg angeben', min: 40, max: 130)] public ?string $weight = null; #[Assert\NotNull(message: 'Bitte angeben')] public ?\DateTimeImmutable $dateOfBirth = null; - #[Assert\NotBlank(message: 'Bitte angeben')] #[Assert\Email(message: 'Bitte eine gültige E-Mail Adresse angeben', mode: 'strict')] public ?string $email = null; @@ -112,4 +105,4 @@ class ParticipantData return $instance; } -} \ No newline at end of file +} diff --git a/src/Form/ParticipantType.php b/src/Form/ParticipantType.php index 84b77f9..84cee78 100644 --- a/src/Form/ParticipantType.php +++ b/src/Form/ParticipantType.php @@ -10,7 +10,6 @@ use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\BirthdayType; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\Form\Extension\Core\Type\EmailType; -use Symfony\Component\Form\Extension\Core\Type\IntegerType; use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormEvent; @@ -77,6 +76,7 @@ class ParticipantType extends AbstractType ]) ->add('email', EmailType::class, [ 'label' => 'E-Mail', + 'required' => false, 'attr' => [ 'readonly' => false === $personalDataMutable, ] @@ -87,17 +87,43 @@ class ParticipantType extends AbstractType 'readonly' => false === $personalDataMutable, ] ]) - ->add('height', IntegerType::class, [ - 'label' => 'Körpergröße [cm]', + ->add('height', ChoiceType::class, [ + 'label' => 'Körpergröße', 'required' => false, + 'expanded' => false, + 'multiple' => false, + 'placeholder' => 'Keine Angabe', + 'choices' => [ + 'bis 148cm' => '-148', + '149 - 157cm' => '149-157', + '158 - 166cm' => '158-166', + '167 - 178cm' => '167-178', + '179 - 194cm' => '179-197', + '195cm oder mehr' => '195cm+', + ], ]) - ->add('shoeSize', IntegerType::class, [ + ->add('shoeSize', ChoiceType::class, [ 'label' => 'Schuhgröße', 'required' => false, + 'expanded' => false, + 'multiple' => false, + 'placeholder' => 'Keine Angabe', + 'choices' => array_combine(range(36, 48), range(36, 48)), ]) - ->add('weight', IntegerType::class, [ - 'label' => 'Gewicht [kg]', + ->add('weight', ChoiceType::class, [ + 'label' => 'Gewicht', 'required' => false, + 'expanded' => false, + 'multiple' => false, + 'placeholder' => 'Keine Angabe', + 'choices' => [ + '42 - 48kg' => '42-48', + '49 - 57kg' => '49-57', + '58 - 66kg' => '58-66', + '67 - 78kg' => '67-78', + '79 - 94kg' => '79-94', + '95kg oder mehr' => '95k+', + ], ]) ; @@ -130,11 +156,21 @@ class ParticipantType extends AbstractType if (true === $service->mandatory) { $attributes['checked'] = true; $attributes['disabled'] = true; + $attributes['class'] = 'text-pink'; + $attributes['tooltip'] = 'Diese Leistung ist nicht abwählbar'; } // disable selection of services only available in booking data if (Service::SOURCE_BOOKING === $service->source) { $attributes['disabled'] = true; + $attributes['class'] = 'text-pink'; + } + + // disable selection of services that are unavailable according to their status + if (Service::STATUS_BLOCKED === $service->status) { + $attributes['checked'] = false; + $attributes['disabled'] = true; + $attributes['tooltip'] = 'Diese Leistung ist derzeit leider nicht buchbar'; } return $attributes; @@ -297,4 +333,4 @@ class ParticipantType extends AbstractType 'anti_xss' => true, ]); } -} \ No newline at end of file +} diff --git a/src/Form/PersonalDataType.php b/src/Form/PersonalDataType.php index 451daea..495b0ed 100644 --- a/src/Form/PersonalDataType.php +++ b/src/Form/PersonalDataType.php @@ -16,31 +16,6 @@ class PersonalDataType extends AbstractType public function buildForm(FormBuilderInterface $builder, array $options): void { $builder - ->add('gender', ChoiceType::class, [ - 'label' => 'Gender', - 'choices' => [ - 'männlich' => 'M', - 'weiblich' => 'W', - 'divers' => 'D', - ], - ]) - ->add('firstName', TextType::class, [ - 'label' => 'Name', - ]) - ->add('name', TextType::class, [ - 'label' => 'Nachname', - ]) - ->add('dateOfBirth', BirthdayType::class, [ - 'label' => 'Geburtsdatum', - 'html5' => true, - 'widget' => 'single_text', - 'input' => 'datetime_immutable', - ]) - ->add('nationality', CountryType::class, [ - 'label' => 'Nationalität', - 'property' => 'nationality', - 'preferred_choices' => ['D', 'A', 'CH'], - ]) ->add('street', TextType::class, [ 'label' => 'Straße', 'property_path' => 'address.street', @@ -78,4 +53,4 @@ class PersonalDataType extends AbstractType 'anti_xss' => true, ]); } -} \ No newline at end of file +} diff --git a/src/Twig/AppExtension.php b/src/Twig/AppExtension.php index 5c3bf83..8ab5f84 100644 --- a/src/Twig/AppExtension.php +++ b/src/Twig/AppExtension.php @@ -14,7 +14,10 @@ class AppExtension extends AbstractExtension new TwigFilter('file_size', [AppRuntime::class, 'formatBytes']), new TwigFilter('file_icon', [AppRuntime::class, 'fileIconFilter'], ['is_safe' => ['html']]), new TwigFilter('format_money', [AppRuntime::class, 'formatMoney']), + new TwigFilter('map_gender', [AppRuntime::class, 'mapGender']), new TwigFilter('map_status', [AppRuntime::class, 'mapStatus']), + new TwigFilter('map_country', [AppRuntime::class, 'mapCountry']), + new TwigFilter('map_nationality', [AppRuntime::class, 'mapNationality']), ]; } diff --git a/src/Twig/AppRuntime.php b/src/Twig/AppRuntime.php index ef3d407..73b4f61 100644 --- a/src/Twig/AppRuntime.php +++ b/src/Twig/AppRuntime.php @@ -2,14 +2,17 @@ namespace App\Twig; +use App\BusProNet\DataProvider\CountryDataProvider; use Twig\Environment; use Twig\Extension\RuntimeExtensionInterface; use Twig\Extra\Intl\IntlExtension; class AppRuntime implements RuntimeExtensionInterface { - public function __construct(private readonly IntlExtension $intlExtension) - { + public function __construct( + private readonly IntlExtension $intlExtension, + private readonly CountryDataProvider $countryDataProvider, + ) { } public function fileIconFilter(Environment $environment, string $mimeType, ?string $classes = 'w-4 h-4'): string @@ -50,6 +53,8 @@ class AppRuntime implements RuntimeExtensionInterface public function mapStatus(string $status): string { + $status = strtoupper($status); + return match ($status) { 'F', 'F/S' => 'Festbuchung', 'S' => 'Stornierung', @@ -58,4 +63,34 @@ class AppRuntime implements RuntimeExtensionInterface default => '', }; } + + public function mapGender(string $gender): string + { + $gender = strtoupper($gender); + + return match ($gender) { + 'M' => 'männlich', + 'F' => 'weiblich', + 'D' => 'divers', + default => '', + }; + } + + public function mapCountry(?string $country): ?string + { + if (null === $country) { + return null; + } + + return $this->countryDataProvider->get($country)?->name; + } + + public function mapNationality(?string $nationality): ?string + { + if (null === $nationality) { + return null; + } + + return $this->countryDataProvider->get($nationality)?->nationality; + } } diff --git a/tailwind.config.js b/tailwind.config.js index 6cd4c85..dbd893f 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -2,8 +2,7 @@ module.exports = { content: [ './templates/**/*.twig', - './src/Twig/*.php', - './src/Menu/*.php', + './src/**/*.php', ], safelist: ['rotate-90'], theme: { @@ -22,8 +21,12 @@ module.exports = { 'primary-light': '#0080ff', 'primary-medium': '#165883', 'primary-dark': '#18527b', - pink: '#fa1a8c', - } + pink: '#960167', + }, + backgroundImage: { + 'badge-gradient': 'linear-gradient(120deg, rgba(150,1,103,1) 0%, rgba(158,3,106,1) 40%, rgba(250,26,140,1) 100%)', + 'brand-gradient': 'linear-gradient(to top right, #009fff, #165883, #18527b)', + }, }, }, plugins: [ diff --git a/templates/_partials/_loading_indicator.html.twig b/templates/_partials/_loading_indicator.html.twig index 08857bb..058a998 100644 --- a/templates/_partials/_loading_indicator.html.twig +++ b/templates/_partials/_loading_indicator.html.twig @@ -1,4 +1,4 @@ diff --git a/templates/booking/edit.html.twig b/templates/booking/edit.html.twig index 60cde46..f7cf360 100644 --- a/templates/booking/edit.html.twig +++ b/templates/booking/edit.html.twig @@ -7,7 +7,7 @@ {% set messages = form.vars.errors|map(error => error.message) %} {% include '_partials/_alert.html.twig' with { 'level': 'error', 'title': 'Die Buchung konnte nicht aktualisiert werden', 'messages': messages } %} {% endif %} -
+
@@ -35,6 +35,18 @@ {{ bookingData.bookingDate|date('d.m.Y') }}
+
+

+ Vorgangsnummer +

+ {{ bookingData.bookingNumber }} +
+
+

+ Rechnungsnummer +

+ {{ bookingData.invoiceNumber }} +

Anmelder:in @@ -57,15 +69,19 @@

Inklusivleistungen

-
    - {% for selectionGroup in travelData.includedServices %} - {% for service in selectionGroup.selections %} -
  • - {{ service.label }} -
  • + {% if travelData.includedServices | length == 0 %} + - + {% else %} +
      + {% for selectionGroup in travelData.includedServices %} + {% for service in selectionGroup.selections %} +
    • + {{ service.label }} +
    • + {% endfor %} {% endfor %} - {% endfor %} -
    +
+ {% endif %}

@@ -93,122 +109,128 @@

{% for child in form.participants %} - {% set participant = child.vars.data %} -
-
-
Teilnehmer:in {{ participant.index }}: {{ participant.firstName }} {{ participant.lastName }}
- - - -
-
+
{% endfor %}
@@ -224,4 +246,4 @@ {{ form_rest(form) }} {{ form_end(form) }} -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/templates/booking/index.html.twig b/templates/booking/index.html.twig index af0279e..fed7c97 100644 --- a/templates/booking/index.html.twig +++ b/templates/booking/index.html.twig @@ -12,7 +12,7 @@ Reise - Buchungsdatum + Reisedatum Buchungsnummer @@ -35,15 +35,15 @@ - {% if booking.travelData %} - {{ booking.travel }}, {{ booking.travelData.dateFrom | date('d.m.Y') }} - {{ booking.travelData.dateTo | date('d.m.Y') }} - {% else %} - {{ booking.travel }}, {{ booking.travelDate | date('d.m.Y') }} - {% endif %} + {{ booking.travel }} - {{ booking.bookingDate | date('d.m.Y') }} + {% if booking.travelData %} + {{ booking.travelData.dateFrom | date('d.m.Y') }} - {{ booking.travelData.dateTo | date('d.m.Y') }} + {% else %} + {{ booking.travelDate | date('d.m.Y') }} + {% endif %} @@ -77,7 +77,7 @@ {% if booking.hasDocuments %} Reisedokumente @@ -88,4 +88,4 @@ {% endfor %} -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/templates/forms.html.twig b/templates/forms.html.twig index 60a6288..0f63102 100644 --- a/templates/forms.html.twig +++ b/templates/forms.html.twig @@ -72,7 +72,14 @@ {%- if attr.disabled is defined and attr.disabled == true -%} {%- set attr = attr|merge({'class': attr.class|default('') ~ ' cursor-not-allowed' }) -%} {%- endif -%} - + {%- set tooltip = null -%} + {%- if attr.tooltip is defined -%} + {%- set tooltip = attr.tooltip -%} + {%- set attr = attr|filter((v, k) => k != 'tooltip') -%} + {%- endif -%} + + + {%- endblock checkbox_widget -%} {%- block radio_widget -%} @@ -83,7 +90,14 @@ {%- if attr.disabled is defined and attr.disabled == true -%} {%- set attr = attr|merge({'class': attr.class|default('') ~ ' cursor-not-allowed' }) -%} {%- endif -%} - + {%- set tooltip = null -%} + {%- if attr.tooltip is defined -%} + {%- set tooltip = attr.tooltip -%} + {%- set attr = attr|filter((v, k) => k != 'tooltip') -%} + {%- endif -%} + + + {%- endblock radio_widget -%} {% block checkbox_row %} diff --git a/templates/personal_data/index.html.twig b/templates/personal_data/index.html.twig index ef02456..5b12b68 100644 --- a/templates/personal_data/index.html.twig +++ b/templates/personal_data/index.html.twig @@ -3,17 +3,47 @@ {% block content %}
-

- Persönliche Daten -

{% include '_partials/_flashes.html.twig' %} {{ form_start(personalDataForm, { 'attr': { 'data-action': 'loading#toggle' } }) }} +
+ +
+

+ Persönliche Daten +

- {{ form_row(personalDataForm.firstName) }} - {{ form_row(personalDataForm.name) }} - {{ form_row(personalDataForm.gender) }} - {{ form_row(personalDataForm.dateOfBirth) }} - {{ form_row(personalDataForm.nationality) }} +
+

+ Vorname +

+ {{ personalData.firstName }} +
+
+

+ Nachname +

+ {{ personalData.name }} +
+
+

+ Gender +

+ {{ personalData.gender|map_gender }} +
+
+

+ Geburtsdatum +

+ {{ personalData.dateOfBirth|date('d.m.Y') }} +
+
+

+ Nationaliät +

+ {{ personalData.nationality|map_nationality|default('-') }} +

Anschrift @@ -64,4 +94,4 @@

-{% endblock %} \ No newline at end of file +{% endblock %}