← back to Norma

app/api/scheduled/route.ts

77 lines

import { NextRequest, NextResponse } from 'next/server';
import { query } from '@/lib/db';
import { requireRole } from '@/lib/require-role';

/**
 * GET /api/scheduled
 * List scheduled dispatches. Supports filters:
 *   ?status=scheduled (default: all)
 *   ?platform=twitter
 *   ?from=2026-03-01T00:00:00Z
 *   ?to=2026-03-31T23:59:59Z
 *   ?limit=50
 */
export async function GET(request: NextRequest) {
  const auth = requireRole(request, 'admin', 'staff');
  if (auth instanceof NextResponse) return auth;

  try {
    const url = new URL(request.url);
    const status = url.searchParams.get('status');
    const platform = url.searchParams.get('platform');
    const from = url.searchParams.get('from');
    const to = url.searchParams.get('to');
    const limit = Math.min(parseInt(url.searchParams.get('limit') || '100', 10), 500);

    const conditions: string[] = [];
    const values: unknown[] = [];
    let idx = 1;

    if (status) {
      conditions.push(`sd.status = $${idx++}`);
      values.push(status);
    }
    if (platform) {
      conditions.push(`sd.platform = $${idx++}`);
      values.push(platform);
    }
    if (from) {
      conditions.push(`sd.scheduled_at >= $${idx++}`);
      values.push(from);
    }
    if (to) {
      conditions.push(`sd.scheduled_at <= $${idx++}`);
      values.push(to);
    }

    const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';

    const { rows } = await query(
      `SELECT sd.*,
              pp.status AS pipeline_status,
              pp.ai_confidence,
              pp.auto_generated
       FROM scheduled_dispatches sd
       LEFT JOIN petition_pipeline pp ON sd.pipeline_id = pp.id
       ${whereClause}
       ORDER BY sd.scheduled_at ASC
       LIMIT $${idx}`,
      [...values, limit],
    );

    // Summary counts
    const { rows: summary } = await query(
      `SELECT status, COUNT(*)::int AS count FROM scheduled_dispatches GROUP BY status`,
    );

    return NextResponse.json({
      items: rows,
      total: rows.length,
      summary: Object.fromEntries(summary.map(r => [r.status, r.count])),
    });
  } catch (err) {
    console.error('[api/scheduled] error:', (err as Error).message);
    return NextResponse.json({ error: 'Failed to list scheduled dispatches' }, { status: 500 });
  }
}