← back to Bubbesblock
public/opportunities.html
101 lines
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>BubbesBlock — Opportunity Alerts</title>
<meta name="description" content="Opportunity Alerts — real-time leads when neighbors near you need wallcoverings, decor, drapery & window treatments." />
<link rel="stylesheet" href="/styles.css" />
</head>
<body>
<div id="hdr"></div>
<div class="wrap">
<div id="left"></div>
<main class="col-center" id="main"></main>
<div id="right"></div>
</div>
<script>window.__bbAutoInit = false;</script>
<script src="/chrome.js"></script>
<script src="/app.js"></script>
<script>
const lockSvg = '<svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="4" y="11" width="16" height="10" rx="2"/><path d="M8 11V7a4 4 0 0 1 8 0v4"/></svg>';
const pinSvg = '<svg viewBox="0 0 24 24" width="13" height="13" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 21s-7-5.2-7-11a7 7 0 0 1 14 0c0 5.8-7 11-7 11z"/><circle cx="12" cy="10" r="2.5"/></svg>';
function respCta(o){
return o.youResponded
? `<button class="go done" disabled>Responded ✓</button>`
: `<button class="go" data-respond="${o.id}" data-neighbor="${o.neighbor}">Respond</button>`;
}
function oppCard(o){
const action = o.locked ? `<button class="lock" data-unlock="${o.id}">${lockSvg} Unlock</button>` : respCta(o);
const wlt = o.address
? `<button class="wlt" data-wlt="${encodeURIComponent(o.address)}">🏚️ See who lived at ${o.area} →</button><div class="wlt-mount"></div>`
: '';
return `<div class="opp ${o.forYou?'you':''}" data-opp="${o.id}" data-neighbor="${o.neighbor}">
<span class="ava ${o.color}">${o.initials}</span>
<div class="main">
<div class="toprow"><span class="who2">${o.neighbor}</span><span class="cat2">${o.category}</span>${o.forYou?'<span class="youtag">★ For you</span>':''}</div>
<div class="body2">${o.body}</div>
${wlt}
<div class="foot">
<span class="loc">${pinSvg} ${o.area}</span><span>· ${o.time}</span>
<span class="rc">· ${o.responses} responded</span>
<span class="resp">${action}</span>
</div>
</div>
</div>`;
}
function renderHistory(h){
if(!h || h.source==='unavailable') return `<div class="wlt-panel"><h5>🏚️ ${h.normalized||h.address||''}</h5><p class="res">Full home history isn't in yet. <a href="${h.link||'https://wholivedthere.com'}" target="_blank">Search wholivedthere.com →</a></p></div>`;
const res = (h.residents||[]).map(r=>`${r.name}${r.years?` (${r.years})`:''}`).join(' · ');
return `<div class="wlt-panel"><h5>🏚️ ${h.normalized||h.address}</h5>
${h.summary?`<p>${h.summary}</p>`:''}
${h.builtYear?`<p class="res">Built ${h.builtYear}${h.sqft?` · ${h.sqft} sqft`:''}${h.beds?` · ${h.beds}bd/${h.baths||'?'}ba`:''}</p>`:''}
${h.lastSold?`<p class="res">Last sold ${h.lastSold.date||''}${h.lastSold.price?` · ${h.lastSold.price}`:''}</p>`:''}
${res?`<p class="res">Past residents: ${res}</p>`:''}
<a class="wlt" href="https://wholivedthere.com/?address=${encodeURIComponent(h.address||'')}" target="_blank">Full record on wholivedthere.com →</a>
</div>`;
}
fetch('/api/opportunities', { credentials:'same-origin' }).then(r=>r.json()).then(d=>{
document.getElementById('hdr').innerHTML = topbar(d.me);
document.getElementById('left').innerHTML = leftRail(d.me);
document.getElementById('right').innerHTML = rightRail(d.me);
const sa = d.serviceArea || {};
const chips = (d.categoriesForYou||[]).map(c=>`<span>${c}</span>`).join('');
const forYou = d.opportunities.filter(o=>o.forYou).length;
const hero = `<div class="opp-hero">
<h2>Opportunity Alerts</h2>
<p>Real-time leads when neighbors near you ask for services like yours.</p>
<div class="area">${pinSvg} ${sa.radius_miles||20}-mile radius · ${sa.center||''}</div>
<div class="opp-chips">${chips}</div></div>`;
const count = `<div class="opp-count">${d.opportunities.length} open opportunities · ${forYou} matched to your services</div>`;
document.getElementById('main').innerHTML = hero + count + d.opportunities.map(oppCard).join('');
BB.init();
}).catch(()=>{ document.getElementById('main').innerHTML = '<div class="card"><div class="post">Could not load opportunities.</div></div>'; });
// inline home-history toggle
document.addEventListener('click', async e=>{
const b = e.target.closest('[data-wlt]'); if(!b) return;
const mount = b.nextElementSibling;
if(b.dataset.open){ mount.innerHTML=''; delete b.dataset.open; b.textContent = b.textContent.replace('Hide','See'); return; }
b.dataset.open='1'; mount.innerHTML='<div class="wlt-panel loading">Looking up home history…</div>';
try{ const h = await BB.api.get('/api/home-history?address='+b.dataset.wlt); mount.innerHTML = renderHistory(h); }
catch{ mount.innerHTML='<div class="wlt-panel">Could not load history.</div>'; }
});
// reflect respond/unlock results
document.addEventListener('opp-responded', e=>{
const card = document.querySelector(`.opp[data-opp="${e.detail.id}"]`); if(!card) return;
const rc = card.querySelector('.rc'); if(rc) rc.textContent = `· ${e.detail.responses} responded`;
card.querySelector('.resp').innerHTML = `<button class="go done" disabled>Responded ✓</button>`;
});
document.addEventListener('opp-unlocked', e=>{
const card = document.querySelector(`.opp[data-opp="${e.detail.id}"]`); if(!card) return;
card.querySelector('.resp').innerHTML = `<button class="go" data-respond="${e.detail.id}" data-neighbor="${card.dataset.neighbor||''}">Respond</button>`;
});
</script>
</body>
</html>