first pass at storing data in DB instead of client only
This commit is contained in:
@@ -687,6 +687,7 @@ function savePackage(view){
|
||||
const ix=savedPackages.findIndex(p=>p.id===pkg.id);
|
||||
if(ix>=0) savedPackages[ix]=pkg; else savedPackages.push(pkg);
|
||||
editingId=pkg.id; saveStore(); renderSavedList(); track('package_saved',{status:pkg.status});
|
||||
if(typeof ProjectData!=='undefined' && ProjectData.pushWP) ProjectData.pushWP(pkg, activeProjectId); // share to server
|
||||
document.getElementById('loadingOverlay').classList.add('active');
|
||||
setTimeout(()=>{ document.getElementById('loadingOverlay').classList.remove('active'); if(view) renderPackage(pkg); }, 400);
|
||||
}
|
||||
@@ -846,8 +847,8 @@ function renderSavedList(){
|
||||
}).join('');
|
||||
}
|
||||
function viewPackage(i){ if(savedPackages[i]) renderPackage(savedPackages[i]); }
|
||||
function deletePackage(i){ const p=savedPackages[i]; if(!p) return; if(!confirm('Delete work package "'+(p.number||p.subject||'untitled')+'"? This cannot be undone.')) return; savedPackages.splice(i,1); saveStore(); renderSavedList(); track('package_deleted'); }
|
||||
function clearSaved(){ if(!savedPackages.length) return; if(!confirm('Delete all '+savedPackages.length+' saved packages on this device?')) return; savedPackages=[]; saveStore(); renderSavedList(); }
|
||||
function deletePackage(i){ const p=savedPackages[i]; if(!p) return; if(!confirm('Delete work package "'+(p.number||p.subject||'untitled')+'"? This cannot be undone.')) return; const delId=p.id; savedPackages.splice(i,1); saveStore(); renderSavedList(); track('package_deleted'); if(typeof ProjectData!=='undefined' && ProjectData.removeWP) ProjectData.removeWP(delId); }
|
||||
function clearSaved(){ if(!savedPackages.length) return; if(!confirm('Delete all '+savedPackages.length+' saved packages?')) return; const ids=savedPackages.map(p=>p.id); savedPackages=[]; saveStore(); renderSavedList(); if(typeof ProjectData!=='undefined' && ProjectData.removeWP) ids.forEach(id=>ProjectData.removeWP(id)); }
|
||||
function editPackage(i){ const p=savedPackages[i]; if(!p) return; editingId=p.id; loadPackageIntoForm(p); }
|
||||
function loadExample(){ loadPackageIntoForm(JSON.parse(JSON.stringify(EXAMPLE_PKG))); editingId=null; toast('Example work package loaded'); track('example_loaded'); }
|
||||
function loadPackageIntoForm(p){
|
||||
@@ -916,6 +917,7 @@ function duplicateWP(){
|
||||
savedPackages.push(c); made.push(c);
|
||||
}
|
||||
editingId=null; saveStore(); renderSavedList();
|
||||
if(typeof ProjectData!=='undefined' && ProjectData.pushWP) made.forEach(m=>ProjectData.pushWP(m, activeProjectId)); // share to server
|
||||
toast('Created '+n+' duplicate'+(n>1?'s':''));
|
||||
track('wp_duplicated',{count:n});
|
||||
alert('Created '+n+' duplicate'+(n>1?'s':'')+':\n\n• '+made.map(m=>m.number).join('\n• ')+'\n\nThey are in the Saved Work Packages list — edit each as needed.');
|
||||
@@ -951,12 +953,14 @@ function exportPackages(){
|
||||
// Data adapter: localStorage today. In Phase 2 swap list()/issue()/setStatus()
|
||||
// bodies for fetch() calls to /api/wps — the dashboard UI doesn't change.
|
||||
const WPData = {
|
||||
list(){ return savedPackages.slice(); }, // → GET /api/wps
|
||||
get(id){ return savedPackages.find(p=>p.id===id); }, // → GET /api/wps/{id}
|
||||
list(){ return savedPackages.slice(); }, // hydrated from GET /api/wps on boot
|
||||
get(id){ return savedPackages.find(p=>p.id===id); },
|
||||
issue(id){ const p=savedPackages.find(x=>x.id===id); if(!p) return false;
|
||||
p.status='Issued'; p.issuedAt=new Date().toISOString(); p.updatedAt=p.issuedAt; saveStore(); return true; }, // → POST /api/wps/{id}/issue
|
||||
p.status='Issued'; p.issuedAt=new Date().toISOString(); p.updatedAt=p.issuedAt; saveStore();
|
||||
if(typeof ProjectData!=='undefined' && ProjectData.pushWP) ProjectData.pushWP(p, activeProjectId); return true; },
|
||||
setStatus(id,status){ const p=savedPackages.find(x=>x.id===id); if(!p) return false;
|
||||
p.status=status; p.updatedAt=new Date().toISOString(); saveStore(); return true; }, // → POST /api/wps/{id}/status
|
||||
p.status=status; p.updatedAt=new Date().toISOString(); saveStore();
|
||||
if(typeof ProjectData!=='undefined' && ProjectData.pushWP) ProjectData.pushWP(p, activeProjectId); return true; },
|
||||
};
|
||||
|
||||
let dashFilter={status:'',discipline:'',q:'',flag:''};
|
||||
@@ -1144,10 +1148,10 @@ document.querySelectorAll('#status-group .radio-pill').forEach(p=>p.addEventList
|
||||
ProjectData.setActive(cached && cached.id===activeProjectId ? cached : { id: activeProjectId });
|
||||
}
|
||||
})();
|
||||
loadStore();
|
||||
(function bootSOP(){
|
||||
function bootSOP(){
|
||||
// When embedded in the Suite, hide the SOP import/sample controls (SOP is injected)
|
||||
// and prefer the SOP the Suite just completed (persisted to localStorage).
|
||||
// and prefer the SOP the Suite just completed (persisted to localStorage, which
|
||||
// we've already hydrated from the server for this project).
|
||||
const params = new URLSearchParams(location.search);
|
||||
if(params.get('embedded')) document.body.classList.add('embedded');
|
||||
try {
|
||||
@@ -1162,11 +1166,22 @@ loadStore();
|
||||
// state so it's clear the project's SOP must be completed first.
|
||||
if(activeProjectId){ SOP=null; renderCtxBar(); newPackage(); }
|
||||
else { loadSampleSOP(); }
|
||||
})();
|
||||
setRadio('status','Draft');
|
||||
renderSavedList();
|
||||
cmtInit();
|
||||
// Deep-link: open straight to the dashboard when requested (?view=dashboard or #dashboard).
|
||||
(function(){ const p=new URLSearchParams(location.search); if(p.get('view')==='dashboard' || location.hash==='#dashboard'){ showDashboard(); } })();
|
||||
}
|
||||
function bootData(){
|
||||
loadStore(); // reads the localStorage cache (hydrated from the server below)
|
||||
bootSOP();
|
||||
setRadio('status','Draft');
|
||||
renderSavedList();
|
||||
cmtInit();
|
||||
// Deep-link: open straight to the dashboard when requested (?view=dashboard or #dashboard).
|
||||
const p=new URLSearchParams(location.search); if(p.get('view')==='dashboard' || location.hash==='#dashboard'){ showDashboard(); }
|
||||
track('app_open');
|
||||
}
|
||||
window.addEventListener('hashchange',()=>{ if(location.hash==='#dashboard') showDashboard(); });
|
||||
track('app_open');
|
||||
// Pull this project's shared SOP + Work Packages from the server first, then boot
|
||||
// off the refreshed cache. Falls back to whatever is cached locally if offline.
|
||||
if(activeProjectId && typeof ProjectData!=='undefined' && ProjectData.pullProject){
|
||||
ProjectData.pullProject(activeProjectId).then(bootData).catch(bootData);
|
||||
} else {
|
||||
bootData();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user