Wszystkie projekty PROJEKT DEMONSTRACYJNY · LANDING PAGE / REACT

Ruch Manual: Gabinet Fizjoterapii

Strona gabinetu, na której pacjent sam wskazuje, co go boli

To projekt demonstracyjny, nie wdrożenie u klienta. Zbudowałem go, żeby pokazać ten mechanizm w działaniu.

React 18 SVG interaktywny IntersectionObserver API useMemo useCallback Vite
Zobacz live Chcę coś podobnego

W skrócie

Dla kogo

Gabinety i praktyki, w których pacjent nie wie, której usługi potrzebuje: fizjoterapia, rehabilitacja, stomatologia, kosmetologia.

Problem

Pacjent z bólem kolana wchodzi na listę usług i musi sam zgadnąć, czy potrzebuje kinesiotapingu, suchego igłowania czy terapii manualnej. Część zamyka stronę i dzwoni gdzie indziej.

Co to zmienia

Klika miejsce, które boli, na rysunku ciała. Strona pokazuje pasujące usługi i wypełnia za niego formularz rezerwacji. Nie musi znać nazw zabiegów.

Strona gabinetu, na której pacjent sam wskazuje, co go boli

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.

Co z tego wynika dla Twojej firmy

Ten wzorzec przenosi się na każdą praktykę z listą usług dłuższą niż pięć pozycji. Pacjent nie musi znać się na nazwach zabiegów, żeby umówić wizytę, a Ty dostajesz zgłoszenie z opisanym problemem zamiast wiadomości „dzień dobry, bolą mnie plecy”. Techniczna strona rzeczy jest tu drugorzędna: liczy się to, że decyzja, która wcześniej stała po stronie pacjenta, przeszła na stronę.

DLA ZAINTERESOWANYCH TECHNICZNIE Na czym to zbudowałem i dlaczego akurat tak. Kliknij, żeby rozwinąć.

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

1

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.

2

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.

3

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.

Twoja firma może być
moim kolejnym projektem

Opowiedz mi o swojej firmie, a powiem, który z tych mechanizmów miałby u Ciebie sens, a który byłby wydatkiem bez pokrycia.

Porozmawiajmy →

Powiem też, czego nie warto u Ciebie robić