From e70a07d6035d7e99b8bf1cc6f90f546fabdb3eb2 Mon Sep 17 00:00:00 2001 From: john <johnbarlas39@gmail.com> Date: Tue, 13 Dec 2016 21:42:11 +0200 Subject: [PATCH] chapter refactor - part two --- app/components/BookBuilder/Chapter.jsx | 38 +-- .../BookBuilder/Chapter/ChapterButtons.jsx | 173 ++++++++++- .../BookBuilder/Chapter/ChapterTitle.jsx | 22 +- .../BookBuilder/Chapter/DeleteModal.jsx | 41 +++ .../Chapter/EditingNotification.jsx | 109 +++++++ .../BookBuilder/Chapter/FirstRow.jsx | 273 ++---------------- ...ProgressIndicator.jsx => ProgressItem.jsx} | 25 +- .../BookBuilder/Chapter/ProgressList.jsx | 62 ++++ .../BookBuilder/Chapter/SecondRow.jsx | 62 +--- app/components/BookBuilder/Chapter/Title.jsx | 14 - .../BookBuilder/Chapter/UnlockModal.jsx | 42 +++ .../BookBuilderModal.jsx => utils/Modal.jsx} | 1 + app/components/utils/noop.js | 3 + 13 files changed, 492 insertions(+), 373 deletions(-) create mode 100644 app/components/BookBuilder/Chapter/DeleteModal.jsx create mode 100644 app/components/BookBuilder/Chapter/EditingNotification.jsx rename app/components/BookBuilder/Chapter/{ProgressIndicator.jsx => ProgressItem.jsx} (84%) create mode 100644 app/components/BookBuilder/Chapter/ProgressList.jsx create mode 100644 app/components/BookBuilder/Chapter/UnlockModal.jsx rename app/components/{BookBuilder/BookBuilderModal.jsx => utils/Modal.jsx} (98%) create mode 100644 app/components/utils/noop.js diff --git a/app/components/BookBuilder/Chapter.jsx b/app/components/BookBuilder/Chapter.jsx index 3cece69..0559817 100644 --- a/app/components/BookBuilder/Chapter.jsx +++ b/app/components/BookBuilder/Chapter.jsx @@ -1,14 +1,11 @@ +import { flow } from 'lodash' import React from 'react' import { DragSource, DropTarget } from 'react-dnd' -import { flow } from 'lodash' - import FirstRow from './Chapter/FirstRow' -// import SecondRow from './Chapter/SecondRow' - -import { chapterSource, chapterTarget, collectDrag, collectDrop, itemTypes } from '../utils/DnD' - +import SecondRow from './Chapter/SecondRow' import styles from './styles/bookBuilder.local.scss' +import { chapterSource, chapterTarget, collectDrag, collectDrop, itemTypes } from '../utils/DnD' export class Chapter extends React.Component { constructor (props) { @@ -21,19 +18,6 @@ export class Chapter extends React.Component { } } - // _viewOrEdit () { - // const { roles, chapter } = this.props - // - // if (includes(roles, 'production-editor')) return this.setState({ canEdit: true }) - // - // if (chapter.progress['review'] === 1 && includes(roles, 'author') || - // chapter.progress['edit'] === 1 && includes(roles, 'copy-editor')) { - // this.setState({ canEdit: true }) - // } else { - // this.setState({ canEdit: false }) - // } - // } - update (changedChapter) { const { book, update } = this.props update(book, changedChapter) @@ -45,20 +29,23 @@ export class Chapter extends React.Component { chapter, connectDragSource, connectDropTarget, - // ink, + ink, isDragging, outerContainer, - // roles, + roles, title, type } = this.props - const opacity = isDragging ? 0 : 1 + const listItemStyle = { + opacity: isDragging ? 0 : 1 + } return connectDragSource(connectDropTarget( <li className={styles.chapterContainer + ' col-lg-12 bb-chapter ' + (chapter.subCategory === 'chapter' ? styles.isChapter : styles.isPart)} - style={{ opacity: opacity }}> + style={listItemStyle} + > <div className={styles.grabIcon + ' ' + (chapter.division === 'body' ? styles.grabIconBody : '')}> <i className='fa fa-circle' /> @@ -72,6 +59,7 @@ export class Chapter extends React.Component { book={book} chapter={chapter} outerContainer={outerContainer} + roles={roles} title={title} type={type} update={this.update} @@ -79,14 +67,14 @@ export class Chapter extends React.Component { <div className={styles.chapterBottomLine} /> - {/* <SecondRow + <SecondRow chapter={chapter} ink={ink} outerContainer={outerContainer} roles={roles} update={this.update} viewOrEdit={this._viewOrEdit} - /> */} + /> </div> <div className={chapter.division === 'body' ? styles.leftBorderBody : styles.leftBorderComponent} /> diff --git a/app/components/BookBuilder/Chapter/ChapterButtons.jsx b/app/components/BookBuilder/Chapter/ChapterButtons.jsx index d10878d..ff09e1f 100644 --- a/app/components/BookBuilder/Chapter/ChapterButtons.jsx +++ b/app/components/BookBuilder/Chapter/ChapterButtons.jsx @@ -1,12 +1,161 @@ -// import React from 'react' -// import { LinkContainer } from 'react-router-bootstrap' -// -// class ChapterButtons extends React.Component { -// // constructor (props) { -// // super(props) -// // } -// -// render () { -// -// } -// } +import { get, includes } from 'lodash' +import React from 'react' +import { LinkContainer } from 'react-router-bootstrap' + +import DeleteModal from './DeleteModal' +import EditingNotification from './EditingNotification' +import styles from './styles/bookBuilder.local.scss' + +class ChapterButtons extends React.Component { + constructor (props) { + super(props) + + this.state = { + showDeleteModal: false + } + } + + // TODO -- should maybe check for lock + isLocked () { + const { chapter } = this.props + return get(chapter, 'lock.editor.username') + } + + canEdit () { + const { chapter, roles } = this.props + + if (includes(roles, 'admin') || includes(roles, 'production-editor')) { + return true + } + + if (includes(roles, 'copy-editor')) { + const isEditing = (chapter.progress.edit === 1) + if (isEditing) return true + } + + if (includes(roles, 'author')) { + const isReviewing = (chapter.progress.review === 1) + if (isReviewing) return true + } + + return false + } + + toggleDeleteModal () { + this.setState({ + showDeleteModal: !this.state.showDeleteModal + }) + } + + renderEditingNotification () { + const { chapter, modalContainer, roles, update } = this.props + + return ( + <EditingNotification + chapter={chapter} + modalContainer={modalContainer} + roles={roles} + update={update} + /> + ) + } + + renderRenameButton () { + const { chapter, isRenaming } = this.props + const type = chapter.type + + if (type === 'chapter' || type === 'part') { + let renameButtonText = 'Rename' + let renameButtonFunction = this.onClickRename + + if (isRenaming) { + renameButtonText = 'Save' + renameButtonFunction = this.onSaveRename + } + + return ( + <a id='bb-rename' + onClick={renameButtonFunction}> + { renameButtonText } + </a> + ) + } + + return null + } + + renderEditButton () { + const { bookId, chapter } = this.props + const text = this.canEdit() ? 'Edit' : 'View' + const url = `/books/${bookId}/fragments/${chapter.id}` + + return ( + <LinkContainer id='bb-edit' to={url} > + <a> { text } </a> + </LinkContainer> + ) + } + + renderDeleteButton () { + const { chapter, modalContainer, remove } = this.props + const { showDeleteModal } = this.state + const toggle = this.toggleDeleteModal + + const deleteModal = ( + <DeleteModal + chapter={chapter} + container={modalContainer} + remove={remove} + show={showDeleteModal} + toggle={toggle} + /> + ) + + return ( + <a id='bb-delete' onClick={toggle} > + Delete + { deleteModal } + </a> + ) + } + + renderRightArea () { + if (this.isLocked()) return this.renderEditingNotification() + + const renameButton = this.renderRenameButton() + const editButton = this.renderEditButton() + const deleteButton = this.renderDeleteButton() + + return ( + <div> + { renameButton } + { editButton } + { deleteButton } + </div> + ) + } + + render () { + let rightArea = this.renderRightArea() + + return ( + <div className={styles.chapterActions + ' pull-right'}> + { rightArea } + </div> + ) + } +} + +ChapterButtons.propTypes = { + bookId: React.PropTypes.string.isRequired, + chapter: React.PropTypes.object.isRequired, + isRenaming: React.PropTypes.bool.isRequired, + modalContainer: React.PropTypes.object.isRequired, + onClickRename: React.PropTypes.func.isRequired, + onSaveRename: React.PropTypes.func.isRequired, + remove: React.PropTypes.func.isRequired, + roles: React.PropTypes.array.isRequired, + update: React.PropTypes.func.isRequired +} + +export default ChapterButtons diff --git a/app/components/BookBuilder/Chapter/ChapterTitle.jsx b/app/components/BookBuilder/Chapter/ChapterTitle.jsx index 8334f89..652e60f 100644 --- a/app/components/BookBuilder/Chapter/ChapterTitle.jsx +++ b/app/components/BookBuilder/Chapter/ChapterTitle.jsx @@ -7,26 +7,18 @@ import Title from './Title' import styles from '../styles/bookBuilder.local.scss' class ChapterTitle extends React.Component { - constructor (props) { - super(props) - - this.state = { - isRenameEmpty: false, - isRenamingTitle: false - } - } - render () { const { chapter, division, + isRenaming, + isRenameEmpty, onClickRename, onSaveRename, title, type, update } = this.props - const { isRenameEmpty, isRenaming } = this.state let titleArea @@ -52,9 +44,15 @@ class ChapterTitle extends React.Component { return ( <div className={styles.chapterTitle}> + { titleArea } - <RenameEmptyError isRenameEmpty={isRenameEmpty} /> + + <RenameEmptyError + isRenameEmpty={isRenameEmpty} + /> + <div className={styles.separator} /> + </div> ) } @@ -63,6 +61,8 @@ class ChapterTitle extends React.Component { ChapterTitle.propTypes = { chapter: React.PropTypes.object.isRequired, division: React.PropTypes.string.isRequired, + isRenaming: React.PropTypes.bool.isRequired, + isRenameEmpty: React.PropTypes.bool.isRequired, onClickRename: React.PropTypes.func.isRequired, onSaveRename: React.PropTypes.func.isRequired, title: React.PropTypes.string.isRequired, diff --git a/app/components/BookBuilder/Chapter/DeleteModal.jsx b/app/components/BookBuilder/Chapter/DeleteModal.jsx new file mode 100644 index 0000000..5ef2167 --- /dev/null +++ b/app/components/BookBuilder/Chapter/DeleteModal.jsx @@ -0,0 +1,41 @@ +import React from 'react' + +import Modal from '../../utils/Modal' + +class DeleteModal extends React.Component { + onDelete () { + const { chapter, remove, toggle } = this.props + + remove(chapter) + toggle() + } + + render () { + const { chapter, container, show, toggle } = this.props + const type = chapter.type + + return ( + <Modal + title={'Delete ' + type} + chapter={chapter} + action='delete' + successText='Delete' + type={type} + successAction={this.onDelete} + show={show} + toggle={toggle} + container={container} + /> + ) + } +} + +DeleteModal.propTypes = { + chapter: React.PropTypes.object.isRequired, + container: React.PropTypes.object.isRequired, + show: React.PropTypes.bool.isRequired, + remove: React.PropTypes.func.isRequired, + toggle: React.PropTypes.func.isRequired +} + +export default DeleteModal diff --git a/app/components/BookBuilder/Chapter/EditingNotification.jsx b/app/components/BookBuilder/Chapter/EditingNotification.jsx new file mode 100644 index 0000000..d020cf7 --- /dev/null +++ b/app/components/BookBuilder/Chapter/EditingNotification.jsx @@ -0,0 +1,109 @@ +import { includes } from 'lodash' +import React from 'react' + +import noop from '../../utils/noop' +import styles from '../styles/bookBuilder.local.scss' +import UnlockModal from './UnlockModal' + +class EditingNotification extends React.Component { + constructor (props) { + super(props) + + this.state = { + showModal: false + } + } + + toggleModal () { + this.setState({ + showModal: !this.state.showModal + }) + } + + isAdmin () { + const { roles } = this.props + return includes(roles, 'admin') + } + + formatDate (timestamp) { + const date = new Date(timestamp) + + const day = date.getDate() + const month = date.getMonth() + 1 + const year = date.getFullYear() + + let hours = date.getHours().toString() + if (hours.length === 1) { + hours = '0' + hours + } + + let minutes = date.getMinutes().toString() + if (minutes.length === 1) { + minutes = '0' + minutes + } + + const theDate = month + '/' + day + '/' + year + const theTime = hours + ':' + minutes + const formatted = theDate + ' ' + theTime + + return formatted + } + + render () { + const { chapter, modalContainer, update } = this.props + const { showModal } = this.state + const username = chapter.lock.editor.username + + let message = username + ' is editing' + let hoverTitle, unlockModal + let toggle = noop + + if (this.isAdmin()) { + toggle = this.toggle() + + unlockModal = ( + <UnlockModal + chapter={chapter} + container={modalContainer} + show={showModal} + toggle={toggle} + update={update} + /> + ) + + if (chapter.lock.timestamp) { + const date = this.formatDate(chapter.lock.timestamp) + hoverTitle = username + ' has been editing since ' + date + } + } + + return ( + <a id='bb-unlock' + className={styles.lEditing} + onClick={toggle} + title={hoverTitle} + > + <i + className={styles.lockIcon + ' fa fa-lock'} + aria-hidden='true' + alt='unlock' + /> + + <span className={styles.lockMessage}> + { message } + </span> + + { unlockModal } + </a> + ) + } +} + +EditingNotification.propTypes = { + chapter: React.PropTypes.object.isRequired, + modalContainer: React.PropTypes.object.isRequired, + roles: React.PropTypes.array.isRequired, + update: React.PropTypes.func.isRequired +} + +export default EditingNotification diff --git a/app/components/BookBuilder/Chapter/FirstRow.jsx b/app/components/BookBuilder/Chapter/FirstRow.jsx index 17344be..2e08387 100644 --- a/app/components/BookBuilder/Chapter/FirstRow.jsx +++ b/app/components/BookBuilder/Chapter/FirstRow.jsx @@ -1,250 +1,45 @@ -import { get, includes, map, slice } from 'lodash' import React from 'react' -import { DropdownButton, MenuItem } from 'react-bootstrap' -import { LinkContainer } from 'react-router-bootstrap' - -import { findDOMNode } from 'react-dom' - -import BookBuilderModal from '../BookBuilderModal' -import TextInput from '../../utils/TextInput' +import ChapterButtons from './ChapterButtons' import ChapterTitle from './ChapterTitle' class ChapterFirstRow extends React.Component { constructor (props) { super(props) - this._viewOrEdit = this._viewOrEdit.bind(this) - - this._onClickRename = this._onClickRename.bind(this) - this._onSaveRename = this._onSaveRename.bind(this) - - this._onClickDelete = this._onClickDelete.bind(this) - this._onClickUnlock = this._onClickUnlock.bind(this) - this._toggleDelete = this._toggleDelete.bind(this) - this._toggleUnlock = this._toggleUnlock.bind(this) - - this._isAdmin = this._isAdmin.bind(this) - this._formatDate = this._formatDate.bind(this) - - this._viewOrEdit = this._viewOrEdit.bind(this) - - // this._onClickTitleDropdown = this._onClickTitleDropdown.bind(this) - // this._onClickCustomTitle = this._onClickCustomTitle.bind(this) + this.onClickRename = this.onClickRename.bind(this) + this.onSaveRename = this.onSaveRename.bind(this) this.state = { - canEdit: true, isRenameEmpty: false, - isRenamingTitle: false, - showDeleteModal: false, - showUnlockModal: false + isRenamingTitle: false } } - _toggleDelete () { - this.setState({ showDeleteModal: !this.state.showDeleteModal }) - } - - _toggleUnlock () { - if (!this._isAdmin()) { return } - this.setState({ showUnlockModal: !this.state.showUnlockModal }) - } - - _isAdmin () { - const { roles } = this.props - return includes(roles, 'admin') - } - - _onClickUnlock () { - const { book, chapter, update } = this.props - const isAdmin = this._isAdmin() - - if (!isAdmin) { return } - - chapter.lock = null - update(book, chapter) - this._toggleUnlock() - } - - _onClickRename () { + onClickRename () { this.setState({ isRenamingTitle: true }) } - _onSaveRename (title) { - // save button has been clicked from outside the component - if (typeof title !== 'string') { - // console.log(this.refs) - title = this.refs.chapterInput.state.value - } + // TODO -- trim title + onSaveRename (title) { + const { book, chapter, update } = this.props - if (title.length === 0) { - this.setState({ - isRenameEmpty: true - }) - return - } + // handle save button click (from outside the component) + if (typeof title !== 'string') title = this.refs.chapterInput.state.value - this.setState({ - isRenameEmpty: false - }) + if (title.length === 0) return this.setState({ isRenameEmpty: true }) + this.setState({ isRenameEmpty: false }) - const { book, chapter, update } = this.props chapter.title = title - update(book, chapter) - - this.setState({ - isRenamingTitle: false - }) - } - - _onClickDelete () { - const { chapter, remove } = this.props - remove(chapter) - this._toggleDelete() - } - - _viewOrEdit () { - const { roles, chapter } = this.props - - if (includes(roles, 'production-editor')) return this.setState({ canEdit: true }) - - if (chapter.progress['review'] === 1 && includes(roles, 'author') || - chapter.progress['edit'] === 1 && includes(roles, 'copy-editor')) { - this.setState({ canEdit: true }) - } else { - this.setState({ canEdit: false }) - } - } - - _formatDate (timestamp) { - const date = new Date(timestamp) - - const day = date.getDate() - const month = date.getMonth() + 1 - const year = date.getFullYear() - - let hours = date.getHours().toString() - if (hours.length === 1) { - hours = '0' + hours - } - - let minutes = date.getMinutes().toString() - if (minutes.length === 1) { - minutes = '0' + minutes - } - - const theDate = month + '/' + day + '/' + year - const theTime = hours + ':' + minutes - const formatted = theDate + ' ' + theTime - return formatted + this.setState({ isRenamingTitle: false }) } render () { - const { - book, - chapter, - outerContainer, - title, - type, - update - } = this.props - + const { book, chapter, outerContainer, remove, roles, title, type, update } = this.props const { isRenameEmpty, isRenamingTitle } = this.state - - // let titleArea = null - // let renameButton = null - - // let renameEmptyError = isRenameEmpty - // ? ( - // <span className={styles.emptyTitle}> - // New title cannot be empty - // </span> - // ) - // : null - - // if (type === 'chapter' || type === 'part') { - // // if type is chapter, make the title editable text - // let renameButtonText, renameButtonFunction - // - // const input = ( - // <TextInput - // className='edit' - // ref='chapterInput' - // onSave={this._onSaveRename} - // value={title} - // /> - // ) - // - // if (isRenamingTitle) { - // titleArea = input - // renameButtonText = 'Save' - // renameButtonFunction = this._onSaveRename - // } else { - // titleArea = (<h3 onDoubleClick={this._onClickRename}> { title } </h3>) - // renameButtonText = 'Rename' - // renameButtonFunction = this._onClickRename - // } - // - // // add id so that it can be selected for testing - // // could do with refs, but that would mean mounting instead of - // // shallow rendering to access enzyme's refs() api method - // renameButton = ( - // <a id='bb-rename' - // onClick={renameButtonFunction}> - // { renameButtonText } - // </a> - // ) - // } - - // const editOrView = this.state.canEdit ? 'Edit' : 'View' - - // const buttons = ( - // <div> - // { renameButton } - // <LinkContainer - // to={`/books/${book.id}/fragments/${chapter.id}`} - // id='bb-edit' - // > - // <a>{ editOrView } </a> - // </LinkContainer> - // - // <a id='bb-delete' - // onClick={this._toggleDelete}> - // Delete - // </a> - // </div> - // ) - - // let editorArea - // if (get(chapter, 'lock.editor.username')) { - // let message = ' is editing' - // if (chapter.lock.timestamp && this._isAdmin()) { - // message = ' has been editing since ' + this._formatDate(chapter.lock.timestamp) - // } - // - // editorArea = ( - // <a id='bb-unlock' - // className={styles.lEditing} - // onClick={this._toggleUnlock}> - // - // <i - // className={styles.lockIcon + ' fa fa-lock'} - // aria-hidden='true' - // alt='unlock' - // /> - // <span className={styles.lockMessage}> - // { chapter.lock.editor.username + message} - // </span> - // - // </a> - // ) - // } - - // const rightArea = chapter.lock ? editorArea : buttons - const division = chapter.division return ( @@ -252,41 +47,23 @@ class ChapterFirstRow extends React.Component { <ChapterTitle chapter={chapter} division={division} - onClickRename={this._onClickRename} - onSaveRename={this._onSaveRename} + isRenaming={isRenamingTitle} + isRenameEmpty={isRenameEmpty} + onClickRename={this.onClickRename} + onSaveRename={this.onSaveRename} title={title} type={type} update={update} /> - {/* <ChapterButtons /> */} - - {/* <div className={styles.chapterActions + ' pull-right'}> - { rightArea } - </div> */} - - <BookBuilderModal - title={'Delete ' + type} + <ChapterButtons + bookId={book.id} chapter={chapter} - action='delete' - successText='Delete' - type={type} - successAction={this._onClickDelete} - show={this.state.showDeleteModal} - toggle={this._toggleDelete} - container={outerContainer} - /> - - <BookBuilderModal - title={'Unlock ' + type} - chapter={chapter} - action='unlock' - successText='Unlock' - type={type} - successAction={this._onClickUnlock} - show={this.state.showUnlockModal} - toggle={this._toggleUnlock} - container={outerContainer} + isRenaming={isRenamingTitle} + modalContainer={outerContainer} + remove={remove} + roles={roles} + update={update} /> </span> ) diff --git a/app/components/BookBuilder/Chapter/ProgressIndicator.jsx b/app/components/BookBuilder/Chapter/ProgressItem.jsx similarity index 84% rename from app/components/BookBuilder/Chapter/ProgressIndicator.jsx rename to app/components/BookBuilder/Chapter/ProgressItem.jsx index f5015cf..82b1333 100644 --- a/app/components/BookBuilder/Chapter/ProgressIndicator.jsx +++ b/app/components/BookBuilder/Chapter/ProgressItem.jsx @@ -4,15 +4,16 @@ import { Alert } from 'react-bootstrap' import BookBuilderModal from '../BookBuilderModal' import styles from '../styles/bookBuilder.local.scss' -export class ProgressIndicator extends React.Component { +export class ProgressItem extends React.Component { constructor (props) { super(props) - this._isAllowedToChange = this._isAllowedToChange.bind(this) + this.canChange = this.canChange.bind(this) this._onClick = this._onClick.bind(this) this._toggleModal = this._toggleModal.bind(this) this._changeWorkflowState = this._changeWorkflowState.bind(this) + // TODO -- move to config this.progressValues = { style: ['To Style', 'Styling', 'Styled'], edit: ['To Edit', 'Editing', 'Edited'], @@ -26,15 +27,21 @@ export class ProgressIndicator extends React.Component { } } - _isAllowedToChange () { + canChange () { const { type, roles, chapter } = this.props - if (includes(roles, 'production-editor')) return true + if (includes(roles, 'admin') || includes(roles, 'production-editor')) return true - const isOne = (chapter.progress[type] === 1) + const isActive = (chapter.progress[type] === 1) - if (chapter.progress[type] === 1 && type === 'edit' && includes(roles, 'copy-editor')) return true - if (isOne && type === 'review' && includes(roles, 'author')) return true + if (isActive) { + if (type === 'edit') { + if (includes(roles, 'copy-editor')) return true + } + if (type === 'review') { + if (includes(roles, 'author')) return true + } + } return false } @@ -121,7 +128,7 @@ export class ProgressIndicator extends React.Component { } } -ProgressIndicator.propTypes = { +ProgressItem.propTypes = { type: React.PropTypes.string.isRequired, chapter: React.PropTypes.object.isRequired, hasIcon: React.PropTypes.bool, @@ -131,4 +138,4 @@ ProgressIndicator.propTypes = { viewOrEdit: React.PropTypes.func } -export default ProgressIndicator +export default ProgressItem diff --git a/app/components/BookBuilder/Chapter/ProgressList.jsx b/app/components/BookBuilder/Chapter/ProgressList.jsx new file mode 100644 index 0000000..163a1b1 --- /dev/null +++ b/app/components/BookBuilder/Chapter/ProgressList.jsx @@ -0,0 +1,62 @@ +import React from 'react' + +import ProgressItem from './ProgressItem' +import styles from '../styles/bookBuilder.local.scss' + +class ProgressList extends React.Component { + render () { + const { chapter, roles, modalContainer, update } = this.props + + return ( + <ul className={styles.secondActions + ' col-lg-7 col-md-12 col-sm-12 col-xs-12'}> + <ProgressItem + type='style' + chapter={chapter} + update={update} + roles={roles} + modalContainer={modalContainer} + hasIcon + // viewOrEdit={this._viewOrEdit} + /> + + <ProgressItem + type='edit' + chapter={chapter} + update={update} + roles={roles} + modalContainer={modalContainer} + hasIcon + // viewOrEdit={this._viewOrEdit} + /> + + <ProgressItem + type='review' + chapter={chapter} + update={update} + roles={roles} + modalContainer={modalContainer} + hasIcon + // viewOrEdit={this._viewOrEdit} + /> + + <ProgressItem + type='clean' + chapter={chapter} + roles={roles} + modalContainer={modalContainer} + update={update} + // viewOrEdit={this._viewOrEdit} + /> + </ul> + ) + } +} + +ProgressList.propTypes = { + chapter: React.PropTypes.object.isRequired, + modalContainer: React.PropTypes.object.isRequired, + roles: React.PropTypes.array.isRequired, + update: React.PropTypes.func.isRequired +} + +export default ProgressList diff --git a/app/components/BookBuilder/Chapter/SecondRow.jsx b/app/components/BookBuilder/Chapter/SecondRow.jsx index 131623d..1e2844c 100644 --- a/app/components/BookBuilder/Chapter/SecondRow.jsx +++ b/app/components/BookBuilder/Chapter/SecondRow.jsx @@ -1,19 +1,14 @@ import React from 'react' import PagePositionAlignment from './PagePositionAlignment' -import ProgressIndicator from './ProgressIndicator' +import ProgressList from './ProgressList' import UploadWordButton from './UploadWordBtn' import styles from '../styles/bookBuilder.local.scss' class ChapterSecondRow extends React.Component { render () { - const { - chapter, - ink, - outerContainer, - roles - } = this.props + const { chapter, ink, outerContainer, roles, update } = this.props return ( <div className={styles.secondLineContainer}> @@ -27,46 +22,12 @@ class ChapterSecondRow extends React.Component { /> </div> - <ul className={styles.secondActions + ' col-lg-7 col-md-12 col-sm-12 col-xs-12'}> - <ProgressIndicator - type='style' - chapter={chapter} - update={this.update} - roles={roles} - outerContainer={outerContainer} - hasIcon - viewOrEdit={this._viewOrEdit} - /> - - <ProgressIndicator - type='edit' - chapter={chapter} - update={this.update} - roles={roles} - outerContainer={outerContainer} - hasIcon - viewOrEdit={this._viewOrEdit} - /> - - <ProgressIndicator - type='review' - chapter={chapter} - update={this.update} - roles={roles} - outerContainer={outerContainer} - hasIcon - viewOrEdit={this._viewOrEdit} - /> - - <ProgressIndicator - type='clean' - chapter={chapter} - roles={roles} - outerContainer={outerContainer} - update={this.update} - viewOrEdit={this._viewOrEdit} - /> - </ul> + <ProgressList + chapter={chapter} + modalContainer={outerContainer} + roles={roles} + update={update} + /> <div className={styles.noPadding + ' col-lg-3 col-md-12 col-sm-12 col-xs-12'}> <PagePositionAlignment @@ -82,17 +43,10 @@ class ChapterSecondRow extends React.Component { } ChapterSecondRow.propTypes = { - book: React.PropTypes.object.isRequired, chapter: React.PropTypes.object.isRequired, - connectDragSource: React.PropTypes.func.isRequired, - connectDropTarget: React.PropTypes.func.isRequired, ink: React.PropTypes.func.isRequired, - isDragging: React.PropTypes.bool.isRequired, outerContainer: React.PropTypes.object.isRequired, - remove: React.PropTypes.func.isRequired, roles: React.PropTypes.array, - title: React.PropTypes.string.isRequired, - type: React.PropTypes.string.isRequired, update: React.PropTypes.func.isRequired } diff --git a/app/components/BookBuilder/Chapter/Title.jsx b/app/components/BookBuilder/Chapter/Title.jsx index dac49bc..eb65cd7 100644 --- a/app/components/BookBuilder/Chapter/Title.jsx +++ b/app/components/BookBuilder/Chapter/Title.jsx @@ -3,20 +3,6 @@ import React from 'react' import TextInput from '../../utils/TextInput' class Title extends React.Component { - // constructor (props) { - // super(props) - // - // // this.state = { - // // isRenaming: false - // // } - // } - - // _onClickRename () { - // this.setState({ - // isRenaming: true - // }) - // } - render () { const { isRenaming, onClickRename, onSaveRename, title } = this.props diff --git a/app/components/BookBuilder/Chapter/UnlockModal.jsx b/app/components/BookBuilder/Chapter/UnlockModal.jsx new file mode 100644 index 0000000..4c3ca1e --- /dev/null +++ b/app/components/BookBuilder/Chapter/UnlockModal.jsx @@ -0,0 +1,42 @@ +import React from 'react' + +import Modal from '../../utils/Modal' + +class UnlockModal extends React.Component { + onUnlock () { + const { chapter, toggle, update } = this.props + + chapter.lock = null + update(chapter) + toggle() + } + + render () { + const { chapter, container, show, toggle } = this.props + const type = chapter.type + + return ( + <Modal + title={'Unlock ' + type} + chapter={chapter} + action='unlock' + successText='Unlock' + type={type} + successAction={this.onUnlock} + show={show} + toggle={toggle} + container={container} + /> + ) + } +} + +UnlockModal.propTypes = { + chapter: React.PropTypes.object.isRequired, + container: React.PropTypes.object.isRequired, + show: React.PropTypes.bool.isRequired, + toggle: React.PropTypes.func.isRequired, + update: React.PropTypes.func.isRequired +} + +export default UnlockModal diff --git a/app/components/BookBuilder/BookBuilderModal.jsx b/app/components/utils/Modal.jsx similarity index 98% rename from app/components/BookBuilder/BookBuilderModal.jsx rename to app/components/utils/Modal.jsx index 0a2a649..8d052e7 100644 --- a/app/components/BookBuilder/BookBuilderModal.jsx +++ b/app/components/utils/Modal.jsx @@ -28,6 +28,7 @@ export class BookBuilderModal extends React.Component { { successText } </a> : null + // TODO -- move to config if (action === 'delete') { modalBodyText = ( <div> diff --git a/app/components/utils/noop.js b/app/components/utils/noop.js new file mode 100644 index 0000000..9b98d9c --- /dev/null +++ b/app/components/utils/noop.js @@ -0,0 +1,3 @@ +const noop = () => {} + +export default noop -- GitLab