Claude/kind ptolemy 9 mvh0 - #42
Open
fpudelko wants to merge 389 commits into
Open
Conversation
fpudelko
force-pushed
the
claude/kind-ptolemy-9Mvh0
branch
from
June 8, 2026 11:07
c6e8dd3 to
b1bb8f9
Compare
- EventRow on /wydarzenia: add visible green "Dołącz" button, "Dziś/Jutro" date format, bigger sport icon with bg-primary-50, cleaner spots label - EventCard (home/moje-gry): same date format + icon improvements - Event detail: taller hero image (h-52) with gradient overlay, info chips (date, time, cost, visibility), participant avatar strip, bigger join CTA - Use design tokens consistently: bg-canvas, text-ink, border-slate-100 throughout event detail page instead of gray-* classes - Sport filter chips: pill style, show emoji only on mobile https://claude.ai/code/session_017dvpk3tbb8nsot5XNTaS8C
Phone mockups 2, 3, 4 have dark green backgrounds — displaying them on the light canvas caused a jarring rectangular clash. Now each feature row matches its mockup: row 1 stays on bg-canvas (light phone), rows 2/3/4 use bg-[#0C1E13] dark green so dark phones blend seamlessly. Text colors updated per-row (white/primary-400 on dark, ink/slate on light). Verified with Playwright screenshots: all 4 feature rows match the Lovable design reference. https://claude.ai/code/session_017dvpk3tbb8nsot5XNTaS8C
fpudelko
force-pushed
the
claude/kind-ptolemy-9Mvh0
branch
from
June 8, 2026 11:51
4da9553 to
8ddcd4f
Compare
…atch mockup BottomNav component (md:hidden — mobile only): - Fixed bottom bar with Mecze / Znajdź grę / Moje mecze / Profil - Active tab highlighted in primary-700, safe-area-inset-bottom support - Auto spacer so content isn't hidden behind it - Added to events list, event detail, moje-gry, profil pages EventRow redesign to match Lovable mockup exactly: - Green dot indicator left of title (replaces sport emoji icon) - "Dzisiaj 18:00" date format (not "Dziś") - Progress bar showing taken/max fill with "X/Y dołączonych" - Dołącz button aligned to title row - Loading skeleton matches card structure (dot + button + rows + bar) https://claude.ai/code/session_017dvpk3tbb8nsot5XNTaS8C
…ading update - Header: replace hamburger menu with centered BOJO branding + user icon on mobile - AnnouncementBar: hide on mobile (hidden md:block) - /wydarzenia: heading changed to "Nadchodzące mecze" - /mapa: add BottomNav for consistent iOS-style navigation https://claude.ai/code/session_017dvpk3tbb8nsot5XNTaS8C
… detail - Events list: count now includes app participants (not just externalCount) - Events list: show district + "Poznań" instead of raw fieldName when district available - Event detail: remove avatar strip that duplicated participant avatars above the list https://claude.ai/code/session_017dvpk3tbb8nsot5XNTaS8C
- Remove use cases, FieldsTeaser, map preview, SportsSectionWithCounts, tournament banner from landing page - FeaturesSection: replace 4 alternating rows with 2-column phone grid using CSS phone chrome (no background clash) - Take real screenshots of the app as mockup images (events list, map) - Remove piłka ręczna from sport filters and hero copy https://claude.ai/code/session_017dvpk3tbb8nsot5XNTaS8C
…landing - CookieBanner: change mobile position bottom-3 → bottom-20 so it no longer covers the BottomNav (z-9999 was blocking z-1000 nav items) - Landing page: remove FeaturesSection entirely (phone screen mockups removed) - Header: slightly bigger tap target for mobile Zaloguj link https://claude.ai/code/session_017dvpk3tbb8nsot5XNTaS8C
- Header: restore hamburger + mobile slide drawer (was replaced with centered BOJO + bottom nav) - Remove BottomNav import and usage from wszystkich, [id], moje-gry, profil, mapa https://claude.ai/code/session_017dvpk3tbb8nsot5XNTaS8C
…in users - cykliczne: 'Czeka na otwarcie zapisów' → 'Brak terminu' (neutral, not always-shown noise) - moje-gry: remove empty state texts, hide empty sections, add 🔁 emoji to Stałe gierki link, remove subtitle - HomeHero (logged-in): replace NearbyGames with full event feed — open games with Dołącz, full/past as ghost rows so app looks alive; two quick-links (Dołącz do gry / Mapa boisk); alert button always visible https://claude.ai/code/session_017dvpk3tbb8nsot5XNTaS8C
…ue card - /wydarzenia: sport filter is now 4 large emoji pills across the screen width - Event detail: mockup-style header card — rounded photo, big title, green date pill, location, "Zapisani gracze X/Y" avatar stack, info chips, prominent "Dołącz do gry" CTA - Event detail: detailed roster gated to organizer (everyone sees avatar stack); joined players get an "Opuść" button; removed duplicate join card - Map: venue popup restyled as a card with photo + bold "Zobacz boisko" button; rounded leaflet popup corners https://claude.ai/code/session_017dvpk3tbb8nsot5XNTaS8C
Cancelled matches are excluded from the /wydarzenia feed and from the personalised home-page event feed so they never appear to users. https://claude.ai/code/session_017dvpk3tbb8nsot5XNTaS8C
The boiska map now mirrors the design mock: BOJO header, three floating filter pills (sport / date range / blisko mnie), a full-bleed map and a horizontal swipeable venue carousel pinned to the bottom — no bottom nav. Map and carousel are bidirectionally synced: selecting a pin centres that venue's card in the carousel, and scrolling the carousel flies the map to the corresponding venue. Each card shows the venue photo, game count for the chosen date range and a "Zobacz boisko" link. https://claude.ai/code/session_017dvpk3tbb8nsot5XNTaS8C
Non-organizers now only get the actions meant for them — joining and commenting. Hidden from them: - the reserve list (squad/roster info is private) - the "Zaproś" invite-link card Team line-ups remain hidden until the organizer publishes them, and the edit / "Zarządzaj wydarzeniem" / cancel / restore controls stay organizer-only as before. The organizer is now shown prominently with an avatar and name on every event. https://claude.ai/code/session_017dvpk3tbb8nsot5XNTaS8C
…lter Carousel ↔ map sync: - Debounce scroll detection (100ms) so the map only pans once scrolling settles, eliminating jitter - Scroll triggers panTo (no zoom change); map pin click triggers flyTo — source is passed to MapLayer to choose the right animation - Explicit spacer divs left/right of the card list so first and last cards snap to the centre correctly (no more half-card cutoff) - Stale cardRefs cleaned up when the filtered field list changes Filters: - Remove useless date-range dropdown - Add "Rezerwacja" toggle (bookingEnabled) — filters map + carousel - Add "Wolne" toggle (available) — filters map + carousel - Sport filter now correctly resets selection to first card - Empty-state message when all filters yield no venues Card UI: shows Rezerwacja/Wolne badges inline so users see at a glance what each venue offers. https://claude.ai/code/session_017dvpk3tbb8nsot5XNTaS8C
Previously venues were sorted by game count, so adjacent carousel cards could be on opposite sides of the city — every swipe jumped across Poznań. Now the default sort uses a Morton (Z-order curve) key computed from lat/lng, which guarantees geographic locality: adjacent items in the carousel are always physically close on the map, so swiping moves the map by one venue's distance rather than city-wide. Also call map.stop() before every panTo/flyTo to cancel any in-flight animation and prevent compounding jumps when swiping quickly. https://claude.ai/code/session_017dvpk3tbb8nsot5XNTaS8C
The sport dropdown and Blisko mnie pill were silently broken because overflow-x-auto on the pill bar clips absolutely-positioned children. Fixed by rendering the dropdown panel via createPortal into document.body at fixed coordinates (getBoundingClientRect), so no parent overflow can clip it. Filters now: Sport dropdown · Rezerwacja · Gry dziś · Blisko mnie - Removed "Wolne" (field.available is unreliable/stale data) - Added "Gry dziś" — filters to venues with at least one event today; cards also show a "📅 Gra dziś" badge when relevant https://claude.ai/code/session_017dvpk3tbb8nsot5XNTaS8C
…her cards Performance: - Add markerClusterGroup (same as main map) — 400 pins → clusters, no lag - Filter to powiat Poznański bounding box (lat 52.05-52.70, lng 16.55-17.35) - Only show venues with ≥1 useful data point (phone/website/email/ description/bookingEnabled/imageUrl) — cuts ~60% of empty stubs Names: - Strip leading "Boisko - " / "Boisko-" prefix from display names Cards: - Show surface type (e.g. "Sztuczna nawierzchnia · 👥 3 gry / tydzień") - "Hala" badge over the thumbnail for indoor venues - "⚡ Oświetlone" badge where field.lit = true - Smaller font so longer real names fit on two lines https://claude.ai/code/session_017dvpk3tbb8nsot5XNTaS8C
Previously clusters formed even at city-district scale (zoom 12). Now only truly overlapping pins merge; individual pins appear from zoom 13 onward (neighbourhood level). https://claude.ai/code/session_017dvpk3tbb8nsot5XNTaS8C
Migration 032 adds to fields table:
venue_type, dimensions_m, pitch_count, access_type,
is_verified_venue, has_stands, has_fence, condition,
ai_notes, ai_typed_at
analyze_venues.py:
Fetches Mapbox satellite tile (zoom 18, 512×512@2x) for each venue,
sends to Claude with a structured Polish prompt, writes results back.
Detects 13 attributes per venue:
- is_verified_venue — filters bad OSM entries
- venue_type — full_size/seven_a_side/five_a_side/orlik/
futsal_hall/basketball_*/volleyball_*/
tennis_outdoor/multi_sport/other
- surface — trawa_naturalna/sztuczna_trawa/tartan/
szuter/asfalt/beton/piasek/parkiet/nieznana
- is_indoor — covered hall?
- dimensions_m — e.g. "105x68", estimated from pitch lines
- pitch_count — number of separate courts at the location
- access_type — public/school/private/club/unknown
- lit — floodlight masts visible
- has_changing_rooms — changing room building visible
- has_stands — bleachers/tribune visible
- has_fence — enclosed perimeter
- condition — good/fair/poor/unknown
- ai_notes — free-form note (unusual features, uncertainty)
Usage: python analyze_venues.py --limit 5 --dry-run
https://claude.ai/code/session_017dvpk3tbb8nsot5XNTaS8C
… action - Migration 033: adds contact_visible BOOLEAN DEFAULT false to fields - api.ts toField(): phone and email only returned when contact_visible is true - updateField(): accepts contactVisible and persists it to DB - Field type: adds contactVisible?: boolean - Admin venue editor: always shows raw phone/email from DB (bypasses API gate), adds checkbox to toggle contact_visible per venue - analyze_venues.py: auto-sets map_visibility='hidden' when is_verified_venue=false, adds --model CLI arg, defaults to claude-sonnet-4-6 - GitHub Action analyze-venues-satellite.yml: manual + monthly scheduled run, cost notes (~$4–6 Sonnet / ~$1 Haiku for 400 quality venues) in comments https://claude.ai/code/session_017dvpk3tbb8nsot5XNTaS8C
…fy.py heuristic hidden = AI says it's not a real sports venue organizer_only = venue confirmed but sparse info (no type/surface/dims) public = confirmed venue with ≥2 meaningful fields or existing contact data https://claude.ai/code/session_017dvpk3tbb8nsot5XNTaS8C
…rency 1 Haiku has tighter rate limits than Sonnet — concurrency 3 caused cascading 429s. Now retries up to 5 times (2, 3, 5, 9, 17s waits) before giving up. https://claude.ai/code/session_017dvpk3tbb8nsot5XNTaS8C
The map_visibility=public filter was wrong — AI should analyze everything and set visibility itself. Also fetch phone/website/email for the visibility scoring logic. https://claude.ai/code/session_017dvpk3tbb8nsot5XNTaS8C
- VenueExplorer: desktop md+ shows fixed sidebar (380px) with filters + scrollable venue list; map fills remaining width. Mobile keeps existing carousel overlay. - VenueCard: show venue type label (Orlik/Piątka/Hala/…), remove lighting badge, highlight selected card with ring on desktop - FilterPills extracted as shared component — rendered in sidebar (wrap) and mobile overlay (horizontal scroll) - Added venue type filter dropdown (13 types from AI analysis) - types/index.ts + api.ts: map venue_type, dimensions_m, access_type, condition, is_verified_venue, ai_typed_at from DB - analyze_venues.py: 429 retry waits changed from 2/3/5/9s to 30/60/90/120s (API has per-minute rate limits, short waits were useless) https://claude.ai/code/session_017dvpk3tbb8nsot5XNTaS8C
…) on PromiseLike Supabase .single() returns PromiseLike which lacks .catch()/.finally(). https://claude.ai/code/session_017dvpk3tbb8nsot5XNTaS8C
…t column - Default model: claude-sonnet-4-6 (Haiku misclassified bars as pitches) - New AI field: sports[] — lists playable sports from satellite view using app's sport taxonomy (piłka nożna / futsal / koszykówka / siatkówka / tenis…) - build_update: merges AI-detected sports with existing OSM sports (deduped); --overwrite replaces instead of merging - Removes dependency on blunt "multi_sport" type for sport filter accuracy - max_tokens: 512→600 for longer sports array output - GitHub Action default updated to Sonnet https://claude.ai/code/session_017dvpk3tbb8nsot5XNTaS8C
Adds --save-images flag to analyze_venues.py that uploads each venue's satellite JPEG to the 'venue-satellites' public bucket and sets image_url in the DB. Respects --overwrite: skips upload when image already exists unless forced. Adds save_images input to the GitHub Action workflow. Also selects image_url in fetch_fields() so the existing-image check works. https://claude.ai/code/session_017dvpk3tbb8nsot5XNTaS8C
Landing page for logged-out visitors with marketing copy
Bugi UI (§5):
- sticky CTA na landingu zaslania stopke (fixed bottom-0 bez kompensacji)
- pusta strona glowna gdy brak otwartych meczow; do tego uwaga strukturalna:
LandingOpenGames filtruje taken < maxPlayers, wiec im lepiej produkt dziala
(mecze zdobywaja komplet), tym czesciej sekcja bedzie pusta
Pomysly (§8):
- zamykanie zapisow po komplecie — po zwolnieniu miejsca organizator decyduje
('Otworz zapisy'), spojne z decyzja o braku auto-awansu z rezerwy
- propozycje skladow przez graczy z glosowaniem, organizator zatwierdza
Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017dvpk3tbb8nsot5XNTaS8C
Landing dopelnia wlasne sekcje (pb-24), ale SiteFooter jest rodzenstwem <main> w app/page.tsx — poza tym dopelnieniem — wiec pasek przypiety do dolu okna przykrywal linki stopki (Prywatnosc, Regulamin, nawigacja). StickyCta obserwuje teraz takze stopke (#site-footer) i chowa sie, gdy ta wejdzie w widok. Na dole strony jest juz LandingFinalCta, wiec sticky bar w tym miejscu i tak nic nie wnosil. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017dvpk3tbb8nsot5XNTaS8C
Dotad po wypisaniu sie gracza miejsce wracalo do wspolnej puli i bral je pierwszy, kto kliknal 'Dolacz' — rowniez ktos z zewnatrz, z pominieciem rezerwy. Teraz miejsce jest OFEROWANE pierwszej osobie z rezerwy, ktora ma ograniczony czas na 'Wchodze' / 'Odpuszczam'; potem oferta idzie do kolejnej. Zachowana zasada braku cichego awansu: rezerwowy musi kliknac sam. - migracja 058: events.reserve_claim_hours (1-72h, domyslnie 3), event_participants.claim_offered_at + claim_passed, funkcja sync_reserve_claim(event_id) SECURITY DEFINER - kolejke rusza wejscie na strone meczu (brak backendu/crona), wiec funkcja jest idempotentna; wolana tez po wypisaniu i po odrzuceniu oferty - miejsce pod aktywna oferta liczy sie jako zajete — nikt z zewnatrz go nie podbierze w trakcie okna - kto przepuscil, zostaje na liscie (organizator moze awansowac recznie), ale nie blokuje kolejki; goscie bez konta pomijani - organizator ustawia dlugosc okna w formularzu tworzenia i edycji - widok organizatora oznacza 'czeka na decyzje' / 'przepuscil(a)' Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017dvpk3tbb8nsot5XNTaS8C
Dotad sklady ustalal wylacznie organizator. Teraz uczestnik moze zaproponowac wlasny podzial, reszta go popiera, a organizator jednym kliknieciem przenosi wybrana propozycje na realne druzyny. Rozdzial rol (najwazniejsze, zeby nie pomieszac): - uczestnik uklada propozycje i popiera cudze; nie widzi kontrolek organizatora i NICZEGO nie zmienia w skladzie - organizator nie proponuje (ustawia wprost w panelu obok), za to jako jedyny widzi 'Zatwierdz' - propozycja nie dotyka event_participants.team dopoki nie zostanie zatwierdzona — zyje w osobnych tabelach - migracja 059: team_proposals / team_proposal_picks / team_proposal_votes z RLS (proponowac i glosowac moze tylko uczestnik, zatwierdzac tylko organizator) + accept_team_proposal() SECURITY DEFINER - TeamsPanel dostal variant='propose': chowa plakietke stanu publikacji i przelacznik publikacji, naglowek mowi 'Twoja propozycja' - jedna aktywna propozycja na osobe i mecz — kolejna zastepuje poprzednia Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017dvpk3tbb8nsot5XNTaS8C
…cja osobnej bazy seed_test_data.sql rozszerzony z 20 do 25 wydarzen: - 21: aktywna oferta zwolnionego miejsca (test 'Wchodze'/'Odpuszczam') - 22: oferta wygasla — wejscie na strone ma ja wygasic i przekazac dalej - 23: ktos juz przepuscil, oferta u kolejnego, przepuszczony zostaje na liscie - 24: dwie propozycje skladow z glosami (test rozdzialu rol organizator/uczestnik) - 25: propozycja zatwierdzona, sklady opublikowane docs/baza-danych.md: nowa sekcja 'Osobna baza (dev / preview)' — jak postawic drugi projekt Supabase i przepiac na niego preview, zeby testy nie pisaly do produkcji. Doszly tez nowe tabele (team_proposal*) i funkcje RPC w mapach. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017dvpk3tbb8nsot5XNTaS8C
Postawienie nowego projektu Supabase wymagalo uruchomienia ~60 plikow po kolei — prosta droga do pominiecia jednego i szukania, czemu apka rzuca bledem o nieznanej kolumnie. scripts/build-db-bundles.mjs skleja migracje w 3 czesci + seedy w czwarta. Wynik w supabase/bundles/ jest commitowany, zeby dalo sie go otworzyc na GitHubie i skopiowac bez klonowania repo. Po dodaniu migracji: uruchom generator ponownie i zacommituj wynik. Paczka z seedami dokłada konta organizatorow zakladane haslem — swiezy projekt nie ma jeszcze Google OAuth, a seed_test_data.sql tych kont wymaga. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017dvpk3tbb8nsot5XNTaS8C
…ezerwy dla zapisanych
…s. przez OR w harmonogramie)
…em, kontakty, adresy)
Strona główna zalogowanego wciąż otwierała się marketingowym hero
("Znajdź mecz. Albo stwórz własny.") — sprzedaż produktu komuś, kto
już go używa. Serwer nie wiedział, kto jest zalogowany, więc
zalogowany widział na moment landing dla gości, zanim JS zdążył
odczytać sesję z localStorage. Dashboard robił 7-8 zapytań do
Supabase na każde wejście, a mecz z imiennym zaproszeniem do grupy
pokazywał się dwa razy.
Nowy dashboard: kompaktowe powitanie + karta najbliższego meczu
zamiast hero, jedna wspólna warstwa danych (useDashboardData,
Promise.allSettled), status uczestnictwa 'invited' realnie zwracany
(usuwa duplikat zaproszenia), aktywowana dolna nawigacja mobilna
(BottomNav, wcześniej gotowa ale nieużywana).
Mignięcie usunięte ciasteczkiem-wskazówką bez tokenu
(lib/sessionHint.ts) — serwer wciąż nie ma prawdziwej sesji, tylko
podpowiedź którą skorupę wyrenderować przy pierwszym responsie.
Pełna sesja serwerowa (@supabase/ssr + middleware) zostaje
świadomie osobnym, późniejszym krokiem — dotyka klienta Supabase
używanego w ~44 plikach i logowania Google, więc nie jedzie w tym
samym PR-ze co UI.
Zweryfikowane wobec produkcji przez Supabase MCP: sekcja "Otwarte
mecze" była martwa u każdego użytkownika (0 publicznych meczów na
12 nadchodzących), stąd copy stanu pustego naprawione z fałszywego
"wszystkie mają komplet" na rozróżnienie dwóch prawdziwych
przypadków. Potwierdzony też stary bug: licznik w hero pytał o
nieistniejącą kolumnę `date` zamiast `event_date` i cicho zwracał
zero.
Przebudowa dashboardu zalogowanego + koniec mignięcia landingu
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.