Wybór obiektu w zakładce Rezerwacje
Instrukcja
Dotyczy zakładki Rezerwacje w aplikacji klienta, w miastach z więcej niż jednym obiektem (np. Opole: ul. Oleska i ul. Spokojna).
Co widzi klient
- Miasto (klub) klient wybiera na stronie logowania — kafelek „AcePark Opole / Oleska · Spokojna / Zmień” pod logo jest żółty i od razu widoczny; kliknięcie otwiera listę klubów. Wewnątrz aplikacji klient nie zmienia miasta.
- W górnej belce, po lewej od avatara, klient ma jeden żółty przycisk
lokalizacji — na komputerze „Opole · ul. Spokojna · Zmień”, na telefonie
pigułkę z nazwą ulicy („Spokojna”). Pokazuje się tylko w mieście z więcej
niż jednym obiektem i tylko na stronach, na których lokalizacja ma
znaczenie (Rezerwacje, Uczestnicy). Kliknięcie otwiera listę Wybierz
obiekt z obiektami tego miasta — na komputerze jako panel pod
przyciskiem, na telefonie jako panel wysuwany od dołu. Każdy obiekt to karta
z nazwą, miastem i plakietką:
- Rezerwacje online — w tym obiekcie można rezerwować kort z aplikacji,
- Brak rezerwacji online — obiekt bez rezerwacji online; po wybraniu widać tylko listę własnych rezerwacji i komunikat „Rezerwacje niedostępne”.
- Wybrany obiekt jest zapamiętywany (ciasteczko na 30 dni). Przy następnym wejściu w Rezerwacje bez parametrów w adresie strona otwiera się na ostatnio wybranym obiekcie zamiast na domyślnej ul. Spokojnej.
- Na telefonie panel otwiera się sam przy wejściu w Rezerwacje tylko wtedy, gdy klient nie ma jeszcze zapamiętanego obiektu. Po pierwszym wyborze nic nie wyskakuje. Na komputerze nic nie otwiera się automatycznie.
Co widzi pracownik
Pracownik (ADMIN / BACKOFFICE) ma w belce jeden żółty przycisk w tym samym designie z listą: „Wszystkie miasta” (tam, gdzie widok nie jest ograniczony do jednego miasta), potem każde miasto jako całość („Opole · Wszystkie lokalizacje”) i pod nim jego obiekty („ul. Oleska”, „ul. Spokojna”). Wybór ulicy z innego miasta to jedno dotknięcie. Na stronach bez wymiaru ulicy (np. Płatności) lista zawiera tylko miasta. Reguły, na których stronach jest wybór miasta lub ulicy, są bez zmian względem dawnych selectów.
Po co
Domyślnym obiektem klienta była ul. Spokojna (NEXT_PUBLIC_DEFAULT_STREET).
Gdy rezerwacje online są tam wyłączone, klient widział tylko komunikat
„Rezerwacje niedostępne” i pusty widok, a ikona zmiany lokalizacji w belce nie
była dla niego oczywista. Wymuszony wybór przy wejściu pokazuje od razu, że są
dwa obiekty i w którym z nich można rezerwować.
Dokumentacja techniczna
Dane
getBookableLocationOptions(city) w lib/actions/booking-settings.ts zwraca
oprócz streets (otwarte online) i enabled także allStreets — wszystkie
ulice miasta z tabeli court. getAllLocationOptions() składa z tego listę
HeaderLocationOption { city, street | null, bookable } dla wszystkich miast
(getCities() + getBookableLocationOptions per miasto, równolegle) i trzyma
ją w cache booking-settings:<tenant> z TTL 120 s — belka renderuje się na
każdej stronie, więc bez cache byłoby to 2 zapytania na miasto przy każdym
wejściu. Zmiana allow_online_booking unieważnia ten namespace od razu;
zmiana reservation_enabled w app_settings propaguje się po wygaśnięciu TTL.
components/layout/global-city-select.tsx ładuje tę listę tylko dla klienta i
przekazuje jako locations. Strona reservations/page.tsx nadal buduje własne
locationOptions (obiekty bieżącego miasta) dla mobilnego panelu przy wejściu.
Zapamiętana lokalizacja
Ciasteczko dotyczy ulicy w mieście klienta: page.tsx i selektor biorą z niego
tylko street, i tylko gdy city z ciasteczka zgadza się z pokazywanym
miastem. Zapamiętane inne miasto jest ignorowane.
- Ciasteczko
client-location(lib/location-cookies.ts) o wartościmiasto|ulica(ulica pusta dla miasta bez ulic), 30 dni,sameSite=lax. Zapis: server actionrememberClientLocation(city, street)wlib/utils/location.ts, wołany zhandleLocationChangew belce i zhandleLocationSelectwReservationsClient(mobilny panel). Odczyt:getRememberedClientLocation()— zwracanullbez ciasteczka lub poza zakresem żądania. - To celowo inne ciasteczko niż
selected-city/selected-street: tamte karmią zapisy po stronie serwera i muszą wskazywać własny klub klienta nawet wtedy, gdy przegląda korty w innym mieście (isBorrowedCity). W selektorze własne miasto to terazownCity(zpreferred_city), afallbackCitydo URL-a to zapamiętane miasto na/dashboard/reservationsalboownCitywszędzie indziej. reservations/page.tsx: bez?city=bierze zapamiętane miasto (jeśli ma korty), bez?street=— zapamiętaną ulicę, o ile dotyczy wybranego miasta i nadal w nim istnieje. Ulica, której klub już nie ma (zmiana adresu, zamknięcie obiektu), jest pomijana: filtr po nieistniejącej ulicy pokazywał „brak rezerwacji online" bez niczego w URL-u, co by to tłumaczyło. Wtedy strona wraca do całego miasta, a na mobile pyta o obiekt jeszcze raz. Selektor w belce liczy ten sam fallback (rememberedCity,rememberedStreetprzedDEFAULT_STREET), więcrouter.replace, który dopisuje parametry do URL-a, zgadza się z pierwszym renderem.- Pracownicy ciasteczka nie zapisują ani nie czytają.
Komponenty
components/location/option-card-list.tsx— generyczna lista kart (OptionCard { key, label, description?, badge?, icon?, indent? },role="option",id="<prefix>-<key>").density="compact"(popover na desktopie) daje niskie wiersze bez ramek, ulice wcięte pod miastem; domyślnecomfortable(drawer na mobile) to duże karty.components/location/location-option-list.tsx—LocationOption { city, street | null, bookable }→ karty z plakietką (useLocationOptionCards), kluczlocationOptionKey(city, street).components/location/location-picker-button.tsx— żółta pigułka w belce: desktop#<prefix>-select+Popover(align="end", 380 px), mobile#<prefix>-select-mobile+Drawer; tytuł i opcjonalny opis.components/layout/global-city-select-client.tsx— wszystkie efekty korygujące URL (miasto zpreferred_city, domyślna ulica, ciasteczko lokalizacji) bez zmian. Klient: jedenLocationPickerButton(header-location) z ulicamiselectedCity(zlocations, z plakietkami),handleStreetChangezapisuje teżclient-location. Pracownik: jeden przyciskheader-locationz kluczamiALL,<miasto>(całe miasto →street=ALLgdy miasto ma wymiar ulicy, inaczej bezstreet) i<miasto>|<ulica>;locationssą ładowane także dla pracownika, więc ulice każdego miasta są znane bezfetchStreetsByCity.app/(dashboard)/dashboard/reservations/components/LocationPicker.tsx—LocationDrawer+LocationOptionListużywane przezReservationsClientwyłącznie na mobile (promptLocationOnEntry = hasLocationChoice && isMobile && !hasRememberedLocation).app/auth/login/login-entry.tsx— kafelek wybranego klubu (#selected-club) w żółtej ramce z ulicami klubu i chipem „Zmień”.
Tłumaczenia
Namespace tennis (baseline ładowany na każdej stronie, bo belka jest w
layoucie): chooseLocationTitle, chooseLocationDescription,
locationBookable, locationNotBookable, changeLocation, streetPrefix,
selectLocation.
Testy
__tests__/components/reservations-client-location-picker.test.tsx— otwarcie przy wejściu na mobile, brak panelu na desktopie / przy jednej ulicy / dla pracownika, nawigacja po wyborze (street,city, bezpage), brak nawigacji przy ponownym wyborze tej samej ulicy.__tests__/components/global-city-select-client-location-picker.test.tsx— wszystkie lokalizacje na Rezerwacjach, nawigacja zcity+street, brakstreetdla miasta bez ulic, tylko własne miasto poza Rezerwacjami, brak przycisku na stronach bez wyboru, klasyczne selecty dla pracownika, zapis ciasteczka przy wyborze, fallback URL-a z zapamiętanej lokalizacji (miasto i ulica) oraz jego ignorowanie poza Rezerwacjami.
Powiązane: Ustawienia rezerwacji — reguły, kiedy lokalizacja jest otwarta online.