| Line 682... |
Line 682... |
| 682 |
list.forEach(function(r){
|
682 |
list.forEach(function(r){
|
| 683 |
var A=r.userId+",'"+js(r.name)+"','"+date+"'";
|
683 |
var A=r.userId+",'"+js(r.name)+"','"+date+"'";
|
| 684 |
var go = r.userId ? ' class="clickable" onclick="openExec('+A+')"' : '';
|
684 |
var go = r.userId ? ' class="clickable" onclick="openExec('+A+')"' : '';
|
| 685 |
var agenda = !r.hasBeat ? '<span style="color:#97a1b5">—</span>'
|
685 |
var agenda = !r.hasBeat ? '<span style="color:#97a1b5">—</span>'
|
| 686 |
: (r.agendaFilled ? '<span style="color:#2f9e44">✓</span>' : '<span class="badflag">✗</span>');
|
686 |
: (r.agendaFilled ? '<span style="color:#2f9e44">✓</span>' : '<span class="badflag">✗</span>');
|
| - |
|
687 |
// Execs who aren't clearly working today can be marked on leave: agenda not
|
| 687 |
// Unscheduled execs can be marked on leave (manager / super-user only; server-enforced).
|
688 |
// filled or not punched in (covers unscheduled). Manager / super-user only;
|
| - |
|
689 |
// server-enforced. Already-on-leave rows show no button.
|
| 688 |
var leaveBtn = (window._canMarkLeave && r.authUserId && !r.hasBeat && !r.onLeave)
|
690 |
var leaveBtn = (window._canMarkLeave && r.authUserId && !r.onLeave && (!r.agendaFilled || !r.punchedIn))
|
| 689 |
? ' <button class="leavebtn" onclick="event.stopPropagation();markLeave('+r.authUserId+",'"+js(r.name)+"',this)\">Mark leave</button>" : '';
|
691 |
? ' <button class="leavebtn" onclick="event.stopPropagation();markLeave('+r.authUserId+",'"+js(r.name)+"',this)\">Mark leave</button>" : '';
|
| 690 |
h+='<tr'+go+'>'+
|
692 |
h+='<tr'+go+'>'+
|
| 691 |
'<td><b>'+esc(r.name)+'</b></td>'+
|
693 |
'<td><b>'+esc(r.name)+'</b></td>'+
|
| 692 |
'<td>'+esc(r.beatName||'-')+'</td>'+
|
694 |
'<td>'+esc(r.beatName||'-')+'</td>'+
|
| 693 |
'<td style="text-align:center">'+agenda+'</td>'+
|
695 |
'<td style="text-align:center">'+agenda+'</td>'+
|
| Line 695... |
Line 697... |
| 695 |
});
|
697 |
});
|
| 696 |
return h+'</tbody></table>';
|
698 |
return h+'</tbody></table>';
|
| 697 |
}
|
699 |
}
|
| 698 |
function openCards(key){
|
700 |
function openCards(key){
|
| 699 |
var m=CARD_META[key]; if(!m) return;
|
701 |
var m=CARD_META[key]; if(!m) return;
|
| - |
|
702 |
window._openCardKey=key; // remembered so markLeave can re-render the same view
|
| 700 |
var all=(window._execList||[]), date=window._boardDate||'';
|
703 |
var all=(window._execList||[]), date=window._boardDate||'';
|
| 701 |
var list=all.filter(m.f);
|
704 |
var list=all.filter(m.f);
|
| 702 |
var dropped=m.drop ? all.filter(m.drop) : [];
|
705 |
var dropped=m.drop ? all.filter(m.drop) : [];
|
| 703 |
var mb=el('bj-modal-back'), md=el('bj-modal');
|
706 |
var mb=el('bj-modal-back'), md=el('bj-modal');
|
| 704 |
var h='<button class="x" onclick="closeModal()">×</button><h3>'+esc(m.title)+'</h3>'+
|
707 |
var h='<button class="x" onclick="closeModal()">×</button><h3>'+esc(m.title)+'</h3>'+
|
| Line 951... |
Line 954... |
| 951 |
else closeModal();
|
954 |
else closeModal();
|
| 952 |
})
|
955 |
})
|
| 953 |
.catch(function(){ btn.disabled=false; btn.textContent='Approve'; alert('Approve failed (not authorised, or server error).'); });
|
956 |
.catch(function(){ btn.disabled=false; btn.textContent='Approve'; alert('Approve failed (not authorised, or server error).'); });
|
| 954 |
}
|
957 |
}
|
| 955 |
|
958 |
|
| 956 |
// Mark an unscheduled executive on leave for the board date. Manager / super-user only
|
959 |
// Mark an executive on leave for the board date (unscheduled, or scheduled but not
|
| - |
|
960 |
// started / agenda unfilled). Manager / super-user only (server-enforced).
|
| 957 |
// (server-enforced). Optimistically drops them from the Unscheduled list on success.
|
961 |
// Optimistically flips the row to "On leave" and re-renders the open drill-down.
|
| 958 |
function markLeave(authUserId, name, btn){
|
962 |
function markLeave(authUserId, name, btn){
|
| 959 |
if(!authUserId) return;
|
963 |
if(!authUserId) return;
|
| 960 |
var reason = prompt('Mark '+name+' on leave for '+(window._boardDate||'today')+'?\nOptional reason:', '');
|
964 |
var reason = prompt('Mark '+name+' on leave for '+(window._boardDate||'today')+'?\nOptional reason:', '');
|
| 961 |
if(reason===null) return; // cancelled
|
965 |
if(reason===null) return; // cancelled
|
| 962 |
btn.disabled=true; btn.textContent='Marking…';
|
966 |
btn.disabled=true; btn.textContent='Marking…';
|
| 963 |
var body='authUserId='+authUserId+'&date='+encodeURIComponent(window._boardDate||'')+'&reason='+encodeURIComponent(reason||'');
|
967 |
var body='authUserId='+authUserId+'&date='+encodeURIComponent(window._boardDate||'')+'&reason='+encodeURIComponent(reason||'');
|
| 964 |
fetch(CTX+'/beat-journey/mark-leave',{method:'POST',headers:{'Content-Type':'application/x-www-form-urlencoded'},body:body})
|
968 |
fetch(CTX+'/beat-journey/mark-leave',{method:'POST',headers:{'Content-Type':'application/x-www-form-urlencoded'},body:body})
|
| 965 |
.then(function(r){ if(!r.ok) throw new Error('HTTP '+r.status); return r.json(); })
|
969 |
.then(function(r){ if(!r.ok) throw new Error('HTTP '+r.status); return r.json(); })
|
| 966 |
.then(function(){
|
970 |
.then(function(){
|
| 967 |
(window._execList||[]).forEach(function(x){ if(x.authUserId===authUserId){ x.onLeave=true; x.statusLabel='On leave'; } });
|
971 |
(window._execList||[]).forEach(function(x){ if(x.authUserId===authUserId){ x.onLeave=true; x.statusLabel='On leave'; } });
|
| 968 |
openCards('unscheduled'); // re-render (row now filtered out of Unscheduled)
|
972 |
openCards(window._openCardKey||'unscheduled'); // re-render the open drill-down (row now shows "On leave", no button)
|
| 969 |
loadToday(); // refresh KPI tiles / counts in the background
|
973 |
loadToday(); // refresh KPI tiles / counts in the background
|
| 970 |
})
|
974 |
})
|
| 971 |
.catch(function(){ btn.disabled=false; btn.textContent='Mark leave'; alert('Could not mark leave (not authorised, or server error).'); });
|
975 |
.catch(function(){ btn.disabled=false; btn.textContent='Mark leave'; alert('Could not mark leave (not authorised, or server error).'); });
|
| 972 |
}
|
976 |
}
|
| 973 |
|
977 |
|