# react-native-ctp-odp

React Native ODP Components

## Installation

```sh
npm install react-native-ctp-odp
```

## Usage

1. Install the required packages

```sh
npm install react-native-ctp-odp
npm install react-native-webview
```

2. Import JMapView object (and types)

```js
import {
  // types
  MAP_TAP_EVENT_TYPE,
  // Objects
  JMapView,
  Utilities,
} from 'react-native-ctp-odp';
```

3. Add a JMapView

```js
const mapRef = useRef<MAP_VIEW_REFERENCE_TYPE>(null);

<JMapView
    style={{ width: "100%", height: "100%" }}
    ref={mapRef}
    onMapMessage={{
        callbacks...
    }}
/>
```

## JMapView Methods

Map methods can be called by adding a refence to the JMapView object. All of the available methods should be visible and typed through typescript.

```js
const mapRef = useRef < MAP_VIEW_REFERENCE_TYPE > null;
<JMapView ref={mapRef} />;

if (mapRef.current) mapRef.current.clearWayfindingPath();
```

```js
  /**
   * Set map venue. Used for changing the map venue. Map may be unresponsive until the onVenueLoaded callback is triggered
   *
   * @param credentials - Map credentials object
   * @param mapOptions - Map options, including styles, user settings, etc.
   */
  setMapVenue: (
    credentials: MAP_CREDENTIALS_TYPE,
    mapOptions?: MAP_OPTIONS_TYPE
  ) => void;

  /**
   * Center map on current user location
   *
   * @param options.zoom - Optional, set zoom level
   * @param options.rotation - Optional, map orientation in degrees
   * @param options.animationDuration - Optional, set animation duration, in ms
   */
  centerMapOnUser: (options: MAP_CENTER_USER_OPTIONS_TYPE) => void;

  /**
   * Center map on specified location. If you are intending to continually follow the user, see setFollowBlueDot
   *
   * @param options.point - [x, y] or [lat, lng], dependent on format param
   * @param options.format - 'X_Y' or 'LAT_LONG'
   * @param options.zoom - Optional, set zoom level. Defaults to 5
   * @param options.rotation - Optional, map orientation in degrees. Defaults to 0
   * @param options.animationDuration - Optional, set animation duration, in ms. Defaults to 1000ms
   */
  centerMapOnPoint: (options: MAP_CENTER_OPTIONS_TYPE) => void;

  /**
   * Focus map to specific view bounds. Used for zooming to a specific area of the map
   *
   * @param options.topLeft - Location of top left corner of view bounds, [x, y] or [lat, lng], dependent on format param
   * @param options.bottomRight - Location of bottom right corner of view bounds, [x, y] or [lat, lng], dependent on format param
   * @param options.format - 'X_Y' or 'LAT_LONG'. Defaults to 'LAT_LONG'
   * @param options.rotation - Optional, map orientation in degrees. Defaults to 0
   * @param options.animationDuration - Optional, set animation duration, in ms. Defaults to 1000ms
   */
  setMapViewBounds: (options: MAP_ZOOM_BOUNDS_OPTIONS_TYPE) => void;

  /**
   * Focus map to currently displayed path. If you want the map to automatically center on the path, use the shouldFocus parameter on the drawNavigationPath method
   *
   * @param options.margin - Percentage to pad edges of path, 0-1. 0.25 = 12.5% padding on each side
   * @param options.rotation - Optional, map orientation in degrees. Defaults to 0
   * @param options.animationDuration - Optional, set animation duration, in ms. Defaults to 1000ms
   */
  setMapViewToPath: (options: MAP_ZOOM_TO_PATH_OPTIONS_TYPE) => void;

  /**
   * Set the map to follow the user location
   *
   * @param enabled - Percentage to pad edges of path, 0-1
   * @param rotate - Optional, indicate whether to rotate map with user heading. Defaults to false
   * @param interval - Optional, set the update interval, in ms. Defaults to 500ms
   */
  setFollowBlueDot: (
    enabled: boolean,
    rotate?: boolean,
    interval?: number
  ) => void;

  /**
   * Update the position of the user, by lat/long. This is expected to be joined with the ODP onNavigationUpdate method output
   *
   * @param lat - latitude of the user, in degrees
   * @param long - longitude of the user, in degrees
   * @param heading - Current heading of the user, in degrees
   * @param confidence - Confidence of new location, 0-100 (100 is extremely confident). Used to filter the user location
   */
  setUserPosition: (
    lat: number,
    long: number,
    heading: number,
    confidence: number
  ) => void;

  /**
   * Update the position of the user, in map coordinates
   *
   * @param x - x coordinate of user, in map coordinates
   * @param y - y coordinate of user, in map coordinates
   * @param heading - Current heading of the user, in degrees
   * @param confidence - Confidence of new location, 0-100 (100 is extremely confident). Used to filter the user location
   */
  setUserPositionXY: (
    x: number,
    y: number,
    heading: number,
    confidence: number
  ) => void;

  /**
   * Erase all wayfinding paths currently displayed and associated markers
   */
  clearWayfindingPath: () => void;

  /**
   * Generate a navigation path from the user's current location to the specified waypoint. This will trigger the onNavigationPathGenerated callback when complete
   *
   * @param waypointId - Jibestream waypoint ID for destination. Can be retrieved from the onSearchDestinationsGenerated callback
   */
  wayfindToWaypoint: (waypointId: number) => void;

  /**
   * Generate a navigation path between two specified waypoints. This will trigger the onNavigationPathGenerated callback when complete
   *
   * @param originId - Jibestream waypoint ID for origin. Can be retrieved from the onSearchDestinationsGenerated callback
   * @param destinationId - Jibestream waypoint ID for destination. Can be retrieved from the onSearchDestinationsGenerated callback
   */
  wayfindBetweenWaypoints: (originId: number, destinationId: number) => void;

  /**
   * Draw an already generated navigation path, using the path ID from the onNavigationPathGenerated callback
   *
   * @param pathId - Path ID from onNavigationPathGenerated callback
   * @param shouldFocus - If true, map will center on path after path is drawn
   * @param style - Add custom styles to path
   * @param originIcon - Image object for icon to place at path origin
   * @param destinationIcon - Image object for icon to place at path destination
   */
  drawNavigationPath: (
    pathId: string,
    {
      shouldFocus,
      style,
      originIcon,
      destinationIcon,
    }: {
      shouldFocus?: boolean;
      style?: JIBESTREAM_STYLE_TYPE;
      originIcon?: MAP_IMAGE_TYPE;
      destinationIcon?: MAP_IMAGE_TYPE;
    }
  ) => void;

  /**
   * Style all units corresponding to the specified destination
   *
   * @param destinationId - ID of destination
   * @param style - Style to apply to units
   */
  styleUnitsForDestination: (
    destinationId: number,
    style?: JIBESTREAM_STYLE_TYPE
  ) => void;

  /**
   * Add a custom icon to the map
   *
   * @param coordinates - [x, y] or [lat, lng], dependent on format param
   * @param coordType - 'X_Y' or 'LAT_LONG'. Defaults to 'LAT_LONG'
   * @param icon - Icon to place on map
   */
  addMapIcon: (
    coordinates: number[],
    coordType: COORDINATE_TYPE,
    icon: MAP_IMAGE_TYPE
  ) => void;
```

## JMapView Callbacks

Map callback methods are specified through the onMapMessage property.

```js
<JMapView
  onMapMessage={{
    onMapTappedGeneric: (event: MAP_TAP_EVENT) => {
      console.log(event.localPoint);
    },
  }}
/>;

if (mapRef.current) mapRef.current.clearWayfindingPath();
```

```js
  /**
   * Callback method triggered when a navigation path and instructions are generated by the GUI, most likely from the wayfindToWaypoint or wayfindBetweenWaypoints methods. If no possible routes are found after 3 attempts, an empty object will be returned (all parameters will be undefined).
   *
   * @param pathId - The ID of the generated path (originId_destinationId). Used to render path (drawNavigationPath)
   * @param instructions - Array of generated instructions
   * @param start - Start waypoint
   * @param end - End waypoint
   * @param jibestreamPath - Generated path in jibestream format
   * @param path - Generated path in GeoJSON
   */
  onNavigationPathGenerated?: (
    pathId?: string,
    instructions?: INSTRUCTION_TYPE[],
    start?: JIBESTREAM_WAYPOINT_TYPE,
    end?: JIBESTREAM_WAYPOINT_TYPE,
    jibestreamPath?: JIBESTREAM_PATH_TYPE[],
    path?: GEOJSON_PATH_TYPE
  ) => void;

  /**
   * Callback method triggered when the user strays off of the navigation path. This method is only triggered if the autoReroute option is set to true in the mapOptions object. If no possible routes are found after 3 attempts, an empty object will be returned (all parameters will be undefined).
   *
   * @param pathId - The ID of the generated path (originId_destinationId). Used to render path (drawNavigationPath)
   * @param instructions - Array of generated instructions
   * @param start - Start waypoint
   * @param end - End waypoint
   * @param jibestreamPath - Generated path in jibestream format
   * @param path - Generated path in GeoJSON
   */
  onRerouteNavigationPathGenerated?: (
    pathId?: string,
    instructions?: INSTRUCTION_TYPE[],
    start?: JIBESTREAM_WAYPOINT_TYPE,
    end?: JIBESTREAM_WAYPOINT_TYPE,
    jibestreamPath?: JIBESTREAM_PATH_TYPE[],
    path?: GEOJSON_PATH_TYPE
  ) => void;

  /**
   * Callback method triggered when the user position changes
   *
   * @param userPosition - [x, y] of the user in map coordinates
   */
  onUserPositionUpdated?: (userPosition: number[]) => void;

  /**
   * Callback method triggered when the map generates the set of possible destinations, triggered on load an after setMapVenue
   *
   * @param destinations - Array of destinations
   */
  onSearchDestinationsGenerated?: (
    destinations: JIBESTREAM_DESTINATION_TYPE[]
  ) => void;

  /**
   * Callback method triggered when the module encounters an error. Intended for logging only
   *
   * @param msg - Error message, human readable
   */
  onError?: (msg: string) => void;

  /**
   * Callback method triggered when the map venue is fully initialized. The map is now ready to be used
   *
   * @param venueId - ID of the venue which finished initializing
   */
  onVenueLoaded?: (venueId: number) => void;

  /**
   * Callback method triggered when the map is tapped
   *
   * @param event - Location and destination (if available) of tapped location
   */
  onMapTappedGeneric?: (event: MAP_TAP_EVENT_TYPE) => void;

  /**
   * Callback method the user enters or exits a geofence (configured on {@link https://maps.jibestream.com/geofence-manager})
   *
   * @param entered - True if user entered geofence(s), false if user exited geofence(s)
   * @param geofences - Array of geofences the user entered or exited
   */
  onGeofencesChanged?: (
    entered: boolean,
    geofences: JIBESTREAM_GEOFENCE_TYPE[]
  ) => void;

  /**
   * Callback method the path simulator status changes
   *
   * @param status - Status of current path simulation, including state (active/paused), current location, and time remaining
   */
  onSimulationStatusChanged?: (status: SIMULATION_STATUS_TYPE) => void;
```

## Map Options Object

```js
export type MAP_OPTIONS_TYPE = {
  snap?: {
    grid?: boolean, // Snap to grid - if true, user position will snap to the nearest waypoint or edge, regardless of whether the user is wayfinding or not
    waypoint?: boolean, // Snap to waypoint - if true, user position will snap to the nearest waypoint, regardless of whether the user is wayfinding or not
    path?: boolean, // Snap to path - if true, user position will snap to the nearest location along the wayfinding path
    pathThreshold?: number, // - Snap to path threshold - distance in meters from the path to snap to
  },
  user?: MAP_IMAGE_TYPE & {
    maxSpeed?: number, // Maximum speed of user, in pixels/s (there are between 17 and 70 pixels per meter, depending on the map scale)
  },
  userCircle?: {
    delayBetweenPulses?: number, // Delay between user location circular pulses, in seconds
    pulseAnimationDuration?: number, // Duration of user location circular pulse animation, in seconds
    confidenceColor?: string, // Color of user location confidence circle, in hex
    confidenceOpacity?: number, // Opacity of user location confidence circle, 0-1
    confidenceRadius?: number, // Radius of user location confidence circle, in meters
  },
  navigation?: {
    autoReroute?: boolean, // Automatically reroute user if they stray off the path (see autoRerouteThreshold)
    autoRerouteThreshold?: number, // Distance in meters from the path to trigger reroute
    directionsUnit?: DISTANCE_UNIT_TYPE, // Unit of distance for directions, used by geojson path generator ['METERS' | 'FEET' | 'INCHES']
  },
};
```

## JOdpViewModule Methods

The JODPView module can be used to get a users location from the navigation beacons. This module can be initialized as shown below:

```js
const odpRef = useRef < ODP_VIEW_REFERENCE_TYPE > null;
<JOdpViewModule ref={odpRef} />;

if (odpRef.current) odpRef.current.startOdp('key', 'host');
```

```js
  /**
   * Start the ODP solution. Should trigger onReady and onKeyValidation callbacks, then consistent navigation updates
   *
   * @param key - ODP authentication key
   * @param host - IP address of authentication server
   * @param interval - How often the navigation reading should update measured in ms. Defaults to 1000 ms.
   */
  startOdp: (key: string, host: string, interval_ms: number=1000) => void;

  /**
   * Stop ODP positioning updates
   */
  stopOdp: () => void;

  /**
   * Upload ODP logs to Jibestream team for manual review
   */
  uploadLogs: () => void;
```

## JOdpViewModule Callbacks

The JOdpView module can be used to get a users location from the navigation beacons. This module can be subscribed to as shown below:

```js
<JOdpViewModule
  ref={odpRef}
  onOdpEvent={{
    onReady: (event) => console.log('ODP onReady', event),
    onKeyValidation: (event) => console.log('ODP onKeyValidation', event),
    onNavigationUpdate: (event) => console.log('ODP onNavigationUpdate', event),
    onFacilityUpdate: (event) => console.log('ODP onFacilityUpdate', event),
  }}
/>
```

```js
  /**
   * Callback method ODP ready state has changed
   *
   * @param message - Status of ready state
   */
  onReady?: (message: ODP_ON_READY_TYPE) => void;

  /**
   * Callback method ODP key validation has occurred
   *
   * @param message - Status of key validation (if false, host/key is invalid)
   */
  onKeyValidation?: (message: ODP_ON_KEY_VALIDATION_TYPE) => void;

  /**
   * Callback method ODP new location emitted. The user location will not change unless the setUserPosition method is called with the new location
   *
   * @param message - Location object
   */
  onNavigationUpdate?: (message: ODP_ON_NAVIGATION_UPDATE_TYPE) => void;

  /**
   * Callback method ODP user has entered a new facility
   *
   * @param message - Metadata of facility
   */
  onFacilityUpdate?: (message: ODP_ON_FACILITY_UPDATE_TYPE) => void;
```

## Utilities Object

The Utilities object, imported alongside the JMapView, enalbles proessing of instructions.

- preProcessPath(path: JIBESTREAM_PATH_TYPE[], instructions: INSTRUCTION_TYPE[])
  - Add start and end points to instructions from path. This will enable easy generation of current instruction and distance remaining
- getCurrentInstruction(userLocation: number[], instructions: INSTRUCTION_TYPE[])
  - Get current instruction from user location and processed instructions.

4. Implement callbacks and call methods from the map reference!

See [JMapView Methods](#jmapview-methods) and [JMapView Callbacks](#jmapview-callbacks) sections

## Contributing

See the [contributing guide](CONTRIBUTING.md) to learn how to contribute to the repository and the development workflow.

## License

MIT

---

Made with [create-react-native-library](https://github.com/callstack/react-native-builder-bob)
