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:
@@ -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>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user