diff --git a/frontend/public/locales/en-GB/translation.json b/frontend/public/locales/en-GB/translation.json index 3b4cd0aba..64cd9408d 100644 --- a/frontend/public/locales/en-GB/translation.json +++ b/frontend/public/locales/en-GB/translation.json @@ -1062,7 +1062,18 @@ "tags": "remove,delete,form,field,readonly", "title": "Remove Read-Only from Form Fields", "header": "Unlock PDF Forms", - "submit": "Remove" + "submit": "Unlock Forms", + "description": "This tool will remove read-only restrictions from PDF form fields, making them editable and fillable.", + "filenamePrefix": "unlocked_forms", + "files": { + "placeholder": "Select a PDF file in the main view to get started" + }, + "error": { + "failed": "An error occurred whilst unlocking PDF forms." + }, + "results": { + "title": "Unlocked Forms Results" + } }, "changeMetadata": { "tags": "Title,author,date,creation,time,publisher,producer,stats", @@ -1310,7 +1321,18 @@ "title": "Remove Certificate Signature", "header": "Remove the digital certificate from the PDF", "selectPDF": "Select a PDF file:", - "submit": "Remove Signature" + "submit": "Remove Signature", + "description": "This tool will remove digital certificate signatures from your PDF document.", + "filenamePrefix": "unsigned", + "files": { + "placeholder": "Select a PDF file in the main view to get started" + }, + "error": { + "failed": "An error occurred whilst removing certificate signatures." + }, + "results": { + "title": "Certificate Removal Results" + } }, "pageLayout": { "tags": "merge,composite,single-view,organize", @@ -1638,7 +1660,18 @@ "pdfToSinglePage": { "title": "PDF To Single Page", "header": "PDF To Single Page", - "submit": "Convert To Single Page" + "submit": "Convert To Single Page", + "description": "This tool will merge all pages of your PDF into one large single page. The width will remain the same as the original pages, but the height will be the sum of all page heights.", + "filenamePrefix": "single_page", + "files": { + "placeholder": "Select a PDF file in the main view to get started" + }, + "error": { + "failed": "An error occurred whilst converting to single page." + }, + "results": { + "title": "Single Page Results" + } }, "pageExtracter": { "title": "Extract Pages", diff --git a/frontend/public/locales/en-US/translation.json b/frontend/public/locales/en-US/translation.json index 495ae8c20..358ccd53a 100644 --- a/frontend/public/locales/en-US/translation.json +++ b/frontend/public/locales/en-US/translation.json @@ -812,7 +812,18 @@ "tags": "remove,delete,form,field,readonly", "title": "Remove Read-Only from Form Fields", "header": "Unlock PDF Forms", - "submit": "Remove" + "submit": "Unlock Forms", + "description": "This tool will remove read-only restrictions from PDF form fields, making them editable and fillable.", + "filenamePrefix": "unlocked_forms", + "files": { + "placeholder": "Select a PDF file in the main view to get started" + }, + "error": { + "failed": "An error occurred while unlocking PDF forms." + }, + "results": { + "title": "Unlocked Forms Results" + } }, "changeMetadata": { "tags": "Title,author,date,creation,time,publisher,producer,stats", @@ -1060,7 +1071,18 @@ "title": "Remove Certificate Signature", "header": "Remove the digital certificate from the PDF", "selectPDF": "Select a PDF file:", - "submit": "Remove Signature" + "submit": "Remove Signature", + "description": "This tool will remove digital certificate signatures from your PDF document.", + "filenamePrefix": "unsigned", + "files": { + "placeholder": "Select a PDF file in the main view to get started" + }, + "error": { + "failed": "An error occurred while removing certificate signatures." + }, + "results": { + "title": "Certificate Removal Results" + } }, "pageLayout": { "tags": "merge,composite,single-view,organize", @@ -1388,7 +1410,18 @@ "pdfToSinglePage": { "title": "PDF To Single Page", "header": "PDF To Single Page", - "submit": "Convert To Single Page" + "submit": "Convert To Single Page", + "description": "This tool will merge all pages of your PDF into one large single page. The width will remain the same as the original pages, but the height will be the sum of all page heights.", + "filenamePrefix": "single_page", + "files": { + "placeholder": "Select a PDF file in the main view to get started" + }, + "error": { + "failed": "An error occurred while converting to single page." + }, + "results": { + "title": "Single Page Results" + } }, "pageExtracter": { "title": "Extract Pages", diff --git a/frontend/src/components/tools/removeCertificateSign/RemoveCertificateSignSettings.tsx b/frontend/src/components/tools/removeCertificateSign/RemoveCertificateSignSettings.tsx new file mode 100644 index 000000000..f34e3f2e6 --- /dev/null +++ b/frontend/src/components/tools/removeCertificateSign/RemoveCertificateSignSettings.tsx @@ -0,0 +1,27 @@ +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import { RemoveCertificateSignParameters } from '../../../hooks/tools/removeCertificateSign/useRemoveCertificateSignParameters'; + +interface RemoveCertificateSignSettingsProps { + parameters: RemoveCertificateSignParameters; + onParameterChange: (parameter: K, value: RemoveCertificateSignParameters[K]) => void; + disabled?: boolean; +} + +const RemoveCertificateSignSettings: React.FC = ({ + parameters, + onParameterChange, // Unused - kept for interface consistency and future extensibility + disabled = false +}) => { + const { t } = useTranslation(); + + return ( +
+

+ {t('removeCertSign.description', 'This tool will remove digital certificate signatures from your PDF document.')} +

+
+ ); +}; + +export default RemoveCertificateSignSettings; \ No newline at end of file diff --git a/frontend/src/components/tools/singleLargePage/SingleLargePageSettings.tsx b/frontend/src/components/tools/singleLargePage/SingleLargePageSettings.tsx new file mode 100644 index 000000000..87dfef926 --- /dev/null +++ b/frontend/src/components/tools/singleLargePage/SingleLargePageSettings.tsx @@ -0,0 +1,27 @@ +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import { SingleLargePageParameters } from '../../../hooks/tools/singleLargePage/useSingleLargePageParameters'; + +interface SingleLargePageSettingsProps { + parameters: SingleLargePageParameters; + onParameterChange: (parameter: K, value: SingleLargePageParameters[K]) => void; + disabled?: boolean; +} + +const SingleLargePageSettings: React.FC = ({ + parameters, + onParameterChange, + disabled = false +}) => { + const { t } = useTranslation(); + + return ( +
+

+ {t('pdfToSinglePage.description', 'This tool will merge all pages of your PDF into one large single page. The width will remain the same as the original pages, but the height will be the sum of all page heights.')} +

+
+ ); +}; + +export default SingleLargePageSettings; \ No newline at end of file diff --git a/frontend/src/components/tools/unlockPdfForms/UnlockPdfFormsSettings.tsx b/frontend/src/components/tools/unlockPdfForms/UnlockPdfFormsSettings.tsx new file mode 100644 index 000000000..cc8697d7a --- /dev/null +++ b/frontend/src/components/tools/unlockPdfForms/UnlockPdfFormsSettings.tsx @@ -0,0 +1,27 @@ +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import { UnlockPdfFormsParameters } from '../../../hooks/tools/unlockPdfForms/useUnlockPdfFormsParameters'; + +interface UnlockPdfFormsSettingsProps { + parameters: UnlockPdfFormsParameters; + onParameterChange: (parameter: K, value: UnlockPdfFormsParameters[K]) => void; + disabled?: boolean; +} + +const UnlockPdfFormsSettings: React.FC = ({ + parameters, + onParameterChange, // Unused - kept for interface consistency and future extensibility + disabled = false +}) => { + const { t } = useTranslation(); + + return ( +
+

+ {t('unlockPDFForms.description', 'This tool will remove read-only restrictions from PDF form fields, making them editable and fillable.')} +

+
+ ); +}; + +export default UnlockPdfFormsSettings; \ No newline at end of file diff --git a/frontend/src/data/useTranslatedToolRegistry.tsx b/frontend/src/data/useTranslatedToolRegistry.tsx index 1a53cf651..359cf6d35 100644 --- a/frontend/src/data/useTranslatedToolRegistry.tsx +++ b/frontend/src/data/useTranslatedToolRegistry.tsx @@ -11,6 +11,11 @@ import RemovePassword from '../tools/RemovePassword'; import { SubcategoryId, ToolCategory, ToolRegistry } from './toolsTaxonomy'; import AddWatermark from '../tools/AddWatermark'; import Repair from '../tools/Repair'; +import SingleLargePage from '../tools/SingleLargePage'; +import UnlockPdfForms from '../tools/UnlockPdfForms'; +import RemoveCertificateSign from '../tools/RemoveCertificateSign'; + + // Hook to get the translated tool registry export function useFlatToolRegistry(): ToolRegistry { @@ -95,11 +100,13 @@ export function useFlatToolRegistry(): ToolRegistry { "unlock-pdf-forms": { icon: preview_off, name: t("home.unlockPDFForms.title", "Unlock PDF Forms"), - component: null, + component: UnlockPdfForms, view: "security", description: t("home.unlockPDFForms.desc", "Remove read-only property of form fields in a PDF document."), category: ToolCategory.STANDARD_TOOLS, - subcategory: SubcategoryId.DOCUMENT_SECURITY + subcategory: SubcategoryId.DOCUMENT_SECURITY, + maxFiles: -1, + endpoints: ["unlock-pdf-forms"] }, "manage-certificates": { icon: license, @@ -231,11 +238,13 @@ export function useFlatToolRegistry(): ToolRegistry { "single-large-page": { icon: looks_one, name: t("home.PdfToSinglePage.title", "PDF to Single Large Page"), - component: null, + component: SingleLargePage, view: "format", description: t("home.PdfToSinglePage.desc", "Merges all PDF pages into one large single page"), category: ToolCategory.STANDARD_TOOLS, - subcategory: SubcategoryId.PAGE_FORMATTING + subcategory: SubcategoryId.PAGE_FORMATTING, + maxFiles: -1, + endpoints: ["pdf-to-single-page"] }, "add-attachments": { icon: attachment, @@ -323,11 +332,13 @@ export function useFlatToolRegistry(): ToolRegistry { "remove-certificate-sign": { icon: remove_moderator, name: t("home.removeCertSign.title", "Remove Certificate Signatures"), - component: null, + component: RemoveCertificateSign, view: "security", description: t("home.removeCertSign.desc", "Remove digital signatures from PDF documents"), category: ToolCategory.STANDARD_TOOLS, - subcategory: SubcategoryId.REMOVAL + subcategory: SubcategoryId.REMOVAL, + maxFiles: -1, + endpoints: ["remove-certificate-sign"] }, diff --git a/frontend/src/hooks/tools/removeCertificateSign/useRemoveCertificateSignOperation.ts b/frontend/src/hooks/tools/removeCertificateSign/useRemoveCertificateSignOperation.ts new file mode 100644 index 000000000..5987944ec --- /dev/null +++ b/frontend/src/hooks/tools/removeCertificateSign/useRemoveCertificateSignOperation.ts @@ -0,0 +1,23 @@ +import { useTranslation } from 'react-i18next'; +import { useToolOperation } from '../shared/useToolOperation'; +import { createStandardErrorHandler } from '../../../utils/toolErrorHandler'; +import { RemoveCertificateSignParameters } from './useRemoveCertificateSignParameters'; + +export const useRemoveCertificateSignOperation = () => { + const { t } = useTranslation(); + + const buildFormData = (parameters: RemoveCertificateSignParameters, file: File): FormData => { + const formData = new FormData(); + formData.append("fileInput", file); + return formData; + }; + + return useToolOperation({ + operationType: 'removeCertificateSign', + endpoint: '/api/v1/security/remove-cert-sign', + buildFormData, + filePrefix: t('removeCertSign.filenamePrefix', 'unsigned') + '_', + multiFileEndpoint: false, + getErrorMessage: createStandardErrorHandler(t('removeCertSign.error.failed', 'An error occurred while removing certificate signatures.')) + }); +}; \ No newline at end of file diff --git a/frontend/src/hooks/tools/removeCertificateSign/useRemoveCertificateSignParameters.ts b/frontend/src/hooks/tools/removeCertificateSign/useRemoveCertificateSignParameters.ts new file mode 100644 index 000000000..59903ccfc --- /dev/null +++ b/frontend/src/hooks/tools/removeCertificateSign/useRemoveCertificateSignParameters.ts @@ -0,0 +1,19 @@ +import { BaseParameters } from '../../../types/parameters'; +import { useBaseParameters, BaseParametersHook } from '../shared/useBaseParameters'; + +export interface RemoveCertificateSignParameters extends BaseParameters { + // Extends BaseParameters - ready for future parameter additions if needed +} + +export const defaultParameters: RemoveCertificateSignParameters = { + // No parameters needed +}; + +export type RemoveCertificateSignParametersHook = BaseParametersHook; + +export const useRemoveCertificateSignParameters = (): RemoveCertificateSignParametersHook => { + return useBaseParameters({ + defaultParameters, + endpointName: 'remove-certificate-sign', + }); +}; \ No newline at end of file diff --git a/frontend/src/hooks/tools/singleLargePage/useSingleLargePageOperation.ts b/frontend/src/hooks/tools/singleLargePage/useSingleLargePageOperation.ts new file mode 100644 index 000000000..e73944864 --- /dev/null +++ b/frontend/src/hooks/tools/singleLargePage/useSingleLargePageOperation.ts @@ -0,0 +1,23 @@ +import { useTranslation } from 'react-i18next'; +import { useToolOperation } from '../shared/useToolOperation'; +import { createStandardErrorHandler } from '../../../utils/toolErrorHandler'; +import { SingleLargePageParameters } from './useSingleLargePageParameters'; + +export const useSingleLargePageOperation = () => { + const { t } = useTranslation(); + + const buildFormData = (parameters: SingleLargePageParameters, file: File): FormData => { + const formData = new FormData(); + formData.append("fileInput", file); + return formData; + }; + + return useToolOperation({ + operationType: 'singleLargePage', + endpoint: '/api/v1/general/pdf-to-single-page', + buildFormData, + filePrefix: t('pdfToSinglePage.filenamePrefix', 'single_page') + '_', + multiFileEndpoint: false, + getErrorMessage: createStandardErrorHandler(t('pdfToSinglePage.error.failed', 'An error occurred while converting to single page.')) + }); +}; \ No newline at end of file diff --git a/frontend/src/hooks/tools/singleLargePage/useSingleLargePageParameters.ts b/frontend/src/hooks/tools/singleLargePage/useSingleLargePageParameters.ts new file mode 100644 index 000000000..df401b1a4 --- /dev/null +++ b/frontend/src/hooks/tools/singleLargePage/useSingleLargePageParameters.ts @@ -0,0 +1,19 @@ +import { BaseParameters } from '../../../types/parameters'; +import { useBaseParameters, BaseParametersHook } from '../shared/useBaseParameters'; + +export interface SingleLargePageParameters extends BaseParameters { + // Extends BaseParameters - ready for future parameter additions if needed +} + +export const defaultParameters: SingleLargePageParameters = { + // No parameters needed +}; + +export type SingleLargePageParametersHook = BaseParametersHook; + +export const useSingleLargePageParameters = (): SingleLargePageParametersHook => { + return useBaseParameters({ + defaultParameters, + endpointName: 'pdf-to-single-page', + }); +}; \ No newline at end of file diff --git a/frontend/src/hooks/tools/unlockPdfForms/useUnlockPdfFormsOperation.ts b/frontend/src/hooks/tools/unlockPdfForms/useUnlockPdfFormsOperation.ts new file mode 100644 index 000000000..3b648762b --- /dev/null +++ b/frontend/src/hooks/tools/unlockPdfForms/useUnlockPdfFormsOperation.ts @@ -0,0 +1,23 @@ +import { useTranslation } from 'react-i18next'; +import { useToolOperation } from '../shared/useToolOperation'; +import { createStandardErrorHandler } from '../../../utils/toolErrorHandler'; +import { UnlockPdfFormsParameters } from './useUnlockPdfFormsParameters'; + +export const useUnlockPdfFormsOperation = () => { + const { t } = useTranslation(); + + const buildFormData = (parameters: UnlockPdfFormsParameters, file: File): FormData => { + const formData = new FormData(); + formData.append("fileInput", file); + return formData; + }; + + return useToolOperation({ + operationType: 'unlockPdfForms', + endpoint: '/api/v1/misc/unlock-pdf-forms', + buildFormData, + filePrefix: t('unlockPDFForms.filenamePrefix', 'unlocked_forms') + '_', + multiFileEndpoint: false, + getErrorMessage: createStandardErrorHandler(t('unlockPDFForms.error.failed', 'An error occurred while unlocking PDF forms.')) + }); +}; \ No newline at end of file diff --git a/frontend/src/hooks/tools/unlockPdfForms/useUnlockPdfFormsParameters.ts b/frontend/src/hooks/tools/unlockPdfForms/useUnlockPdfFormsParameters.ts new file mode 100644 index 000000000..ad2536643 --- /dev/null +++ b/frontend/src/hooks/tools/unlockPdfForms/useUnlockPdfFormsParameters.ts @@ -0,0 +1,19 @@ +import { BaseParameters } from '../../../types/parameters'; +import { useBaseParameters, BaseParametersHook } from '../shared/useBaseParameters'; + +export interface UnlockPdfFormsParameters extends BaseParameters { + // Extends BaseParameters - ready for future parameter additions if needed +} + +export const defaultParameters: UnlockPdfFormsParameters = { + // No parameters needed +}; + +export type UnlockPdfFormsParametersHook = BaseParametersHook; + +export const useUnlockPdfFormsParameters = (): UnlockPdfFormsParametersHook => { + return useBaseParameters({ + defaultParameters, + endpointName: 'unlock-pdf-forms', + }); +}; \ No newline at end of file diff --git a/frontend/src/tools/RemoveCertificateSign.tsx b/frontend/src/tools/RemoveCertificateSign.tsx new file mode 100644 index 000000000..e33675625 --- /dev/null +++ b/frontend/src/tools/RemoveCertificateSign.tsx @@ -0,0 +1,80 @@ +import React, { useEffect } from "react"; +import { useTranslation } from "react-i18next"; +import { useEndpointEnabled } from "../hooks/useEndpointConfig"; +import { useFileContext } from "../contexts/FileContext"; +import { useToolFileSelection } from "../contexts/FileSelectionContext"; + +import { createToolFlow } from "../components/tools/shared/createToolFlow"; + +import { useRemoveCertificateSignParameters } from "../hooks/tools/removeCertificateSign/useRemoveCertificateSignParameters"; +import { useRemoveCertificateSignOperation } from "../hooks/tools/removeCertificateSign/useRemoveCertificateSignOperation"; +import { BaseToolProps } from "../types/tool"; + +const RemoveCertificateSign = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => { + const { t } = useTranslation(); + const { setCurrentMode } = useFileContext(); + const { selectedFiles } = useToolFileSelection(); + + const removeCertificateSignParams = useRemoveCertificateSignParameters(); + const removeCertificateSignOperation = useRemoveCertificateSignOperation(); + + // Endpoint validation + const { enabled: endpointEnabled, loading: endpointLoading } = useEndpointEnabled(removeCertificateSignParams.getEndpointName()); + + useEffect(() => { + removeCertificateSignOperation.resetResults(); + onPreviewFile?.(null); + }, [removeCertificateSignParams.parameters]); + + const handleRemoveSignature = async () => { + try { + await removeCertificateSignOperation.executeOperation(removeCertificateSignParams.parameters, selectedFiles); + if (removeCertificateSignOperation.files && onComplete) { + onComplete(removeCertificateSignOperation.files); + } + } catch (error) { + if (onError) { + onError(error instanceof Error ? error.message : t("removeCertSign.error.failed", "Remove certificate signature operation failed")); + } + } + }; + + const handleThumbnailClick = (file: File) => { + onPreviewFile?.(file); + sessionStorage.setItem("previousMode", "removeCertificateSign"); + setCurrentMode("viewer"); + }; + + const handleSettingsReset = () => { + removeCertificateSignOperation.resetResults(); + onPreviewFile?.(null); + setCurrentMode("removeCertificateSign"); + }; + + const hasFiles = selectedFiles.length > 0; + const hasResults = removeCertificateSignOperation.files.length > 0 || removeCertificateSignOperation.downloadUrl !== null; + + return createToolFlow({ + files: { + selectedFiles, + isCollapsed: hasFiles || hasResults, + placeholder: t("removeCertSign.files.placeholder", "Select a PDF file in the main view to get started"), + }, + steps: [], + executeButton: { + text: t("removeCertSign.submit", "Remove Signature"), + isVisible: !hasResults, + loadingText: t("loading"), + onClick: handleRemoveSignature, + disabled: !removeCertificateSignParams.validateParameters() || !hasFiles || !endpointEnabled, + }, + review: { + isVisible: hasResults, + operation: removeCertificateSignOperation, + title: t("removeCertSign.results.title", "Certificate Removal Results"), + onFileClick: handleThumbnailClick, + }, + }); +}; + +export default RemoveCertificateSign; \ No newline at end of file diff --git a/frontend/src/tools/SingleLargePage.tsx b/frontend/src/tools/SingleLargePage.tsx new file mode 100644 index 000000000..0c4fb96db --- /dev/null +++ b/frontend/src/tools/SingleLargePage.tsx @@ -0,0 +1,80 @@ +import React, { useEffect } from "react"; +import { useTranslation } from "react-i18next"; +import { useEndpointEnabled } from "../hooks/useEndpointConfig"; +import { useFileContext } from "../contexts/FileContext"; +import { useToolFileSelection } from "../contexts/FileSelectionContext"; + +import { createToolFlow } from "../components/tools/shared/createToolFlow"; + +import { useSingleLargePageParameters } from "../hooks/tools/singleLargePage/useSingleLargePageParameters"; +import { useSingleLargePageOperation } from "../hooks/tools/singleLargePage/useSingleLargePageOperation"; +import { BaseToolProps } from "../types/tool"; + +const SingleLargePage = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => { + const { t } = useTranslation(); + const { setCurrentMode } = useFileContext(); + const { selectedFiles } = useToolFileSelection(); + + const singleLargePageParams = useSingleLargePageParameters(); + const singleLargePageOperation = useSingleLargePageOperation(); + + // Endpoint validation + const { enabled: endpointEnabled, loading: endpointLoading } = useEndpointEnabled(singleLargePageParams.getEndpointName()); + + useEffect(() => { + singleLargePageOperation.resetResults(); + onPreviewFile?.(null); + }, [singleLargePageParams.parameters]); + + const handleConvert = async () => { + try { + await singleLargePageOperation.executeOperation(singleLargePageParams.parameters, selectedFiles); + if (singleLargePageOperation.files && onComplete) { + onComplete(singleLargePageOperation.files); + } + } catch (error) { + if (onError) { + onError(error instanceof Error ? error.message : t("pdfToSinglePage.error.failed", "Single large page operation failed")); + } + } + }; + + const handleThumbnailClick = (file: File) => { + onPreviewFile?.(file); + sessionStorage.setItem("previousMode", "single-large-page"); + setCurrentMode("viewer"); + }; + + const handleSettingsReset = () => { + singleLargePageOperation.resetResults(); + onPreviewFile?.(null); + setCurrentMode("single-large-page"); + }; + + const hasFiles = selectedFiles.length > 0; + const hasResults = singleLargePageOperation.files.length > 0 || singleLargePageOperation.downloadUrl !== null; + + return createToolFlow({ + files: { + selectedFiles, + isCollapsed: hasFiles || hasResults, + placeholder: t("pdfToSinglePage.files.placeholder", "Select a PDF file in the main view to get started"), + }, + steps: [], + executeButton: { + text: t("pdfToSinglePage.submit", "Convert To Single Page"), + isVisible: !hasResults, + loadingText: t("loading"), + onClick: handleConvert, + disabled: !singleLargePageParams.validateParameters() || !hasFiles || !endpointEnabled, + }, + review: { + isVisible: hasResults, + operation: singleLargePageOperation, + title: t("pdfToSinglePage.results.title", "Single Page Results"), + onFileClick: handleThumbnailClick, + }, + }); +}; + +export default SingleLargePage; \ No newline at end of file diff --git a/frontend/src/tools/UnlockPdfForms.tsx b/frontend/src/tools/UnlockPdfForms.tsx new file mode 100644 index 000000000..b8aee7894 --- /dev/null +++ b/frontend/src/tools/UnlockPdfForms.tsx @@ -0,0 +1,80 @@ +import React, { useEffect } from "react"; +import { useTranslation } from "react-i18next"; +import { useEndpointEnabled } from "../hooks/useEndpointConfig"; +import { useFileContext } from "../contexts/FileContext"; +import { useToolFileSelection } from "../contexts/FileSelectionContext"; + +import { createToolFlow } from "../components/tools/shared/createToolFlow"; + +import { useUnlockPdfFormsParameters } from "../hooks/tools/unlockPdfForms/useUnlockPdfFormsParameters"; +import { useUnlockPdfFormsOperation } from "../hooks/tools/unlockPdfForms/useUnlockPdfFormsOperation"; +import { BaseToolProps } from "../types/tool"; + +const UnlockPdfForms = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => { + const { t } = useTranslation(); + const { setCurrentMode } = useFileContext(); + const { selectedFiles } = useToolFileSelection(); + + const unlockPdfFormsParams = useUnlockPdfFormsParameters(); + const unlockPdfFormsOperation = useUnlockPdfFormsOperation(); + + // Endpoint validation + const { enabled: endpointEnabled, loading: endpointLoading } = useEndpointEnabled(unlockPdfFormsParams.getEndpointName()); + + useEffect(() => { + unlockPdfFormsOperation.resetResults(); + onPreviewFile?.(null); + }, [unlockPdfFormsParams.parameters]); + + const handleUnlock = async () => { + try { + await unlockPdfFormsOperation.executeOperation(unlockPdfFormsParams.parameters, selectedFiles); + if (unlockPdfFormsOperation.files && onComplete) { + onComplete(unlockPdfFormsOperation.files); + } + } catch (error) { + if (onError) { + onError(error instanceof Error ? error.message : t("unlockPDFForms.error.failed", "Unlock PDF forms operation failed")); + } + } + }; + + const handleThumbnailClick = (file: File) => { + onPreviewFile?.(file); + sessionStorage.setItem("previousMode", "unlockPdfForms"); + setCurrentMode("viewer"); + }; + + const handleSettingsReset = () => { + unlockPdfFormsOperation.resetResults(); + onPreviewFile?.(null); + setCurrentMode("unlockPdfForms"); + }; + + const hasFiles = selectedFiles.length > 0; + const hasResults = unlockPdfFormsOperation.files.length > 0 || unlockPdfFormsOperation.downloadUrl !== null; + + return createToolFlow({ + files: { + selectedFiles, + isCollapsed: hasFiles || hasResults, + placeholder: t("unlockPDFForms.files.placeholder", "Select a PDF file in the main view to get started"), + }, + steps: [], + executeButton: { + text: t("unlockPDFForms.submit", "Unlock Forms"), + isVisible: !hasResults, + loadingText: t("loading"), + onClick: handleUnlock, + disabled: !unlockPdfFormsParams.validateParameters() || !hasFiles || !endpointEnabled, + }, + review: { + isVisible: hasResults, + operation: unlockPdfFormsOperation, + title: t("unlockPDFForms.results.title", "Unlocked Forms Results"), + onFileClick: handleThumbnailClick, + }, + }); +}; + +export default UnlockPdfForms; \ No newline at end of file diff --git a/frontend/src/types/fileContext.ts b/frontend/src/types/fileContext.ts index 1c513b523..d9dde75b7 100644 --- a/frontend/src/types/fileContext.ts +++ b/frontend/src/types/fileContext.ts @@ -19,7 +19,10 @@ export type ModeType = | 'changePermissions' | 'watermark' | 'removePassword' - | 'repair'; + | 'single-large-page' + | 'repair' + | 'unlockPdfForms' + | 'removeCertificateSign'; export type ViewType = 'viewer' | 'pageEditor' | 'fileEditor';