import isElectron from 'is-electron'; import React, { useEffect, useState } from 'react'; import { Button } from 'react-bootstrap'; import exportService, { ExportProgress, ExportStage, ExportStats, ExportType } from 'services/exportService'; import styled from 'styled-components'; import { sleep } from 'utils/common'; import { getData, LS_KEYS, setData } from 'utils/storage/localStorage'; import constants from 'utils/strings/constants'; import { Label, Row, Value } from './Container'; import ExportFinished from './ExportFinished'; import ExportInit from './ExportInit'; import ExportInProgress from './ExportInProgress'; import FolderIcon from './icons/FolderIcon'; import InProgressIcon from './icons/InProgressIcon'; import MessageDialog from './MessageDialog'; const FolderIconWrapper = styled.div` width: 15%; margin-left: 10px; cursor: pointer; padding: 3px; border: 1px solid #444; border-radius:15%; &:hover{ background-color:#444; } `; interface Props { show: boolean onHide: () => void usage: string } export default function ExportModal(props: Props) { const [exportStage, setExportStage] = useState(ExportStage.INIT); const [exportFolder, setExportFolder] = useState(''); const [exportSize, setExportSize] = useState(''); const [exportProgress, setExportProgress] = useState({ current: 0, total: 0 }); const [exportStats, setExportStats] = useState({ failed: 0, success: 0 }); const [lastExportTime, setLastExportTime] = useState(0); // ==================== // SIDE EFFECTS // ==================== useEffect(() => { if (!isElectron()) { return; } setExportFolder(getData(LS_KEYS.EXPORT)?.folder); exportService.ElectronAPIs.registerStopExportListener(stopExport); exportService.ElectronAPIs.registerPauseExportListener(pauseExport); exportService.ElectronAPIs.registerResumeExportListener(resumeExport); exportService.ElectronAPIs.registerRetryFailedExportListener(retryFailedExport); }, []); useEffect(() => { const main = async () => { const exportInfo = await exportService.getExportRecord(); setExportStage(exportInfo?.stage ?? ExportStage.INIT); setLastExportTime(exportInfo?.lastAttemptTimestamp); setExportProgress(exportInfo?.progress ?? { current: 0, total: 0 }); setExportStats({ success: exportInfo?.exportedFiles?.length ?? 0, failed: exportInfo?.failedFiles?.length ?? 0 }); if (exportInfo?.stage === ExportStage.INPROGRESS) { startExport(); } }; main(); }, [exportFolder]); useEffect(() => { setExportSize(props.usage); }, [props.usage]); // ============= // STATE UPDATERS // ============== const updateExportFolder = (newFolder: string) => { setExportFolder(newFolder); setData(LS_KEYS.EXPORT, { folder: newFolder }); }; const updateExportStage = (newStage: ExportStage) => { setExportStage(newStage); exportService.updateExportRecord({ stage: newStage }); }; const updateExportTime = (newTime: number) => { setLastExportTime(newTime); exportService.updateExportRecord({ time: newTime }); }; const updateExportProgress = (newProgress: ExportProgress) => { setExportProgress(newProgress); exportService.updateExportRecord({ progress: newProgress }); }; // ====================== // HELPER FUNCTIONS // ========================= const preExportRun = async () => { const exportFolder = getData(LS_KEYS.EXPORT)?.folder; if (!exportFolder) { const folderSelected = await selectExportDirectory(); if (!folderSelected) { // no-op as select folder aborted return; } } updateExportStage(ExportStage.INPROGRESS); await sleep(100); }; const postExportRun = async (paused: Boolean) => { if (!paused) { updateExportStage(ExportStage.FINISHED); await sleep(100); updateExportTime(Date.now()); syncExportStatsWithReport(); } }; const startExport = async () => { await preExportRun(); updateExportProgress({ current: 0, total: 0 }); const { paused } = await exportService.exportFiles(updateExportProgress, ExportType.NEW); await postExportRun(paused); }; const stopExport = async () => { if (exportStage === ExportStage.PAUSED) { postExportRun(false); } else { exportService.stopRunningExport(); } }; const pauseExport = () => { updateExportStage(ExportStage.PAUSED); exportService.pauseRunningExport(); }; const resumeExport = async () => { const exportRecord = await exportService.getExportRecord(); if (exportRecord.stage !== ExportStage.PAUSED) { // export not paused return; } await preExportRun(); const pausedStageProgress = exportRecord.progress; updateExportProgress(pausedStageProgress); const updateExportStatsWithOffset = ((progress: ExportProgress) => updateExportProgress( { current: pausedStageProgress.current + progress.current, total: pausedStageProgress.current + progress.total, }, )); const { paused } = await exportService.exportFiles(updateExportStatsWithOffset, ExportType.PENDING); await postExportRun(paused); }; const retryFailedExport = async () => { await preExportRun(); updateExportProgress({ current: 0, total: exportStats.failed }); const { paused } = await exportService.exportFiles(updateExportProgress, ExportType.RETRY_FAILED); await postExportRun(paused); }; const syncExportStatsWithReport = async () => { const exportRecord = await exportService.getExportRecord(); const failed = exportRecord?.failedFiles?.length ?? 0; const success = exportRecord?.exportedFiles?.length ?? 0; setExportStats({ failed, success }); }; const selectExportDirectory = async () => { const newFolder = await exportService.selectExportDirectory(); if (newFolder) { updateExportFolder(newFolder); return true; } else { return false; } }; const ExportDynamicState = () => { switch (exportStage) { case ExportStage.INIT: return ( ); case ExportStage.INPROGRESS: case ExportStage.PAUSED: return ( ); case ExportStage.FINISHED: return ( ); default: return (<>); } }; return (
{!exportFolder ? () : (<> {exportFolder} {(exportStage === ExportStage.FINISHED || exportStage === ExportStage.INIT) && ( )} ) } {exportSize ? `${exportSize} GB` : }
); }