← back to AbramsOS

routes/people.js

76 lines

// Household — people (self, spouse, dependents) whose records AbramsOS tracks.
const express = require('express');
const db = require('../lib/db');
const audit = require('../lib/audit');
const { id } = require('../lib/ids');

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

const RELATIONS = ['self', 'spouse', 'partner', 'child', 'dependent', 'parent', 'other'];

async function listPeople(userId) {
  const r = await db.query(
    `SELECT p.*,
            (SELECT count(*)::int FROM medication m WHERE m.person_id = p.id AND m.is_active) AS med_count
       FROM person p WHERE p.user_id = $1
      ORDER BY (relation <> 'self'), full_name ASC`,
    [userId]
  );
  return r.rows;
}

router.get('/household', async (_req, res) => {
  res.render('household', { people: await listPeople(DEV_USER_ID), relations: RELATIONS });
});

router.get('/api/people', async (_req, res) => {
  res.json(await listPeople(DEV_USER_ID));
});

router.post('/api/people', async (req, res) => {
  try {
    const b = req.body || {};
    if (!b.full_name) return res.status(400).json({ error: 'full_name required' });
    const pid = id('person');
    await db.query(
      `INSERT INTO person (id, user_id, relation, full_name, nickname, dob, phone, email, notes)
       VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9)`,
      [pid, DEV_USER_ID, RELATIONS.includes(b.relation) ? b.relation : 'other', b.full_name,
       b.nickname || null, b.dob || null, b.phone || null, b.email || null, b.notes || null]
    );
    await audit.log({ actorType: 'user', actorId: DEV_USER_ID, objectType: 'person', objectId: pid, eventType: 'person_created', metadata: { relation: b.relation } });
    const r = await db.query(`SELECT * FROM person WHERE id = $1`, [pid]);
    res.status(201).json(r.rows[0]);
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});

router.post('/api/people/:id', async (req, res) => {
  try {
    const b = req.body || {};
    const fields = ['relation', 'full_name', 'nickname', 'dob', 'phone', 'email', 'notes'];
    const sets = [], vals = [];
    let i = 1;
    for (const f of fields) { if (b[f] === undefined) continue; sets.push(`${f} = $${i++}`); vals.push(b[f] === '' ? null : b[f]); }
    if (!sets.length) return res.status(400).json({ error: 'no fields to update' });
    sets.push(`updated_at = now()`);
    vals.push(req.params.id, DEV_USER_ID);
    const r = await db.query(`UPDATE person SET ${sets.join(', ')} WHERE id = $${i++} AND user_id = $${i} RETURNING *`, vals);
    if (!r.rows.length) return res.status(404).json({ error: 'not found' });
    await audit.log({ actorType: 'user', actorId: DEV_USER_ID, objectType: 'person', objectId: req.params.id, eventType: 'person_updated' });
    res.json(r.rows[0]);
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});

router.post('/api/people/:id/delete', async (req, res) => {
  await db.query(`DELETE FROM person WHERE id = $1 AND user_id = $2`, [req.params.id, DEV_USER_ID]);
  await audit.log({ actorType: 'user', actorId: DEV_USER_ID, objectType: 'person', objectId: req.params.id, eventType: 'person_deleted' });
  res.json({ ok: true });
});

module.exports = router;