diff --git a/check_loginads.mjs b/check_loginads.mjs new file mode 100644 index 0000000..7b15d7b --- /dev/null +++ b/check_loginads.mjs @@ -0,0 +1,18 @@ +import pkg from 'file:///D:/Projects/MarketingAgent/qa-tester/node_modules/playwright/index.js'; +const { chromium } = pkg; +const b = await chromium.connectOverCDP('http://127.0.0.1:9222'); +const page = await b.contexts()[0].newPage(); +await page.setViewportSize({ width: 1500, height: 1000 }); +await page.goto('https://www.adrevsplit.com/aradmin/admin.php?b=4411', { waitUntil:'domcontentloaded', timeout:45000 }); +await page.waitForTimeout(2500); +const r = await page.evaluate(() => { + const rows = [...document.querySelectorAll('table tr')].map(tr => + [...tr.querySelectorAll('td,th')].map(td => td.innerText.replace(/\s+/g,' ').trim())); + const links = [...document.querySelectorAll('a[href*="rmcircle"], a[href*="join"]')].map(a=>a.getAttribute('href')); + return { rows: rows.filter(r2=>r2.length>3).slice(0,14), links: [...new Set(links)] }; +}); +console.log('=== approved login ads ==='); +r.rows.forEach(x => console.log(' ' + x.join(' | ').slice(0,150))); +console.log('\n=== destination links found ==='); +r.links.forEach(l => console.log(' ' + l)); +await page.close(); await b.close(); diff --git a/gaps.mjs b/gaps.mjs new file mode 100644 index 0000000..97bce0a --- /dev/null +++ b/gaps.mjs @@ -0,0 +1,28 @@ +import pkg from 'file:///D:/Projects/MarketingAgent/qa-tester/node_modules/playwright/index.js'; +const { chromium } = pkg; +const b = await chromium.connectOverCDP('http://127.0.0.1:9222'); +const page = await b.contexts()[0].newPage(); +await page.setViewportSize({ width: 1340, height: 1000 }); +await page.goto('https://adrevsplit.com/login.php', { waitUntil:'domcontentloaded', timeout:45000 }); +await page.waitForTimeout(3000); +console.log(JSON.stringify(await page.evaluate(() => { + const col = document.querySelector('.col-lg-10, .custom-col-10'); + const out = { colTop: col ? Math.round(col.getBoundingClientRect().top) : null, children: [] }; + if (col) for (const c of col.children) { + if (c.getBoundingClientRect().height === 0) continue; + const r = c.getBoundingClientRect(); const cs = getComputedStyle(c); + out.children.push({ + tag: c.tagName, cls: (c.className||'').toString().slice(0,30), + top: Math.round(r.top), h: Math.round(r.height), + mt: cs.marginTop, mb: cs.marginBottom, + text: (c.innerText||'').replace(/\s+/g,' ').trim().slice(0,40) + }); + } + const ul = document.querySelector('.flexy-menu'); + out.menuTop = ul ? Math.round(ul.getBoundingClientRect().top) : null; + const sec = document.querySelector('section.container'); + out.sectionTop = sec ? Math.round(sec.getBoundingClientRect().top) : null; + out.sectionPadTop = sec ? getComputedStyle(sec).paddingTop : null; + return out; +}, null), null, 1)); +await b.close(); diff --git a/public/my.js b/public/my.js index 963fb27..0b2476b 100644 --- a/public/my.js +++ b/public/my.js @@ -399,7 +399,18 @@ // One-tap nudges: pre-written message per coach recommendation, sent over // the wallet-verified Messages rails (and bridged to Telegram if linked). const nudgeTexts={}; - function nudgeBtn(key){return `
`} + // Nudges used to send silently with only a "Delivered" note, so nobody could + // see WHAT went out or to whom. A member went hunting in her clipboard, found + // the unrelated "copy my summary" text still sitting there, and reasonably + // concluded the nudge had sent her own position instead of the recipient's. + // Preview before, and the exact sent text after, removes the guesswork. + function nudgeBtn(key){return `
`+ + ``+ + ``+ + ``+ + `
`} function regNudge(id,kind,text){const key=id+':'+kind;nudgeTexts[key]={to:id,text};return nudgeBtn(key)} function renderCoach(d){ const card=document.getElementById('dCoachCard'),el=document.getElementById('dCoach'); @@ -418,10 +429,20 @@ if(!el.__nudgeBound){ el.__nudgeBound=true; el.addEventListener('click',async ev=>{ + const pv=ev.target.closest&&ev.target.closest('button.coach-nudge-preview'); const btn=ev.target.closest&&ev.target.closest('button.coach-nudge'); - if(!btn)return; - const rec=nudgeTexts[btn.dataset.nkey];if(!rec)return; - const note=btn.nextElementSibling; + if(!pv&&!btn)return; + const rec=nudgeTexts[(pv||btn).dataset.nkey];if(!rec)return; + const wrap=(pv||btn).closest('.coach-nudge-wrap'); + const note=wrap&&wrap.querySelector('.coach-nudge-note'); + const prev=wrap&&wrap.querySelector('.coach-nudge-prev'); + const showPrev=(label)=>{if(!prev)return;prev.textContent=label+'\n\n'+rec.text;prev.style.display='';}; + // Preview: show exactly what will be sent, and to whom, before sending. + if(pv){ + if(prev&&prev.style.display!=='none'){prev.style.display='none';pv.textContent='\u{1F441} Preview';} + else{showPrev('This will be sent to #'+rec.to+':');pv.textContent='\u{1F441} Hide preview';} + return; + } const say=(t,color)=>{if(note){note.style.display='';note.style.color=color||'var(--muted)';note.textContent=t;}}; btn.disabled=true;const old=btn.textContent;btn.textContent='Sending…'; try{ @@ -434,7 +455,7 @@ } const r=await fetch('/api/public/msg-send',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({toId:rec.to,body:rec.text})}); const dd=await r.json().catch(()=>({})); - if(r.ok&&!dd.error){btn.textContent='Sent ✓';say('Delivered to their dashboard — and straight to their Telegram if they’ve linked it.');} + if(r.ok&&!dd.error){btn.textContent='Sent ✓';showPrev('✅ Sent to #'+rec.to+' — this is exactly what they received:');const pb=wrap&&wrap.querySelector('.coach-nudge-preview');if(pb)pb.style.display='none';say('Delivered to #'+rec.to+'’s dashboard — and straight to their Telegram if they’ve linked it.');} else{btn.textContent=old;btn.disabled=false;say(dd.error||'Could not send — try again.','var(--danger)');} }catch(e){btn.textContent=old;btn.disabled=false;say('Network hiccup — try again.','var(--danger)');} });