Introduce note editing, allow deleting note.
--- a/client/src/App.scss Thu Jun 22 12:37:53 2017 +0200
+++ b/client/src/App.scss Fri Jun 23 10:16:49 2017 +0200
@@ -132,22 +132,28 @@
.note {
display: flex;
position: relative;
- padding-left: 70px;
+ padding: 10px 10px 10px 80px;
margin-bottom: 20px;
- min-height: ($line-height-computed * 3);
+ cursor: pointer;
+ min-height: ($line-height-computed * 4);
+ border: 1px solid transparent;
&:before {
content: "";
position: absolute;
top: 0;
bottom: 0;
- left: 27px;
+ left: 37px;
z-index: -1;
display: block;
width: 2px;
background-color: #e6ebf1;
}
+ &:hover {
+ border: 1px solid #efefef;
+ }
+
.start, .finish {
position: absolute;
background-color: #fff;
@@ -156,10 +162,12 @@
.start {
top: 0;
left: 0;
+ padding: 10px 0 0 10px;
}
.finish {
bottom: 0;
left: 0;
+ padding: 0 0 10px 10px;
}
&-content {
--- a/client/src/actions/notesActions.js Thu Jun 22 12:37:53 2017 +0200
+++ b/client/src/actions/notesActions.js Fri Jun 23 10:16:49 2017 +0200
@@ -43,3 +43,10 @@
}
};
}
+
+export const deleteNote = (note) => {
+ return {
+ type: types.DELETE_NOTE,
+ note
+ };
+}
--- a/client/src/components/Note.js Thu Jun 22 12:37:53 2017 +0200
+++ b/client/src/components/Note.js Fri Jun 23 10:16:49 2017 +0200
@@ -1,22 +1,80 @@
-import React from 'react';
+import React, { Component } from 'react';
+import { connect } from 'react-redux';
+import { bindActionCreators } from 'redux';
import PropTypes from 'prop-types';
-import {formatTimestamp} from '../utils';
+import { formatTimestamp } from '../utils';
+import SlateEditor from './SlateEditor';
+import * as notesActions from '../actions/notesActions';
+
+class Note extends Component {
+
+ state = {
+ edit: false
+ }
+
+ toggleEditMode = () => {
+ const { edit } = this.state;
+ this.setState({ edit: !edit })
+ }
+
+ onClickDelete = (e) => {
+ e.preventDefault();
+ e.stopPropagation();
+
+ this.props.notesActions.deleteNote(this.props.note);
+ }
-const Note = ({note}) => {
- return (
- <div id={"note-" + note._id} className="note">
- <span className="start">{formatTimestamp(note.startedAt)}</span>
- <span className="finish">{formatTimestamp(note.finishedAt)}</span>
- <div className="note-content" dangerouslySetInnerHTML={{ __html: note.html }} />
- <div className="note-margin-comment">
- <small className="text-muted">{ note.marginComment }</small>
+ renderNoteContent() {
+ if (this.state.edit) {
+ return (
+ <div className="note-content">
+ <SlateEditor ref="editor"
+ onChange={this.onEditorChange}
+ onEnterKeyDown={this.onAddNoteClick}
+ onButtonClick={this.onAddNoteClick}
+ onCheckboxChange={this.onCheckboxChange}
+ isChecked={this.props.autoSubmit}
+ isButtonDisabled={this.state.buttonDisabled}
+ withButtons={false}
+ note={this.props.note} />
+ </div>
+ )
+ }
+
+ return (
+ <div className="note-content" dangerouslySetInnerHTML={{ __html: this.props.note.html }} />
+ )
+ }
+
+ render() {
+ return (
+ <div id={"note-" + this.props.note._id} className="note" onClick={ this.toggleEditMode }>
+ <span className="start">{ formatTimestamp(this.props.note.startedAt) }</span>
+ <span className="finish">{ formatTimestamp(this.props.note.finishedAt) }</span>
+ { this.renderNoteContent() }
+ <div className="note-margin-comment">
+ <small className="text-muted">{ this.props.note.marginComment }</small>
+ </div>
+ <a onClick={this.onClickDelete}>
+ <span className="material-icons">delete</span>
+ </a>
</div>
- </div>
- );
-};
+ );
+ };
+}
Note.propTypes = {
note: PropTypes.object.isRequired
};
-export default Note;
+function mapStateToProps(state, props) {
+ return props;
+}
+
+function mapDispatchToProps(dispatch) {
+ return {
+ notesActions: bindActionCreators(notesActions, dispatch),
+ }
+}
+
+export default connect(mapStateToProps, mapDispatchToProps)(Note);
--- a/client/src/components/NoteInput.js Thu Jun 22 12:37:53 2017 +0200
+++ b/client/src/components/NoteInput.js Fri Jun 23 10:16:49 2017 +0200
@@ -68,7 +68,8 @@
onButtonClick={this.onAddNoteClick}
onCheckboxChange={this.onCheckboxChange}
isChecked={this.props.autoSubmit}
- isButtonDisabled={this.state.buttonDisabled} />
+ isButtonDisabled={this.state.buttonDisabled}
+ withButtons={true} />
</div>
<div className="editor-right">
<FormControl
--- a/client/src/components/SlateEditor.js Thu Jun 22 12:37:53 2017 +0200
+++ b/client/src/components/SlateEditor.js Fri Jun 23 10:16:49 2017 +0200
@@ -77,7 +77,7 @@
plugins.push(annotationPlugin);
this.state = {
- state: Plain.deserialize(''),
+ state: props.note ? Raw.deserialize(props.note.raw) : Plain.deserialize(''),
startedAt: null,
finishedAt: null,
currentSelectionText: '',
@@ -420,18 +420,31 @@
{this.renderBlockButton('numbered-list', 'format_list_numbered')}
{this.renderBlockButton('bulleted-list', 'format_list_bulleted')}
- <div>
- <div className="checkbox">
- <label>
- <input type="checkbox" checked={this.props.isChecked} onChange={this.onCheckboxChange} /> <kbd>Enter</kbd> = add note
- </label>
- </div>
- <Button bsStyle="primary" disabled={this.props.isButtonDisabled} onClick={this.onButtonClick}>Add note</Button>
- </div>
+
+ {this.renderToolbarButtons()}
</div>
)
}
+ renderToolbarButtons = () => {
+ if (!this.props.withButtons) {
+ return (
+ <div />
+ )
+ }
+
+ return (
+ <div>
+ <div className="checkbox">
+ <label>
+ <input type="checkbox" checked={this.props.isChecked} onChange={this.onCheckboxChange} /> <kbd>Enter</kbd> = add note
+ </label>
+ </div>
+ <Button bsStyle="primary" disabled={this.props.isButtonDisabled} onClick={this.onButtonClick}>Add note</Button>
+ </div>
+ );
+ }
+
/**
* Render a mark-toggling toolbar button.
*
--- a/client/src/constants/actionTypes.js Thu Jun 22 12:37:53 2017 +0200
+++ b/client/src/constants/actionTypes.js Fri Jun 23 10:16:49 2017 +0200
@@ -1,6 +1,7 @@
export const NOOP = 'NOOP';
export const ADD_NOTE = 'ADD_NOTE';
+export const DELETE_NOTE = 'DELETE_NOTE';
export const CREATE_SESSION = 'CREATE_SESSION';
export const UPDATE_SESSION = 'UPDATE_SESSION';
--- a/client/src/reducers/notesReducer.js Thu Jun 22 12:37:53 2017 +0200
+++ b/client/src/reducers/notesReducer.js Fri Jun 23 10:16:49 2017 +0200
@@ -6,6 +6,9 @@
switch (action.type) {
case types.ADD_NOTE:
return state.push(new NoteRecord(action.note));
+ case types.DELETE_NOTE:
+ const noteIndex = state.findIndex((note) => note.get('_id') === action.note.get('_id'));
+ return state.delete(noteIndex);
default:
return state;
}