Manage subscriptions in ui routes with angular meteor - javascript

I'm currently building an application with meteor and angularJS using angular-meteor. I'm currently asking myself, how to properly handle subscriptions. My current approach is to:
resolve a route when each dependent subscription is ready
make sure that previous subscriptions on that publication are stopped
Is there a more performant way of doing this?
profileRoutes.js:
function profileRoutes($stateProvider, ResolverProvider) {
$stateProvider
.state('user.profile', {
url: '/:username/profile',
resolve: _.extend(
{
$title: ['$stateParams', function($sp) {
return $sp.username + "'s Profil";
}]
},
ResolverProvider.waitForMedia(),
ResolverProvider.waitForUsers()
),
abstract: true,
views: {
'main': {
controller: 'UserProfileController',
templateUrl: 'client/components/users/profile.html'
}
}
});
}
angular
.module('myApp')
.config(profileRoutes);
resolver.js
function ResolverProvider() {
/**
* _stopIfSubscribed
*
* Checks if a subscription for that publication is already present and stops it.
* #param publicationName
* #private
*/
function _stopIfSubscribed(publicationName) {
_.forEach(_.get(Meteor, 'default_connection._subscriptions'), (handle) => {
if(_.get(handle, 'name') === publicationName && handle.stop) {
handle.stop();
}
});
}
/**
* waitForUsers
*
* Returns resolvers for waiting on my own and all other users
* Does not require a user
* #returns {{meSubscription: *[], usersSubscription: *[]}}
*/
this.waitForUsers = () => {
return {
"meSubscription": ['$meteor', function ($meteor) {
return $meteor.waitForUser();
}],
"usersSubscription": ['$meteor', function ($meteor) {
_stopIfSubscribed('allUsers');
return $meteor.subscribe('allUsers');
}]
};
};
/**
* waitForMedia
*
* Returns resolvers for waiting on galleries and media
* #returns {{mediaSubscription: *[], gallerySubscription: *[]}}
*/
this.waitForMedia = () => {
return {
"mediaSubscription": ['$meteor', function ($meteor) {
_stopIfSubscribed('media');
return $meteor.subscribe('media');
}],
"gallerySubscription": ['$meteor', function ($meteor) {
_stopIfSubscribed('galleries');
return $meteor.subscribe('galleries');
}]
};
};
}

Related

FullCalendar - I can't retrieve the events on the calendar

I have json format events available on a "/ index" url. I would like to be able to retrieve them in order to display them on the calendar. I followed the official tutorial to the letter but unfortunately I still can't do it, here are my files:
calendar.js
$(function () {
'use strict'
// Initialize fullCalendar
$('#calendar').fullCalendar({
height: 'parent',
locale: 'fr',
header: {
left: 'prev,next today',
center: 'title',
right: 'month,agendaWeek,agendaDay,listWeek'
},
navLinks: true,
selectable: true,
selectLongPressDelay: 100,
editable: true,
nowIndicator: true,
defaultView: 'listMonth',
views: {
agenda: {
columnHeaderHtml: function (mom) {
return '<span>' + mom.format('ddd') + '</span>' +
'<span>' + mom.format('DD') + '</span>';
}
},
day: {
columnHeader: false
},
listMonth: {
listDayFormat: 'ddd DD',
listDayAltFormat: false
},
listWeek: {
listDayFormat: 'ddd DD',
listDayAltFormat: false
},
agendaThreeDay: {
type: 'agenda',
duration: {
days: 3
},
titleFormat: 'MMMM YYYY'
}
},
events: "/index",
eventAfterAllRender: function (view) {
if (view.name === 'listMonth' || view.name === 'listWeek') {
var dates = view.el.find('.fc-list-heading-main');
dates.each(function () {
var text = $(this).text().split(' ');
var now = moment().format('DD');
$(this).html(text[0] + '<span>' + text[1] + '</span>');
if (now === text[1]) {
$(this).addClass('now');
}
});
}
console.log(view.el);
},
eventRender: function (event, element) {
if (event.description) {
element.find('.fc-list-item-title').append('<span class="fc-desc">' + event.description + '</span>');
element.find('.fc-content').append('<span class="fc-desc">' + event.description + '</span>');
}
var eBorderColor = (event.source.borderColor) ? event.source.borderColor : event.borderColor;
element.find('.fc-list-item-time').css({
color: eBorderColor,
borderColor: eBorderColor
});
element.find('.fc-list-item-title').css({
borderColor: eBorderColor
});
element.css('borderLeftColor', eBorderColor);
},
});
var calendar = $('#calendar').fullCalendar('getCalendar');
// change view to week when in tablet
if (window.matchMedia('(min-width: 576px)').matches) {
calendar.changeView('agendaWeek');
}
// change view to month when in desktop
if (window.matchMedia('(min-width: 992px)').matches) {
calendar.changeView('month');
}
// change view based in viewport width when resize is detected
calendar.option('windowResize', function (view) {
if (view.name === 'listWeek') {
if (window.matchMedia('(min-width: 992px)').matches) {
calendar.changeView('month');
} else {
calendar.changeView('listWeek');
}
}
});
// Display calendar event modal
calendar.on('eventClick', function (calEvent, jsEvent, view) {
var modal = $('#modalCalendarEvent');
modal.modal('show');
modal.find('.event-title').text(calEvent.title);
if (calEvent.description) {
modal.find('.event-desc').text(calEvent.description);
modal.find('.event-desc').prev().removeClass('d-none');
} else {
modal.find('.event-desc').text('');
modal.find('.event-desc').prev().addClass('d-none');
}
modal.find('.event-start-date').text(moment(calEvent.start).format('LLL'));
modal.find('.event-end-date').text(moment(calEvent.end).format('LLL'));
//styling
modal.find('.modal-header').css('backgroundColor', (calEvent.source.borderColor) ? calEvent.source.borderColor : calEvent.borderColor);
});
//display current date
var dateNow = calendar.getDate();
calendar.option('select', function (startDate, endDate) {
$('#modalCreateEvent').modal('show');
$('#eventStartDate').val(startDate.format('LL'));
$('#eventEndDate').val(endDate.format('LL'));
$('#eventStartTime').val('07:00:00').trigger('change');
$('#eventEndTime').val('10:00:00').trigger('change');
});
$('.select2-modal').select2({
minimumResultsForSearch: Infinity,
dropdownCssClass: 'select2-dropdown-modal',
});
$('.calendar-add').on('click', function (e) {
e.preventDefault()
$('#modalCreateEvent').modal('show');
});
})
web.php (laravel)
<?php
use Illuminate\Support\Facades\Route;
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
/* Courses Routes */
Route::post('admin/calendar', 'CoursesController#store')->name('courses.store');
Route::get('index', 'CoursesController#index');
Result when I do a request on "/ index", this is the result:
{
"backgroundColor": "rgba(91,71,251,.2)",
"borderColor": "#5b47fb",
"events": [{
"start": "2020-10-07T07:00:00",
"end": "2020-10-07T10:00:00",
"title": "statistiques",
"description": "drink Coffee"
}]
};
Screenshot of similar result:
Here is the class "Coursescontroller" which manages everything
<?php
namespace App\Http\Controllers;
use App\Courses;
use Illuminate\Support\Str;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Auth;
use App\Http\Resources\CourseResource;
class CoursesController extends Controller
{
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware('auth:admin');
}
/**
* retrieve the data from the "courses" table
*
* #return \Illuminate\Http\Response
*/
public function index()
{
$course = DB::select('select * from courses where universityReference = ?', [Auth::user()->universityReference]);
//let's select the first line
$data = [
"backgroundColor" => $course[0]->backgroundColor,
"borderColor" => $course[0]->borderColor,
"events" => [unserialize($course[0]->events)]
];
return array($data);
}
/**
* Show the form for creating a new resource.
*
* #return \Illuminate\Http\Response
*/
public function create()
{
//
}
/**
* transform the raw data collected, in order to properly format them for recording
*
*/
public function composeCourseData($arg)
{
//convert dates into ISODATE format ('Y-m-d')
$convertStartDate = date('Y-m-d', strtotime(str_replace('-', '/', $arg->input('startDate'))));
$convertEndDate = date('Y-m-d', strtotime(str_replace('-', '/', $arg->input('endDate'))));
//convert times into ISOTIME format (H:M:S)
$convertStartTime = strftime('%H:%M:%S', strtotime($arg->input('startTime')));
$convertEndTime = strftime('%H:%M:%S', strtotime($arg->input('endTime')));
//final datetime output
$outputStartDate = "".$convertStartDate."T".$convertStartTime."" ;
$outputEndDate = "".$convertEndDate."T".$convertEndTime."" ;
//array to store course basic informations
$courseData = array(
'courseToken' => Str::random(23,'alphaNum'),
'creatorReference' => Auth::user()->reference,
'professorName' => $arg->input('professorName'),
'location' => $arg->input('location'),
'start' => $outputStartDate,
'end' => $outputEndDate,
'title' => $arg->input('subject'),
'description' => "".$arg->input('type')." '".$arg->input('subject')."' en ".$arg->input('location')." du ".$arg->input('professorName')." avec les etudiants de ".$arg->input('studyYear')." annee (".$arg->input('faculty').")",
);
//serialize course data before saving in db;
return serialize($courseData);
}
/**
* Store a newly created resource in storage.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function store(Request $request)
{
//Validate informations
/*$course = request()->validate([
/*'professorName'=>'required|string'
'subject'=> 'string|required',
'location'=>'required',
'start'=>'required',
'end'=>'required',
'description'=>'string'
]);*/
/* switch to determine the type of event (course, homework, tutorials or exams)
* in order to assign a color
* */
switch ($request->input('type')) {
case 'examens':
$ok = Courses::create([
//think about how to externalize this part of the code which is repeated almost 4 times
'universityReference' => Auth::user()->universityReference,
'creatorReference' => Auth::user()->reference,
'type' => $arg->input('type'),
'faculty' => $arg->input('faculty'),
'studyYear' => $arg->input('studyYear'),
//green
'backgroundColor' => 'rgba(16,183,89,.25)',
'borderColor' => '#10b759',
'events' => $this->composeCourseData($request)
]);
break;
case 'TD':
Courses::create([
//orange
'universityReference' => Auth::user()->universityReference,
'creatorReference' => Auth::user()->reference,
'type' => $request->input('type'),
'faculty' => $request->input('faculty'),
'studyYear' => $request->input('studyYear'),
'backgroundColor' => 'rgba(253,126,20,.25)',
'borderColor' => '#fd7e14',
'events' => $this->composeCourseData($request)
]);
break;
case 'devoirs':
Courses::create([
//pink
'universityReference' => Auth::user()->universityReference,
'creatorReference' => Auth::user()->reference,
'type' => $request->input('type'),
'faculty' => $request->input('faculty'),
'studyYear' => $request->input('studyYear'),
'backgroundColor' => 'rgba(241,0,117,.25)',
'borderColor' => '#f10075',
'events' => $this->composeCourseData($request)
]);
break;
default:
Courses::create([
//purple
'universityReference' => Auth::user()->universityReference,
'creatorReference' => Auth::user()->reference,
'type' => $request->input('type'),
'faculty' => $request->input('faculty'),
'studyYear' => $request->input('studyYear'),
'backgroundColor' => 'rgba(91,71,251,.2)',
'borderColor' => '#5b47fb',
'events' => $this->composeCourseData($request)
]);
break;
}
return redirect()->route('admin.app.calendar');
}
/**
* Display the specified resource.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function show($id)
{
//
}
/**
* Show the form for editing the specified resource.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function edit($id)
{
//
}
/**
* Update the specified resource in storage.
*
* #param \Illuminate\Http\Request $request
* #param int $id
* #return \Illuminate\Http\Response
*/
public function update(Request $request, Courses $course)
{
}
/**
* Remove the specified resource from storage.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function destroy(Courses $course)
{
$course->delete();
return response('Course removed successfuly !', Response::HTTP_NO_CONTENT);
}
}
I know this is not the satandard use but, i would like to retrieve events in this format, is that possible?
because: I save all the events of the same type ($ request-> input ('type') as (exams or TD ..), in a single "events" array that I store with a precise backgroundColor and borderColor. Every time an event of this same "type" tries to be saved, I just modify the corresponding line by editing the "events" array.
{
backgroundColor: 'rgba(253,126,20,.25)',
borderColor: '#fd7e14',
events: [{
id: '16',
start: '2020-10-07T07:00:00',
end: '2020-10-07T07:00:00',
title: 'My Rest Day'
},
{
id: '17',
start: '2020-10-07T07:00:00',
end: '2020-10-08T11:00:00',
title: 'My Rest Day'
}
]
}
The structure of the JSON being generated by your PHP code not compatible with fullCalendar. It must be a plain array of events, with no outer structure around it.
e.g. it should output this kind of structure
[
{
"start": "2020-10-07T07:00:00",
"end": "2020-10-07T10:00:00",
"title": "statistiques",
"description": "drink Coffee"
}
]
only.
To do that you need to amend your PHP as follows. I've included the background and border colours still, but they need to be appended to each event object individually:
public function index()
{
$course = DB::select('select * from courses where universityReference = ?', [Auth::user()->universityReference]);
//let's select the first line
$data = [unserialize($course[0]->events)];
foreach ($data as $item)
{
$item["backgroundColor"] = $course[0]->backgroundColor;
$item["borderColor"] = $course[0]->borderColor;
}
return $data;
}

Calls within callback do nothing

I am trying to make a call to another function from a callback but it does not do anything even if the callback is executed. What can be?
This is React Native, although in this payment gateway code there is no JSX involved:
var conektaApi = new Conekta();
conektaApi.setPublicKey('key_CWraZrrnBCZ5aFP6FtYNz9w');
conektaApi.createToken({
cardNumber: '4242424242424242',
name: 'Manolo Virolo',
cvc: '111',
expMonth: '11',
expYear: '21',
}, function(data){
this.callAnotherFunction()
//I also tried anonymous function and arrow
// ()=>{ callAnotherFunction}
}, function(){
console.log( 'Error!' );
})
}
In no way am I succeeding in having another function executed in case of success. In github you can find the js code of the Conekta module, which is a very simple code in reality but I can not deduce what is happening or how to fix it.
I think the problem is in the index.js of the dependency of Conekta:
Conekta module js
This contains the index.js of Conekta:
/**
* #providesModule Conekta
*/
'use strict';
// RNConekta
const RNConekta = require('react-native').NativeModules.RNConekta;
const Platform = require('react-native').Platform;
var Conekta = function() {
this.publicKey = false;
};
/**
* Params:
* publicKey: String (Your testing or production Public Key)
*/
Conekta.prototype.setPublicKey = function(publicKey: String) {
this.publicKey = publicKey;
};
/**
* Params:
* info = {
* cardNumber: String
* name: String
* cvc: String
* expMonth: String
* expYear: String
* }
*/
Conekta.prototype.createToken = function(info: Object, success: Function, error:Function) {
info.publicKey = this.publicKey;
RNConekta.createToken(info, function(response){
if ( Platform.OS === 'android' ) {
success( JSON.parse( response ) );
} else {
success( response );
}
}, error);
};
module.exports = Conekta;
I'm not familiar with Conekta but I think you need to specify a parameter for an error too in your function(data) line like this:
function(err, data){
if (err) {
console.error(err);
return;
}
this.callAnotherFunction()
}

Anonymous function not working

I am getting the error "Uncaught TypeError: $.fblogin is not a function" when I call
$.fblogin({
fbId: 'xxxxxxxxxx',
permissions: 'email,user_birthday',
success: function (data) {
console.log('User birthday' + data.birthday + 'and email ' + data.email);
}
});
The function is defined bellow:
(function (factory) {
if (typeof define === 'function' && define.amd) {
// AMD
define(['jquery'], factory);
} else if (typeof exports === 'object') {
// CommonJS
factory(require('jquery'));
} else {
// Browser globals
factory(jQuery);
}
}(function ($) {
$.extend({
/**
* fblogin
* #property {object} options - settings for fblogin plugin.
*
* Required:
* options.fbId {string} - the Facebook app id
*
* Optional:
* options.permissions {string} - a comma seperated list of FB permissions. See http://bit.ly/1plqJSs
* options.fields {string} - a comma seperated list of field ids. See http://bit.ly/1plrevO
* options.success {function} - callback that will be triggered when data is successfully returned from FB.
* options.error {function} - callback that will be triggered by any errors.
*/
fblogin: function (options) {
/**
* Private Props
* #property {object} __ - add private module functions here.
* #property {object} isSdkLoaded - a flag for when the FB SDK has loaded.
* #property {object} isFbInitiated - a flag for when FB.init has been called.
* #property {object} $dfd - stores an instance of jquery Deferred.
*/
var __,
isSdkLoaded,
isFbInitiated,
$dfd;
options = options || {};
isSdkLoaded = false;
isFbInitiated = false;
$dfd = $.Deferred();
// PRIVATE FUNCTIONS
__ = {
init: function () {
// FB ID is required
if (!options.fbId) {
throw new Error('Required option "fbId" is missing!');
}
options.permissions = options.permissions || '';
options.fields = options.fields || '';
options.success = options.success || function(){};
options.error = options.error || function(){};
__.listenForFbAsync();
},
listenForFbAsync: function () {
if (window.fbAsyncInit) {
var notMyFunction = window.fbAsyncInit;
}
// listen for FB SDK load
window.fbAsyncInit = function() {
__.initFB();
isSdkLoaded = true;
if (notMyFunction) { notMyFunction(); }
};
if (isSdkLoaded || window.FB) {
window.fbAsyncInit();
return;
}
},
initFB: function () {
if (!isFbInitiated) {
window.FB.init({
appId : options.fbId,
cookie : true,
xfbml : true,
version : 'v2.0'
});
isFbInitiated = true;
}
$dfd.notify({status: 'init.fblogin'});
},
loginToFB: function () {
window.FB.login(function(response) {
if (response.authResponse) {
$dfd.notify({
status: 'authenticate.fblogin',
data: response
});
} else {
// mimic facebook sdk error format
$dfd.reject({
error: {
message: 'User cancelled login or did not fully authorize.'
}
});
}
}, {
scope: options.permissions,
return_scopes: true
});
},
getFbFields: function (accessToken) {
FB.api('/me', {fields: options.fields}, function(response) {
if (response && !response.error) {
$dfd.resolve(response);
}
else {
$dfd.reject(response);
}
});
}
};
// This monitors the FB login progresssion
// 1. Init FB
// 2. FB.login
// 3. Get user data
$dfd.progress(function (response) {
if( response.status === 'init.fblogin' ) {
__.loginToFB();
} else if( response.status === 'authenticate.fblogin' ) {
__.getFbFields(response.data.authResponse.accessToken);
} else {
dfd.reject();
}
});
// point callbacks at deffereds
$dfd.done(options.success);
$dfd.fail(options.error);
// here we go!
__.init();
return $dfd;
}
});
}));
It seems your jQuery is getting loaded again after the above script. You can check in console or move the script down in the page and verify.

Using Typescript can I create a service in more compact way?

My code looks like this:
app.factory('utilityService', [
'$http',
'$angularCacheFactory',
utilityService
]);
function utilityService(
$http,
$angularCacheFactory
) {
var factory: {
rowClicked($index, collection);
} = <any>{};
factory.rowClicked = function ($index, collection) {
var row = collection[$index];
if (row.current) {
row.current = false;
return null;
} else {
collection.forEach(function (object) {
object.current = false;
});
row.current = true;
return $index;
}
};
return factory;
}
Is there a way I can combine the definition and code something like this:
var factory2: {
rowClicked: ($index, collection) => { ... };
}
return factory2;
Note that I did try the code above but I think I'm not on the right track as I saw many typescript related errors.
You can define an interface for your service instead and keep it external to your service. So you can summarize this as :-
export interface IUtilityService {
/**
* Returns ...
* #param {number} $index - ...
* #param {SomeType[]} collection:SomeType - ...
* #returns {SomeType}
*/
rowClicked($index:number, collection:SomeType[]):number
}
Class UtilityService implements IUtilityService {
static $inject = [
'$http',
'$angularCacheFactory'
];
constructor(private $http : ng.IHttpService,
private $angularCacheFactory :ng.ICacheFactoryService) {
}
rowClicked($index, collection) {
var row = collection[$index];
if (row.current) {
row.current = false;
return null;
} else {
collection.forEach(function (object) {
object.current = false;
});
row.current = true;
return $index;
}
};
}
app.service('utilityService',UtilityService);
and when you consume it else where you could specify the type for your dependency as IUtilityService

navigator.geolocation.getCurrentPosition() method returns location request timeout in some devices react-native

I'm working on an app in which user location is track. I have almost completed this but when I had tested there are some devices returns location request timeout message. Also in some devices it works fine. I have also added the location permissions. In some case it also returns "provider gps unavailable".
LocationTrackingService.js
/**
* Location Tracking Service
*/
import Toast from "react-native-simple-toast";
import WebService from "../webservice/WebService";
import WebServiceConfig, { APITypes } from "../webservice/WebServiceConfig";
import APINames from "../webservice/APINames";
// actions
import { getUserId } from "BkProvider/src/actions/AppInitializer";
// constants
const TIME_TO_CALL_API = 30000;
const WATCH_LOCATION_TIMEOUT = 1000;
const GeolocationOptions = {
enableHighAccuracy: true,
timeout: 10000,
maximumAge: 1000
}
class LocationTrackingService {
static classInstance = null;
bookingId = '';
currentWatchLocationTimeout = 0;
isRunningService = false;
callback = null;
onGeolocationErrorOccurCallback = null;
isServiceInBackground = false;
/**
* #returns {LocationTrackingService}
*/
static getInstance() {
if (LocationTrackingService.classInstance == null) {
LocationTrackingService.classInstance = new LocationTrackingService();
}
return this.classInstance;
}
webServiceObject = null;
apiNames = APINames;
apiTypes = APITypes;
/**
* Method To Get Api Names
*/
getAPINames() {
return this.apiNames;
}
/**
* Method To Get Web Service Config Instance
*/
getWebServiceConfigInstance(apiName) {
if (apiName !== null) {
return new WebServiceConfig(apiName)
}
return null;
}
/**
* Method To Clear the web service object
*/
clearWebServiceObject() {
this.webServiceObject = null;
}
/**
* Method To Get Web Service Object
* #param {*} onResultCallback
*/
getWebServiceObject(onResultCallback) {
//if (this.webServiceObject == null)
this.webServiceObject = new WebService(onResultCallback);
return this.webServiceObject;
}
/**
* Method To Get User Id
*/
getUserIdBase() {
return getUserId();
}
/**
* Method To Show Toast
* #param {string} message
*/
showToast(message) {
if (message != null)
Toast.show(message, Toast.SHORT);
else
Toast.show("Dev error message should not be null", Toast.SHORT);
}
/**
* Method To Set BookingId
*/
setBookingId(bookingId) {
if (bookingId)
this.bookingId = bookingId;
}
/**
* This Method Start Service In Background Mode
* If It Set Callback No Longer Work and UI no longer update
*/
startServiceInBackground() {
this.isServiceInBackground = true;
}
/**
* Method To Clock In The Provicer
*/
clockInProvider() {
navigator.geolocation.getCurrentPosition(response => {
console.log(response)
if (response && response.coords) {
this.showToast('Step 1: Provider Clocked In');
this.saveProviderClockInLogs(response.coords);
}
},
(error) => {
//this.onGeolocationErrorOccurCallback;
console.log(error) // { TIMEOUT: 3, POSITION_UNAVAILABLE: 2, PERMISSION_DENIED: 1, message: "Location request timed out", code: 3 }
},
GeolocationOptions
)
}
/**
* Method To Save Provider Clock In Logs
*/
saveProviderClockInLogs(geolocation) {
let postParams = {
"booking_id": this.bookingId,
"provider_id": this.getUserIdBase(),
"location": {
"lat": geolocation.latitude,
"lng": geolocation.longitude
}
}
let apiConfig = this.getWebServiceConfigInstance(this.getAPINames().SaveProviderClockInLogs)
.setAPIType(this.apiTypes.POST);
this.getWebServiceObject(this.onResultCallback)
.addServiceConfiguration(apiConfig)
.addPostParameterObject(JSON.stringify(postParams))
.execute()
}
/**
* Method To Clock Out Provier
*/
clockOutProvider() {
navigator.geolocation.getCurrentPosition((response) => {
if (response && response.coords) {
this.saveProviderClockOutLogs(response.coords);
}
},
() => {
this.onGeolocationErrorOccurCallback;
},
GeolocationOptions
);
}
/**
* Method To Save Provider Clock Out Logs
*/
saveProviderClockOutLogs(response) {
if (response) {
let postParams = {
"booking_id": this.bookingId,
"provider_id": this.getUserIdBase(),
"location": {
"lat": response.latitude,
"lng": response.longitude
}
}
let apiConfig = this.getWebServiceConfigInstance(this.getAPINames().SaveProviderClockOutLogs)
.setAPIType(this.apiTypes.POST);
this.getWebServiceObject(this.onResultCallback)
.addPostParameterObject(JSON.stringify(postParams))
.addServiceConfiguration(apiConfig)
.execute()
}
}
providerRouteCoordinates = []; // provider routes followed coordinates
/**
* Method To Start Location Tracking
*/
start(destinationLocation, bookingAddressArea) {
this.showToast('Step 3: Before Update Location');
console.log('provider tracking enable', destinationLocation)
this.isRunningService = true;
let currentPosition = {
lat: '',
lng: ''
}
this.watchId = navigator.geolocation.watchPosition((response) => {
this.showToast('Step 4: Location Changed')
this.currentWatchLocationTimeout = this.currentWatchLocationTimeout + WATCH_LOCATION_TIMEOUT;
currentPosition.lat = response.coords.latitude;
currentPosition.lng = response.coords.longitude;
this.providerRouteCoordinates.push(`${(currentPosition.lat).toString()},${(currentPosition.lng).toString()}`);
if (this.calculateBookingLocationDistanceFromProviderLocation(currentPosition.lat, currentPosition.lng, destinationLocation.lat, destinationLocation.lng) <= bookingAddressArea) {
this.stopTracking();
this.showToast('Provider Reached The Destination!')
this.saveProviderRouteCoordinates(this.providerRouteCoordinates);
this.providerRouteCoordinates = []; // clear the old routes coordinates
this.providerReachedTheDestination();
}
if (this.currentWatchLocationTimeout == TIME_TO_CALL_API) {
this.currentWatchLocationTimeout = 0;
this.showToast(`Step 5: Routes Are Updated In ${this.currentWatchLocationTimeout}`);
this.saveProviderRouteCoordinates(this.providerRouteCoordinates);
this.providerRouteCoordinates = []; // clear the old routes coordinates
}
}, (error) => {
alert(JSON.stringify(error))
}, {
timeout: WATCH_LOCATION_TIMEOUT,
distanceFilter: 5,
enableHighAccuracy: true
});
}
/**
* Method To Pause Tracking
*/
pauseTracking() {
navigator.geolocation.getCurrentPosition((response) => {
if (response && response.coords) {
this.saveProviderPauseLogs(response.coords);
}
},
() => {
this.onGeolocationErrorOccurCallback;
},
GeolocationOptions
);
}
/**
* Method To Resume Tracking
*/
resumeTracking() {
navigator.geolocation.getCurrentPosition((response) => {
if (response && response.coords) {
this.saveProviderResumeLogs(response.coords);
}
},
() => {
this.onGeolocationErrorOccurCallback;
},
GeolocationOptions
);
}
/**
* Method To Save Provider Pause Logs
*/
saveProviderPauseLogs(response) {
if (response) {
let postParams = {
"booking_id": this.bookingId,
"provider_id": this.getUserIdBase(),
"location": {
"lat": response.latitude,
"lng": response.longitude
}
}
let apiConfig = this.getWebServiceConfigInstance(this.apiNames.SaveProviderPauseLogs)
.setAPIType(this.apiTypes.POST);
this.getWebServiceObject(this.onResultCallback)
.addServiceConfiguration(apiConfig)
.addPostParameterObject(JSON.stringify(postParams))
.execute()
}
}
/**
* Method To Save Provider Resume Logs
*/
saveProviderResumeLogs(response) {
if (response) {
let postParams = {
"booking_id": this.bookingId,
"provider_id": this.getUserIdBase(),
"resume_location": {
"lat": response.latitude,
"lng": response.longitude
}
}
let apiConfig = this.getWebServiceConfigInstance(this.apiNames.SaveProviderResumeLogs)
.setAPIType(this.apiTypes.POST);
this.getWebServiceObject(this.onResultCallback)
.addServiceConfiguration(apiConfig)
.addPostParameterObject(JSON.stringify(postParams))
.execute()
}
}
/**
* This Method Is Used To Save The Provider Route Coordinates
*/
saveProviderRouteCoordinates(routesCoordinates) {
// post params
let postParams = {
"route_coordinates": routesCoordinates
}
let apiConfig = this.getWebServiceConfigInstance(this.apiNames.SavProviderTrackingLogs)
.addURLParameters([this.bookingId, this.getUserIdBase()])
.setAPIType(this.apiTypes.POST)
this.getWebServiceObject(this.onResultCallback)
.addServiceConfiguration(apiConfig)
.addPostParameterObject(JSON.stringify(postParams))
.execute()
}
/**
* On Provider Reached The Destination
*/
providerReachedTheDestination() {
let apiConfig = this.getWebServiceConfigInstance(this.apiNames.AddProviderArrivalTime)
.addURLParameters([this.bookingId, this.getUserIdBase()])
.setAPIType(this.apiTypes.PUT)
this.getWebServiceObject(this.onResultCallback)
.addServiceConfiguration(apiConfig)
.execute()
}
/**
* Get Traveled Distance And Time
*/
getTraveledDistanceAndTime() {
let apiConfig = this.getWebServiceConfigInstance(this.apiNames.GetTraveledDistanceAndTime)
.addURLParameters([this.bookingId, this.getUserIdBase()])
this.getWebServiceObject(this.onResultCallback)
.addServiceConfiguration(apiConfig)
.execute()
}
/**
* Api Method To Save Adjustments
*/
saveAdjustments(data) {
if (data) {
let postParams = {
booking_id: this.bookingId,
provider_id: this.getUserIdBase(),
travel_time: data.travel_time,
job_length: data.job_length,
travel_distance: Number((data.travel_distance).toFixed(2))
}
let apiConfig = this.getWebServiceConfigInstance(this.apiNames.SaveAdjustments)
.setAPIType(this.apiTypes.POST)
this.getWebServiceObject(this.onResultCallback)
.addServiceConfiguration(apiConfig)
.addPostParameterObject(JSON.stringify(postParams))
.execute()
}
}
/**
* On Result Callback
*/
onResultCallback = (webServiceResultObj) => {
this.callback(webServiceResultObj);
}
/**
* Method To Stop Location Tracking
*/
stopTracking() {
this.isRunningService = false;
navigator.geolocation.clearWatch(this.watchId);
}
/**
* Method To Calculate Booking Location Distance From Provider Location
*/
calculateBookingLocationDistanceFromProviderLocation(lat1, lon1, lat2, lon2) {
var R = 6371; // km (change this constant to get miles)
var dLat = (lat2 - lat1) * Math.PI / 180;
var dLon = (lon2 - lon1) * Math.PI / 180;
var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) * Math.sin(dLon / 2) * Math.sin(dLon / 2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
var d = R * c;
return Math.round(d * 1000);
}
}
export default LocationTrackingService;
I got the same issue sometimes. In my case was because of weak GPS signal, try to set enableHighAccuracy to false -- enableHighAccuracy: false.
Some devices can't get a high accuracy signal.

Categories