| 36838 |
ranu |
1 |
// Location Approval — drives the #bra-* DOM in beat-report-approval.vm.
|
|
|
2 |
// Lives in /resources/js to keep Velocity's lexer off jQuery's $(/$. patterns.
|
|
|
3 |
|
|
|
4 |
(function () {
|
|
|
5 |
var ctx = (typeof context === 'string' && context) ? context : '';
|
|
|
6 |
|
|
|
7 |
function fetchRows() {
|
|
|
8 |
var from = $('#bra-from').val();
|
|
|
9 |
var to = $('#bra-to').val();
|
|
|
10 |
if (!from || !to) {
|
|
|
11 |
alert('Pick a date range first');
|
|
|
12 |
return;
|
|
|
13 |
}
|
|
|
14 |
$.get(ctx + '/beat-report/approval/data', {
|
|
|
15 |
fromDate: from,
|
|
|
16 |
toDate: to,
|
|
|
17 |
categoryId: $('#bra-category').val(),
|
|
|
18 |
escalationType: $('#bra-level').val()
|
|
|
19 |
}, function (resp) {
|
|
|
20 |
renderRows((resp && resp.rows) || []);
|
|
|
21 |
}).fail(function () {
|
|
|
22 |
alert('Failed to load approval list');
|
|
|
23 |
});
|
|
|
24 |
}
|
|
|
25 |
|
|
|
26 |
function renderRows(rows) {
|
|
|
27 |
var $tb = $('#bra-table tbody').empty();
|
|
|
28 |
if (!rows.length) {
|
|
|
29 |
$tb.append('<tr><td colspan="10" style="text-align:center;color:#888;padding:20px;">No off-site check-ins pending approval in this window.</td></tr>');
|
|
|
30 |
$('#bra-select-all').prop('checked', false);
|
|
|
31 |
updateSelectionUi();
|
|
|
32 |
return;
|
|
|
33 |
}
|
|
|
34 |
rows.forEach(function (r) {
|
|
|
35 |
var attach = r.attachment
|
|
|
36 |
? '<a href="javascript:void(0);" class="bra-view-attach" data-src="' + r.attachment + '"><i class="fa fa-paperclip" style="color:#27ae60;"></i> view</a>'
|
|
|
37 |
: '<span style="color:#aaa;">-</span>';
|
|
|
38 |
var typeBadge = badgeForType(r.taskType);
|
|
|
39 |
var time = r.checkInTime ? (r.taskDate + ' ' + r.checkInTime) : r.taskDate;
|
|
|
40 |
var mapBoth = (r.checkInLatLng && r.visitLocation)
|
|
|
41 |
? '<br><a href="' + mapsDirUrl(r.visitLocation, r.checkInLatLng) + '" target="_blank" style="font-size:11px;"><i class="fa fa-arrows-h"></i> compare on map</a>'
|
|
|
42 |
: '';
|
|
|
43 |
var $tr = $('<tr></tr>')
|
|
|
44 |
.append('<td><input type="checkbox" class="bra-row-check" data-id="' + r.trackingId + '"></td>')
|
|
|
45 |
.append('<td>' + escapeHtml(r.username) + '</td>')
|
|
|
46 |
.append('<td>' + escapeHtml(time) + '</td>')
|
|
|
47 |
.append('<td>' + typeBadge + '</td>')
|
|
|
48 |
.append('<td>' + escapeHtml(r.taskName || '') + '<br><small style="color:#888;">' + escapeHtml(r.address || '') + '</small></td>')
|
|
|
49 |
.append('<td>' + latLngCell(r.visitLocation, '#27ae60') + '</td>')
|
|
|
50 |
.append('<td>' + latLngCell(r.checkInLatLng, '#e67e22') + '</td>')
|
|
|
51 |
.append('<td><span class="label label-warning">' + r.distanceM + ' m</span>' + mapBoth + '</td>')
|
|
|
52 |
.append('<td>' + attach + '</td>')
|
|
|
53 |
.append('<td><button class="btn btn-xs btn-success bra-approve-one" data-id="' + r.trackingId + '"><i class="fa fa-check"></i> Approve</button></td>');
|
|
|
54 |
$tb.append($tr);
|
|
|
55 |
});
|
|
|
56 |
$('#bra-select-all').prop('checked', false);
|
|
|
57 |
updateSelectionUi();
|
|
|
58 |
}
|
|
|
59 |
|
|
|
60 |
function latLngCell(s, color) {
|
|
|
61 |
if (!s) return '<span style="color:#aaa;">-</span>';
|
|
|
62 |
var safe = escapeHtml(s);
|
|
|
63 |
return '<span style="display:inline-block;width:8px;height:8px;border-radius:50%;background:' + color + ';margin-right:6px;vertical-align:middle;"></span>'
|
|
|
64 |
+ '<a href="https://www.google.com/maps?q=' + encodeURIComponent(s) + '" target="_blank" style="font-family:monospace;font-size:11px;">' + safe + '</a>';
|
|
|
65 |
}
|
|
|
66 |
|
|
|
67 |
function mapsDirUrl(visit, checkin) {
|
|
|
68 |
return 'https://www.google.com/maps/dir/?api=1&origin=' + encodeURIComponent(visit) + '&destination=' + encodeURIComponent(checkin);
|
|
|
69 |
}
|
|
|
70 |
|
|
|
71 |
function badgeForType(t) {
|
|
|
72 |
t = (t || '').toLowerCase();
|
|
|
73 |
if (t === 'office-visit') return '<span class="label label-primary">Office</span>';
|
|
|
74 |
if (t === 'lead') return '<span class="label label-info">Lead</span>';
|
|
|
75 |
return '<span class="label label-default">Partner</span>';
|
|
|
76 |
}
|
|
|
77 |
|
|
|
78 |
function escapeHtml(s) {
|
|
|
79 |
return (s == null ? '' : String(s))
|
|
|
80 |
.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>')
|
|
|
81 |
.replace(/"/g, '"').replace(/'/g, ''');
|
|
|
82 |
}
|
|
|
83 |
|
|
|
84 |
function selectedIds() {
|
|
|
85 |
return $('.bra-row-check:checked').map(function () {
|
|
|
86 |
return $(this).data('id');
|
|
|
87 |
}).get();
|
|
|
88 |
}
|
|
|
89 |
|
|
|
90 |
function updateSelectionUi() {
|
|
|
91 |
var ids = selectedIds();
|
|
|
92 |
$('#bra-sel-count').text(ids.length);
|
|
|
93 |
$('#bra-approve-selected').prop('disabled', ids.length === 0);
|
|
|
94 |
}
|
|
|
95 |
|
|
|
96 |
$('#bra-fetch').on('click', fetchRows);
|
|
|
97 |
|
|
|
98 |
$(document).on('change', '#bra-select-all', function () {
|
|
|
99 |
var on = $(this).is(':checked');
|
|
|
100 |
$('.bra-row-check').prop('checked', on);
|
|
|
101 |
updateSelectionUi();
|
|
|
102 |
});
|
|
|
103 |
|
|
|
104 |
$(document).on('change', '.bra-row-check', updateSelectionUi);
|
|
|
105 |
|
|
|
106 |
$(document).on('click', '.bra-view-attach', function () {
|
|
|
107 |
$('#bra-attach-img').attr('src', $(this).data('src'));
|
|
|
108 |
$('#bra-attach-modal').modal('show');
|
|
|
109 |
});
|
|
|
110 |
|
|
|
111 |
$(document).on('click', '.bra-approve-one', function () {
|
|
|
112 |
var $btn = $(this);
|
|
|
113 |
var id = $btn.data('id');
|
|
|
114 |
$btn.prop('disabled', true).html('<i class="fa fa-spinner fa-spin"></i>');
|
|
|
115 |
$.post(ctx + '/beat-report/approve-checkin', {trackingId: id}, function () {
|
|
|
116 |
$btn.closest('tr').fadeOut(200, function () {
|
|
|
117 |
$(this).remove();
|
|
|
118 |
updateSelectionUi();
|
|
|
119 |
});
|
|
|
120 |
}).fail(function () {
|
|
|
121 |
alert('Approve failed');
|
|
|
122 |
$btn.prop('disabled', false).html('<i class="fa fa-check"></i> Approve');
|
|
|
123 |
});
|
|
|
124 |
});
|
|
|
125 |
|
|
|
126 |
$('#bra-approve-selected').on('click', function () {
|
|
|
127 |
var ids = selectedIds();
|
|
|
128 |
if (!ids.length) return;
|
|
|
129 |
if (!confirm('Approve ' + ids.length + ' off-site check-in(s)?')) return;
|
|
|
130 |
var $btn = $(this).prop('disabled', true).html('<i class="fa fa-spinner fa-spin"></i> Approving...');
|
|
|
131 |
$.post({
|
|
|
132 |
url: ctx + '/beat-report/approve-checkin-bulk',
|
|
|
133 |
data: $.param({trackingIds: ids}, true)
|
|
|
134 |
}).done(function (resp) {
|
|
|
135 |
(resp.approved || []).forEach(function (id) {
|
|
|
136 |
$('.bra-row-check[data-id="' + id + '"]').closest('tr').remove();
|
|
|
137 |
});
|
|
|
138 |
if ((resp.failed || []).length) {
|
|
|
139 |
alert(resp.failed.length + ' row(s) could not be approved');
|
|
|
140 |
}
|
|
|
141 |
updateSelectionUi();
|
|
|
142 |
}).fail(function () {
|
|
|
143 |
alert('Bulk approve failed');
|
|
|
144 |
}).always(function () {
|
|
|
145 |
$btn.html('<i class="fa fa-check"></i> Approve selected (<span id="bra-sel-count">0</span>)');
|
|
|
146 |
updateSelectionUi();
|
|
|
147 |
});
|
|
|
148 |
});
|
|
|
149 |
|
|
|
150 |
// Auto-load on first render so the head sees pending work immediately.
|
|
|
151 |
fetchRows();
|
|
|
152 |
})();
|