diff --git a/README.md b/README.md index db8d8b8..62e8132 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,8 @@ After installation you will have the possibility to enable registration for indi - **End of registraton**: You can define an optional date after which registration will not be possible anymore. - **End of cancellation**: You cand efine an optional date after which cancellation will not be possible anymore. - **Require confirmation**: When enabled, only confirmed registrations count towards the total number of registrations. +- **Enable waiting list**: Keeps the registration open after the maximum amount of participants is reached. All registrations will be put on a waiting list and will automatically be advanced, if prior registrations are cancelled. +- **Advancement from waiting list notification**: This notification will be sent when a participant is advanced from the waiting list. ### Modules @@ -63,6 +65,7 @@ The following template variables are available in event templates as well as the - `$this->canRegister`: Whether registration is possible for this event. - `$this->registrationForm`: Contains the registration form. - `$this->isFull`: Whether the maximum amount of registrations have been reached for this event. +- `$this->isWaitingList`: Whether the maximum amount of registrations have been reached for this event and waiting list is enabled. - `$this->registrationCount`: The current registration count for this event. - `$this->reg_min`: The minimum amount of registrations for this event. - `$this->reg_max`: The maximum amount of registrations for this event. diff --git a/composer.json b/composer.json index a7171aa..535db83 100644 --- a/composer.json +++ b/composer.json @@ -36,6 +36,7 @@ "symfony/dependency-injection": "^5.4 || ^6.4 || ^7.1", "symfony/http-foundation": "^5.4 || ^6.4 || ^7.1", "symfony/http-kernel": "^5.4 || ^6.4 || ^7.1", + "symfony/lock": "^5.4 || ^6.4 || ^7.1", "symfony/routing": "^5.4 || ^6.4 || ^7.1", "symfony/security-core": "^5.4 || ^6.4 || ^7.1", "symfony/translation": "^5.4 || ^6.4 || ^7.1", diff --git a/config/services.yaml b/config/services.yaml index a67f903..38f0fd2 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -3,6 +3,7 @@ parameters: - !php/const Terminal42\NotificationCenterBundle\NotificationType\FormGeneratorNotificationType::NAME - !php/const InspiredMinds\ContaoEventRegistration\NotificationTypes::CONFIRM - !php/const InspiredMinds\ContaoEventRegistration\NotificationTypes::CANCEL + - !php/const InspiredMinds\ContaoEventRegistration\NotificationTypes::WAITING_LIST_ADVANCEMENT services: _defaults: diff --git a/contao/dca/tl_calendar_events.php b/contao/dca/tl_calendar_events.php index 2930740..65b7b60 100644 --- a/contao/dca/tl_calendar_events.php +++ b/contao/dca/tl_calendar_events.php @@ -67,8 +67,25 @@ 'sql' => ['type' => 'boolean', 'default' => false], ]; +$GLOBALS['TL_DCA']['tl_calendar_events']['fields']['reg_enableWaitingList'] = [ + 'inputType' => 'checkbox', + 'exclude' => true, + 'eval' => ['tl_class' => 'clr w50', 'submitOnChange' => true], + 'sql' => ['type' => 'boolean', 'default' => false], +]; + +$GLOBALS['TL_DCA']['tl_calendar_events']['fields']['reg_waitingListAdvancementNotification'] = [ + 'exclude' => true, + 'inputType' => 'select', + 'eval' => ['includeBlankOption' => true, 'chosen' => true, 'tl_class' => 'w50'], + 'sql' => ['type' => 'integer', 'unsigned' => true, 'default' => 0], + 'relation' => ['type' => 'hasOne', 'load' => 'lazy', 'table' => 'tl_nc_notification'], +]; + $GLOBALS['TL_DCA']['tl_calendar_events']['palettes']['__selector__'][] = 'reg_enable'; -$GLOBALS['TL_DCA']['tl_calendar_events']['subpalettes']['reg_enable'] = 'reg_form,reg_min,reg_max,reg_regEnd,reg_cancelEnd,reg_requireConfirm'; +$GLOBALS['TL_DCA']['tl_calendar_events']['palettes']['__selector__'][] = 'reg_enableWaitingList'; +$GLOBALS['TL_DCA']['tl_calendar_events']['subpalettes']['reg_enable'] = 'reg_form,reg_min,reg_max,reg_regEnd,reg_cancelEnd,reg_requireConfirm,reg_enableWaitingList'; +$GLOBALS['TL_DCA']['tl_calendar_events']['subpalettes']['reg_enableWaitingList'] = 'reg_waitingListAdvancementNotification'; foreach ($GLOBALS['TL_DCA']['tl_calendar_events']['palettes'] as $name => $palette) { if (!is_string($palette)) { diff --git a/contao/dca/tl_event_registration.php b/contao/dca/tl_event_registration.php index 7b477be..4027409 100644 --- a/contao/dca/tl_event_registration.php +++ b/contao/dca/tl_event_registration.php @@ -75,6 +75,12 @@ 'eval' => ['tl_class' => 'w50'], 'sql' => ['type' => 'boolean', 'default' => false], ], + 'waiting' => [ + 'inputType' => 'checkbox', + 'exclude' => true, + 'eval' => ['tl_class' => 'w50', 'disabled' => true], + 'sql' => ['type' => 'boolean', 'default' => false], + ], 'form_data' => [ 'inputType' => 'textarea', 'eval' => ['readonly' => true], @@ -86,7 +92,7 @@ 'sorting' => [ 'mode' => 4, 'fields' => ['id'], - 'headerFields' => ['title', 'reg_max'], + 'headerFields' => ['title', 'reg_max', 'reg_waiting'], 'disableGrouping' => true, 'panelLayout' => 'limit', ], diff --git a/contao/languages/de/tl_nc_notification.php b/contao/languages/de/tl_nc_notification.php index 7938a25..f186dab 100644 --- a/contao/languages/de/tl_nc_notification.php +++ b/contao/languages/de/tl_nc_notification.php @@ -13,5 +13,6 @@ use InspiredMinds\ContaoEventRegistration\NotificationTypes; $GLOBALS['TL_LANG']['tl_nc_notification']['type']['event_registration'] = 'Event Registrierung'; -$GLOBALS['TL_LANG']['tl_nc_notification']['type'][NotificationTypes::CONFIRM] = ['Event Registration: Registrierung bestätigt', 'Diese Benachrichtigung wird gesendet, wenn eine Registrierung für ein Event bestätigt wurde.']; -$GLOBALS['TL_LANG']['tl_nc_notification']['type'][NotificationTypes::CANCEL] = ['Event Registration: Registrierung storniert', 'Diese Benachrichtigung wird gesendet, wenn eine Registrierung für ein Event storniert wurde.']; +$GLOBALS['TL_LANG']['tl_nc_notification']['type'][NotificationTypes::CONFIRM] = ['Registrierung bestätigen', 'Diese Benachrichtigung wird gesendet, wenn eine Registrierung für ein Event bestätigt wurde.']; +$GLOBALS['TL_LANG']['tl_nc_notification']['type'][NotificationTypes::CANCEL] = ['Registrierung stornieren', 'Diese Benachrichtigung wird gesendet, wenn eine Registrierung für ein Event storniert wurde.']; +$GLOBALS['TL_LANG']['tl_nc_notification']['type'][NotificationTypes::WAITING_LIST_ADVANCEMENT] = ['Aufstieg von Warteliste', 'Diese Benachrichtigung wird gesendet, wenn eine Registrierung von der Warteliste auf die normale Liste kommt.']; diff --git a/contao/languages/en/tl_calendar_events.php b/contao/languages/en/tl_calendar_events.php index fe84ca1..cbc005b 100644 --- a/contao/languages/en/tl_calendar_events.php +++ b/contao/languages/en/tl_calendar_events.php @@ -18,4 +18,6 @@ $GLOBALS['TL_LANG']['tl_calendar_events']['reg_regEnd'] = ['End of registration', 'Specify an optional date for the end of the registration.']; $GLOBALS['TL_LANG']['tl_calendar_events']['reg_cancelEnd'] = ['End of cancellation', 'Specify an optional date for the end of being able to cancel.']; $GLOBALS['TL_LANG']['tl_calendar_events']['reg_requireConfirm'] = ['Require confirmation', 'Only confirmed registrations are counted.']; +$GLOBALS['TL_LANG']['tl_calendar_events']['reg_enableWaitingList'] = ['Enable waiting list', 'Enables registrations past the maximum amount of participants.']; +$GLOBALS['TL_LANG']['tl_calendar_events']['reg_waitingListAdvancementNotification'] = ['Advancement from waiting list notification', 'This notification will be sent when a participant is moved from the waiting list to the regular list of active registrations.']; $GLOBALS['TL_LANG']['tl_calendar_events']['registrations'] = 'Registrations'; diff --git a/contao/languages/en/tl_event_registration.php b/contao/languages/en/tl_event_registration.php index 00b376e..196c9b6 100644 --- a/contao/languages/en/tl_event_registration.php +++ b/contao/languages/en/tl_event_registration.php @@ -17,4 +17,5 @@ $GLOBALS['TL_LANG']['tl_event_registration']['amount'] = ['Amount', 'Amount of people for this registration.']; $GLOBALS['TL_LANG']['tl_event_registration']['confirmed'] = ['Confirmed', 'Whether this registration has been confirmed.']; $GLOBALS['TL_LANG']['tl_event_registration']['cancelled'] = ['Cancelled', 'Whether this registration has been cancelled.']; +$GLOBALS['TL_LANG']['tl_event_registration']['waiting'] = ['Waiting list', 'Whether this registration is on the waiting list.']; $GLOBALS['TL_LANG']['tl_event_registration']['form_data'] = ['Form data', 'The form data for this registration.']; diff --git a/contao/languages/en/tl_nc_notification.php b/contao/languages/en/tl_nc_notification.php index 49fd451..d435c18 100644 --- a/contao/languages/en/tl_nc_notification.php +++ b/contao/languages/en/tl_nc_notification.php @@ -13,5 +13,6 @@ use InspiredMinds\ContaoEventRegistration\NotificationTypes; $GLOBALS['TL_LANG']['tl_nc_notification']['type']['event_registration'] = 'Event registration'; -$GLOBALS['TL_LANG']['tl_nc_notification']['type'][NotificationTypes::CONFIRM] = ['Event Registration: registration confirmed', 'This notification type is sent when an event registration was confirmed.']; -$GLOBALS['TL_LANG']['tl_nc_notification']['type'][NotificationTypes::CANCEL] = ['Event Registration: registration cancelled', 'This notification type is sent when an event registration was cancelled.']; +$GLOBALS['TL_LANG']['tl_nc_notification']['type'][NotificationTypes::CONFIRM] = ['Confirm registration', 'This notification type can be sent when an event registration is confirmed.']; +$GLOBALS['TL_LANG']['tl_nc_notification']['type'][NotificationTypes::CANCEL] = ['Cancel registration', 'This notification type can be sent when an event registration is cancelled.']; +$GLOBALS['TL_LANG']['tl_nc_notification']['type'][NotificationTypes::WAITING_LIST_ADVANCEMENT] = ['Advancement from waiting list', 'This notification type can be sent when an event registration is cancelled.']; diff --git a/contao/templates/mod_event_registration_form.html5 b/contao/templates/mod_event_registration_form.html5 index 422c171..ab27647 100644 --- a/contao/templates/mod_event_registration_form.html5 +++ b/contao/templates/mod_event_registration_form.html5 @@ -5,6 +5,9 @@ canRegister): ?>

trans('cannot_register', [], 'im_contao_event_registration') ?>

+ isWaitingList): ?> +

trans('is_waiting_list', [], 'im_contao_event_registration') ?>

+ registrationForm ?> diff --git a/src/Controller/FrontendModule/EventRegistrationCancelController.php b/src/Controller/FrontendModule/EventRegistrationCancelController.php index d1aa1c7..0251af5 100644 --- a/src/Controller/FrontendModule/EventRegistrationCancelController.php +++ b/src/Controller/FrontendModule/EventRegistrationCancelController.php @@ -22,6 +22,7 @@ use Contao\Template; use InspiredMinds\ContaoEventRegistration\EventRegistration; use InspiredMinds\ContaoEventRegistration\Model\EventRegistrationModel; +use InspiredMinds\ContaoEventRegistration\WaitingListChecker; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Contracts\Translation\TranslatorInterface; @@ -43,6 +44,7 @@ public function __construct( private readonly TranslatorInterface $translator, private readonly SimpleTokenParser $simpleTokenParser, private readonly NotificationCenter $notificationCenter, + private readonly WaitingListChecker $waitingListChecker, ) { } @@ -110,5 +112,8 @@ private function processCancel(Template $template, ModuleModel $model, CalendarE if ($model->nc_notification) { $this->notificationCenter->sendNotification($model->nc_notification, $tokens); } + + // Process waiting lists + ($this->waitingListChecker)($event); } } diff --git a/src/Cron/WaitingListsCronJob.php b/src/Cron/WaitingListsCronJob.php new file mode 100644 index 0000000..49f351b --- /dev/null +++ b/src/Cron/WaitingListsCronJob.php @@ -0,0 +1,29 @@ +waitingListChecker)(); + } +} diff --git a/src/EventListener/DataContainer/CalendarEvents/ConfigOnLoadCallbackListener.php b/src/EventListener/DataContainer/CalendarEvents/ConfigOnLoadCallbackListener.php index 06cf45e..189e0f6 100644 --- a/src/EventListener/DataContainer/CalendarEvents/ConfigOnLoadCallbackListener.php +++ b/src/EventListener/DataContainer/CalendarEvents/ConfigOnLoadCallbackListener.php @@ -49,6 +49,7 @@ public function __invoke(DataContainer $dc): void ->removeField('reg_regEnd') ->removeField('reg_cancelEnd') ->removeField('reg_requireConfirm') + ->removeField('reg_enableWaitingList') ->applyToSubPalette('reg_enable', 'tl_calendar_events') ; } diff --git a/src/EventListener/DataContainer/CalendarEvents/WaitingListAdvancementNotificationOptionsCallbackListener.php b/src/EventListener/DataContainer/CalendarEvents/WaitingListAdvancementNotificationOptionsCallbackListener.php new file mode 100644 index 0000000..0093c07 --- /dev/null +++ b/src/EventListener/DataContainer/CalendarEvents/WaitingListAdvancementNotificationOptionsCallbackListener.php @@ -0,0 +1,30 @@ +db->fetchAllKeyValue('SELECT id, title FROM tl_nc_notification WHERE type = ? ORDER BY title', [NotificationTypes::WAITING_LIST_ADVANCEMENT]); + } +} diff --git a/src/EventListener/DataContainer/EventRegistration/ChildRecordCallbackListener.php b/src/EventListener/DataContainer/EventRegistration/ChildRecordCallbackListener.php index 586c893..3a32787 100644 --- a/src/EventListener/DataContainer/EventRegistration/ChildRecordCallbackListener.php +++ b/src/EventListener/DataContainer/EventRegistration/ChildRecordCallbackListener.php @@ -16,14 +16,17 @@ use Contao\Image; use Contao\StringUtil; use InspiredMinds\ContaoEventRegistration\EventRegistration\LabelBuilder; +use Symfony\Contracts\Translation\TranslatorInterface; /** * @Callback(table="tl_event_registration", target="list.sorting.child_record") */ class ChildRecordCallbackListener { - public function __construct(private readonly LabelBuilder $labelBuilder) - { + public function __construct( + private readonly LabelBuilder $labelBuilder, + private readonly TranslatorInterface $translator, + ) { } public function __invoke(array $row): string @@ -42,14 +45,25 @@ public function __invoke(array $row): string } $icon = 'visible_.svg'; + $alt = ''; + $attributes = ' style="float:left; margin-right:0.3em;"'; if ($row['cancelled']) { $icon = 'unpublished.svg'; + $alt = $this->translator->trans('tl_event_registration.cancelled.0', [], 'contao_tl_event_registration'); + } elseif ($row['waiting']) { + $icon = 'news.svg'; + $alt = $this->translator->trans('tl_event_registration.waiting.0', [], 'contao_tl_event_registration'); } elseif ($row['confirmed']) { $icon = 'visible.svg'; + $alt = $this->translator->trans('tl_event_registration.confirmed.0', [], 'contao_tl_event_registration'); + } + + if ($alt) { + $attributes .= ' title="'.$alt.'"'; } - $label = Image::getHtml($icon, '', ' style="float:left; margin-right:0.3em;"').' '.$label; + $label = Image::getHtml($icon, '', $attributes).' '.$label; return '
'.$label.'
'; } diff --git a/src/EventListener/DataContainer/EventRegistration/ConfigOnSubmitCallbackListener.php b/src/EventListener/DataContainer/EventRegistration/ConfigOnSubmitCallbackListener.php new file mode 100644 index 0000000..dc25b7c --- /dev/null +++ b/src/EventListener/DataContainer/EventRegistration/ConfigOnSubmitCallbackListener.php @@ -0,0 +1,33 @@ +activeRecord?->pid)) { + ($this->waitingListChecker)($event); + } + } +} diff --git a/src/EventListener/DataContainer/EventRegistration/HeaderCallbackListener.php b/src/EventListener/DataContainer/EventRegistration/HeaderCallbackListener.php index d002c6e..d16f7cb 100644 --- a/src/EventListener/DataContainer/EventRegistration/HeaderCallbackListener.php +++ b/src/EventListener/DataContainer/EventRegistration/HeaderCallbackListener.php @@ -34,9 +34,11 @@ public function __construct( public function __invoke(array $labels, DataContainer $dc): array { $event = $this->helper->getMainEvent(CalendarEventsModel::findById($dc->id)); - $label = $this->helper->getRegistrationCount($event); + $count = $this->helper->getRegistrationCount($event, true); + $waiting = $this->helper->getRegistrationCount($event) - $count; - $labels[$this->trans->trans('header_count_title', [], 'im_contao_event_registration')] = $label; + $labels[$this->trans->trans('header_count_title', [], 'im_contao_event_registration')] = $count; + $labels[$this->trans->trans('header_waiting_title', [], 'im_contao_event_registration')] = $waiting; return $labels; } diff --git a/src/EventListener/EventRegistrationFormListener.php b/src/EventListener/EventRegistrationFormListener.php index f7cb7bb..b4b8e8c 100644 --- a/src/EventListener/EventRegistrationFormListener.php +++ b/src/EventListener/EventRegistrationFormListener.php @@ -18,8 +18,10 @@ use Contao\FrontendUser; use InspiredMinds\ContaoEventRegistration\EventRegistration; use InspiredMinds\ContaoEventRegistration\Model\EventRegistrationModel; +use InspiredMinds\ContaoEventRegistration\WaitingListChecker; use Ramsey\Uuid\Uuid; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; +use Symfony\Component\Lock\LockFactory; use Symfony\Contracts\Translation\TranslatorInterface; /** @@ -34,6 +36,7 @@ public function __construct( private readonly EventRegistration $eventRegistration, private readonly TokenStorageInterface $tokenStorage, private readonly TranslatorInterface $translator, + private readonly LockFactory $lockFactory, ) { } @@ -49,17 +52,28 @@ public function __invoke(array &$submittedData, array $formData, array|null $fil return; } - $registration = new EventRegistrationModel(); - $registration->pid = (int) $event->id; - $registration->created = time(); - $registration->tstamp = time(); - $registration->uuid = Uuid::uuid4()->toString(); - $registration->form = (int) $form->id; - $registration->member = (int) $this->getMember()?->id ?? 0; - $registration->amount = max(1, (int) ($submittedData['amount'] ?? 1)); - $registration->form_data = json_encode($submittedData, JSON_THROW_ON_ERROR); - - $registration->save(); + $lock = $this->lockFactory->createLock(WaitingListChecker::class); + $lock->acquire(true); + + try { + $amount = max(1, (int) ($submittedData['amount'] ?? 1)); + $waiting = $this->eventRegistration->getRegistrationCount($event, true) + $amount > $event->reg_max; + + $registration = new EventRegistrationModel(); + $registration->pid = (int) $event->id; + $registration->created = time(); + $registration->tstamp = time(); + $registration->uuid = Uuid::uuid4()->toString(); + $registration->form = (int) $form->id; + $registration->member = (int) $this->getMember()?->id ?? 0; + $registration->amount = $amount; + $registration->waiting = $waiting; + $registration->form_data = json_encode($submittedData, JSON_THROW_ON_ERROR); + + $registration->save(); + } finally { + $lock->release(); + } // Inject event registration UUID $t = EventRegistrationModel::getTable(); diff --git a/src/EventRegistration.php b/src/EventRegistration.php index f92ed17..85af78f 100644 --- a/src/EventRegistration.php +++ b/src/EventRegistration.php @@ -56,6 +56,8 @@ public function addTemplateData(Template $template, CalendarEventsModel $event): $template->registrationCount = fn (): int => $this->getRegistrationCount($event); + $template->isWaitingList = fn (): bool => $this->isWaitingList($event); + $mainEvent = $this->getMainEvent($event); $template->reg_min = $mainEvent->reg_min; @@ -80,7 +82,12 @@ public function canRegister(CalendarEventsModel $event): bool return false; } - return !$this->isFull($event); + return $this->isWaitingList($event) || !$this->isFull($event); + } + + public function isWaitingList(CalendarEventsModel $event): bool + { + return $this->getMainEvent($event)->reg_enableWaitingList && $this->isFull($event); } public function isFull(CalendarEventsModel $event): bool @@ -92,12 +99,12 @@ public function isFull(CalendarEventsModel $event): bool return false; } - $count = $this->getRegistrationCount($event); + $count = $this->getRegistrationCount($event, true); return $count >= (int) $event->reg_max; } - public function getRegistrationCount(CalendarEventsModel $event): int + public function getRegistrationCount(CalendarEventsModel $event, bool $excludeWaitingList = false): int { $event = $this->getMainEvent($event); @@ -107,6 +114,10 @@ public function getRegistrationCount(CalendarEventsModel $event): int $query .= ' AND confirmed = 1'; } + if ($event->reg_enableWaitingList && $excludeWaitingList) { + $query .= ' AND waiting != 1'; + } + $query .= ';'; return (int) $this->db->fetchOne($query, [(int) $event->id]); diff --git a/src/NotificationType/EventRegistrationWaitingListAdvancementNotificationType.php b/src/NotificationType/EventRegistrationWaitingListAdvancementNotificationType.php new file mode 100644 index 0000000..eef2316 --- /dev/null +++ b/src/NotificationType/EventRegistrationWaitingListAdvancementNotificationType.php @@ -0,0 +1,23 @@ +framework->initialize(); + + $lock = $this->lockFactory->createLock(self::class); + $lock->acquire(true); + + try { + // Go through all upcoming events, if no event given + $events = $event ? [$event] : CalendarEventsModel::findUpcomingByPids(CalendarModel::findAll()->fetchEach('id')); + + foreach ($events as $event) { + $event = $this->eventRegistration->getMainEvent($event); + + // Check if waiting list is enabled at all + if (!$event->reg_enableWaitingList) { + continue; + } + + // Fill up slots with waiting list entries + while (($diff = $event->reg_max - $this->eventRegistration->getRegistrationCount($event, true)) > 0) { + // Get the next waiting registration entry whose amount is equal or smaller to the diff + $waitingRegistration = EventRegistrationModel::findOneBy(['pid = ?', 'waiting = 1', 'cancelled != 1', 'amount <= ?'], [$event->id, $diff], ['order' => 'created ASC']); + + // If there are no waiting registrations, break + if (!$waitingRegistration) { + break; + } + + $waitingRegistration->waiting = false; + $waitingRegistration->save(); + + // Send notification + if ($event->reg_waitingListAdvancementNotification && ($notification = Notification::findById((int) $event->reg_waitingListAdvancementNotification))) { + $notification->send($this->eventRegistration->getSimpleTokens($event, $waitingRegistration)); + } + } + } + } finally { + $lock->release(); + } + } +} diff --git a/translations/im_contao_event_registration.de.yaml b/translations/im_contao_event_registration.de.yaml index c1b6131..702f2c6 100644 --- a/translations/im_contao_event_registration.de.yaml +++ b/translations/im_contao_event_registration.de.yaml @@ -14,3 +14,5 @@ already_cancelled: Diese Registrierung wurde bereits storniert. cannot_confirm: Registrierungen für dieses Event können nicht mehr bestätigt werden. cannot_cancel: Anmeldungen für dieses Event können nicht mehr storniert werden. header_count_title: Anmeldungen +header_waiting_title: Warteliste +is_waiting_list: Registrierungen zu diesem Event sind nur mehr mit Warteliste möglich. diff --git a/translations/im_contao_event_registration.en.yaml b/translations/im_contao_event_registration.en.yaml index 23c5beb..b82e4f1 100644 --- a/translations/im_contao_event_registration.en.yaml +++ b/translations/im_contao_event_registration.en.yaml @@ -14,3 +14,5 @@ already_cancelled: This event registration has already been cancelled. cannot_confirm: Registrations for this event cannot be confirmed anymore. cannot_cancel: Registrations for this event cannot be cancelled anymore. header_count_title: Registrations +header_waiting_title: Waiting list +is_waiting_list: Registrations to this event will be put on a waiting list.