76 lines
2.2 KiB
TypeScript
76 lines
2.2 KiB
TypeScript
export type BatchItemStatus = 'pending' | 'processing' | 'done' | 'error';
|
|
|
|
export type BatchItem = {
|
|
id: string;
|
|
file: File;
|
|
status: BatchItemStatus;
|
|
resultBytes?: Uint8Array;
|
|
resultName?: string;
|
|
errorMessage?: string | null;
|
|
};
|
|
|
|
export type BatchProcessResult = { bytes: Uint8Array; name: string };
|
|
|
|
export type BatchRunOptions = {
|
|
/**
|
|
* Error message written to a row when `process` throws for it. A function
|
|
* receives the thrown error so tools can surface a specific German message.
|
|
*/
|
|
errorMessage?: string | ((error: unknown, file: File) => string);
|
|
/**
|
|
* Optional predicate consulted before each item; when it returns `false`
|
|
* (for example because the row was removed mid-run), the item is skipped.
|
|
*/
|
|
shouldProcess?: (id: string) => boolean;
|
|
};
|
|
|
|
export const createBatchItem = (file: File): BatchItem => ({
|
|
id: crypto.randomUUID(),
|
|
file,
|
|
status: 'pending'
|
|
});
|
|
|
|
/**
|
|
* Processes the given items strictly one after another so only one PDF is in
|
|
* flight at a time. Never throws: a failing item is marked as an error row and
|
|
* the queue continues with the remaining files.
|
|
*/
|
|
export const runBatch = async (
|
|
items: BatchItem[],
|
|
process: (file: File) => Promise<BatchProcessResult>,
|
|
update: (id: string, patch: Partial<BatchItem>) => void,
|
|
options: BatchRunOptions = {}
|
|
): Promise<void> => {
|
|
const { errorMessage = 'Die Datei konnte nicht verarbeitet werden.', shouldProcess } = options;
|
|
|
|
for (const item of items) {
|
|
if (shouldProcess && !shouldProcess(item.id)) continue;
|
|
|
|
update(item.id, { status: 'processing', errorMessage: null });
|
|
try {
|
|
const result = await process(item.file);
|
|
update(item.id, {
|
|
status: 'done',
|
|
resultBytes: result.bytes,
|
|
resultName: result.name,
|
|
errorMessage: null
|
|
});
|
|
} catch (error) {
|
|
console.error(`Batch processing failed for ${item.file.name}:`, error);
|
|
update(item.id, {
|
|
status: 'error',
|
|
resultBytes: undefined,
|
|
resultName: undefined,
|
|
errorMessage:
|
|
typeof errorMessage === 'function' ? errorMessage(error, item.file) : errorMessage
|
|
});
|
|
}
|
|
}
|
|
};
|
|
|
|
export const formatBytes = (bytes: number) => {
|
|
if (bytes < 1024) return `${bytes} B`;
|
|
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
};
|