← back to AbramsOS

routes/claims.js

82 lines

const express = require('express');
const db = require('../lib/db');
const audit = require('../lib/audit');
const strategist = require('../lib/claim-strategist');

const router = express.Router();
const DEV_USER_ID = 'user_steve';

// HTML — list view
router.get('/claims', async (_req, res) => {
  const r = await db.query(
    `SELECT id, claim_type, routing, state, draft_subject, due_at, created_at, asset_table, asset_id
       FROM claim_case WHERE user_id = $1 ORDER BY created_at DESC LIMIT 200`,
    [DEV_USER_ID]
  );
  // Household names to suggest against the CA unclaimed-property search.
  // Defensive: never let a missing/renamed table break the claims page.
  let household = [];
  try {
    const p = await db.query(
      `SELECT full_name FROM person WHERE user_id = $1 AND full_name IS NOT NULL ORDER BY (relation <> 'self'), full_name`,
      [DEV_USER_ID]
    );
    household = p.rows.map(x => x.full_name).filter(Boolean);
  } catch (_e) { household = []; }
  res.render('claims', { claims: r.rows, household });
});

// HTML — detail view
router.get('/claims/:id', async (req, res) => {
  const c = await db.query(`SELECT * FROM claim_case WHERE id = $1 AND user_id = $2`, [req.params.id, DEV_USER_ID]);
  if (!c.rows.length) return res.status(404).render('error', { error: 'claim not found' });
  const a = await db.query(`SELECT * FROM action_queue WHERE case_id = $1 ORDER BY created_at`, [req.params.id]);
  res.render('claim-detail', { claim: c.rows[0], actions: a.rows });
});

router.get('/api/claims', async (_req, res) => {
  const r = await db.query(
    `SELECT id, claim_type, routing, state, draft_subject, due_at, created_at, asset_table, asset_id
       FROM claim_case WHERE user_id = $1 ORDER BY created_at DESC LIMIT 200`,
    [DEV_USER_ID]
  );
  res.json(r.rows);
});

router.get('/api/claims/:id', async (req, res) => {
  const r = await db.query(`SELECT * FROM claim_case WHERE id = $1 AND user_id = $2`, [req.params.id, DEV_USER_ID]);
  if (!r.rows.length) return res.status(404).json({ error: 'claim not found' });
  const actions = await db.query(`SELECT * FROM action_queue WHERE case_id = $1 ORDER BY created_at`, [req.params.id]);
  res.json({ ...r.rows[0], actions: actions.rows });
});

router.post('/api/claims/from-reminder/:id', async (req, res) => {
  try {
    const { caseId, claim } = await strategist.fromReminder(req.params.id, DEV_USER_ID);
    res.json({ ok: true, case_id: caseId, claim });
  } catch (err) {
    res.status(400).json({ error: err.message });
  }
});

// Approve an action — but DON'T execute. Steve still has to physically click "send" elsewhere.
// This just flips the gate; sending happens in a future tick when we wire George email.
router.post('/api/claims/:caseId/actions/:actionId/approve', async (req, res) => {
  const { caseId, actionId } = req.params;
  await db.query(
    `UPDATE action_queue SET state = 'approved' WHERE id = $1 AND case_id = $2 AND state = 'pending'`,
    [actionId, caseId]
  );
  await audit.log({
    actorType: 'user',
    actorId: DEV_USER_ID,
    objectType: 'action_queue',
    objectId: actionId,
    eventType: 'action_approved',
    metadata: { case_id: caseId },
  });
  res.json({ ok: true });
});

module.exports = router;