Subversion Repositories SmartDukaan

Rev

Rev 37046 | Rev 37050 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
35548 aman 1
$(function () {
2
    $(document).on('click', ".lead", function () {
3
        loadLead("main-content");
4
    });
29598 tejbeer 5
 
35548 aman 6
    $(document).on('click', ".team-commitment", function () {
7
        loadTeamCommitment("main-content");
8
    });
30439 tejbeer 9
 
10
 
35548 aman 11
    $(document).on('click', ".partner-health", function () {
12
        loadPartnerHealth("main-content");
13
    });
29598 tejbeer 14
 
35548 aman 15
    $(document).on('click', ".lead-detail", function () {
16
        loadLeadDetail("main-content");
17
    });
30439 tejbeer 18
 
31370 tejbeer 19
 
35548 aman 20
    $(document).on('click', ".submitCommitment",
21
        function () {
22
            var startDateTime = getDatesFromPicker('input[name="commitmentDate"]').startDate;
23
            doGetAjaxRequestHandler(context + "/getTeamCommitment?date="
24
                + startDateTime, function (response) {
25
                $('.teamcommitmentcontainer').html(response);
31370 tejbeer 26
 
35548 aman 27
            });
28
        });
30439 tejbeer 29
 
30
 
35548 aman 31
    $(document).on('click', ".submitDateWiseLead", function () {
30439 tejbeer 32
 
35769 amit 33
        var startDate = $("#startDate").val();
34
        var endDate = $("#endDate").val();
35548 aman 35
        var status = $("#statusFilter").val();
36
        var color = $("#colorFilter").val();
31370 tejbeer 37
 
35548 aman 38
        if (color == null) {
39
            color = "";
40
        }
31370 tejbeer 41
 
35769 amit 42
        if (startDate && endDate) {
43
            var start = new Date(startDate);
44
            var end = new Date(endDate);
45
            if (end < start) {
46
                alert("End date must be after start date");
47
                return;
48
            }
49
        }
31370 tejbeer 50
 
35769 amit 51
        doGetAjaxRequestHandler(context + "/getOpenLead?leadStatus=" + status + "&color=" + color + "&startDate=" + startDate + "&endDate=" + endDate, function (response) {
35548 aman 52
            $('#' + 'main-content').html(response);
53
        });
29598 tejbeer 54
 
55
 
35548 aman 56
    })
57
    ;$(document).on('click', ".downloadDateWiseLead", function () {
29598 tejbeer 58
 
35769 amit 59
        var startDate = $("#startDate").val();
60
        var endDate = $("#endDate").val();
35548 aman 61
        var status = $("#statusFilter").val();
62
        var color = $("#colorFilter").val();
29598 tejbeer 63
 
35548 aman 64
        if (color == null) {
65
            color = "";
66
        }
29598 tejbeer 67
 
35769 amit 68
        if (startDate && endDate) {
69
            var start = new Date(startDate);
70
            var end = new Date(endDate);
71
            if (end < start) {
72
                alert("End date must be after start date");
73
                return;
74
            }
75
        }
76
 
77
        let endPoint = `${context}/downloadDateWiseLead?leadStatus=${status}&color=${color}&startDate=${startDate}&endDate=${endDate}`;
35548 aman 78
        window.location.href = endPoint;
31249 tejbeer 79
 
35548 aman 80
    });
34650 aman.kumar 81
 
37046 aman 82
    // Lead-table Search boxes (top DataTables box + bottom mirror below the table/pagination) =
83
    // GLOBAL partner search: matches ANY lead by name / mobile / outlet / city across ALL statuses
84
    // and ALL dates (this year, last year, anytime) - not just the loaded date-scoped rows. It
85
    // searches AS YOU TYPE (debounced) so old partners surface without needing to press Enter;
86
    // Enter still triggers an immediate search. Results render into #global-search-results above
87
    // the date-scoped table; the view auto-scrolls there so a search from the bottom box is visible
88
    // without the user having to scroll back up manually.
89
    var LEAD_SEARCH_BOXES = "#lead-table_filter input, #lead-table-bottom-filter";
37021 aman 90
    var leadGlobalSearchTimer = null;
91
 
37048 ranu 92
    function clearInjectedGlobalRows() {
93
        if ($.fn.dataTable.isDataTable('#lead-table')) {
94
            $('#lead-table').DataTable()
95
                .rows('.global-search-row')
96
                .remove()
97
                .draw(false);
98
        }
99
    }
100
 
37021 aman 101
    function runGlobalLeadSearch(term) {
102
        term = $.trim(term || "");
103
        if (term.length < 2) {
104
            $('#global-search-results').html("");
37048 ranu 105
            clearInjectedGlobalRows();
37021 aman 106
            return;
107
        }
108
        var safeTerm = $('<div>').text(term).html();
109
        doGetAjaxRequestHandler(context + "/globalLeadSearch?searchTerm=" + encodeURIComponent(term),
110
            function (response) {
111
                $('#global-search-results').html(
112
                    '<h4 style="margin:15px 0 8px;">Search results — all partners, any date '
113
                    + '<small class="text-muted">(matching "' + safeTerm + '")</small></h4>' + response);
37046 aman 114
                var resultsEl = document.getElementById('global-search-results');
115
                if (resultsEl) {
116
                    resultsEl.scrollIntoView({behavior: 'smooth', block: 'start'});
117
                }
37048 ranu 118
 
119
                // Mirror the hits into the main #lead-table so the same row is findable there too.
120
                // Rows carry class .global-search-row so we can clear them on the next search.
121
                clearInjectedGlobalRows();
122
                var $hiddenRows = $('#global-search-main-rows tbody tr');
123
                if ($hiddenRows.length && $.fn.dataTable.isDataTable('#lead-table')) {
124
                    var dt = $('#lead-table').DataTable();
125
                    $hiddenRows.each(function () {
126
                        dt.row.add(this);
127
                    });
128
                    dt.draw(false);
129
                }
37021 aman 130
            });
131
    }
132
 
37046 aman 133
    $(document).on('keydown', LEAD_SEARCH_BOXES, function (e) {
36984 aman 134
        if (e.which === 13) {
135
            e.preventDefault();
37021 aman 136
            clearTimeout(leadGlobalSearchTimer);
137
            runGlobalLeadSearch($(this).val());
36984 aman 138
        }
139
    });
34650 aman.kumar 140
 
37046 aman 141
    $(document).on('input', LEAD_SEARCH_BOXES, function () {
37021 aman 142
        var term = $(this).val();
143
        clearTimeout(leadGlobalSearchTimer);
144
        leadGlobalSearchTimer = setTimeout(function () {
145
            runGlobalLeadSearch(term);
146
        }, 350);
36984 aman 147
    });
148
 
37046 aman 149
    // Bottom box isn't a native DataTables filter element, so mirror it into the DataTable's own
150
    // search + keep both boxes showing the same value regardless of which one the user typed into.
151
    $(document).on('keyup input', '#lead-table-bottom-filter', function () {
152
        var term = $(this).val();
153
        $('#lead-table_filter input').val(term);
154
        if ($.fn.dataTable.isDataTable('#lead-table')) {
155
            $('#lead-table').DataTable().search(term).draw();
156
        }
157
    });
36984 aman 158
 
37046 aman 159
    $(document).on('keyup input', '#lead-table_filter input', function () {
160
        $('#lead-table-bottom-filter').val($(this).val());
161
    });
162
 
163
 
35548 aman 164
    $(document).on('click', ".visit-request-plan", function () {
34650 aman.kumar 165
 
35548 aman 166
        doGetAjaxRequestHandler(context + "/visitPlan", function (response) {
167
            $('#' + 'main-content').html(response);
168
        });
34650 aman.kumar 169
 
35548 aman 170
    });
34650 aman.kumar 171
 
35548 aman 172
    $(document).on('click', ".visitPlan", function () {
25980 tejbeer 173
 
35548 aman 174
        let dateWisePlan = $("#dateVisitSearch").val();
31249 tejbeer 175
 
35548 aman 176
        doGetAjaxRequestHandler(context + "/visit/getVisitPlan?date=" + dateWisePlan, function (response) {
177
            $('#' + 'main-content').html(response);
178
        });
31249 tejbeer 179
 
35548 aman 180
    });
31249 tejbeer 181
 
35548 aman 182
    $(document).on('click', ".lead-close", function () {
183
        loadClosedLead("main-content");
184
    });
31249 tejbeer 185
 
35548 aman 186
    $(document).on('click', "#lead-close-paginated .next",
187
        function () {
31249 tejbeer 188
 
35548 aman 189
            var searchText = $("#authUser").val();
190
            // var searchTxt=$("#scheme-search-text").val();
191
            console.log(searchText);
192
            if (typeof (searchText) == "undefined" || !searchText) {
193
                searchText = "";
194
            }
31249 tejbeer 195
 
35548 aman 196
            if ((searchText)) {
197
                var params = {};
198
                params['searchTerm'] = searchText;
199
                loadPaginatedNextItems('/searchLeadPaginated', params,
200
                    'lead-close-paginated', 'close-lead-table',
201
                    'lead-close-container');
202
            } else {
31249 tejbeer 203
 
35548 aman 204
                loadPaginatedNextItems('/getPaginatedClosedLeads', null,
205
                    'lead-close-paginated', 'close-lead-table',
206
                    'lead-close-container');
207
            }
208
            $(this).blur();
209
        });
31249 tejbeer 210
 
35548 aman 211
    $(document).on('click', "#lead-close-paginated .previous",
212
        function () {
213
            var searchText = $("#authUser").val();
214
            // var searchTxt=$("#scheme-search-text").val();
215
            console.log(searchText);
216
            if (typeof (searchText) == "undefined" || !searchText) {
217
                searchText = "";
218
            }
25988 tejbeer 219
 
35548 aman 220
            if ((searchText)) {
221
                var params = {};
222
                params['searchTerm'] = searchText;
223
                loadPaginatedPreviousItems('/searchLeadPaginated', params,
224
                    'lead-close-paginated', 'close-lead-table',
225
                    'lead-close-container');
226
            } else {
227
                loadPaginatedPreviousItems('/getPaginatedClosedLeads',
228
                    null, 'lead-close-paginated', 'close-lead-table',
229
                    'lead-close-container');
230
            }
231
            $(this).blur();
232
        });
25988 tejbeer 233
 
35548 aman 234
    $(document).on('click', "#close-lead-search-button", function () {
235
        var searchText = $("#authUser").val();
236
        if (typeof (searchText) == "undefined" || !searchText) {
237
            searchText = "";
238
        }
239
        loadLeadSearchInfo(searchText);
240
    });
25988 tejbeer 241
 
35548 aman 242
    $(document).on("keyup", "#authUser", function (e) {
243
        var keyCode = e.keyCode || e.which;
244
        if (keyCode == 13) {
245
            $("#close-lead-search-button").click();
246
        }
247
    });
248
    $(document).on('click', ".view",
249
        function () {
250
            var id = $(this).data('requestid');
251
            console.log(id);
252
            doGetAjaxRequestHandler(context + "/getLeadActivity?leadId="
253
                + id, function (response) {
25988 tejbeer 254
 
35548 aman 255
                console.log(response)
25988 tejbeer 256
 
35548 aman 257
                $('#fetchLeadActivityData .modal-content').html(response);
25988 tejbeer 258
 
35548 aman 259
            });
260
        });
25988 tejbeer 261
 
35548 aman 262
    $(document).on('click', ".newLead", function () {
263
        $('#newEntryLeadModal').modal('show');
264
        $("#scheduleTime").hide();
265
    });
25988 tejbeer 266
 
35548 aman 267
    $(document).on('click', ".show-lead", function () {
268
        var status = $("#statusFilter").val();
269
        doGetAjaxRequestHandler(context + "/getOpenLead?leadStatus=" + status, function (response) {
270
            $('#' + 'main-content').html(response);
271
        });
272
    });
25980 tejbeer 273
 
31370 tejbeer 274
 
35548 aman 275
    $(document).on('click', ".show-colowise-lead", function () {
276
        var status = $("#statusFilter").val();
277
        var color = $("#colorFilter").val();
278
        doGetAjaxRequestHandler(context + "/getOpenLead?leadStatus=" + status + "&color=" + color, function (response) {
279
            $('#' + 'main-content').html(response);
280
        });
281
    });
25980 tejbeer 282
 
35548 aman 283
    $(document).on('click', "#uploadIvoryLead", function () {
25980 tejbeer 284
 
35548 aman 285
        window.location.href = context + "/downloadIvoryLead";
286
    });
25980 tejbeer 287
 
35548 aman 288
    $(document).on('click', ".submitLeadGenerate", function () {
27609 tejbeer 289
 
35548 aman 290
        console.log("hello");
291
        if (confirm('Confirm upload ?')) {
292
            var fileSelector = $(this)[0];
293
            if (fileSelector != undefined) {
294
                var url = `${context}/csvFileAndSetLead`;
295
                console.log(url);
296
                var file = $(".fileLeadGenerate")[0].files[0];
297
                let fileInput = $(this);
298
                console.log("file" + file);
299
                console.log("fileInput" + fileInput);
300
                doAjaxUploadRequestHandler(
301
                    url,
302
                    'POST',
303
                    file, function (response) {
27642 tejbeer 304
 
35548 aman 305
                        console.log("reponse" + response);
31370 tejbeer 306
 
35548 aman 307
                        if (response == true) {
308
                            alert("successfully uploaded");
31370 tejbeer 309
 
310
 
35548 aman 311
                        }
312
                    });
29598 tejbeer 313
 
35548 aman 314
            }
315
        } else {
316
            // Do nothing!
317
        }
318
    });
27642 tejbeer 319
 
320
 
35548 aman 321
    $(document).on('click', ".lead-request",
322
        function () {
29598 tejbeer 323
 
35548 aman 324
            var firstName = $('input[name="firstName"]').val();
325
            var lastName = $('input[name="lastName"]').val();
326
            var mobile = $('input[name="mobile"]').val();
327
            var address = $('input[name="address"]').val();
328
            var status = $("#status").val();
329
            var city = $('input[name="city"]').val();
330
            var state = $("#state").val();
331
            var remark = $("#createRemark").val();
332
            var assignTo = $("#createAssignTo").val();
333
            var source = $("#leadSource").val();
334
            var communicationType = $("#communicationTye").val();
29427 manish 335
 
35548 aman 336
            var conversionprobability = $("#conversionprobabilit").val();
29598 tejbeer 337
 
338
 
35548 aman 339
            var outletName = $('input[name="leadoutletName"]').val();
340
            var counterSize = $('input[name="leadcounterSize"]').val();
341
            var table = document.getElementById('brandtable');
342
            var brandValueJson = [];
343
            var leadBrands;
29598 tejbeer 344
 
35548 aman 345
            console.log(conversionprobability)
29598 tejbeer 346
 
347
 
35548 aman 348
            if (firstName === "" && lastName === "" && mobile === ""
349
                && address === "" && status === "" && city === ""
350
                && state === "" && remark === "" && source === "") {
351
                alert("Field can't be empty");
352
                return;
353
            }
29598 tejbeer 354
 
25980 tejbeer 355
 
35548 aman 356
            if (firstName === "") {
357
                alert("First Name is required");
358
                return;
359
            }
360
            if (lastName === "") {
361
                alert("Last Name is required");
362
                return;
363
            }
364
            if (mobile === "") {
365
                alert("Mobile is required");
366
                return;
367
            }
368
            if (status === "") {
369
                alert("Status is required");
370
                return;
371
            }
372
            if (address === "") {
373
                alert("address is required");
374
                return;
375
            }
376
            if (city === "") {
377
                alert("city is required");
378
                return;
379
            }
32471 tejbeer 380
 
35548 aman 381
            if (state === "") {
382
                alert("state is required");
383
                return;
384
            }
385
            if (source === "") {
386
                alert("Source is required")
387
                return;
388
            }
32471 tejbeer 389
 
35548 aman 390
            if (remark === "") {
391
                alert("Remark is required");
392
                return;
393
            }
32471 tejbeer 394
 
35548 aman 395
            if (conversionprobability === "") {
396
                alert("Conversion Probability is required");
397
                return;
398
            }
399
            if (status == "followUp" || status == "pending" || status == "finalized") {
400
                if (outletName === "") {
401
                    alert("Outlet Name is required");
402
                    return;
403
                }
25980 tejbeer 404
 
35548 aman 405
                if (counterSize === "") {
406
                    alert("Counter Size is required");
407
                    return;
408
                }
32464 tejbeer 409
 
35548 aman 410
                if (localStorage.getItem("frontph") == "undefined" && localStorage.getItem("frontph") == null) {
411
                    alert("Front Document is required");
412
                    return;
413
                }
32464 tejbeer 414
 
35548 aman 415
                if (localStorage.getItem("internalMarketh") == "undefined" || localStorage.getItem("internalMarketh") == null) {
416
                    alert("Front With Market Document is required");
417
                    return;
418
                }
25980 tejbeer 419
 
35548 aman 420
                if (localStorage.getItem("leftShoth") == "undefined" || localStorage.getItem("leftShoth") == null) {
421
                    alert("Internal Left Shot Document is required");
422
                    return;
423
                }
32464 tejbeer 424
 
35548 aman 425
                if (localStorage.getItem("leftWallh") == "undefined" || localStorage.getItem("leftWallh") == null) {
426
                    alert("Internal Left Wall Document is required");
427
                    return;
428
                }
25980 tejbeer 429
 
430
 
35548 aman 431
                if (localStorage.getItem("rightWallh") == "undefined" || localStorage.getItem("rightWallh") == null) {
432
                    alert("Internal Right Wall Document is required");
433
                    return;
434
                }
25980 tejbeer 435
 
32464 tejbeer 436
 
35548 aman 437
                for (i = 1; i < table.rows.length; i++) {
32464 tejbeer 438
 
35548 aman 439
                    var objCells = table.rows[i].cells;
32464 tejbeer 440
 
35548 aman 441
                    leadBrands = {
442
                        brand: objCells[0].innerText,
443
                        value: objCells[1].getElementsByTagName('input')[0].value
444
                    }
445
                    brandValueJson.push(leadBrands);
446
                }
32464 tejbeer 447
 
448
 
35548 aman 449
            }
32464 tejbeer 450
 
451
 
35548 aman 452
            var leaddetailData = {}
453
            leaddetailData['firstName'] = firstName;
454
            leaddetailData['lastName'] = lastName
455
            leaddetailData['mobile'] = mobile
456
            leaddetailData['address'] = address
457
            leaddetailData['city'] = city
458
            leaddetailData['state'] = state
459
            leaddetailData['status'] = status
460
            leaddetailData['remark'] = remark
461
            leaddetailData['assignTo'] = assignTo
462
            leaddetailData['source'] = source
463
            leaddetailData['colorCheck'] = conversionprobability
32464 tejbeer 464
 
465
 
35548 aman 466
            if (status == "followUp") {
467
                leaddetailData['schelduleTimestamp'] = getDatesFromPicker('#scheduleTime').startDate;
32464 tejbeer 468
 
35548 aman 469
                leaddetailData['communicationType'] = communicationType
470
            }
32464 tejbeer 471
 
472
 
35548 aman 473
            leaddetailData['outletName'] = outletName;
32464 tejbeer 474
 
35548 aman 475
            leaddetailData['counterSize'] = counterSize;
32464 tejbeer 476
 
477
 
35548 aman 478
            leaddetailData['leadBrands'] = brandValueJson;
32464 tejbeer 479
 
35548 aman 480
            console.log(localStorage.getItem("frontp"));
32464 tejbeer 481
 
482
 
35548 aman 483
            leaddetailData['frontp'] = localStorage
484
                .getItem("frontph");
31249 tejbeer 485
 
32464 tejbeer 486
 
35548 aman 487
            leaddetailData['frontWithMarket'] = localStorage
488
                .getItem("internalMarketh");
32464 tejbeer 489
 
490
 
35548 aman 491
            leaddetailData['internalLongShot'] = localStorage
492
                .getItem("leftShoth");
32464 tejbeer 493
 
494
 
35548 aman 495
            leaddetailData['internalLeftWall'] = localStorage
496
                .getItem("leftWallh");
32464 tejbeer 497
 
498
 
35548 aman 499
            leaddetailData['internalRightWall'] = localStorage
500
                .getItem("rightWallh");
32464 tejbeer 501
 
35548 aman 502
            console.log(leaddetailData);
32464 tejbeer 503
 
35548 aman 504
            if (confirm("Are you sure you want to add lead!") == true) {
505
                doPostAjaxRequestWithJsonHandler(context + "/createLead",
506
                    JSON.stringify(leaddetailData), function (response) {
507
                        if (response == 'true') {
508
                            alert("successfully Add");
509
                            $('#newEntryLeadModal').modal('hide');
510
                            $('.modal-backdrop').remove();
511
                            loadLead("main-content");
512
                        } else {
513
                            alert(response);
514
                        }
515
                    });
32464 tejbeer 516
 
35548 aman 517
                return false;
518
            }
519
        });
36642 ranu 520
    window.leadId = null;
35548 aman 521
    var row = null;
37003 ranu 522
    // Turn Assign To into a search-select. We attempt initialisation at 3 points to be
523
    // robust against ordering / DOM-timing issues:
524
    //   1. Immediately at load time (element is in DOM per lead.vm)
525
    //   2. On the modal's shown.bs.modal event (post-transition)
526
    //   3. As a fallback in the click handler with a small delay
527
    function initAssignToSelect2() {
528
        if (!$.fn.select2) {
529
            console.warn('[lead.js] select2 not loaded — falling back to native <select>');
530
            return;
531
        }
532
        var $assign = $('#assignTo');
533
        if ($assign.length === 0) return;
534
        if ($assign.hasClass('select2-hidden-accessible')) return; // already applied
535
        $assign.select2({
536
            placeholder: 'Assign To',
537
            allowClear: true,
538
            width: '100%',
539
            dropdownParent: $('#editLeadData'),
540
            // Hide disabled options — VISIT/TELEPHONIC filter uses .prop('disabled', true).
541
            matcher: function (params, data) {
542
                if (data.element && $(data.element).prop('disabled')) return null;
543
                if (!params.term || $.trim(params.term) === '') return data;
544
                if (data.text && data.text.toLowerCase().indexOf(params.term.toLowerCase()) > -1) return data;
545
                return null;
546
            }
547
        });
548
        console.log('[lead.js] select2 applied to #assignTo');
549
    }
550
 
551
    initAssignToSelect2();
552
    $(document).on('shown.bs.modal', '#editLeadData', initAssignToSelect2);
553
 
35548 aman 554
    $(document).on('click', ".editLead", function () {
555
        $('#editLeadData').modal('show');
37003 ranu 556
        // Belt-and-braces: also try after the modal transition completes.
557
        setTimeout(initAssignToSelect2, 300);
32464 tejbeer 558
 
35548 aman 559
        $("#remark").val("");
37003 ranu 560
        $("#assignTo").val("").trigger('change');
35548 aman 561
        $("#editStatus").val("");
562
        $("#reason").val("");
563
        $("#editCity").val("");
564
        $("#editState").val("");
35769 amit 565
        $("#editSource").val("");
35548 aman 566
        $("#editScheduleTime").hide();
32464 tejbeer 567
 
568
 
35548 aman 569
        localStorage.removeItem("frontph");
570
        localStorage.removeItem("leftShoth");
571
        localStorage.removeItem("rightWallh");
572
        localStorage.removeItem("leftWallh");
573
        localStorage.removeItem("internalMarketh");
32464 tejbeer 574
 
35548 aman 575
        row = $(this).closest("tr");
576
        leadId = $(this).data('leadid');
32464 tejbeer 577
 
35548 aman 578
        doAjaxRequestHandler(
579
            context + "/getLeadDetailByLeadId?leadId=" + leadId,
580
            "GET",
581
            function (response) {
32464 tejbeer 582
 
35548 aman 583
                var data = response.response;
584
                if (!data) return;
585
                console.log(data);
586
                $("#editCity").val(data.city);
587
                $("#editState").val(data.state);
588
                $("input[name='outletName']").val(data.outletName);
589
                $("input[name='counterSize']").val(data.counterSize);
590
            }
591
        );
592
    });
32464 tejbeer 593
 
594
 
35548 aman 595
    $(document).on('click', ".lead-edit-request",
596
        function () {
32464 tejbeer 597
 
36761 ranu 598
            // Gate the assign/status submit on approved geo. Modal stays open so the
599
            // user can still work the other sub-forms (lead detail, etc.).
600
            var clickedBtn = $(this);
36789 ranu 601
            // notInterested is a close-out — no geo / no beat / no assignee
602
            // needed. Skip the geo gate and submit straight through with just
603
            // the activity (status + reason + remark).
604
            var currentStatus = $('#editStatus').val();
605
            if (currentStatus === 'notInterested') {
606
                submitLeadEdit();
607
                return;
608
            }
36792 ranu 609
            // Non-sales assignees (BGC / other internal hand-offs) don't need
610
            // geo or a beat-day — the lead just routes to their queue. Skip the
611
            // geo gate and submit straight through, same as the legacy flow.
612
            var assigneeId = parseInt($('#assignTo').val(), 10);
613
            var isSalesAssignee = !isNaN(assigneeId)
614
                && typeof salesUserIds !== 'undefined'
615
                && salesUserIds.indexOf(assigneeId) !== -1;
616
            if (!isSalesAssignee) {
617
                submitLeadEdit();
618
                return;
619
            }
36761 ranu 620
            if (clickedBtn.data('geoChecking')) return;
621
            clickedBtn.data('geoChecking', true);
622
            doAjaxRequestHandler(
623
                context + "/lead-geo/check/" + leadId,
624
                "GET",
625
                function (response) {
626
                    clickedBtn.removeData('geoChecking');
627
                    var hasGeo = response && response.response && response.response.hasApprovedGeo;
628
                    if (!hasGeo) {
629
                        alert('Live geo-location for this lead has not been approved yet. Please approve the geo-location before assigning / updating status.');
630
                        return;
631
                    }
632
                    submitLeadEdit();
633
                }
634
            );
635
        });
25980 tejbeer 636
 
36761 ranu 637
    function submitLeadEdit() {
638
 
35548 aman 639
            console.log(row);
640
            var remark = $('input[name="remark"]').val();
641
            var assignTo = $("#assignTo").val();
642
            var editStatus = $("#editStatus").val();
643
            var city = $('input[name="editCity"]').val();
644
            var state = $("#editState").val();
645
            var reason = $("#reason").val();
25980 tejbeer 646
 
35769 amit 647
            var startDate = $("#startDate").val();
648
            var endDate = $("#endDate").val();
35548 aman 649
            var leadStatus = $("#statusFilter").val();
650
            var color = $("#colorFilter").val();
651
            var communicationType = $("#communicationType").val();
29640 tejbeer 652
 
35548 aman 653
            var conversionprobability = $("#conversionprobability").val();
35769 amit 654
            var editSource = $("#editSource").val();
29640 tejbeer 655
 
35548 aman 656
            console.log(conversionprobability)
29640 tejbeer 657
 
31473 tejbeer 658
 
35769 amit 659
            console.log(startDate)
35548 aman 660
            console.log(leadStatus)
31370 tejbeer 661
 
35548 aman 662
            console.log(color)
663
            console.log(reason)
31370 tejbeer 664
 
35548 aman 665
            if (remark === "" && assignTo === "" && editStatus === "") {
666
                alert("All fields is required");
667
                return;
668
            }
31370 tejbeer 669
 
36789 ranu 670
        // For notInterested (close-out) the lead doesn't need an assignee
671
        // — it's just a status + reason + remark write. Only enforce
672
        // assignTo for the other statuses where scheduling matters.
673
        if (assignTo === "" && editStatus !== "notInterested") {
35548 aman 674
                alert("assignTo is required");
675
                return;
676
            }
31409 tejbeer 677
 
35548 aman 678
            if (remark === "") {
679
                alert("Remark is required");
680
                return;
681
            }
31370 tejbeer 682
 
683
 
35548 aman 684
            if (editStatus === "") {
685
                alert("status is required");
686
                return;
687
            }
31370 tejbeer 688
 
35548 aman 689
            if (editStatus === "notInterested") {
36789 ranu 690
                if (reason == null || reason === "") {
35548 aman 691
                    alert("Reason  is required");
692
                    return;
693
                }
694
            }
695
            var leadActivityData = {}
696
            leadActivityData['id'] = leadId;
697
            leadActivityData['remark'] = remark;
698
            leadActivityData['assignTo'] = assignTo
699
            leadActivityData['status'] = editStatus
700
            leadActivityData['reason'] = reason
36741 ranu 701
            leadActivityData['colorCheck'] = (conversionprobability === "true" || conversionprobability === true)
35548 aman 702
            if (city && city.trim() !== "") {
703
                leadActivityData.city = city;
704
            }
25980 tejbeer 705
 
35548 aman 706
            if (state && state.trim() !== "") {
707
                leadActivityData.state = state;
708
            }
29473 manish 709
 
35769 amit 710
            if (editSource && editSource.trim() !== "") {
711
                leadActivityData.source = editSource;
712
            }
29598 tejbeer 713
 
35769 amit 714
 
35548 aman 715
            if (editStatus == "followUp") {
36642 ranu 716
                leadActivityData['communicationType'] = communicationType
36792 ranu 717
                var assigneeIdForBeat = parseInt(assignTo, 10);
718
                var isSalesAssigneeForBeat = !isNaN(assigneeIdForBeat)
719
                    && typeof salesUserIds !== 'undefined'
720
                    && salesUserIds.indexOf(assigneeIdForBeat) !== -1;
36741 ranu 721
                var beatVal = $('#beatDate').val();
36792 ranu 722
                // Beat-day gate only applies to sales assignees. Non-sales
723
                // (BGC / other) hand-offs are just routed to the user's queue
724
                // without a beat attachment — same as the legacy flow.
725
                if (isSalesAssigneeForBeat) {
726
                    if (!beatVal) {
727
                        var hasBadges = $('#beatBadges .beat-badge').length > 0;
728
                        if (!hasBadges) {
729
                            alert('No upcoming beat is available for this assignee. Cannot schedule the lead until they have a beat.');
730
                        } else {
731
                            alert('Please select a beat date for the assignee before submitting.');
732
                        }
733
                        return;
36761 ranu 734
                    }
36792 ranu 735
                    var beatDate = beatVal.split('|')[0];
736
                    leadActivityData['scheldule'] = beatDate + 'T12:00:00';
737
                    leadActivityData['beatSelection'] = beatVal;
36642 ranu 738
                }
35548 aman 739
            }
29598 tejbeer 740
 
35548 aman 741
            console.log(leadActivityData);
742
            if (confirm("Are you sure you want to add lead!") == true) {
743
                doPostAjaxRequestWithJsonHandler(context + "/editLead", JSON.stringify(leadActivityData), function (response) {
744
                    console.log(response);
745
                    $('#editLeadData').modal('hide');
746
                    $('.modal-backdrop').remove();
747
                    row.html(response);
748
                });
749
            }
29598 tejbeer 750
 
36761 ranu 751
    }
32477 tejbeer 752
 
753
 
35548 aman 754
    $(document).on('click', ".show-partner-health",
755
        function () {
29598 tejbeer 756
 
35548 aman 757
            var email = $("#authUserFilter").val();
25980 tejbeer 758
 
35548 aman 759
            console.log(email)
760
            doGetAjaxRequestHandler(context + "/partnerHealth?email="
761
                + email, function (response) {
762
                console.log(response)
763
                $('#' + 'main-content').html(response);
25980 tejbeer 764
 
35548 aman 765
            });
766
        });
25980 tejbeer 767
 
768
 
35548 aman 769
    $(document).on('click', ".lead-detail-entry",
770
        function () {
28200 tejbeer 771
 
35548 aman 772
            console.log("hello");
773
            var outletName = $('input[name="outletName"]').val();
774
            var counterSize = $('input[name="counterSize"]').val();
775
            var table = document.getElementById('editbrandtable');
776
            var brandValueJson = [];
777
            var leadBrands;
25980 tejbeer 778
 
35548 aman 779
            if (outletName === "") {
780
                alert("Outlet Name is required");
781
                return;
782
            }
29598 tejbeer 783
 
35548 aman 784
            if (counterSize === "") {
785
                alert("Counter Size is required");
786
                return;
787
            }
32471 tejbeer 788
 
35548 aman 789
            if (localStorage.getItem("frontph") == "undefined" && localStorage.getItem("frontph") == null) {
790
                alert("Front Document is required");
791
                return;
792
            }
31249 tejbeer 793
 
35548 aman 794
            if (localStorage.getItem("internalMarketh") == "undefined" || localStorage.getItem("internalMarketh") == null) {
795
                alert("Front With Market Document is required");
796
                return;
797
            }
25980 tejbeer 798
 
35548 aman 799
            if (localStorage.getItem("leftShoth") == "undefined" || localStorage.getItem("leftShoth") == null) {
800
                alert("Internal Left Shot Document is required");
801
                return;
802
            }
27605 tejbeer 803
 
35548 aman 804
            if (localStorage.getItem("leftWallh") == "undefined" || localStorage.getItem("leftWallh") == null) {
805
                alert("Internal Left Wall Document is required");
806
                return;
807
            }
27605 tejbeer 808
 
30185 tejbeer 809
 
35548 aman 810
            if (localStorage.getItem("rightWallh") == "undefined" || localStorage.getItem("rightWallh") == null) {
811
                alert("Internal Right Wall Document is required");
812
                return;
813
            }
30185 tejbeer 814
 
815
 
35548 aman 816
            for (i = 1; i < table.rows.length; i++) {
30185 tejbeer 817
 
35548 aman 818
                var objCells = table.rows[i].cells;
30185 tejbeer 819
 
35548 aman 820
                leadBrands = {
821
                    brand: objCells[0].innerText,
822
                    value: objCells[1].getElementsByTagName('input')[0].value
823
                }
824
                brandValueJson.push(leadBrands);
825
            }
30185 tejbeer 826
 
30416 tejbeer 827
 
35548 aman 828
            var leadDetailObject = {};
31402 tejbeer 829
 
35548 aman 830
            leadDetailObject['leadId'] = leadId;
30416 tejbeer 831
 
832
 
35548 aman 833
            leadDetailObject['outletName'] = outletName;
31370 tejbeer 834
 
35548 aman 835
            leadDetailObject['counterSize'] = counterSize;
31370 tejbeer 836
 
35548 aman 837
            leadDetailObject['leadBrands'] = brandValueJson;
31370 tejbeer 838
 
31402 tejbeer 839
 
35548 aman 840
            console.log(localStorage.getItem("frontp"));
31402 tejbeer 841
 
842
 
35548 aman 843
            leadDetailObject['frontp'] = localStorage
844
                .getItem("frontph");
31402 tejbeer 845
 
846
 
35548 aman 847
            leadDetailObject['frontWithMarket'] = localStorage
848
                .getItem("internalMarketh");
31370 tejbeer 849
 
850
 
35548 aman 851
            leadDetailObject['internalLongShot'] = localStorage
852
                .getItem("leftShoth");
31370 tejbeer 853
 
854
 
35548 aman 855
            leadDetailObject['internalLeftWall'] = localStorage
856
                .getItem("leftWallh");
31370 tejbeer 857
 
858
 
35548 aman 859
            leadDetailObject['internalRightWall'] = localStorage
860
                .getItem("rightWallh");
31370 tejbeer 861
 
35548 aman 862
            console.log(leadDetailObject);
31370 tejbeer 863
 
35548 aman 864
            if (confirm("Are you sure you want to add lead detail!") == true) {
865
                doPostAjaxRequestWithJsonHandler(context + "/leadDetail", JSON.stringify(leadDetailObject), function (response) {
866
                    console.log(response);
867
                    if (response == 'true') {
868
                        alert("Submit Successfully");
869
                    }
31370 tejbeer 870
 
35548 aman 871
                });
872
            }
31370 tejbeer 873
 
35548 aman 874
        });
31370 tejbeer 875
 
876
 
35548 aman 877
    $(document).on('change', '.frontp',
878
        function () {
31370 tejbeer 879
 
35548 aman 880
            if (confirm('Document has been selected, Do you want to upload ?')) {
31370 tejbeer 881
 
35548 aman 882
                var documentId = uploadImage(this, "frontph");
31370 tejbeer 883
 
884
 
35548 aman 885
            } else {
31370 tejbeer 886
 
35548 aman 887
            }
888
        });
31456 tejbeer 889
 
35548 aman 890
    $(document).on('change', '.internalMarket',
891
        function () {
31456 tejbeer 892
 
35548 aman 893
            if (confirm('Document has been selected, Do you want to upload ?')) {
31456 tejbeer 894
 
35548 aman 895
                var documentId = uploadImage(this, "internalMarketh");
31456 tejbeer 896
 
35548 aman 897
            } else {
31456 tejbeer 898
 
35548 aman 899
            }
900
        });
31370 tejbeer 901
 
35548 aman 902
    $(document).on('change', '.leftShot',
31370 tejbeer 903
 
35548 aman 904
        function () {
905
            if (confirm('Document has been selected, Do you want to upload ?')) {
906
                var documentId = uploadImage(this, "leftShoth");
907
            } else {
31370 tejbeer 908
 
35548 aman 909
            }
910
        });
31370 tejbeer 911
 
35548 aman 912
    $(document).on('change', '.leftWall',
913
        function () {
914
            if (confirm('Document has been selected, Do you want to upload ?')) {
915
                var documentId = uploadImage(this, "leftWallh");
916
            } else {
31370 tejbeer 917
 
35548 aman 918
            }
919
        });
31370 tejbeer 920
 
35548 aman 921
    $(document).on('change', '.rightWall',
922
        function () {
923
            if (confirm('Document has been selected, Do you want to upload ?')) {
924
                var documentId = uploadImage(this, "rightWallh");
925
            } else {
926
            }
927
        });
31370 tejbeer 928
 
929
 
25980 tejbeer 930
});
931
 
31404 tejbeer 932
function uploadImage(fileSelector, attrName) {
35548 aman 933
    var documentId;
934
    if (fileSelector != undefined
935
        && fileSelector.files[0] != undefined) {
936
        var url = context
937
            + '/document-upload';
31370 tejbeer 938
 
35548 aman 939
        console.log(url);
940
        var file = fileSelector.files[0];
31370 tejbeer 941
 
35548 aman 942
        console.log(file)
943
        doAjaxUploadRequestHandler(
944
            url,
945
            'POST',
946
            file,
947
            function (response) {
948
                console.log(response)
949
                documentId = response.response.document_id;
950
                console
951
                    .log("documentId : "
952
                        + documentId);
31370 tejbeer 953
 
954
 
35548 aman 955
                localStorage
956
                    .setItem(
957
                        attrName,
958
                        documentId);
31402 tejbeer 959
 
35548 aman 960
            });
961
        return documentId;
962
    }
31370 tejbeer 963
 
964
}
965
 
966
 
25980 tejbeer 967
function loadLead(domId) {
35548 aman 968
    doGetAjaxRequestHandler(context + "/getOpenLead", function (response) {
969
        $('#' + domId).html(response);
970
    });
25980 tejbeer 971
}
972
 
25988 tejbeer 973
function loadClosedLead(domId, searchTerm) {
35548 aman 974
    doGetAjaxRequestHandler(context + "/getClosedLead", function (response) {
975
        $('#' + domId).html(response);
976
    })
25988 tejbeer 977
}
978
 
25980 tejbeer 979
function statusAction() {
35548 aman 980
    var val = $('#status').val();
981
    if (val == "followUp") {
982
        $("#scheduleTime").show();
983
    } else {
984
        $("#scheduleTime").hide();
985
    }
25980 tejbeer 986
 
987
}
27605 tejbeer 988
 
989
 
990
function editStatusAction() {
35548 aman 991
    var val = $('#editStatus').val();
992
    if (val == "followUp") {
36642 ranu 993
        // Show communication type and schedule date
994
        $("#communicationTypeSection").show();
35548 aman 995
        $("#editScheduleTime").show();
36642 ranu 996
        $("#beatDateSelection").hide();
997
 
36761 ranu 998
        // Reset communication type only; preserve the assignee the user picked.
36642 ranu 999
        $('#communicationType').val('');
37003 ranu 1000
        $('#assignTo option').prop('disabled', false);
36642 ranu 1001
 
1002
        // Check if lead has approved geolocation to decide VISIT option
1003
        doAjaxRequestHandler(context + "/lead-geo/check/" + leadId, "GET", function (response) {
1004
            var hasGeo = response.response.hasApprovedGeo;
1005
            var commDropdown = $('#communicationType');
1006
            commDropdown.empty();
1007
            commDropdown.append('<option value="" disabled selected>Communication Type</option>');
1008
            commDropdown.append('<option value="TELEPHONIC">TELEPHONIC</option>');
1009
            if (hasGeo) {
1010
                commDropdown.append('<option value="VISIT">VISIT</option>');
1011
            }
1012
        });
35548 aman 1013
    } else {
36642 ranu 1014
        $("#communicationTypeSection").hide();
35548 aman 1015
        $("#editScheduleTime").hide();
36642 ranu 1016
        $("#beatDateSelection").hide();
37003 ranu 1017
        $('#assignTo option').prop('disabled', false);
35548 aman 1018
    }
27605 tejbeer 1019
 
1020
}
1021
 
25988 tejbeer 1022
function loadLeadSearchInfo(search_text) {
35548 aman 1023
    loadSearchLead("main-content", search_text);
25988 tejbeer 1024
}
1025
 
30185 tejbeer 1026
function loadTeamCommitment(domId) {
35548 aman 1027
    doGetAjaxRequestHandler(context + "/teamCommitment",
1028
        function (response) {
1029
            $('#' + domId).html(response);
1030
        });
30185 tejbeer 1031
}
1032
 
31370 tejbeer 1033
function loadLeadDetail(domId) {
35548 aman 1034
    doGetAjaxRequestHandler(context + "/getLeadDetail",
1035
        function (response) {
1036
            $('#' + domId).html(response);
1037
        });
31370 tejbeer 1038
}
1039
 
30416 tejbeer 1040
function loadPartnerHealth(domId) {
35548 aman 1041
    doGetAjaxRequestHandler(context + "/partnerHealth",
1042
        function (response) {
1043
            $('#' + domId).html(response);
1044
        });
30416 tejbeer 1045
}
1046
 
25988 tejbeer 1047
function loadSearchLead(domId, search_text) {
35548 aman 1048
    doGetAjaxRequestHandler(context + "/searchLeads?searchTerm=" + search_text,
1049
        function (response) {
1050
            $('#' + domId).html(response);
1051
        });
25988 tejbeer 1052
}
33917 ranu 1053
 
1054
$(document).on('click', ".arr-button-mk",
35548 aman 1055
    function () {
1056
        var startDate = $('.arr-start_date').val();
1057
        doGetAjaxRequestHandler(context + "/rbmTodayArr?startDate=" + startDate, function (response) {
1058
            $('#main-content').html(response);
33917 ranu 1059
 
35548 aman 1060
        });
1061
    });
33917 ranu 1062
 
1063
$(document).on('click', ".rbm-today-arr",
35548 aman 1064
    function () {
1065
        doGetAjaxRequestHandler(context + "/rbmTodayArr", function (response) {
1066
            $('#main-content').html(response);
33917 ranu 1067
 
35548 aman 1068
        });
1069
    });
1070
$(document).on('click', '.reassign', function () {
1071
    $('#bulkReassignFile').val(null);
1072
    $('#bulkReassignFile').click();
1073
});
1074
 
1075
$(document).on('change', '#bulkReassignFile', function () {
1076
 
1077
    if (!confirm("Confirm bulk reassign upload?")) {
1078
        return;
1079
    }
1080
 
1081
    var file = this.files[0];
1082
    if (!file) {
1083
        alert("No file selected");
1084
        return;
1085
    }
1086
 
1087
    doAjaxUploadRequestHandler(
1088
        context + "/upload-assign-id",
1089
        'POST',
1090
        file,
1091
        function (response) {
1092
            alert("Bulk reassignment completed");
1093
            loadLead("main-content");
1094
        }
1095
    );
1096
});
1097
 
36642 ranu 1098
// ==================== GEO LOCATION HANDLERS ====================
1099
 
1100
// Communication type change: filter assignTo based on type
1101
$(document).on('change', '#communicationType', function () {
1102
    var val = $(this).val();
1103
    var assignDropdown = $('#assignTo');
1104
 
36741 ranu 1105
    // Reset beat + restore manual date input
36642 ranu 1106
    $('#beatDate').val('');
1107
    $('#beatBadges').empty();
1108
    $("#beatDateSelection").hide();
36741 ranu 1109
    $("#editScheduleTime").show();
36642 ranu 1110
 
1111
    if (val == 'VISIT') {
37003 ranu 1112
        // Filter assignTo to sales users only (no BGC). Uses .prop('disabled', ...)
1113
        // instead of .hide()/.show() because select2 doesn't respect hidden <option>s
1114
        // in its dropdown UI. Disabled options are filtered out by our matcher above.
36642 ranu 1115
        if (typeof salesUserIds !== 'undefined') {
1116
            assignDropdown.find('option').each(function () {
1117
                var optVal = parseInt($(this).val());
1118
                if (optVal && salesUserIds.indexOf(optVal) === -1) {
37003 ranu 1119
                    $(this).prop('disabled', true);
36642 ranu 1120
                } else {
37003 ranu 1121
                    $(this).prop('disabled', false);
36642 ranu 1122
                }
1123
            });
1124
        }
1125
    } else {
37003 ranu 1126
        // TELEPHONIC — enable all users
1127
        assignDropdown.find('option').prop('disabled', false);
36642 ranu 1128
    }
37003 ranu 1129
    // Nudge select2 to re-render its dropdown with the new enabled/disabled state.
1130
    if ($.fn.select2 && assignDropdown.hasClass('select2-hidden-accessible')) {
1131
        assignDropdown.trigger('change.select2');
1132
    }
36741 ranu 1133
    // Both VISIT and TELEPHONIC offer beat-day slots when an assignee is set
1134
    // (TELEPHONIC just uses the beat date as the call slot; backend won't
1135
    // attach a LeadRoute for it). Non-sales assignees simply get an empty list.
1136
    if (val && assignDropdown.val()) {
1137
        fetchBeatDates();
1138
    }
36642 ranu 1139
});
1140
 
36741 ranu 1141
// Fetch beats when assignTo changes (works for both VISIT and TELEPHONIC)
1142
$(document).on('change', '#assignTo', function () {
36642 ranu 1143
    var commType = $('#communicationType').val();
1144
    var salesAuthId = $('#assignTo').val();
36741 ranu 1145
    if (commType && salesAuthId && leadId) {
36642 ranu 1146
        fetchBeatDates();
36741 ranu 1147
    } else if (!commType) {
36642 ranu 1148
        $("#beatDateSelection").hide();
1149
    }
1150
});
1151
 
1152
function fetchBeatDates() {
1153
    var salesAuthId = $('#assignTo').val();
1154
    if (!salesAuthId || !leadId) return;
1155
 
36792 ranu 1156
    // Beat slots only make sense for sales assignees. BGC / other internal
1157
    // hand-offs skip the entire beat panel (and the visit-request CTA that
1158
    // sits inside it). Mirrors the server-side carve-out in /editLead.
1159
    var assigneeIntId = parseInt(salesAuthId, 10);
1160
    var isSalesAssigneeFetch = !isNaN(assigneeIntId)
1161
        && typeof salesUserIds !== 'undefined'
1162
        && salesUserIds.indexOf(assigneeIntId) !== -1;
1163
    if (!isSalesAssigneeFetch) {
1164
        $('#beatBadges').empty();
1165
        $('#beatDate').val('');
1166
        $('#beatDateSelection').hide();
1167
        return;
1168
    }
1169
 
36642 ranu 1170
    var badgesDiv = $('#beatBadges');
1171
    badgesDiv.html('<span style="color:#999; font-size:12px;">Loading beats...</span>');
1172
    $("#beatDateSelection").show();
1173
    $('#beatDate').val('');
1174
 
1175
    var url = context + "/lead-geo/beat-dates?leadId=" + leadId + "&salesAuthId=" + salesAuthId;
1176
 
1177
    $.ajax({
1178
        url: url,
1179
        method: 'GET',
1180
        success: function (response) {
1181
            var data = response.response || response;
1182
            badgesDiv.empty();
36644 ranu 1183
 
36741 ranu 1184
            // Stores within radius of the lead — show count + top 3 inline.
1185
            var radius = (data && data.radiusKm) ? data.radiusKm : 30;
1186
            var stores = (data && data.nearestStores) || [];
1187
            if (stores.length > 0) {
1188
                var preview = stores.slice(0, 3).map(function (s) {
1189
                    return '<strong>' + s.code + ' - ' + s.name + '</strong> (' + s.distanceKm + ' km)';
1190
                }).join(', ');
1191
                var more = stores.length > 3 ? ' +' + (stores.length - 3) + ' more' : '';
36644 ranu 1192
                badgesDiv.append('<div style="font-size:12px; color:#333; margin-bottom:6px;">' +
36741 ranu 1193
                    stores.length + ' partner store(s) within ' + radius + ' km of this lead: ' +
1194
                    preview + more + '</div>');
36644 ranu 1195
            }
1196
 
36741 ranu 1197
            // All upcoming beat-dates for the assignee that touch any nearby store.
36642 ranu 1198
            if (data && data.beats && data.beats.length > 0) {
36644 ranu 1199
                badgesDiv.append('<div style="font-weight:bold; font-size:11px; color:#666; margin-bottom:4px;">Available Slots (near this lead):</div>');
36741 ranu 1200
                var beats = data.beats;
36642 ranu 1201
                for (var i = 0; i < beats.length; i++) {
1202
                    var beat = beats[i];
36644 ranu 1203
                    var nearTxt = beat.nearStore ? ' &middot; near ' + beat.nearStore : '';
36642 ranu 1204
                    var badge = $('<span class="beat-badge" style="' +
1205
                        'display:inline-block; background:#337ab7; color:#fff; padding:6px 12px; ' +
1206
                        'margin:4px 6px 4px 0; border-radius:16px; cursor:pointer; font-size:12px; ' +
1207
                        'border:2px solid #337ab7; transition:all 0.2s;">' +
36644 ranu 1208
                        beat.planDate + ' &middot; ' + beat.beatName + ' (' + beat.stops + ' stops)' + nearTxt +
36642 ranu 1209
                        '</span>');
1210
                    badge.data('value', beat.planDate + '|' + beat.beatName + '|' + beat.planGroupId);
1211
                    badgesDiv.append(badge);
1212
                }
1213
            } else {
36787 ranu 1214
                // No beat-days available for this assignee. Surface a CTA so the
1215
                // user can fire a visit request to the assignee's hierarchy instead
1216
                // of being stuck. The pre-existing 'beats > 0' branch above is
1217
                // untouched — this only fires for the empty-beats case.
1218
                var nearestId = (stores.length > 0 && stores[0].storeId) ? stores[0].storeId : '';
1219
                badgesDiv.append(
1220
                    '<div style="background:#fff8e1; border:1px solid #f0e0a0; border-radius:6px; padding:8px 10px; margin-top:4px;">'
1221
                    + '<div style="font-size:12px; color:#7c5a00; margin-bottom:6px;">'
1222
                    + 'No upcoming beat is available for this assignee.'
1223
                    + '</div>'
1224
                    + '<div style="display:flex; gap:8px; align-items:center;">'
1225
                    + '<label style="font-size:11px; color:#666; margin:0;">Preferred date (optional):</label>'
1226
                    + '<input type="date" id="vrPreferredDate" class="input-sm" style="font-size:12px; padding:3px 6px;">'
1227
                    + '<button type="button" id="vrSendBtn" class="btn btn-warning btn-sm" '
1228
                    + 'data-nearest="' + nearestId + '" style="font-size:12px;">Send Visit Request</button>'
1229
                    + '</div>'
1230
                    + '<div style="font-size:11px; color:#888; margin-top:6px;">'
1231
                    + 'The request goes to the assignee\'s reporting head (and up). Once they approve and pick a beat-day, the lead lands on that beat.'
1232
                    + '</div>'
1233
                    + '</div>');
36642 ranu 1234
            }
1235
        },
1236
        error: function () {
1237
            badgesDiv.html('<span style="color:#d9534f; font-size:12px;">Error loading beats</span>');
1238
        }
1239
    });
1240
}
1241
 
36787 ranu 1242
// Send Visit Request when no beats are available for the chosen assignee.
1243
// Posts to /visitRequest/create. Existing beat-pick + Submit flow is unchanged.
1244
$(document).on('click', '#vrSendBtn', function () {
1245
    var $btn = $(this);
1246
    var assigneeAuthId = parseInt($('#assignTo').val());
1247
    var commType = $('#communicationType').val() || null;
1248
    var nearestStoreId = parseInt($btn.data('nearest'));
1249
    var preferred = $('#vrPreferredDate').val() || null;
1250
    if (!leadId || !assigneeAuthId) {
1251
        alert('Pick an assignee first.');
1252
        return;
1253
    }
1254
    $btn.prop('disabled', true).text('Sending...');
1255
    var payload = {
1256
        leadId: leadId,
1257
        assigneeAuthId: assigneeAuthId,
1258
        communicationType: commType,
1259
        reason: 'No upcoming beats for assignee'
1260
    };
1261
    if (!isNaN(nearestStoreId) && nearestStoreId > 0) payload.nearestStoreId = nearestStoreId;
1262
    if (preferred) payload.requestedDate = preferred;
1263
 
1264
    doPostAjaxRequestWithJsonHandler(context + '/visitRequest/create', JSON.stringify(payload),
1265
        function (response) {
1266
            $btn.prop('disabled', false).text('Send Visit Request');
1267
            var data = (response && response.response) || response || {};
1268
            if (data && data.id) {
1269
                alert('Visit request sent. The assignee\'s manager has been notified.');
1270
                $('#editLeadData').modal('hide');
1271
                $('.modal-backdrop').remove();
1272
            } else {
1273
                var msg = (data && data.message) || (data && data.error) || 'Could not send request.';
1274
                alert(msg);
1275
            }
1276
        });
1277
});
1278
 
36741 ranu 1279
// Click on beat badge to select it. A picked beat becomes the schedule
1280
// source — the manual date input is hidden (not needed when scheduling by beat).
36642 ranu 1281
$(document).on('click', '.beat-badge', function () {
1282
    $('.beat-badge').css({'background': '#337ab7', 'border-color': '#337ab7'});
1283
    $(this).css({'background': '#1a5276', 'border-color': '#f39c12', 'border-width': '2px'});
1284
    $('#beatDate').val($(this).data('value'));
36741 ranu 1285
    $("#editScheduleTime").hide();
36642 ranu 1286
});
1287
 
1288
// Generate Geo Link for lead
1289
$(document).on('click', '.generateGeoLink', function (e) {
1290
    e.stopPropagation();
1291
    var lid = $(this).data('leadid');
1292
    doAjaxRequestHandler(context + "/lead-geo/generate-link?leadId=" + lid, "GET", function (response) {
1293
        var url = response.response;
1294
        if (navigator.clipboard) {
1295
            navigator.clipboard.writeText(url).then(function () {
1296
                alert("Link copied to clipboard:\n" + url);
1297
            });
1298
        } else {
1299
            prompt("Share this link with the prospect:", url);
1300
        }
1301
    });
1302
});
1303
 
36868 ranu 1304
// Manual geo verification — for cases where the prospect refused to tap the
1305
// verification link. Team-member confirms lat/lng over phone (or pastes a
1306
// Maps URL the prospect shared) and writes it APPROVED directly.
1307
function ensureManualVerifyModal() {
1308
    if ($('#manualVerifyGeoModal').length) return;
1309
    var html =
1310
        '<div id="manualVerifyGeoModal" class="modal" role="dialog" tabindex="-1">' +
1311
        '  <div class="modal-dialog modal-lg">' +
1312
        '    <div class="modal-content">' +
1313
        '      <div class="modal-header">' +
1314
        '        <button type="button" class="close" data-dismiss="modal">&times;</button>' +
1315
        '        <h4 class="modal-title">Verify Lead Location Manually</h4>' +
1316
        '      </div>' +
1317
        '      <div class="modal-body" style="max-height:75vh;overflow-y:auto;">' +
1318
        '        <input type="hidden" id="manualVerifyLeadId">' +
1319
        '        <div class="form-group">' +
1320
        '          <label>Address <small class="text-muted">(include city, state, pincode for best result)</small></label>' +
1321
        '          <div class="input-group">' +
1322
        '            <input type="text" class="form-control" id="manualVerifyAddress" placeholder="e.g. Shop 12, Sector 18, Noida, UP, 201301">' +
1323
        '            <span class="input-group-btn">' +
1324
        '              <button type="button" class="btn btn-default" id="manualVerifyGeocodeBtn">Find on map</button>' +
1325
        '            </span>' +
1326
        '          </div>' +
1327
        '        </div>' +
1328
        '        <div class="form-group">' +
1329
        '          <label>Latitude, Longitude</label>' +
1330
        '          <div class="input-group">' +
1331
        '            <input type="text" class="form-control" id="manualVerifyLatLng" placeholder="28.6139,77.2090">' +
1332
        '            <span class="input-group-btn">' +
1333
        '              <button type="button" class="btn btn-default" id="manualVerifyPreviewBtn">Show on map</button>' +
1334
        '            </span>' +
1335
        '          </div>' +
1336
        '          <small class="text-muted">You can also paste a Google Maps URL containing coords.</small>' +
1337
        '        </div>' +
1338
        '        <div class="form-group" id="manualVerifyMapWrap" style="display:none;">' +
1339
        '          <label>Map preview <small class="text-muted">(confirm the pin is right)</small></label>' +
1340
        '          <div style="border:1px solid #ddd;border-radius:3px;overflow:hidden;">' +
1341
        '            <iframe id="manualVerifyMapFrame" width="100%" height="260" frameborder="0" style="border:0;" allowfullscreen></iframe>' +
1342
        '          </div>' +
1343
        '          <small><a href="#" id="manualVerifyOpenMap" target="_blank">Open in Google Maps</a></small>' +
1344
        '        </div>' +
1345
        '        <div class="form-group">' +
1346
        '          <label>Store-board photo <span class="text-danger">*</span> <small class="text-muted">(required &mdash; proves the verification)</small></label>' +
1347
        '          <input type="file" id="manualVerifyPhoto" accept="image/jpeg,image/png" required>' +
1348
        '          <div id="manualVerifyPhotoPreview" style="margin-top:6px;display:none;">' +
1349
        '            <img id="manualVerifyPhotoImg" src="" style="max-height:120px;border:1px solid #ddd;border-radius:3px;padding:2px;">' +
1350
        '          </div>' +
1351
        '        </div>' +
1352
        '        <div class="form-group">' +
1353
        '          <label>Remark <small class="text-muted">(optional)</small></label>' +
1354
        '          <input type="text" class="form-control" id="manualVerifyRemark" placeholder="e.g. Confirmed on call with prospect">' +
1355
        '        </div>' +
1356
        '        <div id="manualVerifyErr" class="text-danger" style="display:none;"></div>' +
1357
        '      </div>' +
1358
        '      <div class="modal-footer">' +
1359
        '        <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>' +
1360
        '        <button type="button" class="btn btn-success" id="manualVerifySaveBtn">Save &amp; Verify</button>' +
1361
        '      </div>' +
1362
        '    </div>' +
1363
        '  </div>' +
1364
        '</div>';
1365
    $('body').append(html);
1366
}
1367
 
1368
function manualVerifyShowMap(lat, lng) {
1369
    var src = 'https://www.google.com/maps?q=' + lat + ',' + lng + '&z=17&output=embed';
1370
    $('#manualVerifyMapFrame').attr('src', src);
1371
    $('#manualVerifyOpenMap').attr('href', 'https://www.google.com/maps?q=' + lat + ',' + lng);
1372
    $('#manualVerifyMapWrap').show();
1373
}
1374
 
1375
// Parses raw "lat,lng" or a Google Maps URL containing the coords.
1376
// Maps formats covered: /@lat,lng, /maps?q=lat,lng, ?ll=lat,lng, ?destination=lat,lng.
1377
function parseLatLngInput(raw) {
1378
    if (!raw) return null;
1379
    var s = String(raw).trim();
1380
    // Strip any leading "lat:" / "lng:" tokens
1381
    var direct = s.match(/(-?\d{1,3}\.\d+)\s*,\s*(-?\d{1,3}\.\d+)/);
1382
    if (direct) return {lat: parseFloat(direct[1]), lng: parseFloat(direct[2])};
1383
    return null;
1384
}
1385
 
1386
$(document).on('click', '.verifyGeoManual', function (e) {
1387
    e.stopPropagation();
1388
    var lid = $(this).data('leadid');
1389
    ensureManualVerifyModal();
1390
    $('#manualVerifyLeadId').val(lid);
1391
    $('#manualVerifyAddress').val('');
1392
    $('#manualVerifyLatLng').val('');
1393
    $('#manualVerifyRemark').val('');
1394
    $('#manualVerifyErr').hide().text('');
1395
    $('#manualVerifyMapWrap').hide();
1396
    $('#manualVerifyMapFrame').attr('src', '');
1397
    $('#manualVerifyPhoto').val('');
1398
    $('#manualVerifyPhotoImg').attr('src', '');
1399
    $('#manualVerifyPhotoPreview').hide();
1400
    $('#manualVerifyGeoModal').modal('show');
1401
});
1402
 
1403
// Local thumbnail preview as soon as the user picks a file (no upload yet —
1404
// upload happens on Save so we don't orphan documents on cancel).
1405
$(document).on('change', '#manualVerifyPhoto', function () {
1406
    var f = this.files && this.files[0];
1407
    if (!f) {
1408
        $('#manualVerifyPhotoPreview').hide();
1409
        return;
1410
    }
1411
    var reader = new FileReader();
1412
    reader.onload = function (ev) {
1413
        $('#manualVerifyPhotoImg').attr('src', ev.target.result);
1414
        $('#manualVerifyPhotoPreview').show();
1415
    };
1416
    reader.readAsDataURL(f);
1417
});
1418
 
1419
// Address -> coords via server (uses existing GeocodingService).
1420
// On success, fills the lat/lng box and renders the map preview.
1421
$(document).on('click', '#manualVerifyGeocodeBtn', function () {
1422
    var addr = ($('#manualVerifyAddress').val() || '').trim();
1423
    if (!addr) {
1424
        $('#manualVerifyErr').text('Enter an address first.').show();
1425
        return;
1426
    }
1427
    $('#manualVerifyErr').hide();
1428
    var btn = $(this);
1429
    btn.prop('disabled', true).text('Finding...');
1430
    $.ajax({
1431
        url: context + '/lead-geo/geocode-address',
1432
        type: 'POST',
1433
        data: {address: addr},
1434
        success: function (resp) {
1435
            btn.prop('disabled', false).text('Find on map');
1436
            var r = resp && resp.response ? resp.response : resp;
1437
            if (!r || !r.success) {
1438
                $('#manualVerifyErr').text((r && r.message) || 'Could not geocode that address.').show();
1439
                return;
1440
            }
1441
            $('#manualVerifyLatLng').val(r.latitude + ',' + r.longitude);
1442
            manualVerifyShowMap(r.latitude, r.longitude);
1443
        },
1444
        error: function () {
1445
            btn.prop('disabled', false).text('Find on map');
1446
            $('#manualVerifyErr').text('Geocode request failed. Try again.').show();
1447
        }
1448
    });
1449
});
1450
 
1451
// "Show on map" — re-render the iframe from whatever is in the lat/lng input.
1452
// Useful after the user nudges the coords manually.
1453
$(document).on('click', '#manualVerifyPreviewBtn', function () {
1454
    var parsed = parseLatLngInput($('#manualVerifyLatLng').val());
1455
    if (!parsed) {
1456
        $('#manualVerifyErr').text('Enter latitude,longitude first.').show();
1457
        return;
1458
    }
1459
    $('#manualVerifyErr').hide();
1460
    manualVerifyShowMap(parsed.lat, parsed.lng);
1461
});
1462
 
1463
$(document).on('click', '#manualVerifySaveBtn', function () {
1464
    var lid = $('#manualVerifyLeadId').val();
1465
    var raw = $('#manualVerifyLatLng').val();
1466
    var remark = $('#manualVerifyRemark').val() || '';
1467
    var parsed = parseLatLngInput(raw);
1468
    if (!parsed) {
1469
        $('#manualVerifyErr').text('Could not read latitude/longitude. Paste like 28.6139,77.2090').show();
1470
        return;
1471
    }
1472
    if (parsed.lat < -90 || parsed.lat > 90 || parsed.lng < -180 || parsed.lng > 180
1473
        || (parsed.lat === 0 && parsed.lng === 0)) {
1474
        $('#manualVerifyErr').text('Latitude/longitude out of range.').show();
1475
        return;
1476
    }
1477
    var fileInput = document.getElementById('manualVerifyPhoto');
1478
    var pickedFile = fileInput && fileInput.files && fileInput.files[0];
1479
    if (!pickedFile) {
1480
        $('#manualVerifyErr').text('Please attach a store-board photo to verify.').show();
1481
        return;
1482
    }
1483
    $('#manualVerifyErr').hide();
1484
    var btn = $('#manualVerifySaveBtn');
1485
    btn.prop('disabled', true).text('Verifying...');
1486
 
1487
    function callVerify(docId) {
1488
        $.ajax({
1489
            url: context + '/lead-geo/manual-verify',
1490
            type: 'POST',
1491
            data: {
1492
                leadId: lid,
1493
                latitude: parsed.lat,
1494
                longitude: parsed.lng,
1495
                remark: remark,
1496
                imageDocumentId: docId || 0
1497
            },
1498
            success: function () {
1499
                btn.prop('disabled', false).text('Save & Verify');
1500
                $('#manualVerifyGeoModal').modal('hide');
1501
                // Replace the cell of this lead row with the Verified badge so
1502
                // the user sees the result without reloading the whole list.
1503
                var $cell = $('.verifyGeoManual[data-leadid="' + lid + '"]').closest('td');
1504
                if ($cell.length) {
1505
                    var photoBtn = docId > 0
1506
                        ? '  <a href="' + context + '/open-attachment?documentId=' + docId + '" target="_blank" class="btn btn-xs btn-default" style="margin-bottom:2px;">View Photo</a>'
1507
                        : '';
1508
                    $cell.html(
1509
                        '<div class="btn-group-vertical" style="width:100%">' +
1510
                        '  <span class="label label-success" style="margin-bottom:4px;">Verified</span>' +
1511
                        '  <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>' +
1512
                        photoBtn +
1513
                        '  <button class="btn btn-xs btn-danger reject-geo" data-leadid="' + lid + '">Revoke</button>' +
1514
                        '</div>'
1515
                    );
1516
                }
1517
            },
1518
            error: function (xhr) {
1519
                btn.prop('disabled', false).text('Save & Verify');
1520
                var msg = 'Failed to verify. Please try again.';
1521
                try {
1522
                    var j = xhr.responseJSON || JSON.parse(xhr.responseText || '{}');
1523
                    if (j && j.response) msg = j.response;
1524
                    else if (j && j.message) msg = j.message;
1525
                } catch (e) {
1526
                }
1527
                $('#manualVerifyErr').text(msg).show();
1528
            }
1529
        });
1530
    }
1531
 
1532
    // Upload first, then verify with the returned document id. Photo is
1533
    // required (gate at the top of the handler), so we always go through this.
1534
    btn.text('Uploading photo...');
1535
    var formData = new FormData();
1536
    formData.append('file', pickedFile, pickedFile.name || 'store-photo.jpg');
1537
    $.ajax({
1538
        url: context + '/lead-geo/upload-image',
1539
        type: 'POST',
1540
        data: formData,
1541
        processData: false,
1542
        contentType: false,
1543
        success: function (resp) {
1544
            var r = resp && resp.response ? resp.response : resp;
1545
            var docId = r && (r.document_id || r.documentId || r.id);
1546
            if (!docId) {
1547
                btn.prop('disabled', false).text('Save & Verify');
1548
                $('#manualVerifyErr').text('Photo upload failed. Try again or remove the photo.').show();
1549
                return;
1550
            }
1551
            btn.text('Verifying...');
1552
            callVerify(docId);
1553
        },
1554
        error: function () {
1555
            btn.prop('disabled', false).text('Save & Verify');
1556
            $('#manualVerifyErr').text('Photo upload failed. Try again or remove the photo.').show();
1557
        }
1558
    });
1559
});
1560
 
36642 ranu 1561
// Geo Review navigation
1562
$(document).on('click', '.geo-review', function () {
1563
    doGetAjaxRequestHandler(context + "/lead-geo/pending-reviews", function (response) {
1564
        $('#main-content').html(response);
1565
    });
1566
});
1567
 
1568
// Visit Approvals navigation
1569
$(document).on('click', '.visit-approvals', function () {
1570
    doGetAjaxRequestHandler(context + "/visit-approvals", function (response) {
1571
        $('#main-content').html(response);
1572
    });
1573
});
1574
 
36650 ranu 1575
// Beat Day View — load inline into dashboard
1576
$(document).on('click', '.beat-plan-dayview', function (e) {
1577
    e.preventDefault();
1578
    doGetAjaxRequestHandler(context + '/beatPlan/dayView', function (response) {
1579
        $('#main-content').html(response);
1580
    });
1581
});
1582
 
36655 ranu 1583
// Base Location manager — load inline into dashboard
1584
$(document).on('click', '.base-location', function (e) {
1585
    e.preventDefault();
1586
    doGetAjaxRequestHandler(context + '/beatPlan/baseLocationPage', function (response) {
1587
        $('#main-content').html(response);
1588
    });
1589
});
1590
 
36740 ranu 1591
// Deferred Partners — load inline into dashboard
1592
$(document).on('click', '.beat-plan-deferred', function (e) {
1593
    e.preventDefault();
1594
    doGetAjaxRequestHandler(context + '/beatPlan/deferredView', function (response) {
1595
        $('#main-content').html(response);
1596
    });
1597
});
1598
 
36642 ranu 1599
// Approve geolocation from lead table
1600
$(document).on('click', '.approve-geo', function (e) {
1601
    e.stopPropagation();
1602
    var lid = $(this).data('leadid');
1603
    if (!confirm('Approve geolocation for Lead #' + lid + '?')) return;
1604
 
1605
    var btn = $(this);
1606
    var cell = btn.closest('td');
1607
 
1608
    doPostAjaxRequestWithParamsHandler(
1609
        context + '/lead-geo/review',
1610
        {leadId: lid, status: 'APPROVED', remark: ''},
1611
        function (response) {
1612
            cell.html('<span class="label label-success">Verified</span>');
1613
        }
1614
    );
1615
});
1616
 
1617
// Reject geolocation from lead table
1618
$(document).on('click', '.reject-geo', function (e) {
1619
    e.stopPropagation();
1620
    var lid = $(this).data('leadid');
1621
    var reason = prompt('Reason for rejection:');
1622
    if (reason === null) return;
1623
 
1624
    var btn = $(this);
1625
    var cell = btn.closest('td');
1626
 
1627
    doPostAjaxRequestWithParamsHandler(
1628
        context + '/lead-geo/review',
1629
        {leadId: lid, status: 'REJECTED', remark: reason},
1630
        function (response) {
1631
            cell.html('<button class="btn btn-xs btn-warning generateGeoLink" data-leadid="' + lid + '">Rejected - Resend</button>');
1632
        }
1633
    );
1634
});
1635