← back to AbramsOS
views/claims.ejs
222 lines
<%- include('partials/header', { title: 'Claims' }) %>
<section class="page-head">
<h1>Claims</h1>
<p class="subtle" style="margin:0;color:var(--text-dim);font-size:13px">Drafts only. Nothing leaves AbramsOS without your explicit approval per action.</p>
</section>
<%
var household = (typeof household !== 'undefined' && household) ? household : [];
var claimitUrl = 'https://claimit.ca.gov/app/claim-search';
%>
<section class="glass" style="padding:16px 18px;margin-bottom:20px;display:flex;flex-direction:column;gap:12px">
<header style="display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap">
<span class="name" style="display:flex;align-items:center;gap:10px">
<span class="icon">🐻</span>
<strong>California Unclaimed Property</strong>
</span>
<a class="button" href="<%= claimitUrl %>" target="_blank" rel="noopener noreferrer">Search claimit.ca.gov ↗</a>
</header>
<p class="desc" style="margin:0;color:var(--text-dim);font-size:13px">
Free official search from the California State Controller for money owed to you —
forgotten bank accounts, refunds, uncashed checks, insurance, deposits. Search each
household name (and prior addresses / maiden names). Filing a claim is always free.
</p>
<% if (household.length) { %>
<div style="display:flex;flex-direction:column;gap:6px">
<span class="subtle" style="font-size:11px;color:var(--text-dim);text-transform:uppercase;letter-spacing:.05em">Names to search</span>
<div style="display:flex;flex-wrap:wrap;gap:8px">
<% household.forEach(function (name) { %>
<button type="button" class="chip" data-copy="<%= name %>"
style="cursor:pointer;border:1px solid var(--border,#3a3a3a);background:transparent;color:inherit;border-radius:999px;padding:5px 12px;font-size:12px"
title="Copy name, then paste into claimit.ca.gov">
<%= name %>
</button>
<% }); %>
</div>
<span class="subtle" style="font-size:11px;color:var(--text-dim)">Tap a name to copy it, then paste into the search on claimit.ca.gov (it opens in a new tab).</span>
</div>
<% } else { %>
<span class="subtle" style="font-size:12px;color:var(--text-dim)">Tip: add people in <a href="/household">Household</a> and their names will appear here as one-tap searches.</span>
<% } %>
</section>
<%
var properties = (typeof properties !== 'undefined' && properties) ? properties : [];
var ucpTotals = (typeof ucpTotals !== 'undefined' && ucpTotals) ? ucpTotals : { count: 0, staged: 0, filed: 0, paid: 0, found: 0, totalCents: 0, totalDisplay: '$0.00' };
var statusOptions = ['found', 'staged', 'filed', 'paid', 'not_mine'];
%>
<% if (properties.length) { %>
<section class="glass" style="padding:16px 18px;margin-bottom:20px;display:flex;flex-direction:column;gap:12px">
<header style="display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap">
<span class="name" style="display:flex;align-items:center;gap:10px">
<span class="icon">💰</span>
<strong>Tracked Properties</strong>
</span>
<span class="subtle" style="font-size:12px;color:var(--text-dim);display:flex;align-items:center;gap:10px;flex-wrap:wrap">
<strong style="color:inherit"><%= ucpTotals.count %></strong> propert<%= ucpTotals.count === 1 ? 'y' : 'ies' %>
· <strong style="color:#7dd88a"><%= ucpTotals.totalDisplay %></strong> total
<span style="opacity:.7">·</span>
<span title="staged">staged <strong><%= ucpTotals.staged %></strong></span>
<span style="opacity:.7">·</span>
<span title="filed">filed <strong><%= ucpTotals.filed %></strong></span>
<span style="opacity:.7">·</span>
<span title="paid">paid <strong><%= ucpTotals.paid %></strong></span>
</span>
</header>
<div style="overflow-x:auto">
<table style="width:100%;border-collapse:collapse;font-size:12px">
<thead>
<tr style="text-align:left;color:var(--text-dim);text-transform:uppercase;letter-spacing:.05em;font-size:11px">
<th style="padding:8px 10px;border-bottom:1px solid var(--border,#3a3a3a)">Amount</th>
<th style="padding:8px 10px;border-bottom:1px solid var(--border,#3a3a3a)">Holder</th>
<th style="padding:8px 10px;border-bottom:1px solid var(--border,#3a3a3a)">Address</th>
<th style="padding:8px 10px;border-bottom:1px solid var(--border,#3a3a3a)">Type</th>
<th style="padding:8px 10px;border-bottom:1px solid var(--border,#3a3a3a)">Property ID</th>
<th style="padding:8px 10px;border-bottom:1px solid var(--border,#3a3a3a)">Status</th>
<th style="padding:8px 10px;border-bottom:1px solid var(--border,#3a3a3a)">Found</th>
</tr>
</thead>
<tbody>
<% properties.forEach(function (p) {
var st = p.status || 'found';
var stColor = st === 'paid' ? '#7dd88a' : st === 'staged' ? '#e0b24a' : st === 'not_mine' ? 'var(--text-dim,#8a8a8a)' : 'inherit';
var addrParts = [];
if (p.address) addrParts.push(p.address);
var cityLine = [p.city, [p.state, p.zip].filter(Boolean).join(' ')].filter(Boolean).join(', ');
if (cityLine) addrParts.push(cityLine);
var foundIso = p.found_at ? String(p.found_at) : '';
var foundLabel = '';
if (p.found_at) {
try { foundLabel = new Date(p.found_at).toLocaleString(undefined, { year:'numeric', month:'short', day:'numeric', hour:'numeric', minute:'2-digit' }); }
catch (e) { foundLabel = foundIso; }
}
%>
<tr style="border-bottom:1px solid var(--border,#2a2a2a)">
<td style="padding:8px 10px;white-space:nowrap">
<a href="<%= claimitUrl %>" target="_blank" rel="noopener noreferrer" style="color:inherit;text-decoration:none;font-weight:600" title="Search this on claimit.ca.gov">
<%= p.amount_display || (p.amount_cents != null ? ('$' + (p.amount_cents / 100).toFixed(2)) : '—') %> ↗
</a>
</td>
<td style="padding:8px 10px">
<span title="<%= p.owner_name || '' %>"><%= p.holder_name || '—' %></span>
<% if (p.owner_name) { %><div class="subtle" style="font-size:11px;color:var(--text-dim)"><%= p.owner_name %><% if (p.co_owner) { %> · <%= p.co_owner %><% } %></div><% } %>
</td>
<td style="padding:8px 10px;color:var(--text-dim)">
<% if (addrParts.length) { %><%= addrParts.join(' · ') %><% } else { %>—<% } %>
</td>
<td style="padding:8px 10px"><%= p.property_type || '—' %></td>
<td style="padding:8px 10px;white-space:nowrap">
<a href="<%= claimitUrl %>" target="_blank" rel="noopener noreferrer" style="color:inherit;text-decoration:none" title="Search Property ID on claimit.ca.gov">
<%= p.property_id || '—' %> ↗
</a>
</td>
<td style="padding:8px 10px;white-space:nowrap">
<select class="ucp-status" data-id="<%= p.id %>" style="background:transparent;color:<%= stColor %>;border:1px solid var(--border,#3a3a3a);border-radius:6px;padding:4px 6px;font-size:12px">
<% statusOptions.forEach(function (opt) { %>
<option value="<%= opt %>"<%= st === opt ? ' selected' : '' %>><%= opt %></option>
<% }); %>
</select>
<span class="ucp-saved" style="display:none;font-size:11px;color:#7dd88a;margin-left:6px">saved ✓</span>
</td>
<td style="padding:8px 10px;white-space:nowrap;color:var(--text-dim)">
<% if (foundLabel) { %><span title="<%= foundIso %>">🕓 <%= foundLabel %></span><% } else { %>—<% } %>
</td>
</tr>
<% }); %>
</tbody>
</table>
</div>
</section>
<script>
// Inline per-row status update for tracked unclaimed-property records.
document.querySelectorAll('select.ucp-status').forEach(function (sel) {
sel.addEventListener('change', function () {
var id = sel.getAttribute('data-id');
var status = sel.value;
var saved = sel.parentNode.querySelector('.ucp-saved');
var colors = { paid: '#7dd88a', staged: '#e0b24a', not_mine: '#8a8a8a', filed: '', found: '' };
sel.disabled = true;
fetch('/api/unclaimed/' + encodeURIComponent(id) + '/status', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ status: status })
}).then(function (res) {
if (!res.ok) throw new Error('HTTP ' + res.status);
return res.json().catch(function () { return {}; });
}).then(function () {
sel.style.color = (colors[status] || 'inherit');
if (saved) {
saved.style.display = 'inline';
setTimeout(function () { saved.style.display = 'none'; }, 1400);
}
}).catch(function () {
if (saved) {
saved.textContent = 'failed';
saved.style.color = '#e07a7a';
saved.style.display = 'inline';
setTimeout(function () { saved.style.display = 'none'; saved.textContent = 'saved ✓'; saved.style.color = '#7dd88a'; }, 1800);
}
}).finally(function () {
sel.disabled = false;
});
});
});
</script>
<% } else if (typeof properties !== 'undefined') { %>
<p class="subtle" style="font-size:12px;color:var(--text-dim);margin:0 0 20px">No tracked properties yet.</p>
<% } %>
<% if (!claims.length) { %>
<section class="empty glass">
<p>No claims yet. Claims are created automatically when a reminder fires (returns window closing, warranty expiry, recall match).</p>
<a class="button" href="/import">Go to Import</a>
</section>
<% } else { %>
<section class="connector-grid">
<% claims.forEach(c => { %>
<a class="connector-card glass" href="/claims/<%= c.id %>" style="text-decoration:none;color:inherit;display:flex;flex-direction:column;gap:10px">
<header>
<span class="name">
<span class="icon"><%= c.routing[0].toUpperCase() %></span>
<%= c.draft_subject || (c.claim_type + ' — ' + c.routing) %>
</span>
<span class="status <%= c.state === 'sent' ? 'connected' : c.state === 'draft' ? 'syncing' : 'not_connected' %>">
<%= c.state %>
</span>
</header>
<p class="desc">
<strong><%= c.claim_type %></strong> →
<%= c.routing %>
<% if (c.due_at) { %> · due <%= new Date(c.due_at).toLocaleDateString() %><% } %>
</p>
<p class="subtle" style="font-size:11px;color:var(--text-dim)">created <%= new Date(c.created_at).toLocaleString() %></p>
</a>
<% }) %>
</section>
<% } %>
<script>
// Copy a household name to the clipboard so it can be pasted into claimit.ca.gov.
document.querySelectorAll('.chip[data-copy]').forEach(function (btn) {
btn.addEventListener('click', function () {
var name = btn.getAttribute('data-copy') || '';
var done = function () {
var prev = btn.textContent;
btn.textContent = 'Copied ✓';
setTimeout(function () { btn.textContent = prev; }, 1200);
};
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(name).then(done).catch(done);
} else {
var ta = document.createElement('textarea');
ta.value = name; document.body.appendChild(ta); ta.select();
try { document.execCommand('copy'); } catch (e) {}
document.body.removeChild(ta); done();
}
});
});
</script>
<%- include('partials/footer') %>