Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/DavidCevallos15/Crucidrive---APP/llms.txt

Use this file to discover all available pages before exploring further.

CruciDrive uses two complementary location-related hooks. useLocation manages expo-location permissions and returns the device’s current GPS coordinates — optionally enabling continuous tracking for the driver console. useMapRegion takes those coordinates and computes a MapRegion object compatible with react-native-maps, falling back to the default Crucita region when GPS is unavailable.
expo-location permissions must be declared in app.json. CruciDrive registers both foreground and background location permissions under the expo-location plugin, with Spanish-language permission strings shown to the user on iOS and Android.

useLocation

useLocation wraps expo-location to handle the full permissions + position lifecycle. It stores coordinates and the detected sector in the Zustand useLocationStore, making the last known position available app-wide without prop-drilling.

Signature

import { useLocation } from '@/hooks/useLocation';

const {
  userCoords,
  currentSectorId,
  hasPermission,
  isTracking,
  requestPermissions,
  requestBackgroundPermissions,
  getCurrentPosition,
  startTracking,
  stopTracking,
} = useLocation(enableTracking?: boolean);
enableTracking
boolean
default:"false"
When true, the hook automatically calls startTracking() on mount and stops the watch subscription on unmount. Set to true on the driver console screen; leave false (default) on the passenger map to use one-shot position reads instead.

Return values

PropertyTypeDescription
userCoords{ lat: number; lng: number } | nullMost recent GPS coordinates from the Zustand location store
currentSectorIdstring | nullID of the Crucita sector nearest to userCoords, computed by findNearestSector
hasPermissionbooleanWhether foreground location permission has been granted
isTrackingbooleantrue while a watchPositionAsync subscription is active
requestPermissions() => Promise<boolean>Requests foreground location permission; returns true if granted
requestBackgroundPermissions() => Promise<boolean>Requests background location permission — required for driver tracking when the app is backgrounded
getCurrentPosition() => Promise<{ lat: number; lng: number } | null>Reads the current position once using Location.getCurrentPositionAsync()
startTracking() => Promise<void>Starts a watchPositionAsync subscription with the configured interval and distance filter
stopTracking() => voidRemoves the watch subscription and sets isTracking to false

How tracking works

When startTracking() is called, it creates a Location.watchPositionAsync subscription using the values from LOCATION_CONFIG:
const subscription = await Location.watchPositionAsync(
  {
    accuracy:         Location.Accuracy.Balanced,
    timeInterval:     LOCATION_CONFIG.driverUpdateIntervalMs, // 5 000 ms
    distanceInterval: LOCATION_CONFIG.distanceFilterMeters,   // 10 m
  },
  (location) => {
    const coords = { lat: location.coords.latitude, lng: location.coords.longitude };
    setUserCoords(coords);
    const nearestSector = findNearestSector(coords.lat, coords.lng);
    setCurrentSector(nearestSector.id);
  }
);
Each GPS update also runs findNearestSector, which uses a Euclidean distance comparison across the five Crucita sectors to determine which sector the driver is currently in.

useMapRegion

useMapRegion is a thin memoization wrapper that converts a Coordinates object (or null) into the MapRegion shape expected by react-native-maps<MapView region={...} /> prop.

Signature

import { useMapRegion } from '@/hooks/useMapRegion';

const region = useMapRegion(userCoords: Coordinates | null): MapRegion;
userCoords
Coordinates | null
required
The { lat, lng } object from useLocation. Pass null to fall back to the default Crucita region.

Return type

interface MapRegion {
  latitude:       number;
  longitude:      number;
  latitudeDelta:  number;
  longitudeDelta: number;
}
When userCoords is null — GPS denied or not yet resolved — the hook returns LOCATION_CONFIG.defaultRegion, centring the map on Crucita:
{
  latitude:       -1.0448,
  longitude:      -80.5432,
  latitudeDelta:   0.02,
  longitudeDelta:  0.02,
}
The result is memoized via useMemo and only recomputes when userCoords changes, preventing unnecessary <MapView> re-renders.

Location config constants

Both hooks are governed by the LOCATION_CONFIG object in src/constants/config.ts:
ConstantValueEffect
driverUpdateIntervalMs5000Drivers push a GPS update to the server every 5 seconds
distanceFilterMeters10A GPS event is only emitted after the device has moved at least 10 metres
defaultRegion.latitude-1.0448Map fallback latitude — Crucita town centre
defaultRegion.longitude-80.5432Map fallback longitude — Crucita town centre
defaultRegion.latitudeDelta0.02~2.2 km vertical map span
defaultRegion.longitudeDelta0.02~2.2 km horizontal map span

Usage — passenger map screen

For passengers, a single position read on mount is sufficient. enableTracking stays false:
import { useLocation } from '@/hooks/useLocation';
import { useMapRegion } from '@/hooks/useMapRegion';
import MapView from 'react-native-maps';

const PassengerMapScreen = () => {
  const { userCoords, currentSectorId } = useLocation();
  const region = useMapRegion(userCoords);

  return <MapView region={region} />;
};

Usage — driver console screen

Drivers need continuous tracking so their position is broadcast to nearby passengers:
import { useLocation } from '@/hooks/useLocation';
import { useMapRegion } from '@/hooks/useMapRegion';
import { useSocket } from '@/hooks/useSocket';
import { LOCATION_CONFIG } from '@/constants/config';

const DriverConsoleScreen = () => {
  // enableTracking: true starts watchPositionAsync automatically
  const { userCoords, currentSectorId } = useLocation(true);
  const region = useMapRegion(userCoords);
  const { updateLocation } = useSocket();

  useEffect(() => {
    if (!userCoords || !currentSectorId) return;

    const interval = setInterval(() => {
      updateLocation(currentSectorId, userCoords, 'disponible');
    }, LOCATION_CONFIG.driverUpdateIntervalMs);

    return () => clearInterval(interval);
  }, [userCoords, currentSectorId]);

  return <MapView region={region} />;
};
On driver screens, wire updateLocation from useSocket inside a setInterval using LOCATION_CONFIG.driverUpdateIntervalMs (5 000 ms) as the delay. This decouples the Socket.io emit cadence from the GPS polling rate, giving you independent control over how often the device samples GPS versus how often the server is notified.

Build docs developers (and LLMs) love