npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@os1-platform/dispatch-mobile

v3.0.0

Published

Dispatch SDK React Native Package

Downloads

338

Readme

React Native Dispatch SDK

Introduction

Dispatch SDK is an expo based SDK that is written in Typescript and some Modules are in Java/Kotlin. This SDK can be used to render execution task screens on UI and maintain their states.

Currently supports SDK>=21 (Android)

Dispatch SDK provides the following features:

  • Sync Manager: Provides Sync Manager for syncing events & Docs in background with retry functionality.

  • Execution Tasks: Provides a list of Execution Tasks inbuilt UIs which are as follows.

    • Deliver
    • Capture Input
    • Deliver Cash
    • Complete-Success
    • Complete-Failure
    • Pickup
    • Doodle
    • Form
    • Display
    • Verify Location
    • Verify Input
    • Scan
    • Image Capture
    • Init Payment
    • Process Payment
    • Complete Payment
    • Validate OTP
    • Collect Payment
  • Execution Engine: Provides methods for Executing a given workflow/Job in a dispatch`

  • Firebase Cloud Messaging:Provides method for receiving Firebase Cloud Messaging

  • Async storage:Provides Async storage for storing key value pairs

  • Async Events: Support for async events triggered on start and end of every execution task except end-state tasks, as for them a summary is generated at the end of completion of workflow.

    • Format of events:

      const eventName =
        `onTaskStart:{ET_Name}` |
        `onTaskEnd:{ET_name}` |
        `onTaskBack:{ET_name}` |
        `onScan:{ET_name}` |
        `onScanRemove:{ET_name}`;
    • Format of click events for collect payment ET:

      const eventName = `onClick:{clickEventName}:{etName}`
      enum clickEventName { QR_CODE, SEND_LINK, RESEND_LINK, CHECK_STATUS }
    • Usage:

      import { eventListener } from '@os1-platform/dispatch-mobile';
      eventListener.on('{eventName}', (eventData) => {
        console.log(eventData);
      });
      eventListener.remove('{eventName}');
    • Event data Payload: onTaskStart event:

        `onTaskStart:{ETCustomName}` = {
          "timestamp":"number",
          "taskId":"string",
          "etData":{
            "jobId1":{
                ...ET inputs
            },
            "jobId2":{
                ...ET inputs
            }
          }
        }

      onTaskEnd event | onTaskBack event:

        `onTaskEnd:{ETCustomName}` = {
          "timestamp": "string",
          "taskId": "string",
          "etData":{
            "jobId1":{
                "success":"boolean",
                "eventCode":"string",
                "reasonCode":"string",
                ...ET output
            },
            "jobId2":{
                "success":"boolean",
                "eventCode":"string",
                "reasonCode":"string",
                ...ET output
            }
          },
          "meta"?:{},
      }

      onClick event for QR_CODE and CHECK_STATUS

      {
        timestamp: number;
        taskId: string;
        customData?: any;
        etData: {
          ...etInput
        }
        additionalData: {
          //This is the same refId passed by the app at the start of an objective
          "refId":"string",
          //This amount  will be sum of amount for all the merged objective
          "money":{       
              "amount":"number", // sum of all the merged objectives
              "currency":"string"
          }
        }
      }

      onClick event for SEND_LINK and RESEND_LINK

      {
        timestamp: number;
        taskId: string;
        customData?: any;
        etData: {
          ...etInput
        }
        additionalData: {
          //This is the same refId passed by the app at the start of an objective
          "refId": string,
          //This amount  will be sum of amount for all the merged objective
          "money":{       
              "amount": number, // sum of all the merged objectives
              "currency": string
          }
          //This will contain either phoneNumber or email as per user selection
          "contactDetails": string,
          //Static ENV based payment landing page link
          "paymentLink": string
        }
      }

Dispatch SDK Installation

Setup Expo (For non-expo projects only)

npx install-expo-modules

Install Dispatch SDK Package

#using npm
npm install @os1-platform/dispatch-mobile

Install these dependencies

{
  "dependencies": {
    "@apollo/client": "^3.5.6",
    "@expo-google-fonts/ibm-plex-sans": "*",
    //MTS SDK has been removed as a dependency now
    //"@delhivery/platform-coreos-mts-sdk": "^2.0.3",
    "@react-native-async-storage/async-storage": "^1.15.5",
    "@react-native-community/datetimepicker": "^3.5.2",
    "@react-native-community/netinfo": "^6.0.2",
    "@react-native-community/slider": "^4.1.7",
    "@react-native-firebase/analytics": "^14.2.2",
    "@react-native-firebase/app": "^14.2.2",
    "@react-native-firebase/crashlytics": "^14.2.2",
    "@react-native-firebase/messaging": "^14.2.2",
    "@react-native-firebase/remote-config": "^14.2.2",
    "@react-navigation/native": "^6.0.6",
    "@react-navigation/native-stack": "^6.2.5",
    "@sentry/react-native": "^3.2.13",
    "axios": "^0.24.0",
    "expo": "~47.0.13",
    "expo-barcode-scanner": "~11.4.0",
    "expo-blur": "~11.0.0",
    "expo-camera": "~13.1.0",
    "expo-file-system": "~15.1.1",
    "expo-font": "~11.0.1",
    "expo-image-manipulator": "~11.0.0",
    "expo-image-picker": "~14.1.0",
    "expo-location": "~15.0.1",
    "expo-sqlite": "~11.0.0",
    "graphql": "^16.2.0",
    "react": "^18.0.0",
    "react-native": "^0.69.5",
    "react-native-dropdown-picker": "^5.4.0",
    "react-native-get-random-values": "^1.8.0",
    "react-native-paper": "^4.9.2",
    "react-native-safe-area-context": "^3.3.2",
    "react-native-screens": "^3.9.0",
    "react-native-vector-icons": "^9.0.0"
  }
}

Async Storage Size Increase

  • Add this line in gradle.properties file for increasing storage (AsyncStorage_db_size_in_MB=10)

Changes in Android Manifest File (Android only)

android:allowBackup="false"
tools:replace="android:allowBackup"
<activity
      android:name=".MainActivity"
      android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode"
      android:label="@string/app_name"
      android:launchMode="singleTask"
      android:windowSoftInputMode="adjustResize"
      android:exported="true">

Add jcenter() if not added already added in the Project-level build.gradle (/build.gradle): (Android only)

buildscript {

    repositories {
        ...
        jcenter()
    }
}

allprojects {
    repositories {
        ...
        jcenter()
        ...
    }
}

Fix for Apollo GraphQL Client (metro.config.js)

Add the following changes in metro.config.js file

Issue Link https://github.com/apollographql/apollo-client/releases/tag/v3.5.4

const { getDefaultConfig } = require('metro-config');
const { resolver: defaultResolver } = getDefaultConfig.getDefaultValues();
exports.resolver = {
  ...defaultResolver,
  sourceExts: [...defaultResolver.sourceExts, 'cjs'],
};

Dispatch SDK Usage

Init Dispatch SDK

interface EventMapping {
  eventCode: string;
  successEvent: boolean;
  description: string;
}

interface DispatchSDKConfig {
  ...previous configs
  debugLevelLog?: Boolean;
  callbacks?: {
    fetchPhoneNumbersCallback?: (sdsIds: string[]) => Promise<{ key: string; value: string[]}>;
  };
}


const fetchPhoneNumbersCallback = (ids: string[]) => {
  console.log('sds ids: ', ids);
  return {
    key: 'phoneNumber', //This key is same, what was being sent in meta as key
    value: ['8888888888'],
  };
};

import { DispatchSDKManager } from '@os1-platform/dispatch-mobile';

await DispatchSDKManager.getInstance().initDispatchSDK({
  userName: 'testuser',
  userID: 'testID',
  tenantID: tenantId,
  tenantBaseURL: 'baseURL',
  accessToken: 'accessToken',
  headers: {
    'x-user-id': 'testID',
    'x-coreos-tid': tenantId,
    'x-coreos-access': accessToken,
    'Content-Type': 'application/json',
    'x-coreos-request-id': new Date().getTime(),
    'x-coreos-userinfo': JSON.stringify({ id: 'testID' }),
  },
  // Used for Scan ET dropdown list => eventMapping: EventMapping[]
  eventMapping: [
    {
      eventCode: 'E-010',
      successEvent: true,
      description: 'Success',
    },
    {
      eventCode: 'E-011',
      successEvent: false,
      description: 'Failure',
    },
  ],
  /* 
  * Callback to fetch mobile number based on the sds-ids passed
  * This same callback will be used to fetch contacts for collect payment ET.
  */
  callbacks: { fetchPhoneNumbersCallback }, 
});

Init Execution engine

interface Job {
    id: string;
    jobRef: string;
    jobWorkflowId: string;
    status: string;
    subStatus?: string | null;
    containers: Array<Container>;
    customData: any;
    displayInfo: any;
    start: string;
    objectives: Array<Objective>;
}

interface Workflow {
    name: string;
    id: string;
    tag: IWfTag[];
    description: string;
    flows: Array<ExecutionTask>;
    expire?: boolean;
    meta?: string;
}

interface Workflows {
  [workflowId:string]: Workflow;
}

import { DispatchStateContainer } from '@os1-platform/dispatch-mobile';

/**
 * Call this function when dispatch data is fetched successfully
 * @param dispatchID
 * @param jobs
 * @param logging
 * @param maxTaskReattempt
 */

await DispatchStateContainer.getInstance().initDispatchExecutor(
  dispatchID: string,
  dispatchJobs: Job[],
  dispatchWorkflows: Workflows,
  maxTaskReattempt?: number
);

Start Objective Execution

interface sdkError {
  code: string;
  message: string;
}
// Error Handling from the calling Screen
React.useEffect(() => {
  if (route.params?.sdkError) {
    console.log(JSON.stringify(route.params.sdkError));
    Alert.alert('Error', JSON.stringify(route.params.sdkError));
  }
}, [route.params?.sdkError]);

navigation.navigate('DispatchExec', {
  success: true,
  initRoute: 'TaskDetail',
  mergedWI: {
    mwId: route.params.moId,
    customEventsData: {},
    statusFilter: ExecutionStatus[]
  },
  successRoute: 'SuccessScreen',
  failureRoute: 'FailureScreen',
  meta: META,
  paymentConfig: {
    paymentRefId: string, 
    pgConfigId?: string,
    userInfo?:{
      phone?:{
        countryCode:string
        mobileNumber:string
      }
    }
  }

});

Payment Handling

  • FCM Notification To handle the payment status notification using FCM, following data should be provided while sending the notification to app:

      interface notificationPaymentStatus {
        refId: string;
        status: STATUS;
      }
    • Example: In notification payload data should have: type: 'PAYMENT_COMPLETED' and data.data should be json stringified.

        var payload = {
          "notification":{
              "title":"Payment Completion",
              "body":"payment complete notify"
          },
          "data": {
            "type": "PAYMENT_COMPLETED",
            "data": JSON.stringify({
              "status":INITIATED | FAILED | SUCCESS,
              "refId":"ref:12345",
            })
          }
        };
    • Notification Handling

      1. In case of status: success, the user will be redirected to the complete payment screen, from init/ contact details/process payment screens.
      2. In case of status:failure, 2.1. If the user is on the Init Payment screen, then it will stay on the same screen. 2.2. If the user is on the ContactDetails screen, then it will stay on the same screen. 2.3. If the user is on the Process Payment screen, then it will get redirected to the complete payment screen, and the complete payment screen will have the option for retry or cancel.
  • GO Back Feature

    1. If the user is on Init Payment screen and a payment is already initiated for that order(objective), and refId id is in-progress, then going back to previous ET should not be allowed and user to get redirected to home screen instead.
    2. If the user is on Init Payment screen and the payment is not yet initiated, then going back to previous ET as per the workflow should be allowed.

Objective Summary Route Params


export interface ObjectiveSummary {
entityCode: string;
eventCode: string;
reasonCode: string;
reasonCodeDesc?: string;
}

// When navigating to success or failure route, following are the route params:
{
summary: {
 success?: ObjectiveSummary[];
 failure?: ObjectiveSummary[];
},
objSuccess: boolean,
}

New functions

// getObjectiveTaskList
public async getMergedObjectiveList getObjectiveTaskList(
    status: ExecutionStatus[]
  ): Promise<IObjectiveTask[]> {
    return [];
  }

// getObjectiveTaskDetails
public async getMergedObjectiveDetails getObjectiveTaskDetails(
    mwId: string,
    status: ExecutionStatus[]
  ):  Promise< (IObjectiveTask & { workflowData: StoredWorkflowInstance[] | [] }) | {} >
  {
    return [];
  }

// Inventory Data
public async getRiderInventory(): Promise<IDispatch.ItemsInRiderCustody> {
	return {}
}

Interfaces

export interface IObjectiveTask {
  id: string;
  status: ExecutionStatus;
  tags: IWfTag[];
  inputs: any;
  instanceCount: number;
  location: Location;
  contact: string[];
}

export interface StoredWorkflowInstance {
  id: string;
  mergedObjectiveId: string;
  jobId: string;
  scannableId: string;
  initialMergedObjectiveId: string;
  status: ExecutionStatus;
  jobWorkflowId: string;
  workflowId: string;
  displayInfo: any;
  cashAmount: number;
}

enum ExecutionStatus {
  READY = 'READY',
  IN_PROGRESS = 'IN_PROGRESS',
  NOT_READY = 'NOT_READY',
  COMPLETED_SUCCESS = 'COMPLETED-SUCCESS',
  COMPLETED_FAILURE = 'COMPLETED-FAILURE',
}

interface IWfTag {
  name: string;
  value: string;
}

export interface Location {
  locationId: string;
  address?: any;
  geolocation?: any;
}
export interface ItemsInRiderCustody {
  shipments: {
    totalCount: number;
    deliveredCount: number;
    pickedCount: number;
  };
  cash: {
    expectedAmount: number;
    collectedAmount: number;
  };
}

FCM

Setup (android only)

Add the Firebase Android configuration file to your app:
  • Create a firebase project (Check Firebase instructions for creating app).
  • Click Download google-services.json to obtain your Firebase Android config file (google-services.json).
  • Move your config file into the module (app-level) directory of your app.
  • To enable Firebase products in your app, add the google-services plugin to your Gradle files.
In your module (app-level) Gradle file (usually app/build.gradle), apply the Google Services Gradle plugin:
apply plugin: 'com.android.application'
// Add the following line:
apply plugin: 'com.google.gms.google-services'  // Google Services plugin

android {
  // ...
}

In your root-level (project-level) Gradle file (build.gradle), add rules to include the Google Services Gradle plugin. Check that you have Google's Maven repository, as well

buildscript {

  repositories {
    // Check that you have the following line (if not, add it):
    google()  // Google's Maven repository
  }

  dependencies {
    // ...

    // Add the following line:
    classpath("com.android.tools.build:gradle:7.1.1")
    classpath("com.google.gms:google-services:4.3.10")  // Google Services plugin
    classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
  }
}

allprojects {
  // ...

  repositories {
    // Check that you have the following line (if not, add it):
    google()  // Google's Maven repository
    // ...
  }
}

Get FCM Token

import {
  getFCMToken,
  requestFirebasePermissions,
} from '@os1-platform/dispatch-mobile';
//Get FCM Token
let token = await getFCMToken();

//Request Notifications permissions (ios)
// It will ask for user permissions for showing alert/notifications
let enabled = await requestFirebasePermissions();

Background FCM Messages

Register callback for receiving FCM Messages in background

Note : Call this function in the root component i.e in index.js file of the app

import { registerBackgroundHandler } from '@os1-platform/dispatch-mobile';

registerBackgroundHandler((message: object) => {
  // Handle FCM Message here
});

Foreground FCM Messages

useFcmMessage() custom hook in functional components to receive FCM Messages in Foregound
import { useFCMMessage } from '@os1-platform/dispatch-mobile';

const fcmMessage = useFCMMessage();
if (fcmMessage != null) {
  // update UI here to show the message
}

OR

extend FCM Base class in case of class components
import { FCM } from '@os1-platform/dispatch-mobile';

class ClassComponent extends FCM {
  //implement these methods
  handleFcmMessage(remoteMessage: object): void {}

  //implement these methods
  handleNotification(remoteMessage: object): void {}
}

Error Codes

PERMISSIONS_ERROR[2500] = 'Mandatory Android Permissions not provided';
PARAM_MISSING[2502] = 'Mandatory Paramater is missing in request';

Sync Manager

import { AppSyncManager, SdkSyncType } from '@os1-platform/dispatch-mobile';

// Start Events sync
await AppSyncManager.getInstance().startSyncing(
  false, // pass true for force sync
  SdkSyncType.EVENTS_SYNC
);

//Start Documents sync
await AppSyncManager.getInstance().startSyncing(
  false, // pass true for force sync
  SdkSyncType.DOCUMENT_SYNC
);

//Get All Events By Dispatch ID
await AppSyncManager.getInstance().getAllEvents('dsp_id');

//Get all documents By Dispatch ID
await AppSyncManager.getInstance().getAllDocuments('dsp_id');

Start Sync Manager as a Foreground Service in android

import { NativeSyncManager } from '@os1-platform/dispatch-mobile';

NativeSyncManager.startSyncManager(
  interval,
  notificationTitle,
  notificationText
);
// interval will be in seconds
NativeSyncManager.startSyncManager(
  2000,
  'Dispatch Service',
  'Syncing events...'
);

//To stop the foreground android service
NativeSyncManager.stopSyncManager();

SDK Utility methods

Download Firebase Config

import { SdkUtils } from '@os1-platform/dispatch-mobile';

await SdkUtils.getRemoteConfig(3000);
// 3000 is the number of seconds to cache the config

Download APK from Public URL

/**
 * Function to download apk file from a public URL
 * @param apkURL - URL where apk is hosted
 * @param version - expected version of apk (used for naming the file)
 * @param callback - callback for getting progress of download
 */
await SdkUtils.downloadAPK('https://apk_url.com', '1', (progress) =>
  console.log(progress.totalBytesWritten)
);

Open & Install an APK File

/**
 * Opens & Install an APK file
 * @param uri - source of apk file
 */

await SdkUtils.openAPKFile(result.uri);

Send events to Firebase analytics

/**
 *
 * @param eventName-> string
 * @param tag -> string
 * @param message -> string
 */
await Logger.getInstance().sendToFirebaseAnalytics('ev_name', 'tag', 'message');

Log events to console

/**
 *
 * @param TAG
 * @param message
 * @param logType
 */
Logger.getInstance().logEvent('tag', 'message', LOG_TYPE.SDK_ERROR);

Error Codes

const enum BaseErrorCodes {
  InvalidArgumentError = '100100',
  InvalidBaseURL = '100101',
  SyncManagerNotInitialized = '100102',
  MissingOrInvalidProps = '100103',
  SQLiteDBIssue = '100104',
  AppSyncNotInitialized = '100105',
  FMS_FOLDER_CREATION_ERROR = '100106',
  REASON_CODE_API_ERROR = '100107',
  MERGING_ERROR = '100108',
  LOCATION_PERMISSION_DENIED = '100109',
  CAMERA_PERMISSION_DENIED = '100110',
  STORAGE_PERMISSION_DENIED = '100111',
  GRAPHQL_CLIENT_NOT_INITIALIZED = '100112',
  FMS_GRAPHQL_API_ERROR = '100113',
  INTERNET_NOT_ENABLED = '100114',
  LOCATION_OR_GPS_NOT_ENABLED = '100115',
  EXECUTION_ENGINE_ERROR = '100116',
  UNEXPECTED_ERROR = '100117',
}