Skip to content

Claude/kind ptolemy 9 mvh0 - #42

Open
fpudelko wants to merge 389 commits into
creativetimofficial:masterfrom
fpudelko:claude/kind-ptolemy-9Mvh0
Open

Claude/kind ptolemy 9 mvh0#42
fpudelko wants to merge 389 commits into
creativetimofficial:masterfrom
fpudelko:claude/kind-ptolemy-9Mvh0

Conversation

@fpudelko

@fpudelko fpudelko commented Jun 6, 2026

Copy link
Copy Markdown

No description provided.

@fpudelko
fpudelko force-pushed the claude/kind-ptolemy-9Mvh0 branch from c6e8dd3 to b1bb8f9 Compare June 8, 2026 11:07
claude added 2 commits June 8, 2026 11:51
- 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
fpudelko force-pushed the claude/kind-ptolemy-9Mvh0 branch from 4da9553 to 8ddcd4f Compare June 8, 2026 11:51
claude added 26 commits June 8, 2026 12:57
…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
janbrzo and others added 30 commits August 3, 2026 22:54
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
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants