import { useCallback } from 'react'; import { useChartData } from '../context/ChartContext.js'; import { useToaster } from '../context/ToasterContext.js'; import { browserNotSupportedErrorToast, copyPNGToClipboard, exportAsPng, exportAsSVG, } from '../utility/export.js'; import { saveAs } from '../utility/save_as.js'; import { useCreateNmriumZip } from './useCreateNmriumZip.ts'; type DataType = | 'NO_DATA' | 'SELF_CONTAINED' | 'SELF_CONTAINED_EXTERNAL_DATASOURCE'; export interface SaveIncludeOptions { settings: boolean; view: boolean; dataType: DataType; } export interface SaveOptions { include: SaveIncludeOptions; name: string; } export function useExport() { const toaster = useToaster(); const state = useChartData(); const createNmriumZip = useCreateNmriumZip(); const saveHandler = useCallback( (options: SaveOptions) => { async function handler() { const name = options.name || 'experiment'; const include = options.include; const hideLoading = toaster.showLoading({ message: `Exporting as ${name}.nmrium.zip process in progress`, }); setTimeout(async () => { try { const zipBlob = await createNmriumZip(include); saveAs({ blob: zipBlob, name, extension: '.nmrium.zip' }); } catch (error) { toaster.show({ intent: 'danger', message: `Export failed due to an unexpected error: ${(error as Error)?.message || 'Unknown error'}`, }); reportError(error); } finally { hideLoading(); } }, 0); } void handler(); }, [createNmriumZip, toaster], ); const defaultName = state.data[0]?.info?.name || 'experiment'; const defaultSaveAsHandler = useCallback(() => { saveHandler({ name: defaultName, include: { dataType: 'SELF_CONTAINED', view: true, settings: false, }, }); }, [saveHandler, defaultName]); return { defaultSaveAsHandler, saveHandler, }; } export function useExportViewPort() { const toaster = useToaster(); const state = useChartData(); function copyPNGToClipboardHandler(targetElement: HTMLElement) { return new Promise((resolve, reject) => { if (state.data.length === 0 || !targetElement) { return; } const hideLoading = toaster.showLoading({ message: 'Exporting as NMRium process in progress', }); setTimeout(async () => { try { await copyPNGToClipboard('nmrSVG', { rootElement: targetElement, }); toaster.show({ message: 'Image copied to clipboard', intent: 'success', }); resolve(); } catch (error: unknown) { if (error instanceof Error) { toaster.show({ intent: 'danger', message: error.message }); reject(error); } else { toaster.show(browserNotSupportedErrorToast); // eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors reject(error); } } finally { hideLoading(); } }, 0); }); } function saveAsSVGHandler(targetElement: HTMLElement) { return new Promise((resolve) => { if (state.data.length === 0 || !targetElement) { return; } const hideLoading = toaster.showLoading({ message: 'Exporting as SVG process in progress', }); void setTimeout(async () => { const fileName = state.data[0]?.info?.name; exportAsSVG('nmrSVG', { rootElement: targetElement, fileName, }); hideLoading(); resolve(); }, 0); }); } function saveAsPNGHandler(targetElement: HTMLElement) { return new Promise((resolve, reject) => { if (state.data.length === 0 || !targetElement) { return; } const hideLoading = toaster.showLoading({ message: 'Exporting as PNG process in progress', }); void setTimeout(async () => { try { const fileName = state.data[0]?.info?.name; await exportAsPng('nmrSVG', { rootElement: targetElement, fileName, }); resolve(); } catch (error: unknown) { if (error instanceof Error) { toaster.show({ intent: 'danger', message: error.message }); reject(error); } else { toaster.show(browserNotSupportedErrorToast); // eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors reject(error); } } finally { hideLoading(); } }, 0); }); } return { copyPNGToClipboardHandler, saveAsSVGHandler, saveAsPNGHandler, }; }