);
}
```
**B. Wire "Add Document" button into the existing client profile page**
Read `src/app/portal/clients/[id]/page.tsx` first to understand the current structure (Phase 3 built this). Then:
- Add a state-controlled "Add Document" button near the top of the documents section (or the page header)
- The button triggers a `showModal` state that renders ` setShowModal(false)} />`
- Since the profile page is likely a server component with a `ClientProfileClient` sub-component (per Phase 3 pattern), add the modal trigger and state inside the existing client component — do NOT convert the server page to a client component. Add the button and modal inside `_components/ClientProfileClient.tsx` or the equivalent client sub-component.
**C. Create PdfViewer.tsx**
`src/app/portal/documents/[docId]/_components/PdfViewer.tsx`:
```typescript
'use client';
import { useState } from 'react';
import { Document, Page, pdfjs } from 'react-pdf';
import 'react-pdf/dist/Page/AnnotationLayer.css';
import 'react-pdf/dist/Page/TextLayer.css';
// Worker setup — must use import.meta.url for local/Docker environments (no CDN)
pdfjs.GlobalWorkerOptions.workerSrc = new URL(
'pdfjs-dist/build/pdf.worker.min.mjs',
import.meta.url,
).toString();
export function PdfViewer({ docId }: { docId: string }) {
const [numPages, setNumPages] = useState(0);
const [pageNumber, setPageNumber] = useState(1);
const [scale, setScale] = useState(1.0);
return (
);
}
```
**D. Create document detail page**
`src/app/portal/documents/[docId]/page.tsx`:
```typescript
import { auth } from '@/lib/auth';
import { redirect } from 'next/navigation';
import { db } from '@/lib/db';
import { documents, clients } from '@/lib/db/schema';
import { eq } from 'drizzle-orm';
import Link from 'next/link';
import { PdfViewer } from './_components/PdfViewer';
export default async function DocumentPage({
params,
}: {
params: Promise<{ docId: string }>;
}) {
const session = await auth();
if (!session) redirect('/login');
const { docId } = await params;
const doc = await db.query.documents.findFirst({
where: eq(documents.id, docId),
with: { client: true },
});
if (!doc) redirect('/portal/dashboard');
return (
← Back to {doc.client?.name ?? 'Client'}
{doc.name}
{doc.client?.name}
);
}
```
NOTE: The `with: { client: true }` relation requires that the Drizzle relations are defined in schema.ts. If Phase 3 already defined client/documents relations, use those. If not, add the minimal relation:
```typescript
// In schema.ts, add after table definitions:
import { relations } from 'drizzle-orm';
export const documentsRelations = relations(documents, ({ one }) => ({
client: one(clients, { fields: [documents.clientId], references: [clients.id] }),
}));
```
If relations already exist in schema.ts (check the existing file), extend them rather than overwriting.
Also ensure that clicking a document name in the client profile's documents table navigates to `/portal/documents/{doc.id}` — read the existing DocumentsTable component from Phase 3 and add the link if not present.
```bash
cd /Users/ccopeland/temp/red/teressa-copeland-homes && npm run build 2>&1 | grep -E "error|Error|compiled" | head -20
```
Expected: "compiled successfully" or "Compiled" with no errors referencing react-pdf, PdfViewer, or AddDocumentModal.
- Client profile page has "Add Document" button that opens the modal.
- Modal shows searchable template list and file picker fallback.
- Submitting the modal creates a document and refreshes the documents list.
- Document name in client profile links to `/portal/documents/{id}`.
- Document detail page renders PdfViewer with page nav, zoom, and download controls.
- Build passes with no errors.
- `npm run build` completes without errors
- AddDocumentModal imports from react-pdf DO NOT include CDN worker URLs
- Both CSS layers imported in PdfViewer: AnnotationLayer.css and TextLayer.css
- Document detail page uses `await params` (Next.js 15 pattern)
- PdfViewer uses `new URL('pdfjs-dist/build/pdf.worker.min.mjs', import.meta.url)` for worker — not a CDN URL
Agent can open the forms library modal, add a document from the library or via file picker, see it appear in the documents list, click it to navigate to the detail page, and see the PDF rendered in the browser with page navigation and zoom.