jchavarri/flywheeljs

View on GitHub
examples/nodejs/index-request.js

Summary

Maintainability
A
3 hrs
Test Coverage
const program = require('commander');
const chalk = require('chalk');
const axios = require('axios');
const flywheel = require('flywheeljs');
const mergeObjects = require('./utils').mergeObjects;
const readline = require('readline');

program
  .description('request a new ride at a given location')
  .option('-e, --email <email>', '[required] The email of the user to authenticate as')
  .option('-p, --password <password>', '[required] The user\'s password')
  .option('-a, --address <address>', '[required] The address to request the taxi at. Usage: --address \'22 Estate Ct, South San Francisco, CA\'')
  .option('-t, --tip <tip>', '[optional] The tip for the ride, in cents. For example, for the minimum amount ($5) the param should be \'--tip 500\'')
  .option('-n, --notes <notes>', '[optional] Some notes to add to the ride request. Use it with quotes: --notes \'Park below the white building\'')
  .option('-s, --skip', '[optional] Skip address confirmation step')
  .parse(process.argv);

if (!process.argv.slice(2).length) {
  program.outputHelp();
}
else {
  const tip = program.tip || 500;
  const notes = program.notes || '';
  var authToken = undefined;
  var passenger = undefined;

  if (program.email && program.password && program.address) {
    var addressData = {}; // Will fill this object with google geocoding results
    const googleUrl = 'http://maps.googleapis.com/maps/api/geocode/json?address=' + encodeURIComponent(program.address);
    axios.get(googleUrl)
    .then(function (response) {
      const results = response.data.results;
      if (!results || results.length === 0) {
        return Promise.reject('We couldn\'t find any addresses corresponding to \'' + program.address + '\'. Use a comma separated format including the state, for example: --address \'22 Estate Ct, South San Francisco, CA\'');
      }
      const googleData = results[0];
      locationData = {
        pickUpLat: googleData.geometry.location.lat,
        pickUpLon: googleData.geometry.location.lng,
        address: googleData.address_components
          .filter((el) => (el.types.indexOf('street_number') !== -1 || el.types.indexOf('route') !== -1))
          .reduce((prev, next) => prev + (prev.length === 0 ? '' : ' ') + next.short_name, ''),
        state: googleData.address_components
          .filter((el) => el.types.indexOf('administrative_area_level_1') !== -1)
          .reduce((prev, next) => next.short_name, ''),
        country: googleData.address_components
          .filter((el) => el.types.indexOf('country') !== -1)
          .reduce((prev, next) => next.long_name, ''),
        city: googleData.address_components
          .filter((el) => el.types.indexOf('locality') !== -1)
          .reduce((prev, next) => next.long_name, '')
      };
      if (!program.skip) {
        return new Promise((resolve, reject) => {
          const rl = readline.createInterface({
            input: process.stdin,
            output: process.stdout
          });
          rl.question('\nEverything ready! A taxi will be ordered to pick you up at this address:\n' +
            JSON.stringify(locationData, null, '  ') +
            '\n\nAre you sure you want to continue? (Y/n)',
            (yesno) => {
              rl.close();
              if (yesno.length === 0 || yesno.toLowerCase() === 'y' || yesno.toLowerCase() === 'yes')
                resolve();
              else
                reject('The request was canceled by user');
            });
        });
      }
    })
    .then(function() {
      return flywheel.login({
        email: program.email,
        password: program.password
      });
    })
    .then(function(response) {
      authToken = response.auth_token;
      passenger = response.passenger;
      return flywheel.applicationContext({
        authToken: authToken,
        latitude: locationData.pickUpLat,
        longitude: locationData.pickUpLon
      });
    })
    .then(function(response) {
      if (!response.service_availabilities || response.service_availabilities.length === 0) {
        return Promise.reject('Flywheel is not available at this address. Please check with another address, or try to add more information to it (postal code, state, city)');
      }
      if (!passenger.payment_instruments || passenger.payment_instruments.length === 0) {
        return Promise.reject('There are no payment instruments linked to this account. Please add a payment instrument from the Flywheel mobile app');
      }
      return flywheel.createRide(mergeObjects(locationData, {
        passenger: {
          name: passenger.name,
          phone: passenger.telephone
        },
        paymentToken: passenger.payment_instruments[0].token,
        serviceAvailabilitiesId: response.service_availabilities[0].id,
        tip: tip,
        notes: notes,
        authToken: authToken
      }));
    })
    .then(function(response) {
      console.log(chalk.green('👍  Your request has been created! Your ride id is: ' + response.id));
      var counter = 0;
      const timeout = 120;
      const timeBetweenTrials = 2;
      const maxTrials = timeout / timeBetweenTrials;
      const retry = function() {
        return new Promise(function (resolve) {
          setTimeout(resolve, timeBetweenTrials * 1000);
        })
        .then(function() {
          return flywheel.getRideStatus({
            authToken: authToken,
            rideId: response.id
          })
          .then(function(response) {
            counter++;
            if (response.status === 'hail_accepted') {
              return response;
            }
            else if (!response.someRandom && counter < maxTrials) {
              console.log(chalk.green('⏳  Waiting for a driver to accept the ride. Remaining attempts: ' + (maxTrials - counter)));
              return retry();
            }
            else {
              return Promise.reject('Too much time went by without a driver accepting the ride. Please cancel your ride using the \'cancel\' command or open the Flywheel app on your phone to handle this ride from there.');
            }
          });
        });
        return retryPromise;
      }
      return retry();
    })
    .then(function(response) {
      console.log(chalk.green('🚕  Yay!! Your request has been accepted. These are the details of your ride and driver:\nid: ' + response.id + '\nride data: ', JSON.stringify(response.hail, null, '  ')));
    })
    .catch(function(error) {
      console.log(chalk.red('There was an error: ⚠️\n', JSON.stringify(error, null, '  ')));
    });
  }
  else {
    console.log(chalk.yellow('Some of these params are missing: <email>, <password>, <latitude>, <longitude>. Use -h or --help to get some usage information'));
  }
}