- Refactored signature saving process

This commit is contained in:
Reece 2025-10-07 21:52:40 +01:00
parent 991be9ffa2
commit f6290c0238
5 changed files with 94 additions and 35 deletions

View File

@ -10,6 +10,7 @@ import { useFileState, useFileContext } from '../../../contexts/FileContext';
import { generateThumbnailWithMetadata } from '../../../utils/thumbnailUtils';
import { createProcessedFile } from '../../../contexts/file/fileActions';
import { createStirlingFile, createNewStirlingFileStub } from '../../../types/fileContext';
import { useNavigationState } from '../../../contexts/NavigationContext';
interface ViewerAnnotationControlsProps {
currentView: string;
@ -32,6 +33,10 @@ export default function ViewerAnnotationControls({ currentView }: ViewerAnnotati
const { actions: fileActions } = useFileContext();
const activeFiles = selectors.getFiles();
// Check if we're in sign mode
const { selectedTool } = useNavigationState();
const isSignMode = selectedTool === 'sign';
// Turn off annotation mode when switching away from viewer
useEffect(() => {
if (currentView !== 'viewer' && viewerContext?.isAnnotationMode) {
@ -39,6 +44,11 @@ export default function ViewerAnnotationControls({ currentView }: ViewerAnnotati
}
}, [currentView, viewerContext]);
// Don't show any annotation controls in sign mode
if (isSignMode) {
return null;
}
return (
<>
{/* Annotation Visibility Toggle */}

View File

@ -116,6 +116,13 @@ const SignSettings = ({
}
}, [parameters.signatureType, parameters.signerName, parameters.fontSize, parameters.fontFamily, onActivateSignaturePlacement, onDeactivateSignature]);
// Reset to move mode when placement mode is deactivated
useEffect(() => {
if (!isPlacementMode && interactionMode === 'place') {
setInteractionMode('move');
}
}, [isPlacementMode, interactionMode]);
// Handle signature data updates
useEffect(() => {
let newSignatureData: string | undefined = undefined;
@ -288,7 +295,10 @@ const SignSettings = ({
{/* Apply Signatures Button */}
{onSave && (
<Button
onClick={onSave}
onClick={() => {
console.log('Apply Signatures button clicked');
onSave();
}}
color="blue"
variant="filled"
fullWidth

View File

@ -51,8 +51,9 @@ function processFileSwap(
}
});
// Clear selections that reference removed files
// Clear selections that reference removed files and add new files to selection
const validSelectedFileIds = state.ui.selectedFileIds.filter(id => !unpinnedRemoveIds.includes(id));
const newSelectedFileIds = [...validSelectedFileIds, ...addedIds];
return {
...state,
@ -62,7 +63,7 @@ function processFileSwap(
},
ui: {
...state.ui,
selectedFileIds: validSelectedFileIds
selectedFileIds: newSelectedFileIds
}
};
}

View File

@ -15,9 +15,10 @@ import { flattenSignatures } from "../utils/signatureFlattening";
const Sign = (props: BaseToolProps) => {
const { t } = useTranslation();
const { setWorkbench } = useNavigation();
const { setSignatureConfig, activateDrawMode, activateSignaturePlacementMode, deactivateDrawMode, updateDrawSettings, undo, redo, signatureApiRef, getImageData, setSignaturesApplied } = useSignature();
const { setSignatureConfig, activateDrawMode, activateSignaturePlacementMode, deactivateDrawMode, updateDrawSettings, undo, redo, signatureApiRef, getImageData, setSignaturesApplied, historyApiRef } = useSignature();
const { consumeFiles, selectors } = useFileContext();
const { exportActions, getScrollState } = useViewer();
const { setHasUnsavedChanges, unregisterUnsavedChangesChecker } = useNavigation();
// Track which signature mode was active for reactivation after save
const activeModeRef = useRef<'draw' | 'placement' | null>(null);
@ -38,6 +39,11 @@ const Sign = (props: BaseToolProps) => {
handleSignaturePlacement();
}, [handleSignaturePlacement]);
const handleDeactivateSignature = useCallback(() => {
activeModeRef.current = null;
deactivateDrawMode();
}, [deactivateDrawMode]);
const base = useBaseTool(
'sign',
useSignParameters,
@ -65,6 +71,17 @@ const Sign = (props: BaseToolProps) => {
// Save signed files to the system - apply signatures using EmbedPDF and replace original
const handleSaveToSystem = useCallback(async () => {
try {
console.log('=== Apply Signatures Started ===');
console.log('exportActions:', exportActions);
console.log('signatureApiRef.current:', signatureApiRef.current);
// Deactivate signature placement mode immediately
handleDeactivateSignature();
// Unregister unsaved changes checker to prevent warning during apply
unregisterUnsavedChangesChecker();
setHasUnsavedChanges(false);
// Get the original file
let originalFile = null;
if (base.selectedFiles.length > 0) {
@ -84,8 +101,10 @@ const Sign = (props: BaseToolProps) => {
return;
}
console.log('originalFile:', originalFile);
// Use the signature flattening utility
const success = await flattenSignatures({
const newFileIds = await flattenSignatures({
signatureApiRef,
getImageData,
exportActions,
@ -95,34 +114,26 @@ const Sign = (props: BaseToolProps) => {
getScrollState
});
if (success) {
console.log('flattenSignatures result:', newFileIds);
if (newFileIds && newFileIds.length > 0) {
console.log('✓ Signature flattening completed successfully');
// Mark signatures as applied
setSignaturesApplied(true);
// Force refresh the viewer to show the flattened PDF
// Force viewer reload to show flattened PDF
setWorkbench('fileEditor');
setTimeout(() => {
// Navigate away from viewer and back to force reload
setWorkbench('fileEditor');
setTimeout(() => {
setWorkbench('viewer');
// Reactivate the signature mode that was active before save
if (activeModeRef.current === 'draw') {
activateDrawMode();
} else if (activeModeRef.current === 'placement') {
handleSignaturePlacement();
}
}, 100);
}, 200);
setWorkbench('viewer');
}, 50);
} else {
console.error('Signature flattening failed');
}
} catch (error) {
console.error('Error saving signed document:', error);
}
}, [exportActions, base.selectedFiles, selectors, consumeFiles, signatureApiRef, getImageData, setWorkbench, activateDrawMode]);
}, [exportActions, base.selectedFiles, selectors, consumeFiles, signatureApiRef, getImageData, setWorkbench, activateDrawMode, setSignaturesApplied, getScrollState, handleDeactivateSignature, setHasUnsavedChanges, unregisterUnsavedChangesChecker]);
const getSteps = () => {
const steps = [];
@ -140,7 +151,7 @@ const Sign = (props: BaseToolProps) => {
disabled={base.endpointLoading}
onActivateDrawMode={handleActivateDrawMode}
onActivateSignaturePlacement={handleActivateSignaturePlacement}
onDeactivateSignature={deactivateDrawMode}
onDeactivateSignature={handleDeactivateSignature}
onUpdateDrawSettings={updateDrawSettings}
onUndo={undo}
onRedo={redo}

View File

@ -1,6 +1,6 @@
import { PDFDocument, rgb } from 'pdf-lib';
import { generateThumbnailWithMetadata } from './thumbnailUtils';
import { createProcessedFile } from '../contexts/file/fileActions';
import { createProcessedFile, createChildStub } from '../contexts/file/fileActions';
import { createNewStirlingFileStub, createStirlingFile, StirlingFile, FileId, StirlingFileStub } from '../types/fileContext';
import type { SignatureAPI } from '../components/viewer/SignatureAPIBridge';
@ -22,7 +22,7 @@ interface SignatureFlatteningOptions {
getScrollState: () => { currentPage: number; totalPages: number };
}
export async function flattenSignatures(options: SignatureFlatteningOptions): Promise<boolean> {
export async function flattenSignatures(options: SignatureFlatteningOptions): Promise<FileId[] | null> {
const { signatureApiRef, getImageData, exportActions, selectors, consumeFiles, originalFile, getScrollState } = options;
try {
@ -85,7 +85,7 @@ export async function flattenSignatures(options: SignatureFlatteningOptions): Pr
// Step 3: Use EmbedPDF's saveAsCopy to get the base PDF (now without annotations)
if (!exportActions) {
console.error('No export actions available');
return false;
return null;
}
const pdfArrayBuffer = await exportActions.saveAsCopy();
@ -111,7 +111,7 @@ export async function flattenSignatures(options: SignatureFlatteningOptions): Pr
if (!currentFile) {
console.error('No file available to replace');
return false;
return null;
}
let signedFile = new File([blob], currentFile.name, { type: 'application/pdf' });
@ -150,9 +150,11 @@ export async function flattenSignatures(options: SignatureFlatteningOptions): Pr
const pages = pdfDoc.getPages();
console.log('Starting to render annotations. Total pages with annotations:', allAnnotations.length);
for (const pageData of allAnnotations) {
const { pageIndex, annotations } = pageData;
console.log(`Rendering ${annotations.length} annotations on page ${pageIndex}`);
if (pageIndex < pages.length) {
const page = pages[pageIndex];
@ -187,8 +189,18 @@ export async function flattenSignatures(options: SignatureFlatteningOptions): Pr
}
}
console.log('Processing annotation:', {
pageIndex,
hasImageData: !!imageDataUrl,
imageDataType: typeof imageDataUrl,
startsWithDataImage: imageDataUrl && typeof imageDataUrl === 'string' && imageDataUrl.startsWith('data:image'),
position: { pdfX, pdfY, width, height }
});
if (imageDataUrl && typeof imageDataUrl === 'string' && imageDataUrl.startsWith('data:image')) {
try {
console.log('Rendering image annotation at:', { pdfX, pdfY, width, height });
// Convert data URL to bytes
const base64Data = imageDataUrl.split(',')[1];
const imageBytes = Uint8Array.from(atob(base64Data), c => c.charCodeAt(0));
@ -211,10 +223,13 @@ export async function flattenSignatures(options: SignatureFlatteningOptions): Pr
height: height,
});
console.log('✓ Successfully rendered image annotation');
} catch (imageError) {
console.error('Failed to render image annotation:', imageError);
}
} else if (annotation.content || annotation.text) {
console.warn('Rendering text annotation instead');
// Handle text annotations
page.drawText(annotation.content || annotation.text, {
x: pdfX,
@ -287,23 +302,35 @@ export async function flattenSignatures(options: SignatureFlatteningOptions): Pr
const record = selectors.getStirlingFileStub(currentFile.fileId);
if (!record) {
console.error('No file record found for:', currentFile.fileId);
return false;
return null;
}
// Create output stub and file
const outputStub = createNewStirlingFileStub(signedFile, undefined, thumbnailResult.thumbnail, processedFileMetadata);
console.log('Parent file record:', record);
console.log('Parent version:', record.versionNumber);
// Create output stub and file as a child of the original (increments version)
const outputStub = createChildStub(
record,
{ toolId: 'sign', timestamp: Date.now() },
signedFile,
thumbnailResult.thumbnail,
processedFileMetadata
);
const outputStirlingFile = createStirlingFile(signedFile, outputStub.id);
// Replace the original file with the signed version
await consumeFiles(inputFileIds, [outputStirlingFile], [outputStub]);
console.log('Output stub version:', outputStub.versionNumber);
console.log('Consuming files - replacing:', inputFileIds, 'with:', outputStub.id);
console.log('✓ Signature flattening completed successfully');
return true;
// Replace the original file with the signed version
const newFileIds = await consumeFiles(inputFileIds, [outputStirlingFile], [outputStub]);
console.log('✓ Signature flattening completed successfully. New file IDs:', newFileIds);
return newFileIds;
}
return false;
return null;
} catch (error) {
console.error('Error flattening signatures:', error);
return false;
return null;
}
}