Co-authored-by: renee-png <262607627+renee-png@users.noreply.github.com>
This commit is contained in:
gpt-engineer-app[bot]
2026-04-24 03:33:29 +00:00
co-authored by renee-png
parent 66194febdf
commit aff994bd05
+147
View File
@@ -0,0 +1,147 @@
// Server-side helper that loads all the lookup data needed for matching and
// runs `matchEmailToCases` against an array of incoming_emails rows. Updates
// each row in place with the resulting status, case_id, suggestions, etc.
import { supabaseAdmin } from "@/integrations/supabase/client.server";
import {
matchEmailToCases,
type CaseLookup,
type ContactCaseLink,
type ClientCaseLink,
type HomeownerCaseLink,
type EmailLike,
type PriorEmail,
} from "@/lib/email-matching";
interface IncomingEmailRow extends EmailLike {
id: string;
}
async function loadLookups() {
const [casesRes, contactsRes, clientsRes, homeownersRes, priorRes] =
await Promise.all([
supabaseAdmin
.from("cases")
.select(
"id, case_number, court_case_number, case_caption, title, client_id, opposing_counsel_email, status, updated_at",
)
.is("archived_at", null),
supabaseAdmin
.from("case_contacts")
.select("case_id, contact_id, contact:contacts(email)"),
supabaseAdmin
.from("clients")
.select("id, primary_contact_email")
.is("archived_at", null),
supabaseAdmin
.from("homeowners")
.select("id, email, client_id")
.is("archived_at", null),
supabaseAdmin
.from("incoming_emails")
.select("message_id, case_id")
.not("case_id", "is", null)
.not("message_id", "is", null)
.limit(5000),
]);
const cases: CaseLookup[] = (casesRes.data ?? []) as any;
const contactLinks: ContactCaseLink[] = ((contactsRes.data ?? []) as any[])
.map((row: any) => ({
case_id: row.case_id,
contact_id: row.contact_id,
email: row.contact?.email ?? null,
}))
.filter((r) => r.email);
// Build case_ids per client/homeowner
const casesByClient = new Map<string, string[]>();
const clientByCases = new Map<string, string | null>();
for (const c of cases) {
clientByCases.set(c.id, c.client_id);
if (c.client_id) {
const arr = casesByClient.get(c.client_id) ?? [];
arr.push(c.id);
casesByClient.set(c.client_id, arr);
}
}
const clientLinks: ClientCaseLink[] = ((clientsRes.data ?? []) as any[])
.filter((r) => r.primary_contact_email)
.map((r) => ({
client_id: r.id,
primary_contact_email: r.primary_contact_email,
case_ids: casesByClient.get(r.id) ?? [],
}))
.filter((r) => r.case_ids.length > 0);
const homeownerLinks: HomeownerCaseLink[] = ((homeownersRes.data ?? []) as any[])
.filter((r) => r.email && r.client_id)
.map((r) => ({
homeowner_id: r.id,
email: r.email,
case_ids: casesByClient.get(r.client_id) ?? [],
}))
.filter((r) => r.case_ids.length > 0);
const priorEmails: PriorEmail[] = (priorRes.data ?? []) as any;
return { cases, contactLinks, clientLinks, homeownerLinks, priorEmails };
}
export async function matchAndUpdateEmails(emailIds: string[]): Promise<{
matched: number;
suggested: number;
unmatched: number;
}> {
if (emailIds.length === 0) return { matched: 0, suggested: 0, unmatched: 0 };
const { data: rowsRaw, error } = await supabaseAdmin
.from("incoming_emails")
.select(
"id, message_id, in_reply_to, email_references, from_address, to_addresses, cc_addresses, subject, body_text",
)
.in("id", emailIds);
if (error) throw new Error(`Failed to load emails for matching: ${error.message}`);
const rows = (rowsRaw ?? []) as IncomingEmailRow[];
if (rows.length === 0) return { matched: 0, suggested: 0, unmatched: 0 };
const lookups = await loadLookups();
let matched = 0,
suggested = 0,
unmatched = 0;
for (const row of rows) {
const result = matchEmailToCases(
row,
lookups.cases,
lookups.contactLinks,
lookups.clientLinks,
lookups.homeownerLinks,
lookups.priorEmails,
);
const update: Record<string, unknown> = {
match_status: result.status,
match_suggestions: result.suggestions,
match_reason: result.reason,
};
if (result.status === "matched" && result.case_id) {
update.case_id = result.case_id;
update.matched_at = new Date().toISOString();
matched++;
} else if (result.status === "suggested") {
suggested++;
} else {
unmatched++;
}
await supabaseAdmin.from("incoming_emails").update(update).eq("id", row.id);
}
return { matched, suggested, unmatched };
}