import { nteeDescription } from '@novelpad/outreach-core'; import { serverGetMatchDetail, serverSetMatchReview, } from '@novelpad/outreach-core/server'; import { Form, Link, redirect } from 'react-router'; import { db } from '#~/db.server.js'; import type { Route } from './+types/matches.$matchId.js'; export async function loader({ request, params }: Route.LoaderArgs) { if (request.method === 'HEAD') return; const detail = await serverGetMatchDetail(db, params.matchId); if (detail == null) { throw new Response('Match not found', { status: 404 }); } return { detail }; } export async function action({ request, params }: Route.ActionArgs) { if (request.method === 'HEAD') return; const formData = await request.formData(); const decision = formData.get('decision'); if (decision !== 'approved' && decision !== 'rejected') { throw new Response('Invalid review submission', { status: 400 }); } await serverSetMatchReview(db, { matchId: params.matchId, reviewStatus: decision, rejectReason: decision === 'rejected' ? 'other' : undefined, }); return redirect('/'); } function dollars(n: number | null): string { if (n == null) return '—'; return `$${n.toLocaleString('en-US')}`; } const SUBSCORE_MAX: Record = { missionFit: 30, funderPrecedent: 25, capacityFit: 15, competition: 15, effort: 10, runway: 5, }; export default function MatchDetail({ loaderData }: Route.ComponentProps) { const { detail } = loaderData ?? {}; if (detail == null) return null; const { match, org, grant, funderGivingHistory } = detail; const subscores = (match.subscores ?? {}) as Record; const rationale = (match.rationale ?? {}) as Record; const nhHistory = funderGivingHistory; return (

{org.name} ↔ {grant.funder}

Score {match.totalScore}/100 {match.easyWin ? ' · Easy win' : ''} {match.isHero ? ' · Hero' : ''} · Status: {match.reviewStatus}

Organization

Location:
{[org.city, org.state].filter(Boolean).join(', ')}
Focus (NTEE):
{org.nteeCode ?? '—'} {nteeDescription(org.nteeCode) != null && ` — ${nteeDescription(org.nteeCode)}`}
Annual revenue:
{dollars(org.totalRevenue)}
Mission (profile):
{org.missionStatement ?? '—'} {org.profileConfidence != null && org.profileConfidence <= 0.2 && ( {' '} (auto-generated stub — verify on their website) )}

Grant

Title:
{grant.title}
Award:
{dollars(grant.awardFloor)} – {dollars(grant.awardCeiling)}
Closes:
{grant.closeDate == null ? 'Rolling / no stated deadline' : new Date(grant.closeDate).toLocaleDateString('en-US')}
Source:
{grant.source}
{grant.eligibilityEntityTypes != null && grant.eligibilityEntityTypes.length > 0 && (
Eligibility:
{grant.eligibilityEntityTypes.join('; ')}
)}

Score breakdown

{Object.entries(SUBSCORE_MAX).map(([key, max]) => ( ))}
{key.replace(/([A-Z])/g, ' $1').toLowerCase()} {subscores[key] ?? 0} / {max}
{typeof rationale.similarity === 'number' && (

Embedding similarity: {(rationale.similarity as number).toFixed(3)} {Array.isArray(rationale.gateFailures) && (rationale.gateFailures as string[]).length > 0 && ` · Ignored gate flags: ${(rationale.gateFailures as string[]).join(', ')}`}

)}

Grant synopsis

{grant.synopsis ?? '—'}

{nhHistory.length > 0 && (

Funder giving history (from 990-PF filings)

The concrete evidence behind the precedent score — who this funder actually paid, sorted in-state first.

{nhHistory.map((g, i) => ( ))}
Recipient City Amount Year Purpose
{g.recipientName} {g.recipientCity ?? '—'} {dollars(g.amount)} {g.taxYear} {g.purpose ?? '—'}
)}
); }