← back to Hub

app/api/activity/route.ts

152 lines

import { NextRequest, NextResponse } from 'next/server';
import { verifyAuth } from '@/lib/auth';
import { query } from '@/lib/db';

export const dynamic = 'force-dynamic';

interface ActivityItem {
  id: string;
  app: string;
  type: string;
  title: string;
  description: string;
  created_at: string;
}

export async function GET(request: NextRequest) {
  const user = verifyAuth(request);
  if (!user) {
    return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
  }

  try {
    const [sdccDrafts, sdccCollabs, grantGrants, grantProposals, pattyPetitions, pattyCampaigns, freddyMatches, freddyContacts] = await Promise.all([
      // SDCC: latest drafts
      query('sdcc', `SELECT id, subject, status, lane, created_at FROM drafts ORDER BY created_at DESC LIMIT 5`),
      // SDCC: latest collaborations
      query('sdcc', `SELECT id, name, collab_type, status, created_at FROM collaborations ORDER BY created_at DESC LIMIT 5`),
      // Grant: latest grants
      query('grant', `SELECT id, title, funder, status, created_at FROM grants ORDER BY created_at DESC LIMIT 5`),
      // Grant: latest proposals
      query('grant', `SELECT id, subject, status, created_at FROM grant_proposals ORDER BY created_at DESC LIMIT 5`),
      // Patty: latest petitions
      query('patty', `SELECT id, title, status, signature_count, created_at FROM petitions ORDER BY created_at DESC LIMIT 5`),
      // Patty: latest campaigns
      query('patty', `SELECT id, subject, status, created_at FROM email_campaigns ORDER BY created_at DESC LIMIT 5`),
      // Freddy: latest matches
      query('freddy', `SELECT id, match_score, status, created_at FROM matches ORDER BY created_at DESC LIMIT 5`),
      // Freddy: latest contacts
      query('freddy', `SELECT id, name, contact_type, organization, created_at FROM contacts ORDER BY created_at DESC LIMIT 5`),
    ]);

    const items: ActivityItem[] = [];

    // SDCC drafts
    for (const row of sdccDrafts.rows) {
      items.push({
        id: `sdcc-draft-${row.id}`,
        app: 'sdcc',
        type: 'draft',
        title: row.subject,
        description: `${row.lane} draft - ${row.status}`,
        created_at: row.created_at,
      });
    }

    // SDCC collaborations
    for (const row of sdccCollabs.rows) {
      items.push({
        id: `sdcc-collab-${row.id}`,
        app: 'sdcc',
        type: 'collaboration',
        title: row.name,
        description: `${row.collab_type} - ${row.status}`,
        created_at: row.created_at,
      });
    }

    // Grant grants
    for (const row of grantGrants.rows) {
      items.push({
        id: `grant-grant-${row.id}`,
        app: 'grant',
        type: 'grant',
        title: row.title,
        description: `From ${row.funder} - ${row.status}`,
        created_at: row.created_at,
      });
    }

    // Grant proposals
    for (const row of grantProposals.rows) {
      items.push({
        id: `grant-proposal-${row.id}`,
        app: 'grant',
        type: 'proposal',
        title: row.subject,
        description: `Proposal - ${row.status}`,
        created_at: row.created_at,
      });
    }

    // Patty petitions
    for (const row of pattyPetitions.rows) {
      items.push({
        id: `patty-petition-${row.id}`,
        app: 'patty',
        type: 'petition',
        title: row.title,
        description: `${row.signature_count || 0} signatures - ${row.status}`,
        created_at: row.created_at,
      });
    }

    // Patty campaigns
    for (const row of pattyCampaigns.rows) {
      items.push({
        id: `patty-campaign-${row.id}`,
        app: 'patty',
        type: 'campaign',
        title: row.subject,
        description: `Email campaign - ${row.status}`,
        created_at: row.created_at,
      });
    }

    // Freddy matches
    for (const row of freddyMatches.rows) {
      items.push({
        id: `freddy-match-${row.id}`,
        app: 'freddy',
        type: 'match',
        title: `Match (score: ${(row.match_score * 100).toFixed(0)}%)`,
        description: `Cause-Org match - ${row.status}`,
        created_at: row.created_at,
      });
    }

    // Freddy contacts
    for (const row of freddyContacts.rows) {
      items.push({
        id: `freddy-contact-${row.id}`,
        app: 'freddy',
        type: 'contact',
        title: row.name,
        description: `${row.contact_type}${row.organization ? ' at ' + row.organization : ''}`,
        created_at: row.created_at,
      });
    }

    // Sort by created_at DESC and return top 20
    items.sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime());

    return NextResponse.json({ items: items.slice(0, 20) });
  } catch (err) {
    console.error('[activity] Error:', (err as Error).message);
    return NextResponse.json(
      { error: 'Failed to fetch activity data' },
      { status: 500 },
    );
  }
}