Subversion Repositories SmartDukaan

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
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, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')
81
            .replace(/"/g, '&quot;').replace(/'/g, '&#39;');
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
})();