feat(08-02): add type-branching guards to SigningPageClient
- Import getFieldType from @/lib/db/schema - handleFieldClick returns early for non-client-signature fields (defense-in-depth) - handleSubmit counts only client-signature fields for completeness check - SigningProgressBar total reflects client-signature count only - signatureFields added to handleFieldClick and handleSubmit dependency arrays
This commit is contained in:
@@ -8,6 +8,7 @@ import 'react-pdf/dist/Page/TextLayer.css';
|
|||||||
import { SigningProgressBar } from './SigningProgressBar';
|
import { SigningProgressBar } from './SigningProgressBar';
|
||||||
import { SignatureModal } from './SignatureModal';
|
import { SignatureModal } from './SignatureModal';
|
||||||
import type { SignatureFieldData } from '@/lib/db/schema';
|
import type { SignatureFieldData } from '@/lib/db/schema';
|
||||||
|
import { getFieldType } from '@/lib/db/schema';
|
||||||
|
|
||||||
// Worker setup — reuse same pattern as PdfViewerWrapper (no CDN, works in local/Docker)
|
// Worker setup — reuse same pattern as PdfViewerWrapper (no CDN, works in local/Docker)
|
||||||
pdfjs.GlobalWorkerOptions.workerSrc = new URL(
|
pdfjs.GlobalWorkerOptions.workerSrc = new URL(
|
||||||
@@ -84,11 +85,16 @@ export function SigningPageClient({
|
|||||||
|
|
||||||
const handleFieldClick = useCallback(
|
const handleFieldClick = useCallback(
|
||||||
(fieldId: string) => {
|
(fieldId: string) => {
|
||||||
|
const field = signatureFields.find((f) => f.id === fieldId);
|
||||||
|
if (!field) return;
|
||||||
|
// Defense-in-depth: primary protection is the server filter in GET /api/sign/[token]
|
||||||
|
// Only client-signature fields open the modal; Phase 10 will expand this for initials
|
||||||
|
if (getFieldType(field) !== 'client-signature') return;
|
||||||
if (signedFields.has(fieldId)) return;
|
if (signedFields.has(fieldId)) return;
|
||||||
setActiveFieldId(fieldId);
|
setActiveFieldId(fieldId);
|
||||||
setModalOpen(true);
|
setModalOpen(true);
|
||||||
},
|
},
|
||||||
[signedFields]
|
[signatureFields, signedFields]
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleModalConfirm = useCallback(
|
const handleModalConfirm = useCallback(
|
||||||
@@ -126,7 +132,10 @@ export function SigningPageClient({
|
|||||||
}, [signatureFields, signedFields]);
|
}, [signatureFields, signedFields]);
|
||||||
|
|
||||||
const handleSubmit = useCallback(async () => {
|
const handleSubmit = useCallback(async () => {
|
||||||
if (signedFields.size < signatureFields.length || submitting) return;
|
const clientSigFields = signatureFields.filter(
|
||||||
|
(f) => getFieldType(f) === 'client-signature'
|
||||||
|
);
|
||||||
|
if (signedFields.size < clientSigFields.length || submitting) return;
|
||||||
setSubmitting(true);
|
setSubmitting(true);
|
||||||
try {
|
try {
|
||||||
const res = await fetch(`/api/sign/${token}`, {
|
const res = await fetch(`/api/sign/${token}`, {
|
||||||
@@ -148,7 +157,7 @@ export function SigningPageClient({
|
|||||||
alert('Network error. Please check your connection and try again.');
|
alert('Network error. Please check your connection and try again.');
|
||||||
setSubmitting(false);
|
setSubmitting(false);
|
||||||
}
|
}
|
||||||
}, [signedFields.size, signatureFields.length, submitting, token]);
|
}, [signedFields.size, signatureFields, submitting, token]);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert PDF user-space coordinates (bottom-left origin) to screen overlay position.
|
* Convert PDF user-space coordinates (bottom-left origin) to screen overlay position.
|
||||||
@@ -325,7 +334,7 @@ export function SigningPageClient({
|
|||||||
|
|
||||||
{/* Sticky progress bar */}
|
{/* Sticky progress bar */}
|
||||||
<SigningProgressBar
|
<SigningProgressBar
|
||||||
total={signatureFields.length}
|
total={signatureFields.filter((f) => getFieldType(f) === 'client-signature').length}
|
||||||
signed={signedFields.size}
|
signed={signedFields.size}
|
||||||
onJumpToNext={handleJumpToNext}
|
onJumpToNext={handleJumpToNext}
|
||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
|
|||||||
Reference in New Issue
Block a user