| 36740 |
ranu |
1 |
<section class="wrapper">
|
|
|
2 |
<div class="row">
|
|
|
3 |
<div class="col-lg-12">
|
|
|
4 |
<h3 class="page-header"><i class="icon_calendar"></i> Deferred Partners</h3>
|
|
|
5 |
<ol class="breadcrumb">
|
|
|
6 |
<li><i class="fa fa-home"></i><a href="${rc.contextPath}/dashboard">Home</a></li>
|
|
|
7 |
<li><i class="icon_group"></i> Partner Acquisition</li>
|
|
|
8 |
<li><i class="icon_calendar"></i> Deferred Partners</li>
|
|
|
9 |
</ol>
|
|
|
10 |
</div>
|
|
|
11 |
</div>
|
|
|
12 |
|
|
|
13 |
<div class="row" style="margin-bottom:10px;">
|
|
|
14 |
<div class="col-lg-12" style="display:flex; gap:10px; align-items:center; flex-wrap:wrap;">
|
| 36761 |
ranu |
15 |
<label style="margin:0;">Date:</label>
|
|
|
16 |
<input type="date" id="defDate" class="form-control input-sm" style="width:160px;">
|
| 36740 |
ranu |
17 |
<button class="btn btn-primary btn-sm" id="defLoad">Load</button>
|
|
|
18 |
<span id="defSummary" style="color:#777; font-size:12px; margin-left:10px;"></span>
|
|
|
19 |
</div>
|
|
|
20 |
</div>
|
|
|
21 |
|
|
|
22 |
<div class="row">
|
|
|
23 |
<div class="col-lg-12">
|
|
|
24 |
<div class="table-responsive">
|
|
|
25 |
<table class="table table-bordered table-striped table-hover" id="defTable">
|
|
|
26 |
<thead>
|
|
|
27 |
<tr>
|
|
|
28 |
<th>User</th>
|
|
|
29 |
<th>Date</th>
|
|
|
30 |
<th>Type</th>
|
|
|
31 |
<th>Partner / Agenda</th>
|
|
|
32 |
<th>Reason</th>
|
|
|
33 |
<th>Status</th>
|
|
|
34 |
<th>Next Scheduled</th>
|
|
|
35 |
<th>Action</th>
|
|
|
36 |
</tr>
|
|
|
37 |
</thead>
|
|
|
38 |
<tbody id="defRows">
|
|
|
39 |
<tr>
|
| 36761 |
ranu |
40 |
<td colspan="8" style="text-align:center; color:#999;">Pick a date and click Load.</td>
|
| 36740 |
ranu |
41 |
</tr>
|
|
|
42 |
</tbody>
|
|
|
43 |
</table>
|
|
|
44 |
</div>
|
|
|
45 |
</div>
|
|
|
46 |
</div>
|
|
|
47 |
</section>
|
|
|
48 |
|
|
|
49 |
<!-- Reschedule modal -->
|
|
|
50 |
<!-- Reschedule via the beat-plan calendar window (pick an upcoming beat to drop the item into) -->
|
|
|
51 |
<div class="modal fade" id="defCalModal" tabindex="-1">
|
|
|
52 |
<div class="modal-dialog" style="width:95%; max-width:1300px; margin-top:20px;">
|
|
|
53 |
<div class="modal-content">
|
|
|
54 |
<div class="modal-header">
|
|
|
55 |
<button type="button" class="close" data-dismiss="modal"
|
|
|
56 |
onclick="$('#defCalFrame').attr('src','');">×
|
|
|
57 |
</button>
|
|
|
58 |
<h4 class="modal-title" id="defCalTitle">Reschedule into a Beat</h4>
|
|
|
59 |
</div>
|
|
|
60 |
<div class="modal-body" style="padding:0;">
|
|
|
61 |
<iframe id="defCalFrame" style="width:100%; height:80vh; border:none;"></iframe>
|
|
|
62 |
</div>
|
|
|
63 |
</div>
|
|
|
64 |
</div>
|
|
|
65 |
</div>
|
|
|
66 |
|
|
|
67 |
<script>
|
|
|
68 |
(function () {
|
|
|
69 |
var d = new Date();
|
|
|
70 |
|
|
|
71 |
function fmt(x) {
|
|
|
72 |
return x.getFullYear() + '-' + ('0' + (x.getMonth() + 1)).slice(-2) + '-' + ('0' + x.getDate()).slice(-2);
|
|
|
73 |
}
|
|
|
74 |
|
| 36761 |
ranu |
75 |
$('#defDate').val(fmt(d));
|
| 36740 |
ranu |
76 |
loadDeferred();
|
|
|
77 |
})();
|
|
|
78 |
|
|
|
79 |
$(document).on('click', '#defLoad', function () {
|
|
|
80 |
loadDeferred();
|
|
|
81 |
});
|
|
|
82 |
|
|
|
83 |
function loadDeferred() {
|
| 36761 |
ranu |
84 |
var d = $('#defDate').val();
|
|
|
85 |
if (!d) {
|
|
|
86 |
alert('Pick a date');
|
| 36740 |
ranu |
87 |
return;
|
|
|
88 |
}
|
|
|
89 |
$('#defRows').html('<tr><td colspan="8" style="text-align:center;">Loading...</td></tr>');
|
|
|
90 |
$('#defSummary').text('');
|
| 36761 |
ranu |
91 |
$.get(context + '/beatPlan/deferred', {startDate: d, endDate: d}).done(function (r) {
|
| 36740 |
ranu |
92 |
var data = r.response || r;
|
|
|
93 |
renderDeferredRows(data.rows || []);
|
| 36761 |
ranu |
94 |
$('#defSummary').text((data.rows || []).length + ' deferred on ' + data.startDate);
|
| 36740 |
ranu |
95 |
}).fail(function (xhr) {
|
|
|
96 |
$('#defRows').html('<tr><td colspan="8" style="color:#d9534f; text-align:center;">Error: ' + (xhr.responseText || xhr.statusText) + '</td></tr>');
|
|
|
97 |
});
|
|
|
98 |
}
|
|
|
99 |
|
|
|
100 |
function renderDeferredRows(rows) {
|
|
|
101 |
if (!rows || rows.length === 0) {
|
| 36761 |
ranu |
102 |
$('#defRows').html('<tr><td colspan="8" style="text-align:center; color:#999;">No deferred items on this date.</td></tr>');
|
| 36740 |
ranu |
103 |
return;
|
|
|
104 |
}
|
|
|
105 |
var html = '';
|
|
|
106 |
rows.forEach(function (r) {
|
|
|
107 |
// "Auto-covered" = the same partner is on an upcoming beat run. Just a
|
|
|
108 |
// hint — the row stays actionable (the next run may be far off, so the
|
|
|
109 |
// head can still reschedule it sooner). Leads never auto-cover.
|
|
|
110 |
var autoCovered = !!r.nextScheduledDate;
|
|
|
111 |
var statusCell = autoCovered
|
|
|
112 |
? '<span class="label label-success" title="Also scheduled on ' + r.nextScheduledDate + '">Auto-covered</span>'
|
|
|
113 |
: '<span class="label label-warning">Deferred</span>';
|
|
|
114 |
var typeCell = (r.type === 'Lead')
|
|
|
115 |
? '<span class="label label-warning">Lead</span>'
|
|
|
116 |
: '<span class="label label-info">Visit</span>';
|
|
|
117 |
var next = autoCovered
|
|
|
118 |
? '<span style="color:#2e7d32; font-weight:600;">' + r.nextScheduledDate + '</span>'
|
|
|
119 |
: '<span style="color:#999;">—</span>';
|
|
|
120 |
var safeName = (r.name || '').replace(/"/g, '"');
|
|
|
121 |
var action = '<button class="btn btn-xs btn-success def-reschedule"'
|
|
|
122 |
+ ' data-id="' + r.id + '"'
|
|
|
123 |
+ ' data-userid="' + r.authUserId + '"'
|
|
|
124 |
+ ' data-username="' + (r.userName || '').replace(/"/g, '"') + '"'
|
|
|
125 |
+ ' data-type="' + (r.type === 'Lead' ? 'lead' : 'visit') + '"'
|
|
|
126 |
+ ' data-deferdate="' + (r.deferredDate || '') + '"'
|
|
|
127 |
+ ' data-name="' + safeName + '">Reschedule</button> '
|
|
|
128 |
+ '<button class="btn btn-xs btn-default def-cancel" data-id="' + r.id + '">Cancel</button>';
|
|
|
129 |
html += '<tr>'
|
|
|
130 |
+ '<td>' + (r.userName || '') + '</td>'
|
|
|
131 |
+ '<td><span class="label label-primary">' + (r.deferredDate || '') + '</span></td>'
|
|
|
132 |
+ '<td>' + typeCell + '</td>'
|
|
|
133 |
+ '<td>' + (r.name || '') + '</td>'
|
|
|
134 |
+ '<td>' + (r.reason || '') + '</td>'
|
|
|
135 |
+ '<td>' + statusCell + '</td>'
|
|
|
136 |
+ '<td>' + next + '</td>'
|
|
|
137 |
+ '<td>' + action + '</td>'
|
|
|
138 |
+ '</tr>';
|
|
|
139 |
});
|
|
|
140 |
$('#defRows').html(html);
|
|
|
141 |
}
|
|
|
142 |
|
|
|
143 |
// Cancel
|
|
|
144 |
$(document).on('click', '.def-cancel', function () {
|
|
|
145 |
var id = $(this).data('id');
|
|
|
146 |
if (!confirm('Cancel this deferred visit? It will be dropped (no re-visit).')) return;
|
|
|
147 |
$.ajax({
|
|
|
148 |
url: context + '/beatPlan/deferred/action',
|
|
|
149 |
type: 'POST', contentType: 'application/json',
|
|
|
150 |
data: JSON.stringify({deferredId: id, action: 'cancel'}),
|
|
|
151 |
success: function () {
|
|
|
152 |
loadDeferred();
|
|
|
153 |
},
|
|
|
154 |
error: function (xhr) {
|
|
|
155 |
alert(serverMsg(xhr, 'Cancel failed'));
|
|
|
156 |
}
|
|
|
157 |
});
|
|
|
158 |
});
|
|
|
159 |
|
|
|
160 |
// Reschedule → open the beat-plan calendar window scoped to that sales person,
|
|
|
161 |
// in "deferred-assign" mode. The head clicks an upcoming beat there to drop the
|
|
|
162 |
// deferred lead/partner into it. On close, reload (the assigned item drops off).
|
|
|
163 |
$(document).on('click', '.def-reschedule', function () {
|
|
|
164 |
var id = $(this).data('id');
|
|
|
165 |
var userId = $(this).data('userid');
|
|
|
166 |
var userName = $(this).data('username') || '';
|
|
|
167 |
var type = $(this).data('type') || 'visit';
|
|
|
168 |
var name = $(this).data('name') || '';
|
|
|
169 |
var deferDate = $(this).data('deferdate') || '';
|
|
|
170 |
var url = context + '/beatPlanWindow'
|
|
|
171 |
+ '?autoUserId=' + userId
|
|
|
172 |
+ '&autoUserName=' + encodeURIComponent(userName)
|
|
|
173 |
+ '&assignDeferredId=' + id
|
|
|
174 |
+ '&deferType=' + encodeURIComponent(type)
|
|
|
175 |
+ '&deferDate=' + encodeURIComponent(deferDate)
|
|
|
176 |
+ '&deferName=' + encodeURIComponent(name);
|
|
|
177 |
$('#defCalTitle').text('Reschedule "' + name + '" into a beat — ' + userName);
|
|
|
178 |
$('#defCalFrame').attr('src', url);
|
|
|
179 |
$('#defCalModal').modal('show');
|
|
|
180 |
});
|
|
|
181 |
|
|
|
182 |
// Reload the list when the calendar window closes (item may have been assigned)
|
|
|
183 |
$('#defCalModal').on('hidden.bs.modal', function () {
|
|
|
184 |
$('#defCalFrame').attr('src', '');
|
|
|
185 |
loadDeferred();
|
|
|
186 |
});
|
|
|
187 |
|
|
|
188 |
function serverMsg(xhr, fallback) {
|
|
|
189 |
try {
|
|
|
190 |
var err = JSON.parse(xhr.responseText);
|
|
|
191 |
if (err && err.response) {
|
|
|
192 |
if (typeof err.response === 'string') return err.response;
|
|
|
193 |
if (err.response.message) return err.response.message;
|
|
|
194 |
}
|
|
|
195 |
} catch (e) {
|
|
|
196 |
}
|
|
|
197 |
return fallback;
|
|
|
198 |
}
|
|
|
199 |
</script>
|