Subversion Repositories SmartDukaan

Rev

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

Rev 36788 Rev 36792
Line 75... Line 75...
75
	state.baseLocations = [];
75
	state.baseLocations = [];
76
	state.viewDate = null;
76
	state.viewDate = null;
77
	state.originalDayCount = 0;
77
	state.originalDayCount = 0;
78
	state.visitRequests = [];
78
	state.visitRequests = [];
79
	state.assignVisitRequest = null;
79
	state.assignVisitRequest = null;
-
 
80
	state.deferredItems = [];
80
	$('#visit-request-panel').hide();
81
	$('#visit-request-panel').hide();
-
 
82
	// #deferred-items-panel now sits inside its own tab pane (#panel-deferred)
-
 
83
	// which controls visibility — no need to hide the inner panel here.
-
 
84
	$('#di-list').empty();
-
 
85
	$('#di-count').text('');
-
 
86
	$('#di-tab-count').text('');
81
	// Clear the rendered calendar grid + route map / panel so nothing from
87
	// Clear the rendered calendar grid + route map / panel so nothing from
82
	// the previous user is briefly visible while the new fetch is in flight.
88
	// the previous user is briefly visible while the new fetch is in flight.
83
	$('#cal-grid-content').empty();
89
	$('#cal-grid-content').empty();
84
	$('#route-list').empty();
90
	$('#route-list').empty();
85
	if (typeof clearRoute === 'function') {
91
	if (typeof clearRoute === 'function') {
Line 138... Line 144...
138
			}
144
			}
139
			// Pending visit requests for this user's hierarchy. Hidden when empty.
145
			// Pending visit requests for this user's hierarchy. Hidden when empty.
140
			if (typeof loadVisitRequests === 'function') {
146
			if (typeof loadVisitRequests === 'function') {
141
				loadVisitRequests();
147
				loadVisitRequests();
142
			}
148
			}
-
 
149
			// Deferred items (partners + leads) for this user. Hidden when empty.
-
 
150
			if (typeof loadDeferredItems === 'function') {
-
 
151
				loadDeferredItems();
-
 
152
			}
143
        }
153
        }
144
    });
154
    });
145
});
155
});
146
 
156
 
147
// Called from the picker → swap the start location for the beat being
157
// Called from the picker → swap the start location for the beat being
Line 1806... Line 1816...
1806
	var tab = $(this).data('tab');
1816
	var tab = $(this).data('tab');
1807
	$('.panel-tab').removeClass('active');
1817
	$('.panel-tab').removeClass('active');
1808
	$(this).addClass('active');
1818
	$(this).addClass('active');
1809
	$('#panel-route').toggle(tab === 'route');
1819
	$('#panel-route').toggle(tab === 'route');
1810
	$('#panel-calendar').toggle(tab === 'calendar');
1820
	$('#panel-calendar').toggle(tab === 'calendar');
-
 
1821
	$('#panel-deferred').toggle(tab === 'deferred');
1811
	$('#cal-grid-container').toggle(tab === 'calendar');
1822
	$('#cal-grid-container').toggle(tab === 'calendar');
1812
	$('#bottom-bar').toggle(tab === 'route' && (state.mode === 'create' || state.mode === 'edit') && state.days && state.days.length > 0);
1823
	$('#bottom-bar').toggle(tab === 'route' && (state.mode === 'create' || state.mode === 'edit') && state.days && state.days.length > 0);
1813
 
1824
 
1814
	if (tab === 'calendar' && !state.calMonth) {
1825
	if (tab === 'calendar' && !state.calMonth) {
1815
		var now = new Date();
1826
		var now = new Date();
1816
		state.calMonth = now.getFullYear() + '-' + ('0' + (now.getMonth() + 1)).slice(-2);
1827
		state.calMonth = now.getFullYear() + '-' + ('0' + (now.getMonth() + 1)).slice(-2);
1817
		loadCalendarData();
1828
		loadCalendarData();
1818
	}
1829
	}
-
 
1830
	if (tab === 'deferred' && typeof loadDeferredItems === 'function') {
-
 
1831
		loadDeferredItems();
-
 
1832
	}
1819
});
1833
});
1820
 
1834
 
1821
// Click a beat chip on the calendar → view that specific day's route
1835
// Click a beat chip on the calendar → view that specific day's route
1822
// (partners + only the leads scheduled for that exact date)
1836
// (partners + only the leads scheduled for that exact date)
1823
$(document).on('click', '.cal-chip-view', function (e) {
1837
$(document).on('click', '.cal-chip-view', function (e) {
Line 1867... Line 1881...
1867
			$('#deferred-assign-banner').html('<span style="color:#bbf7d0;">' + msg + '</span>');
1881
			$('#deferred-assign-banner').html('<span style="color:#bbf7d0;">' + msg + '</span>');
1868
			// Confirm to the head (name included so they don't have to read the banner),
1882
			// Confirm to the head (name included so they don't have to read the banner),
1869
			// then auto-close the parent's iframe modal. The parent's `hidden.bs.modal`
1883
			// then auto-close the parent's iframe modal. The parent's `hidden.bs.modal`
1870
			// handler reloads the deferred list (rescheduled row drops off).
1884
			// handler reloads the deferred list (rescheduled row drops off).
1871
			alert(msg);
1885
			alert(msg);
-
 
1886
			// Clear the assign-mode so subsequent chip clicks don't try to
-
 
1887
			// re-schedule the same (now-resolved) deferred row and trip the
-
 
1888
			// "already scheduled" guard. Refresh the in-page deferred panel and
-
 
1889
			// switch back to the route tab.
-
 
1890
			state.assignDeferred = null;
-
 
1891
			if (typeof loadDeferredItems === 'function') loadDeferredItems();
-
 
1892
			$('.panel-tab[data-tab="route"]').click();
1872
			if (window.parent && window.parent !== window) {
1893
			if (window.parent && window.parent !== window) {
1873
				try {
1894
				try {
1874
					window.parent.$('#defCalModal').modal('hide');
1895
					window.parent.$('#defCalModal').modal('hide');
1875
				} catch (e) {
1896
				} catch (e) {
1876
				}
1897
				}
Line 2799... Line 2820...
2799
			try {
2820
			try {
2800
				var e = JSON.parse(xhr.responseText);
2821
				var e = JSON.parse(xhr.responseText);
2801
				if (e && e.response) msg = (typeof e.response === 'string') ? e.response : (e.response.message || msg);
2822
				if (e && e.response) msg = (typeof e.response === 'string') ? e.response : (e.response.message || msg);
2802
			} catch (_) {
2823
			} catch (_) {
2803
			}
2824
			}
-
 
2825
			alert(msg);
-
 
2826
		}
-
 
2827
	});
-
 
2828
});
-
 
2829
 
-
 
2830
// ============ DEFERRED ITEMS PANEL (inside beat-plan-window) ============
-
 
2831
// Reuses the existing /beatPlan/deferred read (hierarchy-scoped) and filters
-
 
2832
// client-side to the currently-loaded sales user. Schedule → switches to the
-
 
2833
// Calendar tab in deferred-assign mode and reuses assignDeferredToBeat() on
-
 
2834
// chip click (existing flow). Cancel posts /beatPlan/deferred/action with a
-
 
2835
// required reason. The standalone Deferred Partners page is untouched.
-
 
2836
function loadDeferredItems() {
-
 
2837
	if (!state.authUserId) return;
-
 
2838
	// Wide window so recent misses + any not-yet-acted older ones surface.
-
 
2839
	var now = new Date();
-
 
2840
 
-
 
2841
	function fmt(d) {
-
 
2842
		return d.getFullYear() + '-' + ('0' + (d.getMonth() + 1)).slice(-2) + '-' + ('0' + d.getDate()).slice(-2);
-
 
2843
	}
-
 
2844
 
-
 
2845
	var start = new Date();
-
 
2846
	start.setDate(now.getDate() - 30);
-
 
2847
	var end = new Date();
-
 
2848
	end.setDate(now.getDate() + 30);
-
 
2849
	$.ajax({
-
 
2850
		url: context + '/beatPlan/deferred',
-
 
2851
		type: 'GET', dataType: 'json', cache: false,
-
 
2852
		data: {startDate: fmt(start), endDate: fmt(end)},
-
 
2853
		success: function (r) {
-
 
2854
			var data = r.response || r;
-
 
2855
			var all = (data && data.rows) || [];
-
 
2856
			var mine = all.filter(function (row) {
-
 
2857
				return row.authUserId === state.authUserId;
-
 
2858
			});
-
 
2859
			state.deferredItems = mine;
-
 
2860
			renderDeferredItems(mine);
-
 
2861
		},
-
 
2862
		error: function () {
-
 
2863
			$('#di-list').html('<p style="color:#d9534f;font-size:12px;text-align:center;padding:20px 10px;">Could not load deferred items.</p>');
-
 
2864
		}
-
 
2865
	});
-
 
2866
}
-
 
2867
 
-
 
2868
function renderDeferredItems(rows) {
-
 
2869
	var n = (rows && rows.length) || 0;
-
 
2870
	$('#di-count').text('(' + n + ')');
-
 
2871
	// Tab pill counter — keeps the head aware of pending items while on other tabs.
-
 
2872
	if (n > 0) {
-
 
2873
		$('#di-tab-count').text('(' + n + ')').css('color', '#fca5a5');
-
 
2874
	} else {
-
 
2875
		$('#di-tab-count').text('').css('color', '');
-
 
2876
	}
-
 
2877
	if (n === 0) {
-
 
2878
		$('#di-list').html('<p style="color:#64748b;font-size:12px;text-align:center;padding:20px 10px;">No deferred items for this user.</p>');
-
 
2879
		return;
-
 
2880
	}
-
 
2881
	var html = '';
-
 
2882
	rows.forEach(function (r) {
-
 
2883
		var safeName = String(r.name || '').replace(/"/g, '&quot;');
-
 
2884
		var typeTag = r.type === 'Lead'
-
 
2885
			? '<span style="background:#fbbf24;color:#0f172a;font-size:10px;padding:1px 5px;border-radius:3px;margin-right:6px;">Lead</span>'
-
 
2886
			: '<span style="background:#60a5fa;color:#0f172a;font-size:10px;padding:1px 5px;border-radius:3px;margin-right:6px;">Visit</span>';
-
 
2887
		var nextLine = r.nextScheduledDate
-
 
2888
			? '<div style="color:#22c55e;font-size:11px;">Auto-covered on ' + r.nextScheduledDate + '</div>' : '';
-
 
2889
		html += '<div data-did="' + r.id + '" style="padding:8px;border:1px solid #334155;border-radius:6px;background:#0f172a;margin-bottom:6px;">'
-
 
2890
			+ typeTag
-
 
2891
			+ '<strong style="color:#e2e8f0;">' + (r.name || '#' + r.fofoStoreId) + '</strong>'
-
 
2892
			+ '<div style="color:#94a3b8;font-size:11px;margin-top:2px;">'
-
 
2893
			+ 'Deferred: <span style="color:#fca5a5;">' + (r.deferredDate || '-') + '</span>'
-
 
2894
			+ (r.reason ? ' · ' + r.reason : '')
-
 
2895
			+ '</div>'
-
 
2896
			+ nextLine
-
 
2897
			+ '<div style="margin-top:6px;display:flex;gap:6px;flex-wrap:wrap;">'
-
 
2898
			+ '<button class="di-schedule" data-did="' + r.id + '" data-type="' + (r.type === 'Lead' ? 'lead' : 'visit') + '" data-name="' + safeName + '" data-deferdate="' + (r.deferredDate || '') + '" style="font-size:11px;padding:3px 8px;border:none;border-radius:4px;background:#22c55e;color:#fff;cursor:pointer;">Schedule on a beat</button>'
-
 
2899
			+ '<button class="di-cancel" data-did="' + r.id + '" data-name="' + safeName + '" style="font-size:11px;padding:3px 8px;border:none;border-radius:4px;background:#ef4444;color:#fff;cursor:pointer;">Cancel</button>'
-
 
2900
			+ '</div>'
-
 
2901
			+ '</div>';
-
 
2902
	});
-
 
2903
	$('#di-list').html(html);
-
 
2904
}
-
 
2905
 
-
 
2906
$(document).on('click', '#di-refresh', function () {
-
 
2907
	loadDeferredItems();
-
 
2908
});
-
 
2909
 
-
 
2910
// Schedule: set state.assignDeferred (existing pattern) and switch to the
-
 
2911
// Calendar tab. The existing .cal-chip-view handler dispatches into
-
 
2912
// assignDeferredToBeat() when state.assignDeferred is set.
-
 
2913
$(document).on('click', '.di-schedule', function () {
-
 
2914
	var $b = $(this);
-
 
2915
	var deferDate = String($b.data('deferdate') || '');
-
 
2916
	var todayObj = new Date();
-
 
2917
	var todayStr = todayObj.getFullYear() + '-' + ('0' + (todayObj.getMonth() + 1)).slice(-2) + '-' + ('0' + todayObj.getDate()).slice(-2);
-
 
2918
	// Floor: later of the deferred-date OR today — same guard the iframe flow uses.
-
 
2919
	var floor = (deferDate && deferDate > todayStr) ? deferDate : todayStr;
-
 
2920
	state.assignDeferred = {
-
 
2921
		id: parseInt($b.data('did')),
-
 
2922
		type: String($b.data('type') || 'visit'),
-
 
2923
		name: String($b.data('name') || 'item'),
-
 
2924
		deferDate: deferDate,
-
 
2925
		minDate: floor
-
 
2926
	};
-
 
2927
	alert('Click a future beat-chip on the calendar to drop "' + (state.assignDeferred.name) + '" onto it (after ' + floor + ').');
-
 
2928
	$('.panel-tab[data-tab="calendar"]').click();
-
 
2929
});
-
 
2930
 
-
 
2931
$(document).on('click', '.di-cancel', function () {
-
 
2932
	var did = $(this).data('did');
-
 
2933
	var name = String($(this).data('name') || 'this deferred item');
-
 
2934
	var reason = prompt('Cancel reason (required) — why is "' + name + '" being cancelled?');
-
 
2935
	if (!reason || !reason.trim()) return;
-
 
2936
	$.ajax({
-
 
2937
		url: context + '/beatPlan/deferred/action',
-
 
2938
		type: 'POST', contentType: 'application/json',
-
 
2939
		data: JSON.stringify({deferredId: did, action: 'cancel', reason: reason.trim()}),
-
 
2940
		success: function () {
-
 
2941
			alert('Cancelled. The row will drop off this panel.');
-
 
2942
			loadDeferredItems();
-
 
2943
		},
-
 
2944
		error: function (xhr) {
-
 
2945
			var msg = 'Cancel failed';
-
 
2946
			try {
-
 
2947
				var e = JSON.parse(xhr.responseText);
-
 
2948
				if (e && e.response) msg = (typeof e.response === 'string') ? e.response : (e.response.message || msg);
-
 
2949
			} catch (_) {
-
 
2950
			}
2804
			alert(msg);
2951
			alert(msg);
2805
		}
2952
		}
2806
	});
2953
	});
2807
});
2954
});
2808
 
2955