← back to Norma

app/api/onboard/[id]/route.ts

131 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/onboard/[id] ────────────────────────────────────────────────────

export async function GET(
  request: NextRequest,
  { params }: { params: Promise<{ id: string }> },
) {
  const auth = requireRole(request, 'admin', 'staff');
  if (auth instanceof NextResponse) return auth;

  const { id } = await params;
  if (!id) {
    return NextResponse.json({ error: 'Missing id' }, { status: 400 });
  }
  const orgId = auth.role === 'admin' ? getOrgId(request) : auth.orgId;

  try {
    const orgFilter = orgId ? ' AND od.org_id = $2' : '';
    const { rows } = await query<Record<string, unknown>>(
      `SELECT
         od.*,
         o.name AS org_full_name,
         o.mission,
         o.website,
         o.email,
         o.phone,
         o.founded_year,
         o.employee_count,
         o.ntee_code AS org_ntee_code,
         o.state AS org_state,
         o.city,
         o.ein
       FROM onboard_discoveries od
       LEFT JOIN organizations o ON o.id = od.org_id
       WHERE od.id = $1${orgFilter}
       LIMIT 1`,
      orgId ? [id, orgId] : [id],
    );

    if (rows.length === 0) {
      return NextResponse.json({ error: 'Not found' }, { status: 404 });
    }

    return NextResponse.json({ item: rows[0] });
  } catch (err: unknown) {
    console.error('[api/onboard/[id] GET] Error:', (err as Error).message);
    return NextResponse.json({ error: (err as Error).message }, { status: 500 });
  }
}

// ─── PUT /api/onboard/[id] — update status / notes ───────────────────────────

export async function PUT(
  request: NextRequest,
  { params }: { params: Promise<{ id: string }> },
) {
  const auth = requireRole(request, 'admin', 'staff');
  if (auth instanceof NextResponse) return auth;

  const { id } = await params;
  if (!id) {
    return NextResponse.json({ error: 'Missing id' }, { status: 400 });
  }

  try {
    const body = (await request.json()) as {
      status?: string;
      notes?: string;
      contacted_at?: string;
    };
    const { status, notes, contacted_at } = body;

    const VALID_STATUSES = ['discovered', 'contacted', 'onboarded', 'rejected'];
    if (status && !VALID_STATUSES.includes(status)) {
      return NextResponse.json(
        { error: `Invalid status. Must be one of: ${VALID_STATUSES.join(', ')}` },
        { status: 400 },
      );
    }

    // Build dynamic SET clause
    const setClauses: string[] = ['updated_at = NOW()'];
    const queryParams: unknown[] = [];

    if (status !== undefined) {
      queryParams.push(status);
      setClauses.push(`status = $${queryParams.length}`);

      // Auto-set contacted_at when status changes to 'contacted'
      if (status === 'contacted' && !contacted_at) {
        setClauses.push(`contacted_at = NOW()`);
      }
    }
    if (notes !== undefined) {
      queryParams.push(notes);
      setClauses.push(`notes = $${queryParams.length}`);
    }
    if (contacted_at !== undefined) {
      queryParams.push(contacted_at);
      setClauses.push(`contacted_at = $${queryParams.length}`);
    }

    queryParams.push(id);
    const idIdx = queryParams.length;
    const orgId = auth.role === 'admin' ? getOrgId(request) : auth.orgId;
    let orgFilter = '';
    if (orgId) {
      queryParams.push(orgId);
      orgFilter = ` AND org_id = $${queryParams.length}`;
    }

    const { rowCount } = await query(
      `UPDATE onboard_discoveries SET ${setClauses.join(', ')} WHERE id = $${idIdx}${orgFilter}`,
      queryParams,
    );

    if ((rowCount ?? 0) === 0) {
      return NextResponse.json({ error: 'Not found' }, { status: 404 });
    }

    return NextResponse.json({ success: true, id, status, notes });
  } catch (err: unknown) {
    console.error('[api/onboard/[id] PUT] Error:', (err as Error).message);
    return NextResponse.json({ error: (err as Error).message }, { status: 500 });
  }
}