Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/jhonyes04/new-wayfy/llms.txt

Use this file to discover all available pages before exploring further.

WayFy’s Accessibility Map is the core feature of the platform — an interactive Mapbox GL map that overlays real OpenStreetMap wheelchair-accessibility data on top of a location-aware map view. As you pan and zoom the map, data is streamed in progressively from the Overpass API across three query phases, filtered in real time by both accessibility level and place category. Community-submitted pins sit as a second data layer alongside OSM data, so travelers benefit from both authoritative tagging and lived experience.

How the Map Works

The map is driven by the useAccessibilityMap hook (hooks/useAccessibilityMap.jsx). On load it requests the browser’s geolocation, flies to the user’s coordinates at zoom level 14, and triggers the first Overpass data fetch. As the user pans or zooms, a 300 ms debounce fires a fresh fetch for the new bounding box. All in-flight requests are cancelled via AbortController when a new move event arrives, keeping the map responsive.
The map does not load OSM data below zoom level 14. If you zoom out past that threshold, the POI layer is cleared and a prompt asks you to zoom in closer.

Map Style Selector

The MapStyleSelector component lets users switch between Mapbox base styles (Streets, Satellite, Outdoors, Light, Dark) without reloading any data. The style choice persists while the session is active.

Layer Architecture

The map registers four interactive Mapbox GL layer IDs in interactiveLayerIds, all managed through the layers object returned by useAccessibilityMap:

clusters

Circle clusters that group nearby OSM points. Color steps from teal (≤9 points) → sky blue (10–49) → soft red (50+). Clicking a cluster zooms to its expansion level.

unclustered-point

Individual OSM wheelchair-tagged nodes. Color encodes the wheelchair tag value: green (yes), amber (limited), red (no), grey (unknown/absent).

community-approved

Community pins that have been approved by an admin. Rendered as solid purple circles (#8b5cf6) with a white stroke.

community-pending

The current user’s own pending community pins, shown at 45% opacity so they are visually distinct from approved data.
A fifth layer, cluster-count, is also rendered as a symbol on top of each cluster circle showing the abbreviated point count in white DIN Offc Pro Medium text. It is not included in interactiveLayerIds because click events are handled by the clusters layer beneath it.

OSM Data Flow via Overpass API

Wheelchair data is fetched by fetchWheelchairPlacesProgressive in services/overpass.api.js. Each call fires three sequential Overpass QL queries and calls onPartialData after each one completes, so the map populates incrementally rather than waiting for all three to finish.

Query Phases

1

Phase 1 — Direct wheelchair tags

Fetches all OSM nodes, ways, and relations that carry a wheelchair tag directly. This is the fastest phase and gives the clearest signal: the mapper explicitly evaluated the place.
[out:json][timeout:25];
(
  node["wheelchair"]({{bbox}});
  way["wheelchair"]({{bbox}});
  relation["wheelchair"]({{bbox}});
);
out body;
>;
out skel qt;
2

Phase 2 — Amenities, shops, and tourism with accessibility tags

Fetches all amenity, shop, and tourism nodes in the bounding box, then filters to those carrying any of the following accessibility-related tags: wheelchair, wheelchair:description, wheelchair:access, entrance:wheelchair, door:width, door:automatic, door:bell, kerb, incline, tactile_paving, or toilets:wheelchair.
[out:json][timeout:40];
(
  node["amenity"]({{bbox}});
  node["shop"]({{bbox}});
  node["tourism"]({{bbox}});
);
(
  ._;
  node(w)["wheelchair"];
  node(w)["wheelchair:description"];
  node(w)["wheelchair:access"];
  node(w)["entrance:wheelchair"];
  node(w)["door:width"];
  node(w)["door:automatic"];
  node(w)["door:bell"];
  node(w)["kerb"];
  node(w)["incline"];
  node(w)["tactile_paving"];
  node(w)["toilets:wheelchair"];
);
out body;
>;
out skel qt;
3

Phase 3 — Public transport and buildings

Fetches public_transport nodes and named buildings, filtering to those with accessibility-transit tags: wheelchair, wheelchair:boarding, step_free, lift, or escalator.
[out:json][timeout:40];
(
  node["public_transport"]({{bbox}});
  node["building"]["building"!="yes"]({{bbox}});
);
(
  ._;
  node(w)["wheelchair"];
  node(w)["wheelchair:boarding"];
  node(w)["step_free"];
  node(w)["lift"];
  node(w)["escalator"];
);
out body;
>;
out skel qt;

Endpoint Failover

Each Overpass query is attempted against three endpoints in order, with a 10-second timeout per attempt:
PriorityEndpoint
1 (primary)https://overpass-api.de/api/interpreter
2 (fallback)https://overpass.kumi.systems/api/interpreter
3 (fallback)https://maps.mail.ru/osm/tools/overpass/api/interpreter
If all three endpoints fail for a given phase, that phase is skipped silently and any data already loaded from earlier phases remains visible.

Wheelchair Filter Values

The activeFilters array in global state holds the currently active set of wheelchair values. The filter panel (FilterAccessibility component) toggles these; at least one value is always active.
ValueMeaningMap Color
yesFully accessible — no barriers for wheelchair usersGreen #10b891
limitedPartially accessible — usable with difficulty or assistanceAmber #ffc108
noNot accessibleRed #db3545
unknownNo accessibility tag present in OSMGrey #93a2b8

Category Filters

The activeCategories array holds the active OSM category slugs. The FilterCategories component toggles them individually or clears all at once.
SlugLabelIcon
alojamientoAlojamientosfa-bed
gastronomiaGastronomíafa-utensils
transporteTransportefa-bus
saludSaludfa-house-medical
cultura_turismoTurismofa-landmark-flag
recreacionOciofa-champagne-glasses
deporteDeportefa-volleyball
gobiernoOficinasfa-building-columns
bañosBañosfa-restroom
dineroBancosfa-money-bill-transfer
tiendasTiendasfa-bag-shopping
Deselecting all categories via the “clear all” button hides every OSM POI. Use this when you only want to see community pins or to get a clean basemap view.

Community Pins Workflow

Community pins are places submitted by logged-in WayFy users through the CustomPinPopup component. Clicking an empty spot on the map while authenticated drops a pin at that coordinate; the popup lets the user fill in a place name, sub-type, and label before submitting to POST /api/places.
1

User places a custom pin

A click on an empty map area sets customPin state in useAccessibilityMap. The CustomPinPopup renders at the pin’s coordinates and the user fills in place details.
2

Pin saved as pending

The backend creates a Place record with status: 'pending'. The pin appears immediately in the community-pending layer (semi-transparent purple) for the submitting user.
3

Admin review

An administrator reviews submitted places via /admin/places. Approving a place sets status: 'approved'.
4

Pin promoted to approved layer

Approved places are returned by GET /api/places (bbox query) and rendered in the community-approved layer (solid purple) visible to all users.

Favorites on the Map

Saved favorites are rendered as <Marker> components with a heart icon rather than as a map layer. This means they are always visible regardless of the active wheelchair filters or category filters. The useFavorites hook provides addFavorite, removeFavorite, and isFavorite methods; the heart button inside AccessibilityDetails calls these while the map reflects the updated state.

Place Detail Panel

Clicking any unclustered-point or community pin opens the AccessibilityDetails offcanvas panel. It is divided into three sections:

InfoSection

Name, address (reverse-geocoded via Nominatim), OSM type, opening hours, phone, website, and a direct link to the OSM element.

OsmAccessibilitySection

All OSM accessibility tags present on the feature: kerb type, incline, tactile paving, door width, automatic door, accessible toilets, and more — displayed with human-readable labels from OSM_TRANSLATIONS.

CommunityReviewSection

The community-sourced accessibility review for the place (wheelchair rating, ramp, elevator, accessible toilet, parking, automatic door, description, and photos). Opens AccessibilityEditor for logged-in users.
Photos attached to a community review are viewable in the PhotoLightbox component, which opens inline within the AccessibilityDetails panel.

AI Assistant Integration

The AIAssistant component sits in the bottom center of the map as a floating input bar. When a user submits a natural-language query (for example, “accessible hotels near Atocha”), the useAIAssistant hook calls fetchMapData, which posts to POST /api/ai/mapgpt and then geocodes the extracted location. On success it dispatches three global state updates simultaneously:
  • SET_SELECTED_LOCATION — flies the map to the geocoded coordinates at zoom 15
  • SET_ACTIVE_FILTERS — applies the AI-extracted wheelchair filter values
  • SET_ACTIVE_CATEGORIES — applies the AI-extracted category slugs
This replaces any manual filter selection the user had previously made. Voice input is also supported via the Web Speech API (language: es-ES); the microphone icon in the input bar toggles listening mode. See the AI Assistant page for full endpoint and prompt documentation.

Build docs developers (and LLMs) love