diff --git a/index.html b/index.html index 7edf68c..05978e3 100644 --- a/index.html +++ b/index.html @@ -405,6 +405,8 @@ footer{margin-top:34px;padding-top:22px;border-top:1px solid var(--border);color
+
Agents to include
+
Send a digest whenever agents open, close, stop out, or take gains during a cycle.
@@ -737,7 +739,7 @@ footer{margin-top:34px;padding-top:22px;border-top:1px solid var(--border);color @@ -1156,10 +1158,24 @@ const EMAIL_ALERT_TYPES=[ {id:"GAIN",label:"Gain stops"}, ]; function defaultEmailAlerts(){ - return {enabled:false,email:"",events:{OPEN:true,CLOSE:true,EXIT:true,STOP:true,GAIN:true},last_sent_at:null,last_error:null}; + return { + enabled:false, + email:"", + events:{OPEN:true,CLOSE:true,EXIT:true,STOP:true,GAIN:true}, + agents:Object.fromEntries(AGENTS.map(a=>[a.id,true])), + last_sent_at:null, + last_error:null, + }; } function loadEmailAlerts(){ - try{return Object.assign(defaultEmailAlerts(),JSON.parse(localStorage.getItem(EMAIL_ALERT_KEY)||"{}"));} + try{ + const base=defaultEmailAlerts(); + const saved=JSON.parse(localStorage.getItem(EMAIL_ALERT_KEY)||"{}"); + const merged=Object.assign(base,saved||{}); + merged.events=Object.assign(base.events,(saved&&saved.events)||{}); + merged.agents=Object.assign(base.agents,(saved&&saved.agents)||{}); + return merged; + } catch(e){return defaultEmailAlerts();} } function saveEmailAlerts(cfg){ @@ -1167,6 +1183,7 @@ function saveEmailAlerts(cfg){ const merged=Object.assign(base,cfg||{}); merged.email=String(merged.email||"").trim(); merged.events=Object.assign(base.events,(cfg&&cfg.events)||{}); + merged.agents=Object.assign(base.agents,(cfg&&cfg.agents)||{}); merged.enabled=Boolean(merged.enabled&&validEmail(merged.email)); localStorage.setItem(EMAIL_ALERT_KEY,JSON.stringify(merged)); return merged; @@ -1181,7 +1198,9 @@ function collectNewAgentEvents(st,offsets){ const cfg=loadEmailAlerts(); if(!cfg.enabled||!validEmail(cfg.email))return []; const enabled=cfg.events||{}; + const selected=cfg.agents||{}; return AGENTS.flatMap(a=>{ + if(!selected[a.id])return []; const p=st.agents[a.id]||defaultPortfolio(); const start=Math.max(0,offsets[a.id]||0); return (p.history||[]).slice(start).filter(h=>enabled[h.action]).map(h=>({ @@ -1941,51 +1960,62 @@ function renderTopPicks(){
${Math.round(s.conviction)}
conviction
`).join(""); } function renderEmailAlerts(){ - const input=$("emailAlertInput"),eventsRoot=$("emailAlertEvents"),meta=$("emailAlertMeta"),status=$("emailAlertStatus"); - if(!input||!eventsRoot)return; + const input=$("emailAlertInput"),eventsRoot=$("emailAlertEvents"),agentsRoot=$("emailAlertAgents"),meta=$("emailAlertMeta"),status=$("emailAlertStatus"); + if(!input||!eventsRoot||!agentsRoot)return; const cfg=loadEmailAlerts(); input.value=cfg.email||""; - meta.textContent=cfg.enabled?`on for ${cfg.email}`:"off"; + const selectedCount=AGENTS.filter(a=>cfg.agents&&cfg.agents[a.id]).length; + meta.textContent=cfg.enabled?`on for ${cfg.email} · ${selectedCount}/${AGENTS.length} agents`:"off"; eventsRoot.innerHTML=EMAIL_ALERT_TYPES.map(t=>` `).join(""); + agentsRoot.innerHTML=AGENTS.map(a=>` + `).join(""); status.textContent=cfg.last_error ? `Last error: ${cfg.last_error}` - : (cfg.last_sent_at?`Last sent ${new Date(cfg.last_sent_at).toLocaleString()}.`:"Send a digest whenever agents open, close, stop out, or take gains during a cycle."); - $("saveEmailAlertsBtn").onclick=()=>{ + : (cfg.last_sent_at?`Last sent ${new Date(cfg.last_sent_at).toLocaleString()}.`:"Send a digest whenever selected agents open, close, stop out, or take gains during a cycle."); + const readAlertForm=()=>{ const email=input.value.trim(); const events={}; + const agents={}; document.querySelectorAll("[data-email-event]").forEach(el=>{events[el.dataset.emailEvent]=el.checked;}); - const saved=saveEmailAlerts({enabled:validEmail(email),email,events,last_error:validEmail(email)?null:"Enter a valid email address."}); - toast(saved.enabled?"Trade email alerts saved.":"Enter a valid email to turn alerts on."); + document.querySelectorAll("[data-email-agent]").forEach(el=>{agents[el.dataset.emailAgent]=el.checked;}); + return {email,events,agents}; + }; + const hasSelectedAgent=(agents)=>Object.values(agents||{}).some(Boolean); + $("saveEmailAlertsBtn").onclick=()=>{ + const form=readAlertForm(); + const anyAgent=hasSelectedAgent(form.agents); + const saved=saveEmailAlerts({enabled:validEmail(form.email)&&anyAgent,email:form.email,events:form.events,agents:form.agents,last_error:validEmail(form.email)?(anyAgent?null:"Select at least one agent."):"Enter a valid email address."}); + toast(saved.enabled?"Trade email alerts saved.":(anyAgent?"Enter a valid email to turn alerts on.":"Select at least one agent.")); renderEmailAlerts();pushCloudState(true); }; $("testEmailAlertsBtn").onclick=async()=>{ - const email=input.value.trim(); - const events={}; - document.querySelectorAll("[data-email-event]").forEach(el=>{events[el.dataset.emailEvent]=el.checked;}); - const saved=saveEmailAlerts({enabled:validEmail(email),email,events,last_error:null}); - if(!saved.enabled){toast("Enter a valid email first.");renderEmailAlerts();return;} + const form=readAlertForm(); + const anyAgent=hasSelectedAgent(form.agents); + const saved=saveEmailAlerts({enabled:validEmail(form.email)&&anyAgent,email:form.email,events:form.events,agents:form.agents,last_error:anyAgent?null:"Select at least one agent."}); + if(!saved.enabled){toast(anyAgent?"Enter a valid email first.":"Select at least one agent.");renderEmailAlerts();return;} + const testAgent=AGENTS.find(a=>saved.agents&&saved.agents[a.id])||AGENTS[0]; await notifyTradeDigest([{ - agent_id:"test", - agent_name:"Test Agent", - agent_emoji:"✉️", + agent_id:testAgent.id, + agent_name:testAgent.name, + agent_emoji:testAgent.emoji, action:"OPEN", date:todayStr(), question:"Test alert from Poly Arena", side:"YES", - detail:"This confirms trade email alerts are connected.", + detail:`This confirms trade email alerts are connected for ${testAgent.name}.`, equity:STARTING_BALANCE, return_pct:0, }],{test:true}); pushCloudState(true); }; - document.querySelectorAll("[data-email-event]").forEach(el=>el.onchange=()=>{ - const email=input.value.trim(); - const events={}; - document.querySelectorAll("[data-email-event]").forEach(box=>{events[box.dataset.emailEvent]=box.checked;}); - saveEmailAlerts({enabled:validEmail(email),email,events,last_error:null}); + document.querySelectorAll("[data-email-event],[data-email-agent]").forEach(el=>el.onchange=()=>{ + const form=readAlertForm(); + saveEmailAlerts({enabled:validEmail(form.email)&&hasSelectedAgent(form.agents),email:form.email,events:form.events,agents:form.agents,last_error:null}); renderEmailAlerts();pushCloudState(true); }); }