Subversion Repositories SmartDukaan

Rev

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

Rev 36792 Rev 36868
Line 1178... Line 1178...
1178
            prompt("Share this link with the prospect:", url);
1178
            prompt("Share this link with the prospect:", url);
1179
        }
1179
        }
1180
    });
1180
    });
1181
});
1181
});
1182
 
1182
 
-
 
1183
// Manual geo verification — for cases where the prospect refused to tap the
-
 
1184
// verification link. Team-member confirms lat/lng over phone (or pastes a
-
 
1185
// Maps URL the prospect shared) and writes it APPROVED directly.
-
 
1186
function ensureManualVerifyModal() {
-
 
1187
    if ($('#manualVerifyGeoModal').length) return;
-
 
1188
    var html =
-
 
1189
        '<div id="manualVerifyGeoModal" class="modal" role="dialog" tabindex="-1">' +
-
 
1190
        '  <div class="modal-dialog modal-lg">' +
-
 
1191
        '    <div class="modal-content">' +
-
 
1192
        '      <div class="modal-header">' +
-
 
1193
        '        <button type="button" class="close" data-dismiss="modal">&times;</button>' +
-
 
1194
        '        <h4 class="modal-title">Verify Lead Location Manually</h4>' +
-
 
1195
        '      </div>' +
-
 
1196
        '      <div class="modal-body" style="max-height:75vh;overflow-y:auto;">' +
-
 
1197
        '        <input type="hidden" id="manualVerifyLeadId">' +
-
 
1198
        '        <div class="form-group">' +
-
 
1199
        '          <label>Address <small class="text-muted">(include city, state, pincode for best result)</small></label>' +
-
 
1200
        '          <div class="input-group">' +
-
 
1201
        '            <input type="text" class="form-control" id="manualVerifyAddress" placeholder="e.g. Shop 12, Sector 18, Noida, UP, 201301">' +
-
 
1202
        '            <span class="input-group-btn">' +
-
 
1203
        '              <button type="button" class="btn btn-default" id="manualVerifyGeocodeBtn">Find on map</button>' +
-
 
1204
        '            </span>' +
-
 
1205
        '          </div>' +
-
 
1206
        '        </div>' +
-
 
1207
        '        <div class="form-group">' +
-
 
1208
        '          <label>Latitude, Longitude</label>' +
-
 
1209
        '          <div class="input-group">' +
-
 
1210
        '            <input type="text" class="form-control" id="manualVerifyLatLng" placeholder="28.6139,77.2090">' +
-
 
1211
        '            <span class="input-group-btn">' +
-
 
1212
        '              <button type="button" class="btn btn-default" id="manualVerifyPreviewBtn">Show on map</button>' +
-
 
1213
        '            </span>' +
-
 
1214
        '          </div>' +
-
 
1215
        '          <small class="text-muted">You can also paste a Google Maps URL containing coords.</small>' +
-
 
1216
        '        </div>' +
-
 
1217
        '        <div class="form-group" id="manualVerifyMapWrap" style="display:none;">' +
-
 
1218
        '          <label>Map preview <small class="text-muted">(confirm the pin is right)</small></label>' +
-
 
1219
        '          <div style="border:1px solid #ddd;border-radius:3px;overflow:hidden;">' +
-
 
1220
        '            <iframe id="manualVerifyMapFrame" width="100%" height="260" frameborder="0" style="border:0;" allowfullscreen></iframe>' +
-
 
1221
        '          </div>' +
-
 
1222
        '          <small><a href="#" id="manualVerifyOpenMap" target="_blank">Open in Google Maps</a></small>' +
-
 
1223
        '        </div>' +
-
 
1224
        '        <div class="form-group">' +
-
 
1225
        '          <label>Store-board photo <span class="text-danger">*</span> <small class="text-muted">(required &mdash; proves the verification)</small></label>' +
-
 
1226
        '          <input type="file" id="manualVerifyPhoto" accept="image/jpeg,image/png" required>' +
-
 
1227
        '          <div id="manualVerifyPhotoPreview" style="margin-top:6px;display:none;">' +
-
 
1228
        '            <img id="manualVerifyPhotoImg" src="" style="max-height:120px;border:1px solid #ddd;border-radius:3px;padding:2px;">' +
-
 
1229
        '          </div>' +
-
 
1230
        '        </div>' +
-
 
1231
        '        <div class="form-group">' +
-
 
1232
        '          <label>Remark <small class="text-muted">(optional)</small></label>' +
-
 
1233
        '          <input type="text" class="form-control" id="manualVerifyRemark" placeholder="e.g. Confirmed on call with prospect">' +
-
 
1234
        '        </div>' +
-
 
1235
        '        <div id="manualVerifyErr" class="text-danger" style="display:none;"></div>' +
-
 
1236
        '      </div>' +
-
 
1237
        '      <div class="modal-footer">' +
-
 
1238
        '        <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>' +
-
 
1239
        '        <button type="button" class="btn btn-success" id="manualVerifySaveBtn">Save &amp; Verify</button>' +
-
 
1240
        '      </div>' +
-
 
1241
        '    </div>' +
-
 
1242
        '  </div>' +
-
 
1243
        '</div>';
-
 
1244
    $('body').append(html);
-
 
1245
}
-
 
1246
 
-
 
1247
function manualVerifyShowMap(lat, lng) {
-
 
1248
    var src = 'https://www.google.com/maps?q=' + lat + ',' + lng + '&z=17&output=embed';
-
 
1249
    $('#manualVerifyMapFrame').attr('src', src);
-
 
1250
    $('#manualVerifyOpenMap').attr('href', 'https://www.google.com/maps?q=' + lat + ',' + lng);
-
 
1251
    $('#manualVerifyMapWrap').show();
-
 
1252
}
-
 
1253
 
-
 
1254
// Parses raw "lat,lng" or a Google Maps URL containing the coords.
-
 
1255
// Maps formats covered: /@lat,lng, /maps?q=lat,lng, ?ll=lat,lng, ?destination=lat,lng.
-
 
1256
function parseLatLngInput(raw) {
-
 
1257
    if (!raw) return null;
-
 
1258
    var s = String(raw).trim();
-
 
1259
    // Strip any leading "lat:" / "lng:" tokens
-
 
1260
    var direct = s.match(/(-?\d{1,3}\.\d+)\s*,\s*(-?\d{1,3}\.\d+)/);
-
 
1261
    if (direct) return {lat: parseFloat(direct[1]), lng: parseFloat(direct[2])};
-
 
1262
    return null;
-
 
1263
}
-
 
1264
 
-
 
1265
$(document).on('click', '.verifyGeoManual', function (e) {
-
 
1266
    e.stopPropagation();
-
 
1267
    var lid = $(this).data('leadid');
-
 
1268
    ensureManualVerifyModal();
-
 
1269
    $('#manualVerifyLeadId').val(lid);
-
 
1270
    $('#manualVerifyAddress').val('');
-
 
1271
    $('#manualVerifyLatLng').val('');
-
 
1272
    $('#manualVerifyRemark').val('');
-
 
1273
    $('#manualVerifyErr').hide().text('');
-
 
1274
    $('#manualVerifyMapWrap').hide();
-
 
1275
    $('#manualVerifyMapFrame').attr('src', '');
-
 
1276
    $('#manualVerifyPhoto').val('');
-
 
1277
    $('#manualVerifyPhotoImg').attr('src', '');
-
 
1278
    $('#manualVerifyPhotoPreview').hide();
-
 
1279
    $('#manualVerifyGeoModal').modal('show');
-
 
1280
});
-
 
1281
 
-
 
1282
// Local thumbnail preview as soon as the user picks a file (no upload yet —
-
 
1283
// upload happens on Save so we don't orphan documents on cancel).
-
 
1284
$(document).on('change', '#manualVerifyPhoto', function () {
-
 
1285
    var f = this.files && this.files[0];
-
 
1286
    if (!f) {
-
 
1287
        $('#manualVerifyPhotoPreview').hide();
-
 
1288
        return;
-
 
1289
    }
-
 
1290
    var reader = new FileReader();
-
 
1291
    reader.onload = function (ev) {
-
 
1292
        $('#manualVerifyPhotoImg').attr('src', ev.target.result);
-
 
1293
        $('#manualVerifyPhotoPreview').show();
-
 
1294
    };
-
 
1295
    reader.readAsDataURL(f);
-
 
1296
});
-
 
1297
 
-
 
1298
// Address -> coords via server (uses existing GeocodingService).
-
 
1299
// On success, fills the lat/lng box and renders the map preview.
-
 
1300
$(document).on('click', '#manualVerifyGeocodeBtn', function () {
-
 
1301
    var addr = ($('#manualVerifyAddress').val() || '').trim();
-
 
1302
    if (!addr) {
-
 
1303
        $('#manualVerifyErr').text('Enter an address first.').show();
-
 
1304
        return;
-
 
1305
    }
-
 
1306
    $('#manualVerifyErr').hide();
-
 
1307
    var btn = $(this);
-
 
1308
    btn.prop('disabled', true).text('Finding...');
-
 
1309
    $.ajax({
-
 
1310
        url: context + '/lead-geo/geocode-address',
-
 
1311
        type: 'POST',
-
 
1312
        data: {address: addr},
-
 
1313
        success: function (resp) {
-
 
1314
            btn.prop('disabled', false).text('Find on map');
-
 
1315
            var r = resp && resp.response ? resp.response : resp;
-
 
1316
            if (!r || !r.success) {
-
 
1317
                $('#manualVerifyErr').text((r && r.message) || 'Could not geocode that address.').show();
-
 
1318
                return;
-
 
1319
            }
-
 
1320
            $('#manualVerifyLatLng').val(r.latitude + ',' + r.longitude);
-
 
1321
            manualVerifyShowMap(r.latitude, r.longitude);
-
 
1322
        },
-
 
1323
        error: function () {
-
 
1324
            btn.prop('disabled', false).text('Find on map');
-
 
1325
            $('#manualVerifyErr').text('Geocode request failed. Try again.').show();
-
 
1326
        }
-
 
1327
    });
-
 
1328
});
-
 
1329
 
-
 
1330
// "Show on map" — re-render the iframe from whatever is in the lat/lng input.
-
 
1331
// Useful after the user nudges the coords manually.
-
 
1332
$(document).on('click', '#manualVerifyPreviewBtn', function () {
-
 
1333
    var parsed = parseLatLngInput($('#manualVerifyLatLng').val());
-
 
1334
    if (!parsed) {
-
 
1335
        $('#manualVerifyErr').text('Enter latitude,longitude first.').show();
-
 
1336
        return;
-
 
1337
    }
-
 
1338
    $('#manualVerifyErr').hide();
-
 
1339
    manualVerifyShowMap(parsed.lat, parsed.lng);
-
 
1340
});
-
 
1341
 
-
 
1342
$(document).on('click', '#manualVerifySaveBtn', function () {
-
 
1343
    var lid = $('#manualVerifyLeadId').val();
-
 
1344
    var raw = $('#manualVerifyLatLng').val();
-
 
1345
    var remark = $('#manualVerifyRemark').val() || '';
-
 
1346
    var parsed = parseLatLngInput(raw);
-
 
1347
    if (!parsed) {
-
 
1348
        $('#manualVerifyErr').text('Could not read latitude/longitude. Paste like 28.6139,77.2090').show();
-
 
1349
        return;
-
 
1350
    }
-
 
1351
    if (parsed.lat < -90 || parsed.lat > 90 || parsed.lng < -180 || parsed.lng > 180
-
 
1352
        || (parsed.lat === 0 && parsed.lng === 0)) {
-
 
1353
        $('#manualVerifyErr').text('Latitude/longitude out of range.').show();
-
 
1354
        return;
-
 
1355
    }
-
 
1356
    var fileInput = document.getElementById('manualVerifyPhoto');
-
 
1357
    var pickedFile = fileInput && fileInput.files && fileInput.files[0];
-
 
1358
    if (!pickedFile) {
-
 
1359
        $('#manualVerifyErr').text('Please attach a store-board photo to verify.').show();
-
 
1360
        return;
-
 
1361
    }
-
 
1362
    $('#manualVerifyErr').hide();
-
 
1363
    var btn = $('#manualVerifySaveBtn');
-
 
1364
    btn.prop('disabled', true).text('Verifying...');
-
 
1365
 
-
 
1366
    function callVerify(docId) {
-
 
1367
        $.ajax({
-
 
1368
            url: context + '/lead-geo/manual-verify',
-
 
1369
            type: 'POST',
-
 
1370
            data: {
-
 
1371
                leadId: lid,
-
 
1372
                latitude: parsed.lat,
-
 
1373
                longitude: parsed.lng,
-
 
1374
                remark: remark,
-
 
1375
                imageDocumentId: docId || 0
-
 
1376
            },
-
 
1377
            success: function () {
-
 
1378
                btn.prop('disabled', false).text('Save & Verify');
-
 
1379
                $('#manualVerifyGeoModal').modal('hide');
-
 
1380
                // Replace the cell of this lead row with the Verified badge so
-
 
1381
                // the user sees the result without reloading the whole list.
-
 
1382
                var $cell = $('.verifyGeoManual[data-leadid="' + lid + '"]').closest('td');
-
 
1383
                if ($cell.length) {
-
 
1384
                    var photoBtn = docId > 0
-
 
1385
                        ? '  <a href="' + context + '/open-attachment?documentId=' + docId + '" target="_blank" class="btn btn-xs btn-default" style="margin-bottom:2px;">View Photo</a>'
-
 
1386
                        : '';
-
 
1387
                    $cell.html(
-
 
1388
                        '<div class="btn-group-vertical" style="width:100%">' +
-
 
1389
                        '  <span class="label label-success" style="margin-bottom:4px;">Verified</span>' +
-
 
1390
                        '  <a href="https://www.google.com/maps?q=' + parsed.lat + ',' + parsed.lng + '" target="_blank" class="btn btn-xs btn-default" style="margin-bottom:2px;">View Map</a>' +
-
 
1391
                        photoBtn +
-
 
1392
                        '  <button class="btn btn-xs btn-danger reject-geo" data-leadid="' + lid + '">Revoke</button>' +
-
 
1393
                        '</div>'
-
 
1394
                    );
-
 
1395
                }
-
 
1396
            },
-
 
1397
            error: function (xhr) {
-
 
1398
                btn.prop('disabled', false).text('Save & Verify');
-
 
1399
                var msg = 'Failed to verify. Please try again.';
-
 
1400
                try {
-
 
1401
                    var j = xhr.responseJSON || JSON.parse(xhr.responseText || '{}');
-
 
1402
                    if (j && j.response) msg = j.response;
-
 
1403
                    else if (j && j.message) msg = j.message;
-
 
1404
                } catch (e) {
-
 
1405
                }
-
 
1406
                $('#manualVerifyErr').text(msg).show();
-
 
1407
            }
-
 
1408
        });
-
 
1409
    }
-
 
1410
 
-
 
1411
    // Upload first, then verify with the returned document id. Photo is
-
 
1412
    // required (gate at the top of the handler), so we always go through this.
-
 
1413
    btn.text('Uploading photo...');
-
 
1414
    var formData = new FormData();
-
 
1415
    formData.append('file', pickedFile, pickedFile.name || 'store-photo.jpg');
-
 
1416
    $.ajax({
-
 
1417
        url: context + '/lead-geo/upload-image',
-
 
1418
        type: 'POST',
-
 
1419
        data: formData,
-
 
1420
        processData: false,
-
 
1421
        contentType: false,
-
 
1422
        success: function (resp) {
-
 
1423
            var r = resp && resp.response ? resp.response : resp;
-
 
1424
            var docId = r && (r.document_id || r.documentId || r.id);
-
 
1425
            if (!docId) {
-
 
1426
                btn.prop('disabled', false).text('Save & Verify');
-
 
1427
                $('#manualVerifyErr').text('Photo upload failed. Try again or remove the photo.').show();
-
 
1428
                return;
-
 
1429
            }
-
 
1430
            btn.text('Verifying...');
-
 
1431
            callVerify(docId);
-
 
1432
        },
-
 
1433
        error: function () {
-
 
1434
            btn.prop('disabled', false).text('Save & Verify');
-
 
1435
            $('#manualVerifyErr').text('Photo upload failed. Try again or remove the photo.').show();
-
 
1436
        }
-
 
1437
    });
-
 
1438
});
-
 
1439
 
1183
// Geo Review navigation
1440
// Geo Review navigation
1184
$(document).on('click', '.geo-review', function () {
1441
$(document).on('click', '.geo-review', function () {
1185
    doGetAjaxRequestHandler(context + "/lead-geo/pending-reviews", function (response) {
1442
    doGetAjaxRequestHandler(context + "/lead-geo/pending-reviews", function (response) {
1186
        $('#main-content').html(response);
1443
        $('#main-content').html(response);
1187
    });
1444
    });