feat(5-03-04): create useExport hook for managing export API calls and file downloads
This commit is contained in:
118
frontend/hooks/useExport.ts
Normal file
118
frontend/hooks/useExport.ts
Normal file
@@ -0,0 +1,118 @@
|
||||
import { useState } from "react";
|
||||
import axios from "axios";
|
||||
|
||||
interface UseExportReturn {
|
||||
exportSnapshot: (format: "csv" | "xlsx") => Promise<void>;
|
||||
exportAuditTrail: (format: "csv" | "xlsx") => Promise<void>;
|
||||
isLoading: boolean;
|
||||
error: string | null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom hook for managing inventory export operations.
|
||||
* Handles API calls, file downloads, and error management.
|
||||
*
|
||||
* @returns Object with export functions and state
|
||||
*/
|
||||
export function useExport(): UseExportReturn {
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
/**
|
||||
* Extract filename from Content-Disposition header.
|
||||
* Handles both inline and attachment disposition.
|
||||
*/
|
||||
const extractFilenameFromHeader = (contentDisposition: string): string => {
|
||||
const match = contentDisposition.match(/filename="?([^"]+)"?/);
|
||||
return match ? match[1] : `export_${Date.now()}`;
|
||||
};
|
||||
|
||||
/**
|
||||
* Trigger file download from blob response.
|
||||
*/
|
||||
const downloadFile = (blob: Blob, filename: string) => {
|
||||
const url = URL.createObjectURL(blob);
|
||||
const link = document.createElement("a");
|
||||
link.href = url;
|
||||
link.download = filename;
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
URL.revokeObjectURL(url);
|
||||
};
|
||||
|
||||
/**
|
||||
* Export inventory snapshot in specified format.
|
||||
*/
|
||||
const exportSnapshot = async (format: "csv" | "xlsx"): Promise<void> => {
|
||||
setIsLoading(true);
|
||||
setError(null);
|
||||
|
||||
try {
|
||||
const response = await axios.post(
|
||||
`/api/admin/exports/inventory-snapshot?format=${format}`,
|
||||
{},
|
||||
{
|
||||
responseType: "blob",
|
||||
}
|
||||
);
|
||||
|
||||
// Extract filename from response headers
|
||||
const contentDisposition = response.headers["content-disposition"] || "";
|
||||
const filename = contentDisposition
|
||||
? extractFilenameFromHeader(contentDisposition)
|
||||
: `inventory_snapshot_${new Date().toISOString().split("T")[0]}.${format}`;
|
||||
|
||||
// Trigger download
|
||||
downloadFile(response.data, filename);
|
||||
} catch (err) {
|
||||
const errorMessage =
|
||||
err instanceof Error ? err.message : "Failed to export inventory snapshot";
|
||||
setError(errorMessage);
|
||||
throw err;
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Export audit trail in specified format.
|
||||
*/
|
||||
const exportAuditTrail = async (format: "csv" | "xlsx"): Promise<void> => {
|
||||
setIsLoading(true);
|
||||
setError(null);
|
||||
|
||||
try {
|
||||
const response = await axios.post(
|
||||
`/api/admin/exports/audit-trail?format=${format}`,
|
||||
{},
|
||||
{
|
||||
responseType: "blob",
|
||||
}
|
||||
);
|
||||
|
||||
// Extract filename from response headers
|
||||
const contentDisposition = response.headers["content-disposition"] || "";
|
||||
const filename = contentDisposition
|
||||
? extractFilenameFromHeader(contentDisposition)
|
||||
: `audit_trail_${new Date().toISOString().split("T")[0]}.${format}`;
|
||||
|
||||
// Trigger download
|
||||
downloadFile(response.data, filename);
|
||||
} catch (err) {
|
||||
const errorMessage =
|
||||
err instanceof Error ? err.message : "Failed to export audit trail";
|
||||
setError(errorMessage);
|
||||
throw err;
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
exportSnapshot,
|
||||
exportAuditTrail,
|
||||
isLoading,
|
||||
error,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user