feat: reconcile Today with due Week Ahead work (Closes #1200)
This commit is contained in:
1 parent
5ac90d01e6
commit
a10592c349
5 files changed
+280
-24
No files matched your search
+41
-6
@@ -312,6 +312,18 @@ function createWeekPlan({fetchJson,localDate,timeZone,storage,getLogin}={}) {
|
||||
plan_date:due.plan_date,today_revision:todayRevision,
|
||||
})});
|
||||
}
|
||||
async function reconcilePromotion(preserved,selection) {
|
||||
if(pending()||conflict()) return false;
|
||||
const due=(preserved?.week?.days||week.days).find(item=>item.plan_date<=localDate()&&item.ids.length);
|
||||
if(!due||!Number.isInteger(preserved?.today?.revision)) return false;
|
||||
const result=await fetchJson('api/v1/week/reconcile',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({
|
||||
promotion_id:`reconcile-${due.plan_date}-r${preserved.week.revision}`,
|
||||
week_revision:preserved.week.revision,plan_date:due.plan_date,today_revision:preserved.today.revision,
|
||||
ids:[...(selection.ids||[])],capacity_minutes:selection.capacity_minutes??null,estimates:{...(selection.estimates||{})},
|
||||
})});
|
||||
adopt(result.week);
|
||||
return result;
|
||||
}
|
||||
function summary() {
|
||||
const planned=week.days.filter(item=>item.ids.length);
|
||||
const items=planned.reduce((total,item)=>total+item.ids.length,0);
|
||||
@@ -319,7 +331,7 @@ function createWeekPlan({fetchJson,localDate,timeZone,storage,getLogin}={}) {
|
||||
return label+(pending()?' · sync pending':'');
|
||||
}
|
||||
return {adopt,state,dates,day,pass,load,saveDay,stageDay,review,move,placement,place,pending,flush,conflict,chooseDay,saveMerged,
|
||||
keepLocal,useRemote,promote,summary};
|
||||
keepLocal,useRemote,promote,reconcile:reconcilePromotion,summary};
|
||||
}
|
||||
function createWeekPlanWorkflow({controller,qs,getLogin,getItem=()=>null,openPlanner,setReviewMode=()=>{},escapeHtml,escapeAttribute,
|
||||
todayWork,refresh,warm}={}) {
|
||||
@@ -327,6 +339,15 @@ function createWeekPlanWorkflow({controller,qs,getLogin,getItem=()=>null,openPla
|
||||
let reviewing=false;
|
||||
let editingFromReview=false;
|
||||
let blockedReviewOpen=false;
|
||||
let reconciliation=null;
|
||||
function reconciliationDay(){
|
||||
if(!reconciliation)return null;
|
||||
const due=(reconciliation.week?.days||[]).find(day=>day.ids?.length);
|
||||
if(!due)return null;
|
||||
const ids=[...new Set([...(reconciliation.today?.ids||[]),...(due.ids||[])])];
|
||||
return {plan_date:due.plan_date,ids,capacity_minutes:due.capacity_minutes??reconciliation.today?.capacity_minutes??null,
|
||||
estimates:{...(due.estimates||{}),...(reconciliation.today?.estimates||{})}};
|
||||
}
|
||||
function renderPass() {
|
||||
const progress=qs('#week-plan-progress'),save=qs('#save-today-plan');
|
||||
if(reviewing){
|
||||
@@ -458,6 +479,18 @@ function createWeekPlanWorkflow({controller,qs,getLogin,getItem=()=>null,openPla
|
||||
}
|
||||
function save(plan){
|
||||
const date=selectedDate,normalized=Array.isArray(plan)?{ids:plan,capacity_minutes:null,estimates:{}}:plan;
|
||||
if(reconciliation){
|
||||
const preserved=reconciliation;
|
||||
controller.reconcile(preserved,normalized).then(result=>{
|
||||
reconciliation=null;blockedReviewOpen=false;
|
||||
todayWork.replace(result.today.ids);todayWork.replacePlanning(result.today);
|
||||
refresh();warm();qs('#mobile-week-summary').textContent=controller.summary();
|
||||
qs('#my-work-action-status').textContent='Today started from unfinished and Week Ahead work.';
|
||||
}).catch(error=>{
|
||||
qs('#my-work-action-status').textContent=(error.message||'Plans changed during review.')+' Reopen Start today’s plan.';
|
||||
});
|
||||
return true;
|
||||
}
|
||||
const staged=controller.stageDay(date,normalized);
|
||||
if(!staged){qs('#my-work-action-status').textContent='Week Ahead could not be saved on this phone. Free browser storage and retry.';return false;}
|
||||
qs('#mobile-week-summary').textContent=controller.summary();
|
||||
@@ -496,7 +529,8 @@ function createWeekPlanWorkflow({controller,qs,getLogin,getItem=()=>null,openPla
|
||||
try{await controller.load();const promoted=await controller.promote(plan.revision);if(!promoted)return false;blockedReviewOpen=false;todayWork.replace(promoted.ids);todayWork.replacePlanning({capacity_minutes:promoted.capacity_minutes??null,estimates:promoted.estimates||{}});refresh();warm();qs('#mobile-week-summary').textContent=controller.summary();qs('#my-work-action-status').textContent='Your saved Week Ahead plan is now Today.';return true;}
|
||||
catch(error){
|
||||
if(error?.code==='week_today_in_progress'){
|
||||
qs('#my-work-action-status').textContent='Review unfinished Today before starting the saved Week Ahead day.';
|
||||
reconciliation={today:plan,week:controller.state()};
|
||||
qs('#my-work-action-status').textContent='Review unfinished Today with the due Week Ahead work before starting.';
|
||||
if(!blockedReviewOpen){blockedReviewOpen=true;openPlanner(null,false);}
|
||||
return false;
|
||||
}
|
||||
@@ -504,11 +538,12 @@ function createWeekPlanWorkflow({controller,qs,getLogin,getItem=()=>null,openPla
|
||||
qs('#my-work-action-status').textContent=(error.message||'Week Ahead needs review before promotion.')+' Open Week Ahead to review.';return false;
|
||||
}
|
||||
}
|
||||
return {open,save,advance,confirm,finish,promote,renderDates,renderConflict,active:()=>Boolean(selectedDate)||reviewing,
|
||||
return {open,save,advance,confirm,finish,promote,renderDates,renderConflict,active:()=>Boolean(selectedDate)||reviewing||Boolean(reconciliation),
|
||||
reviewing:()=>reviewing,selectedDate:()=>selectedDate,
|
||||
day:()=>selectedDate?controller.day(selectedDate):null,
|
||||
copy:()=>selectedDate?{title:'Plan Week Ahead',heading:selectedDate+', in order',available:'Available this day',build:'Build this day'}:null,
|
||||
clear(){selectedDate=null;reviewing=false;editingFromReview=false;setReviewMode(false);qs('#week-review').hidden=true;
|
||||
day:()=>reconciliationDay()||(selectedDate?controller.day(selectedDate):null),
|
||||
copy:()=>reconciliation?{title:"Start today's plan",heading:'Unfinished Today + due Week Ahead',available:'Available today',build:'Build combined Today'}:
|
||||
(selectedDate?{title:'Plan Week Ahead',heading:selectedDate+', in order',available:'Available this day',build:'Build this day'}:null),
|
||||
clear(){selectedDate=null;reviewing=false;editingFromReview=false;reconciliation=null;setReviewMode(false);qs('#week-review').hidden=true;
|
||||
const back=qs('#back-to-week-review');if(back)back.hidden=true;renderDates();}};
|
||||
}
|
||||
if(typeof module!=='undefined'&&module.exports){
|
||||
|
||||
Reference in new issue
Block a user