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
- SDK Maps para a web: o mapa e o campo de pesquisa (preenchimento automático).
- Pesquisa de códigos postais: o edifício de um código postal NIPOST e as suas entradas, as verificadas primeiro.
- Percursos no modo
okadacomfares: true: o percurso evita as estradas e as zonas onde os okadas são proibidos, e a resposta contém a tarifa.
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
- A pesquisa.
attachAutocompletesugere 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. - A porta, não o meio do edifício. Uma sugestão com um
postcodeé um edifício com código NIPOST; as suasentrancesdizem onde fica o portão, e as marcadas comoverifiedforam confirmadas por pessoas no local. - Um percurso de okada.
mode: 'okada'respeita as proibições de okadas que o N-Ways conhece;vehicleRules.avoidedlista 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 emvehicleRules.endBan. - A tarifa. Com
fares: true, cada percurso contémfares: um intervalo e umtextcomo 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.