# React Native Customer Tracking Integration Guide This guide outlines how to connect and implement live driver location tracking in your React Native Customer App. --- ## πŸ“¦ Dependencies Install the required packages in your React Native project: ```bash npm install socket.io-client react-native-maps ``` --- ## πŸ”Œ 1. Tracking Socket Service (`trackingSocket.ts`) Create a socket helper to handle the namespace connection (`/tracking`) and events: ```typescript import { io, Socket } from "socket.io-client"; const SOCKET_URL = "http://:8000/tracking"; export interface DriverLocationUpdate { orderId: string; latitude: number; longitude: number; heading?: number; speedKph?: number; recordedAt: string; } export interface TrackingStatusUpdate { orderId: string; status: "OUT_FOR_DELIVERY" | "DELIVERED"; timestamp: string; } class TrackingSocketService { private socket: Socket | null = null; connect(token: string): Socket { if (this.socket?.connected) { return this.socket; } this.socket = io(SOCKET_URL, { auth: { token }, transports: ["websocket"], reconnection: true, }); this.socket.on("connect", () => { console.log("Connected to Tracking WebSocket Namespace"); }); this.socket.on("connect_error", (error) => { console.error("Socket Connection Error:", error); }); return this.socket; } joinOrderTracking(orderId: string) { this.socket?.emit("join_order_tracking", { orderId }); } leaveOrderTracking(orderId: string) { this.socket?.emit("leave_order_tracking", { orderId }); } onDriverLocationUpdate(callback: (data: DriverLocationUpdate) => void) { this.socket?.on("driver_location_update", callback); } onOrderStatusUpdate(callback: (data: TrackingStatusUpdate) => void) { this.socket?.on("order_tracking_status", callback); } disconnect(orderId: string) { if (this.socket) { this.leaveOrderTracking(orderId); this.socket.off("driver_location_update"); this.socket.off("order_tracking_status"); this.socket.disconnect(); this.socket = null; } } } export const trackingSocketService = new TrackingSocketService(); ``` --- ## πŸͺ 2. Customer Tracking Hook (`useOrderTracking.ts`) Manage room state subscription, events listening, and automatic teardown on component unmount: ```typescript import { useEffect, useState } from "react"; import { trackingSocketService, DriverLocationUpdate } from "./trackingSocket"; export function useOrderTracking(orderId: string, userJwtToken: string) { const [driverLocation, setDriverLocation] = useState(null); const [orderStatus, setOrderStatus] = useState(null); useEffect(() => { if (!orderId || !userJwtToken) return; const socket = trackingSocketService.connect(userJwtToken); trackingSocketService.joinOrderTracking(orderId); trackingSocketService.onDriverLocationUpdate((data) => { if (data.orderId === orderId) { setDriverLocation(data); } }); trackingSocketService.onOrderStatusUpdate((data) => { if (data.orderId === orderId) { setOrderStatus(data.status); } }); return () => { trackingSocketService.disconnect(orderId); }; }, [orderId, userJwtToken]); return { driverLocation, orderStatus }; } ``` --- ## πŸ—ΊοΈ 3. Tracking Screen Component Render Google Maps with the destination address, live driver position, and auto-camera alignment: ```tsx import React, { useRef, useEffect } from "react"; import { StyleSheet, View, Text } from "react-native"; import MapView, { Marker, PROVIDER_GOOGLE } from "react-native-maps"; import { useOrderTracking } from "./useOrderTracking"; interface TrackingScreenProps { orderId: string; token: string; customerDropoff: { latitude: number; longitude: number }; } export default function OrderTrackingScreen({ orderId, token, customerDropoff, }: TrackingScreenProps) { const mapRef = useRef(null); const { driverLocation, orderStatus } = useOrderTracking(orderId, token); useEffect(() => { if (driverLocation && mapRef.current) { mapRef.current.animateToRegion( { latitude: driverLocation.latitude, longitude: driverLocation.longitude, latitudeDelta: 0.01, longitudeDelta: 0.01, }, 1000, ); } }, [driverLocation]); return ( {/* Customer dropoff point */} {/* Live Driver */} {driverLocation && ( πŸ›΅ )} Status:{" "} {orderStatus === "OUT_FOR_DELIVERY" ? "Out for Delivery πŸ›΅" : orderStatus || "Preparing"} {driverLocation?.speedKph !== undefined && ( Driver speed: {Math.round(driverLocation.speedKph)} km/h )} ); } const styles = StyleSheet.create({ container: { ...StyleSheet.absoluteFillObject, justifyContent: "flex-end", alignItems: "center", }, map: { ...StyleSheet.absoluteFillObject, }, driverMarker: { backgroundColor: "#FFF", padding: 6, borderRadius: 20, borderWidth: 2, borderColor: "#FF7F00", elevation: 4, }, driverEmoji: { fontSize: 20, }, statusContainer: { position: "absolute", bottom: 40, backgroundColor: "white", padding: 16, borderRadius: 12, width: "90%", elevation: 5, shadowColor: "#000", shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.25, shadowRadius: 3.84, }, statusTitle: { fontSize: 16, fontWeight: "bold", color: "#333", }, statusSubtitle: { fontSize: 14, color: "#666", marginTop: 4, }, }); ```