Urgent pipeline: step-by-step workflow walks staffer through emergency fills
Urgent contracts now show a 4-step action plan: Step 1 (red): Review pre-matched workers Step 2 (yellow): Call first choice — highest match score Step 3 (blue): Confirm or replace — backup is ready Step 4 (green): Send shift details to confirmed workers First-choice worker highlighted with red border + label. Backup workers shown with dimmed styling + 'BACKUP' label. Urgent cards show ALL matched workers + backups (not just 3). Non-urgent contracts split into 'In Progress' (still filling) and 'Ready to Go' (fully staffed) sections. The staffer doesn't stare at a red label wondering what to do. They follow the steps: review, call, confirm, send. Done. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
c0ff7434cb
commit
45a95a9feb
@ -102,27 +102,58 @@ function renderMain(today,sum,roles,topWorkers,coverage){
|
||||
addStat(stats,'500K','Workers in System');
|
||||
el.appendChild(stats);
|
||||
|
||||
// INSIGHT 1: Contracts that need attention
|
||||
// INSIGHT 1: Urgent pipeline — step-by-step workflow
|
||||
if(today&&today.contracts){
|
||||
var urgent=today.contracts.filter(function(c){return c.priority==='urgent'||c.filled<c.headcount});
|
||||
var urgent=today.contracts.filter(function(c){return c.priority==='urgent'});
|
||||
var needsWork=today.contracts.filter(function(c){return c.priority!=='urgent'&&c.filled<c.headcount});
|
||||
var filled=today.contracts.filter(function(c){return c.filled>=c.headcount});
|
||||
|
||||
if(urgent.length){
|
||||
var ins=makeInsight('urgent','Needs Your Attention',
|
||||
urgent.length+' contract'+(urgent.length>1?'s':'')+' need'+(urgent.length===1?'s':'')+' action — workers are pre-matched and ready',
|
||||
'The system analyzed '+sum.total_needed+' positions across all contracts and found the best available matches. These still need your confirmation.');
|
||||
var ins=makeInsight('urgent','Urgent Pipeline',
|
||||
urgent.length+' emergency contract'+(urgent.length>1?'s':'') +' — the system found workers, here\'s your action plan',
|
||||
null);
|
||||
// Pipeline steps explanation
|
||||
var steps=document.createElement('div');
|
||||
steps.style.cssText='display:flex;gap:4px;margin-bottom:16px;flex-wrap:wrap';
|
||||
var stepData=[
|
||||
['1','Review','Check the pre-matched workers below','#f85149'],
|
||||
['2','Call first choice','Highest-rated worker gets the first call','#d29922'],
|
||||
['3','Confirm or replace','If they can\'t make it, the backup is ready','#58a6ff'],
|
||||
['4','Send details','Client address, start time, dress code','#3fb950']
|
||||
];
|
||||
stepData.forEach(function(s){
|
||||
var sd=document.createElement('div');
|
||||
sd.style.cssText='flex:1;min-width:120px;background:#0d1117;border-radius:8px;padding:10px;border-top:2px solid '+s[3];
|
||||
var num=document.createElement('div');num.style.cssText='font-size:18px;font-weight:800;color:'+s[3];num.textContent='Step '+s[0];
|
||||
var title=document.createElement('div');title.style.cssText='font-size:12px;font-weight:600;color:#f0f6fc;margin-top:2px';title.textContent=s[1];
|
||||
var desc=document.createElement('div');desc.style.cssText='font-size:10px;color:#8b949e;margin-top:2px';desc.textContent=s[2];
|
||||
sd.appendChild(num);sd.appendChild(title);sd.appendChild(desc);steps.appendChild(sd);
|
||||
});
|
||||
ins.appendChild(steps);
|
||||
|
||||
urgent.forEach(function(c){
|
||||
addContractInsight(ins,c);
|
||||
addContractInsight(ins,c,true);
|
||||
});
|
||||
el.appendChild(ins);
|
||||
}
|
||||
|
||||
// Non-urgent that need work
|
||||
if(needsWork.length){
|
||||
var ins1b=makeInsight('warning','In Progress',
|
||||
needsWork.length+' contract'+(needsWork.length>1?'s':'')+' still filling — workers matched, awaiting confirmation',
|
||||
'These are standard priority. Workers are ranked by fit — start from the top.');
|
||||
needsWork.forEach(function(c){
|
||||
addContractInsight(ins1b,c,false);
|
||||
});
|
||||
el.appendChild(ins1b);
|
||||
}
|
||||
|
||||
if(filled.length){
|
||||
var ins2=makeInsight('opportunity','Ready to Confirm',
|
||||
filled.length+' contract'+(filled.length>1?'s':'')+' fully matched — review and send outreach',
|
||||
'These contracts have enough qualified workers matched. The system ranked them by skills, reliability, and location fit.');
|
||||
var ins2=makeInsight('opportunity','Ready to Go',
|
||||
filled.length+' contract'+(filled.length>1?'s':'')+' fully staffed — review and send shift details',
|
||||
'All positions matched. The workers listed below are the system\'s best picks based on role, location, reliability, and certifications. Tap Call or SMS to confirm.');
|
||||
filled.forEach(function(c){
|
||||
addContractInsight(ins2,c);
|
||||
addContractInsight(ins2,c,false);
|
||||
});
|
||||
el.appendChild(ins2);
|
||||
}
|
||||
@ -170,7 +201,7 @@ function makeInsight(type,headline,sub,explanation){
|
||||
return d;
|
||||
}
|
||||
|
||||
function addContractInsight(parent,c){
|
||||
function addContractInsight(parent,c,isUrgent){
|
||||
var isFilled=c.filled>=c.headcount;
|
||||
var cd=document.createElement('div');cd.style.cssText='background:#0d1117;border-radius:8px;padding:12px;margin-bottom:8px';
|
||||
var hdr=document.createElement('div');hdr.style.cssText='display:flex;justify-content:space-between;align-items:center;margin-bottom:8px';
|
||||
@ -184,15 +215,22 @@ function addContractInsight(parent,c){
|
||||
hdr.appendChild(left);hdr.appendChild(right);cd.appendChild(hdr);
|
||||
|
||||
if(c.matches&&c.matches.length){
|
||||
c.matches.slice(0,Math.min(c.headcount,3)).forEach(function(m,i){
|
||||
var showCount=Math.min(c.headcount,isUrgent?c.headcount+2:3);
|
||||
c.matches.slice(0,showCount).forEach(function(m,i){
|
||||
var w=pw(m.chunk_text||'');if(!w.nm)w.nm=m.name||m.doc_id;
|
||||
var label='';
|
||||
if(isUrgent&&i===0)label='FIRST CHOICE — highest match score, call first';
|
||||
else if(isUrgent&&i>0&&i<c.headcount)label='';
|
||||
else if(isUrgent&&i>=c.headcount)label='BACKUP — if someone above can\'t make it';
|
||||
addWorkerInsight(cd,w.nm,
|
||||
[w.role,w.loc].filter(Boolean).join(' · '),
|
||||
buildWhyText(w,c),i);
|
||||
label||buildWhyText(w,c),i,
|
||||
isUrgent&&i===0?'#f85149':isUrgent&&i>=c.headcount?'#484f58':null);
|
||||
});
|
||||
if(c.matches.length>3){
|
||||
var remaining=c.matches.length-showCount;
|
||||
if(remaining>0){
|
||||
var more=document.createElement('div');more.style.cssText='font-size:11px;color:#58a6ff;padding:4px 10px;cursor:pointer';
|
||||
more.textContent='+ '+(c.matches.length-3)+' more matched workers';
|
||||
more.textContent='+ '+remaining+' more available workers';
|
||||
cd.appendChild(more);
|
||||
}
|
||||
}
|
||||
@ -215,8 +253,9 @@ function buildWhyText(w,c){
|
||||
return reasons.length?reasons.join(' · '):'Matched by AI based on role and skills';
|
||||
}
|
||||
|
||||
function addWorkerInsight(parent,name,detail,why,idx){
|
||||
function addWorkerInsight(parent,name,detail,why,idx,highlight){
|
||||
var w=document.createElement('div');w.className='iworker';
|
||||
if(highlight)w.style.borderLeft='3px solid '+highlight;
|
||||
var av=document.createElement('div');av.className='av';av.style.background=AC[(idx||0)%AC.length];
|
||||
av.textContent=(name||'?').split(' ').map(function(n){return(n[0]||'').toUpperCase()}).join('').substring(0,2);
|
||||
w.appendChild(av);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user