Przewodnik „Pierwsze kroki w AcePark"
Instrukcja (klient)
Po pierwszym zalogowaniu i uzupełnieniu profilu klient dostaje trzykrokowy przewodnik po aplikacji: rezerwacja kortu lub zapis na trening próbny, grafik zajęć oraz płatności. Każdy krok ma przycisk prowadzący prosto do właściwej sekcji.
Przewodnik można zamknąć na trzy sposoby — „Pomiń", „Zakończ" na ostatnim kroku albo przycisk przenoszący do wybranej sekcji. Każdy z nich kończy przewodnik na stałe: nie pojawi się ponownie po przeładowaniu strony, wylogowaniu ani na innym urządzeniu.
Żeby obejrzeć go jeszcze raz, wybierz „Pokaż przewodnik ponownie" w menu pod awatarem (pozycja widoczna tylko dla klientów).
Kiedy przewodnik się pokazuje
Wszystkie warunki muszą być spełnione naraz:
- rola
CLIENT(pracownicy —ADMIN,BACKOFFICE,INSTRUCTOR— go nie widzą), - profil kompletny: zweryfikowany telefon, imię i wybrane miasto,
- pole
user.onboardingCompletedAtjest puste.
Dialogi po zalogowaniu mają priorytety — weryfikacja telefonu (1) wyprzedza przewodnik (2), a ten wyprzedza zachętę do instalacji PWA (3). Zamknięcie jednego otwiera kolejny z listy.
Dokumentacja techniczna
Pliki
components/onboarding/onboarding-tour.tsx— dialog przewodnikacomponents/post-login-dialogs.tsx— kolejkowanie dialogów po zalogowaniu, zamontowane wapp/layout.tsx, czyli aktywne na każdej podstronielib/actions/users.ts—completeOnboarding()iresetOnboarding()components/layout/user-nav.tsx— pozycja „Pokaż przewodnik ponownie"messages/pl.json,messages/en.json— przestrzeńonboarding.*
Trwałość stanu
Stan trzyma kolumna onboardingCompletedAt w tabeli user (D1). Jest to jedno
źródło prawdy — nie ma localStorage ani ciasteczka, dzięki czemu przewodnik
zachowuje się tak samo w przeglądarce i w aplikacji mobilnej (TWA).
completeOnboarding() zapisuje znacznik czasu ISO, resetOnboarding() ustawia
NULL. Ta druga akcja musi przekazywać null, a nie undefined — D1 odrzuca
undefined w bind() błędem D1_TYPE_ERROR.
Odświeżanie sesji po zapisie (AP-827)
Better Auth trzyma sesję w podpisanym ciasteczku z 5-minutowym cache
(cookieCache w lib/auth.ts). Zapis server action idzie prosto do D1, więc
authClient.useSession() przez te kilka minut nadal zwraca użytkownika sprzed
zmiany — a warunek pokazania przewodnika czyta właśnie tę sesję.
Dlatego po każdym zapisie flagi wołany jest refreshUser() z hooks/useUser.ts,
który robi refetch({ query: { disableCookieCache: true } }): serwer czyta wiersz
z bazy na nowo i nadpisuje cache w ciasteczku.
Dodatkowo PostLoginDialogs pamięta w stanie lokalnym, które dialogi zostały już
w tej sesji przeglądania zamknięte. To zabezpieczenie na wypadek nieudanego
zapisu (błąd sieci, chwilowa niedostępność D1) — przewodnik nie wraca wtedy przy
nawigacji, choć po pełnym przeładowaniu strony może się pojawić ponownie, bo w
bazie nic nie zostało zapisane.
Nie przekierowuj po zapisie na /auth/login. Za czasów Auth0 był to endpoint
SDK, który wystawiał nowy token i przepisywał ciasteczko sesji. Po migracji na
Better Auth jest to zwykły formularz logowania bez przekierowania zalogowanych,
więc taki „refresh" pokazywał zalogowanemu klientowi ekran logowania.
Backfill
Migracja 0199_backfill_onboarding_completed_at.sql ustawia flagę wszystkim
kontom założonym przed 2026-07-18, które jej nie miały. Powód: do czasu
naprawy AP-827 przycisk „Pomiń" nie zapisywał niczego, więc ~820 klientów
widziało przewodnik przy każdym wejściu na dowolną podstronę przez ponad dwa
miesiące. Konta nowsze niż ta data zachowują normalne pierwsze uruchomienie.