2025-07-23 16:41:27 +01:00
|
|
|
import React, { useMemo } from "react";
|
2025-07-23 16:55:13 +01:00
|
|
|
import { Stack, Text, Group, Divider, UnstyledButton, useMantineTheme, useMantineColorScheme } from "@mantine/core";
|
2025-07-23 12:01:40 +01:00
|
|
|
import KeyboardArrowDownIcon from "@mui/icons-material/KeyboardArrowDown";
|
2025-07-23 11:25:55 +01:00
|
|
|
import { useTranslation } from "react-i18next";
|
2025-07-23 16:41:27 +01:00
|
|
|
import { useMultipleEndpointsEnabled } from "../../../hooks/useEndpointConfig";
|
2025-07-25 11:36:57 +01:00
|
|
|
import { isImageFormat } from "../../../utils/convertUtils";
|
2025-07-23 12:01:40 +01:00
|
|
|
import GroupedFormatDropdown from "./GroupedFormatDropdown";
|
2025-07-23 16:55:13 +01:00
|
|
|
import ConvertToImageSettings from "./ConvertToImageSettings";
|
|
|
|
import ConvertFromImageSettings from "./ConvertFromImageSettings";
|
2025-07-28 13:58:43 +01:00
|
|
|
import ConvertFromPdfToCsvSettings from "./ConvertFromPdfToCsvSettings";
|
2025-07-23 11:25:55 +01:00
|
|
|
import { ConvertParameters } from "../../../hooks/tools/convert/useConvertParameters";
|
|
|
|
import {
|
|
|
|
FROM_FORMAT_OPTIONS,
|
2025-07-23 16:55:13 +01:00
|
|
|
EXTENSION_TO_ENDPOINT,
|
2025-07-23 11:25:55 +01:00
|
|
|
COLOR_TYPES,
|
2025-07-23 16:55:13 +01:00
|
|
|
OUTPUT_OPTIONS
|
2025-07-23 11:25:55 +01:00
|
|
|
} from "../../../constants/convertConstants";
|
|
|
|
|
|
|
|
interface ConvertSettingsProps {
|
|
|
|
parameters: ConvertParameters;
|
|
|
|
onParameterChange: (key: keyof ConvertParameters, value: any) => void;
|
|
|
|
getAvailableToExtensions: (fromExtension: string) => Array<{value: string, label: string, group: string}>;
|
|
|
|
disabled?: boolean;
|
|
|
|
}
|
|
|
|
|
|
|
|
const ConvertSettings = ({
|
|
|
|
parameters,
|
|
|
|
onParameterChange,
|
|
|
|
getAvailableToExtensions,
|
|
|
|
disabled = false
|
|
|
|
}: ConvertSettingsProps) => {
|
|
|
|
const { t } = useTranslation();
|
2025-07-23 12:01:40 +01:00
|
|
|
const theme = useMantineTheme();
|
|
|
|
const { colorScheme } = useMantineColorScheme();
|
2025-07-23 11:25:55 +01:00
|
|
|
|
2025-07-23 16:41:27 +01:00
|
|
|
// Get all possible conversion endpoints to check their availability
|
|
|
|
const allEndpoints = useMemo(() => {
|
|
|
|
const endpoints = new Set<string>();
|
|
|
|
Object.values(EXTENSION_TO_ENDPOINT).forEach(toEndpoints => {
|
|
|
|
Object.values(toEndpoints).forEach(endpoint => {
|
|
|
|
endpoints.add(endpoint);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
return Array.from(endpoints);
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
const { endpointStatus } = useMultipleEndpointsEnabled(allEndpoints);
|
|
|
|
|
|
|
|
// Function to check if a conversion is available based on endpoint
|
|
|
|
const isConversionAvailable = (fromExt: string, toExt: string): boolean => {
|
|
|
|
const endpointKey = EXTENSION_TO_ENDPOINT[fromExt]?.[toExt];
|
|
|
|
if (!endpointKey) return false;
|
|
|
|
|
|
|
|
return endpointStatus[endpointKey] === true;
|
|
|
|
};
|
|
|
|
|
|
|
|
// Enhanced FROM options with endpoint availability
|
|
|
|
const enhancedFromOptions = useMemo(() => {
|
2025-07-25 11:36:57 +01:00
|
|
|
return FROM_FORMAT_OPTIONS.map(option => {
|
|
|
|
// Check if this source format has any available conversions
|
|
|
|
const availableConversions = getAvailableToExtensions(option.value) || [];
|
|
|
|
const hasAvailableConversions = availableConversions.some(targetOption =>
|
|
|
|
isConversionAvailable(option.value, targetOption.value)
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
...option,
|
|
|
|
enabled: hasAvailableConversions
|
|
|
|
};
|
|
|
|
});
|
|
|
|
}, [getAvailableToExtensions, endpointStatus]);
|
2025-07-23 16:41:27 +01:00
|
|
|
|
|
|
|
// Enhanced TO options with endpoint availability
|
|
|
|
const enhancedToOptions = useMemo(() => {
|
|
|
|
if (!parameters.fromExtension) return [];
|
|
|
|
|
|
|
|
const availableOptions = getAvailableToExtensions(parameters.fromExtension) || [];
|
|
|
|
return availableOptions.map(option => ({
|
|
|
|
...option,
|
|
|
|
enabled: isConversionAvailable(parameters.fromExtension, option.value)
|
|
|
|
}));
|
2025-07-25 11:36:57 +01:00
|
|
|
}, [parameters.fromExtension, getAvailableToExtensions, endpointStatus]);
|
2025-07-23 16:41:27 +01:00
|
|
|
|
2025-07-23 14:30:53 +01:00
|
|
|
const handleFromExtensionChange = (value: string) => {
|
|
|
|
onParameterChange('fromExtension', value);
|
|
|
|
// Reset to extension when from extension changes
|
|
|
|
onParameterChange('toExtension', '');
|
|
|
|
// Reset format-specific options
|
|
|
|
onParameterChange('imageOptions', {
|
|
|
|
colorType: COLOR_TYPES.COLOR,
|
|
|
|
dpi: 300,
|
|
|
|
singleOrMultiple: OUTPUT_OPTIONS.MULTIPLE,
|
|
|
|
});
|
2025-07-23 11:25:55 +01:00
|
|
|
};
|
|
|
|
|
2025-07-23 12:01:40 +01:00
|
|
|
const handleToExtensionChange = (value: string) => {
|
|
|
|
onParameterChange('toExtension', value);
|
|
|
|
// Reset format-specific options when target extension changes
|
|
|
|
onParameterChange('imageOptions', {
|
|
|
|
colorType: COLOR_TYPES.COLOR,
|
|
|
|
dpi: 300,
|
|
|
|
singleOrMultiple: OUTPUT_OPTIONS.MULTIPLE,
|
|
|
|
});
|
2025-07-28 13:58:43 +01:00
|
|
|
onParameterChange('pageNumbers', 'all');
|
2025-07-23 11:25:55 +01:00
|
|
|
};
|
|
|
|
|
2025-07-23 12:01:40 +01:00
|
|
|
|
2025-07-23 11:25:55 +01:00
|
|
|
return (
|
|
|
|
<Stack gap="md">
|
|
|
|
{/* Format Selection */}
|
|
|
|
<Stack gap="sm">
|
|
|
|
<Text size="sm" fw={500}>
|
|
|
|
{t("convert.convertFrom", "Convert from")}:
|
|
|
|
</Text>
|
2025-07-23 14:30:53 +01:00
|
|
|
<GroupedFormatDropdown
|
2025-07-28 13:58:43 +01:00
|
|
|
name="convert-from-dropdown"
|
|
|
|
data-testid="from-format-dropdown"
|
2025-07-23 11:25:55 +01:00
|
|
|
value={parameters.fromExtension}
|
2025-07-23 16:57:28 +01:00
|
|
|
placeholder={t("convert.sourceFormatPlaceholder", "Source format")}
|
2025-07-23 16:41:27 +01:00
|
|
|
options={enhancedFromOptions}
|
2025-07-23 11:25:55 +01:00
|
|
|
onChange={handleFromExtensionChange}
|
|
|
|
disabled={disabled}
|
2025-07-23 14:52:54 +01:00
|
|
|
minWidth="21.875rem"
|
2025-07-23 11:25:55 +01:00
|
|
|
/>
|
|
|
|
</Stack>
|
|
|
|
|
|
|
|
<Stack gap="sm">
|
|
|
|
<Text size="sm" fw={500}>
|
|
|
|
{t("convert.convertTo", "Convert to")}:
|
|
|
|
</Text>
|
2025-07-23 12:01:40 +01:00
|
|
|
{!parameters.fromExtension ? (
|
|
|
|
<UnstyledButton
|
|
|
|
style={{
|
2025-07-23 14:52:54 +01:00
|
|
|
padding: '0.5rem 0.75rem',
|
|
|
|
border: `0.0625rem solid ${theme.colors.gray[4]}`,
|
2025-07-23 12:01:40 +01:00
|
|
|
borderRadius: theme.radius.sm,
|
|
|
|
backgroundColor: colorScheme === 'dark' ? theme.colors.dark[5] : theme.colors.gray[1],
|
|
|
|
color: colorScheme === 'dark' ? theme.colors.dark[2] : theme.colors.gray[6],
|
|
|
|
cursor: 'not-allowed'
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
<Group justify="space-between">
|
|
|
|
<Text size="sm">Select a source format first</Text>
|
|
|
|
<KeyboardArrowDownIcon
|
|
|
|
style={{
|
2025-07-23 14:52:54 +01:00
|
|
|
fontSize: '1rem',
|
2025-07-23 12:01:40 +01:00
|
|
|
color: colorScheme === 'dark' ? theme.colors.dark[2] : theme.colors.gray[6]
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
</Group>
|
|
|
|
</UnstyledButton>
|
|
|
|
) : (
|
|
|
|
<GroupedFormatDropdown
|
2025-07-28 13:58:43 +01:00
|
|
|
name="convert-to-dropdown"
|
|
|
|
data-testid="to-format-dropdown"
|
2025-07-23 12:01:40 +01:00
|
|
|
value={parameters.toExtension}
|
2025-07-28 13:58:43 +01:00
|
|
|
placeholder={t("convert.targetFormatPlaceholder", "Target format")}
|
2025-07-23 16:41:27 +01:00
|
|
|
options={enhancedToOptions}
|
2025-07-23 12:01:40 +01:00
|
|
|
onChange={handleToExtensionChange}
|
|
|
|
disabled={disabled}
|
2025-07-23 14:52:54 +01:00
|
|
|
minWidth="21.875rem"
|
2025-07-23 12:01:40 +01:00
|
|
|
/>
|
|
|
|
)}
|
2025-07-23 11:25:55 +01:00
|
|
|
</Stack>
|
|
|
|
|
|
|
|
{/* Format-specific options */}
|
2025-07-25 11:36:57 +01:00
|
|
|
{isImageFormat(parameters.toExtension) && (
|
2025-07-23 11:25:55 +01:00
|
|
|
<>
|
|
|
|
<Divider />
|
2025-07-23 16:55:13 +01:00
|
|
|
<ConvertToImageSettings
|
|
|
|
parameters={parameters}
|
|
|
|
onParameterChange={onParameterChange}
|
|
|
|
disabled={disabled}
|
|
|
|
/>
|
2025-07-23 11:25:55 +01:00
|
|
|
</>
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
|
|
{/* Color options for image to PDF conversion */}
|
2025-07-25 11:36:57 +01:00
|
|
|
{isImageFormat(parameters.fromExtension) && parameters.toExtension === 'pdf' && (
|
2025-07-23 11:25:55 +01:00
|
|
|
<>
|
|
|
|
<Divider />
|
2025-07-23 16:55:13 +01:00
|
|
|
<ConvertFromImageSettings
|
|
|
|
parameters={parameters}
|
|
|
|
onParameterChange={onParameterChange}
|
|
|
|
disabled={disabled}
|
|
|
|
/>
|
2025-07-23 11:25:55 +01:00
|
|
|
</>
|
|
|
|
)}
|
2025-07-25 11:36:57 +01:00
|
|
|
|
|
|
|
{/* EML specific options */}
|
|
|
|
{parameters.fromExtension === 'eml' && parameters.toExtension === 'pdf' && (
|
|
|
|
<>
|
|
|
|
<Divider />
|
2025-07-28 13:58:43 +01:00
|
|
|
<Stack gap="sm" data-testid="eml-options-section">
|
|
|
|
<Text size="sm" fw={500} data-testid="eml-options-title">{t("convert.emlOptions", "Email Options")}:</Text>
|
|
|
|
<Text size="xs" c="dimmed" data-testid="eml-options-note">
|
2025-07-25 11:36:57 +01:00
|
|
|
{t("convert.emlNote", "Email attachments and embedded images will be included in the PDF conversion.")}
|
|
|
|
</Text>
|
|
|
|
</Stack>
|
|
|
|
</>
|
|
|
|
)}
|
2025-07-28 13:58:43 +01:00
|
|
|
|
|
|
|
{/* CSV specific options */}
|
|
|
|
{parameters.fromExtension === 'pdf' && parameters.toExtension === 'csv' && (
|
|
|
|
<>
|
|
|
|
<Divider />
|
|
|
|
<ConvertFromPdfToCsvSettings
|
|
|
|
parameters={parameters}
|
|
|
|
onParameterChange={onParameterChange}
|
|
|
|
disabled={disabled}
|
|
|
|
/>
|
|
|
|
</>
|
|
|
|
)}
|
2025-07-23 11:25:55 +01:00
|
|
|
</Stack>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
export default ConvertSettings;
|