← back to Butlr

views/admin/calls.ejs

68 lines

<%- include('../partials/head', { title, meta_desc }) %>
<%- include('../partials/header') %>

<main class="container" style="max-width: 1200px; padding: 24px;">

  <p style="margin-bottom: 8px;"><a href="/admin">← Admin</a></p>
  <h1 style="margin: 0 0 6px;">Call history</h1>
  <p class="muted" style="margin: 0 0 16px;"><%= calls.length %> total · all users · ordered newest first</p>

  <div style="display:flex; gap:12px; margin-bottom:16px; flex-wrap:wrap;">
    <input id="filter-q" placeholder="filter by business / goal / id" style="flex:1; min-width:240px; padding:8px 12px; border:1px solid var(--line); border-radius:6px;"/>
    <select id="filter-status" style="padding:8px 12px; border:1px solid var(--line); border-radius:6px;">
      <option value="">all statuses</option>
      <option value="queued">queued</option>
      <option value="dialing">dialing</option>
      <option value="connected">connected</option>
      <option value="done">done</option>
      <option value="failed">failed</option>
    </select>
  </div>

  <table style="width:100%; border-collapse:collapse; font-size:13px;">
    <thead style="background:var(--panel-2);">
      <tr style="border-bottom:1px solid var(--line);">
        <th style="text-align:left; padding:8px;">When</th>
        <th style="text-align:left; padding:8px;">Business</th>
        <th style="text-align:left; padding:8px;">Goal</th>
        <th style="text-align:left; padding:8px;">Status</th>
        <th style="text-align:left; padding:8px;">User</th>
        <th style="text-align:left; padding:8px;">Listen</th>
      </tr>
    </thead>
    <tbody id="calls-tbody">
      <% for (const c of calls) { %>
      <tr class="row" data-status="<%= c.status %>" data-search="<%= ((c.business_name||'') + ' ' + (c.goal||'') + ' ' + c.id).toLowerCase() %>" style="border-bottom:1px solid var(--line);">
        <td style="padding:8px; white-space:nowrap; color:var(--ink-dim);"><%= new Date(c.created_at).toLocaleString('en-US',{month:'short',day:'numeric',hour:'numeric',minute:'2-digit'}) %></td>
        <td style="padding:8px;"><strong><%= c.business_name %></strong><br><span class="muted" style="font-size:11px;"><%= c.business_phone %></span></td>
        <td style="padding:8px; max-width:300px;"><span class="muted"><%= (c.goal||'').slice(0,80) %><%= (c.goal||'').length > 80 ? '…' : '' %></span></td>
        <td style="padding:8px;">
          <span style="padding:2px 8px; border-radius:4px; font-size:11px; background:<%= c.status === 'done' ? '#dcfce7' : c.status === 'failed' ? '#fee2e2' : c.status === 'connected' ? '#fef3c7' : '#e0e7ff' %>; color:<%= c.status === 'done' ? '#166534' : c.status === 'failed' ? '#991b1b' : c.status === 'connected' ? '#92400e' : '#3730a3' %>;"><%= c.status %></span>
        </td>
        <td style="padding:8px; font-size:11px;"><%= (c.user_id || 'legacy').slice(0,8) %></td>
        <td style="padding:8px;"><a href="/listen/<%= c.id %>">▶</a></td>
      </tr>
      <% } %>
    </tbody>
  </table>

  <script>
  const q = document.getElementById('filter-q');
  const s = document.getElementById('filter-status');
  function apply() {
    const ql = (q.value || '').toLowerCase();
    const sv = s.value;
    document.querySelectorAll('.row').forEach(r => {
      const m1 = !ql || r.dataset.search.includes(ql);
      const m2 = !sv || r.dataset.status === sv;
      r.style.display = (m1 && m2) ? '' : 'none';
    });
  }
  q.addEventListener('input', apply);
  s.addEventListener('change', apply);
  </script>

</main>

<%- include('../partials/footer') %>