mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2025-08-26 14:19:24 +00:00
Merge remote-tracking branch 'origin/V2' into feature/v2/file-handling-improvements
This commit is contained in:
commit
c8b3db295c
@ -366,14 +366,6 @@
|
||||
"title": "Convert",
|
||||
"desc": "Convert files between different formats"
|
||||
},
|
||||
"imageToPDF": {
|
||||
"title": "Image to PDF",
|
||||
"desc": "Convert a image (PNG, JPEG, GIF) to PDF."
|
||||
},
|
||||
"pdfToImage": {
|
||||
"title": "PDF to Image",
|
||||
"desc": "Convert a PDF to a image. (PNG, JPEG, GIF)"
|
||||
},
|
||||
"pdfOrganiser": {
|
||||
"title": "Organise",
|
||||
"desc": "Remove/Rearrange pages in any order"
|
||||
@ -390,14 +382,6 @@
|
||||
"title": "Add Watermark",
|
||||
"desc": "Add a custom watermark to your PDF document."
|
||||
},
|
||||
"permissions": {
|
||||
"title": "Change Permissions",
|
||||
"desc": "Change the permissions of your PDF document"
|
||||
},
|
||||
"pageRemover": {
|
||||
"title": "Remove",
|
||||
"desc": "Delete unwanted pages from your PDF document."
|
||||
},
|
||||
"removePassword": {
|
||||
"title": "Remove Password",
|
||||
"desc": "Remove password protection from your PDF document."
|
||||
@ -414,10 +398,6 @@
|
||||
"title": "Change Metadata",
|
||||
"desc": "Change/Remove/Add metadata from a PDF document"
|
||||
},
|
||||
"fileToPDF": {
|
||||
"title": "Convert file to PDF",
|
||||
"desc": "Convert nearly any file to PDF (DOCX, PNG, XLS, PPT, TXT and more)"
|
||||
},
|
||||
"ocr": {
|
||||
"title": "OCR / Cleanup scans",
|
||||
"desc": "Cleanup scans and detects text from images within a PDF and re-adds it as text."
|
||||
@ -426,30 +406,6 @@
|
||||
"title": "Extract Images",
|
||||
"desc": "Extracts all images from a PDF and saves them to zip"
|
||||
},
|
||||
"pdfToPDFA": {
|
||||
"title": "PDF to PDF/A",
|
||||
"desc": "Convert PDF to PDF/A for long-term storage"
|
||||
},
|
||||
"PDFToWord": {
|
||||
"title": "PDF to Word",
|
||||
"desc": "Convert PDF to Word formats (DOC, DOCX and ODT)"
|
||||
},
|
||||
"PDFToPresentation": {
|
||||
"title": "PDF to Presentation",
|
||||
"desc": "Convert PDF to Presentation formats (PPT, PPTX and ODP)"
|
||||
},
|
||||
"PDFToText": {
|
||||
"title": "PDF to RTF (Text)",
|
||||
"desc": "Convert PDF to Text or RTF format"
|
||||
},
|
||||
"PDFToHTML": {
|
||||
"title": "PDF to HTML",
|
||||
"desc": "Convert PDF to HTML format"
|
||||
},
|
||||
"PDFToXML": {
|
||||
"title": "PDF to XML",
|
||||
"desc": "Convert PDF to XML format"
|
||||
},
|
||||
"ScannerImageSplit": {
|
||||
"title": "Detect/Split Scanned photos",
|
||||
"desc": "Splits multiple photos from within a photo/PDF"
|
||||
@ -518,34 +474,14 @@
|
||||
"title": "Auto Split Pages",
|
||||
"desc": "Auto Split Scanned PDF with physical scanned page splitter QR Code"
|
||||
},
|
||||
"sanitizePdf": {
|
||||
"sanitize": {
|
||||
"title": "Sanitise",
|
||||
"desc": "Remove scripts and other elements from PDF files"
|
||||
},
|
||||
"URLToPDF": {
|
||||
"title": "URL/Website To PDF",
|
||||
"desc": "Converts any http(s)URL to PDF"
|
||||
},
|
||||
"HTMLToPDF": {
|
||||
"title": "HTML to PDF",
|
||||
"desc": "Converts any HTML file or zip to PDF"
|
||||
},
|
||||
"MarkdownToPDF": {
|
||||
"title": "Markdown to PDF",
|
||||
"desc": "Converts any Markdown file to PDF"
|
||||
},
|
||||
"PDFToMarkdown": {
|
||||
"title": "PDF to Markdown",
|
||||
"desc": "Converts any PDF to Markdown"
|
||||
"desc": "Remove potentially harmful elements from PDF files"
|
||||
},
|
||||
"getPdfInfo": {
|
||||
"title": "Get ALL Info on PDF",
|
||||
"desc": "Grabs any and all information possible on PDFs"
|
||||
},
|
||||
"pageExtracter": {
|
||||
"title": "Extract page(s)",
|
||||
"desc": "Extracts select pages from PDF"
|
||||
},
|
||||
"pdfToSinglePage": {
|
||||
"title": "PDF to Single Large Page",
|
||||
"desc": "Merges all PDF pages into one large single page"
|
||||
@ -562,14 +498,6 @@
|
||||
"title": "Manual Redaction",
|
||||
"desc": "Redacts a PDF based on selected text, drawn shapes and/or selected page(s)"
|
||||
},
|
||||
"PDFToCSV": {
|
||||
"title": "PDF to CSV",
|
||||
"desc": "Extracts Tables from a PDF converting it to CSV"
|
||||
},
|
||||
"split-by-size-or-count": {
|
||||
"title": "Auto Split by Size/Count",
|
||||
"desc": "Split a single PDF into multiple documents based on size, page count, or document count"
|
||||
},
|
||||
"overlay-pdfs": {
|
||||
"title": "Overlay PDFs",
|
||||
"desc": "Overlays PDFs on-top of another PDF"
|
||||
@ -625,6 +553,54 @@
|
||||
"reorganizePages": {
|
||||
"title": "Reorganize Pages",
|
||||
"desc": "Rearrange, duplicate, or delete PDF pages with visual drag-and-drop control."
|
||||
},
|
||||
"extractPages": {
|
||||
"title": "Extract Pages",
|
||||
"desc": "Extract specific pages from a PDF document"
|
||||
},
|
||||
"removePages": {
|
||||
"title": "Remove Pages",
|
||||
"desc": "Remove specific pages from a PDF document"
|
||||
},
|
||||
"removeImagePdf": {
|
||||
"title": "Remove Image",
|
||||
"desc": "Remove images from PDF documents"
|
||||
},
|
||||
"autoSizeSplitPDF": {
|
||||
"title": "Auto Split by Size/Count",
|
||||
"desc": "Automatically split PDFs by file size or page count"
|
||||
},
|
||||
"adjust-contrast": {
|
||||
"title": "Adjust Colours/Contrast",
|
||||
"desc": "Adjust colours and contrast of PDF documents"
|
||||
},
|
||||
"replaceColorPdf": {
|
||||
"title": "Replace & Invert Colour",
|
||||
"desc": "Replace or invert colours in PDF documents"
|
||||
},
|
||||
"devApi": {
|
||||
"title": "API",
|
||||
"desc": "Link to API documentation"
|
||||
},
|
||||
"devFolderScanning": {
|
||||
"title": "Automated Folder Scanning",
|
||||
"desc": "Link to automated folder scanning guide"
|
||||
},
|
||||
"devSsoGuide": {
|
||||
"title": "SSO Guide",
|
||||
"desc": "Link to SSO guide"
|
||||
},
|
||||
"devAirgapped": {
|
||||
"title": "Air-gapped Setup",
|
||||
"desc": "Link to air-gapped setup guide"
|
||||
},
|
||||
"addPassword": {
|
||||
"title": "Add Password",
|
||||
"desc": "Add password protection and restrictions to PDF files"
|
||||
},
|
||||
"changePermissions": {
|
||||
"title": "Change Permissions",
|
||||
"desc": "Change document restrictions and permissions"
|
||||
}
|
||||
},
|
||||
"viewPdf": {
|
||||
|
@ -1,7 +1,7 @@
|
||||
import React, { useState } from "react";
|
||||
import { Button, Stack, Text, NumberInput, Select, Divider } from "@mantine/core";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { CompressParameters } from "../../../hooks/tools/compress/useCompressOperation";
|
||||
import { CompressParameters } from "../../../hooks/tools/compress/useCompressParameters";
|
||||
|
||||
interface CompressSettingsProps {
|
||||
parameters: CompressParameters;
|
||||
|
@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
import { Stack, Text, Checkbox } from '@mantine/core';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { OCRParameters } from './OCRSettings';
|
||||
import { OCRParameters } from '../../../hooks/tools/ocr/useOCRParameters';
|
||||
|
||||
export interface AdvancedOCRParameters {
|
||||
advancedOptions: string[];
|
||||
|
@ -2,13 +2,7 @@ import React from 'react';
|
||||
import { Stack, Select, Text, Divider } from '@mantine/core';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import LanguagePicker from './LanguagePicker';
|
||||
|
||||
export interface OCRParameters {
|
||||
languages: string[];
|
||||
ocrType: string;
|
||||
ocrRenderType: string;
|
||||
additionalOptions: string[];
|
||||
}
|
||||
import { OCRParameters } from '../../../hooks/tools/ocr/useOCRParameters';
|
||||
|
||||
interface OCRSettingsProps {
|
||||
parameters: OCRParameters;
|
||||
|
@ -1,5 +1,3 @@
|
||||
import { AddWatermarkParameters } from "../hooks/tools/addWatermark/useAddWatermarkParameters";
|
||||
|
||||
export interface AlphabetOption {
|
||||
value: string;
|
||||
label: string;
|
||||
@ -13,16 +11,3 @@ export const alphabetOptions: AlphabetOption[] = [
|
||||
{ value: "chinese", label: "简体中文" },
|
||||
{ value: "thai", label: "ไทย" },
|
||||
];
|
||||
|
||||
export const defaultWatermarkParameters: AddWatermarkParameters = {
|
||||
watermarkType: undefined,
|
||||
watermarkText: '',
|
||||
fontSize: 12,
|
||||
rotation: 0,
|
||||
opacity: 50,
|
||||
widthSpacer: 50,
|
||||
heightSpacer: 50,
|
||||
alphabet: 'roman',
|
||||
customColor: '#d3d3d3',
|
||||
convertPDFToImage: false
|
||||
};
|
@ -1,5 +1,6 @@
|
||||
import { type TFunction } from 'i18next';
|
||||
import React from 'react';
|
||||
import { BaseToolProps } from '../types/tool';
|
||||
|
||||
export enum SubcategoryId {
|
||||
SIGNING = 'signing',
|
||||
@ -24,7 +25,7 @@ export enum ToolCategory {
|
||||
export type ToolRegistryEntry = {
|
||||
icon: React.ReactNode;
|
||||
name: string;
|
||||
component: React.ComponentType<any> | null;
|
||||
component: React.ComponentType<BaseToolProps> | null;
|
||||
view: 'sign' | 'security' | 'format' | 'extract' | 'view' | 'merge' | 'pageEditor' | 'convert' | 'redact' | 'split' | 'convert' | 'remove' | 'compress' | 'external';
|
||||
description: string;
|
||||
category: ToolCategory;
|
||||
|
@ -15,13 +15,13 @@ import SingleLargePage from '../tools/SingleLargePage';
|
||||
import UnlockPdfForms from '../tools/UnlockPdfForms';
|
||||
import RemoveCertificateSign from '../tools/RemoveCertificateSign';
|
||||
|
||||
|
||||
const showPlaceholderTools = false; // For development purposes. Allows seeing the full list of tools, even if they're unimplemented
|
||||
|
||||
// Hook to get the translated tool registry
|
||||
export function useFlatToolRegistry(): ToolRegistry {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return {
|
||||
const allTools: ToolRegistry = {
|
||||
// Signing
|
||||
|
||||
"certSign": {
|
||||
@ -57,7 +57,7 @@ export function useFlatToolRegistry(): ToolRegistry {
|
||||
maxFiles: -1,
|
||||
endpoints: ["add-password"]
|
||||
},
|
||||
"add-watermark": {
|
||||
"watermark": {
|
||||
icon: <span className="material-symbols-rounded">branding_watermark</span>,
|
||||
name: t("home.watermark.title", "Add Watermark"),
|
||||
component: AddWatermark,
|
||||
@ -217,12 +217,12 @@ export function useFlatToolRegistry(): ToolRegistry {
|
||||
category: ToolCategory.STANDARD_TOOLS,
|
||||
subcategory: SubcategoryId.PAGE_FORMATTING
|
||||
},
|
||||
"add-page-numbers": {
|
||||
"addPageNumbers": {
|
||||
icon: <span className="material-symbols-rounded">123</span>,
|
||||
name: t("home.add-page-numbers.title", "Add Page Numbers"),
|
||||
name: t("home.addPageNumbers.title", "Add Page Numbers"),
|
||||
component: null,
|
||||
view: "format",
|
||||
description: t("home.add-page-numbers.desc", "Add Page numbers throughout a document in a set location"),
|
||||
description: t("home.addPageNumbers.desc", "Add Page numbers throughout a document in a set location"),
|
||||
category: ToolCategory.STANDARD_TOOLS,
|
||||
subcategory: SubcategoryId.PAGE_FORMATTING
|
||||
},
|
||||
@ -237,10 +237,10 @@ export function useFlatToolRegistry(): ToolRegistry {
|
||||
},
|
||||
"single-large-page": {
|
||||
icon: <span className="material-symbols-rounded">looks_one</span>,
|
||||
name: t("home.PdfToSinglePage.title", "PDF to Single Large Page"),
|
||||
name: t("home.pdfToSinglePage.title", "PDF to Single Large Page"),
|
||||
component: SingleLargePage,
|
||||
view: "format",
|
||||
description: t("home.PdfToSinglePage.desc", "Merges all PDF pages into one large single page"),
|
||||
description: t("home.pdfToSinglePage.desc", "Merges all PDF pages into one large single page"),
|
||||
category: ToolCategory.STANDARD_TOOLS,
|
||||
subcategory: SubcategoryId.PAGE_FORMATTING,
|
||||
maxFiles: -1,
|
||||
@ -259,12 +259,12 @@ export function useFlatToolRegistry(): ToolRegistry {
|
||||
|
||||
// Extraction
|
||||
|
||||
"extract-pages": {
|
||||
"extractPages": {
|
||||
icon: <span className="material-symbols-rounded">upload</span>,
|
||||
name: t("home.extractPage.title", "Extract Pages"),
|
||||
name: t("home.extractPages.title", "Extract Pages"),
|
||||
component: null,
|
||||
view: "extract",
|
||||
description: t("home.extractPage.desc", "Extract specific pages from a PDF document"),
|
||||
description: t("home.extractPages.desc", "Extract specific pages from a PDF document"),
|
||||
category: ToolCategory.STANDARD_TOOLS,
|
||||
subcategory: SubcategoryId.EXTRACTION
|
||||
},
|
||||
@ -281,7 +281,7 @@ export function useFlatToolRegistry(): ToolRegistry {
|
||||
|
||||
// Removal
|
||||
|
||||
"remove": {
|
||||
"removePages": {
|
||||
icon: <span className="material-symbols-rounded">delete</span>,
|
||||
name: t("home.removePages.title", "Remove Pages"),
|
||||
component: null,
|
||||
@ -331,10 +331,10 @@ export function useFlatToolRegistry(): ToolRegistry {
|
||||
},
|
||||
"remove-certificate-sign": {
|
||||
icon: <span className="material-symbols-rounded">remove_moderator</span>,
|
||||
name: t("home.removeCertSign.title", "Remove Certificate Signatures"),
|
||||
name: t("home.removeCertSign.title", "Remove Certificate Sign"),
|
||||
component: RemoveCertificateSign,
|
||||
view: "security",
|
||||
description: t("home.removeCertSign.desc", "Remove digital signatures from PDF documents"),
|
||||
description: t("home.removeCertSign.desc", "Remove digital signature from PDF documents"),
|
||||
category: ToolCategory.STANDARD_TOOLS,
|
||||
subcategory: SubcategoryId.REMOVAL,
|
||||
maxFiles: -1,
|
||||
@ -384,12 +384,12 @@ export function useFlatToolRegistry(): ToolRegistry {
|
||||
|
||||
// Advanced Formatting
|
||||
|
||||
"adjust-colors-contrast": {
|
||||
"adjustContrast": {
|
||||
icon: <span className="material-symbols-rounded">palette</span>,
|
||||
name: t("home.adjust-contrast.title", "Adjust Colors/Contrast"),
|
||||
name: t("home.adjustContrast.title", "Adjust Colors/Contrast"),
|
||||
component: null,
|
||||
view: "format",
|
||||
description: t("home.adjust-contrast.desc", "Adjust colors and contrast of PDF documents"),
|
||||
description: t("home.adjustContrast.desc", "Adjust colors and contrast of PDF documents"),
|
||||
category: ToolCategory.ADVANCED_TOOLS,
|
||||
subcategory: SubcategoryId.ADVANCED_FORMATTING
|
||||
},
|
||||
@ -523,22 +523,22 @@ export function useFlatToolRegistry(): ToolRegistry {
|
||||
category: ToolCategory.RECOMMENDED_TOOLS,
|
||||
subcategory: SubcategoryId.GENERAL
|
||||
},
|
||||
"compressPdfs": {
|
||||
"compress": {
|
||||
icon: <span className="material-symbols-rounded">zoom_in_map</span>,
|
||||
name: t("home.compressPdfs.title", "Compress"),
|
||||
name: t("home.compress.title", "Compress"),
|
||||
component: CompressPdfPanel,
|
||||
view: "compress",
|
||||
description: t("home.compressPdfs.desc", "Compress PDFs to reduce their file size."),
|
||||
description: t("home.compress.desc", "Compress PDFs to reduce their file size."),
|
||||
category: ToolCategory.RECOMMENDED_TOOLS,
|
||||
subcategory: SubcategoryId.GENERAL,
|
||||
maxFiles: -1
|
||||
},
|
||||
"convert": {
|
||||
icon: <span className="material-symbols-rounded">sync_alt</span>,
|
||||
name: t("home.fileToPDF.title", "Convert"),
|
||||
name: t("home.convert.title", "Convert"),
|
||||
component: ConvertPanel,
|
||||
view: "convert",
|
||||
description: t("home.fileToPDF.desc", "Convert files to and from PDF format"),
|
||||
description: t("home.convert.desc", "Convert files to and from PDF format"),
|
||||
category: ToolCategory.RECOMMENDED_TOOLS,
|
||||
subcategory: SubcategoryId.GENERAL,
|
||||
maxFiles: -1,
|
||||
@ -617,4 +617,16 @@ export function useFlatToolRegistry(): ToolRegistry {
|
||||
subcategory: SubcategoryId.GENERAL
|
||||
},
|
||||
};
|
||||
|
||||
if (showPlaceholderTools) {
|
||||
return allTools;
|
||||
} else {
|
||||
const filteredTools = Object.keys(allTools)
|
||||
.filter(key => allTools[key].component !== null || allTools[key].link)
|
||||
.reduce((obj, key) => {
|
||||
obj[key] = allTools[key];
|
||||
return obj;
|
||||
}, {} as ToolRegistry);
|
||||
return filteredTools;
|
||||
}
|
||||
}
|
@ -1,7 +1,8 @@
|
||||
import { useState } from 'react';
|
||||
import { ChangePermissionsParameters, ChangePermissionsParametersHook, useChangePermissionsParameters } from '../changePermissions/useChangePermissionsParameters';
|
||||
import { BaseParameters } from '../../../types/parameters';
|
||||
import { useBaseParameters, BaseParametersHook } from '../shared/useBaseParameters';
|
||||
|
||||
export interface AddPasswordParameters {
|
||||
export interface AddPasswordParameters extends BaseParameters {
|
||||
password: string;
|
||||
ownerPassword: string;
|
||||
keyLength: number;
|
||||
@ -11,14 +12,9 @@ export interface AddPasswordFullParameters extends AddPasswordParameters {
|
||||
permissions: ChangePermissionsParameters;
|
||||
}
|
||||
|
||||
export interface AddPasswordParametersHook {
|
||||
export interface AddPasswordParametersHook extends BaseParametersHook<AddPasswordParameters> {
|
||||
fullParameters: AddPasswordFullParameters;
|
||||
parameters: AddPasswordParameters;
|
||||
permissions: ChangePermissionsParametersHook;
|
||||
updateParameter: <K extends keyof AddPasswordParameters>(parameter: K, value: AddPasswordParameters[K]) => void;
|
||||
resetParameters: () => void;
|
||||
validateParameters: () => boolean;
|
||||
getEndpointName: () => string;
|
||||
}
|
||||
|
||||
export const defaultParameters: AddPasswordParameters = {
|
||||
@ -28,42 +24,31 @@ export const defaultParameters: AddPasswordParameters = {
|
||||
};
|
||||
|
||||
export const useAddPasswordParameters = (): AddPasswordParametersHook => {
|
||||
const [parameters, setParameters] = useState<AddPasswordParameters>(defaultParameters);
|
||||
const permissions = useChangePermissionsParameters();
|
||||
|
||||
const baseHook = useBaseParameters({
|
||||
defaultParameters,
|
||||
endpointName: 'add-password',
|
||||
validateFn: () => {
|
||||
// No required parameters for Add Password. Defer to permissions validation.
|
||||
return permissions.validateParameters();
|
||||
},
|
||||
});
|
||||
|
||||
const fullParameters: AddPasswordFullParameters = {
|
||||
...parameters,
|
||||
...baseHook.parameters,
|
||||
permissions: permissions.parameters,
|
||||
};
|
||||
|
||||
const updateParameter = <K extends keyof AddPasswordParameters>(parameter: K, value: AddPasswordParameters[K]) => {
|
||||
setParameters(prev => ({
|
||||
...prev,
|
||||
[parameter]: value,
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const resetParameters = () => {
|
||||
setParameters(defaultParameters);
|
||||
baseHook.resetParameters();
|
||||
permissions.resetParameters();
|
||||
};
|
||||
|
||||
const validateParameters = () => {
|
||||
// No required parameters for Add Password. Defer to permissions validation.
|
||||
return permissions.validateParameters();
|
||||
};
|
||||
|
||||
const getEndpointName = () => {
|
||||
return 'add-password';
|
||||
};
|
||||
|
||||
return {
|
||||
...baseHook,
|
||||
fullParameters,
|
||||
parameters,
|
||||
permissions,
|
||||
updateParameter,
|
||||
resetParameters,
|
||||
validateParameters,
|
||||
getEndpointName,
|
||||
};
|
||||
};
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { useState, useCallback } from 'react';
|
||||
import { defaultWatermarkParameters } from '../../../constants/addWatermarkConstants';
|
||||
import { BaseParameters } from '../../../types/parameters';
|
||||
import { useBaseParameters, BaseParametersHook } from '../shared/useBaseParameters';
|
||||
|
||||
export interface AddWatermarkParameters {
|
||||
export interface AddWatermarkParameters extends BaseParameters {
|
||||
watermarkType?: 'text' | 'image';
|
||||
watermarkText: string;
|
||||
watermarkImage?: File;
|
||||
@ -15,36 +15,34 @@ export interface AddWatermarkParameters {
|
||||
convertPDFToImage: boolean;
|
||||
}
|
||||
|
||||
export const defaultParameters: AddWatermarkParameters = {
|
||||
watermarkType: undefined,
|
||||
watermarkText: '',
|
||||
fontSize: 12,
|
||||
rotation: 0,
|
||||
opacity: 50,
|
||||
widthSpacer: 50,
|
||||
heightSpacer: 50,
|
||||
alphabet: 'roman',
|
||||
customColor: '#d3d3d3',
|
||||
convertPDFToImage: false
|
||||
};
|
||||
|
||||
export const useAddWatermarkParameters = () => {
|
||||
const [parameters, setParameters] = useState<AddWatermarkParameters>(defaultWatermarkParameters);
|
||||
export type AddWatermarkParametersHook = BaseParametersHook<AddWatermarkParameters>;
|
||||
|
||||
const updateParameter = useCallback(<K extends keyof AddWatermarkParameters>(
|
||||
key: K,
|
||||
value: AddWatermarkParameters[K]
|
||||
) => {
|
||||
setParameters(prev => ({ ...prev, [key]: value }));
|
||||
}, []);
|
||||
|
||||
const resetParameters = useCallback(() => {
|
||||
setParameters(defaultWatermarkParameters);
|
||||
}, []);
|
||||
|
||||
const validateParameters = useCallback((): boolean => {
|
||||
if (!parameters.watermarkType) {
|
||||
export const useAddWatermarkParameters = (): AddWatermarkParametersHook => {
|
||||
return useBaseParameters({
|
||||
defaultParameters: defaultParameters,
|
||||
endpointName: 'add-watermark',
|
||||
validateFn: (params): boolean => {
|
||||
if (!params.watermarkType) {
|
||||
return false;
|
||||
}
|
||||
if (parameters.watermarkType === 'text') {
|
||||
return parameters.watermarkText.trim().length > 0;
|
||||
if (params.watermarkType === 'text') {
|
||||
return params.watermarkText.trim().length > 0;
|
||||
} else {
|
||||
return parameters.watermarkImage !== undefined;
|
||||
return params.watermarkImage !== undefined;
|
||||
}
|
||||
}, [parameters]);
|
||||
|
||||
return {
|
||||
parameters,
|
||||
updateParameter,
|
||||
resetParameters,
|
||||
validateParameters
|
||||
};
|
||||
},
|
||||
});
|
||||
};
|
@ -1,6 +1,7 @@
|
||||
import { useState } from 'react';
|
||||
import { BaseParameters } from '../../../types/parameters';
|
||||
import { useBaseParameters, BaseParametersHook } from '../shared/useBaseParameters';
|
||||
|
||||
export interface ChangePermissionsParameters {
|
||||
export interface ChangePermissionsParameters extends BaseParameters {
|
||||
preventAssembly: boolean;
|
||||
preventExtractContent: boolean;
|
||||
preventExtractForAccessibility: boolean;
|
||||
@ -11,14 +12,6 @@ export interface ChangePermissionsParameters {
|
||||
preventPrintingFaithful: boolean;
|
||||
}
|
||||
|
||||
export interface ChangePermissionsParametersHook {
|
||||
parameters: ChangePermissionsParameters;
|
||||
updateParameter: (parameter: keyof ChangePermissionsParameters, value: boolean) => void;
|
||||
resetParameters: () => void;
|
||||
validateParameters: () => boolean;
|
||||
getEndpointName: () => string;
|
||||
}
|
||||
|
||||
export const defaultParameters: ChangePermissionsParameters = {
|
||||
preventAssembly: false,
|
||||
preventExtractContent: false,
|
||||
@ -30,35 +23,11 @@ export const defaultParameters: ChangePermissionsParameters = {
|
||||
preventPrintingFaithful: false,
|
||||
};
|
||||
|
||||
export type ChangePermissionsParametersHook = BaseParametersHook<ChangePermissionsParameters>;
|
||||
|
||||
export const useChangePermissionsParameters = (): ChangePermissionsParametersHook => {
|
||||
const [parameters, setParameters] = useState<ChangePermissionsParameters>(defaultParameters);
|
||||
|
||||
const updateParameter = <K extends keyof ChangePermissionsParameters>(parameter: K, value: ChangePermissionsParameters[K]) => {
|
||||
setParameters(prev => ({
|
||||
...prev,
|
||||
[parameter]: value,
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const resetParameters = () => {
|
||||
setParameters(defaultParameters);
|
||||
};
|
||||
|
||||
const validateParameters = () => {
|
||||
// Always valid - any combination of permissions is allowed
|
||||
return true;
|
||||
};
|
||||
|
||||
const getEndpointName = () => {
|
||||
return 'add-password'; // Change Permissions is a fake endpoint for the Add Password tool
|
||||
};
|
||||
|
||||
return {
|
||||
parameters,
|
||||
updateParameter,
|
||||
resetParameters,
|
||||
validateParameters,
|
||||
getEndpointName,
|
||||
};
|
||||
return useBaseParameters({
|
||||
defaultParameters,
|
||||
endpointName: 'add-password', // Change Permissions is a fake endpoint for the Add Password tool
|
||||
});
|
||||
};
|
||||
|
@ -1,15 +1,7 @@
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useToolOperation, ToolOperationConfig } from '../shared/useToolOperation';
|
||||
import { useToolOperation } from '../shared/useToolOperation';
|
||||
import { createStandardErrorHandler } from '../../../utils/toolErrorHandler';
|
||||
|
||||
export interface CompressParameters {
|
||||
compressionLevel: number;
|
||||
grayscale: boolean;
|
||||
expectedSize: string;
|
||||
compressionMethod: 'quality' | 'filesize';
|
||||
fileSizeValue: string;
|
||||
fileSizeUnit: 'KB' | 'MB';
|
||||
}
|
||||
import { CompressParameters } from './useCompressParameters';
|
||||
|
||||
const buildFormData = (parameters: CompressParameters, file: File): FormData => {
|
||||
const formData = new FormData();
|
||||
|
@ -1,15 +1,16 @@
|
||||
import { useState } from 'react';
|
||||
import { CompressParameters } from './useCompressOperation';
|
||||
import { BaseParameters } from '../../../types/parameters';
|
||||
import { useBaseParameters, BaseParametersHook } from '../shared/useBaseParameters';
|
||||
|
||||
export interface CompressParametersHook {
|
||||
parameters: CompressParameters;
|
||||
updateParameter: (parameter: keyof CompressParameters, value: string | boolean | number) => void;
|
||||
resetParameters: () => void;
|
||||
validateParameters: () => boolean;
|
||||
getEndpointName: () => string;
|
||||
export interface CompressParameters extends BaseParameters {
|
||||
compressionLevel: number;
|
||||
grayscale: boolean;
|
||||
expectedSize: string;
|
||||
compressionMethod: 'quality' | 'filesize';
|
||||
fileSizeValue: string;
|
||||
fileSizeUnit: 'KB' | 'MB';
|
||||
}
|
||||
|
||||
const initialParameters: CompressParameters = {
|
||||
const defaultParameters: CompressParameters = {
|
||||
compressionLevel: 5,
|
||||
grayscale: false,
|
||||
expectedSize: '',
|
||||
@ -18,32 +19,15 @@ const initialParameters: CompressParameters = {
|
||||
fileSizeUnit: 'MB',
|
||||
};
|
||||
|
||||
export type CompressParametersHook = BaseParametersHook<CompressParameters>;
|
||||
|
||||
export const useCompressParameters = (): CompressParametersHook => {
|
||||
const [parameters, setParameters] = useState<CompressParameters>(initialParameters);
|
||||
|
||||
const updateParameter = (parameter: keyof CompressParameters, value: string | boolean | number) => {
|
||||
setParameters(prev => ({ ...prev, [parameter]: value }));
|
||||
};
|
||||
|
||||
const resetParameters = () => {
|
||||
setParameters(initialParameters);
|
||||
};
|
||||
|
||||
const validateParameters = () => {
|
||||
return useBaseParameters({
|
||||
defaultParameters,
|
||||
endpointName: 'compress-pdf',
|
||||
validateFn: (params) => {
|
||||
// For compression, we only need to validate that compression level is within range
|
||||
// and that at least one file is selected (at least, I think that's all we need to do here)
|
||||
return parameters.compressionLevel >= 1 && parameters.compressionLevel <= 9;
|
||||
};
|
||||
|
||||
const getEndpointName = () => {
|
||||
return 'compress-pdf';
|
||||
};
|
||||
|
||||
return {
|
||||
parameters,
|
||||
updateParameter,
|
||||
resetParameters,
|
||||
validateParameters,
|
||||
getEndpointName,
|
||||
};
|
||||
return params.compressionLevel >= 1 && params.compressionLevel <= 9;
|
||||
},
|
||||
});
|
||||
};
|
@ -5,6 +5,7 @@
|
||||
import { describe, test, expect } from 'vitest';
|
||||
import { renderHook, act } from '@testing-library/react';
|
||||
import { useConvertParameters } from './useConvertParameters';
|
||||
import { FIT_OPTIONS } from '../../../constants/convertConstants';
|
||||
|
||||
describe('useConvertParameters', () => {
|
||||
|
||||
@ -44,13 +45,19 @@ describe('useConvertParameters', () => {
|
||||
result.current.updateParameter('imageOptions', {
|
||||
colorType: 'grayscale',
|
||||
dpi: 150,
|
||||
singleOrMultiple: 'single'
|
||||
singleOrMultiple: 'single',
|
||||
fitOption: FIT_OPTIONS.FILL_PAGE,
|
||||
autoRotate: false,
|
||||
combineImages: false,
|
||||
});
|
||||
});
|
||||
|
||||
expect(result.current.parameters.imageOptions.colorType).toBe('grayscale');
|
||||
expect(result.current.parameters.imageOptions.dpi).toBe(150);
|
||||
expect(result.current.parameters.imageOptions.singleOrMultiple).toBe('single');
|
||||
expect(result.current.parameters.imageOptions.fitOption).toBe(FIT_OPTIONS.FILL_PAGE);
|
||||
expect(result.current.parameters.imageOptions.autoRotate).toBe(false);
|
||||
expect(result.current.parameters.imageOptions.combineImages).toBe(false);
|
||||
});
|
||||
|
||||
test('should update nested HTML options', () => {
|
||||
|
@ -1,4 +1,3 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import {
|
||||
COLOR_TYPES,
|
||||
OUTPUT_OPTIONS,
|
||||
@ -11,8 +10,10 @@ import {
|
||||
} from '../../../constants/convertConstants';
|
||||
import { getEndpointName as getEndpointNameUtil, getEndpointUrl, isImageFormat, isWebFormat } from '../../../utils/convertUtils';
|
||||
import { detectFileExtension as detectFileExtensionUtil } from '../../../utils/fileUtils';
|
||||
import { BaseParameters } from '../../../types/parameters';
|
||||
import { useBaseParameters, BaseParametersHook } from '../shared/useBaseParameters';
|
||||
|
||||
export interface ConvertParameters {
|
||||
export interface ConvertParameters extends BaseParameters {
|
||||
fromExtension: string;
|
||||
toExtension: string;
|
||||
imageOptions: {
|
||||
@ -39,18 +40,13 @@ export interface ConvertParameters {
|
||||
smartDetectionType: 'mixed' | 'images' | 'web' | 'none';
|
||||
}
|
||||
|
||||
export interface ConvertParametersHook {
|
||||
parameters: ConvertParameters;
|
||||
updateParameter: (parameter: keyof ConvertParameters, value: any) => void;
|
||||
resetParameters: () => void;
|
||||
validateParameters: () => boolean;
|
||||
getEndpointName: () => string;
|
||||
export interface ConvertParametersHook extends BaseParametersHook<ConvertParameters> {
|
||||
getEndpoint: () => string;
|
||||
getAvailableToExtensions: (fromExtension: string) => Array<{value: string, label: string, group: string}>;
|
||||
analyzeFileTypes: (files: Array<{name: string}>) => void;
|
||||
}
|
||||
|
||||
const initialParameters: ConvertParameters = {
|
||||
const defaultParameters: ConvertParameters = {
|
||||
fromExtension: '',
|
||||
toExtension: '',
|
||||
imageOptions: {
|
||||
@ -77,19 +73,8 @@ const initialParameters: ConvertParameters = {
|
||||
smartDetectionType: 'none',
|
||||
};
|
||||
|
||||
export const useConvertParameters = (): ConvertParametersHook => {
|
||||
const [parameters, setParameters] = useState<ConvertParameters>(initialParameters);
|
||||
|
||||
const updateParameter = (parameter: keyof ConvertParameters, value: any) => {
|
||||
setParameters(prev => ({ ...prev, [parameter]: value }));
|
||||
};
|
||||
|
||||
const resetParameters = () => {
|
||||
setParameters(initialParameters);
|
||||
};
|
||||
|
||||
const validateParameters = () => {
|
||||
const { fromExtension, toExtension } = parameters;
|
||||
const validateParameters = (params: ConvertParameters): boolean => {
|
||||
const { fromExtension, toExtension } = params;
|
||||
|
||||
if (!fromExtension || !toExtension) return false;
|
||||
|
||||
@ -110,8 +95,8 @@ export const useConvertParameters = (): ConvertParametersHook => {
|
||||
return true;
|
||||
};
|
||||
|
||||
const getEndpointName = () => {
|
||||
const { fromExtension, toExtension, isSmartDetection, smartDetectionType } = parameters;
|
||||
const getEndpointName = (params: ConvertParameters): string => {
|
||||
const { fromExtension, toExtension, isSmartDetection, smartDetectionType } = params;
|
||||
|
||||
if (isSmartDetection) {
|
||||
if (smartDetectionType === 'mixed') {
|
||||
@ -135,8 +120,15 @@ export const useConvertParameters = (): ConvertParametersHook => {
|
||||
return getEndpointNameUtil(fromExtension, toExtension);
|
||||
};
|
||||
|
||||
export const useConvertParameters = (): ConvertParametersHook => {
|
||||
const baseHook = useBaseParameters({
|
||||
defaultParameters,
|
||||
endpointName: getEndpointName,
|
||||
validateFn: validateParameters,
|
||||
});
|
||||
|
||||
const getEndpoint = () => {
|
||||
const { fromExtension, toExtension, isSmartDetection, smartDetectionType } = parameters;
|
||||
const { fromExtension, toExtension, isSmartDetection, smartDetectionType } = baseHook.parameters;
|
||||
|
||||
if (isSmartDetection) {
|
||||
if (smartDetectionType === 'mixed') {
|
||||
@ -189,7 +181,7 @@ export const useConvertParameters = (): ConvertParametersHook => {
|
||||
const analyzeFileTypes = (files: Array<{name: string}>) => {
|
||||
if (files.length === 0) {
|
||||
// No files - only reset smart detection, keep user's format choices
|
||||
setParameters(prev => ({
|
||||
baseHook.setParameters(prev => ({
|
||||
...prev,
|
||||
isSmartDetection: false,
|
||||
smartDetectionType: 'none'
|
||||
@ -215,7 +207,7 @@ export const useConvertParameters = (): ConvertParametersHook => {
|
||||
availableTargets = CONVERSION_MATRIX['any'] || [];
|
||||
}
|
||||
|
||||
setParameters(prev => {
|
||||
baseHook.setParameters(prev => {
|
||||
// Check if current toExtension is still valid for the new fromExtension
|
||||
const currentToExt = prev.toExtension;
|
||||
const isCurrentToExtValid = availableTargets.includes(currentToExt);
|
||||
@ -256,7 +248,7 @@ export const useConvertParameters = (): ConvertParametersHook => {
|
||||
availableTargets = CONVERSION_MATRIX['any'] || [];
|
||||
}
|
||||
|
||||
setParameters(prev => {
|
||||
baseHook.setParameters(prev => {
|
||||
// Check if current toExtension is still valid for the new fromExtension
|
||||
const currentToExt = prev.toExtension;
|
||||
const isCurrentToExtValid = availableTargets.includes(currentToExt);
|
||||
@ -285,7 +277,7 @@ export const useConvertParameters = (): ConvertParametersHook => {
|
||||
|
||||
if (allImages) {
|
||||
// All files are images - use image-to-pdf conversion
|
||||
setParameters(prev => ({
|
||||
baseHook.setParameters(prev => ({
|
||||
...prev,
|
||||
isSmartDetection: true,
|
||||
smartDetectionType: 'images',
|
||||
@ -294,7 +286,7 @@ export const useConvertParameters = (): ConvertParametersHook => {
|
||||
}));
|
||||
} else if (allWeb) {
|
||||
// All files are web files - use html-to-pdf conversion
|
||||
setParameters(prev => ({
|
||||
baseHook.setParameters(prev => ({
|
||||
...prev,
|
||||
isSmartDetection: true,
|
||||
smartDetectionType: 'web',
|
||||
@ -303,7 +295,7 @@ export const useConvertParameters = (): ConvertParametersHook => {
|
||||
}));
|
||||
} else {
|
||||
// Mixed non-image types - use file-to-pdf conversion
|
||||
setParameters(prev => ({
|
||||
baseHook.setParameters(prev => ({
|
||||
...prev,
|
||||
isSmartDetection: true,
|
||||
smartDetectionType: 'mixed',
|
||||
@ -315,11 +307,7 @@ export const useConvertParameters = (): ConvertParametersHook => {
|
||||
};
|
||||
|
||||
return {
|
||||
parameters,
|
||||
updateParameter,
|
||||
resetParameters,
|
||||
validateParameters,
|
||||
getEndpointName,
|
||||
...baseHook,
|
||||
getEndpoint,
|
||||
getAvailableToExtensions,
|
||||
analyzeFileTypes,
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { OCRParameters } from '../../../components/tools/ocr/OCRSettings';
|
||||
import { OCRParameters } from './useOCRParameters';
|
||||
import { useToolOperation, ToolOperationConfig } from '../shared/useToolOperation';
|
||||
import { createStandardErrorHandler } from '../../../utils/toolErrorHandler';
|
||||
import { useToolResources } from '../shared/useToolResources';
|
||||
|
@ -1,13 +1,15 @@
|
||||
import { useState } from 'react';
|
||||
import { OCRParameters } from '../../../components/tools/ocr/OCRSettings';
|
||||
import { BaseParameters } from '../../../types/parameters';
|
||||
import { useBaseParameters, BaseParametersHook } from '../shared/useBaseParameters';
|
||||
|
||||
export interface OCRParametersHook {
|
||||
parameters: OCRParameters;
|
||||
updateParameter: (key: keyof OCRParameters, value: any) => void;
|
||||
resetParameters: () => void;
|
||||
validateParameters: () => boolean;
|
||||
export interface OCRParameters extends BaseParameters {
|
||||
languages: string[];
|
||||
ocrType: string;
|
||||
ocrRenderType: string;
|
||||
additionalOptions: string[];
|
||||
}
|
||||
|
||||
export type OCRParametersHook = BaseParametersHook<OCRParameters>;
|
||||
|
||||
const defaultParameters: OCRParameters = {
|
||||
languages: [],
|
||||
ocrType: 'skip-text',
|
||||
@ -16,28 +18,12 @@ const defaultParameters: OCRParameters = {
|
||||
};
|
||||
|
||||
export const useOCRParameters = (): OCRParametersHook => {
|
||||
const [parameters, setParameters] = useState<OCRParameters>(defaultParameters);
|
||||
|
||||
const updateParameter = (key: keyof OCRParameters, value: any) => {
|
||||
setParameters(prev => ({
|
||||
...prev,
|
||||
[key]: value
|
||||
}));
|
||||
};
|
||||
|
||||
const resetParameters = () => {
|
||||
setParameters(defaultParameters);
|
||||
};
|
||||
|
||||
const validateParameters = () => {
|
||||
return useBaseParameters({
|
||||
defaultParameters,
|
||||
endpointName: 'ocr-pdf',
|
||||
validateFn: (params) => {
|
||||
// At minimum, we need at least one language selected
|
||||
return parameters.languages.length > 0;
|
||||
};
|
||||
|
||||
return {
|
||||
parameters,
|
||||
updateParameter,
|
||||
resetParameters,
|
||||
validateParameters,
|
||||
};
|
||||
return params.languages.length > 0;
|
||||
},
|
||||
});
|
||||
};
|
@ -1,49 +1,22 @@
|
||||
import { useState } from 'react';
|
||||
import { BaseParameters } from '../../../types/parameters';
|
||||
import { useBaseParameters, BaseParametersHook } from '../shared/useBaseParameters';
|
||||
|
||||
export interface RemovePasswordParameters {
|
||||
export interface RemovePasswordParameters extends BaseParameters {
|
||||
password: string;
|
||||
}
|
||||
|
||||
export interface RemovePasswordParametersHook {
|
||||
parameters: RemovePasswordParameters;
|
||||
updateParameter: <K extends keyof RemovePasswordParameters>(parameter: K, value: RemovePasswordParameters[K]) => void;
|
||||
resetParameters: () => void;
|
||||
validateParameters: () => boolean;
|
||||
getEndpointName: () => string;
|
||||
}
|
||||
export type RemovePasswordParametersHook = BaseParametersHook<RemovePasswordParameters>;
|
||||
|
||||
export const defaultParameters: RemovePasswordParameters = {
|
||||
password: '',
|
||||
};
|
||||
|
||||
export const useRemovePasswordParameters = (): RemovePasswordParametersHook => {
|
||||
const [parameters, setParameters] = useState<RemovePasswordParameters>(defaultParameters);
|
||||
|
||||
const updateParameter = <K extends keyof RemovePasswordParameters>(parameter: K, value: RemovePasswordParameters[K]) => {
|
||||
setParameters(prev => ({
|
||||
...prev,
|
||||
[parameter]: value,
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const resetParameters = () => {
|
||||
setParameters(defaultParameters);
|
||||
};
|
||||
|
||||
const validateParameters = () => {
|
||||
return parameters.password !== '';
|
||||
};
|
||||
|
||||
const getEndpointName = () => {
|
||||
return 'remove-password';
|
||||
};
|
||||
|
||||
return {
|
||||
parameters,
|
||||
updateParameter,
|
||||
resetParameters,
|
||||
validateParameters,
|
||||
getEndpointName,
|
||||
};
|
||||
return useBaseParameters({
|
||||
defaultParameters,
|
||||
endpointName: 'remove-password',
|
||||
validateFn: (params) => {
|
||||
return params.password !== '';
|
||||
},
|
||||
});
|
||||
};
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { useState, useCallback } from 'react';
|
||||
import { BaseParameters } from '../../../types/parameters';
|
||||
import { useBaseParameters, BaseParametersHook } from '../shared/useBaseParameters';
|
||||
|
||||
export interface SanitizeParameters {
|
||||
export interface SanitizeParameters extends BaseParameters {
|
||||
removeJavaScript: boolean;
|
||||
removeEmbeddedFiles: boolean;
|
||||
removeXMPMetadata: boolean;
|
||||
@ -18,36 +19,14 @@ export const defaultParameters: SanitizeParameters = {
|
||||
removeFonts: false,
|
||||
};
|
||||
|
||||
export const useSanitizeParameters = () => {
|
||||
const [parameters, setParameters] = useState<SanitizeParameters>(defaultParameters);
|
||||
export type SanitizeParametersHook = BaseParametersHook<SanitizeParameters>;
|
||||
|
||||
const updateParameter = useCallback(<K extends keyof SanitizeParameters>(
|
||||
key: K,
|
||||
value: SanitizeParameters[K]
|
||||
) => {
|
||||
setParameters(prev => ({
|
||||
...prev,
|
||||
[key]: value
|
||||
}));
|
||||
}, []);
|
||||
|
||||
const resetParameters = useCallback(() => {
|
||||
setParameters(defaultParameters);
|
||||
}, []);
|
||||
|
||||
const validateParameters = useCallback(() => {
|
||||
return Object.values(parameters).some(value => value === true);
|
||||
}, [parameters]);
|
||||
|
||||
const getEndpointName = () => {
|
||||
return 'sanitize-pdf'
|
||||
};
|
||||
|
||||
return {
|
||||
parameters,
|
||||
updateParameter,
|
||||
resetParameters,
|
||||
validateParameters,
|
||||
getEndpointName,
|
||||
};
|
||||
export const useSanitizeParameters = (): SanitizeParametersHook => {
|
||||
return useBaseParameters({
|
||||
defaultParameters,
|
||||
endpointName: 'sanitize-pdf',
|
||||
validateFn: (params) => {
|
||||
return Object.values(params).some(value => value === true);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
@ -1,7 +1,8 @@
|
||||
import { useState, useCallback } from 'react';
|
||||
import { useState, useCallback, Dispatch, SetStateAction } from 'react';
|
||||
|
||||
export interface BaseParametersHook<T> {
|
||||
parameters: T;
|
||||
setParameters: Dispatch<SetStateAction<T>>;
|
||||
updateParameter: <K extends keyof T>(parameter: K, value: T[K]) => void;
|
||||
resetParameters: () => void;
|
||||
validateParameters: () => boolean;
|
||||
@ -10,7 +11,7 @@ export interface BaseParametersHook<T> {
|
||||
|
||||
export interface BaseParametersConfig<T> {
|
||||
defaultParameters: T;
|
||||
endpointName: string;
|
||||
endpointName: string | ((params: T) => string);
|
||||
validateFn?: (params: T) => boolean;
|
||||
}
|
||||
|
||||
@ -32,12 +33,21 @@ export function useBaseParameters<T>(config: BaseParametersConfig<T>): BaseParam
|
||||
return config.validateFn ? config.validateFn(parameters) : true;
|
||||
}, [parameters, config.validateFn]);
|
||||
|
||||
const getEndpointName = useCallback(() => {
|
||||
return config.endpointName;
|
||||
}, [config.endpointName]);
|
||||
const endpointName = config.endpointName;
|
||||
let getEndpointName: () => string;
|
||||
if (typeof endpointName === "string") {
|
||||
getEndpointName = useCallback(() => {
|
||||
return endpointName;
|
||||
}, []);
|
||||
} else {
|
||||
getEndpointName = useCallback(() => {
|
||||
return endpointName(parameters);
|
||||
}, [parameters]);
|
||||
}
|
||||
|
||||
return {
|
||||
parameters,
|
||||
setParameters,
|
||||
updateParameter,
|
||||
resetParameters,
|
||||
validateParameters,
|
||||
|
@ -1,7 +1,8 @@
|
||||
import { useState } from 'react';
|
||||
import { SPLIT_MODES, SPLIT_TYPES, ENDPOINTS, type SplitMode, SplitType } from '../../../constants/splitConstants';
|
||||
import { BaseParameters } from '../../../types/parameters';
|
||||
import { useBaseParameters, BaseParametersHook } from '../shared/useBaseParameters';
|
||||
|
||||
export interface SplitParameters {
|
||||
export interface SplitParameters extends BaseParameters {
|
||||
mode: SplitMode | '';
|
||||
pages: string;
|
||||
hDiv: string;
|
||||
@ -14,15 +15,9 @@ export interface SplitParameters {
|
||||
allowDuplicates: boolean;
|
||||
}
|
||||
|
||||
export interface SplitParametersHook {
|
||||
parameters: SplitParameters;
|
||||
updateParameter: (parameter: keyof SplitParameters, value: string | boolean) => void;
|
||||
resetParameters: () => void;
|
||||
validateParameters: () => boolean;
|
||||
getEndpointName: () => string;
|
||||
}
|
||||
export type SplitParametersHook = BaseParametersHook<SplitParameters>;
|
||||
|
||||
const initialParameters: SplitParameters = {
|
||||
const defaultParameters: SplitParameters = {
|
||||
mode: '',
|
||||
pages: '',
|
||||
hDiv: '2',
|
||||
@ -36,43 +31,27 @@ const initialParameters: SplitParameters = {
|
||||
};
|
||||
|
||||
export const useSplitParameters = (): SplitParametersHook => {
|
||||
const [parameters, setParameters] = useState<SplitParameters>(initialParameters);
|
||||
return useBaseParameters({
|
||||
defaultParameters,
|
||||
endpointName: (params) => {
|
||||
if (!params.mode) return ENDPOINTS[SPLIT_MODES.BY_PAGES];
|
||||
return ENDPOINTS[params.mode as SplitMode];
|
||||
},
|
||||
validateFn: (params) => {
|
||||
if (!params.mode) return false;
|
||||
|
||||
const updateParameter = (parameter: keyof SplitParameters, value: string | boolean) => {
|
||||
setParameters(prev => ({ ...prev, [parameter]: value }));
|
||||
};
|
||||
|
||||
const resetParameters = () => {
|
||||
setParameters(initialParameters);
|
||||
};
|
||||
|
||||
const validateParameters = () => {
|
||||
if (!parameters.mode) return false;
|
||||
|
||||
switch (parameters.mode) {
|
||||
switch (params.mode) {
|
||||
case SPLIT_MODES.BY_PAGES:
|
||||
return parameters.pages.trim() !== "";
|
||||
return params.pages.trim() !== "";
|
||||
case SPLIT_MODES.BY_SECTIONS:
|
||||
return parameters.hDiv !== "" && parameters.vDiv !== "";
|
||||
return params.hDiv !== "" && params.vDiv !== "";
|
||||
case SPLIT_MODES.BY_SIZE_OR_COUNT:
|
||||
return parameters.splitValue.trim() !== "";
|
||||
return params.splitValue.trim() !== "";
|
||||
case SPLIT_MODES.BY_CHAPTERS:
|
||||
return parameters.bookmarkLevel !== "";
|
||||
return params.bookmarkLevel !== "";
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
const getEndpointName = () => {
|
||||
if (!parameters.mode) return ENDPOINTS[SPLIT_MODES.BY_PAGES];
|
||||
return ENDPOINTS[parameters.mode as SplitMode];
|
||||
};
|
||||
|
||||
return {
|
||||
parameters,
|
||||
updateParameter,
|
||||
resetParameters,
|
||||
validateParameters,
|
||||
getEndpointName,
|
||||
};
|
||||
},
|
||||
});
|
||||
};
|
||||
|
@ -48,8 +48,8 @@ export const useToolManagement = (): ToolManagementResult => {
|
||||
const baseTool = baseRegistry[toolKey as keyof typeof baseRegistry];
|
||||
availableToolRegistry[toolKey] = {
|
||||
...baseTool,
|
||||
name: t(baseTool.name),
|
||||
description: t(baseTool.description)
|
||||
name: baseTool.name,
|
||||
description: baseTool.description,
|
||||
};
|
||||
}
|
||||
});
|
||||
|
@ -13,6 +13,7 @@ import { I18nextProvider } from 'react-i18next';
|
||||
import i18n from '../../i18n/config';
|
||||
import axios from 'axios';
|
||||
import { detectFileExtension } from '../../utils/fileUtils';
|
||||
import { FIT_OPTIONS } from '../../constants/convertConstants';
|
||||
|
||||
// Mock axios
|
||||
vi.mock('axios');
|
||||
@ -403,7 +404,7 @@ describe('Convert Tool - Smart Detection Integration Tests', () => {
|
||||
colorType: 'grayscale',
|
||||
dpi: 150,
|
||||
singleOrMultiple: 'single',
|
||||
fitOption: 'fitToPage',
|
||||
fitOption: FIT_OPTIONS.FIT_PAGE,
|
||||
autoRotate: false,
|
||||
combineImages: true
|
||||
});
|
||||
@ -417,7 +418,7 @@ describe('Convert Tool - Smart Detection Integration Tests', () => {
|
||||
});
|
||||
|
||||
const formData = (mockedAxios.post as Mock).mock.calls[0][1] as FormData;
|
||||
expect(formData.get('fitOption')).toBe('fitToPage');
|
||||
expect(formData.get('fitOption')).toBe(FIT_OPTIONS.FIT_PAGE);
|
||||
expect(formData.get('colorType')).toBe('grayscale');
|
||||
expect(formData.get('autoRotate')).toBe('false');
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user