← back to Norma

app/api/globe/states/[code]/route.ts

78 lines

/**
 * GET /api/globe/states/[code]
 * Returns detailed data for a single US state.
 *
 * Response:
 *   { state, heat, orgs }
 */

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

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

  const { code } = await params;
  const stateCode = code.toUpperCase().trim();

  if (!/^[A-Z]{2}$/.test(stateCode)) {
    return NextResponse.json({ error: 'Invalid state code' }, { status: 400 });
  }

  try {
    // Fetch pulse heat data for this state
    let heat = null;
    await query(
      `SELECT
         state_code, state_name, heat_score,
         petition_count, article_count, org_count,
         avg_sentiment, top_topics
       FROM pulse_geo_heat
       WHERE state_code = $1
       LIMIT 1`,
      [stateCode],
    ).then(res => {
      if (res.rows.length > 0) {
        const r = res.rows[0];
        heat = {
          state: String(r.state_code),
          petition_count: Number(r.petition_count) || 0,
          article_count: Number(r.article_count) || 0,
          org_count: Number(r.org_count) || 0,
          avg_sentiment: r.avg_sentiment != null ? Number(r.avg_sentiment) : null,
          top_topics: Array.isArray(r.top_topics) ? r.top_topics : [],
        };
      }
    }).catch(() => { /* table may not exist */ });

    // Fetch organizations in this state
    const orgsResult = await query(
      `SELECT id, name, type, state
       FROM organizations
       WHERE UPPER(TRIM(state)) = $1
         AND (country IS NULL OR country IN ('US', 'USA', 'United States', ''))
       ORDER BY name ASC
       LIMIT 30`,
      [stateCode],
    ).catch(() => ({ rows: [] }));

    return NextResponse.json({
      state: stateCode,
      heat,
      orgs: orgsResult.rows.map(r => ({
        id: String(r.id),
        name: String(r.name),
        type: r.type ? String(r.type) : null,
      })),
    });
  } catch (err) {
    console.error('[api/globe/states/[code]] error:', (err as Error).message);
    return NextResponse.json({ error: 'Failed to fetch state detail' }, { status: 500 });
  }
}