Persist mailshot admin picker selections

This commit is contained in:
Adrian Stephens 2026-07-27 09:44:57 +01:00
parent 82bba3df03
commit d1ac58ffaf
4 changed files with 34 additions and 4 deletions

View File

@ -112,6 +112,13 @@ final class DownloadPdfAdminPage
echo 'var zip=document.getElementById("feca-download-zip-btn");'; echo 'var zip=document.getElementById("feca-download-zip-btn");';
echo 'var progress=document.getElementById("feca-download-progress");'; echo 'var progress=document.getElementById("feca-download-progress");';
echo 'var shadow=document.getElementById("feca-download-format-shadow");'; echo 'var shadow=document.getElementById("feca-download-format-shadow");';
echo 'var mailshotSelect=document.getElementById("dp_mailshot_id");';
echo 'var selectedKey="fecaMailshotsSelectedMailshotId";';
echo 'function hasOption(value){if(!mailshotSelect){return false;}for(var i=0;i<mailshotSelect.options.length;i++){if(String(mailshotSelect.options[i].value||"")===String(value||"")){return true;}}return false;}';
echo 'function currentUrl(){return new URL(window.location.href);}';
echo 'function updateUrl(value){try{var url=currentUrl();url.searchParams.set("page","' . self::PAGE_SLUG . '");if(value){url.searchParams.set("mailshot_id",String(value));}else{url.searchParams.delete("mailshot_id");}window.history.replaceState({},"",url.toString());}catch(_){}}';
echo 'try{var url=currentUrl();var hasExplicit=url.searchParams.has("mailshot_id");var stored=String(sessionStorage.getItem(selectedKey)||"").trim();if(!hasExplicit&&stored&&hasOption(stored)&&mailshotSelect&&String(mailshotSelect.value||"")!==stored){url.searchParams.set("page","' . self::PAGE_SLUG . '");url.searchParams.set("mailshot_id",stored);window.location.replace(url.toString());return;}}catch(_){}';
echo 'if(mailshotSelect){try{if(mailshotSelect.value){sessionStorage.setItem(selectedKey,String(mailshotSelect.value));}}catch(_){}updateUrl(String(mailshotSelect.value||""));mailshotSelect.addEventListener("change",function(){var value=String(mailshotSelect.value||"");try{if(value){sessionStorage.setItem(selectedKey,value);}else{sessionStorage.removeItem(selectedKey);}}catch(_){}updateUrl(value);});}';
echo 'var clearUi=function(){if(progress){progress.style.display="none";}if(merged){merged.disabled=false;merged.classList.remove("disabled");}if(zip){zip.disabled=false;zip.classList.remove("disabled");}};'; echo 'var clearUi=function(){if(progress){progress.style.display="none";}if(merged){merged.disabled=false;merged.classList.remove("disabled");}if(zip){zip.disabled=false;zip.classList.remove("disabled");}};';
echo 'actualForm.addEventListener("submit",function(ev){'; echo 'actualForm.addEventListener("submit",function(ev){';
echo 'var submitter=ev&&ev.submitter?ev.submitter:null;'; echo 'var submitter=ev&&ev.submitter?ev.submitter:null;';

View File

@ -173,7 +173,16 @@ final class MailshotTestAdminPage
echo '</select></div>'; echo '</select></div>';
echo '</div>'; echo '</div>';
echo '</form>'; echo '</form>';
echo '<script>(function(){var select=document.getElementById("mst_mailshot_id");var form=document.getElementById("mst-mailshot-select-form");if(select&&form){select.addEventListener("change",function(){form.submit();});}})();</script>'; echo '<script>(function(){';
echo 'var select=document.getElementById("mst_mailshot_id");';
echo 'var form=document.getElementById("mst-mailshot-select-form");';
echo 'var key="fecaMailshotsSelectedMailshotId";';
echo 'function hasOption(value){if(!select){return false;}for(var i=0;i<select.options.length;i++){if(String(select.options[i].value||"")===String(value||"")){return true;}}return false;}';
echo 'function currentUrl(){return new URL(window.location.href);}';
echo 'try{var url=currentUrl();var hasExplicit=url.searchParams.has("mailshot_id");var stored=String(sessionStorage.getItem(key)||"").trim();if(!hasExplicit&&stored&&hasOption(stored)&&select&&String(select.value||"")!==stored){url.searchParams.set("page","feca-mailshots-test");url.searchParams.set("mailshot_id",stored);window.location.replace(url.toString());return;}}catch(_){}';
echo 'if(select){try{if(select.value){sessionStorage.setItem(key,String(select.value));}}catch(_){}}';
echo 'if(select&&form){select.addEventListener("change",function(){try{sessionStorage.setItem(key,String(select.value||""));}catch(_){}form.submit();});}';
echo '})();</script>';
echo '</div>'; echo '</div>';
if (!empty($preview['errors'])) { if (!empty($preview['errors'])) {

View File

@ -116,6 +116,7 @@ var headRow=document.getElementById("rr_head_row");
var bodyEl=document.getElementById("rr_body"); var bodyEl=document.getElementById("rr_body");
var loadMoreBtn=document.getElementById("rr_load_more"); var loadMoreBtn=document.getElementById("rr_load_more");
var storagePrefix="fecaReviewRecipientsSelection::"; var storagePrefix="fecaReviewRecipientsSelection::";
var selectedSourceStorageKey="fecaReviewRecipientsSelectedSource";
var state={source:"",filter:"",sortBy:"",sortDirection:"asc",selectedKeys:{},rows:[],columns:[],count:0,offset:0,hasMore:false,loading:false,errors:[]}; var state={source:"",filter:"",sortBy:"",sortDirection:"asc",selectedKeys:{},rows:[],columns:[],count:0,offset:0,hasMore:false,loading:false,errors:[]};
function text(v){if(v===null||v===undefined){return "";}if(typeof v==="string"){return v;}if(typeof v==="number"||typeof v==="boolean"){return String(v);}try{return JSON.stringify(v);}catch(_){return String(v);}} function text(v){if(v===null||v===undefined){return "";}if(typeof v==="string"){return v;}if(typeof v==="number"||typeof v==="boolean"){return String(v);}try{return JSON.stringify(v);}catch(_){return String(v);}}
function clearErr(){errEl.classList.add("feca-hidden");errEl.textContent="";} function clearErr(){errEl.classList.add("feca-hidden");errEl.textContent="";}
@ -123,6 +124,9 @@ function showErr(msg){errEl.classList.remove("feca-hidden");errEl.textContent=ms
function status(msg){statusEl.textContent=msg||"";} function status(msg){statusEl.textContent=msg||"";}
function setColumnWidths(cols){var widthPx=170;var c="<col style=\"width:44px;min-width:44px;max-width:44px\">";for(var i=0;i<cols.length;i++){c+="<col style=\"width:"+widthPx+"px;min-width:"+widthPx+"px;max-width:"+widthPx+"px\">";}colsEl.innerHTML=c;} function setColumnWidths(cols){var widthPx=170;var c="<col style=\"width:44px;min-width:44px;max-width:44px\">";for(var i=0;i<cols.length;i++){c+="<col style=\"width:"+widthPx+"px;min-width:"+widthPx+"px;max-width:"+widthPx+"px\">";}colsEl.innerHTML=c;}
function sourceStorageKey(src){return storagePrefix+String(src||"");} function sourceStorageKey(src){return storagePrefix+String(src||"");}
function sourceExists(src){if(!src){return false;}var opts=sourceSel?sourceSel.options:[];for(var i=0;i<opts.length;i++){if(String(opts[i].value||"")===src){return true;}}return false;}
function loadSelectedSource(){try{var src=String(sessionStorage.getItem(selectedSourceStorageKey)||"").trim();return sourceExists(src)?src:"";}catch(_){return "";}}
function saveSelectedSource(src){try{if(src){sessionStorage.setItem(selectedSourceStorageKey,src);}else{sessionStorage.removeItem(selectedSourceStorageKey);}}catch(_){}}
function loadSelection(src){if(!src){return {};}try{var raw=sessionStorage.getItem(sourceStorageKey(src));if(!raw){return {};}var parsed=JSON.parse(raw);if(parsed&&typeof parsed==="object"){return parsed;}}catch(_){ }return {};} function loadSelection(src){if(!src){return {};}try{var raw=sessionStorage.getItem(sourceStorageKey(src));if(!raw){return {};}var parsed=JSON.parse(raw);if(parsed&&typeof parsed==="object"){return parsed;}}catch(_){ }return {};}
function saveSelection(){if(!state.source){return;}try{sessionStorage.setItem(sourceStorageKey(state.source),JSON.stringify(state.selectedKeys||{}));}catch(_){ }} function saveSelection(){if(!state.source){return;}try{sessionStorage.setItem(sourceStorageKey(state.source),JSON.stringify(state.selectedKeys||{}));}catch(_){ }}
function isIdField(name){var n=String(name||"").trim().toLowerCase();return n==="id"||n.endsWith(".id")||n.endsWith("_id")||n==="accountid"||n.endsWith(".accountid");} function isIdField(name){var n=String(name||"").trim().toLowerCase();return n==="id"||n.endsWith(".id")||n.endsWith("_id")||n==="accountid"||n.endsWith(".accountid");}
@ -137,7 +141,7 @@ function renderTable(){if(!state.source){clearErr();setColumnWidths([]);headRow.
function applyPayload(sourceName,j,append){var offset=parseInt(j.offset||0,10);var rows=(j.rows||[]).map(function(r,i){var out=(r&&typeof r==="object")?Object.assign({},r):{};out.__rr_index=offset+i;return out;});state.source=sourceName;state.count=parseInt(j.count||0,10)||0;state.offset=offset+rows.length;state.hasMore=!!j.has_more;state.columns=append?Array.from(new Set(state.columns.concat(j.columns||[]))):(j.columns||[]);state.rows=append?state.rows.concat(rows):rows;} function applyPayload(sourceName,j,append){var offset=parseInt(j.offset||0,10);var rows=(j.rows||[]).map(function(r,i){var out=(r&&typeof r==="object")?Object.assign({},r):{};out.__rr_index=offset+i;return out;});state.source=sourceName;state.count=parseInt(j.count||0,10)||0;state.offset=offset+rows.length;state.hasMore=!!j.has_more;state.columns=append?Array.from(new Set(state.columns.concat(j.columns||[]))):(j.columns||[]);state.rows=append?state.rows.concat(rows):rows;}
function fetchSource(sourceName,append){if(!sourceName){state.source="";state.errors=[];state.rows=[];state.columns=[];state.count=0;state.offset=0;state.hasMore=false;renderTable();return;}clearErr();state.errors=[];state.loading=true;status(append?"Loading more recipients...":"Loading recipients...");updateLoadMore();var offset=append?state.offset:0;var limit=parseInt(cfg.pageSize||200,10)||200;var url=(cfg.api||"")+""+(String(cfg.api||"").indexOf("?")===-1?"?":"&")+"op=load&data_source="+encodeURIComponent(sourceName)+"&limit="+encodeURIComponent(String(limit))+"&offset="+encodeURIComponent(String(offset));fetch(url,{credentials:"same-origin"}).then(function(r){return r.text().then(function(raw){var j=null;try{j=JSON.parse(raw||"{}");}catch(_){j=null;}if(!r.ok){var errors=(j&&j.errors)||[(j&&j.error)||("API "+r.status)];return {ok:false,errors:errors,rows:[],columns:[],count:0};}if(j===null){return {ok:false,errors:["API returned non-JSON response."],rows:[],columns:[],count:0};}return j;});}).then(function(j){if(!j||j.ok===false){state.errors=(j&&j.errors)||[(j&&j.error)||"Unknown API error"];state.rows=[];state.columns=[];state.count=0;state.offset=0;state.hasMore=false;}else{applyPayload(sourceName,j,!!append);}state.loading=false;renderTable();}).catch(function(e){state.loading=false;state.errors=[(e&&e.message)||"Request failed"];state.rows=[];state.columns=[];state.count=0;state.offset=0;state.hasMore=false;renderTable();});} function fetchSource(sourceName,append){if(!sourceName){state.source="";state.errors=[];state.rows=[];state.columns=[];state.count=0;state.offset=0;state.hasMore=false;renderTable();return;}clearErr();state.errors=[];state.loading=true;status(append?"Loading more recipients...":"Loading recipients...");updateLoadMore();var offset=append?state.offset:0;var limit=parseInt(cfg.pageSize||200,10)||200;var url=(cfg.api||"")+""+(String(cfg.api||"").indexOf("?")===-1?"?":"&")+"op=load&data_source="+encodeURIComponent(sourceName)+"&limit="+encodeURIComponent(String(limit))+"&offset="+encodeURIComponent(String(offset));fetch(url,{credentials:"same-origin"}).then(function(r){return r.text().then(function(raw){var j=null;try{j=JSON.parse(raw||"{}");}catch(_){j=null;}if(!r.ok){var errors=(j&&j.errors)||[(j&&j.error)||("API "+r.status)];return {ok:false,errors:errors,rows:[],columns:[],count:0};}if(j===null){return {ok:false,errors:["API returned non-JSON response."],rows:[],columns:[],count:0};}return j;});}).then(function(j){if(!j||j.ok===false){state.errors=(j&&j.errors)||[(j&&j.error)||"Unknown API error"];state.rows=[];state.columns=[];state.count=0;state.offset=0;state.hasMore=false;}else{applyPayload(sourceName,j,!!append);}state.loading=false;renderTable();}).catch(function(e){state.loading=false;state.errors=[(e&&e.message)||"Request failed"];state.rows=[];state.columns=[];state.count=0;state.offset=0;state.hasMore=false;renderTable();});}
function updateUrlSource(sourceName){var url=new URL(window.location.href);url.searchParams.set("page",cfg.pageSlug||"feca-mailshots-review-recipients");if(sourceName){url.searchParams.set("data_source",sourceName);}else{url.searchParams.delete("data_source");}window.history.replaceState({}, "", url.toString());} function updateUrlSource(sourceName){var url=new URL(window.location.href);url.searchParams.set("page",cfg.pageSlug||"feca-mailshots-review-recipients");if(sourceName){url.searchParams.set("data_source",sourceName);}else{url.searchParams.delete("data_source");}window.history.replaceState({}, "", url.toString());}
sourceSel.addEventListener("change",function(){var s=String(sourceSel.value||"").trim();state.source=s;state.errors=[];state.selectedKeys=loadSelection(s);state.rows=[];state.columns=[];state.count=0;state.offset=0;state.hasMore=false;updateUrlSource(s);fetchSource(s,false);}); sourceSel.addEventListener("change",function(){var s=String(sourceSel.value||"").trim();state.source=s;state.errors=[];state.selectedKeys=loadSelection(s);state.rows=[];state.columns=[];state.count=0;state.offset=0;state.hasMore=false;saveSelectedSource(s);updateUrlSource(s);fetchSource(s,false);});
filterInput.addEventListener("input",function(){state.filter=String(filterInput.value||"").trim();renderTable();}); filterInput.addEventListener("input",function(){state.filter=String(filterInput.value||"").trim();renderTable();});
sortSel.addEventListener("change",function(){state.sortBy=String(sortSel.value||"").trim();renderTable();}); sortSel.addEventListener("change",function(){state.sortBy=String(sortSel.value||"").trim();renderTable();});
dirSel.addEventListener("change",function(){state.sortDirection=String(dirSel.value||"asc")==="desc"?"desc":"asc";renderTable();}); dirSel.addEventListener("change",function(){state.sortDirection=String(dirSel.value||"asc")==="desc"?"desc":"asc";renderTable();});
@ -145,7 +149,7 @@ if(loadMoreBtn){loadMoreBtn.addEventListener("click",function(){if(state.source&
headRow.addEventListener("change",function(ev){var t=ev.target;if(!t||t.id!=="rr_select_all"){return;}var checked=!!t.checked;var nodes=bodyEl.querySelectorAll("input.rr-row-select[data-key]");nodes.forEach(function(node){var key=String(node.getAttribute("data-key")||"");if(!key){return;}if(checked){state.selectedKeys[key]=true;}else{delete state.selectedKeys[key];}node.checked=checked;});renderTable();}); headRow.addEventListener("change",function(ev){var t=ev.target;if(!t||t.id!=="rr_select_all"){return;}var checked=!!t.checked;var nodes=bodyEl.querySelectorAll("input.rr-row-select[data-key]");nodes.forEach(function(node){var key=String(node.getAttribute("data-key")||"");if(!key){return;}if(checked){state.selectedKeys[key]=true;}else{delete state.selectedKeys[key];}node.checked=checked;});renderTable();});
bodyEl.addEventListener("change",function(ev){var t=ev.target;if(!t||!t.classList||!t.classList.contains("rr-row-select")){return;}var key=String(t.getAttribute("data-key")||"");if(!key){return;}if(t.checked){state.selectedKeys[key]=true;}else{delete state.selectedKeys[key];}renderTable();}); bodyEl.addEventListener("change",function(ev){var t=ev.target;if(!t||!t.classList||!t.classList.contains("rr-row-select")){return;}var key=String(t.getAttribute("data-key")||"");if(!key){return;}if(t.checked){state.selectedKeys[key]=true;}else{delete state.selectedKeys[key];}renderTable();});
state.sortDirection="asc";dirSel.value="asc"; state.sortDirection="asc";dirSel.value="asc";
var startSource=String((cfg.selectedSource||sourceSel.value||"")).trim();state.source=startSource;state.selectedKeys=loadSelection(startSource);if(startSource){fetchSource(startSource,false);}else{renderTable();} var startSource=String((cfg.selectedSource||sourceSel.value||loadSelectedSource()||"")).trim();if(sourceExists(startSource)){sourceSel.value=startSource;}else{startSource="";}state.source=startSource;state.selectedKeys=loadSelection(startSource);if(startSource){saveSelectedSource(startSource);updateUrlSource(startSource);fetchSource(startSource,false);}else{renderTable();}
})(); })();
JS; JS;
echo '</script>'; echo '</script>';

View File

@ -126,7 +126,7 @@ final class RunMailshotAdminPage
echo '<div class="feca-control-row">'; echo '<div class="feca-control-row">';
echo '<div class="feca-control feca-control-min-360">'; echo '<div class="feca-control feca-control-min-360">';
echo '<label for="run_mailshot_id"><strong>Mailshot</strong></label>'; echo '<label for="run_mailshot_id"><strong>Mailshot</strong></label>';
echo '<select id="run_mailshot_id" name="mailshot_id" onchange="document.getElementById(\'run-mailshot-picker\').submit();">'; echo '<select id="run_mailshot_id" name="mailshot_id">';
foreach ($mailshots as $m) { foreach ($mailshots as $m) {
$id = (int) ($m['id'] ?? 0); $id = (int) ($m['id'] ?? 0);
$sel = $id === $selectedMailshotId ? ' selected' : ''; $sel = $id === $selectedMailshotId ? ' selected' : '';
@ -138,6 +138,16 @@ final class RunMailshotAdminPage
} }
echo '</select></div></div>'; echo '</select></div></div>';
echo '</form>'; echo '</form>';
echo '<script>(function(){';
echo 'var select=document.getElementById("run_mailshot_id");';
echo 'var form=document.getElementById("run-mailshot-picker");';
echo 'var key="fecaMailshotsSelectedMailshotId";';
echo 'function hasOption(value){if(!select){return false;}for(var i=0;i<select.options.length;i++){if(String(select.options[i].value||"")===String(value||"")){return true;}}return false;}';
echo 'function currentUrl(){return new URL(window.location.href);}';
echo 'try{var url=currentUrl();var hasExplicit=url.searchParams.has("mailshot_id");var stored=String(sessionStorage.getItem(key)||"").trim();if(!hasExplicit&&stored&&hasOption(stored)&&select&&String(select.value||"")!==stored){url.searchParams.set("page","feca-mailshots-run");url.searchParams.set("mailshot_id",stored);window.location.replace(url.toString());return;}}catch(_){}';
echo 'if(select){try{if(select.value){sessionStorage.setItem(key,String(select.value));}}catch(_){}}';
echo 'if(select&&form){select.addEventListener("change",function(){try{sessionStorage.setItem(key,String(select.value||""));}catch(_){}form.submit();});}';
echo '})();</script>';
if (!empty($recipientSummary['ok'])) { if (!empty($recipientSummary['ok'])) {
echo '<p class="feca-banner-note"><strong>Recipient rows:</strong> ' . (int) ($recipientSummary['count'] ?? 0) . '</p>'; echo '<p class="feca-banner-note"><strong>Recipient rows:</strong> ' . (int) ($recipientSummary['count'] ?? 0) . '</p>';
} elseif (!empty($recipientSummary['errors']) && is_array($recipientSummary['errors'])) { } elseif (!empty($recipientSummary['errors']) && is_array($recipientSummary['errors'])) {