← back to Marketing Command Center

modules/calendars/index.js

40 lines

// All Calendars — unified multi-layer calendar (activation SKUs + marketing dates
// + campaigns + optional Google), with a left-panel field-filter rail. Self-
// contained per the MODULE CONTRACT. Reads dw_unified (READ-only) via ./lib.js;
// fail-soft to mock mode if Postgres is unreachable (never crashes the shell).
const lib = require('./lib');

module.exports = {
  id: 'calendars',
  title: 'All Calendars',
  icon: '📆',

  mount(router) {
    // GET /events — the whole unified feed (front-end holds it, filters + renders
    // per month client-side). ?fresh=1 forces a re-projection from live dw_unified.
    router.get('/events', async (req, res) => {
      try {
        const data = await lib.buildEvents(req.query.fresh === '1');
        res.json(data);
      } catch (e) {
        res.status(200).json({ mock: true, error: e.message, items: [], counts: {}, window: {} });
      }
    });

    // GET /refresh — force re-projection of the activation snapshot.
    router.get('/refresh', async (_req, res) => {
      try { const data = await lib.buildEvents(true); res.json({ ok: true, generated_at: data.generated_at, counts: data.counts, mock: data.mock }); }
      catch (e) { res.status(200).json({ ok: false, error: e.message }); }
    });

    // POST /move — drag reschedule. { key, to_date:'YYYY-MM-DD', layer }
    // activation → override file (survives regenerate); campaign → schedule store.
    // Marketing holidays + Google events are read-only (not draggable).
    router.post('/move', (req, res) => {
      const r = lib.applyMove(req.body || {});
      if (!r.ok) return res.status(400).json(r);
      res.json(r);
    });
  },
};