Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor selected note state from flux to redux #1851

Merged
merged 5 commits into from
Jan 30, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions RELEASE-NOTES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,8 @@
### Other Changes

- Added types to state/ui/actions [#1849](https://github.com/Automattic/simplenote-electron/pull/1849)

### Other Changes

- Updated Dependencies [#1848](https://github.com/Automattic/simplenote-electron/pull/1848)
- Refactored selected note state [1851](https://github.com/Automattic/simplenote-electron/pull/1851)

## [v1.14.0]

Expand Down
1 change: 1 addition & 0 deletions babel.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ module.exports = function(api) {
const plugins = [
'@babel/plugin-proposal-class-properties',
'@babel/plugin-proposal-object-rest-spread',
'@babel/plugin-proposal-optional-chaining',
'@babel/plugin-syntax-dynamic-import',
];
const env = {
Expand Down
9 changes: 1 addition & 8 deletions lib/app-layout/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import React, { FunctionComponent, Suspense } from 'react';
import classNames from 'classnames';
import { get } from 'lodash';

import NoteToolbarContainer from '../note-toolbar-container';
import NoteToolbar from '../note-toolbar';
Expand Down Expand Up @@ -40,7 +39,6 @@ export const AppLayout: FunctionComponent<Props> = ({
isNoteInfoOpen,
isNoteOpen,
isSmallScreen,
note,
noteBucket,
revisions,
onNoteClosed,
Expand Down Expand Up @@ -76,25 +74,20 @@ export const AppLayout: FunctionComponent<Props> = ({
</div>
<div className="app-layout__note-column theme-color-bg theme-color-fg theme-color-border">
<RevisionSelector
note={note}
revisions={revisions || []}
onUpdateContent={onUpdateContent}
/>
<NoteToolbarContainer
onNoteClosed={onNoteClosed}
noteBucket={noteBucket}
toolbar={<NoteToolbar note={note} />}
toolbar={<NoteToolbar />}
/>
<NoteEditor
isSmallScreen={isSmallScreen}
note={note}
noteBucket={noteBucket}
onNoteClosed={onNoteClosed}
onUpdateContent={onUpdateContent}
syncNote={syncNote}
tags={
get(note, 'data.tags', []) /* flattened to trigger re-render */
}
belcherj marked this conversation as resolved.
Show resolved Hide resolved
/>
</div>
</Suspense>
Expand Down
40 changes: 29 additions & 11 deletions lib/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,32 @@ import { toggleSimperiumConnectionStatus } from './state/ui/actions';

import * as settingsActions from './state/settings/actions';

import actions from './state/actions';
import * as S from './state';
import * as T from './types';

const ipc = getIpcRenderer();

export type OwnProps = {
noteBucket: object;
};

export type DispatchProps = {
selectNote: (note: T.NoteEntity) => any;
};

export type Props = DispatchProps;

const mapStateToProps = state => ({
...state,
authIsPending: selectors.auth.authIsPending(state),
isAuthorized: selectors.auth.isAuthorized(state),
});

function mapDispatchToProps(dispatch, { noteBucket }) {
const mapDispatchToProps: S.MapDispatch<
DispatchProps,
OwnProps
> = function mapDispatchToProps(dispatch, { noteBucket }) {
const actionCreators = Object.assign({}, appState.actionCreators);

const thenReloadNotes = action => a => {
Expand Down Expand Up @@ -85,8 +102,9 @@ function mapDispatchToProps(dispatch, { noteBucket }) {
dispatch(actionCreators.setSearchFocus({ searchFocus: true })),
setSimperiumConnectionStatus: connected =>
dispatch(toggleSimperiumConnectionStatus(connected)),
selectNote: note => dispatch(actions.ui.selectNote(note)),
};
}
};

const isElectron = (() => {
// https://github.com/atom/electron/issues/2288
Expand All @@ -102,7 +120,7 @@ export const App = connect(
mapStateToProps,
mapDispatchToProps
)(
class extends Component {
class extends Component<Props> {
static displayName = 'App';

static propTypes = {
Expand All @@ -120,7 +138,6 @@ export const App = connect(
openTagList: PropTypes.func.isRequired,
onSignOut: PropTypes.func.isRequired,
settings: PropTypes.object.isRequired,
noteBucket: PropTypes.object.isRequired,
preferencesBucket: PropTypes.object.isRequired,
resetAuth: PropTypes.func.isRequired,
setAuthorized: PropTypes.func.isRequired,
Expand Down Expand Up @@ -296,12 +313,14 @@ export const App = connect(
onNoteRemoved = () => this.onNotesIndex();

onNoteUpdate = (noteId, data, remoteUpdateInfo = {}) => {
if (remoteUpdateInfo.patch) {
this.props.actions.noteUpdatedRemotely({
noteBucket: this.props.noteBucket,
noteId,
data,
remoteUpdateInfo,
const {
noteBucket,
selectNote,
ui: { note },
} = this.props;
if (remoteUpdateInfo.patch && note && noteId === note.id) {
noteBucket.get(noteId, (e, updatedNote) => {
selectNote({ ...updatedNote, hasRemoteUpdate: true });
});
}
};
Expand Down Expand Up @@ -439,7 +458,6 @@ export const App = connect(
isNoteOpen={this.state.isNoteOpen}
isNoteInfoOpen={state.showNoteInfo}
isSmallScreen={isSmallScreen}
note={state.note}
noteBucket={noteBucket}
revisions={state.revisions}
onNoteClosed={() => this.setState({ isNoteOpen: false })}
Expand Down
40 changes: 25 additions & 15 deletions lib/dialogs/share/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,32 +13,41 @@ import TabPanels from '../../components/tab-panels';
import PanelTitle from '../../components/panel-title';
import ToggleControl from '../../controls/toggle';

import * as S from '../../state';
import * as T from '../../types';

const shareTabs = ['collaborate', 'publish'];

export class ShareDialog extends Component {
type StateProps = {
settings: S.State['settings'];
note: T.NoteEntity | null;
};

type Props = StateProps;

export class ShareDialog extends Component<Props> {
static propTypes = {
actions: PropTypes.object.isRequired,
dialog: PropTypes.object.isRequired,
noteBucket: PropTypes.object.isRequired,
appState: PropTypes.object.isRequired,
requestClose: PropTypes.func.isRequired,
settings: PropTypes.object.isRequired,
tagBucket: PropTypes.object.isRequired,
updateNoteTags: PropTypes.func.isRequired,
};

onTogglePublished = event => {
this.props.actions.publishNote({
noteBucket: this.props.noteBucket,
note: this.props.appState.note,
note: this.props.note,
publish: event.currentTarget.checked,
});
};

getPublishURL = url => (isEmpty(url) ? undefined : `http://simp.ly/p/${url}`);

onAddCollaborator = event => {
const { note } = this.props.appState;
const { note } = this.props;
const tags = (note.data && note.data.tags) || [];
const collaborator = this.collaboratorElement.value.trim();

Expand All @@ -57,7 +66,7 @@ export class ShareDialog extends Component {
};

onRemoveCollaborator = collaborator => {
const { note } = this.props.appState;
const { note } = this.props;

let tags = (note.data && note.data.tags) || [];
tags = tags.filter(tag => tag !== collaborator);
Expand All @@ -67,7 +76,7 @@ export class ShareDialog extends Component {
};

collaborators = () => {
const { note } = this.props.appState;
const { note } = this.props;
const tags = (note.data && note.data.tags) || [];
const collaborators = tags.filter(isEmailTag);

Expand All @@ -86,9 +95,7 @@ export class ShareDialog extends Component {
};

render() {
const { dialog, requestClose } = this.props;
const { note } = this.props.appState;

const { dialog, note, requestClose } = this.props;
const data = (note && note.data) || {};
const isPublished = includes(data.systemTags, 'published');
const publishURL = this.getPublishURL(data.publishURL);
Expand Down Expand Up @@ -207,9 +214,12 @@ export class ShareDialog extends Component {
}
}

export default connect(
state => ({
settings: state.settings,
}),
{ updateNoteTags }
)(ShareDialog);
const mapStateToProps: S.MapState<StateProps> = ({
settings,
ui: { note },
}) => ({
settings,
note,
});

export default connect(mapStateToProps, { updateNoteTags })(ShareDialog);
54 changes: 1 addition & 53 deletions lib/flux/app-state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { get, partition, some } from 'lodash';
import update from 'react-addons-update';
import Debug from 'debug';
import ActionMap from './action-map';
import filterNotes from '../utils/filter-notes';
import analytics from '../analytics';

import { AppState, State } from '../state';
Expand Down Expand Up @@ -36,7 +35,6 @@ const toggleSystemTag = (
const initialState: AppState = {
editorMode: 'edit',
filter: '',
selectedNoteId: null,
previousIndex: -1,
notes: null,
tags: [],
Expand Down Expand Up @@ -100,8 +98,6 @@ export const actionMap = new ActionMap({
showTrash: { $set: false },
listTitle: { $set: 'All Notes' },
tag: { $set: null },
note: { $set: null },
selectedNoteId: { $set: null },
previousIndex: { $set: -1 },
});
},
Expand All @@ -113,8 +109,6 @@ export const actionMap = new ActionMap({
showTrash: { $set: true },
listTitle: { $set: 'Trash' },
tag: { $set: null },
note: { $set: null },
selectedNoteId: { $set: null },
previousIndex: { $set: -1 },
});
},
Expand All @@ -139,8 +133,6 @@ export const actionMap = new ActionMap({
showTrash: { $set: false },
listTitle: { $set: tag.data.name },
tag: { $set: tag },
note: { $set: null },
selectedNoteId: { $set: null },
previousIndex: { $set: -1 },
});
},
Expand Down Expand Up @@ -297,25 +289,8 @@ export const actionMap = new ActionMap({
note.data.systemTags.includes('pinned')
);
const pinSortedNotes = [...pinned, ...notPinned];

let selectedNote = null;

if (state.note) {
// Load the newest version of the selected note
selectedNote = notes.find(note => note.id === state.note.id);
} else {
// If no note is selected, select either the first note
// or the previous note in the list
const filteredNotes = filterNotes(state, pinSortedNotes);
if (filteredNotes.length > 0) {
selectedNote = filteredNotes[Math.max(state.previousIndex, 0)];
}
}

return update(state, {
notes: { $set: pinSortedNotes },
note: { $set: selectedNote },
selectedNoteId: { $set: get(selectedNote, 'id', null) },
});
},

Expand Down Expand Up @@ -395,47 +370,20 @@ export const actionMap = new ActionMap({
},
},

selectNote(state: AppState, { note, hasRemoteUpdate }) {
selectNote(state: AppState) {
belcherj marked this conversation as resolved.
Show resolved Hide resolved
return update(state, {
editingTags: { $set: false },
note: { $set: { ...note, hasRemoteUpdate } },
selectedNoteId: { $set: note.id },
revision: { $set: null },
revisions: { $set: null },
});
},

closeNote(state: AppState, { previousIndex = -1 }) {
return update(state, {
note: { $set: null },
selectedNoteId: { $set: null },
previousIndex: { $set: previousIndex },
});
},

noteUpdatedRemotely: {
creator({ noteBucket, noteId, data, remoteUpdateInfo = {} }) {
return (dispatch, getState: () => State) => {
const state = getState().appState;
const { patch } = remoteUpdateInfo;

debug('noteUpdatedRemotely: %O', data);

if (state.selectedNoteId !== noteId || !patch) {
return;
}

dispatch(
this.action('loadAndSelectNote', {
noteBucket,
noteId,
hasRemoteUpdate: true,
})
);
};
},
},

/**
* A note is being changed from somewhere else! If the same
* note is also open and being edited, we need to make sure
Expand Down
Loading