Exemple : enlèvement par un livreur
Trouvez le point d’enlèvement à partir de ce que le client a tapé, menez-y le livreur en okada en évitant les zones d’interdiction, et affichez ce que rapporte la course.
Sur cette page
Un livreur reçoit un nouvel enlèvement : le client a tapé « Shoprite Ikeja », un code postal NIPOST ou un code GhanaPost. Cet écran trouve le lieu, choisit l’entrée du bâtiment quand N-Ways la connaît, calcule la course en okada jusque-là en contournant les zones d’interdiction des okadas, et affiche la durée du trajet et le tarif à prévoir.
Ce qu’il utilise
- SDK Maps pour le web : la carte et le champ de recherche (saisie semi-automatique).
- Recherche de codes postaux : le bâtiment d’un code postal NIPOST et ses entrées, les entrées vérifiées en premier.
- Itinéraires en mode
okadaavecfares: true: l’itinéraire évite les routes et les zones où les okadas sont interdits, et la réponse contient le tarif.
Utilisez une clé restreinte à votre site web (ou à votre application, dans une web view) et aux API Maps, Saisie semi-automatique, Géocodage et Itinéraires.
La page
pickup.html
<!doctype html>
<html lang="fr">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Enlèvement</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">Enlèvement</label>
<input id="pickup" placeholder="Adresse, code postal NIPOST ou code 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 = 'VOTRE_CLE_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
// Où se trouve le livreur (Allen Avenue, Ikeja, si le téléphone ne le dit pas).
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 },
),
)
// La meilleure entrée d’un code postal NIPOST : une entrée vérifiée s’il y en a une.
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 = 'Calcul de l’itinéraire…'
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 ? ` · tarif ${fare.text}` : '',
bans ? ` · évite ${bans} zone${bans > 1 ? 's' : ''} d’interdiction des okadas` : '',
door ? ' · jusqu’à l’entrée' : '',
)
} catch (e) {
// Pas d’itinéraire en okada (par exemple, le lieu d’enlèvement est isolé par des zones d’interdiction), ou une erreur de clé ou de quota.
trip.textContent = /^(OKADA_BANNED|NO_ROUTE|NO_ROAD_ROUTE)/.test(e.reason ?? '') ? 'Pas d’itinéraire en okada jusque-là. Essayez en voiture.' : `Impossible de calculer la course (${e.reason ?? e.message}).`
}
}
attachAutocomplete(document.getElementById('pickup'), {
client: nways,
near: { lat: 6.6018, lng: 3.3515 },
onSelect: plan,
})
</script>
</body>
</html>Comment ça marche
- La recherche.
attachAutocompletepropose des rues, des commerces, des repères et des codes pendant que le livreur tape, les plus proches en premier. Toute la recherche compte pour une seule session de saisie semi-automatique dans la facturation. - La porte, pas le milieu du bâtiment. Une suggestion avec un
postcodeest un bâtiment doté d’un code NIPOST ; sesentrancesdisent où se trouve le portail, et celles marquéesverifiedont été confirmées par des gens sur place. - Un itinéraire en okada.
mode: 'okada'respecte les interdictions d’okada que N-Ways connaît ;vehicleRules.avoidedliste celles que l’itinéraire a contournées. Si le lieu d’enlèvement est dans une zone d’interdiction, l’itinéraire s’arrête à sa limite et le signale dansvehicleRules.endBan. - Le tarif. Avec
fares: true, chaque itinéraire contientfares: une fourchette et untextcomme 1 500–2 200 ₦, tirés de ce que les passagers ont payé pour des courses semblables.
L’adapter
- Kekes et voitures. Utilisez
mode: 'keke'ou'drive'; le tarif suit le mode. - Directement les codes postaux. Si vos clients donnent un code postal NIPOST, passez la recherche :
destination: { postcode: 'LA08A09DB09' }mène à la meilleure entrée du bâtiment. - Dans une application native. Les mêmes appels existent dans les SDK Android et iOS.