feat(16-04): enrich dashboard rows with signedCount, totalSigners, hasMultipleSigners

- Import signingTokens and sql from drizzle-orm
- Add documents.signers to main select
- Fetch token counts per document in single grouped query (avoids N+1)
- Build tokenMap for O(1) lookup per row
- Produce enrichedRows with signedCount, totalSigners, hasMultipleSigners fields
- Pass enrichedRows to DocumentsTable instead of filteredRows
This commit is contained in:
Chandler Copeland
2026-04-03 16:29:17 -06:00
parent 377133074b
commit ad4e27af42

View File

@@ -1,7 +1,7 @@
import { auth } from "@/lib/auth"; import { auth } from "@/lib/auth";
import { db } from "@/lib/db"; import { db } from "@/lib/db";
import { documents, clients } from "@/lib/db/schema"; import { documents, clients, signingTokens } from "@/lib/db/schema";
import { eq, desc } from "drizzle-orm"; import { eq, desc, sql } from "drizzle-orm";
import { DocumentsTable } from "../../_components/DocumentsTable"; import { DocumentsTable } from "../../_components/DocumentsTable";
import { DashboardFilters } from "../../_components/DashboardFilters"; import { DashboardFilters } from "../../_components/DashboardFilters";
@@ -25,16 +25,44 @@ export default async function DashboardPage({
signedAt: documents.signedAt, signedAt: documents.signedAt,
clientName: clients.name, clientName: clients.name,
clientId: documents.clientId, clientId: documents.clientId,
signers: documents.signers,
}) })
.from(documents) .from(documents)
.leftJoin(clients, eq(documents.clientId, clients.id)) .leftJoin(clients, eq(documents.clientId, clients.id))
.orderBy(desc(documents.createdAt)); .orderBy(desc(documents.createdAt));
// Fetch signing token counts per document in one query (avoids N+1)
const tokenCounts = await db
.select({
documentId: signingTokens.documentId,
total: sql<number>`count(*)`.as("total"),
signed: sql<number>`count(${signingTokens.usedAt})`.as("signed"),
})
.from(signingTokens)
.groupBy(signingTokens.documentId);
const tokenMap = new Map(
tokenCounts.map((t) => [
t.documentId,
{ total: Number(t.total), signed: Number(t.signed) },
])
);
const filteredRows = const filteredRows =
status && (VALID_STATUSES as readonly string[]).includes(status) status && (VALID_STATUSES as readonly string[]).includes(status)
? allRows.filter((r) => r.status === (status as ValidStatus)) ? allRows.filter((r) => r.status === (status as ValidStatus))
: allRows; : allRows;
const enrichedRows = filteredRows.map((row) => {
const tc = tokenMap.get(row.id);
return {
...row,
signedCount: tc?.signed ?? null,
totalSigners: tc?.total ?? null,
hasMultipleSigners: Array.isArray(row.signers) && row.signers.length > 0,
};
});
const firstName = session?.user?.email?.split("@")[0] ?? "Agent"; const firstName = session?.user?.email?.split("@")[0] ?? "Agent";
return ( return (
@@ -51,7 +79,7 @@ export default async function DashboardPage({
<span style={{ fontSize: "0.875rem", color: "#6B7280" }}>Filter by status:</span> <span style={{ fontSize: "0.875rem", color: "#6B7280" }}>Filter by status:</span>
<DashboardFilters currentStatus={status} /> <DashboardFilters currentStatus={status} />
</div> </div>
<DocumentsTable rows={filteredRows} showClientColumn={true} /> <DocumentsTable rows={enrichedRows} showClientColumn={true} />
</div> </div>
</div> </div>
); );