add Communications section to operations — inbox/sent brief with bounce alerts
This commit is contained in:
+160
@@ -368,8 +368,95 @@
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
/* ── Communications ──────────────────────── */
|
||||
.comms-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 14px;
|
||||
}
|
||||
.comms-card {
|
||||
background: var(--bg-card);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-card);
|
||||
padding: 20px;
|
||||
}
|
||||
.comms-card h3 {
|
||||
font-size: 12px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.06em;
|
||||
color: var(--accent);
|
||||
margin-bottom: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
.comms-card .comms-summary {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.comms-card .comms-stat {
|
||||
text-align: center;
|
||||
}
|
||||
.comms-card .comms-stat-num {
|
||||
font-size: 24px;
|
||||
font-weight: 700;
|
||||
color: var(--text);
|
||||
}
|
||||
.comms-card .comms-stat-label {
|
||||
font-size: 10px;
|
||||
color: var(--text-muted);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.04em;
|
||||
}
|
||||
.comms-list { list-style: none; }
|
||||
.comms-list li {
|
||||
font-size: 12px;
|
||||
padding: 6px 0;
|
||||
border-bottom: 1px solid rgba(10,48,96,0.3);
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 8px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
.comms-list li:last-child { border-bottom: none; }
|
||||
.comms-list .comms-time {
|
||||
color: var(--text-muted);
|
||||
font-size: 11px;
|
||||
white-space: nowrap;
|
||||
flex-shrink: 0;
|
||||
min-width: 60px;
|
||||
}
|
||||
.comms-list .comms-subj {
|
||||
color: var(--text);
|
||||
}
|
||||
.comms-list .comms-detail {
|
||||
color: var(--text-muted);
|
||||
font-size: 11px;
|
||||
}
|
||||
.comms-list .comms-from {
|
||||
color: var(--accent);
|
||||
font-size: 11px;
|
||||
}
|
||||
.comms-alert {
|
||||
background: var(--bg-card);
|
||||
border: 1px solid rgba(255,59,59,0.3);
|
||||
border-left: 3px solid var(--danger);
|
||||
border-radius: var(--radius-card);
|
||||
padding: 12px 16px;
|
||||
margin-top: 10px;
|
||||
font-size: 12px;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 8px;
|
||||
}
|
||||
.comms-alert .alert-icon { color: var(--danger); flex-shrink: 0; font-size: 14px; }
|
||||
.comms-alert .alert-body { color: var(--text); }
|
||||
.comms-alert .alert-detail { color: var(--text-muted); font-size: 11px; margin-top: 2px; }
|
||||
|
||||
@media (max-width: 900px) {
|
||||
.campaign-grid { grid-template-columns: 1fr; }
|
||||
.comms-grid { grid-template-columns: 1fr; }
|
||||
.goals-grid { grid-template-columns: repeat(2, 1fr); }
|
||||
.strategy-grid { grid-template-columns: 1fr; }
|
||||
}
|
||||
@@ -427,6 +514,17 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ═══════════════ COMMUNICATIONS ═══════════════ -->
|
||||
<div class="section">
|
||||
<div class="section-header" onclick="toggleSection('comms-section', this)">
|
||||
<h2><span class="icon">✉</span> Communications <span class="count">last 35 hours</span></h2>
|
||||
<span class="section-toggle">▼</span>
|
||||
</div>
|
||||
<div class="section-body" id="comms-section">
|
||||
<div class="comms-grid" id="comms-grid"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ═══════════════ STRATEGY & RECOMMENDATIONS ═══════════════ -->
|
||||
<div class="section">
|
||||
<div class="section-header" onclick="toggleSection('strategy-section', this)">
|
||||
@@ -512,6 +610,30 @@
|
||||
}
|
||||
];
|
||||
|
||||
const comms = {
|
||||
inbox: {
|
||||
total: 4,
|
||||
last35h: 2,
|
||||
items: [
|
||||
{ time: 'Jun 09 14:44', from: 'Mail Delivery System', subj: 'Undelivered — the@123.de', detail: '421 Downstream server error — cold email bounced', alert: true },
|
||||
{ time: 'Jun 08 21:04', from: 'Mail Delivery System', subj: 'Undelivered — the@123.de', detail: '421 Downstream server error', alert: false },
|
||||
],
|
||||
alerts: [
|
||||
{ icon: '⚠', body: 'Cold email to the@123.de bouncing (421 Downstream server error)', detail: 'Check recipient email validity or retry later.' }
|
||||
]
|
||||
},
|
||||
sent: {
|
||||
total: 8,
|
||||
last35h: 2,
|
||||
items: [
|
||||
{ time: 'Jun 09', to: 'o.arnold@projektbox.de', subj: 'setting up an agent for projektbox' },
|
||||
{ time: 'Jun 08', to: 'oliver@odoo4projects.com', subj: 'managing your agents without SSH' },
|
||||
],
|
||||
top_sent: 'Mark — Customer Success Agent'
|
||||
},
|
||||
note: '2 bounce alerts need review. Sending from support@derez.ai as Mark.'
|
||||
};
|
||||
|
||||
const recommendations = [
|
||||
'Prioritise the top 20 YouTube creators from the 60 collected — these are your most winnable influencer channel.',
|
||||
'Unlock cold email outreach by populating real business emails for those 20 creators. Templates and coupons are ready.',
|
||||
@@ -586,6 +708,43 @@
|
||||
).join('');
|
||||
}
|
||||
|
||||
function renderCommunications() {
|
||||
const c = comms;
|
||||
const inboxItems = c.inbox.items.map(i =>
|
||||
`<li><span class="comms-time">${i.time}</span><span><span class="comms-from">${i.from}</span><br><span class="comms-subj">${i.subj}</span> <span class="comms-detail">${i.detail}</span></span></li>`
|
||||
).join('');
|
||||
const alerts = c.inbox.alerts.map(a =>
|
||||
`<div class="comms-alert"><span class="alert-icon">${a.icon}</span><div><div class="alert-body">${a.body}</div><div class="alert-detail">${a.detail}</div></div></div>`
|
||||
).join('');
|
||||
const sentItems = c.sent.items.map(i =>
|
||||
`<li><span class="comms-time">${i.time}</span><span><span class="comms-from">${i.to}</span><br><span class="comms-subj">${i.subj}</span></span></li>`
|
||||
).join('');
|
||||
|
||||
document.getElementById('comms-grid').innerHTML =
|
||||
`<div class="comms-card">
|
||||
<h3>📥 Inbox</h3>
|
||||
<div class="comms-summary">
|
||||
<div class="comms-stat"><div class="comms-stat-num">${c.inbox.total}</div><div class="comms-stat-label">Total</div></div>
|
||||
<div class="comms-stat"><div class="comms-stat-num">${c.inbox.last35h}</div><div class="comms-stat-label">Last 35h</div></div>
|
||||
<div class="comms-stat"><div class="comms-stat-num">${c.inbox.alerts.length}</div><div class="comms-stat-label">Alerts</div></div>
|
||||
</div>
|
||||
<ul class="comms-list">${inboxItems}</ul>
|
||||
${alerts}
|
||||
</div>
|
||||
<div class="comms-card">
|
||||
<h3>📤 Sent</h3>
|
||||
<div class="comms-summary">
|
||||
<div class="comms-stat"><div class="comms-stat-num">${c.sent.total}</div><div class="comms-stat-label">Total Sent</div></div>
|
||||
<div class="comms-stat"><div class="comms-stat-num">${c.sent.last35h}</div><div class="comms-stat-label">Last 35h</div></div>
|
||||
<div class="comms-stat"><div class="comms-stat-num">${c.sent.items.length}</div><div class="comms-stat-label">Recent</div></div>
|
||||
</div>
|
||||
<ul class="comms-list">${sentItems}</ul>
|
||||
<div style="margin-top:8px;font-size:11px;color:var(--text-muted);">
|
||||
Sender: ${c.sent.top_sent} · ${c.note}
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
async function fetchLiveData() {
|
||||
try {
|
||||
const res = await fetch('data/operations.json?t=' + Date.now());
|
||||
@@ -602,6 +761,7 @@
|
||||
renderGoals();
|
||||
renderCampaigns();
|
||||
renderActions();
|
||||
renderCommunications();
|
||||
renderStrategy();
|
||||
fetchLiveData();
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user