mirror of
https://github.com/arsvendg/Stirling-PDF.git
synced 2026-07-15 19:10:47 +02:00
Restructure frontend code to allow for extensions (#4721)
# Description of Changes Move frontend code into `core` folder and add infrastructure for `proprietary` folder to include premium, non-OSS features
This commit is contained in:
@@ -0,0 +1,144 @@
|
||||
import { buildChangeMetadataFormData } from '@app/hooks/tools/changeMetadata/useChangeMetadataOperation';
|
||||
import { ChangeMetadataParameters } from '@app/hooks/tools/changeMetadata/useChangeMetadataParameters';
|
||||
import { TrappedStatus } from '@app/types/metadata';
|
||||
import { describe, expect, test } from 'vitest';
|
||||
|
||||
describe('buildChangeMetadataFormData', () => {
|
||||
const mockFile = new File(['test'], 'test.pdf', { type: 'application/pdf' });
|
||||
|
||||
const defaultParams: ChangeMetadataParameters = {
|
||||
title: '',
|
||||
author: '',
|
||||
subject: '',
|
||||
keywords: '',
|
||||
creator: '',
|
||||
producer: '',
|
||||
creationDate: null,
|
||||
modificationDate: null,
|
||||
trapped: TrappedStatus.UNKNOWN,
|
||||
customMetadata: [],
|
||||
deleteAll: false,
|
||||
};
|
||||
|
||||
test.each([
|
||||
{
|
||||
name: 'should build FormData with basic parameters',
|
||||
params: {
|
||||
...defaultParams,
|
||||
title: 'Test Document',
|
||||
author: 'John Doe',
|
||||
deleteAll: true,
|
||||
},
|
||||
expectedFormData: {
|
||||
fileInput: mockFile,
|
||||
title: 'Test Document',
|
||||
author: 'John Doe',
|
||||
deleteAll: 'true',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'should handle empty string values',
|
||||
params: defaultParams,
|
||||
expectedFormData: {
|
||||
title: '',
|
||||
author: '',
|
||||
subject: '',
|
||||
keywords: '',
|
||||
creator: '',
|
||||
producer: '',
|
||||
creationDate: '',
|
||||
modificationDate: '',
|
||||
trapped: TrappedStatus.UNKNOWN,
|
||||
deleteAll: 'false',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'should include all standard metadata fields',
|
||||
params: {
|
||||
...defaultParams,
|
||||
title: 'Test Title',
|
||||
author: 'Test Author',
|
||||
subject: 'Test Subject',
|
||||
keywords: 'test, keywords',
|
||||
creator: 'Test Creator',
|
||||
producer: 'Test Producer',
|
||||
creationDate: new Date('2025/01/17 14:30:00'),
|
||||
modificationDate: new Date('2025/01/17 15:30:00'),
|
||||
trapped: TrappedStatus.TRUE,
|
||||
},
|
||||
expectedFormData: {
|
||||
title: 'Test Title',
|
||||
author: 'Test Author',
|
||||
subject: 'Test Subject',
|
||||
keywords: 'test, keywords',
|
||||
creator: 'Test Creator',
|
||||
producer: 'Test Producer',
|
||||
creationDate: '2025/01/17 14:30:00',
|
||||
modificationDate: '2025/01/17 15:30:00',
|
||||
trapped: TrappedStatus.TRUE,
|
||||
},
|
||||
},
|
||||
])('$name', ({ params, expectedFormData }) => {
|
||||
const formData = buildChangeMetadataFormData(params, mockFile);
|
||||
|
||||
Object.entries(expectedFormData).forEach(([key, value]) => {
|
||||
expect(formData.get(key)).toBe(value);
|
||||
});
|
||||
});
|
||||
|
||||
test('should handle custom metadata with proper indexing', () => {
|
||||
const params = {
|
||||
...defaultParams,
|
||||
customMetadata: [
|
||||
{ key: 'Department', value: 'Engineering', id: 'custom1' },
|
||||
{ key: 'Project', value: 'Test Project', id: 'custom2' },
|
||||
{ key: 'Status', value: 'Draft', id: 'custom3' },
|
||||
],
|
||||
};
|
||||
|
||||
const formData = buildChangeMetadataFormData(params, mockFile);
|
||||
|
||||
expect(formData.get('allRequestParams[customKey1]')).toBe('Department');
|
||||
expect(formData.get('allRequestParams[customValue1]')).toBe('Engineering');
|
||||
expect(formData.get('allRequestParams[customKey2]')).toBe('Project');
|
||||
expect(formData.get('allRequestParams[customValue2]')).toBe('Test Project');
|
||||
expect(formData.get('allRequestParams[customKey3]')).toBe('Status');
|
||||
expect(formData.get('allRequestParams[customValue3]')).toBe('Draft');
|
||||
});
|
||||
|
||||
test('should skip custom metadata with empty keys or values', () => {
|
||||
const params = {
|
||||
...defaultParams,
|
||||
customMetadata: [
|
||||
{ key: 'Department', value: 'Engineering', id: 'custom1' },
|
||||
{ key: '', value: 'No Key', id: 'custom2' },
|
||||
{ key: 'No Value', value: '', id: 'custom3' },
|
||||
{ key: ' ', value: 'Whitespace Key', id: 'custom4' },
|
||||
{ key: 'Valid', value: 'Valid Value', id: 'custom5' },
|
||||
],
|
||||
};
|
||||
|
||||
const formData = buildChangeMetadataFormData(params, mockFile);
|
||||
|
||||
expect(formData.get('allRequestParams[customKey1]')).toBe('Department');
|
||||
expect(formData.get('allRequestParams[customValue1]')).toBe('Engineering');
|
||||
expect(formData.get('allRequestParams[customKey2]')).toBe('Valid');
|
||||
expect(formData.get('allRequestParams[customValue2]')).toBe('Valid Value');
|
||||
expect(formData.get('allRequestParams[customKey3]')).toBeNull();
|
||||
expect(formData.get('allRequestParams[customKey4]')).toBeNull();
|
||||
});
|
||||
|
||||
test('should trim whitespace from custom metadata', () => {
|
||||
const params = {
|
||||
...defaultParams,
|
||||
customMetadata: [
|
||||
{ key: ' Department ', value: ' Engineering ', id: 'custom1' },
|
||||
],
|
||||
};
|
||||
|
||||
const formData = buildChangeMetadataFormData(params, mockFile);
|
||||
|
||||
expect(formData.get('allRequestParams[customKey1]')).toBe('Department');
|
||||
expect(formData.get('allRequestParams[customValue1]')).toBe('Engineering');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,71 @@
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useToolOperation, ToolType } from '@app/hooks/tools/shared/useToolOperation';
|
||||
import { createStandardErrorHandler } from '@app/utils/toolErrorHandler';
|
||||
import { ChangeMetadataParameters, defaultParameters } from '@app/hooks/tools/changeMetadata/useChangeMetadataParameters';
|
||||
|
||||
// Helper function to format Date object to string
|
||||
const formatDateForBackend = (date: Date | null): string => {
|
||||
if (!date) return '';
|
||||
const year = date.getFullYear();
|
||||
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||||
const day = String(date.getDate()).padStart(2, '0');
|
||||
const hours = String(date.getHours()).padStart(2, '0');
|
||||
const minutes = String(date.getMinutes()).padStart(2, '0');
|
||||
const seconds = String(date.getSeconds()).padStart(2, '0');
|
||||
return `${year}/${month}/${day} ${hours}:${minutes}:${seconds}`;
|
||||
};
|
||||
|
||||
// Static function that can be used by both the hook and automation executor
|
||||
export const buildChangeMetadataFormData = (parameters: ChangeMetadataParameters, file: File): FormData => {
|
||||
const formData = new FormData();
|
||||
formData.append("fileInput", file);
|
||||
|
||||
// Standard metadata fields
|
||||
formData.append("title", parameters.title || "");
|
||||
formData.append("author", parameters.author || "");
|
||||
formData.append("subject", parameters.subject || "");
|
||||
formData.append("keywords", parameters.keywords || "");
|
||||
formData.append("creator", parameters.creator || "");
|
||||
formData.append("producer", parameters.producer || "");
|
||||
|
||||
// Date fields - convert Date objects to strings
|
||||
formData.append("creationDate", formatDateForBackend(parameters.creationDate));
|
||||
formData.append("modificationDate", formatDateForBackend(parameters.modificationDate));
|
||||
|
||||
// Trapped status
|
||||
formData.append("trapped", parameters.trapped || "");
|
||||
|
||||
// Delete all metadata flag
|
||||
formData.append("deleteAll", parameters.deleteAll.toString());
|
||||
|
||||
// Custom metadata - backend expects them as values to 'allRequestParams[customKeyX/customValueX]'
|
||||
let keyNumber = 0;
|
||||
parameters.customMetadata.forEach((entry) => {
|
||||
if (entry.key.trim() && entry.value.trim()) {
|
||||
keyNumber += 1;
|
||||
formData.append(`allRequestParams[customKey${keyNumber}]`, entry.key.trim());
|
||||
formData.append(`allRequestParams[customValue${keyNumber}]`, entry.value.trim());
|
||||
}
|
||||
});
|
||||
|
||||
return formData;
|
||||
};
|
||||
|
||||
// Static configuration object
|
||||
export const changeMetadataOperationConfig = {
|
||||
toolType: ToolType.singleFile,
|
||||
buildFormData: buildChangeMetadataFormData,
|
||||
operationType: 'changeMetadata',
|
||||
endpoint: '/api/v1/misc/update-metadata',
|
||||
defaultParameters,
|
||||
} as const;
|
||||
|
||||
export const useChangeMetadataOperation = () => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return useToolOperation<ChangeMetadataParameters>({
|
||||
...changeMetadataOperationConfig,
|
||||
filePrefix: t('changeMetadata.filenamePrefix', 'metadata') + '_',
|
||||
getErrorMessage: createStandardErrorHandler(t('changeMetadata.error.failed', 'An error occurred while changing the PDF metadata.'))
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,168 @@
|
||||
import { renderHook, act } from '@testing-library/react';
|
||||
import { defaultParameters, useChangeMetadataParameters } from '@app/hooks/tools/changeMetadata/useChangeMetadataParameters';
|
||||
import { TrappedStatus } from '@app/types/metadata';
|
||||
import { describe, expect, test } from 'vitest';
|
||||
|
||||
describe('useChangeMetadataParameters', () => {
|
||||
test('should initialize with default parameters', () => {
|
||||
const { result } = renderHook(() => useChangeMetadataParameters());
|
||||
|
||||
expect(result.current.parameters).toStrictEqual(defaultParameters);
|
||||
});
|
||||
|
||||
describe('parameter updates', () => {
|
||||
test.each([
|
||||
{ paramName: 'title', value: 'Test Document' },
|
||||
{ paramName: 'author', value: 'John Doe' },
|
||||
{ paramName: 'subject', value: 'Test Subject' },
|
||||
{ paramName: 'keywords', value: 'test, metadata' },
|
||||
{ paramName: 'creator', value: 'Test Creator' },
|
||||
{ paramName: 'producer', value: 'Test Producer' },
|
||||
{ paramName: 'creationDate', value: new Date('2025/01/17 14:30:00') },
|
||||
{ paramName: 'modificationDate', value: new Date('2025/01/17 15:30:00') },
|
||||
{ paramName: 'trapped', value: TrappedStatus.TRUE },
|
||||
{ paramName: 'deleteAll', value: true },
|
||||
] as const)('should update $paramName parameter', ({ paramName, value }) => {
|
||||
const { result } = renderHook(() => useChangeMetadataParameters());
|
||||
|
||||
act(() => {
|
||||
result.current.updateParameter(paramName, value);
|
||||
});
|
||||
|
||||
expect(result.current.parameters[paramName]).toBe(value);
|
||||
});
|
||||
});
|
||||
|
||||
describe('validation', () => {
|
||||
test.each([
|
||||
{ description: 'deleteAll is true', updates: { deleteAll: true }, expected: true },
|
||||
{ description: 'has title', updates: { title: 'Test Document' }, expected: true },
|
||||
{ description: 'has author', updates: { author: 'John Doe' }, expected: true },
|
||||
{ description: 'has subject', updates: { subject: 'Test Subject' }, expected: true },
|
||||
{ description: 'has keywords', updates: { keywords: 'test' }, expected: true },
|
||||
{ description: 'has creator', updates: { creator: 'Test Creator' }, expected: true },
|
||||
{ description: 'has producer', updates: { producer: 'Test Producer' }, expected: true },
|
||||
{ description: 'has creation date', updates: { creationDate: new Date('2025/01/17 14:30:00') }, expected: true },
|
||||
{ description: 'has modification date', updates: { modificationDate: new Date('2025/01/17 14:30:00') }, expected: true },
|
||||
{ description: 'has trapped status', updates: { trapped: TrappedStatus.TRUE }, expected: true },
|
||||
{ description: 'no meaningful content', updates: {}, expected: false },
|
||||
{ description: 'whitespace only', updates: { title: ' ', author: ' ' }, expected: false },
|
||||
])('should validate correctly when $description', ({ updates, expected }) => {
|
||||
const { result } = renderHook(() => useChangeMetadataParameters());
|
||||
|
||||
act(() => {
|
||||
Object.entries(updates).forEach(([key, value]) => {
|
||||
result.current.updateParameter(key as keyof typeof updates, value);
|
||||
});
|
||||
});
|
||||
|
||||
expect(result.current.validateParameters()).toBe(expected);
|
||||
});
|
||||
|
||||
test.each([
|
||||
{ description: 'valid creation date', updates: { title: 'Test', creationDate: new Date('2025/01/17 14:30:00') }, expected: true },
|
||||
{ description: 'valid modification date', updates: { title: 'Test', modificationDate: new Date('2025/01/17 14:30:00') }, expected: true },
|
||||
{ description: 'empty dates are valid', updates: { title: 'Test', creationDate: null, modificationDate: null }, expected: true },
|
||||
])('should validate dates correctly with $description', ({ updates, expected }) => {
|
||||
const { result } = renderHook(() => useChangeMetadataParameters());
|
||||
|
||||
act(() => {
|
||||
Object.entries(updates).forEach(([key, value]) => {
|
||||
result.current.updateParameter(key as keyof typeof updates, value);
|
||||
});
|
||||
});
|
||||
|
||||
expect(result.current.validateParameters()).toBe(expected);
|
||||
});
|
||||
});
|
||||
|
||||
describe('custom metadata', () => {
|
||||
test('should add custom metadata with sequential IDs', () => {
|
||||
const { result } = renderHook(() => useChangeMetadataParameters());
|
||||
|
||||
act(() => {
|
||||
result.current.addCustomMetadata();
|
||||
});
|
||||
|
||||
expect(result.current.parameters.customMetadata).toHaveLength(1);
|
||||
expect(result.current.parameters.customMetadata[0]).toEqual({
|
||||
key: '',
|
||||
value: '',
|
||||
id: expect.stringMatching(/^custom\d+$/)
|
||||
});
|
||||
});
|
||||
|
||||
test('should remove custom metadata by ID', () => {
|
||||
const { result } = renderHook(() => useChangeMetadataParameters());
|
||||
|
||||
act(() => {
|
||||
result.current.addCustomMetadata();
|
||||
});
|
||||
|
||||
const customId = result.current.parameters.customMetadata[0].id;
|
||||
|
||||
act(() => {
|
||||
result.current.removeCustomMetadata(customId);
|
||||
});
|
||||
|
||||
expect(result.current.parameters.customMetadata).toHaveLength(0);
|
||||
});
|
||||
|
||||
test('should update custom metadata by ID', () => {
|
||||
const { result } = renderHook(() => useChangeMetadataParameters());
|
||||
|
||||
act(() => {
|
||||
result.current.addCustomMetadata();
|
||||
});
|
||||
|
||||
const customId = result.current.parameters.customMetadata[0].id;
|
||||
|
||||
act(() => {
|
||||
result.current.updateCustomMetadata(customId, 'Department', 'Engineering');
|
||||
});
|
||||
|
||||
expect(result.current.parameters.customMetadata[0]).toEqual({
|
||||
key: 'Department',
|
||||
value: 'Engineering',
|
||||
id: customId
|
||||
});
|
||||
});
|
||||
|
||||
test('should validate with custom metadata', () => {
|
||||
const { result } = renderHook(() => useChangeMetadataParameters());
|
||||
|
||||
act(() => {
|
||||
result.current.addCustomMetadata();
|
||||
});
|
||||
|
||||
const customId = result.current.parameters.customMetadata[0].id;
|
||||
|
||||
act(() => {
|
||||
result.current.updateCustomMetadata(customId, 'Department', 'Engineering');
|
||||
});
|
||||
|
||||
expect(result.current.validateParameters()).toBe(true);
|
||||
});
|
||||
|
||||
test('should generate unique IDs for multiple custom entries', () => {
|
||||
const { result } = renderHook(() => useChangeMetadataParameters());
|
||||
|
||||
for (let i = 0; i < 3; i++) {
|
||||
act(() => {
|
||||
result.current.addCustomMetadata();
|
||||
});
|
||||
}
|
||||
|
||||
const ids = result.current.parameters.customMetadata.map(entry => entry.id);
|
||||
expect(ids).toHaveLength(3);
|
||||
expect(new Set(ids).size).toBe(3); // All unique
|
||||
expect(ids.every(id => id.startsWith('custom'))).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
test('should return correct endpoint name', () => {
|
||||
const { result } = renderHook(() => useChangeMetadataParameters());
|
||||
|
||||
expect(result.current.getEndpointName()).toBe('update-metadata');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,136 @@
|
||||
import { BaseParameters } from '@app/types/parameters';
|
||||
import { TrappedStatus, CustomMetadataEntry } from '@app/types/metadata';
|
||||
import { useBaseParameters, BaseParametersHook } from '@app/hooks/tools/shared/useBaseParameters';
|
||||
|
||||
export interface ChangeMetadataParameters extends BaseParameters {
|
||||
// Standard PDF metadata fields
|
||||
title: string;
|
||||
author: string;
|
||||
subject: string;
|
||||
keywords: string;
|
||||
creator: string;
|
||||
producer: string;
|
||||
|
||||
// Date fields
|
||||
creationDate: Date | null;
|
||||
modificationDate: Date | null;
|
||||
|
||||
// Trapped status
|
||||
trapped: TrappedStatus;
|
||||
|
||||
// Custom metadata entries
|
||||
customMetadata: CustomMetadataEntry[];
|
||||
|
||||
// Delete all metadata option
|
||||
deleteAll: boolean;
|
||||
}
|
||||
|
||||
export const defaultParameters: ChangeMetadataParameters = {
|
||||
title: '',
|
||||
author: '',
|
||||
subject: '',
|
||||
keywords: '',
|
||||
creator: '',
|
||||
producer: '',
|
||||
creationDate: null,
|
||||
modificationDate: null,
|
||||
trapped: TrappedStatus.UNKNOWN,
|
||||
customMetadata: [],
|
||||
deleteAll: false,
|
||||
};
|
||||
|
||||
// Global counter for custom metadata IDs
|
||||
let customMetadataIdCounter = 1;
|
||||
|
||||
// Utility functions that can work with external parameters
|
||||
export const createCustomMetadataFunctions = (
|
||||
parameters: ChangeMetadataParameters,
|
||||
onParameterChange: <K extends keyof ChangeMetadataParameters>(key: K, value: ChangeMetadataParameters[K]) => void
|
||||
) => {
|
||||
const addCustomMetadata = (key: string = '', value: string = '') => {
|
||||
const newEntry: CustomMetadataEntry = {
|
||||
key,
|
||||
value,
|
||||
id: `custom${customMetadataIdCounter++}`,
|
||||
};
|
||||
|
||||
onParameterChange('customMetadata', [
|
||||
...parameters.customMetadata,
|
||||
newEntry,
|
||||
]);
|
||||
};
|
||||
|
||||
const removeCustomMetadata = (id: string) => {
|
||||
onParameterChange('customMetadata',
|
||||
parameters.customMetadata.filter(entry => entry.id !== id)
|
||||
);
|
||||
};
|
||||
|
||||
const updateCustomMetadata = (id: string, key: string, value: string) => {
|
||||
onParameterChange('customMetadata',
|
||||
parameters.customMetadata.map(entry =>
|
||||
entry.id === id ? { ...entry, key, value } : entry
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
return {
|
||||
addCustomMetadata,
|
||||
removeCustomMetadata,
|
||||
updateCustomMetadata
|
||||
};
|
||||
};
|
||||
|
||||
// Validation function
|
||||
const validateParameters = (params: ChangeMetadataParameters): boolean => {
|
||||
// If deleteAll is true, no other validation needed
|
||||
if (params.deleteAll) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// At least one field should have content for the operation to be meaningful
|
||||
const hasStandardMetadata = !!(
|
||||
params.title.trim()
|
||||
|| params.author.trim()
|
||||
|| params.subject.trim()
|
||||
|| params.keywords.trim()
|
||||
|| params.creator.trim()
|
||||
|| params.producer.trim()
|
||||
|| params.creationDate
|
||||
|| params.modificationDate
|
||||
|| params.trapped !== TrappedStatus.UNKNOWN
|
||||
);
|
||||
|
||||
const hasCustomMetadata = params.customMetadata.some(
|
||||
entry => entry.key.trim() && entry.value.trim()
|
||||
);
|
||||
|
||||
return hasStandardMetadata || hasCustomMetadata;
|
||||
};
|
||||
|
||||
export type ChangeMetadataParametersHook = BaseParametersHook<ChangeMetadataParameters> & {
|
||||
addCustomMetadata: (key?: string, value?: string) => void;
|
||||
removeCustomMetadata: (id: string) => void;
|
||||
updateCustomMetadata: (id: string, key: string, value: string) => void;
|
||||
};
|
||||
|
||||
export const useChangeMetadataParameters = (): ChangeMetadataParametersHook => {
|
||||
const base = useBaseParameters({
|
||||
defaultParameters,
|
||||
endpointName: 'update-metadata',
|
||||
validateFn: validateParameters,
|
||||
});
|
||||
|
||||
// Use the utility functions with the hook's parameters and updateParameter
|
||||
const { addCustomMetadata, removeCustomMetadata, updateCustomMetadata } = createCustomMetadataFunctions(
|
||||
base.parameters,
|
||||
base.updateParameter,
|
||||
);
|
||||
|
||||
return {
|
||||
...base,
|
||||
addCustomMetadata,
|
||||
removeCustomMetadata,
|
||||
updateCustomMetadata
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,70 @@
|
||||
import { useState, useEffect, useRef } from "react";
|
||||
import { extractPDFMetadata } from "@app/services/pdfMetadataService";
|
||||
import { useSelectedFiles } from "@app/contexts/file/fileHooks";
|
||||
import { ChangeMetadataParameters } from "@app/hooks/tools/changeMetadata/useChangeMetadataParameters";
|
||||
|
||||
interface MetadataExtractionParams {
|
||||
updateParameter: <K extends keyof ChangeMetadataParameters>(key: K, value: ChangeMetadataParameters[K]) => void;
|
||||
}
|
||||
|
||||
export const useMetadataExtraction = (params: MetadataExtractionParams) => {
|
||||
const { selectedFiles } = useSelectedFiles();
|
||||
const [isExtractingMetadata, setIsExtractingMetadata] = useState(false);
|
||||
const [hasExtractedMetadata, setHasExtractedMetadata] = useState(false);
|
||||
const previousFileCountRef = useRef(0);
|
||||
|
||||
// Reset extraction state only when files are cleared (length goes to 0)
|
||||
useEffect(() => {
|
||||
if (previousFileCountRef.current > 0 && selectedFiles.length === 0) {
|
||||
setHasExtractedMetadata(false);
|
||||
}
|
||||
previousFileCountRef.current = selectedFiles.length;
|
||||
}, [selectedFiles]);
|
||||
|
||||
// Extract metadata from first file when files change
|
||||
useEffect(() => {
|
||||
const extractMetadata = async () => {
|
||||
if (selectedFiles.length === 0) {
|
||||
return;
|
||||
}
|
||||
const firstFile = selectedFiles[0];
|
||||
|
||||
if (hasExtractedMetadata) {
|
||||
return;
|
||||
}
|
||||
|
||||
setIsExtractingMetadata(true);
|
||||
|
||||
const result = await extractPDFMetadata(firstFile);
|
||||
|
||||
if (result.success) {
|
||||
const metadata = result.metadata;
|
||||
|
||||
// Pre-populate all fields with extracted metadata
|
||||
params.updateParameter('title', metadata.title);
|
||||
params.updateParameter('author', metadata.author);
|
||||
params.updateParameter('subject', metadata.subject);
|
||||
params.updateParameter('keywords', metadata.keywords);
|
||||
params.updateParameter('creator', metadata.creator);
|
||||
params.updateParameter('producer', metadata.producer);
|
||||
params.updateParameter('creationDate', metadata.creationDate ? new Date(metadata.creationDate) : null);
|
||||
params.updateParameter('modificationDate', metadata.modificationDate ? new Date(metadata.modificationDate) : null);
|
||||
params.updateParameter('trapped', metadata.trapped);
|
||||
params.updateParameter('customMetadata', metadata.customMetadata);
|
||||
|
||||
setHasExtractedMetadata(true);
|
||||
} else {
|
||||
console.warn('Failed to extract metadata:', result.error);
|
||||
}
|
||||
|
||||
setIsExtractingMetadata(false);
|
||||
};
|
||||
|
||||
extractMetadata();
|
||||
}, [selectedFiles, hasExtractedMetadata, params]);
|
||||
|
||||
return {
|
||||
isExtractingMetadata,
|
||||
hasExtractedMetadata,
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user