Subversion Repositories SmartDukaan

Rev

Rev 36666 | Rev 36685 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 36666 Rev 36682
Line 204... Line 204...
204
            <div class="modal-body" style="padding:0;">
204
            <div class="modal-body" style="padding:0;">
205
                <div id="liveTrackingInfo" style="padding:8px 15px; background:#f8f9fa; border-bottom:1px solid #ddd; font-size:13px;"></div>
205
                <div id="liveTrackingInfo" style="padding:8px 15px; background:#f8f9fa; border-bottom:1px solid #ddd; font-size:13px;"></div>
206
                <div id="liveTrackingMap" style="height:500px; width:100%;"></div>
206
                <div id="liveTrackingMap" style="height:500px; width:100%;"></div>
207
            </div>
207
            </div>
208
            <div class="modal-footer">
208
            <div class="modal-footer">
-
 
209
                <label style="float:left; margin-top:7px; font-weight:normal; font-size:13px;">
-
 
210
                    <input type="checkbox" id="autoRefreshToggle" checked style="margin-right:5px;"> Auto-refresh (30s)
-
 
211
                </label>
209
                <button type="button" class="btn btn-primary" id="refreshTrackingBtn"><i class="fa fa-refresh"></i> Refresh</button>
212
                <button type="button" class="btn btn-primary" id="refreshTrackingBtn"><i class="fa fa-refresh"></i> Refresh</button>
210
                <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
213
                <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
211
            </div>
214
            </div>
212
        </div>
215
        </div>
213
    </div>
216
    </div>
Line 314... Line 317...
314
            liveTrackingMap._markers.forEach(function (m) { m.setMap(null); });
317
            liveTrackingMap._markers.forEach(function (m) { m.setMap(null); });
315
        }
318
        }
316
        if (liveTrackingMap._polyline) {
319
        if (liveTrackingMap._polyline) {
317
            liveTrackingMap._polyline.setMap(null);
320
            liveTrackingMap._polyline.setMap(null);
318
        }
321
        }
-
 
322
        if (liveTrackingMap._visitRoute) {
-
 
323
            liveTrackingMap._visitRoute.setMap(null);
-
 
324
        }
319
        if (liveTrackingMap._currentMarker) {
325
        if (liveTrackingMap._currentMarker) {
320
            liveTrackingMap._currentMarker.setMap(null);
326
            liveTrackingMap._currentMarker.setMap(null);
321
        }
327
        }
322
        liveTrackingMap._markers = [];
328
        liveTrackingMap._markers = [];
323
 
329
 
Line 361... Line 367...
361
            })(marker, infoContent);
367
            })(marker, infoContent);
362
 
368
 
363
            liveTrackingMap._markers.push(marker);
369
            liveTrackingMap._markers.push(marker);
364
        }
370
        }
365
 
371
 
-
 
372
        // Draw visit-to-visit route (dashed line with arrows)
-
 
373
        var visitCoords = [];
-
 
374
        for (var vi = 0; vi < visits.length; vi++) {
-
 
375
            var vv = visits[vi];
-
 
376
            if (!vv.lat || !vv.lng) continue;
-
 
377
            var vLat = parseFloat(vv.lat);
-
 
378
            var vLng = parseFloat(vv.lng);
-
 
379
            if (isNaN(vLat) || isNaN(vLng) || (vLat === 0 && vLng === 0)) continue;
-
 
380
            visitCoords.push({ lat: vLat, lng: vLng });
-
 
381
        }
-
 
382
        if (visitCoords.length > 1) {
-
 
383
            liveTrackingMap._visitRoute = new google.maps.Polyline({
-
 
384
                path: visitCoords,
-
 
385
                geodesic: true,
-
 
386
                strokeColor: '#8e44ad',
-
 
387
                strokeOpacity: 0,
-
 
388
                strokeWeight: 3,
-
 
389
                icons: [{
-
 
390
                    icon: { path: 'M 0,-1 0,1', strokeOpacity: 0.6, strokeWeight: 3, scale: 3 },
-
 
391
                    offset: '0',
-
 
392
                    repeat: '16px'
-
 
393
                }, {
-
 
394
                    icon: { path: google.maps.SymbolPath.FORWARD_CLOSED_ARROW, strokeOpacity: 0.8, scale: 3 },
-
 
395
                    offset: '50%',
-
 
396
                    repeat: '200px'
-
 
397
                }],
-
 
398
                map: liveTrackingMap
-
 
399
            });
-
 
400
        }
-
 
401
 
366
        if (pathPoints.length > 0) {
402
        if (pathPoints.length > 0) {
367
            var pathCoords = [];
403
            var pathCoords = [];
368
            for (var j = 0; j < pathPoints.length; j++) {
404
            for (var j = 0; j < pathPoints.length; j++) {
369
                var pt = pathPoints[j];
405
                var pt = pathPoints[j];
370
                var pLat = parseFloat(pt.lat);
406
                var pLat = parseFloat(pt.lat);
Line 415... Line 451...
415
            liveTrackingMap.fitBounds(bounds);
451
            liveTrackingMap.fitBounds(bounds);
416
        }
452
        }
417
 
453
 
418
        var totalVisits = visits.filter(function (v) { return v.markType !== 'PUNCHIN' && v.markType !== 'PUNCHOUT'; }).length;
454
        var totalVisits = visits.filter(function (v) { return v.markType !== 'PUNCHIN' && v.markType !== 'PUNCHOUT'; }).length;
419
        var completedVisits = visits.filter(function (v) { return v.markType === 'CHECKIN-CHECKOUT' || v.markType === 'CHECKOUT'; }).length;
455
        var completedVisits = visits.filter(function (v) { return v.markType === 'CHECKIN-CHECKOUT' || v.markType === 'CHECKOUT'; }).length;
-
 
456
        var now = new Date();
-
 
457
        var timeStr = now.getHours().toString().padStart(2, '0') + ':' + now.getMinutes().toString().padStart(2, '0') + ':' + now.getSeconds().toString().padStart(2, '0');
420
        $('#liveTrackingInfo').html(
458
        $('#liveTrackingInfo').html(
421
            '<strong>' + username + '</strong> | ' +
459
            '<strong>' + username + '</strong> | ' +
422
            'Visits: <strong>' + totalVisits + '</strong> | ' +
460
            'Visits: <strong>' + totalVisits + '</strong> | ' +
423
            'Completed: <strong>' + completedVisits + '</strong> | ' +
461
            'Completed: <strong>' + completedVisits + '</strong> | ' +
424
            'Path Points: <strong>' + pathPoints.length + '</strong>' +
462
            'Path Points: <strong>' + pathPoints.length + '</strong>' +
425
            (pathPoints.length > 0 ? ' | <span style="color:#e74c3c;"><i class="fa fa-circle"></i></span> Last Known Location' : '')
463
            (pathPoints.length > 0 ? ' | <span style="color:#e74c3c;"><i class="fa fa-circle"></i></span> Last Known' : '') +
-
 
464
            ' | <span style="color:#3498db;">━</span> GPS Path' +
-
 
465
            (visitCoords.length > 1 ? ' | <span style="color:#8e44ad;">┅</span> Visit Route' : '') +
-
 
466
            ' | <span style="color:#999;">Updated: ' + timeStr + '</span>'
426
        );
467
        );
427
    }
468
    }
428
 
469
 
429
    function ensureGoogleMaps(callback) {
470
    function ensureGoogleMaps(callback) {
430
        if (window.google && window.google.maps) {
471
        if (window.google && window.google.maps) {
Line 435... Line 476...
435
        s.src = 'https://maps.googleapis.com/maps/api/js?key=AIzaSyAckO0y4Z6WhBOuMjNjioWLSYZDhGEvGBc&v=weekly';
476
        s.src = 'https://maps.googleapis.com/maps/api/js?key=AIzaSyAckO0y4Z6WhBOuMjNjioWLSYZDhGEvGBc&v=weekly';
436
        s.onload = callback;
477
        s.onload = callback;
437
        document.head.appendChild(s);
478
        document.head.appendChild(s);
438
    }
479
    }
439
 
480
 
-
 
481
    var liveTrackingUsername = '';
-
 
482
 
-
 
483
    function startAutoRefresh() {
-
 
484
        stopAutoRefresh();
-
 
485
        if ($('#autoRefreshToggle').is(':checked') && liveTrackingUserId) {
-
 
486
            liveTrackingInterval = setInterval(function () {
-
 
487
                loadLiveTracking(liveTrackingUserId, liveTrackingUsername);
-
 
488
            }, 30000);
-
 
489
        }
-
 
490
    }
-
 
491
 
-
 
492
    function stopAutoRefresh() {
-
 
493
        if (liveTrackingInterval) {
-
 
494
            clearInterval(liveTrackingInterval);
-
 
495
            liveTrackingInterval = null;
-
 
496
        }
-
 
497
    }
-
 
498
 
440
    $(document).on('click.livetrack', '.live-tracking-btn', function () {
499
    $(document).on('click.livetrack', '.live-tracking-btn', function () {
441
        liveTrackingUserId = $(this).data('userid');
500
        liveTrackingUserId = $(this).data('userid');
442
        var username = $(this).data('username');
501
        liveTrackingUsername = $(this).data('username');
443
        $('#liveTrackingModalTitle').html('<i class="fa fa-map-marker"></i> Live Tracking - ' + username);
502
        $('#liveTrackingModalTitle').html('<i class="fa fa-map-marker"></i> Live Tracking - ' + liveTrackingUsername);
444
        $('#liveTrackingInfo').html('<div class="text-center"><i class="fa fa-spinner fa-spin"></i> Loading...</div>');
503
        $('#liveTrackingInfo').html('<div class="text-center"><i class="fa fa-spinner fa-spin"></i> Loading...</div>');
445
        $('#liveTrackingModal').modal('show');
504
        $('#liveTrackingModal').modal('show');
446
 
505
 
447
        setTimeout(function () {
506
        setTimeout(function () {
448
            liveTrackingMap = null;
507
            liveTrackingMap = null;
449
            ensureGoogleMaps(function () {
508
            ensureGoogleMaps(function () {
450
                loadLiveTracking(liveTrackingUserId, username);
509
                loadLiveTracking(liveTrackingUserId, liveTrackingUsername);
-
 
510
                startAutoRefresh();
451
            });
511
            });
452
        }, 300);
512
        }, 300);
453
    });
513
    });
454
 
514
 
455
    $(document).on('click.livetrack', '#refreshTrackingBtn', function () {
515
    $(document).on('click.livetrack', '#refreshTrackingBtn', function () {
456
        if (liveTrackingUserId) {
516
        if (liveTrackingUserId) {
457
            var username = $('#liveTrackingModalTitle').text().replace('Live Tracking - ', '').trim();
-
 
458
            $('#liveTrackingInfo').html('<div class="text-center"><i class="fa fa-spinner fa-spin"></i> Refreshing...</div>');
517
            $('#liveTrackingInfo').html('<div class="text-center"><i class="fa fa-spinner fa-spin"></i> Refreshing...</div>');
459
            loadLiveTracking(liveTrackingUserId, username);
518
            loadLiveTracking(liveTrackingUserId, liveTrackingUsername);
460
        }
519
        }
461
    });
520
    });
462
 
521
 
463
    $('#liveTrackingModal').on('hidden.bs.modal', function () {
522
    $(document).on('change', '#autoRefreshToggle', function () {
464
        if (liveTrackingInterval) {
523
        if ($(this).is(':checked')) {
465
            clearInterval(liveTrackingInterval);
524
            startAutoRefresh();
-
 
525
        } else {
466
            liveTrackingInterval = null;
526
            stopAutoRefresh();
467
        }
527
        }
468
    });
528
    });
-
 
529
 
-
 
530
    $('#liveTrackingModal').on('hidden.bs.modal', function () {
-
 
531
        stopAutoRefresh();
-
 
532
        liveTrackingUserId = null;
-
 
533
    });
469
</script>
534
</script>