mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2025-08-21 19:59:24 +00:00
V2 reduce boilerplate in param hooks (#4246)
# Description of Changes Extend the base params in all tools param hooks, reducing boilerplate code.
This commit is contained in:
parent
d06cbcaa91
commit
a6706fcb0c
@ -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,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;
|
||||
|
||||
@ -108,10 +93,10 @@ 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') {
|
||||
@ -133,10 +118,17 @@ 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,
|
||||
};
|
||||
},
|
||||
});
|
||||
};
|
||||
|
@ -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