Subversion Repositories SmartDukaan

Rev

Blame | Last modification | View Log | RSS feed

// Location Approval — drives the #bra-* DOM in beat-report-approval.vm.
// Lives in /resources/js to keep Velocity's lexer off jQuery's $(/$. patterns.

(function () {
    var ctx = (typeof context === 'string' && context) ? context : '';

    function fetchRows() {
        var from = $('#bra-from').val();
        var to = $('#bra-to').val();
        if (!from || !to) {
            alert('Pick a date range first');
            return;
        }
        $.get(ctx + '/beat-report/approval/data', {
            fromDate: from,
            toDate: to,
            categoryId: $('#bra-category').val(),
            escalationType: $('#bra-level').val()
        }, function (resp) {
            renderRows((resp && resp.rows) || []);
        }).fail(function () {
            alert('Failed to load approval list');
        });
    }

    function renderRows(rows) {
        var $tb = $('#bra-table tbody').empty();
        if (!rows.length) {
            $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>');
            $('#bra-select-all').prop('checked', false);
            updateSelectionUi();
            return;
        }
        rows.forEach(function (r) {
            var attach = r.attachment
                ? '<a href="javascript:void(0);" class="bra-view-attach" data-src="' + r.attachment + '"><i class="fa fa-paperclip" style="color:#27ae60;"></i> view</a>'
                : '<span style="color:#aaa;">-</span>';
            var typeBadge = badgeForType(r.taskType);
            var time = r.checkInTime ? (r.taskDate + ' ' + r.checkInTime) : r.taskDate;
            var mapBoth = (r.checkInLatLng && r.visitLocation)
                ? '<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>'
                : '';
            var $tr = $('<tr></tr>')
                .append('<td><input type="checkbox" class="bra-row-check" data-id="' + r.trackingId + '"></td>')
                .append('<td>' + escapeHtml(r.username) + '</td>')
                .append('<td>' + escapeHtml(time) + '</td>')
                .append('<td>' + typeBadge + '</td>')
                .append('<td>' + escapeHtml(r.taskName || '') + '<br><small style="color:#888;">' + escapeHtml(r.address || '') + '</small></td>')
                .append('<td>' + latLngCell(r.visitLocation, '#27ae60') + '</td>')
                .append('<td>' + latLngCell(r.checkInLatLng, '#e67e22') + '</td>')
                .append('<td><span class="label label-warning">' + r.distanceM + ' m</span>' + mapBoth + '</td>')
                .append('<td>' + attach + '</td>')
                .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>');
            $tb.append($tr);
        });
        $('#bra-select-all').prop('checked', false);
        updateSelectionUi();
    }

    function latLngCell(s, color) {
        if (!s) return '<span style="color:#aaa;">-</span>';
        var safe = escapeHtml(s);
        return '<span style="display:inline-block;width:8px;height:8px;border-radius:50%;background:' + color + ';margin-right:6px;vertical-align:middle;"></span>'
            + '<a href="https://www.google.com/maps?q=' + encodeURIComponent(s) + '" target="_blank" style="font-family:monospace;font-size:11px;">' + safe + '</a>';
    }

    function mapsDirUrl(visit, checkin) {
        return 'https://www.google.com/maps/dir/?api=1&origin=' + encodeURIComponent(visit) + '&destination=' + encodeURIComponent(checkin);
    }

    function badgeForType(t) {
        t = (t || '').toLowerCase();
        if (t === 'office-visit') return '<span class="label label-primary">Office</span>';
        if (t === 'lead') return '<span class="label label-info">Lead</span>';
        return '<span class="label label-default">Partner</span>';
    }

    function escapeHtml(s) {
        return (s == null ? '' : String(s))
            .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')
            .replace(/"/g, '&quot;').replace(/'/g, '&#39;');
    }

    function selectedIds() {
        return $('.bra-row-check:checked').map(function () {
            return $(this).data('id');
        }).get();
    }

    function updateSelectionUi() {
        var ids = selectedIds();
        $('#bra-sel-count').text(ids.length);
        $('#bra-approve-selected').prop('disabled', ids.length === 0);
    }

    $('#bra-fetch').on('click', fetchRows);

    $(document).on('change', '#bra-select-all', function () {
        var on = $(this).is(':checked');
        $('.bra-row-check').prop('checked', on);
        updateSelectionUi();
    });

    $(document).on('change', '.bra-row-check', updateSelectionUi);

    $(document).on('click', '.bra-view-attach', function () {
        $('#bra-attach-img').attr('src', $(this).data('src'));
        $('#bra-attach-modal').modal('show');
    });

    $(document).on('click', '.bra-approve-one', function () {
        var $btn = $(this);
        var id = $btn.data('id');
        $btn.prop('disabled', true).html('<i class="fa fa-spinner fa-spin"></i>');
        $.post(ctx + '/beat-report/approve-checkin', {trackingId: id}, function () {
            $btn.closest('tr').fadeOut(200, function () {
                $(this).remove();
                updateSelectionUi();
            });
        }).fail(function () {
            alert('Approve failed');
            $btn.prop('disabled', false).html('<i class="fa fa-check"></i> Approve');
        });
    });

    $('#bra-approve-selected').on('click', function () {
        var ids = selectedIds();
        if (!ids.length) return;
        if (!confirm('Approve ' + ids.length + ' off-site check-in(s)?')) return;
        var $btn = $(this).prop('disabled', true).html('<i class="fa fa-spinner fa-spin"></i> Approving...');
        $.post({
            url: ctx + '/beat-report/approve-checkin-bulk',
            data: $.param({trackingIds: ids}, true)
        }).done(function (resp) {
            (resp.approved || []).forEach(function (id) {
                $('.bra-row-check[data-id="' + id + '"]').closest('tr').remove();
            });
            if ((resp.failed || []).length) {
                alert(resp.failed.length + ' row(s) could not be approved');
            }
            updateSelectionUi();
        }).fail(function () {
            alert('Bulk approve failed');
        }).always(function () {
            $btn.html('<i class="fa fa-check"></i> Approve selected (<span id="bra-sel-count">0</span>)');
            updateSelectionUi();
        });
    });

    // Auto-load on first render so the head sees pending work immediately.
    fetchRows();
})();