fix: don't disable room selection field with single option

This commit is contained in:
Björn Fromme
2026-03-16 11:59:12 +01:00
parent 4db2cd7eda
commit cd1ffc3e9a
@@ -10,11 +10,13 @@ use App\BusProNet\Model\Pickup;
use App\BusProNet\Model\Service; use App\BusProNet\Model\Service;
use App\BusProNet\Utility\DirectionMapper; use App\BusProNet\Utility\DirectionMapper;
use App\Form\Model\BookingDto; use App\Form\Model\BookingDto;
use App\Form\Model\RoomSelectionDto;
use App\Form\Service\Abstract\AbstractFieldOptionsProvider; use App\Form\Service\Abstract\AbstractFieldOptionsProvider;
use App\Form\Service\Factory\ParticipantRoomChoiceLoaderFactory; use App\Form\Service\Factory\ParticipantRoomChoiceLoaderFactory;
use App\Service\BookingPriceCalculatorService; use App\Service\BookingPriceCalculatorService;
use App\Service\InsuranceService; use App\Service\InsuranceService;
use App\Service\ServiceAvailabilityCalculator; use App\Service\ServiceAvailabilityCalculator;
use App\Validator\Constraints\RoomSelection;
/** /**
* Provides dynamic field options for participant form fields. * Provides dynamic field options for participant form fields.
@@ -119,35 +121,35 @@ class ParticipantFieldOptionsProvider extends AbstractFieldOptionsProvider
// Room assignment field provider (available for both create and edit workflows) // Room assignment field provider (available for both create and edit workflows)
$this->fieldOptionProviders['assignedRoomId'] = function (BookingDto $bookingDto, int $participantIndex, array $options = []) { $this->fieldOptionProviders['assignedRoomId'] = function (BookingDto $bookingDto, int $participantIndex, array $options = []) {
$choiceLoader = null; $choiceLoader = null;
$disabled = false; $singleChoice = false;
if (BookingDto::MODE_CREATE === $bookingDto->getMode()) { if (BookingDto::MODE_CREATE === $bookingDto->getMode()) {
// Create context: use selected rooms from step 1 // Create context: use selected rooms from step 1, filtered by participant age
$choiceLoader = $this->roomChoiceLoaderFactory->createForCreate( $filteredRooms = $this->filterRoomsByParticipantAge(
$bookingDto->getSelectedRooms() $bookingDto->getSelectedRooms(),
$bookingDto,
$participantIndex
); );
// Disable when only one room type selected (auto-assigned) $choiceLoader = $this->roomChoiceLoaderFactory->createForCreate($filteredRooms);
$disabled = 1 === count($bookingDto->getSelectedRooms()); $singleChoice = 1 === count($filteredRooms);
} elseif (BookingDto::MODE_EDIT === $bookingDto->getMode()) { } elseif (BookingDto::MODE_EDIT === $bookingDto->getMode()) {
// Edit context: use already-booked rooms from booking // Edit context: use already-booked rooms from booking
$choiceLoader = $this->roomChoiceLoaderFactory->createForEdit( $choiceLoader = $this->roomChoiceLoaderFactory->createForEdit(
$bookingDto->booking->rooms $bookingDto->booking->rooms
); );
// Disable when only one room in booking (no reassignment needed) $singleChoice = 1 === count($bookingDto->booking->rooms);
$disabled = 1 === count($bookingDto->booking->rooms);
} }
return [ return [
'label' => 'Zimmer', 'label' => 'Zimmer',
'placeholder' => 'Nicht zugeordnet', // No placeholder when only one room available - the only option is pre-selected
'placeholder' => $singleChoice ? false : 'Nicht zugeordnet',
// Use factory to create context-aware choice loader that: // Use factory to create context-aware choice loader that:
// - Shows only available rooms for this participant // - Shows only available rooms for this participant
// - Excludes rooms already assigned to other participants // - Excludes rooms already assigned to other participants
// - Respects room capacity and booking constraints // - Respects room capacity and booking constraints
// - Filters Baby rooms for participants over 2 years old
'choice_loader' => $choiceLoader, 'choice_loader' => $choiceLoader,
// Make field read-only when only one room type is available
// Room is auto-assigned or cannot be changed, no user choice needed
'disabled' => $disabled,
]; ];
}; };
@@ -540,6 +542,54 @@ class ParticipantFieldOptionsProvider extends AbstractFieldOptionsProvider
// ]; // ];
} }
/**
* Filters room selections by participant age constraints.
*
* Baby rooms (code 'Baby') are only available for participants aged 2 years or younger.
* Other room types are available for all participants regardless of age.
*
* @param RoomSelectionDto[] $roomSelections Array of room selections from Step 1
* @param BookingDto $bookingDto The booking DTO containing participant and travel data
* @param int $participantIndex Index of the participant to evaluate
*
* @return RoomSelectionDto[] Filtered array of room selections available for this participant
*/
private function filterRoomsByParticipantAge(array $roomSelections, BookingDto $bookingDto, int $participantIndex): array
{
$participant = $bookingDto->getParticipant($participantIndex);
// If no participant or no date of birth, return all rooms (field visibility handles this case)
if (null === $participant || null === $participant->dateOfBirth) {
return $roomSelections;
}
// Calculate participant's age at travel start date
$age = $participant->getAge($bookingDto->travel->dateFrom);
if (null === $age) {
return $roomSelections;
}
// Get available rooms from travel data to look up room codes
$availableRooms = $bookingDto->travel->getAvailableRooms();
return array_filter($roomSelections, function (RoomSelectionDto $roomSelection) use ($availableRooms, $age) {
$room = $availableRooms[$roomSelection->roomId] ?? null;
// Exclude rooms not found in travel data to avoid validation issues
if (null === $room) {
return false;
}
// Baby rooms only available for participants 2 years or younger
if (RoomSelection::BABY_ROOM_CODE === $room->code) {
return $age <= 2;
}
// All other rooms available for all ages
return true;
});
}
/** /**
* Filters rental services by selected skipass duration. * Filters rental services by selected skipass duration.
* *