mirror of
https://github.com/Frooodle/Stirling-PDF.git
synced 2025-09-26 17:52:59 +02:00
Save file
This commit is contained in:
parent
a8a0808274
commit
023fd43b72
@ -3,6 +3,7 @@ import { useTranslation } from "react-i18next";
|
||||
import { Stack, TextInput, FileInput, Paper, Group, Button, Text, Alert, Modal, ColorSwatch, Menu, ActionIcon, Slider, Select, Combobox, useCombobox, ColorPicker, Tabs } from '@mantine/core';
|
||||
import ButtonSelector from "../../shared/ButtonSelector";
|
||||
import { SignParameters } from "../../../hooks/tools/sign/useSignParameters";
|
||||
import { SuggestedToolsSection } from "../shared/SuggestedToolsSection";
|
||||
|
||||
interface SignSettingsProps {
|
||||
parameters: SignParameters;
|
||||
@ -14,9 +15,10 @@ interface SignSettingsProps {
|
||||
onUpdateDrawSettings?: (color: string, size: number) => void;
|
||||
onUndo?: () => void;
|
||||
onRedo?: () => void;
|
||||
onSave?: () => void;
|
||||
}
|
||||
|
||||
const SignSettings = ({ parameters, onParameterChange, disabled = false, onActivateDrawMode, onActivateSignaturePlacement, onDeactivateSignature, onUpdateDrawSettings, onUndo, onRedo }: SignSettingsProps) => {
|
||||
const SignSettings = ({ parameters, onParameterChange, disabled = false, onActivateDrawMode, onActivateSignaturePlacement, onDeactivateSignature, onUpdateDrawSettings, onUndo, onRedo, onSave }: SignSettingsProps) => {
|
||||
const { t } = useTranslation();
|
||||
const canvasRef = useRef<HTMLCanvasElement>(null);
|
||||
const [isDrawing, setIsDrawing] = useState(false);
|
||||
@ -439,9 +441,6 @@ const SignSettings = ({ parameters, onParameterChange, disabled = false, onActiv
|
||||
onChange={(value) => onParameterChange('signatureType', value as 'image' | 'text' | 'draw' | 'canvas')}
|
||||
>
|
||||
<Tabs.List grow>
|
||||
<Tabs.Tab value="draw" style={{ fontSize: '0.8rem' }}>
|
||||
{t('sign.type.draw', 'Draw')}
|
||||
</Tabs.Tab>
|
||||
<Tabs.Tab value="canvas" style={{ fontSize: '0.8rem' }}>
|
||||
{t('sign.type.canvas', 'Canvas')}
|
||||
</Tabs.Tab>
|
||||
@ -451,6 +450,9 @@ const SignSettings = ({ parameters, onParameterChange, disabled = false, onActiv
|
||||
<Tabs.Tab value="text" style={{ fontSize: '0.8rem' }}>
|
||||
{t('sign.type.text', 'Text')}
|
||||
</Tabs.Tab>
|
||||
<Tabs.Tab value="draw" style={{ fontSize: '0.8rem' }}>
|
||||
{t('sign.type.draw', 'Draw')}
|
||||
</Tabs.Tab>
|
||||
</Tabs.List>
|
||||
</Tabs>
|
||||
|
||||
@ -472,6 +474,7 @@ const SignSettings = ({ parameters, onParameterChange, disabled = false, onActiv
|
||||
</Button>
|
||||
</Group>
|
||||
|
||||
|
||||
{/* Signature Creation based on type */}
|
||||
{parameters.signatureType === 'canvas' && (
|
||||
<Paper withBorder p="md">
|
||||
@ -958,6 +961,21 @@ const SignSettings = ({ parameters, onParameterChange, disabled = false, onActiv
|
||||
</Group>
|
||||
</Stack>
|
||||
</Modal>
|
||||
|
||||
{/* Save Button */}
|
||||
{onSave && (
|
||||
<Button
|
||||
onClick={onSave}
|
||||
color="green"
|
||||
variant="filled"
|
||||
fullWidth
|
||||
>
|
||||
{t('save', 'Save')}
|
||||
</Button>
|
||||
)}
|
||||
|
||||
{/* Suggested Tools Section */}
|
||||
<SuggestedToolsSection />
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
@ -20,7 +20,7 @@ export interface SignParameters {
|
||||
}
|
||||
|
||||
export const DEFAULT_PARAMETERS: SignParameters = {
|
||||
signatureType: 'draw',
|
||||
signatureType: 'canvas',
|
||||
reason: 'Document signing',
|
||||
location: 'Digital',
|
||||
signerName: '',
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { useEffect, useCallback } from "react";
|
||||
import { useEffect, useCallback, useRef } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { createToolFlow } from "../components/tools/shared/createToolFlow";
|
||||
import { useSignParameters } from "../hooks/tools/sign/useSignParameters";
|
||||
@ -8,11 +8,22 @@ import { BaseToolProps, ToolComponent } from "../types/tool";
|
||||
import SignSettings from "../components/tools/sign/SignSettings";
|
||||
import { useNavigation } from "../contexts/NavigationContext";
|
||||
import { useSignature } from "../contexts/SignatureContext";
|
||||
import { useFileActions, useFileContext } from "../contexts/FileContext";
|
||||
import { useViewer } from "../contexts/ViewerContext";
|
||||
import { generateThumbnailWithMetadata } from "../utils/thumbnailUtils";
|
||||
import { createNewStirlingFileStub, createStirlingFile, StirlingFileStub, StirlingFile, FileId, extractFiles } from "../types/fileContext";
|
||||
import { createProcessedFile } from "../contexts/file/fileActions";
|
||||
|
||||
const Sign = (props: BaseToolProps) => {
|
||||
const { t } = useTranslation();
|
||||
const { setWorkbench } = useNavigation();
|
||||
const { setSignatureConfig, activateDrawMode, activateSignaturePlacementMode, deactivateDrawMode, updateDrawSettings, undo, redo } = useSignature();
|
||||
const { setSignatureConfig, activateDrawMode, activateSignaturePlacementMode, deactivateDrawMode, updateDrawSettings, undo, redo, isPlacementMode } = useSignature();
|
||||
const { actions } = useFileActions();
|
||||
const { consumeFiles, selectors } = useFileContext();
|
||||
const { exportActions } = useViewer();
|
||||
|
||||
// Track which signature mode was active for reactivation after save
|
||||
const activeModeRef = useRef<'draw' | 'placement' | null>(null);
|
||||
|
||||
// Manual sync function
|
||||
const syncSignatureConfig = () => {
|
||||
@ -47,30 +58,125 @@ const Sign = (props: BaseToolProps) => {
|
||||
setSignatureConfig(base.params.parameters);
|
||||
}, [base.params.parameters, setSignatureConfig]);
|
||||
|
||||
// Save signed files to the system - apply signatures using EmbedPDF and replace original
|
||||
const handleSaveToSystem = useCallback(async () => {
|
||||
try {
|
||||
console.log('Save started - attempting to get PDF from viewer...');
|
||||
|
||||
// Use EmbedPDF's saveAsCopy to apply signatures and get ArrayBuffer
|
||||
const pdfArrayBuffer = await exportActions.saveAsCopy();
|
||||
console.log('Got PDF ArrayBuffer:', pdfArrayBuffer ? `${pdfArrayBuffer.byteLength} bytes` : 'null');
|
||||
|
||||
console.log('Checking conditions - ArrayBuffer exists:', !!pdfArrayBuffer, 'Selected files:', base.selectedFiles.length);
|
||||
|
||||
if (pdfArrayBuffer) {
|
||||
console.log('Conditions met, starting file processing...');
|
||||
|
||||
// Convert ArrayBuffer to File
|
||||
const blob = new Blob([pdfArrayBuffer], { type: 'application/pdf' });
|
||||
|
||||
// Get the current file - try from base.selectedFiles first, then from all files
|
||||
let originalFile = null;
|
||||
if (base.selectedFiles.length > 0) {
|
||||
originalFile = base.selectedFiles[0];
|
||||
} else {
|
||||
const allFileIds = selectors.getAllFileIds();
|
||||
if (allFileIds.length > 0) {
|
||||
const fileStub = selectors.getStirlingFileStub(allFileIds[0]);
|
||||
const fileObject = selectors.getFile(allFileIds[0]);
|
||||
if (fileStub && fileObject) {
|
||||
originalFile = createStirlingFile(fileObject, allFileIds[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!originalFile) {
|
||||
console.error('No file available to replace');
|
||||
return;
|
||||
}
|
||||
console.log('Original file:', originalFile.name, 'ID:', originalFile.fileId);
|
||||
|
||||
const signedFile = new File([blob], originalFile.name, { type: 'application/pdf' });
|
||||
console.log('Created signed file:', signedFile.name, 'Size:', signedFile.size);
|
||||
|
||||
console.log('Processing signed file...');
|
||||
|
||||
// Generate thumbnail and metadata for the signed file
|
||||
const thumbnailResult = await generateThumbnailWithMetadata(signedFile);
|
||||
const processedFileMetadata = createProcessedFile(thumbnailResult.pageCount, thumbnailResult.thumbnail);
|
||||
|
||||
// Prepare input file data for replacement
|
||||
const inputFileIds: FileId[] = [originalFile.fileId];
|
||||
const inputStirlingFileStubs: StirlingFileStub[] = [];
|
||||
|
||||
console.log('Original file ID:', originalFile.fileId);
|
||||
const record = selectors.getStirlingFileStub(originalFile.fileId);
|
||||
if (record) {
|
||||
inputStirlingFileStubs.push(record);
|
||||
console.log('Found file record for replacement');
|
||||
} else {
|
||||
console.error('No file record found for:', originalFile.fileId);
|
||||
}
|
||||
|
||||
// Create output stub and file
|
||||
const outputStub = createNewStirlingFileStub(signedFile, undefined, thumbnailResult.thumbnail, processedFileMetadata);
|
||||
const outputStirlingFile = createStirlingFile(signedFile, outputStub.id);
|
||||
console.log('Created new file with ID:', outputStub.id);
|
||||
|
||||
// Replace the original file with the signed version
|
||||
console.log('Replacing file in context...');
|
||||
await consumeFiles(inputFileIds, [outputStirlingFile], [outputStub]);
|
||||
console.log('File replacement complete');
|
||||
|
||||
// Reactivate the signature mode that was active before save
|
||||
setTimeout(() => {
|
||||
if (activeModeRef.current === 'draw') {
|
||||
console.log('Reactivating draw mode');
|
||||
activateDrawMode();
|
||||
} else if (activeModeRef.current === 'placement') {
|
||||
console.log('Reactivating placement mode');
|
||||
handleSignaturePlacement();
|
||||
}
|
||||
}, 200);
|
||||
} else {
|
||||
console.log('Save aborted - conditions not met');
|
||||
if (!pdfArrayBuffer) console.log('No PDF ArrayBuffer received');
|
||||
if (base.selectedFiles.length === 0) console.log('No selected files');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error saving signed document:', error);
|
||||
}
|
||||
}, [exportActions, base.selectedFiles, selectors, consumeFiles]);
|
||||
|
||||
const getSteps = () => {
|
||||
const steps = [];
|
||||
|
||||
// Step 1: Signature Configuration
|
||||
if (base.selectedFiles.length > 0 || base.operation.files.length > 0) {
|
||||
steps.push({
|
||||
title: t('sign.steps.configure', 'Configure Signature'),
|
||||
isCollapsed: base.operation.files.length > 0,
|
||||
onCollapsedClick: base.operation.files.length > 0 ? base.handleSettingsReset : undefined,
|
||||
content: (
|
||||
<SignSettings
|
||||
parameters={base.params.parameters}
|
||||
onParameterChange={base.params.updateParameter}
|
||||
disabled={base.endpointLoading}
|
||||
onActivateDrawMode={() => activateDrawMode()}
|
||||
onActivateSignaturePlacement={handleSignaturePlacement}
|
||||
onDeactivateSignature={deactivateDrawMode}
|
||||
onUpdateDrawSettings={updateDrawSettings}
|
||||
onUndo={undo}
|
||||
onRedo={redo}
|
||||
/>
|
||||
),
|
||||
});
|
||||
}
|
||||
// Step 1: Signature Configuration - Always visible
|
||||
steps.push({
|
||||
title: t('sign.steps.configure', 'Configure Signature'),
|
||||
isCollapsed: false,
|
||||
onCollapsedClick: undefined,
|
||||
content: (
|
||||
<SignSettings
|
||||
parameters={base.params.parameters}
|
||||
onParameterChange={base.params.updateParameter}
|
||||
disabled={base.endpointLoading}
|
||||
onActivateDrawMode={() => {
|
||||
activeModeRef.current = 'draw';
|
||||
activateDrawMode();
|
||||
}}
|
||||
onActivateSignaturePlacement={() => {
|
||||
activeModeRef.current = 'placement';
|
||||
handleSignaturePlacement();
|
||||
}}
|
||||
onDeactivateSignature={deactivateDrawMode}
|
||||
onUpdateDrawSettings={updateDrawSettings}
|
||||
onUndo={undo}
|
||||
onRedo={redo}
|
||||
onSave={handleSaveToSystem}
|
||||
/>
|
||||
),
|
||||
});
|
||||
|
||||
return steps;
|
||||
};
|
||||
@ -81,19 +187,12 @@ const Sign = (props: BaseToolProps) => {
|
||||
isCollapsed: base.operation.files.length > 0,
|
||||
},
|
||||
steps: getSteps(),
|
||||
executeButton: {
|
||||
text: t('sign.submit', 'Sign Document'),
|
||||
isVisible: false, // Hide the execute button - signatures are placed directly
|
||||
loadingText: t('loading'),
|
||||
onClick: base.handleExecute,
|
||||
disabled: !base.params.validateParameters() || base.selectedFiles.length === 0 || !base.endpointEnabled,
|
||||
},
|
||||
review: {
|
||||
isVisible: base.operation.files.length > 0,
|
||||
isVisible: false, // Hide review section - save moved to configure section
|
||||
operation: base.operation,
|
||||
title: t('sign.results.title', 'Signature Results'),
|
||||
onFileClick: base.handleThumbnailClick,
|
||||
onUndo: base.handleUndo,
|
||||
onUndo: () => {},
|
||||
},
|
||||
forceStepNumbers: true,
|
||||
});
|
||||
@ -102,7 +201,7 @@ const Sign = (props: BaseToolProps) => {
|
||||
// Add the required static methods for automation
|
||||
Sign.tool = () => useSignOperation;
|
||||
Sign.getDefaultParameters = () => ({
|
||||
signatureType: 'draw',
|
||||
signatureType: 'canvas',
|
||||
reason: 'Document signing',
|
||||
location: 'Digital',
|
||||
signerName: '',
|
||||
|
Loading…
Reference in New Issue
Block a user