From f2a6e95fcfd50755b0e060f57ddddb4b5e667755 Mon Sep 17 00:00:00 2001 From: EthanHealy01 <80844253+EthanHealy01@users.noreply.github.com> Date: Fri, 26 Sep 2025 12:46:02 +0100 Subject: [PATCH] Feature/remove images (#4503) --- .../public/locales/en-US/translation.json | 14 ++++-- .../src/data/useTranslatedToolRegistry.tsx | 10 +++-- .../removeImage/useRemoveImageOperation.ts | 30 +++++++++++++ .../removeImage/useRemoveImageParameters.ts | 17 +++++++ frontend/src/tools/RemoveImage.tsx | 45 +++++++++++++++++++ 5 files changed, 109 insertions(+), 7 deletions(-) create mode 100644 frontend/src/hooks/tools/removeImage/useRemoveImageOperation.ts create mode 100644 frontend/src/hooks/tools/removeImage/useRemoveImageParameters.ts create mode 100644 frontend/src/tools/RemoveImage.tsx diff --git a/frontend/public/locales/en-US/translation.json b/frontend/public/locales/en-US/translation.json index 5bdde8cb2..331a76511 100644 --- a/frontend/public/locales/en-US/translation.json +++ b/frontend/public/locales/en-US/translation.json @@ -1810,10 +1810,16 @@ } }, "removeImage": { - "title": "Remove image", - "header": "Remove image", - "removeImage": "Remove image", - "submit": "Remove image" + "title": "Remove Images", + "header": "Remove Images", + "removeImage": "Remove Images", + "submit": "Remove Images", + "results": { + "title": "Remove Images Results" + }, + "error": { + "failed": "Failed to remove images from the PDF." + } }, "splitByChapters": { "title": "Split PDF by Chapters", diff --git a/frontend/src/data/useTranslatedToolRegistry.tsx b/frontend/src/data/useTranslatedToolRegistry.tsx index 97aa9725c..c23fe3628 100644 --- a/frontend/src/data/useTranslatedToolRegistry.tsx +++ b/frontend/src/data/useTranslatedToolRegistry.tsx @@ -22,6 +22,7 @@ import AutoRename from "../tools/AutoRename"; import SingleLargePage from "../tools/SingleLargePage"; import UnlockPdfForms from "../tools/UnlockPdfForms"; import RemoveCertificateSign from "../tools/RemoveCertificateSign"; +import RemoveImage from "../tools/RemoveImage"; import CertSign from "../tools/CertSign"; import BookletImposition from "../tools/BookletImposition"; import Flatten from "../tools/Flatten"; @@ -533,11 +534,14 @@ export function useFlatToolRegistry(): ToolRegistry { }, removeImage: { icon: , - name: t("home.removeImage.title", "Remove Image"), - component: null, - description: t("home.removeImage.desc", "Remove images from PDF documents"), + name: t("home.removeImage.title", "Remove Images"), + component: RemoveImage, + description: t("home.removeImage.desc", "Remove all images from a PDF document"), categoryId: ToolCategoryId.STANDARD_TOOLS, subcategoryId: SubcategoryId.REMOVAL, + maxFiles: -1, + endpoints: ["remove-image-pdf"], + operationConfig: undefined, synonyms: getSynonyms(t, "removeImage"), }, removePassword: { diff --git a/frontend/src/hooks/tools/removeImage/useRemoveImageOperation.ts b/frontend/src/hooks/tools/removeImage/useRemoveImageOperation.ts new file mode 100644 index 000000000..0f6649598 --- /dev/null +++ b/frontend/src/hooks/tools/removeImage/useRemoveImageOperation.ts @@ -0,0 +1,30 @@ +import { useTranslation } from 'react-i18next'; +import { useToolOperation, ToolOperationConfig, ToolType } from '../shared/useToolOperation'; +import { createStandardErrorHandler } from '../../../utils/toolErrorHandler'; +import type { RemoveImageParameters } from './useRemoveImageParameters'; + +export const buildRemoveImageFormData = (_params: RemoveImageParameters, file: File): FormData => { + const formData = new FormData(); + formData.append('fileInput', file); + return formData; +}; + +export const removeImageOperationConfig: ToolOperationConfig = { + toolType: ToolType.singleFile, + buildFormData: buildRemoveImageFormData, + operationType: 'removeImage', + endpoint: '/api/v1/general/remove-image-pdf', +}; + +export const useRemoveImageOperation = () => { + const { t } = useTranslation(); + + return useToolOperation({ + ...removeImageOperationConfig, + getErrorMessage: createStandardErrorHandler( + t('removeImage.error.failed', 'Failed to remove images from the PDF.') + ), + }); +}; + + diff --git a/frontend/src/hooks/tools/removeImage/useRemoveImageParameters.ts b/frontend/src/hooks/tools/removeImage/useRemoveImageParameters.ts new file mode 100644 index 000000000..f57a9e93e --- /dev/null +++ b/frontend/src/hooks/tools/removeImage/useRemoveImageParameters.ts @@ -0,0 +1,17 @@ +import { useBaseParameters } from '../shared/useBaseParameters'; +import type { BaseParametersHook } from '../shared/useBaseParameters'; + +export type RemoveImageParameters = Record; + +export const defaultParameters: RemoveImageParameters = {}; + +export type RemoveImageParametersHook = BaseParametersHook; + +export const useRemoveImageParameters = (): RemoveImageParametersHook => { + return useBaseParameters({ + defaultParameters, + endpointName: 'remove-image-pdf', + }); +}; + + diff --git a/frontend/src/tools/RemoveImage.tsx b/frontend/src/tools/RemoveImage.tsx new file mode 100644 index 000000000..f636f9f65 --- /dev/null +++ b/frontend/src/tools/RemoveImage.tsx @@ -0,0 +1,45 @@ +import { useTranslation } from "react-i18next"; +import { createToolFlow } from "../components/tools/shared/createToolFlow"; +import { useRemoveImageParameters } from "../hooks/tools/removeImage/useRemoveImageParameters"; +import { useRemoveImageOperation } from "../hooks/tools/removeImage/useRemoveImageOperation"; +import { useBaseTool } from "../hooks/tools/shared/useBaseTool"; +import { BaseToolProps, ToolComponent } from "../types/tool"; + +const RemoveImage = (props: BaseToolProps) => { + const { t } = useTranslation(); + + const base = useBaseTool( + 'removeImage', + useRemoveImageParameters, + useRemoveImageOperation, + props + ); + + return createToolFlow({ + files: { + selectedFiles: base.selectedFiles, + isCollapsed: base.hasResults, + }, + steps: [], + executeButton: { + text: t("removeImage.submit", "Remove Images"), + isVisible: !base.hasResults, + loadingText: t("loading"), + onClick: base.handleExecute, + disabled: !base.params.validateParameters() || !base.hasFiles || !base.endpointEnabled, + }, + review: { + isVisible: base.hasResults, + operation: base.operation, + title: t("removeImage.results.title", "Remove Images Results"), + onFileClick: base.handleThumbnailClick, + onUndo: base.handleUndo, + }, + }); +}; + +RemoveImage.tool = () => useRemoveImageOperation; + +export default RemoveImage as ToolComponent; + +