// services/renderers/callTestRenderer.js function fmtMs(ms) { if (ms == null || !Number.isFinite(ms)) return '—'; if (ms < 1000) return `${Math.round(ms)}ms`; return `${(ms / 1000).toFixed(1)}s`; } function fmtTime(iso) { if (!iso) return '—'; try { return new Date(iso).toISOString(); } catch { return String(iso); } } /** * @param {object} session */ export function renderCallTestStartedMarkdown(session) { const modeLabel = session.mode === 'store' ? 'Store path' : 'Direct dial'; const storePart = session.storeNum ? ` for store **${session.storeNum}**` : ''; return ( `**Call test started** (${modeLabel})${storePart}\n\n` + `- **Dialing:** ${session.dialNumber}\n` + `- **Test ID:** \`${session.testId}\`\n` + `- Results will post here when the call completes (~2–3 min).` ); } /** * @param {object} session */ export function renderCallTestResultMarkdown(session) { const modeLabel = session.mode === 'store' ? 'Store' : 'Direct'; const inProgress = session.result == null && (session.status === 'in_progress' || session.status === 'pending'); const pass = session.result === 'pass'; const warn = session.result === 'warn'; const icon = inProgress ? '⏳' : (pass || warn ? '✅' : '❌'); const headline = inProgress ? 'IN PROGRESS' : (pass || warn ? 'PASSED' : 'FAILED'); let md = `**${icon} Call test ${headline}** (${modeLabel})\n\n`; if (session.storeNum) md += `- **Store:** ${session.storeNum}\n`; md += `- **Dialed:** ${session.dialNumber}\n`; md += `- **Test ID:** \`${session.testId}\`\n`; if (session.callSid) md += `- **Twilio CallSid:** \`${session.callSid}\`\n`; if (session.resultReason) { md += `- **Result:** ${session.resultReason}\n`; } if (session.failedAt) { md += `- **Failed at:** ${session.failedAt}\n`; } const e = session.events || {}; md += '\n**Timings:**\n'; if (e.initiated) md += `- Initiated: ${fmtTime(e.initiated)}\n`; if (e.ringing) md += `- Ringing: ${fmtTime(e.ringing)}\n`; if (e.answered) md += `- Answered: ${fmtTime(e.answered)}\n`; if (!e.answered && e['in-progress']) md += `- In progress: ${fmtTime(e['in-progress'])}\n`; if (e.completed) md += `- Completed: ${fmtTime(e.completed)}\n`; if (e.answered && e.initiated) { md += `- Ring → answer: ${fmtMs(new Date(e.answered) - new Date(e.initiated))}\n`; } if (e.coreStartedAt) { md += `- Core started: ${fmtTime(e.coreStartedAt)}\n`; } if (e.completed && e.answered) { md += `- Answer → complete: ${fmtMs(new Date(e.completed) - new Date(e.answered))}\n`; } if (session.durationSec != null) { md += `- Total duration: ${session.durationSec}s\n`; } if (session.mode === 'store' && e.dtmfStepAt) { md += `- Entry → DTMF step: ${fmtTime(e.dtmfStepAt)}\n`; } return md.trim(); } /** * @param {object} session * @param {object} cdr */ export function renderCallTestCdrMarkdown(session, cdr) { if (!cdr?.available) { return ( `**Call test CDR** (\`${session.testId}\`)\n\n` + `_Detailed call history unavailable:_ ${cdr?.reason || 'not configured'}` ); } const summary = cdr.summary || {}; let md = `**Call test CDR enrichment** (store **${session.storeNum}**)\n\n` + `- **Window:** ${cdr.startTime} → ${cdr.endTime}\n` + `- **Location:** ${cdr.location || '—'}\n` + `- **Matching legs:** ${summary.totalCalls ?? cdr.rawCount ?? 0}\n`; if (summary.inbound != null) md += `- Inbound legs: ${summary.inbound}\n`; if (summary.missed != null) md += `- Missed / failed legs: ${summary.missed}\n`; const samples = cdr.samples || []; if (samples.length) { md += '\n**Sample legs:**\n'; for (const s of samples.slice(0, 5)) { md += `- ${s.start || '—'} | ${s.direction || '—'} | ${s.duration ?? '—'}s | ${s.otherParty || s.phoneNumber || '—'}\n`; } } return md.trim(); }