← back to AbramsOS

views/warranties.ejs

106 lines

<%- include('partials/header', { title: 'Warranties' }) %>

<section class="page-head">
  <div>
    <h1>Warranties &amp; Guarantees</h1>
    <p class="subtle"><%= warranties.length %> tracked · manual entries live alongside anything the receipt reader finds · expiry windows flow into <a href="/deadlines">Deadlines</a>.</p>
  </div>
  <div class="grid-controls">
    <label>Sort
      <select data-sort-for="warranty">
        <option value="due-asc">Expires soonest</option>
        <option value="due-desc">Expires latest</option>
        <option value="provider-asc">Provider A→Z</option>
        <option value="type-asc">Type</option>
        <option value="created-desc">Newest added</option>
      </select>
    </label>
    <label>Density
      <input data-density-for="warranty" type="range" min="240" max="460" step="10" value="320">
    </label>
    <button type="button" class="btn" id="toggleAdd">+ Add warranty</button>
  </div>
</section>

<form id="addForm" class="add-form glass" hidden>
  <div class="row">
    <label>Provider / item*<input name="provider_name" required placeholder="LG fridge / AppleCare"></label>
    <label>Type
      <select name="commitment_type">
        <% types.forEach(t => { %><option value="<%= t %>" <%= t==='warranty'?'selected':'' %>><%= t %></option><% }) %>
      </select>
    </label>
    <label>Expires<input name="refund_window_ends_at" type="date"></label>
  </div>
  <div class="row">
    <label class="grow">What it covers<input name="guarantee_text" placeholder="1-yr parts &amp; labor; extended to 3-yr via AppleCare"></label>
    <label>Window (days)<input name="window_days" type="number" placeholder="365"></label>
  </div>
  <div class="row">
    <label class="grow">Promised outcome<input name="promised_outcome" placeholder="free repair or replacement"></label>
    <label class="grow">Conditions / notes<input name="conditions" placeholder="keep receipt; excludes accidental damage"></label>
  </div>
  <div class="row"><button type="submit" class="btn primary">Save warranty</button></div>
</form>

<% if (!warranties.length) { %>
  <section class="empty glass"><p>No warranties yet. Click <strong>+ Add warranty</strong> to log one.</p></section>
<% } %>

<section data-grid="warranty" class="purchase-grid" style="grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));">
  <% warranties.forEach(w => { %>
    <article class="purchase glass<%= w.is_expired ? ' overdue' : '' %>"
             data-provider="<%= (w.provider_name||'').toLowerCase() %>"
             data-type="<%= w.commitment_type || '' %>"
             data-due="<%= w.refund_window_ends_at ? new Date(w.refund_window_ends_at).toISOString().slice(0,10) : '' %>"
             data-created="<%= new Date(w.created_at).toISOString() %>">
      <header>
        <h3><%= w.provider_name || 'Warranty' %></h3>
        <span class="chip cat"><%= w.commitment_type || 'warranty' %></span>
      </header>
      <div class="amount" style="font-size:14px;font-weight:500">
        <% if (w.refund_window_ends_at) { %>
          expires <%= new Date(w.refund_window_ends_at).toLocaleDateString() %>
          <% if (w.is_expired) { %><span class="badge red">expired</span>
          <% } else if (w.is_expiring_soon) { %><span class="badge amber">in <%= w.days_until %>d</span>
          <% } else { %><span class="badge">in <%= w.days_until %>d</span><% } %>
        <% } else if (w.window_days) { %><span class="subtle"><%= w.window_days %>-day window</span>
        <% } else { %><span class="subtle">no expiry set</span><% } %>
      </div>
      <dl class="meta">
        <% if (w.guarantee_text) { %><dt>Covers</dt><dd><%= w.guarantee_text %></dd><% } %>
        <% if (w.promised_outcome) { %><dt>Outcome</dt><dd><%= w.promised_outcome %></dd><% } %>
        <% if (w.conditions) { %><dt>Notes</dt><dd><%= w.conditions %></dd><% } %>
        <% if (w.source && w.source !== 'manual') { %><dt>Source</dt><dd><%= w.source %><% if (w.confidence != null) { %> (<%= Math.round(Number(w.confidence)*100) %>%)<% } %></dd><% } %>
      </dl>
      <div class="when" title="<%= new Date(w.created_at).toISOString() %>">🕓 added <%= new Date(w.created_at).toLocaleString(undefined, { year:'numeric', month:'short', day:'numeric', hour:'numeric', minute:'2-digit' }) %></div>
      <div class="card-actions">
        <% if (w.commitment_type !== 'return') { %><a class="btn small" href="/claims">File claim →</a><% } %>
        <button class="btn small danger" data-action="delete" data-id="<%= w.id %>">Delete</button>
      </div>
    </article>
  <% }) %>
</section>

<script>
  const $ = (s, r = document) => r.querySelector(s);
  $('#toggleAdd')?.addEventListener('click', () => { const f = $('#addForm'); f.hidden = !f.hidden; });

  $('#addForm')?.addEventListener('submit', async (e) => {
    e.preventDefault();
    const body = Object.fromEntries(new FormData(e.target).entries());
    const res = await fetch('/api/warranties', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body) });
    if (res.ok) location.reload(); else alert('Save failed: ' + (await res.text()));
  });

  document.querySelectorAll('[data-action="delete"]').forEach((btn) => {
    btn.addEventListener('click', async () => {
      if (!confirm('Delete this warranty?')) return;
      const res = await fetch(`/api/warranties/${btn.dataset.id}/delete`, { method: 'POST' });
      if (res.ok) location.reload(); else alert('Delete failed');
    });
  });
</script>

<%- include('partials/footer', { gridScript: true }) %>