Subversion Repositories SmartDukaan

Rev

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