← back to Norma

app/api/drafts/route.ts

97 lines

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

/**
 * GET /api/drafts
 * List drafts with optional filters:
 *   ?session_id= — filter by session
 *   ?lane=       — filter by lane (A, B, C)
 *   ?status=     — filter by status
 *   ?search=     — full-text search on subject
 *   ?limit=      — rows per page (default 50, max 200)
 *   ?offset=     — pagination offset (default 0)
 * Ordered by created_at DESC.
 */
export async function GET(request: NextRequest) {
  const auth = requireRole(request, 'admin', 'staff');
  if (auth instanceof NextResponse) return auth;

  try {
    const { searchParams } = new URL(request.url);
    const sessionId = searchParams.get('session_id');
    const lane = searchParams.get('lane');
    const status = searchParams.get('status');
    const search = searchParams.get('search');

    let limit = parseInt(searchParams.get('limit') || '50', 10);
    if (isNaN(limit) || limit < 1) limit = 50;
    if (limit > 200) limit = 200;

    let offset = parseInt(searchParams.get('offset') || '0', 10);
    if (isNaN(offset) || offset < 0) offset = 0;

    const orgId = auth.role === 'admin' ? getOrgId(request) : auth.orgId;

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

    if (orgId) {
      conditions.push(`d.org_id = $${paramIndex}`);
      values.push(orgId);
      paramIndex++;
    }

    if (sessionId) {
      conditions.push(`d.session_id = $${paramIndex}`);
      values.push(sessionId);
      paramIndex++;
    }

    if (lane) {
      conditions.push(`d.lane = $${paramIndex}`);
      values.push(lane.toUpperCase());
      paramIndex++;
    }

    if (status) {
      conditions.push(`d.status = $${paramIndex}`);
      values.push(status);
      paramIndex++;
    }

    if (search) {
      conditions.push(`d.subject ILIKE $${paramIndex}`);
      values.push(`%${search}%`);
      paramIndex++;
    }

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

    const countResult = await query(
      `SELECT COUNT(*)::int AS total FROM drafts d ${whereClause}`,
      values
    );
    const total = countResult.rows[0]?.total ?? 0;

    const result = await query(
      `SELECT d.*,
              s.title AS session_title,
              s.session_date
       FROM drafts d
       LEFT JOIN sessions s ON s.id = d.session_id
       ${whereClause}
       ORDER BY d.created_at DESC
       LIMIT $${paramIndex} OFFSET $${paramIndex + 1}`,
      [...values, limit, offset]
    );

    return NextResponse.json({ drafts: result.rows, total, limit, offset });
  } catch (err) {
    console.error('[api/drafts] GET error:', (err as Error).message);
    return NextResponse.json({ error: 'Failed to fetch drafts' }, { status: 500 });
  }
}