← back to Butlr
routes/scheduled.js
81 lines
// routes/scheduled.js — scheduling + calendar endpoints
const express = require('express');
const router = express.Router();
const scheduling = require('../lib/scheduling');
const data = require('../lib/data');
// requireUser middleware — same gate as routes/admin.js uses
function requireUser(req, res, next) {
if (!req.user) return res.status(401).json({ ok: false, error: 'login required' });
next();
}
// GET /api/scheduled — list current user's scheduled calls
router.get('/api/scheduled', requireUser, (req, res) => {
const opts = {};
if (req.query.status) opts.status = String(req.query.status);
if (req.query.from) opts.from = String(req.query.from);
if (req.query.to) opts.to = String(req.query.to);
const rows = scheduling.listScheduled(req.user.id, opts);
res.json({ ok: true, count: rows.length, rows });
});
// POST /api/scheduled — schedule a new call (one-shot OR recurring)
router.post('/api/scheduled', requireUser, express.json({ limit: '8kb' }), (req, res) => {
try {
const b = req.body || {};
const row = scheduling.addScheduled({
user_id: req.user.id,
business_name: b.business_name,
business_phone: b.business_phone,
goal: b.goal,
callback_phone: b.callback_phone,
callback_name: b.callback_name,
schedule_at: b.schedule_at,
cron_expr: b.cron_expr,
category: b.category,
max_hold_minutes: b.max_hold_minutes,
max_spend_cents: b.max_spend_cents,
consent_recording: b.consent_recording,
});
res.json({ ok: true, scheduled: row });
} catch (e) {
res.status(400).json({ ok: false, error: e.message });
}
});
// DELETE /api/scheduled/:id — cancel
router.delete('/api/scheduled/:id', requireUser, (req, res) => {
const ok = scheduling.cancelScheduled(req.params.id, req.user.id);
if (!ok) return res.status(404).json({ ok: false, error: 'not found' });
res.json({ ok: true });
});
// GET /calendar — month view with scheduled + past calls
router.get('/calendar', (req, res) => {
if (!req.user) return res.redirect('/login?return=/calendar');
const year = parseInt(req.query.year || new Date().getFullYear(), 10);
const month = parseInt(req.query.month || (new Date().getMonth() + 1), 10);
// Fetch scheduled rows that intersect this month + past calls fired this month
const monthStart = new Date(year, month - 1, 1);
const monthEnd = new Date(year, month, 1);
const scheduled = scheduling.listScheduled(req.user.id).filter(r => {
const t = new Date(r.next_fire_at || r.last_fire_at || 0);
return t >= monthStart && t < monthEnd;
});
const pastCalls = data.getCalls(req.user.id).filter(c => {
const t = new Date(c.created_at);
return t >= monthStart && t < monthEnd;
});
res.render('public/calendar', {
title: 'Calendar — Butlr',
meta_desc: 'See scheduled + past calls on a calendar.',
year, month,
scheduled, pastCalls,
});
});
module.exports = router;