Refactor to use nullish coalescing and add missing React imports

Replaced many uses of logical OR (||) with nullish coalescing (??) for more accurate handling of undefined/null values. Added missing explicit React imports to various component files to ensure compatibility with tooling and future React versions. Also updated some async function calls to use 'void' for better type safety and intent clarity. Minor whitespace and formatting adjustments included.
This commit is contained in:
Ludy87 2025-09-25 07:36:19 +02:00
parent 906dc9bd8f
commit 490c7c1018
No known key found for this signature in database
GPG Key ID: 92696155E0220F94
57 changed files with 104 additions and 76 deletions

View File

@ -72,7 +72,7 @@ export default function StampPreview({ parameters, onParameterChange, file, show
if (!cancelled) setPageSize(null); if (!cancelled) setPageSize(null);
} }
}; };
load(); void load();
return () => { cancelled = true; }; return () => { cancelled = true; };
}, [file]); }, [file]);
@ -88,12 +88,12 @@ export default function StampPreview({ parameters, onParameterChange, file, show
const pageNumber = Math.max(1, getFirstSelectedPage(parameters.pageNumbers)); const pageNumber = Math.max(1, getFirstSelectedPage(parameters.pageNumbers));
const pageId = `${file.name}:${file.size}:${file.lastModified}:page:${pageNumber}`; const pageId = `${file.name}:${file.size}:${file.lastModified}:page:${pageNumber}`;
const thumb = await requestThumbnail(pageId, file, pageNumber); const thumb = await requestThumbnail(pageId, file, pageNumber);
if (isActive) setPageThumbnail(thumb || null); if (isActive) setPageThumbnail(thumb ?? null);
} catch { } catch {
if (isActive) setPageThumbnail(null); if (isActive) setPageThumbnail(null);
} }
}; };
loadThumb(); void loadThumb();
return () => { isActive = false; }; return () => { isActive = false; };
}, [file, parameters.pageNumbers, requestThumbnail]); }, [file, parameters.pageNumbers, requestThumbnail]);
@ -189,7 +189,7 @@ export default function StampPreview({ parameters, onParameterChange, file, show
draggingRef.current = { draggingRef.current = {
type, type,
startX: e.clientX - (rect?.left || 0), startX: e.clientX - (rect?.left ?? 0),
startY: (rect ? rect.bottom - e.clientY : 0), // convert to bottom-based coords startY: (rect ? rect.bottom - e.clientY : 0), // convert to bottom-based coords
initLeft: left, initLeft: left,
initBottom: bottom, initBottom: bottom,
@ -255,11 +255,11 @@ export default function StampPreview({ parameters, onParameterChange, file, show
<div className={styles.divider} /> <div className={styles.divider} />
<div className={styles.previewLabel}>Preview Stamp</div> <div className={styles.previewLabel}>Preview Stamp</div>
</div> </div>
<div <div
ref={containerRef} ref={containerRef}
className={`${styles.container} ${styles.containerBorder} ${pageThumbnail ? styles.containerWithThumbnail : styles.containerWithoutThumbnail}`} className={`${styles.container} ${styles.containerBorder} ${pageThumbnail ? styles.containerWithThumbnail : styles.containerWithoutThumbnail}`}
style={style.container as React.CSSProperties} style={style.container as React.CSSProperties}
onPointerMove={handlePointerMove} onPointerMove={handlePointerMove}
onPointerUp={handlePointerUp} onPointerUp={handlePointerUp}
> >
{pageThumbnail && ( {pageThumbnail && (

View File

@ -7,7 +7,7 @@ export const buildAddStampFormData = (parameters: AddStampParameters, file: File
const formData = new FormData(); const formData = new FormData();
formData.append('fileInput', file); formData.append('fileInput', file);
formData.append('pageNumbers', parameters.pageNumbers); formData.append('pageNumbers', parameters.pageNumbers);
formData.append('customMargin', parameters.customMargin || 'medium'); formData.append('customMargin', parameters.customMargin || 'medium');
formData.append('position', String(parameters.position)); formData.append('position', String(parameters.position));
const effectiveFontSize = parameters.fontSize; const effectiveFontSize = parameters.fontSize;
formData.append('fontSize', String(effectiveFontSize)); formData.append('fontSize', String(effectiveFontSize));
@ -19,7 +19,7 @@ export const buildAddStampFormData = (parameters: AddStampParameters, file: File
formData.append('alphabet', parameters.alphabet); formData.append('alphabet', parameters.alphabet);
// Stamp type and payload // Stamp type and payload
formData.append('stampType', parameters.stampType || 'text'); formData.append('stampType', parameters.stampType ?? 'text');
if (parameters.stampType === 'text') { if (parameters.stampType === 'text') {
formData.append('stampText', parameters.stampText); formData.append('stampText', parameters.stampText);
} else if (parameters.stampType === 'image' && parameters.stampImage) { } else if (parameters.stampType === 'image' && parameters.stampImage) {

View File

@ -17,7 +17,7 @@ const WatermarkImageFile = ({ parameters, onParameterChange, disabled = false }:
<Stack gap="sm"> <Stack gap="sm">
<FileUploadButton <FileUploadButton
file={parameters.watermarkImage} file={parameters.watermarkImage}
onChange={(file) => onParameterChange('watermarkImage', file || undefined)} onChange={(file) => onParameterChange('watermarkImage', file ?? undefined)}
accept="image/*" accept="image/*"
disabled={disabled} disabled={disabled}
placeholder={t('watermark.settings.image.choose', 'Choose Image')} placeholder={t('watermark.settings.image.choose', 'Choose Image')}

View File

@ -1,3 +1,4 @@
import React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import ButtonSelector from "../../shared/ButtonSelector"; import ButtonSelector from "../../shared/ButtonSelector";

View File

@ -1,3 +1,4 @@
import React from 'react';
import { describe, expect, test, vi, beforeEach } from 'vitest'; import { describe, expect, test, vi, beforeEach } from 'vitest';
import { render, screen } from '@testing-library/react'; import { render, screen } from '@testing-library/react';
import { MantineProvider } from '@mantine/core'; import { MantineProvider } from '@mantine/core';

View File

@ -1,3 +1,4 @@
import React from "react";
import { Stack, NumberInput, Select } from "@mantine/core"; import { Stack, NumberInput, Select } from "@mantine/core";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { AdjustPageScaleParameters, PageSize } from "../../../hooks/tools/adjustPageScale/useAdjustPageScaleParameters"; import { AdjustPageScaleParameters, PageSize } from "../../../hooks/tools/adjustPageScale/useAdjustPageScaleParameters";

View File

@ -1,4 +1,4 @@
import { useState } from 'react'; import React, { useState } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { import {
Button, Button,
@ -100,7 +100,7 @@ export default function AutomationCreation({ mode, existingAutomation, onBack, o
icon: automationIcon, icon: automationIcon,
operations: selectedTools.map(tool => ({ operations: selectedTools.map(tool => ({
operation: tool.operation, operation: tool.operation,
parameters: tool.parameters || {} parameters: tool.parameters ?? {}
})) }))
}; };

View File

@ -240,7 +240,7 @@ export default function AutomationEntry({
); );
// Show tooltip if there's a description OR operations to display // Show tooltip if there's a description OR operations to display
const shouldShowTooltip = description || operations.length > 0; const shouldShowTooltip = description ?? operations.length > 0;
return shouldShowTooltip ? ( return shouldShowTooltip ? (
<Tooltip <Tooltip

View File

@ -26,7 +26,7 @@ export default function AutomationRun({ automation, onComplete, automateOperatio
const [currentStepIndex, setCurrentStepIndex] = useState(-1); const [currentStepIndex, setCurrentStepIndex] = useState(-1);
// Use the operation hook's loading state // Use the operation hook's loading state
const isExecuting = automateOperation?.isLoading || false; const isExecuting = automateOperation?.isLoading ?? false;
const hasResults = automateOperation?.files.length > 0 || automateOperation?.downloadUrl !== null; const hasResults = automateOperation?.files.length > 0 || automateOperation?.downloadUrl !== null;
// Initialize execution steps from automation // Initialize execution steps from automation
@ -194,7 +194,7 @@ export default function AutomationRun({ automation, onComplete, automateOperatio
<Button <Button
leftSection={<PlayArrowIcon />} leftSection={<PlayArrowIcon />}
onClick={executeAutomation} onClick={executeAutomation}
disabled={isExecuting || !selectedFiles || selectedFiles.length === 0} disabled={(isExecuting ?? !selectedFiles) ?? selectedFiles.length === 0}
loading={isExecuting} loading={isExecuting}
> >
{isExecuting {isExecuting

View File

@ -1,4 +1,4 @@
import { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { import {
Modal, Modal,

View File

@ -1,4 +1,4 @@
import { useState, useMemo, useCallback, useRef, useEffect } from 'react'; import React, { useState, useMemo, useCallback, useRef, useEffect } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { Stack, Text, ScrollArea } from '@mantine/core'; import { Stack, Text, ScrollArea } from '@mantine/core';
import { ToolRegistryEntry } from '../../../data/toolsTaxonomy'; import { ToolRegistryEntry } from '../../../data/toolsTaxonomy';
@ -82,7 +82,7 @@ export default function ToolSelector({
// Find the "all" section which contains all tools without duplicates // Find the "all" section which contains all tools without duplicates
const allSection = sections.find(s => (s as any).key === 'all'); const allSection = sections.find(s => (s as any).key === 'all');
return allSection?.subcategories || []; return allSection?.subcategories ?? [];
}, [isSearching, searchGroups, sections, baseFilteredTools]); }, [isSearching, searchGroups, sections, baseFilteredTools]);
const handleToolSelect = useCallback((toolKey: string) => { const handleToolSelect = useCallback((toolKey: string) => {
@ -138,7 +138,7 @@ export default function ToolSelector({
if (selectedValue && toolRegistry[selectedValue]) { if (selectedValue && toolRegistry[selectedValue]) {
return toolRegistry[selectedValue].name; return toolRegistry[selectedValue].name;
} }
return placeholder || t('automate.creation.tools.add', 'Add a tool...'); return placeholder ?? t('automate.creation.tools.add', 'Add a tool...');
}; };
return ( return (

View File

@ -1,3 +1,4 @@
import React from "react";
import { Stack, Text, TextInput } from "@mantine/core"; import { Stack, Text, TextInput } from "@mantine/core";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { CertSignParameters } from "../../../hooks/tools/certSign/useCertSignParameters"; import { CertSignParameters } from "../../../hooks/tools/certSign/useCertSignParameters";
@ -19,7 +20,7 @@ const CertificateFilesSettings = ({ parameters, onParameterChange, disabled = fa
<Stack gap="sm"> <Stack gap="sm">
<FileUploadButton <FileUploadButton
file={parameters.privateKeyFile} file={parameters.privateKeyFile}
onChange={(file) => onParameterChange('privateKeyFile', file || undefined)} onChange={(file) => onParameterChange('privateKeyFile', file ?? undefined)}
accept=".pem,.der,.key" accept=".pem,.der,.key"
disabled={disabled} disabled={disabled}
placeholder={t('certSign.choosePrivateKey', 'Choose Private Key File')} placeholder={t('certSign.choosePrivateKey', 'Choose Private Key File')}
@ -27,7 +28,7 @@ const CertificateFilesSettings = ({ parameters, onParameterChange, disabled = fa
{parameters.privateKeyFile && ( {parameters.privateKeyFile && (
<FileUploadButton <FileUploadButton
file={parameters.certFile} file={parameters.certFile}
onChange={(file) => onParameterChange('certFile', file || undefined)} onChange={(file) => onParameterChange('certFile', file ?? undefined)}
accept=".pem,.der,.crt,.cer" accept=".pem,.der,.crt,.cer"
disabled={disabled} disabled={disabled}
placeholder={t('certSign.chooseCertificate', 'Choose Certificate File')} placeholder={t('certSign.chooseCertificate', 'Choose Certificate File')}
@ -39,7 +40,7 @@ const CertificateFilesSettings = ({ parameters, onParameterChange, disabled = fa
{parameters.certType === 'PKCS12' && ( {parameters.certType === 'PKCS12' && (
<FileUploadButton <FileUploadButton
file={parameters.p12File} file={parameters.p12File}
onChange={(file) => onParameterChange('p12File', file || undefined)} onChange={(file) => onParameterChange('p12File', file ?? undefined)}
accept=".p12" accept=".p12"
disabled={disabled} disabled={disabled}
placeholder={t('certSign.chooseP12File', 'Choose PKCS12 File')} placeholder={t('certSign.chooseP12File', 'Choose PKCS12 File')}
@ -49,7 +50,7 @@ const CertificateFilesSettings = ({ parameters, onParameterChange, disabled = fa
{parameters.certType === 'PFX' && ( {parameters.certType === 'PFX' && (
<FileUploadButton <FileUploadButton
file={parameters.p12File} file={parameters.p12File}
onChange={(file) => onParameterChange('p12File', file || undefined)} onChange={(file) => onParameterChange('p12File', file ?? undefined)}
accept=".pfx" accept=".pfx"
disabled={disabled} disabled={disabled}
placeholder={t('certSign.choosePfxFile', 'Choose PFX File')} placeholder={t('certSign.choosePfxFile', 'Choose PFX File')}
@ -59,7 +60,7 @@ const CertificateFilesSettings = ({ parameters, onParameterChange, disabled = fa
{parameters.certType === 'JKS' && ( {parameters.certType === 'JKS' && (
<FileUploadButton <FileUploadButton
file={parameters.jksFile} file={parameters.jksFile}
onChange={(file) => onParameterChange('jksFile', file || undefined)} onChange={(file) => onParameterChange('jksFile', file ?? undefined)}
accept=".jks,.keystore" accept=".jks,.keystore"
disabled={disabled} disabled={disabled}
placeholder={t('certSign.chooseJksFile', 'Choose JKS File')} placeholder={t('certSign.chooseJksFile', 'Choose JKS File')}
@ -74,9 +75,9 @@ const CertificateFilesSettings = ({ parameters, onParameterChange, disabled = fa
{/* Password - only show when files are uploaded */} {/* Password - only show when files are uploaded */}
{parameters.certType && ( {parameters.certType && (
(parameters.certType === 'PEM' && parameters.privateKeyFile && parameters.certFile) || (parameters.certType === 'PEM' && parameters.privateKeyFile && parameters.certFile) ??
(parameters.certType === 'PKCS12' && parameters.p12File) || (parameters.certType === 'PKCS12' && parameters.p12File) ??
(parameters.certType === 'PFX' && parameters.p12File) || (parameters.certType === 'PFX' && parameters.p12File) ??
(parameters.certType === 'JKS' && parameters.jksFile) (parameters.certType === 'JKS' && parameters.jksFile)
) && ( ) && (
<TextInput <TextInput
@ -92,4 +93,4 @@ const CertificateFilesSettings = ({ parameters, onParameterChange, disabled = fa
); );
}; };
export default CertificateFilesSettings; export default CertificateFilesSettings;

View File

@ -1,3 +1,4 @@
import React from "react";
import { Stack, Button } from "@mantine/core"; import { Stack, Button } from "@mantine/core";
import { CertSignParameters } from "../../../hooks/tools/certSign/useCertSignParameters"; import { CertSignParameters } from "../../../hooks/tools/certSign/useCertSignParameters";

View File

@ -1,3 +1,4 @@
import React from "react";
import { Stack, Button } from "@mantine/core"; import { Stack, Button } from "@mantine/core";
import { CertSignParameters } from "../../../hooks/tools/certSign/useCertSignParameters"; import { CertSignParameters } from "../../../hooks/tools/certSign/useCertSignParameters";
import { useAppConfig } from "../../../hooks/useAppConfig"; import { useAppConfig } from "../../../hooks/useAppConfig";

View File

@ -1,3 +1,4 @@
import React from "react";
import { Stack, Text, Button, TextInput, NumberInput } from "@mantine/core"; import { Stack, Text, Button, TextInput, NumberInput } from "@mantine/core";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { CertSignParameters } from "../../../hooks/tools/certSign/useCertSignParameters"; import { CertSignParameters } from "../../../hooks/tools/certSign/useCertSignParameters";

View File

@ -1,3 +1,4 @@
import React from "react";
import { Stack, Divider, Text } from "@mantine/core"; import { Stack, Divider, Text } from "@mantine/core";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { ChangeMetadataParameters, createCustomMetadataFunctions } from "../../../hooks/tools/changeMetadata/useChangeMetadataParameters"; import { ChangeMetadataParameters, createCustomMetadataFunctions } from "../../../hooks/tools/changeMetadata/useChangeMetadataParameters";

View File

@ -1,3 +1,4 @@
import React from "react";
import { Stack, Select, Divider } from "@mantine/core"; import { Stack, Select, Divider } from "@mantine/core";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { ChangeMetadataParameters } from "../../../../hooks/tools/changeMetadata/useChangeMetadataParameters"; import { ChangeMetadataParameters } from "../../../../hooks/tools/changeMetadata/useChangeMetadataParameters";

View File

@ -1,3 +1,4 @@
import React from "react";
import { Stack, TextInput, Button, Group, Text } from "@mantine/core"; import { Stack, TextInput, Button, Group, Text } from "@mantine/core";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { ChangeMetadataParameters } from "../../../../hooks/tools/changeMetadata/useChangeMetadataParameters"; import { ChangeMetadataParameters } from "../../../../hooks/tools/changeMetadata/useChangeMetadataParameters";

View File

@ -1,3 +1,4 @@
import React from "react";
import { Checkbox } from "@mantine/core"; import { Checkbox } from "@mantine/core";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { ChangeMetadataParameters } from "../../../../hooks/tools/changeMetadata/useChangeMetadataParameters"; import { ChangeMetadataParameters } from "../../../../hooks/tools/changeMetadata/useChangeMetadataParameters";

View File

@ -1,3 +1,4 @@
import React from "react";
import { Stack } from "@mantine/core"; import { Stack } from "@mantine/core";
import { DateTimePicker } from "@mantine/dates"; import { DateTimePicker } from "@mantine/dates";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";

View File

@ -1,3 +1,4 @@
import React from "react";
import { Stack, TextInput } from "@mantine/core"; import { Stack, TextInput } from "@mantine/core";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { ChangeMetadataParameters } from "../../../../hooks/tools/changeMetadata/useChangeMetadataParameters"; import { ChangeMetadataParameters } from "../../../../hooks/tools/changeMetadata/useChangeMetadataParameters";

View File

@ -1,3 +1,4 @@
import React from 'react';
import { describe, expect, test, vi, beforeEach } from 'vitest'; import { describe, expect, test, vi, beforeEach } from 'vitest';
import { render, screen, fireEvent } from '@testing-library/react'; import { render, screen, fireEvent } from '@testing-library/react';
import { MantineProvider } from '@mantine/core'; import { MantineProvider } from '@mantine/core';

View File

@ -1,3 +1,4 @@
import React from "react";
import { Stack, Checkbox } from "@mantine/core"; import { Stack, Checkbox } from "@mantine/core";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { ChangePermissionsParameters } from "../../../hooks/tools/changePermissions/useChangePermissionsParameters"; import { ChangePermissionsParameters } from "../../../hooks/tools/changePermissions/useChangePermissionsParameters";

View File

@ -44,7 +44,7 @@ const ConvertToPdfaSettings = ({
value={parameters.pdfaOptions.outputFormat} value={parameters.pdfaOptions.outputFormat}
onChange={(value) => onParameterChange('pdfaOptions', { onChange={(value) => onParameterChange('pdfaOptions', {
...parameters.pdfaOptions, ...parameters.pdfaOptions,
outputFormat: value || 'pdfa-1' outputFormat: value ?? 'pdfa-1'
})} })}
data={pdfaFormatOptions} data={pdfaFormatOptions}
disabled={disabled || isChecking} disabled={disabled || isChecking}

View File

@ -1,4 +1,4 @@
import { useMemo, useState, useEffect } from "react"; import React, { useMemo, useState, useEffect } from "react";
import { Stack, Text, Box, Group, NumberInput, ActionIcon, Center, Alert } from "@mantine/core"; import { Stack, Text, Box, Group, NumberInput, ActionIcon, Center, Alert } from "@mantine/core";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import RestartAltIcon from "@mui/icons-material/RestartAlt"; import RestartAltIcon from "@mui/icons-material/RestartAlt";
@ -48,7 +48,7 @@ const CropSettings = ({ parameters, disabled = false }: CropSettingsProps) => {
return; return;
} }
setThumbnail(selectedStub.thumbnailUrl || null); setThumbnail(selectedStub.thumbnailUrl ?? null);
try { try {
// Get PDF dimensions from the actual file // Get PDF dimensions from the actual file
@ -89,7 +89,7 @@ const CropSettings = ({ parameters, disabled = false }: CropSettingsProps) => {
} }
}; };
loadPDFDimensions(); void loadPDFDimensions();
}, [selectedStub, selectedFile, parameters]); }, [selectedStub, selectedFile, parameters]);
// Current crop area // Current crop area

View File

@ -1,3 +1,4 @@
import React from "react";
import { Stack, Text, Checkbox } from "@mantine/core"; import { Stack, Text, Checkbox } from "@mantine/core";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { FlattenParameters } from "../../../hooks/tools/flatten/useFlattenParameters"; import { FlattenParameters } from "../../../hooks/tools/flatten/useFlattenParameters";

View File

@ -1,3 +1,4 @@
import React from 'react';
import { describe, expect, test, vi, beforeEach } from 'vitest'; import { describe, expect, test, vi, beforeEach } from 'vitest';
import { render, screen, fireEvent } from '@testing-library/react'; import { render, screen, fireEvent } from '@testing-library/react';
import { MantineProvider } from '@mantine/core'; import { MantineProvider } from '@mantine/core';

View File

@ -1,3 +1,4 @@
import React from 'react';
import { describe, expect, test, vi, beforeEach } from 'vitest'; import { describe, expect, test, vi, beforeEach } from 'vitest';
import { render, screen, fireEvent } from '@testing-library/react'; import { render, screen, fireEvent } from '@testing-library/react';
import { MantineProvider } from '@mantine/core'; import { MantineProvider } from '@mantine/core';

View File

@ -75,7 +75,7 @@ const LanguagePicker: React.FC<LanguagePickerProps> = ({
} }
}; };
fetchLanguages(); void fetchLanguages();
}, [languagesEndpoint]); }, [languagesEndpoint]);
// Auto-fill OCR language based on browser language when languages are loaded // Auto-fill OCR language based on browser language when languages are loaded

View File

@ -23,7 +23,7 @@ const OCRSettings: React.FC<OCRSettingsProps> = ({
<Select <Select
label={t('ocr.settings.ocrMode.label', 'OCR Mode')} label={t('ocr.settings.ocrMode.label', 'OCR Mode')}
value={parameters.ocrType} value={parameters.ocrType}
onChange={(value) => onParameterChange('ocrType', value || 'skip-text')} onChange={(value) => onParameterChange('ocrType', value ?? 'skip-text')}
data={[ data={[
{ value: 'skip-text', label: t('ocr.settings.ocrMode.auto', 'Auto (skip text layers)') }, { value: 'skip-text', label: t('ocr.settings.ocrMode.auto', 'Auto (skip text layers)') },
{ value: 'force-ocr', label: t('ocr.settings.ocrMode.force', 'Force (re-OCR all, replace text)') }, { value: 'force-ocr', label: t('ocr.settings.ocrMode.force', 'Force (re-OCR all, replace text)') },

View File

@ -1,3 +1,4 @@
import React from 'react';
import { describe, expect, test, vi, beforeEach } from 'vitest'; import { describe, expect, test, vi, beforeEach } from 'vitest';
import { render, screen, fireEvent } from '@testing-library/react'; import { render, screen, fireEvent } from '@testing-library/react';
import { MantineProvider } from '@mantine/core'; import { MantineProvider } from '@mantine/core';

View File

@ -1,3 +1,4 @@
import React from "react";
import { Stack, NumberInput, ColorInput, Checkbox } from "@mantine/core"; import { Stack, NumberInput, ColorInput, Checkbox } from "@mantine/core";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { RedactParameters } from "../../../hooks/tools/redact/useRedactParameters"; import { RedactParameters } from "../../../hooks/tools/redact/useRedactParameters";

View File

@ -1,3 +1,4 @@
import React from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { RedactMode } from '../../../hooks/tools/redact/useRedactParameters'; import { RedactMode } from '../../../hooks/tools/redact/useRedactParameters';
import ButtonSelector from '../../shared/ButtonSelector'; import ButtonSelector from '../../shared/ButtonSelector';

View File

@ -1,3 +1,4 @@
import React from 'react';
import { describe, expect, test, vi, beforeEach } from 'vitest'; import { describe, expect, test, vi, beforeEach } from 'vitest';
import { render, screen, fireEvent } from '@testing-library/react'; import { render, screen, fireEvent } from '@testing-library/react';
import { MantineProvider } from '@mantine/core'; import { MantineProvider } from '@mantine/core';

View File

@ -80,7 +80,7 @@ export function SearchInterface({ visible, onClose }: SearchInterfaceProps) {
const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => { const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {
if (event.key === 'Enter') { if (event.key === 'Enter') {
handleSearch(searchQuery); void handleSearch(searchQuery);
} else if (event.key === 'Escape') { } else if (event.key === 'Escape') {
onClose(); onClose();
} }

View File

@ -65,7 +65,7 @@ export function ThumbnailSidebar({ visible, onToggle: _onToggle }: ThumbnailSide
} }
}; };
generateThumbnails(); void generateThumbnails();
}, [visible, scrollState.totalPages, thumbnailAPI]); }, [visible, scrollState.totalPages, thumbnailAPI]);
const handlePageClick = (pageIndex: number) => { const handlePageClick = (pageIndex: number) => {

View File

@ -43,7 +43,7 @@ export const FilesModalProvider: React.FC<{ children: React.ReactNode }> = ({ ch
customHandler(files, insertAfterPage); customHandler(files, insertAfterPage);
} else { } else {
// Use normal file handling // Use normal file handling
addFiles(files); void addFiles(files);
} }
closeFilesModal(); closeFilesModal();
}, [addFiles, closeFilesModal, insertAfterPage, customHandler]); }, [addFiles, closeFilesModal, insertAfterPage, customHandler]);
@ -59,7 +59,7 @@ export const FilesModalProvider: React.FC<{ children: React.ReactNode }> = ({ ch
loadedFiles.push(stirlingFile); loadedFiles.push(stirlingFile);
} }
} }
if (loadedFiles.length > 0) { if (loadedFiles.length > 0) {
customHandler(loadedFiles, insertAfterPage); customHandler(loadedFiles, insertAfterPage);
} }
@ -69,7 +69,11 @@ export const FilesModalProvider: React.FC<{ children: React.ReactNode }> = ({ ch
} else { } else {
// Normal case - use addStirlingFileStubs to preserve metadata // Normal case - use addStirlingFileStubs to preserve metadata
if (actions.addStirlingFileStubs) { if (actions.addStirlingFileStubs) {
actions.addStirlingFileStubs(stirlingFileStubs, { selectFiles: true }); try {
await actions.addStirlingFileStubs(stirlingFileStubs, { selectFiles: true });
} catch (error) {
console.error('Error adding Stirling file stubs:', error);
}
} else { } else {
console.error('addStirlingFileStubs action not available'); console.error('addStirlingFileStubs action not available');
} }

View File

@ -26,7 +26,7 @@ export function useSavedAutomations() {
}, []); }, []);
const refreshAutomations = useCallback(() => { const refreshAutomations = useCallback(() => {
loadSavedAutomations(); void loadSavedAutomations();
}, [loadSavedAutomations]); }, [loadSavedAutomations]);
const deleteAutomation = useCallback(async (id: string) => { const deleteAutomation = useCallback(async (id: string) => {
@ -80,7 +80,7 @@ export function useSavedAutomations() {
// Load automations on mount // Load automations on mount
useEffect(() => { useEffect(() => {
loadSavedAutomations(); void loadSavedAutomations();
}, [loadSavedAutomations]); }, [loadSavedAutomations]);
return { return {

View File

@ -60,7 +60,7 @@ export const useMetadataExtraction = (params: MetadataExtractionParams) => {
setIsExtractingMetadata(false); setIsExtractingMetadata(false);
}; };
extractMetadata(); void extractMetadata();
}, [selectedFiles, hasExtractedMetadata, params]); }, [selectedFiles, hasExtractedMetadata, params]);
return { return {

View File

@ -65,7 +65,7 @@ export function useAppConfig(): UseAppConfigReturn {
}; };
useEffect(() => { useEffect(() => {
fetchConfig(); void fetchConfig();
}, []); }, []);
return { return {

View File

@ -41,7 +41,7 @@ export function useEndpointEnabled(endpoint: string): {
}; };
useEffect(() => { useEffect(() => {
fetchEndpointStatus(); void fetchEndpointStatus();
}, [endpoint]); }, [endpoint]);
return { return {
@ -105,7 +105,7 @@ export function useMultipleEndpointsEnabled(endpoints: string[]): {
}; };
useEffect(() => { useEffect(() => {
fetchAllEndpointStatuses(); void fetchAllEndpointStatuses();
}, [endpoints.join(',')]); // Re-run when endpoints array changes }, [endpoints.join(',')]); // Re-run when endpoints array changes
return { return {

View File

@ -104,7 +104,7 @@ export function useEnhancedProcessedFiles(
} }
}; };
processFiles(); void processFiles();
}, [activeFiles]); // Only depend on activeFiles to avoid infinite loops }, [activeFiles]); // Only depend on activeFiles to avoid infinite loops
// Listen for processing completion // Listen for processing completion

View File

@ -2,7 +2,6 @@ import { useState, useEffect } from "react";
import { StirlingFileStub } from "../types/fileContext"; import { StirlingFileStub } from "../types/fileContext";
import { useIndexedDB } from "../contexts/IndexedDBContext"; import { useIndexedDB } from "../contexts/IndexedDBContext";
import { generateThumbnailForFile } from "../utils/thumbnailUtils"; import { generateThumbnailForFile } from "../utils/thumbnailUtils";
import { FileId } from "../types/fileContext";
/** /**
@ -75,7 +74,7 @@ export function useIndexedDBThumbnail(file: StirlingFileStub | undefined | null)
} }
} }
loadThumbnail(); void loadThumbnail();
return () => { cancelled = true; }; return () => { cancelled = true; };
}, [file, file?.thumbnailUrl, file?.id, indexedDB, generating]); }, [file, file?.thumbnailUrl, file?.id, indexedDB, generating]);

View File

@ -58,7 +58,7 @@ export const usePdfSignatureDetection = (files: StirlingFile[]): PdfSignatureDet
setIsChecking(false); setIsChecking(false);
}; };
checkForDigitalSignatures(); void checkForDigitalSignatures();
}, [files]); }, [files]);
return { return {

View File

@ -36,7 +36,7 @@ export function useProcessedFiles(activeFiles: File[]): UseProcessedFilesResult
setProcessedFiles(newProcessedFiles); setProcessedFiles(newProcessedFiles);
}; };
checkProcessing(); void checkProcessing();
return unsubscribe; return unsubscribe;
}, [activeFiles]); }, [activeFiles]);

View File

@ -52,7 +52,7 @@ export const supportedLanguages = {
// RTL languages (based on your existing language.direction property) // RTL languages (based on your existing language.direction property)
export const rtlLanguages = ['ar-AR', 'fa-IR']; export const rtlLanguages = ['ar-AR', 'fa-IR'];
i18n void i18n
.use(Backend) .use(Backend)
.use(LanguageDetector) .use(LanguageDetector)
.use(initReactI18next) .use(initReactI18next)

View File

@ -2,7 +2,7 @@ import i18n from 'i18next';
import { initReactI18next } from 'react-i18next'; import { initReactI18next } from 'react-i18next';
import Backend from 'i18next-http-backend'; import Backend from 'i18next-http-backend';
i18n void i18n
.use(Backend) .use(Backend)
.use(initReactI18next) .use(initReactI18next)
.init({ .init({
@ -29,7 +29,7 @@ i18n
'convert.singleOrMultiple': 'Output', 'convert.singleOrMultiple': 'Output',
'convert.emailNote': 'Email attachments and embedded images will be included', 'convert.emailNote': 'Email attachments and embedded images will be included',
'common.color': 'Color', 'common.color': 'Color',
'common.grayscale': 'Grayscale', 'common.grayscale': 'Grayscale',
'common.blackWhite': 'Black & White', 'common.blackWhite': 'Black & White',
'common.single': 'Single Image', 'common.single': 'Single Image',
'common.multiple': 'Multiple Images', 'common.multiple': 'Multiple Images',
@ -45,4 +45,4 @@ i18n
} }
}); });
export default i18n; export default i18n;

View File

@ -70,7 +70,7 @@ export class EnhancedPDFProcessingService {
}; };
// Start processing // Start processing
this.startProcessing(file, fileKey, config, analysis.estimatedProcessingTime); await this.startProcessing(file, fileKey, config, analysis.estimatedProcessingTime);
return null; return null;
} }

View File

@ -60,7 +60,7 @@ class FileProcessingService {
this.processingCache.set(fileId, operation); this.processingCache.set(fileId, operation);
// Clean up cache after completion // Clean up cache after completion
processingPromise.finally(() => { void processingPromise.finally(() => {
this.processingCache.delete(fileId); this.processingCache.delete(fileId);
}); });

View File

@ -78,7 +78,7 @@ class FileStorageService {
request.onerror = () => { request.onerror = () => {
console.error('IndexedDB add error:', request.error); console.error('IndexedDB add error:', request.error);
reject(new Error(request.error?.message || 'Unknown error occurred')); reject(new Error(request.error?.message ?? 'Unknown error occurred'));
}; };
request.onsuccess = () => { request.onsuccess = () => {
resolve(); resolve();
@ -101,7 +101,7 @@ class FileStorageService {
const store = transaction.objectStore(this.storeName); const store = transaction.objectStore(this.storeName);
const request = store.get(id); const request = store.get(id);
request.onerror = () => reject(new Error(request.error?.message || 'Unknown error occurred')); request.onerror = () => reject(new Error(request.error?.message ?? 'Unknown error occurred'));
request.onsuccess = () => { request.onsuccess = () => {
const record = request.result as StoredStirlingFileRecord | undefined; const record = request.result as StoredStirlingFileRecord | undefined;
if (!record) { if (!record) {
@ -142,7 +142,7 @@ class FileStorageService {
const store = transaction.objectStore(this.storeName); const store = transaction.objectStore(this.storeName);
const request = store.get(id); const request = store.get(id);
request.onerror = () => reject(new Error(request.error?.message || 'Unknown error occurred')); request.onerror = () => reject(new Error(request.error?.message ?? 'Unknown error occurred'));
request.onsuccess = () => { request.onsuccess = () => {
const record = request.result as StoredStirlingFileRecord | undefined; const record = request.result as StoredStirlingFileRecord | undefined;
if (!record) { if (!record) {
@ -184,7 +184,7 @@ class FileStorageService {
const request = store.openCursor(); const request = store.openCursor();
const stubs: StirlingFileStub[] = []; const stubs: StirlingFileStub[] = [];
request.onerror = () => reject(new Error(request.error?.message || 'Unknown error occurred')); request.onerror = () => reject(new Error(request.error?.message ?? 'Unknown error occurred'));
request.onsuccess = (event) => { request.onsuccess = (event) => {
const cursor = (event.target as IDBRequest).result; const cursor = (event.target as IDBRequest).result;
if (cursor) { if (cursor) {
@ -227,7 +227,7 @@ class FileStorageService {
const request = store.openCursor(); const request = store.openCursor();
const leafStubs: StirlingFileStub[] = []; const leafStubs: StirlingFileStub[] = [];
request.onerror = () => reject(new Error(request.error?.message || 'Unknown error occurred')); request.onerror = () => reject(new Error(request.error?.message ?? 'Unknown error occurred'));
request.onsuccess = (event) => { request.onsuccess = (event) => {
const cursor = (event.target as IDBRequest).result; const cursor = (event.target as IDBRequest).result;
if (cursor) { if (cursor) {
@ -269,7 +269,7 @@ class FileStorageService {
const store = transaction.objectStore(this.storeName); const store = transaction.objectStore(this.storeName);
const request = store.delete(id); const request = store.delete(id);
request.onerror = () => reject(new Error(request.error?.message || 'Unknown error occurred')); request.onerror = () => reject(new Error(request.error?.message ?? 'Unknown error occurred'));
request.onsuccess = () => resolve(); request.onsuccess = () => resolve();
}); });
} }
@ -326,7 +326,7 @@ class FileStorageService {
const store = transaction.objectStore(this.storeName); const store = transaction.objectStore(this.storeName);
const request = store.clear(); const request = store.clear();
request.onerror = () => reject(new Error(request.error?.message || 'Unknown error occurred')); request.onerror = () => reject(new Error(request.error?.message ?? 'Unknown error occurred'));
request.onsuccess = () => resolve(); request.onsuccess = () => resolve();
}); });
} }
@ -384,7 +384,7 @@ class FileStorageService {
const store = transaction.objectStore(this.storeName); const store = transaction.objectStore(this.storeName);
const request = store.get(id); const request = store.get(id);
request.onerror = () => reject(new Error(request.error?.message || 'Unknown error occurred')); request.onerror = () => reject(new Error(request.error?.message ?? 'Unknown error occurred'));
request.onsuccess = () => { request.onsuccess = () => {
const record = request.result as StoredStirlingFileRecord | undefined; const record = request.result as StoredStirlingFileRecord | undefined;
if (record) { if (record) {
@ -415,7 +415,7 @@ class FileStorageService {
const record = await new Promise<StoredStirlingFileRecord | undefined>((resolve, reject) => { const record = await new Promise<StoredStirlingFileRecord | undefined>((resolve, reject) => {
const request = store.get(fileId); const request = store.get(fileId);
request.onsuccess = () => resolve(request.result); request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(new Error(request.error?.message || 'Unknown error occurred')); request.onerror = () => reject(new Error(request.error?.message ?? 'Unknown error occurred'));
}); });
if (!record) { if (!record) {
@ -428,7 +428,7 @@ class FileStorageService {
await new Promise<void>((resolve, reject) => { await new Promise<void>((resolve, reject) => {
const request = store.put(record); const request = store.put(record);
request.onsuccess = () => resolve(); request.onsuccess = () => resolve();
request.onerror = () => reject(new Error(request.error?.message || 'Unknown error occurred')); request.onerror = () => reject(new Error(request.error?.message ?? 'Unknown error occurred'));
}); });
return true; return true;
@ -451,7 +451,7 @@ class FileStorageService {
const record = await new Promise<StoredStirlingFileRecord | undefined>((resolve, reject) => { const record = await new Promise<StoredStirlingFileRecord | undefined>((resolve, reject) => {
const request = store.get(fileId); const request = store.get(fileId);
request.onsuccess = () => resolve(request.result); request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(new Error(request.error?.message || 'Unknown error occurred')); request.onerror = () => reject(new Error(request.error?.message ?? 'Unknown error occurred'));
}); });
if (!record) { if (!record) {
@ -464,7 +464,7 @@ class FileStorageService {
await new Promise<void>((resolve, reject) => { await new Promise<void>((resolve, reject) => {
const request = store.put(record); const request = store.put(record);
request.onsuccess = () => resolve(); request.onsuccess = () => resolve();
request.onerror = () => reject(new Error(request.error?.message || 'Unknown error occurred')); request.onerror = () => reject(new Error(request.error?.message ?? 'Unknown error occurred'));
}); });
return true; return true;

View File

@ -67,7 +67,7 @@ class IndexedDBManager {
request.onerror = () => { request.onerror = () => {
console.error(`Failed to open ${config.name}:`, request.error); console.error(`Failed to open ${config.name}:`, request.error);
reject(new Error(request.error?.message || 'Unknown error occurred while opening the database')); reject(new Error(request.error?.message ?? 'Unknown error occurred while opening the database'));
}; };
request.onsuccess = () => { request.onsuccess = () => {
@ -257,7 +257,7 @@ class IndexedDBManager {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const deleteRequest = indexedDB.deleteDatabase(name); const deleteRequest = indexedDB.deleteDatabase(name);
deleteRequest.onerror = () => reject(new Error(deleteRequest.error?.message || 'Unknown error occurred while deleting the database')); deleteRequest.onerror = () => reject(new Error(deleteRequest.error?.message ?? 'Unknown error occurred while deleting the database'));
deleteRequest.onsuccess = () => { deleteRequest.onsuccess = () => {
console.log(`Deleted database: ${name}`); console.log(`Deleted database: ${name}`);
resolve(); resolve();

View File

@ -35,7 +35,7 @@ export class PDFProcessingService {
} }
// Start processing // Start processing
this.startProcessing(file, fileKey); void this.startProcessing(file, fileKey);
return null; return null;
} }

View File

@ -94,7 +94,7 @@ class PDFWorkerManager {
// If document creation fails, make sure to clean up the loading task // If document creation fails, make sure to clean up the loading task
if (loadingTask) { if (loadingTask) {
try { try {
loadingTask.destroy(); await loadingTask.destroy();
} catch { } catch {
// Ignore errors // Ignore errors
} }
@ -109,7 +109,7 @@ class PDFWorkerManager {
destroyDocument(pdf: PDFDocumentProxy): void { destroyDocument(pdf: PDFDocumentProxy): void {
if (this.activeDocuments.has(pdf)) { if (this.activeDocuments.has(pdf)) {
try { try {
pdf.destroy(); void pdf.destroy();
this.activeDocuments.delete(pdf); this.activeDocuments.delete(pdf);
this.workerCount = Math.max(0, this.workerCount - 1); this.workerCount = Math.max(0, this.workerCount - 1);
} catch { } catch {
@ -167,7 +167,7 @@ class PDFWorkerManager {
// Force destroy all documents // Force destroy all documents
this.activeDocuments.forEach(pdf => { this.activeDocuments.forEach(pdf => {
try { try {
pdf.destroy(); void pdf.destroy();
} catch { } catch {
// Ignore errors // Ignore errors
} }

View File

@ -52,7 +52,7 @@ const AdjustPageScale = (props: BaseToolProps) => {
title: t("adjustPageScale.title", "Page Scale Results"), title: t("adjustPageScale.title", "Page Scale Results"),
onFileClick: base.handleThumbnailClick, onFileClick: base.handleThumbnailClick,
onUndo: () => { onUndo: () => {
base.handleUndo(); void base.handleUndo();
}, },
}, },
}); });

View File

@ -1,3 +1,4 @@
import React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { createToolFlow } from "../components/tools/shared/createToolFlow"; import { createToolFlow } from "../components/tools/shared/createToolFlow";
import CropSettings from "../components/tools/crop/CropSettings"; import CropSettings from "../components/tools/crop/CropSettings";

View File

@ -1,3 +1,4 @@
import React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { createToolFlow } from "../components/tools/shared/createToolFlow"; import { createToolFlow } from "../components/tools/shared/createToolFlow";
import RemovePasswordSettings from "../components/tools/removePassword/RemovePasswordSettings"; import RemovePasswordSettings from "../components/tools/removePassword/RemovePasswordSettings";

View File

@ -1,3 +1,4 @@
import React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { createToolFlow } from "../components/tools/shared/createToolFlow"; import { createToolFlow } from "../components/tools/shared/createToolFlow";
import RotateSettings from "../components/tools/rotate/RotateSettings"; import RotateSettings from "../components/tools/rotate/RotateSettings";