| Line 209... |
Line 209... |
| 209 |
}
|
209 |
}
|
| 210 |
}
|
210 |
}
|
| 211 |
|
211 |
|
| 212 |
var builtVisits = [];
|
212 |
var builtVisits = [];
|
| 213 |
dayVisits.forEach(function (v) {
|
213 |
dayVisits.forEach(function (v) {
|
| - |
|
214 |
if (v.visitType === 'lead') {
|
| - |
|
215 |
// Lead visit — get lead geo from API (sync for simplicity)
|
| - |
|
216 |
var leadVisit = {
|
| - |
|
217 |
id: v.fofoId, type: 'lead',
|
| 214 |
var p = partnerMap[v.fofoId];
|
218 |
name: 'LEAD #' + v.fofoId,
|
| - |
|
219 |
code: 'LEAD',
|
| - |
|
220 |
lat: null, lng: null,
|
| - |
|
221 |
isLead: true
|
| 215 |
if (p) {
|
222 |
};
|
| 216 |
builtVisits.push({
|
223 |
$.ajax({
|
| 217 |
id: p.fofoId, type: 'partner',
|
224 |
url: context + '/lead-geo/check/' + v.fofoId,
|
| 218 |
name: p.code + ' - ' + (p.outletName || p.businessName || ''),
|
225 |
method: 'GET',
|
| 219 |
code: p.code,
|
226 |
async: false,
|
| - |
|
227 |
success: function (resp) {
|
| - |
|
228 |
var geoData = resp.response || resp;
|
| - |
|
229 |
if (geoData && geoData.hasApprovedGeo) {
|
| 220 |
lat: p.latitude ? parseFloat(p.latitude) : null,
|
230 |
leadVisit.lat = geoData.latitude;
|
| 221 |
lng: p.longitude ? parseFloat(p.longitude) : null
|
231 |
leadVisit.lng = geoData.longitude;
|
| - |
|
232 |
}
|
| - |
|
233 |
}
|
| 222 |
});
|
234 |
});
|
| - |
|
235 |
// Also get lead name
|
| - |
|
236 |
$.ajax({
|
| - |
|
237 |
url: context + '/getLead?leadId=' + v.fofoId,
|
| - |
|
238 |
method: 'GET',
|
| - |
|
239 |
async: false,
|
| - |
|
240 |
success: function (resp) {
|
| - |
|
241 |
var lead = resp.response || resp;
|
| - |
|
242 |
if (lead && lead.firstName) {
|
| - |
|
243 |
leadVisit.name = 'LEAD - ' + lead.firstName + ' ' + (lead.lastName || '');
|
| - |
|
244 |
}
|
| - |
|
245 |
}
|
| - |
|
246 |
});
|
| - |
|
247 |
builtVisits.push(leadVisit);
|
| - |
|
248 |
} else {
|
| - |
|
249 |
var p = partnerMap[v.fofoId];
|
| - |
|
250 |
if (p) {
|
| - |
|
251 |
builtVisits.push({
|
| - |
|
252 |
id: p.fofoId, type: 'partner',
|
| - |
|
253 |
name: p.code + ' - ' + (p.outletName || p.businessName || ''),
|
| - |
|
254 |
code: p.code,
|
| - |
|
255 |
lat: p.latitude ? parseFloat(p.latitude) : null,
|
| - |
|
256 |
lng: p.longitude ? parseFloat(p.longitude) : null
|
| - |
|
257 |
});
|
| - |
|
258 |
}
|
| 223 |
}
|
259 |
}
|
| 224 |
});
|
260 |
});
|
| 225 |
|
261 |
|
| 226 |
state.days.push({
|
262 |
state.days.push({
|
| 227 |
dayNumber: d.dayNumber,
|
263 |
dayNumber: d.dayNumber,
|
| Line 248... |
Line 284... |
| 248 |
// Prepend the back button + title before route days
|
284 |
// Prepend the back button + title before route days
|
| 249 |
$('#route-list').prepend('<div style="margin-bottom:8px;"><button class="btn-back-to-list" style="font-size:11px;padding:4px 10px;border:1px solid #475569;border-radius:4px;background:none;color:#94a3b8;cursor:pointer;font-family:inherit;">← Back to list</button></div><div style="font-size:14px;font-weight:600;color:#60a5fa;margin-bottom:10px;">' + beat.beatName + '</div>');
|
285 |
$('#route-list').prepend('<div style="margin-bottom:8px;"><button class="btn-back-to-list" style="font-size:11px;padding:4px 10px;border:1px solid #475569;border-radius:4px;background:none;color:#94a3b8;cursor:pointer;font-family:inherit;">← Back to list</button></div><div style="font-size:14px;font-weight:600;color:#60a5fa;margin-bottom:10px;">' + beat.beatName + '</div>');
|
| 250 |
|
286 |
|
| 251 |
// Init map with all partners + highlight beat route
|
287 |
// Init map with all partners + highlight beat route
|
| 252 |
initMap();
|
288 |
initMap();
|
| - |
|
289 |
// Add lead markers to map
|
| - |
|
290 |
state.days.forEach(function (d) {
|
| - |
|
291 |
d.visits.forEach(function (v, i) {
|
| - |
|
292 |
if (v.isLead && v.lat && v.lng) {
|
| - |
|
293 |
var m = new google.maps.Marker({
|
| - |
|
294 |
map: map,
|
| - |
|
295 |
position: {lat: v.lat, lng: v.lng},
|
| - |
|
296 |
title: v.name,
|
| - |
|
297 |
label: {text: 'L', color: '#fff', fontSize: '11px', fontWeight: '700'},
|
| - |
|
298 |
icon: {
|
| - |
|
299 |
path: google.maps.SymbolPath.CIRCLE,
|
| - |
|
300 |
scale: 16,
|
| - |
|
301 |
fillColor: '#e67e22',
|
| - |
|
302 |
fillOpacity: 0.95,
|
| - |
|
303 |
strokeColor: '#fff',
|
| - |
|
304 |
strokeWeight: 2
|
| - |
|
305 |
}
|
| - |
|
306 |
});
|
| - |
|
307 |
markers[v.id] = m;
|
| - |
|
308 |
}
|
| - |
|
309 |
});
|
| - |
|
310 |
});
|
| 253 |
resetMarkerColors();
|
311 |
resetMarkerColors();
|
| 254 |
drawRoute();
|
312 |
drawRoute();
|
| 255 |
}
|
313 |
}
|
| 256 |
});
|
314 |
});
|
| 257 |
}
|
315 |
}
|
| Line 760... |
Line 818... |
| 760 |
}
|
818 |
}
|
| 761 |
if (segDist > 0) {
|
819 |
if (segDist > 0) {
|
| 762 |
html += '<div class="route-segment"><span class="seg-line"></span><span class="seg-dist">' + segDist.toFixed(1) + ' km | ' + fmtMins(segTime) + '</span></div>';
|
820 |
html += '<div class="route-segment"><span class="seg-line"></span><span class="seg-dist">' + segDist.toFixed(1) + ' km | ' + fmtMins(segTime) + '</span></div>';
|
| 763 |
}
|
821 |
}
|
| 764 |
|
822 |
|
| - |
|
823 |
var isLeadVisit = v.isLead || v.type === 'lead';
|
| 765 |
html += '<div class="route-stop route-stop-clickable" data-fofoid="' + v.id + '" data-daynum="' + day.dayNumber + '" style="cursor:pointer;">';
|
824 |
html += '<div class="route-stop route-stop-clickable" data-fofoid="' + v.id + '" data-daynum="' + day.dayNumber + '" style="cursor:pointer;' + (isLeadVisit ? 'background:#fff3cd;border-left:3px solid #e67e22;' : '') + '">';
|
| 766 |
html += '<span class="stop-num">' + (i + 1) + '</span>';
|
825 |
html += '<span class="stop-num" style="' + (isLeadVisit ? 'background:#e67e22;' : '') + '">' + (i + 1) + '</span>';
|
| 767 |
html += '<div class="stop-info"><div class="stop-name">' + (v.code || '') + '</div>';
|
826 |
html += '<div class="stop-info"><div class="stop-name">' + (v.code || '') + (isLeadVisit ? ' <span style="color:#e67e22;font-size:10px;">LEAD VISIT</span>' : '') + '</div>';
|
| 768 |
html += '<div class="stop-meta">' + (v.name || '') + '</div>';
|
827 |
html += '<div class="stop-meta">' + (v.name || '') + '</div>';
|
| 769 |
|
828 |
|
| 770 |
// Show "Last Visit" + "Day Break" buttons on last stop of current day
|
829 |
// Show "Last Visit" + "Day Break" buttons on last stop of current day
|
| 771 |
if (isLastStop && isCurrent && !day.endAction) {
|
830 |
if (isLastStop && isCurrent && !day.endAction) {
|
| 772 |
html += '<div style="margin-top:4px;display:flex;gap:4px;">';
|
831 |
html += '<div style="margin-top:4px;display:flex;gap:4px;">';
|