import { serverListPendingReviewMatches, serverSetMatchReview, } from '@novelpad/outreach-core/server'; import { Form, Link } from 'react-router'; import { db } from '#~/db.server.js'; import type { Route } from './+types/_index.js'; export async function loader({ request }: Route.LoaderArgs) { if (request.method === 'HEAD') return; const url = new URL(request.url); const source = url.searchParams.get('source') ?? undefined; const statusParam = url.searchParams.get('status'); const status = statusParam === 'approved' || statusParam === 'rejected' ? statusParam : 'pending'; const matches = await serverListPendingReviewMatches(db, { source, status }); return { matches, source: source ?? null, status }; } export async function action({ request }: Route.ActionArgs) { if (request.method === 'HEAD') return; const formData = await request.formData(); const matchId = String(formData.get('matchId') ?? ''); const decision = formData.get('decision'); if (!matchId || (decision !== 'approved' && decision !== 'rejected')) { throw new Response('Invalid review submission', { status: 400 }); } await serverSetMatchReview(db, { matchId, reviewStatus: decision, rejectReason: decision === 'rejected' ? 'other' : undefined, }); return { ok: true as const }; } export default function ReviewQueue({ loaderData }: Route.ComponentProps) { const matches = loaderData?.matches ?? []; const activeSource = loaderData?.source ?? null; const activeStatus = loaderData?.status ?? 'pending'; const withParams = (overrides: Record) => { const params = new URLSearchParams(); const merged = { source: activeSource, status: activeStatus, ...overrides }; if (merged.source != null) params.set('source', merged.source); if (merged.status != null && merged.status !== 'pending') params.set('status', merged.status); const qs = params.toString(); return qs === '' ? '/' : `/?${qs}`; }; return (

Grant Match Review Queue

{matches.length === 0 ? (

No pending matches to review.

) : ( {matches.map((match) => ( ))}
Organization Grant Source Score Easy Win Actions
{match.orgName} {match.grantTitle} {match.source === 'irs_990pf' ? 'foundation' : match.source} {match.totalScore} {match.easyWin ? 'Yes' : 'No'}
)}
); }