mirror of
https://github.com/Frooodle/Stirling-PDF.git
synced 2025-12-18 20:04:17 +01:00
- Refactored signature saving process
This commit is contained in:
parent
991be9ffa2
commit
f6290c0238
@ -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 */}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@ -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}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user