import { useState, useEffect } from 'react'; import { COLOR_TYPES, OUTPUT_OPTIONS, FIT_OPTIONS, TO_FORMAT_OPTIONS, CONVERSION_MATRIX, type ColorType, type OutputOption, type FitOption } from '../../../constants/convertConstants'; import { getEndpointName as getEndpointNameUtil, getEndpointUrl, isImageFormat, isWebFormat } from '../../../utils/convertUtils'; import { detectFileExtension as detectFileExtensionUtil } from '../../../utils/fileUtils'; export interface ConvertParameters { fromExtension: string; toExtension: string; imageOptions: { colorType: ColorType; dpi: number; singleOrMultiple: OutputOption; fitOption: FitOption; autoRotate: boolean; combineImages: boolean; }; htmlOptions: { zoomLevel: number; }; emailOptions: { includeAttachments: boolean; maxAttachmentSizeMB: number; downloadHtml: boolean; includeAllRecipients: boolean; }; pdfaOptions: { outputFormat: string; }; isSmartDetection: boolean; smartDetectionType: 'mixed' | 'images' | 'web' | 'none'; } export interface ConvertParametersHook { parameters: ConvertParameters; updateParameter: (parameter: keyof ConvertParameters, value: any) => void; resetParameters: () => void; validateParameters: () => boolean; getEndpointName: () => string; getEndpoint: () => string; getAvailableToExtensions: (fromExtension: string) => Array<{value: string, label: string, group: string}>; analyzeFileTypes: (files: Array<{name: string}>) => void; } const initialParameters: ConvertParameters = { fromExtension: '', toExtension: '', imageOptions: { colorType: COLOR_TYPES.COLOR, dpi: 300, singleOrMultiple: OUTPUT_OPTIONS.MULTIPLE, fitOption: FIT_OPTIONS.MAINTAIN_ASPECT, autoRotate: true, combineImages: true, }, htmlOptions: { zoomLevel: 1.0, }, emailOptions: { includeAttachments: true, maxAttachmentSizeMB: 10, downloadHtml: false, includeAllRecipients: false, }, pdfaOptions: { outputFormat: 'pdfa-1', }, isSmartDetection: false, smartDetectionType: 'none', }; export const useConvertParameters = (): ConvertParametersHook => { const [parameters, setParameters] = useState(initialParameters); const updateParameter = (parameter: keyof ConvertParameters, value: any) => { setParameters(prev => ({ ...prev, [parameter]: value })); }; const resetParameters = () => { setParameters(initialParameters); }; const validateParameters = () => { const { fromExtension, toExtension } = parameters; if (!fromExtension || !toExtension) return false; // Handle dynamic format identifiers (file-) let supportedToExtensions: string[] = []; if (fromExtension.startsWith('file-')) { // Dynamic format - use 'any' conversion options supportedToExtensions = CONVERSION_MATRIX['any'] || []; } else { // Regular format - check conversion matrix supportedToExtensions = CONVERSION_MATRIX[fromExtension] || []; } if (!supportedToExtensions.includes(toExtension)) { return false; } return true; }; const getEndpointName = () => { const { fromExtension, toExtension, isSmartDetection, smartDetectionType } = parameters; if (isSmartDetection) { if (smartDetectionType === 'mixed') { // Mixed file types -> PDF using file-to-pdf endpoint return 'file-to-pdf'; } else if (smartDetectionType === 'images') { // All images -> PDF using img-to-pdf endpoint return 'img-to-pdf'; } else if (smartDetectionType === 'web') { // All web files -> PDF using html-to-pdf endpoint return 'html-to-pdf'; } } // Handle dynamic format identifiers (file-) if (fromExtension.startsWith('file-')) { // Dynamic format - use file-to-pdf endpoint return 'file-to-pdf'; } return getEndpointNameUtil(fromExtension, toExtension); }; const getEndpoint = () => { const { fromExtension, toExtension, isSmartDetection, smartDetectionType } = parameters; if (isSmartDetection) { if (smartDetectionType === 'mixed') { // Mixed file types -> PDF using file-to-pdf endpoint return '/api/v1/convert/file/pdf'; } else if (smartDetectionType === 'images') { // All images -> PDF using img-to-pdf endpoint return '/api/v1/convert/img/pdf'; } else if (smartDetectionType === 'web') { // All web files -> PDF using html-to-pdf endpoint return '/api/v1/convert/html/pdf'; } } // Handle dynamic format identifiers (file-) if (fromExtension.startsWith('file-')) { // Dynamic format - use file-to-pdf endpoint return '/api/v1/convert/file/pdf'; } return getEndpointUrl(fromExtension, toExtension); }; const getAvailableToExtensions = (fromExtension: string) => { if (!fromExtension) return []; // Handle dynamic format identifiers (file-) if (fromExtension.startsWith('file-')) { // Dynamic format - use 'any' conversion options (file-to-pdf) const supportedExtensions = CONVERSION_MATRIX['any'] || []; return TO_FORMAT_OPTIONS.filter(option => supportedExtensions.includes(option.value) ); } let supportedExtensions = CONVERSION_MATRIX[fromExtension] || []; // If no explicit conversion exists, but file-to-pdf might be available, // fall back to 'any' conversion (which converts unknown files to PDF via file-to-pdf) if (supportedExtensions.length === 0 && fromExtension !== 'any') { supportedExtensions = CONVERSION_MATRIX['any'] || []; } return TO_FORMAT_OPTIONS.filter(option => supportedExtensions.includes(option.value) ); }; const analyzeFileTypes = (files: Array<{name: string}>) => { if (files.length === 0) { // No files - only reset smart detection, keep user's format choices setParameters(prev => ({ ...prev, isSmartDetection: false, smartDetectionType: 'none' // Don't reset fromExtension and toExtension - let user keep their choices })); return; } if (files.length === 1) { // Single file - use regular detection with smart target selection const detectedExt = detectFileExtensionUtil(files[0].name); let fromExt = detectedExt; let availableTargets = detectedExt ? CONVERSION_MATRIX[detectedExt] || [] : []; // If no explicit conversion exists for this file type, create a dynamic format entry // and fall back to 'any' conversion logic for the actual endpoint if (availableTargets.length === 0 && detectedExt) { fromExt = `file-${detectedExt}`; // Create dynamic format identifier availableTargets = CONVERSION_MATRIX['any'] || []; } else if (availableTargets.length === 0) { // No extension detected - fall back to 'any' fromExt = 'any'; availableTargets = CONVERSION_MATRIX['any'] || []; } setParameters(prev => { // Check if current toExtension is still valid for the new fromExtension const currentToExt = prev.toExtension; const isCurrentToExtValid = availableTargets.includes(currentToExt); // Auto-select target only if: // 1. No current target is set, OR // 2. Current target is invalid for new source type, OR // 3. There's only one possible target (forced conversion) let newToExtension = currentToExt; if (!currentToExt || !isCurrentToExtValid) { newToExtension = availableTargets.length === 1 ? availableTargets[0] : ''; } return { ...prev, isSmartDetection: false, smartDetectionType: 'none', fromExtension: fromExt, toExtension: newToExtension }; }); return; } // Multiple files - analyze file types const extensions = files.map(file => detectFileExtensionUtil(file.name)); const uniqueExtensions = [...new Set(extensions)]; if (uniqueExtensions.length === 1) { // All files are the same type - use regular detection with smart target selection const detectedExt = uniqueExtensions[0]; let fromExt = detectedExt; let availableTargets = CONVERSION_MATRIX[detectedExt] || []; // If no explicit conversion exists for this file type, fall back to 'any' if (availableTargets.length === 0) { fromExt = 'any'; availableTargets = CONVERSION_MATRIX['any'] || []; } setParameters(prev => { // Check if current toExtension is still valid for the new fromExtension const currentToExt = prev.toExtension; const isCurrentToExtValid = availableTargets.includes(currentToExt); // Auto-select target only if: // 1. No current target is set, OR // 2. Current target is invalid for new source type, OR // 3. There's only one possible target (forced conversion) let newToExtension = currentToExt; if (!currentToExt || !isCurrentToExtValid) { newToExtension = availableTargets.length === 1 ? availableTargets[0] : ''; } return { ...prev, isSmartDetection: false, smartDetectionType: 'none', fromExtension: fromExt, toExtension: newToExtension }; }); } else { // Mixed file types const allImages = uniqueExtensions.every(ext => isImageFormat(ext)); const allWeb = uniqueExtensions.every(ext => isWebFormat(ext)); if (allImages) { // All files are images - use image-to-pdf conversion setParameters(prev => ({ ...prev, isSmartDetection: true, smartDetectionType: 'images', fromExtension: 'image', toExtension: 'pdf' })); } else if (allWeb) { // All files are web files - use html-to-pdf conversion setParameters(prev => ({ ...prev, isSmartDetection: true, smartDetectionType: 'web', fromExtension: 'html', toExtension: 'pdf' })); } else { // Mixed non-image types - use file-to-pdf conversion setParameters(prev => ({ ...prev, isSmartDetection: true, smartDetectionType: 'mixed', fromExtension: 'any', toExtension: 'pdf' })); } } }; return { parameters, updateParameter, resetParameters, validateParameters, getEndpointName, getEndpoint, getAvailableToExtensions, analyzeFileTypes, }; };