Ruch Manual — Gabinet Fizjoterapii
Interaktywna strona produktowa z systemem triage opartym na danych
Interaktywna strona produktowa z systemem triage opartym na danych
Standardowe strony gabinetów fizjoterapii prezentują listę usług, pozostawiając pacjentowi decyzję, które z nich dotyczą jego problemu. To tworzy tarcie: pacjent z bólem kolana musi sam rozpoznać, czy potrzebuje kineziotapingu, suchego igłowania, czy rehabilitacji pooperacyjnej. Ruch Manual rozwiązuje ten problem odwrotnie — zaczyna od symptomu. Interaktywna figura anatomiczna przyjmuje wielokrotny wybór stref bólu, a system automatycznie filtruje i rankuje usługi pod kątem dopasowania do wybranej kombinacji. Wynik jest przekazywany bezpośrednio do modalu rezerwacji jako pre-selekcja, redukując liczbę kroków do decyzji zakupowej.
Stack technologiczny
React 18 (funkcyjny, single-component)
Cały interfejs to jeden eksportowany komponent RuchManual, bez routera i bez zewnętrznej biblioteki stanu. Decyzja świadoma: projekt to landing page z modalem, nie SPA. Nadmiarowe warstwy abstrakcji byłyby technicznym długiem.
useMemo jako silnik rekomendacji
Funkcja scored rekomputuje ranking usług przy każdej zmianie selParts. Iteruje po macierzy relevance_score (wartości 1–3 per strefa ciała per usługa), sumuje wyniki i sortuje po covered (pokrycie stref), a potem po score (ważona suma). Deterministyczny algorytm triage bez ML, typowany danymi w stałej SVCS.
useCallback na handlerze togglePart
Selektywna memoizacja handlera SVG zapobiega zbędnemu re-renderowi 13 nakładek interaktywnych przy każdej zmianie stanu rodzica.
IntersectionObserver API (bez biblioteki)
Zamiast react-intersection-observer czy framer-motion, scroll-animacje obsługiwane natywnie: useEffect rejestruje observer z threshold: 0.08, który aktualizuje słownik vis (id → boolean). Klasy CSS generowane dynamicznie przez <style>{visStyle}</style> — deklaratywność bez manipulacji DOM.
SVG data-driven — 13 stref interaktywnych
SVG_ZONES to czysta tablica obiektów opisujących typ elementu SVG (ellipse, circle, rect) i parametry geometryczne. Renderowane przez <El {...p} /> z dynamicznie obliczonym fill/stroke na podstawie stanu. Dodanie nowej strefy to jeden obiekt w tablicy.
Base64 asset embedding + CSS-in-JS
Cztery obrazy i logo SVG inlinowane jako Data URI — zero zewnętrznych żądań HTTP po załadowaniu. Cały system wizualny oparty na słowniku tokenów C i jednym bloku <style> z keyframesami. clamp() do responsywności bez breakpointów mediowych w logice JS.
Najciekawsze rozwiązania techniczne
Macierz trafności usług jako model danych
Każdy rekord w SVCS zawiera pole map: Record<BodyPartId, 1|2|3> — słownik mapujący strefę ciała na wagę trafności. Funkcja scored oblicza: covered (ile stref pokryte), score (suma wag), pct (covered/selParts.length) dla paska postępu. Wynik to posortowana lista do 5 usług z animowanym wskaźnikiem trafności.
Wizard rezerwacji jako maszyna stanów opartych na jednej zmiennej step
Modal 4-krokowy (step ∈ {1,2,3,4}) z logiką kontekstową: wywołanie openBook(svcId, thId) z Body-Map pre-wypełnia selSvc/selTh i ustawia step:2, pomijając krok wyboru usługi. closeBook resetuje stan z opóźnieniem 280ms (czas animacji zamknięcia) zapobiegając flashowi pustego formularza.
Animacje scroll bez biblioteki zewnętrznej
Zamiast framer-motion (200+ kB), system animacji to 12-liniowy useEffect z IntersectionObserver i akumulatorem vis (mapa id→boolean). Klasy .fade-in.vis aplikowane przez dynamicznie generowany blok <style> — separacja logiki JS od CSS bez imperatywnych mutacji classList.
Podsumowanie
Projekt demonstruje zdolność do świadomego doboru narzędzi pod ograniczenia: single-file deployment, zero zewnętrznych zależności do obrazów i stylów, brak over-engineeringu routerem czy biblioteką stanu dla projektu, który tego nie wymaga. Algorytm Body-Map Triage to przykład myślenia produktowego wbudowanego w architekturę danych — wzorzec łatwy do rozszerzenia o backend bez zmiany logiki frontendu.
Twoja firma może być
moim kolejnym projektem
Umów 30-minutową rozmowę — opowiesz mi o firmie, a ja powiem, jak zbudowałbym dla Ciebie podobne rozwiązanie.
Bez prezentacji sprzedażowej, bez zobowiązań