Skip to main content

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.onboardingCompletedAt jest 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 przewodnika
  • components/post-login-dialogs.tsx — kolejkowanie dialogów po zalogowaniu, zamontowane w app/layout.tsx, czyli aktywne na każdej podstronie
  • lib/actions/users.tscompleteOnboarding() i resetOnboarding()
  • 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.

warning

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.