It doesn't draw the route from one marker to another marker

29 Views Asked by At
import { useEffect, useReducer, useContext } from "react";
import { AnySourceData, LngLatBounds, Map, Marker, Popup } from "mapbox-gl";
import { MapContext } from "./MapContext";
import { mapReducer } from "./mapRedecuer";
import { PlacesContext } from "..";
import { directionsApi } from "../../apis";
import { DirectionsResponse } from "../../interfaces/directions";
import Store from "../../icons/store.svg";

export interface MapState {
  isMapReady: boolean;
  map?: Map;
  markers: Marker[];
}

const INITIAL_STATE: MapState = {
  isMapReady: false,
  map: undefined,
  markers: [],
};

interface Props {
  children: JSX.Element | JSX.Element[];
}

export const MapProvider = ({ children }: Props) => {
  const [state, dispatch] = useReducer(mapReducer, INITIAL_STATE);
  const { places, userLocation } = useContext(PlacesContext);

  useEffect(() => {
    state.markers.forEach((marker) => marker.remove());
    const newMarkers: Marker[] = [];

    for (const place of places) {
      const [lng, lat] = place.center;
      const popup = new Popup().setHTML(`
        <h6>${place.text_es}</h6>
        <p>${place.place_name}</p>`);

      const newMarker = new Marker()
        .setPopup(popup)
        .setLngLat([lng, lat])
        .addTo(state.map!);

      newMarkers.push(newMarker);
    }

    dispatch({ type: "setMarkers", payload: newMarkers });
  }, [places]);

  const myLocationPopup = new Popup().setHTML(`
  <h4>Esoy aquí ;D</h4>
  `);

  const setMap = async (map: Map) => {
    const joseMarker = new Marker({ color: "#ea4335" })
      .setLngLat(userLocation || [0, 0])
      .setPopup(myLocationPopup)
      .addTo(map);

    joseMarker.getElement().addEventListener("click", () => {
      showRoute(userLocation || [0, 0], [-71.534412, -16.4013919]);
    });

    dispatch({ type: "setMap", payload: map });

    new Marker({
      element: createCustomMarkerElement(Store),
    })
      .setLngLat([-71.553955, -16.398312])
      .setPopup(
        new Popup().setHTML(
          '<h6>Tienda N4</h6><p style="color: red;">Deuda por vencer</p><span>Deuda: $*** <br/> Nombre: Pepe <br/> Tiempo: 2 meses</span>'
        )
      )
      .addTo(map)
      .getElement()
      .addEventListener("click", () =>
        showRoute(userLocation || [0, 0], [-71.553955, -16.398312])
      );

    // Store 2
    new Marker({
      element: createCustomMarkerElement(Store),
    })
      .setLngLat([-71.53949, -16.398466])
      .setPopup(
        new Popup().setHTML(
          '<h6>Tienda N2</h6><p style="color: green;">Sin deuda</p><span>Deuda: $0 <br/> Nombre: Juan <br/> Tiempo: 0 meses</span>'
        )
      )
      .addTo(map)
      .getElement()
      .addEventListener("click", () =>
        showRoute(userLocation || [0, 0], [-71.53949, -16.398466])
      );

    // Store 3
    new Marker({
      element: createCustomMarkerElement(Store),
    })
      .setLngLat([-71.524036, -16.398013])
      .setPopup(
        new Popup().setHTML(
          '<h6>Tienda N3</h6><p style="color: blue;">Deuda al día</p><span>Deuda: $100 <br/> Nombre: Maria <br/> Tiempo: 1 mes</span>'
        )
      )
      .addTo(map)
      .getElement()
      .addEventListener("click", () =>
        showRoute(userLocation || [0, 0], [-71.524036, -16.398013])
      );

    // Store 4
    new Marker({
      element: createCustomMarkerElement(Store),
    })
      .setLngLat([-71.52408, -16.39325])
      .setPopup(
        new Popup().setHTML(
          '<h6>Tienda N4</h6><p style="color: red;">Deuda por vencer</p><span>Deuda: $200 <br/> Nombre: Roberto <br/> Tiempo: 3 meses</span>'
        )
      )
      .addTo(map)
      .getElement()
      .addEventListener("click", () =>
        showRoute(userLocation || [0, 0], [-71.52408, -16.39325])
      );

    // Store 5
    new Marker({
      element: createCustomMarkerElement(Store),
    })
      .setLngLat([-71.519569, -16.38857])
      .setPopup(
        new Popup().setHTML(
          '<h6>Tienda N4</h6><p style="color: red;">Deuda por vencer</p><span>Deuda: $200 <br/> Nombre: Roberto <br/> Tiempo: 3 meses</span>'
        )
      )
      .addTo(map)
      .getElement()
      .addEventListener("click", () =>
        showRoute(userLocation || [0, 0], [-71.519569, -16.38857])
      );

    // Store 6
    new Marker({
      element: createCustomMarkerElement(Store),
    })
      .setLngLat([-71.532303, -16.4048])
      .setPopup(
        new Popup().setHTML(
          '<h6>Tienda N4</h6><p style="color: red;">Deuda por vencer</p><span>Deuda: $200 <br/> Nombre: Roberto <br/> Tiempo: 3 meses</span>'
        )
      )
      .addTo(map)
      .getElement()
      .addEventListener("click", () =>
        showRoute(userLocation || [0, 0], [-71.532303, -16.4048])
      );

    // Store 7
    new Marker({
      element: createCustomMarkerElement(Store),
    })
      .setLngLat([-71.538424, -16.410802])
      .setPopup(
        new Popup().setHTML(
          '<h6>Tienda N4</h6><p style="color: red;">Deuda por vencer</p><span>Deuda: $200 <br/> Nombre: Roberto <br/> Tiempo: 3 meses</span>'
        )
      )
      .addTo(map)
      .getElement()
      .addEventListener("click", () =>
        showRoute(userLocation || [0, 0], [-71.538424, -16.410802])
      );

    dispatch({ type: "setMap", payload: map });
  };

  const getRoutesBetweenPoints = async (
    start: [number, number],
    end: [number, number],
    currentState: MapState
  ) => {
    console.log("Start Coordinates:", start);
    console.log("End Coordinates:", end);
    try {
      const resp = await directionsApi.get<DirectionsResponse>(
        `/${start.join(",")};${end.join(",")}`
      );

      console.log("Respuesta de la API:", resp);

      if (
        resp.data.code === "Ok" &&
        resp.data.routes &&
        resp.data.routes.length > 0
      ) {
        const route = resp.data.routes[0];

        const { distance, duration, geometry } = route;
        const { coordinates: coords } = geometry;

        let kms = distance / 1000;
        kms = Math.round(kms * 100);
        kms /= 100;
        const minutes = Math.floor(duration / 60);
        console.log(kms, minutes);

        const bounds = new LngLatBounds(start, end);

        for (const coord of coords) {
          const newCoord: [number, number] = [coord[0], coord[1]];
          bounds.extend(newCoord);
        }

        currentState.map?.fitBounds(bounds, {
          padding: 200,
        });

        console.log("Distancia:", distance);
        console.log("Duración:", duration);
        console.log("Coordenadas de la ruta:", coords);
        console.log("Coordenadas finales de la ruta:", coords);
        const sourceData: AnySourceData = {
          type: "geojson",
          data: {
            type: "FeatureCollection",
            features: [
              {
                type: "Feature",
                properties: {},
                geometry: {
                  type: "LineString",
                  coordinates: coords,
                },
              },
            ],
          },
        };

        if (currentState.map?.getLayer("RoutesString")) {
          currentState.map.removeLayer("RoutesString");
          currentState.map.removeSource("RoutesString");
        }

        currentState.map?.addSource("RoutesString", sourceData);

        console.log("Adding layer to map");
        currentState.map?.addLayer({
          id: "RoutesString",
          type: "line",
          source: "RoutesString",
          layout: {
            "line-cap": "round",
            "line-join": "round",
          },
          paint: {
            "line-color": "black",
            "line-width": 3,
          },
        });
      } else {
        console.warn("La respuesta de la API no contiene rutas válidas.");
      }
      // eslint-disable-next-line @typescript-eslint/no-explicit-any
    } catch (error: any) {
      console.error(
        "Error al obtener las rutas:",
        error.response?.data?.message || error.message
      );
      console.error(
        "Código de respuesta:",
        error.response?.status || "Desconocido"
      );

      if (error.response?.data?.code === "NoSegment") {
        console.warn(
          "No se encontró un segmento válido para las coordenadas proporcionadas."
        );
      } else {
        console.error("Error inesperado al obtener las rutas.");
      }
    }
  };

  const showRoute = async (
    startCoords: [number, number],
    endCoords: [number, number]
  ) => {
    await getRoutesBetweenPoints(startCoords, endCoords, state);
    console.log("User Location:", userLocation);
  };

  const createCustomMarkerElement = (svgUrl: string) => {
    const customMarker = document.createElement("div");
    customMarker.innerHTML = `<img src="${svgUrl}" alt="Custom Marker"/>`;
    return customMarker;
  };

  return (
    <MapContext.Provider
      value={{
        ...state,
        setMap,
        showRoute,
        getRoutesBetweenPoints: async (startCoords, endCoords) => {
          await getRoutesBetweenPoints(startCoords, endCoords, state);
        },
      }}
    >
      {children}
    </MapContext.Provider>
  );
};

I made 4 random markers and in theory when I click on one of those stores, it should give me or draw the route where to go, but it doesn't draw anything, but it does give me everything through the browser console, it just doesn't show up in the map the route to follow

What I tried was this, however the problem persists

  • Interface and Type Verification: We confirm that the interface and data types used in the context and functions are configured correctly, especially in relation to the getRoutesBetweenPoints function.

  • Logging Coordinates and Responses: Through logs in the browser console, we have observed the start and end coordinates, as well as the responses from the address API. This was done to ensure that the coordinates and responses are as expected.

  • Comparison with Working Functionality: Code that worked, specifically code that is triggered from the search in the SearchResults component, was compared to code that did not work in the user location marker event. This helped identify differences in logic and how routes are being handled.

  • Marker Event Analysis: I have reviewed the code related to the user location marker event. Noticed that clicking this marker calls showRoute with a manually coded location instead of dynamically selecting a store.

0

There are 0 best solutions below