Zajęcia wakacyjne
Kompleksowy przewodnik po module zajęć wakacyjnych — pojedynczych zajęć w kalendarzu (np. „Doubles (wakacyjne)"), na które uczestnik zapisuje się termin po terminie. Obejmuje ustawienia, warunki zapisu, akceptację regulaminu, przepływy płatności, wygaśnięcia oraz zapis wszystkiego w historii.
:::note Rozróżnienie
To nie to samo co moduł Półkolonie (camps). Półkolonie to wielodniowe turnusy z
własnym systemem sezonów, list rezerwowych i dokumentów. Zajęcia wakacyjne opisane tutaj to
zwykłe gry (game) z rodzajem zajęć w kategorii „Wakacyjne", na które klient zapisuje
się pojedynczo, z dedykowaną logiką zapisu, regulaminu i płatności.
:::
Przepływ w skrócie (diagram)
👤 Instrukcja dla pracownika (Administracja / Recepcja / Instruktor)
Czym są zajęcia wakacyjne
Zajęcia wakacyjne to rodzaj zajęć (Rodzaj zajęć) oznaczony kategorią „Wakacyjne".
Zajęcia utworzone z takiego rodzaju trafiają na osobną zakładkę „Zajęcia wakacyjne" w portalu
klienta i podlegają odrębnym regułom widoczności, zapisu i płatności.
Ustawienia (Panel administratora → Ustawienia zajęć wakacyjnych)
Dla każdego miasta konfiguruje się osobno:
- Włącz zajęcia wakacyjne — globalny przełącznik dostępności modułu w danym mieście.
- Natychmiastowa płatność (online) — gdy włączona, klient zapisujący się sam jest od razu kierowany do płatności; Czas na płatność online (minuty) określa, ile ma czasu, zanim zapis wygaśnie.
- Natychmiastowa płatność (pracownik) — gdy recepcja zapisuje uczestnika, do klienta wysyłany jest link do płatności (SMS); Czas na płatność pracownik (minuty) określa okno na opłacenie.
- Dni z wyprzedzeniem (klient) / Dni z wyprzedzeniem (pracownik) — jak daleko w przód widać dostępne terminy (osobno dla klienta i pracownika).
Zapis uczestnika
Zapis możliwy jest przez klienta (portal klienta → zakładka „Zajęcia wakacyjne") oraz przez recepcję (w imieniu uczestnika). System dopuszcza zapis tylko, gdy spełnione są wszystkie warunki:
- Ukończona ocena umiejętności (zajęcia próbne) — nowy uczestnik musi najpierw przejść zajęcia próbne / ocenę umiejętności, zanim zobaczy ofertę wakacyjną.
- Brak zaległej / oczekującej płatności wakacyjnej — uczestnik z nieopłaconą, aktywną płatnością wakacyjną nie może zapisać się na kolejny termin, dopóki jej nie ureguluje lub nie wygaśnie.
- Dopasowanie wieku — termin jest oferowany tylko, gdy jego zakres wiekowy pokrywa się z przypisanym uczestnikowi rodzajem zajęć („Rodzaj zajęć"). Jeśli uczestnik nie ma jeszcze przypisanej grupy, widzi komunikat o oczekiwaniu na przypisanie przez recepcję.
- Wolne miejsca i okno widoczności (dni z wyprzedzeniem).
Akceptacja regulaminu (i RODO)
Zapis na zajęcia wakacyjne wymaga akceptacji regulaminu wakacyjnej szkółki oraz RODO. Akceptacja jest wymuszana na każdej ścieżce płatności:
- podczas zapisu przez klienta (dialog zgody),
- na stronie linku do płatności (SMS od recepcji),
- w widoku Płatności w aplikacji, jeśli klient zamiast klikać w link zaloguje się i opłaci zajęcia z listy płatności.
Bez zaznaczenia zgody nie da się przejść do płatności. Fakt akceptacji jest zapisywany i widoczny w historii (patrz niżej).
Ostrzeżenie o braku możliwości odwołania
Jeśli termin zajęć przypada wcześniej niż wymagany czas na anulowanie (próg anulowania rodzaju zajęć), przy wyborze terminu pojawia się ostrzeżenie:
„Uwaga! Termin zajęć przypada wcześniej niż wymagany czas na jej anulowanie. Po dokonaniu zapisu nie będzie możliwości odwołania zajęć."
Dotyczy to zarówno zajęć wakacyjnych, jak i wakacyjnych zajęć próbnych.
Płatność
- Klient (natychmiastowa płatność online) — po zapisie klient trafia do widoku Płatności
(
/dashboard/payments), gdzie po akceptacji regulaminu opłaca zajęcia. Zajęcia wakacyjne nie są automatycznie przekierowywane wprost na bramkę Przelewy24 — klient reguluje je z poziomu listy płatności (bramką lub portfelem). - Recepcja — po zapisie do klienta wychodzi link do płatności (SMS); na stronie linku klient akceptuje regulamin i płaci (Przelewy24).
- Po zaksięgowaniu płatności klient dostaje powiadomienie „Płatność potwierdzona"
(
vacation_payment_success).
Wygaśnięcie płatności
Jeśli uczestnik nie opłaci w wyznaczonym czasie, płatność wygasa, a miejsce jest zwalniane automatycznie. Wygaśnięcie jest odnotowane w historii zajęć jako „Wygaśnięcie czasu na opłacenie".
Historia
Wszystkie zdarzenia związane z zajęciami wakacyjnymi trafiają do dwóch historii:
- Historia Zajęć (podgląd/edycja pojedynczej gry) — chronologiczny log zdarzeń danej gry: dołączenie, akceptacja regulaminu, płatność, płatność z portfela, zwrot na portfel, usunięcie bez zwrotu, wygaśnięcie, odwołanie.
- Historia aktywności (
/dashboard/history) — ogólny rejestr, w którym zajęcia wakacyjne mają własne źródło „Zajęcia wakacyjne" oraz m.in. wpis „Akceptacja regulaminu".
🛠️ Dokumentacja techniczna
Model danych
- Rodzaj zajęć wakacyjnych:
activity_types.category = 'Wakacyjne'(typat.type = 'other'). To jedyny wyróżnik odróżniający zajęcia wakacyjne od zwykłych. - Gra: zwykły rekord
gamezactivity_type_idwskazującym na rodzaj „Wakacyjne". - Uczestnik wakacyjny: wpis w
game.attendeesztype = 'vacation'ipaymentId. - Płatność:
payment.payment_type = 'school',related_ids = [gameId]. Zajęcia wakacyjne rozpoznaje się jakopayment_type = 'school'orazactivity_type.category = 'Wakacyjne'. - Log zdarzeń gry (
game.event_log, JSON): m.in.joined,consent_accepted,payment_paid,paid_with_wallet,refund_to_wallet,removed_without_refund,attendee_expired,cancelled.
Ustawienia
VacationActivitySettings w lib/actions/app-settings.ts (klucze
app_settings per miasto): vacation_activity_enabled,
vacation_activity_immediate_payment_online, vacation_activity_immediate_payment_employee,
vacation_activity_payment_time_online, vacation_activity_payment_time_employee,
vacation_activity_payment_time (legacy fallback, nie edytowany już w UI),
vacation_activity_days_advance_client, vacation_activity_days_advance_employee.
Formularz: components/forms/vacation-activity-settings/vacation-activity-settings-form.tsx
(w UI zostały tylko dwa pola czasu płatności: online i pracownik).
Zapis i widoczność
enrollInVacationActivity(gameId, playerId, city, consentAccepted)— serwerowa akcja zapisu. WymagaconsentAccepted(inaczejerrors.consentRequired), blokuje przy zaległościach, zapisuje uczestnika typuvacationoraz zdarzenieconsent_accepteddoevent_log.hasPendingVacationPaymentByPlayer(playerId)— blokada zapisu przy aktywnej, nieopłaconej płatności wakacyjnej (świadoma wygaśnięć).getGamesByDateRangeForPlayer(...)— źródło dostępnych terminów; zwracaactivity_typezcategory,cancellation_hours_beforei innymi polami potrzebnymi UI.useVacationEnrollment(...)(components/forms/vacation-enrollment/use-vacation-enrollment.ts) — hook ładujący ustawienia, dostępne terminy, status zaległości i informację o konieczności przypisania do grupy. Dopasowanie wieku:vacationTermMatchesAssignedTypes(...).- Bramka zajęć próbnych (ocena umiejętności) przed ofertą wakacyjną:
playerMustCompleteSkillAssessment(...). - UI zapisu:
components/forms/vacation-enrollment/vacation-enrollment-dialog.tsx(zajęcia wakacyjne) orazcomponents/forms/trial-enrollment/trial-enrollment-dialog.tsxz propemvacationOnly(wakacyjne zajęcia próbne).
Płatności
- Brak auto-redirectu na bramkę dla wakacji: po zapisie klient trafia do
/dashboard/payments(a nie wprost na Przelewy24). Wakacyjne zajęcia próbne bramkowane propemvacationOnly; zwykłe próbne bez zmian. - Link do płatności:
app/pay/[token]/page.tsx+PublicPayButton.tsx; inicjalizacjaapp/api/public/payment/initialize/route.ts. - Wykrywanie płatności wakacyjnej w widoku Płatności: pole
activity_type_categorywystawione z zapytań płatności (lib/actions/payment.ts), warunekpayment_type === 'school' && activity_type_category === 'Wakacyjne'.
Regulamin / zgoda (consent_accepted)
Akceptacja regulaminu jest zapisywana jako zdarzenie consent_accepted w event_log gry na
każdej ścieżce płatności:
- Widok Płatności (w aplikacji) — bramka
VacationStatuteAcceptanceDialog(components/modal/vacation-statute-acceptance-dialog.tsx) wpięta wpayments-list-view-user.tsxiPaymentsTableAccordion.tsx(analogicznie do bramki rezerwacji kortów); po akceptacjisaveVacationStatuteAcceptance(paymentIds). - Link do płatności —
app/api/public/payment/initialize/route.tswywołujerecordVacationStatuteConsent(paymentId, acceptedBy, tenantId)dla płatności typugroup(updateBookingStatuteAcceptancejest no-opem dla gier — dlatego trzeba zapisać zdarzenie na grze). - Zapis przy zapisie —
enrollInVacationActivityzapisujeconsent_acceptedprzy dołączeniu.
Rdzeń zapisu: recordVacationStatuteConsent(...) w lib/actions/payment.ts — bez zależności
od sesji, best-effort, z dedupem po paymentId (nie dubluje zgody). Dialog linkuje do
Regulaminu wakacyjnej szkółki oraz RODO.
Historia — renderowanie
- Historia aktywności: builder
buildGameConsentAcceptedSQLwlib/actions/activity-log.ts(typ akcjiconsent_accepted, źródłovacation); render wapp/(dashboard)/dashboard/history/components/ActivityLogItem.tsx(badge „Akceptacja regulaminu"). Zajęcia wakacyjne mają źródłosource_type = 'vacation'. - Historia Zajęć:
app/(dashboard)/dashboard/schedule/components/GameEventsView.tsxrenderuje wszystkie zdarzenia zevent_log; etykiety/opisy zgameEvents.eventTypes.*ieventDescriptions.*(m.in.consent_accepted,payment_paid,paid_with_wallet,removed_without_refund,game_cancelled).
Wygaśnięcia i zwolnienie miejsca
- Cron
expirePendingPayments(env)(lib/actions/expire-payments.ts) przełącza wygasłe płatnościpending → expired;logExpiriesToGameLog(...)dopisuje zdarzenieattendee_expireddoevent_loggry (dla płatnościschoolna grach „Wakacyjne" oraztrialna dowolnej grze). Miejsce zwalniane jest przez leniwe filtry uczestników.
Powiadomienia
vacation_payment_success(lib/notification-config.ts) — SMS/e-mail po zaksięgowaniu płatności; szablon e-mail:mails/vacation-payment-success.html.
Kluczowe pliki
| Obszar | Plik |
|---|---|
| Ustawienia | lib/actions/app-settings.ts, components/forms/vacation-activity-settings/vacation-activity-settings-form.tsx |
| Zapis | lib/actions/game.ts (enrollInVacationActivity), components/forms/vacation-enrollment/* |
| Dostępne terminy | lib/actions/game.ts (getGamesByDateRangeForPlayer), use-vacation-enrollment.ts |
| Regulamin | components/modal/vacation-statute-acceptance-dialog.tsx, lib/actions/payment.ts (recordVacationStatuteConsent, saveVacationStatuteAcceptance) |
| Płatność (link) | app/pay/[token]/*, app/api/public/payment/initialize/route.ts |
| Płatność (widok) | components/tables/payments-table/payments-list-view-user.tsx, PaymentsTableAccordion.tsx |
| Historia | lib/actions/activity-log.ts, ActivityLogItem.tsx, GameEventsView.tsx |
| Wygaśnięcia | lib/actions/expire-payments.ts |
| Powiadomienia | lib/notification-config.ts, mails/vacation-payment-success.html |