39948-vm/frontend/src/hooks/useCSVHandling.ts
2026-05-13 16:43:08 +02:00

142 lines
3.6 KiB
TypeScript

/**
* useCSVHandling Hook - Manages CSV upload and download operations
*/
import { useState, useCallback } from 'react';
import axios from 'axios';
import { useAppDispatch } from '../stores/hooks';
import type { AsyncThunk } from '@reduxjs/toolkit';
import { logger } from '../lib/logger';
interface UseCSVHandlingReturn {
csvFile: File | null;
setCsvFile: (file: File | null) => void;
isModalActive: boolean;
setIsModalActive: (active: boolean) => void;
isUploading: boolean;
isDownloading: boolean;
downloadCSV: () => Promise<void>;
uploadCSV: () => Promise<void>;
error: string | null;
}
interface UseCSVHandlingOptions {
endpoint: string;
uploadAction: AsyncThunk<
{ imported: number },
File,
{ rejectValue: unknown }
>;
setRefetchAction: (value: boolean) => { type: string; payload: boolean };
fileName?: string;
}
/**
* Hook for handling CSV upload and download operations
*
* @param options - Configuration options
* @returns CSV handling state and functions
*
* @example
* ```typescript
* const {
* csvFile,
* setCsvFile,
* isModalActive,
* setIsModalActive,
* downloadCSV,
* uploadCSV
* } = useCSVHandling({
* endpoint: 'users',
* uploadAction: uploadCsv,
* setRefetchAction: setRefetch
* })
* ```
*/
export function useCSVHandling(
options: UseCSVHandlingOptions,
): UseCSVHandlingReturn {
const { endpoint, uploadAction, setRefetchAction, fileName } = options;
const dispatch = useAppDispatch();
const [csvFile, setCsvFile] = useState<File | null>(null);
const [isModalActive, setIsModalActive] = useState(false);
const [isUploading, setIsUploading] = useState(false);
const [isDownloading, setIsDownloading] = useState(false);
const [error, setError] = useState<string | null>(null);
const downloadCSV = useCallback(async () => {
setIsDownloading(true);
setError(null);
try {
const response = await axios({
url: `${endpoint}?filetype=csv`,
method: 'GET',
responseType: 'blob',
});
const contentType = (response.headers['content-type'] as string) || 'text/csv';
const blob = new Blob([response.data], { type: contentType });
const link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = fileName || `${endpoint}.csv`;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
window.URL.revokeObjectURL(link.href);
} catch (err) {
const message =
err instanceof Error ? err.message : 'Failed to download CSV';
setError(message);
logger.error(
'CSV download error:',
err instanceof Error ? err : { error: err },
);
} finally {
setIsDownloading(false);
}
}, [endpoint, fileName]);
const uploadCSV = useCallback(async () => {
if (!csvFile) {
setError('No file selected');
return;
}
setIsUploading(true);
setError(null);
try {
await dispatch(uploadAction(csvFile)).unwrap();
dispatch(setRefetchAction(true));
setCsvFile(null);
setIsModalActive(false);
} catch (err) {
const message =
err instanceof Error ? err.message : 'Failed to upload CSV';
setError(message);
logger.error(
'CSV upload error:',
err instanceof Error ? err : { error: err },
);
} finally {
setIsUploading(false);
}
}, [csvFile, dispatch, uploadAction, setRefetchAction]);
return {
csvFile,
setCsvFile,
isModalActive,
setIsModalActive,
isUploading,
isDownloading,
downloadCSV,
uploadCSV,
error,
};
}
export default useCSVHandling;