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 { SignatureModal } from './SignatureModal';
|
||||
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)
|
||||
pdfjs.GlobalWorkerOptions.workerSrc = new URL(
|
||||
@@ -84,11 +85,16 @@ export function SigningPageClient({
|
||||
|
||||
const handleFieldClick = useCallback(
|
||||
(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;
|
||||
setActiveFieldId(fieldId);
|
||||
setModalOpen(true);
|
||||
},
|
||||
[signedFields]
|
||||
[signatureFields, signedFields]
|
||||
);
|
||||
|
||||
const handleModalConfirm = useCallback(
|
||||
@@ -126,7 +132,10 @@ export function SigningPageClient({
|
||||
}, [signatureFields, signedFields]);
|
||||
|
||||
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);
|
||||
try {
|
||||
const res = await fetch(`/api/sign/${token}`, {
|
||||
@@ -148,7 +157,7 @@ export function SigningPageClient({
|
||||
alert('Network error. Please check your connection and try again.');
|
||||
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.
|
||||
@@ -325,7 +334,7 @@ export function SigningPageClient({
|
||||
|
||||
{/* Sticky progress bar */}
|
||||
<SigningProgressBar
|
||||
total={signatureFields.length}
|
||||
total={signatureFields.filter((f) => getFieldType(f) === 'client-signature').length}
|
||||
signed={signedFields.size}
|
||||
onJumpToNext={handleJumpToNext}
|
||||
onSubmit={handleSubmit}
|
||||
|
||||
Reference in New Issue
Block a user