Skip to content

Commit

Permalink
feat: export and import NMRIUM file as ZIP.
Browse files Browse the repository at this point in the history
- close #950, Compress NMRIUM json data for download / upload.
- create custom hook for export.
- refactor export and remove export actions from reducer.
  • Loading branch information
hamed-musallam committed Apr 8, 2021
1 parent c06e5ac commit 7bf6f44
Show file tree
Hide file tree
Showing 13 changed files with 262 additions and 137 deletions.
11 changes: 6 additions & 5 deletions src/component/EventsTrackers/KeysListenerTracker.js
Expand Up @@ -6,6 +6,8 @@ import { useChartData } from '../context/ChartContext';
import { useDispatch } from '../context/DispatchContext';
import { useAlert } from '../elements/popup/Alert';
import { TYPES, useHighlightData } from '../highlight/index';
import useExport from '../hooks/useExport';
import useToolsFunctions from '../hooks/useToolsFunctions';
import { DISPLAYER_MODE } from '../reducer/core/Constants';
import {
SET_KEY_PREFERENCES,
Expand All @@ -16,7 +18,6 @@ import {
DELETE_2D_ZONE,
} from '../reducer/types/Types';
import { options } from '../toolbar/ToolTypes';
import useToolsFunctions from '../toolbar/useToolsFunctions';

function KeysListenerTracker() {
const {
Expand All @@ -32,9 +33,9 @@ function KeysListenerTracker() {
handleFullZoomOut,
alignSpectrumsVerticallyHandler,
handleChangeDisplayViewMode,
saveToClipboardHandler,
saveAsJSONHandler,
} = useToolsFunctions(dispatch, alert);
} = useToolsFunctions();

const { saveToClipboardHandler, saveAsJSONHandler } = useExport();

const { highlight } = useHighlightData();
const assignmentData = useAssignmentData();
Expand Down Expand Up @@ -205,7 +206,7 @@ function KeysListenerTracker() {
if (e.shiftKey && (e.metaKey || e.ctrlKey)) {
switch (e.key) {
case 'S':
saveAsJSONHandler(2);
saveAsJSONHandler(2, false);
e.preventDefault();
break;
default:
Expand Down
89 changes: 89 additions & 0 deletions src/component/hooks/useExport.js
@@ -0,0 +1,89 @@
import { useCallback } from 'react';

import { toJSON } from '../../data/SpectraManager';
import { useChartData } from '../context/ChartContext';
import { useDispatch } from '../context/DispatchContext';
import { useAlert } from '../elements/popup/Alert';
import { SET_LOADING_FLAG } from '../reducer/types/Types';
import {
exportAsJSON,
exportAsNMRE,
exportAsPng,
exportAsSVG,
} from '../utility/Export';
import { toNmredata } from '../utility/toNmredata';

export default function useExport() {
const dispatch = useDispatch();
const alert = useAlert();
const state = useChartData();

const saveToClipboardHandler = useCallback(() => {
if (state.data.length > 0) {
dispatch({ type: SET_LOADING_FLAG, isLoading: true });
setTimeout(() => {
// eslint-disable-next-line no-undef
copyPNGToClipboard('nmrSVG');
dispatch({ type: SET_LOADING_FLAG, isLoading: false });
alert.show('Spectrum copied to clipboard');
}, 0);
}
}, [alert, dispatch, state]);

const saveAsJSONHandler = useCallback(
(spaceIndent = 0, isCompressed = true) => {
if (state.data.length > 0) {
dispatch({ type: SET_LOADING_FLAG, isLoading: true });
setTimeout(async () => {
//exported file name by default will be the first spectrum name
const fileName = state.data[0]?.display?.name;
const exportedData = toJSON(state);
await exportAsJSON(exportedData, fileName, spaceIndent, isCompressed);
dispatch({ type: SET_LOADING_FLAG, isLoading: false });
}, 0);
}
},
[dispatch, state],
);

const saveAsNMREHandler = useCallback(() => {
if (state.data.length > 0) {
dispatch({ type: SET_LOADING_FLAG, isLoading: true });
setTimeout(() => {
const fileName = state.data[0]?.display?.name;
const exportedData = toNmredata(state);
exportAsNMRE(exportedData, fileName);
dispatch({ type: SET_LOADING_FLAG, isLoading: false });
}, 0);
}
}, [dispatch, state]);

const saveAsSVGHandler = useCallback(() => {
if (state.data.length > 0) {
dispatch({ type: SET_LOADING_FLAG, isLoading: true });
setTimeout(() => {
const fileName = state.data[0]?.display?.name;
exportAsSVG(fileName, 'nmrSVG');
dispatch({ type: SET_LOADING_FLAG, isLoading: true });
}, 0);
}
}, [dispatch, state.data]);

const saveAsPNGHandler = useCallback(() => {
if (state.data.length > 0) {
dispatch({ type: SET_LOADING_FLAG, isLoading: true });
setTimeout(() => {
const fileName = state.data[0]?.display?.name;
exportAsPng(fileName, 'nmrSVG');
}, 0);
}
}, [dispatch, state.data]);

return {
saveToClipboardHandler,
saveAsJSONHandler,
saveAsNMREHandler,
saveAsSVGHandler,
saveAsPNGHandler,
};
}
Expand Up @@ -2,19 +2,21 @@ import lodashDebounce from 'lodash/debounce';
import lodashMap from 'lodash/map';
import { useCallback, useRef, useState } from 'react';

import { useDispatch } from '../context/DispatchContext';
import { useAlert } from '../elements/popup/Alert';
import { ZoomType } from '../reducer/actions/Zoom';
import {
CHANGE_SPECTRUM_DISPLAY_VIEW_MODE,
EXPORT_DATA,
FULL_ZOOM_OUT,
SET_SELECTED_TOOL,
SET_SPECTRUMS_VERTICAL_ALIGN,
TOGGLE_REAL_IMAGINARY_VISIBILITY,
} from '../reducer/types/Types';
import { options } from '../toolbar/ToolTypes';

import { options } from './ToolTypes';

export default function useToolsFunctions(dispatch, alert) {
export default function useToolsFunctions() {
const dispatch = useDispatch();
const alert = useAlert();
const [isRealSpectrumShown, setIsRealSpectrumShown] = useState(false);
const [isStacked, activateStackView] = useState(false);

Expand Down Expand Up @@ -62,41 +64,6 @@ export default function useToolsFunctions(dispatch, alert) {
}
}, [dispatch, debounceClickEventsRef]);

const saveToClipboardHandler = useCallback(() => {
dispatch({ type: EXPORT_DATA, exportType: 'copy' });
alert.show('Spectrum copied to clipboard');
}, [alert, dispatch]);

const saveAsJSONHandler = useCallback(
(spaceIndent = 0) => {
dispatch({
type: EXPORT_DATA,
exportType: 'json',
spaceIndent: spaceIndent,
});
},
[dispatch],
);

const saveAsNMREHandler = useCallback(() => {
dispatch({
type: EXPORT_DATA,
exportType: 'nmre',
});
}, [dispatch]);

const saveAsSVGHandler = useCallback(() => {
dispatch({
type: EXPORT_DATA,
exportType: 'svg',
});
}, [dispatch]);

const saveAsPNGHandler = useCallback(
() => dispatch({ type: EXPORT_DATA, exportType: 'png' }),
[dispatch],
);

const handleChangeDisplayViewMode = useCallback(() => {
const flag = !isStacked;
activateStackView(flag);
Expand All @@ -123,11 +90,6 @@ export default function useToolsFunctions(dispatch, alert) {
return {
handleChangeOption,
handleFullZoomOut,
saveToClipboardHandler,
saveAsJSONHandler,
saveAsNMREHandler,
saveAsSVGHandler,
saveAsPNGHandler,
handleChangeDisplayViewMode,
changeSpectrumViewHandler,
alignSpectrumsVerticallyHandler,
Expand Down
116 changes: 100 additions & 16 deletions src/component/loader/DropZone.jsx
@@ -1,5 +1,6 @@
/** @jsxImportSource @emotion/react */
import { css } from '@emotion/react';
import Zip from 'jszip';
import { createRef, useCallback } from 'react';
import { useDropzone } from 'react-dropzone';
import { FaUpload } from 'react-icons/fa';
Expand All @@ -14,7 +15,12 @@ import {
LOAD_ZIP_FILE,
LOAD_JDF_FILE,
} from '../reducer/types/Types';
import { getFileExtension, loadFiles } from '../utility/FileUtility';
import {
FILES_TYPES,
getFileExtension,
loadFiles,
loadFilesFromZip,
} from '../utility/FileUtility';

const style = css`
height: 100%;
Expand Down Expand Up @@ -54,21 +60,67 @@ export const DropZoneRef = createRef();
function DropZone(props) {
const { width, height } = useChartData();
const dispatch = useDispatch();
const onDrop = useCallback(
(droppedFiles) => {
dispatch({ type: SET_LOADING_FLAG, isLoading: true });
const loadsubFilesfromZip = useCallback(
(extractedfiles, uniqueFileExtensions) => {
for (let extension of uniqueFileExtensions) {
const selectedFilesByExtensions = extractedfiles.filter(
(file) => getFileExtension(file.name) === extension,
);

switch (extension) {
case FILES_TYPES.MOL:
loadFilesFromZip(selectedFilesByExtensions).then((files) =>
dispatch({ type: LOAD_MOL_FILE, files }),
);

break;
case FILES_TYPES.NMRIUM:
case FILES_TYPES.JSON:
loadFilesFromZip(selectedFilesByExtensions).then((files) => {
if (selectedFilesByExtensions.length === 1) {
dispatch({ type: LOAD_JSON_FILE, files });
} else {
dispatch({ type: SET_LOADING_FLAG, isLoading: false });
// eslint-disable-next-line no-alert
alert('You can add only one json file');
}
});
break;

case FILES_TYPES.JDX:
case FILES_TYPES.DX:
loadFilesFromZip(selectedFilesByExtensions).then((files) =>
dispatch({ type: LOAD_JCAMP_FILE, files }),
);

break;
case FILES_TYPES.JDF:
loadFilesFromZip(selectedFilesByExtensions, {
asBuffer: true,
}).then((files) => dispatch({ type: LOAD_JDF_FILE, files }));
break;

default:
break;
}
}
},
[dispatch],
);

const loadFilesHandler = useCallback(
(files) => {
const uniqueFileExtensions = [
...new Set(droppedFiles.map((file) => getFileExtension(file.name))),
...new Set(files.map((file) => getFileExtension(file.name))),
];

for (let extension of uniqueFileExtensions) {
const selectedFilesByExtensions = droppedFiles.filter(
const selectedFilesByExtensions = files.filter(
(file) => getFileExtension(file.name) === extension,
);

switch (extension) {
case 'mol':
case FILES_TYPES.MOL:
loadFiles(selectedFilesByExtensions).then(
(files) => {
dispatch({ type: LOAD_MOL_FILE, files });
Expand All @@ -79,8 +131,8 @@ function DropZone(props) {
},
);
break;
case 'nmrium':
case 'json':
case FILES_TYPES.NMRIUM:
case FILES_TYPES.JSON:
if (selectedFilesByExtensions.length === 1) {
loadFiles(selectedFilesByExtensions).then(
(files) => {
Expand All @@ -98,8 +150,8 @@ function DropZone(props) {

break;

case 'dx':
case 'jdx':
case FILES_TYPES.JDX:
case FILES_TYPES.DX:
loadFiles(selectedFilesByExtensions).then(
(files) => {
dispatch({ type: LOAD_JCAMP_FILE, files });
Expand All @@ -110,7 +162,7 @@ function DropZone(props) {
},
);
break;
case 'jdf':
case FILES_TYPES.JDF:
loadFiles(selectedFilesByExtensions, { asBuffer: true }).then(
(files) => {
dispatch({ type: LOAD_JDF_FILE, files });
Expand All @@ -121,10 +173,34 @@ function DropZone(props) {
},
);
break;
case 'zip':
case FILES_TYPES.ZIP:
loadFiles(selectedFilesByExtensions).then(
(files) => {
dispatch({ type: LOAD_ZIP_FILE, files });
async (files) => {
for (const zipFile of files) {
const unzipResult = await Zip.loadAsync(zipFile.binary);

const uniqueFileExtensions = [
...new Set(
Object.values(unzipResult.files).map((file) =>
getFileExtension(file.name),
),
),
];

const isNotZip = uniqueFileExtensions.some(
(ex) =>
FILES_TYPES[ex.toUpperCase()] && ex !== FILES_TYPES.ZIP,
);

if (isNotZip) {
loadsubFilesfromZip(
Object.values(unzipResult.files),
uniqueFileExtensions,
);
} else {
dispatch({ type: LOAD_ZIP_FILE, files });
}
}
},
(err) => {
// eslint-disable-next-line no-alert
Expand All @@ -141,7 +217,15 @@ function DropZone(props) {
}
}
},
[dispatch],
[dispatch, loadsubFilesfromZip],
);

const onDrop = useCallback(
(droppedFiles) => {
dispatch({ type: SET_LOADING_FLAG, isLoading: true });
loadFilesHandler(droppedFiles);
},
[dispatch, loadFilesHandler],
);

DropZoneRef.current = useDropzone({
Expand Down
2 changes: 1 addition & 1 deletion src/component/loader/NoData.jsx
Expand Up @@ -46,7 +46,7 @@ function NoData({

return (
<div css={styles} onClick={openFileDialogHadnler}>
<p>{message}</p>
<p>{message}</p>
</div>
);
}
Expand Down

0 comments on commit 7bf6f44

Please sign in to comment.