N-Ways
Documentação para programadoresRecolha por um estafeta

Exemplo: recolha por um estafeta

Encontre o ponto de recolha a partir do que o cliente escreveu, leve o estafeta até lá de okada evitando as zonas de proibição, e mostre quanto rende a viagem.

Nesta página

Um estafeta recebe uma nova recolha: o cliente escreveu «Shoprite Ikeja», um código postal NIPOST ou um código GhanaPost. Este ecrã encontra o lugar, escolhe a entrada do edifício quando o N-Ways a conhece, calcula a viagem de okada até lá contornando as zonas de proibição de okadas, e mostra a duração da viagem e a tarifa a esperar.

O que usa

Use uma chave restrita ao seu site (ou à sua aplicação, numa web view) e às API Maps, Preenchimento automático, Geocodificação e Percursos.

A página

pickup.html
<!doctype html>
<html lang="pt">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>Recolha</title>
    <link rel="stylesheet" href="https://nways.ng/sdk/v1/maplibre-gl.css" />
    <style>
      body { margin: 0; font: 16px/1.4 system-ui, sans-serif }
      #map { height: 60vh }
      .panel { padding: 12px 16px }
      input { width: 100%; box-sizing: border-box; padding: 12px; font-size: 16px; border: 1px solid #b8c2bc; border-radius: 10px }
      #trip { margin-top: 12px }
      #trip b { font-size: 1.4em }
    </style>
  </head>
  <body>
    <div id="map"></div>
    <div class="panel">
      <label for="pickup">Recolha</label>
      <input id="pickup" placeholder="Endereço, código postal NIPOST ou código GhanaPost" />
      <div id="trip" aria-live="polite"></div>
    </div>
    <script type="module">
      import { attachAutocomplete, createClient, createMap, maplibregl } from 'https://nways.ng/sdk/v1/nways-maps.standalone.js'

      const key = 'A_SUA_CHAVE_API'
      const nways = createClient({ key })
      const map = createMap({ container: 'map', key, center: [3.3515, 6.6018], zoom: 13 })
      const trip = document.getElementById('trip')
      let pin = null

      // Onde está o estafeta (Allen Avenue, Ikeja, se o telemóvel não o disser).
      const here = () =>
        new Promise((done) =>
          navigator.geolocation.getCurrentPosition(
            (p) => done({ lat: p.coords.latitude, lng: p.coords.longitude }),
            () => done({ lat: 6.6018, lng: 3.3515 }),
            { enableHighAccuracy: true, timeout: 8000 },
          ),
        )

      // A melhor entrada de um código postal NIPOST: uma entrada verificada, se houver.
      async function entranceOf(place) {
        if (!place.postcode) return null
        const building = await nways.postcode(place.postcode)
        const door = building.entrances?.find((e) => e.verified) ?? building.entrances?.[0]
        return door ? door.location : null
      }

      async function plan(place) {
        trip.textContent = 'A calcular o percurso…'
        const door = await entranceOf(place).catch(() => null)
        const target = door ?? place.location
        const [lng, lat] = target.coordinates
        pin?.remove()
        pin = new maplibregl.Marker({ color: '#0b7a3e' }).setLngLat([lng, lat]).addTo(map)

        try {
          const { routes } = await nways.route({ origin: await here(), destination: { lat, lng }, mode: 'okada', fares: true })
          const r = routes[0]
          const line = { type: 'Feature', properties: {}, geometry: r.geometry }
          if (map.getSource('trip')) map.getSource('trip').setData(line)
          else {
            map.addSource('trip', { type: 'geojson', data: line })
            map.addLayer({ id: 'trip', type: 'line', source: 'trip', layout: { 'line-cap': 'round', 'line-join': 'round' }, paint: { 'line-color': '#1a73e8', 'line-width': 6 } })
          }
          const box = r.geometry.coordinates.reduce((b, c) => b.extend(c), new maplibregl.LngLatBounds(r.geometry.coordinates[0], r.geometry.coordinates[0]))
          map.fitBounds(box, { padding: 48 })

          const fare = r.fares?.find((f) => f.mode === 'okada')
          const bans = r.vehicleRules?.avoided?.length ?? 0
          trip.innerHTML = ''
          trip.append(
            Object.assign(document.createElement('b'), { textContent: `${Math.round(r.durationS / 60)} min` }),
            ` · ${(r.distanceM / 1000).toFixed(1)} km`,
            fare ? ` · tarifa ${fare.text}` : '',
            bans ? ` · evita ${bans} zona${bans > 1 ? 's' : ''} de proibição de okadas` : '',
            door ? ' · até à entrada' : '',
          )
        } catch (e) {
          // Não há percurso de okada (por exemplo, o lugar de recolha está isolado por zonas de proibição), ou um erro de chave ou de quota.
          trip.textContent = /^(OKADA_BANNED|NO_ROUTE|NO_ROAD_ROUTE)/.test(e.reason ?? '') ? 'Não há percurso de okada até lá. Experimente de carro.' : `Não foi possível calcular a viagem (${e.reason ?? e.message}).`
        }
      }

      attachAutocomplete(document.getElementById('pickup'), {
        client: nways,
        near: { lat: 6.6018, lng: 3.3515 },
        onSelect: plan,
      })
    </script>
  </body>
</html>

Como funciona

  1. A pesquisa. attachAutocomplete sugere ruas, lojas, pontos de referência e códigos enquanto o estafeta escreve, os mais próximos primeiro. Toda a pesquisa conta como uma única sessão de preenchimento automático na faturação.
  2. A porta, não o meio do edifício. Uma sugestão com um postcode é um edifício com código NIPOST; as suas entrances dizem onde fica o portão, e as marcadas como verified foram confirmadas por pessoas no local.
  3. Um percurso de okada. mode: 'okada' respeita as proibições de okadas que o N-Ways conhece; vehicleRules.avoided lista as que o percurso contornou. Se o lugar de recolha estiver numa zona de proibição, o percurso termina no limite dela e assinala-o em vehicleRules.endBan.
  4. A tarifa. Com fares: true, cada percurso contém fares: um intervalo e um text como 1 500–2 200 ₦, tirados do que os passageiros pagaram por viagens semelhantes.

Adaptá-lo

  • Kekes e carros. Use mode: 'keke' ou 'drive'; a tarifa segue o modo.
  • Códigos postais diretamente. Se os seus clientes derem um código postal NIPOST, salte a pesquisa: destination: { postcode: 'LA08A09DB09' } leva à melhor entrada do edifício.
  • Numa aplicação nativa. As mesmas chamadas existem nos SDK Android e iOS.