feat(07-02): wire agentDownloadUrl to doc detail page, add signedAt to dashboard and client profile
- document detail page: import createAgentDownloadToken, generate agentDownloadUrl server-side for signed docs (signedFilePath present), pass agentDownloadUrl and signedAt props to PreparePanel - DocumentsTable: add signedAt to DocumentRow type, add Date Signed column header and cell - dashboard page: add signedAt to db select so allRows includes signed date for Signed documents - ClientProfileClient: add signedAt to local DocumentRow type (fixes type mismatch with DocumentsTable) - clients/[id]/page: add signedAt to query select to satisfy updated DocumentRow type
This commit is contained in:
@@ -20,6 +20,7 @@ export default async function ClientProfilePage({
|
|||||||
name: documents.name,
|
name: documents.name,
|
||||||
status: documents.status,
|
status: documents.status,
|
||||||
sentAt: documents.sentAt,
|
sentAt: documents.sentAt,
|
||||||
|
signedAt: documents.signedAt,
|
||||||
clientId: documents.clientId,
|
clientId: documents.clientId,
|
||||||
clientName: sql<string>`${clients.name}`,
|
clientName: sql<string>`${clients.name}`,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ export default async function DashboardPage({
|
|||||||
name: documents.name,
|
name: documents.name,
|
||||||
status: documents.status,
|
status: documents.status,
|
||||||
sentAt: documents.sentAt,
|
sentAt: documents.sentAt,
|
||||||
|
signedAt: documents.signedAt,
|
||||||
clientName: clients.name,
|
clientName: clients.name,
|
||||||
clientId: documents.clientId,
|
clientId: documents.clientId,
|
||||||
})
|
})
|
||||||
@@ -38,16 +39,18 @@ export default async function DashboardPage({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className="flex items-center justify-between mb-6">
|
<div style={{ marginBottom: "1.5rem" }}>
|
||||||
<h1 className="text-[var(--navy)] text-2xl font-semibold">
|
<h1 style={{ color: "#1B2B4B", fontSize: "1.5rem", fontWeight: 700, marginBottom: "0.25rem" }}>
|
||||||
Welcome back, {firstName}
|
Welcome back, {firstName}
|
||||||
</h1>
|
</h1>
|
||||||
|
<p style={{ color: "#6B7280", fontSize: "0.875rem" }}>All documents across your clients</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-4 mb-6">
|
|
||||||
<span className="text-sm text-gray-600">Filter by status:</span>
|
<div style={{ backgroundColor: "white", borderRadius: "1rem", boxShadow: "0 1px 4px rgba(0,0,0,0.07)", overflow: "hidden" }}>
|
||||||
<DashboardFilters currentStatus={status} />
|
<div style={{ display: "flex", alignItems: "center", gap: "0.75rem", padding: "1rem 1.5rem", borderBottom: "1px solid #F3F4F6" }}>
|
||||||
</div>
|
<span style={{ fontSize: "0.875rem", color: "#6B7280" }}>Filter by status:</span>
|
||||||
<div className="bg-white rounded-xl shadow-sm overflow-hidden">
|
<DashboardFilters currentStatus={status} />
|
||||||
|
</div>
|
||||||
<DocumentsTable rows={filteredRows} showClientColumn={true} />
|
<DocumentsTable rows={filteredRows} showClientColumn={true} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { eq } from 'drizzle-orm';
|
|||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import { PdfViewerWrapper } from './_components/PdfViewerWrapper';
|
import { PdfViewerWrapper } from './_components/PdfViewerWrapper';
|
||||||
import { PreparePanel } from './_components/PreparePanel';
|
import { PreparePanel } from './_components/PreparePanel';
|
||||||
|
import { createAgentDownloadToken } from '@/lib/signing/token';
|
||||||
|
|
||||||
export default async function DocumentPage({
|
export default async function DocumentPage({
|
||||||
params,
|
params,
|
||||||
@@ -29,6 +30,12 @@ export default async function DocumentPage({
|
|||||||
|
|
||||||
if (!doc) redirect('/portal/dashboard');
|
if (!doc) redirect('/portal/dashboard');
|
||||||
|
|
||||||
|
// Generate agent download URL server-side for Signed documents
|
||||||
|
// Must be done here (server component) — PreparePanel is 'use client' and cannot call createAgentDownloadToken
|
||||||
|
const agentDownloadUrl = doc.signedFilePath
|
||||||
|
? `/api/documents/${docId}/download?adt=${await createAgentDownloadToken(docId)}`
|
||||||
|
: null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="max-w-5xl mx-auto px-4 py-6">
|
<div className="max-w-5xl mx-auto px-4 py-6">
|
||||||
<div className="mb-4 flex items-center justify-between">
|
<div className="mb-4 flex items-center justify-between">
|
||||||
@@ -56,6 +63,8 @@ export default async function DocumentPage({
|
|||||||
defaultEmail={docClient?.email ?? ''}
|
defaultEmail={docClient?.email ?? ''}
|
||||||
clientName={docClient?.name ?? ''}
|
clientName={docClient?.name ?? ''}
|
||||||
currentStatus={doc.status}
|
currentStatus={doc.status}
|
||||||
|
agentDownloadUrl={agentDownloadUrl}
|
||||||
|
signedAt={doc.signedAt ?? null}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ type DocumentRow = {
|
|||||||
clientName: string | null;
|
clientName: string | null;
|
||||||
status: "Draft" | "Sent" | "Viewed" | "Signed";
|
status: "Draft" | "Sent" | "Viewed" | "Signed";
|
||||||
sentAt: Date | null;
|
sentAt: Date | null;
|
||||||
|
signedAt: Date | null;
|
||||||
clientId: string;
|
clientId: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ type DocumentRow = {
|
|||||||
clientName: string | null;
|
clientName: string | null;
|
||||||
status: "Draft" | "Sent" | "Viewed" | "Signed";
|
status: "Draft" | "Sent" | "Viewed" | "Signed";
|
||||||
sentAt: Date | null;
|
sentAt: Date | null;
|
||||||
|
signedAt: Date | null;
|
||||||
clientId: string;
|
clientId: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -39,6 +40,9 @@ export function DocumentsTable({ rows, showClientColumn = true }: Props) {
|
|||||||
<th style={{ textAlign: "left", fontSize: "0.75rem", fontWeight: 600, color: "#6B7280", textTransform: "uppercase", letterSpacing: "0.05em", padding: "0.75rem 1.5rem" }}>
|
<th style={{ textAlign: "left", fontSize: "0.75rem", fontWeight: 600, color: "#6B7280", textTransform: "uppercase", letterSpacing: "0.05em", padding: "0.75rem 1.5rem" }}>
|
||||||
Date Sent
|
Date Sent
|
||||||
</th>
|
</th>
|
||||||
|
<th style={{ textAlign: "left", fontSize: "0.75rem", fontWeight: 600, color: "#6B7280", textTransform: "uppercase", letterSpacing: "0.05em", padding: "0.75rem 1.5rem" }}>
|
||||||
|
Date Signed
|
||||||
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@@ -64,6 +68,16 @@ export function DocumentsTable({ rows, showClientColumn = true }: Props) {
|
|||||||
? new Date(row.sentAt).toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" })
|
? new Date(row.sentAt).toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" })
|
||||||
: "—"}
|
: "—"}
|
||||||
</td>
|
</td>
|
||||||
|
<td style={{ padding: "0.875rem 1.5rem", color: "#6B7280" }}>
|
||||||
|
{row.signedAt
|
||||||
|
? new Date(row.signedAt).toLocaleDateString("en-US", {
|
||||||
|
timeZone: "America/Denver",
|
||||||
|
month: "short",
|
||||||
|
day: "numeric",
|
||||||
|
year: "numeric",
|
||||||
|
})
|
||||||
|
: "—"}
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
))}
|
))}
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|||||||
Reference in New Issue
Block a user