Skip to content

Commit

Permalink
refactor: Used ModalProvider for unsaved changes dialog
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelkoelle committed May 16, 2021
1 parent ed2b253 commit ab4422b
Show file tree
Hide file tree
Showing 7 changed files with 155 additions and 179 deletions.
202 changes: 43 additions & 159 deletions app/Routes.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
/* eslint react/jsx-props-no-spreading: off */
import React, { useEffect, useState } from 'react';
import React, { useEffect, useRef, useState } from 'react';
import { Switch, Route } from 'react-router-dom';
import { createMuiTheme, ThemeProvider } from '@material-ui/core/styles';
import CssBaseline from '@material-ui/core/CssBaseline';
import { ipcRenderer, remote } from 'electron';
import { useDispatch, useSelector } from 'react-redux';
import { UpdateInfo } from 'electron-updater';
Expand All @@ -29,87 +27,35 @@ import {
selectWorkspacePath,
workspaceSetPath,
} from './features/workspace/workspaceSlice';
import ConfirmDialog from './components/ConfirmDialog';
import {
selectSettingsBackup,
selectSettingsTheme,
} from './model/SettingsSlice';
import { shouldUseDarkColors, themeToPaletteType } from './model/Theme';
import { selectSettingsBackup } from './model/SettingsSlice';
import { BACKUP_START, BACKUP_STOP } from './constants/BackupIPC';
import DialogProvider from './dialogs/DialogProvider';
import ModalProvider from './dialogs/ModalProvider';

const createTheme = (appTheme) =>
createMuiTheme({
palette: {
type: themeToPaletteType(appTheme),
},
overrides: {
MuiCssBaseline: {
'@global': {
'*::-webkit-scrollbar': {
width: '0.5em',
height: '0.5em',
},
'*::-webkit-scrollbar-track': {
'-webkit-box-shadow': 'inset 0 0 6px rgba(0,0,0,0.00)',
},
'*::-webkit-scrollbar-thumb': {
backgroundColor: shouldUseDarkColors(appTheme)
? 'rgba(255,255,255,.2)'
: 'rgba(0,0,0,.2)',
outline: '1px solid slategrey',
borderRadius: '5px',
},
'*::-webkit-scrollbar-corner': {
opacity: 0,
},
},
},
},
});
import { useModal } from './dialogs/ModalProvider';
import ConfirmationDialog from './dialogs/ConfirmationDialog';
import UnsavedChangesDialog from './dialogs/UnsavedChangesDialog';

export default function Routes() {
const dispatch = useDispatch();
const showModal = useRef(useModal());
const unsavedChanges = useSelector(selectUnsavedChanges);
const appTheme = useSelector(selectSettingsTheme);
const saveBackups = useSelector(selectSettingsBackup);
const workspacePath = useSelector(selectWorkspacePath);
const [, setMuiTheme] = useState(createTheme(appTheme));
const [openUpdaterDialog, setOpenUpdaterDialog] = useState<boolean>(false);
const [showNotAvailiable, setShowNotAvailiable] = useState<boolean>(false);
const [openSaveDialog, setOpenSaveDialog] = useState<boolean>(false);
const [openSaveDialogNewFile, setOpenSaveDialogNewFile] = useState<boolean>(
false
);
const [openSaveDialogExit, setOpenSaveDialogExit] = useState<boolean>(false);
const [quitAnyways, setQuitAnyways] = useState<boolean>(false);
const [reload, setReload] = useState<boolean>(false);
const [newFilePath, setNewFilePath] = useState<string>('');

function updaterDialog(show: boolean) {
setShowNotAvailiable(show);
setOpenUpdaterDialog(true);
}

function unsavedChangesDialog(path: string) {
setNewFilePath(path);
if (unsavedChanges) {
setOpenSaveDialogNewFile(true);
} else {
dispatch(workspaceSetPath(path));
dispatch(reloadState());
}
}

useEffect(() => {
ipcRenderer.on(RECEIVE_FILE_PATH, (_event, data: string) => {
if (Path.extname(data) === '.cor') {
setNewFilePath(data);
ipcRenderer.on(RECEIVE_FILE_PATH, (_event, path: string) => {
if (Path.extname(path) === '.cor') {
if (unsavedChanges) {
setOpenSaveDialogNewFile(true);
showModal.current(ConfirmationDialog, UnsavedChangesDialog(path));
} else {
dispatch(workspaceSetPath(data));
dispatch(workspaceSetPath(path));
dispatch(reloadState());
}
}
Expand All @@ -118,7 +64,7 @@ export default function Routes() {
return () => {
ipcRenderer.removeAllListeners(RECEIVE_FILE_PATH);
};
}, [dispatch, unsavedChanges]);
}, [dispatch, showModal, unsavedChanges]);

useEffect(() => {
ipcRenderer.on(
Expand Down Expand Up @@ -161,107 +107,45 @@ export default function Routes() {
} else if (unsavedChanges && !quitAnyways) {
e.returnValue = false;
e.preventDefault();
setOpenSaveDialogExit(true);
showModal.current(ConfirmationDialog, {
title: 'Save before quitting?',
text: 'Do you want to save your changes before quitting?',
onConfirm: () => {
dispatch(save());
setQuitAnyways(false);
remote.getCurrentWindow().close();
},
onReject: () => {
setQuitAnyways(true);
remote.getCurrentWindow().close();
},
onCancel: () => {
setQuitAnyways(false);
},
});
}
};
window.addEventListener('beforeunload', beforeQuit, true);
return () => {
window.removeEventListener('beforeunload', beforeQuit, true);
};
}, [dispatch, quitAnyways, reload, unsavedChanges]);

useEffect(() => {
const setTheme = () => {
// Does nothing but required for force reload
setMuiTheme(createTheme(appTheme));
};
remote.nativeTheme.on('updated', setTheme);
return () => {
remote.nativeTheme.removeListener('updated', setTheme);
};
}, [appTheme]);
}, [dispatch, quitAnyways, reload, showModal, unsavedChanges]);

return (
<ThemeProvider theme={createTheme(appTheme)}>
<CssBaseline />
<App>
<DialogProvider>
<ModalProvider>
<FramelessTitleBar
setOpenUpdater={updaterDialog}
unsavedChangesDialog={unsavedChangesDialog}
setReload={setReload}
/>
<Switch>
<Route
path={routes.SHEETOVERVIEW}
component={SheetOverviewPage}
/>
<Route
path={routes.CORRECTIONVIEW}
component={CorrectionViewPage}
/>
<Route path={routes.OVERVIEW} component={OverviewPage} />
<Route
path={routes.SCHEMAGENERATOR}
component={SchemeGeneratorPage}
/>
<Route path={routes.HOME} component={NewHomePage} />
</Switch>
<UpdaterDialog
open={openUpdaterDialog}
setOpen={setOpenUpdaterDialog}
showNotAvailiable={showNotAvailiable}
/>
<ConfirmDialog
open={openSaveDialog}
setOpen={setOpenSaveDialog}
title="Unsaved changes"
text="Do you want to save your changes?"
onConfirm={() => {
dispatch(save());
setOpenSaveDialog(false);
}}
onReject={() => setOpenSaveDialog(false)}
/>
<ConfirmDialog
open={openSaveDialogNewFile}
setOpen={setOpenSaveDialogNewFile}
title="Unsaved changes"
text="Do you want to save your changes before loading the new file?"
onConfirm={() => {
dispatch(save());
setOpenSaveDialogNewFile(false);
dispatch(workspaceSetPath(newFilePath));
dispatch(reloadState());
}}
onReject={() => {
setOpenSaveDialogNewFile(false);
dispatch(workspaceSetPath(newFilePath));
dispatch(reloadState());
}}
/>
<ConfirmDialog
open={openSaveDialogExit}
setOpen={setOpenSaveDialogExit}
title="Unsaved changes"
text="Do you want to save your changes before quitting? Click reload to discard your changes."
onConfirm={() => {
dispatch(save());
setQuitAnyways(false);
remote.getCurrentWindow().close();
}}
onReject={() => {
setQuitAnyways(true);
remote.getCurrentWindow().close();
}}
onCancel={() => {
setQuitAnyways(false);
}}
/>
</ModalProvider>
</DialogProvider>
</App>
</ThemeProvider>
<App>
<FramelessTitleBar setOpenUpdater={updaterDialog} setReload={setReload} />
<Switch>
<Route path={routes.SHEETOVERVIEW} component={SheetOverviewPage} />
<Route path={routes.CORRECTIONVIEW} component={CorrectionViewPage} />
<Route path={routes.OVERVIEW} component={OverviewPage} />
<Route path={routes.SCHEMAGENERATOR} component={SchemeGeneratorPage} />
<Route path={routes.HOME} component={NewHomePage} />
</Switch>
<UpdaterDialog
open={openUpdaterDialog}
setOpen={setOpenUpdaterDialog}
showNotAvailiable={showNotAvailiable}
/>
</App>
);
}
10 changes: 6 additions & 4 deletions app/containers/FramelessTitleBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,11 @@ const currentWindow = remote.getCurrentWindow();

export default function FramelessTitleBar(props: {
setOpenUpdater: (boolean) => void;
unsavedChangesDialog: (string) => void;
setReload: (boolean) => void;
}) {
const dispatch = useAppDispatch();
const showModal = useModal();
const { setOpenUpdater, unsavedChangesDialog, setReload } = props;
const { setOpenUpdater, setReload } = props;
const theme = useTheme();
const workspace: string = useSelector(selectWorkspacePath);
const settings: SettingsState = useSelector(selectSettings);
Expand Down Expand Up @@ -126,7 +125,7 @@ export default function FramelessTitleBar(props: {
workspace,
settings,
sheets,
unsavedChangesDialog,
unsavedChanges,
recentPaths,
setOpenFileError,
backupPaths,
Expand Down Expand Up @@ -162,7 +161,10 @@ export default function FramelessTitleBar(props: {
title={`${
workspace.length > 0 ? `${Path.parse(workspace).name} - ` : ''
}correctinator v${version}${unsavedChanges ? ' •' : ''}`}
onClose={() => currentWindow.close()}
onClose={() => {
console.log('onCLose');
currentWindow.close();
}}
onMinimize={() => currentWindow.minimize()}
onMaximize={handleMaximize}
// when the titlebar is double clicked
Expand Down
45 changes: 35 additions & 10 deletions app/containers/Root.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,47 @@
import React from 'react';
import React, { useEffect, useState } from 'react';
import { Provider } from 'react-redux';
import { ConnectedRouter } from 'connected-react-router';
import { hot } from 'react-hot-loader/root';
import { History } from 'history';
import { Store } from '../store';
import { CssBaseline, ThemeProvider, useTheme } from '@material-ui/core';
import { remote } from 'electron';
import { AnyAction, EnhancedStore } from '@reduxjs/toolkit';
import Routes from '../Routes';
import ModalProvider from '../dialogs/ModalProvider';
import createTheme from '../theme';

type Props = {
store: Store;
store: EnhancedStore<any, AnyAction, any[]>;
history: History;
};

const Root = ({ store, history }: Props) => (
<Provider store={store}>
<ConnectedRouter history={history}>
<Routes />
</ConnectedRouter>
</Provider>
);
const Root = ({ store, history }: Props) => {
const theme = useTheme();
const [, setCurrentTheme] = useState(createTheme(theme));

useEffect(() => {
const setTheme = () => {
// Does nothing but required for force reload
setCurrentTheme(createTheme(theme));
};
remote.nativeTheme.on('updated', setTheme);
return () => {
remote.nativeTheme.removeListener('updated', setTheme);
};
}, [theme]);

return (
<Provider store={store}>
<ThemeProvider theme={createTheme(theme)}>
<CssBaseline />
<ModalProvider>
<ConnectedRouter history={history}>
<Routes />
</ConnectedRouter>
</ModalProvider>
</ThemeProvider>
</Provider>
);
};

export default hot(Root);
20 changes: 20 additions & 0 deletions app/dialogs/UnsavedChangesDialog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { workspaceSetPath } from '../features/workspace/workspaceSlice';
import { reloadState, save } from '../utils/FileAccess';

const UnsavedChangesDialog = (newFilePath) => {
return {
title: 'Unsaved changes',
text: 'Do you want to save your changes, before loading a new file?',
onConfirm: (dispatch) => {
dispatch(save());
dispatch(workspaceSetPath(newFilePath));
dispatch(reloadState());
},
onReject: (dispatch) => {
dispatch(workspaceSetPath(newFilePath));
dispatch(reloadState());
},
};
};

export default UnsavedChangesDialog;
Loading

0 comments on commit ab4422b

Please sign in to comment.