Refactored routing, broke some editor components

This commit is contained in:
Alex Hunt 2019-07-28 10:20:41 -07:00
parent 91be248aea
commit 006a1b2e1f
15 changed files with 141 additions and 92 deletions

View File

@ -66,9 +66,19 @@ tag_mappings = {
}
}
media_mappings = {
'doc': {
'properties': {
'title': {'type': 'keyword'},
'src': {'type': 'keyword'}
}
}
}
chapter_index_settings = {'settings': default_index_settings, 'mappings': chapter_mappings}
note_index_settings = {'settings': default_index_settings, 'mappings': note_mappings}
tag_index_settings = {'settings': default_index_settings, 'mappings': tag_mappings}
tag_index_settings = {'settings': default_index_settings, 'mappings': media_mappings}
# Read Seed Data from Files

View File

@ -13,6 +13,7 @@ export const DocTypeDropdown = ({docType, setDocType, size='sm'}) =>
<a className='dropdown-item' onClick={()=>setDocType('chapters')}>Chapters</a>
<a className='dropdown-item' onClick={()=>setDocType('notes')}>Notes</a>
<a className='dropdown-item' onClick={()=>setDocType('tags')}>Tags</a>
<a className='dropdown-item' onClick={()=>setDocType('media')}>Media</a>
</div>
</div>

View File

@ -26,7 +26,7 @@ const EditorEditMode = ({
onColorSwatchClick,
userErrors,
}) =>
<div id='editor_read_mode' className='editor_wrapper'>
<div id='editor_edit_mode' className='editor_wrapper'>
<div id='editor_metadata'>
{toggles.loading === true &&
<LoadingSpinner />
@ -39,7 +39,7 @@ const EditorEditMode = ({
onToolButtonClick={onToolButtonClick}
disabled={!currentDocument.id ? true : false}
/>
</div>
</div>
<div id='editor_content' className={'edit_mode ' + docType}>
<Editor
editorState={editorState}

View File

@ -16,9 +16,6 @@ const EditorReadMode = ({
}) =>
<div id='editor_read_mode' className='editor_wrapper'>
<div id='editor_metadata'>
{toggles.loading === true &&
<LoadingSpinner />
}
<DocumentTitle docType={docType} currentDocument={currentDocument} />
</div>
<div id='editor_topbar'>

View File

@ -17,6 +17,8 @@ import { EditorSidebarOptions } from '../components/mobileSidebarOptions'
const EditorPage = ({
chapters,
notes,
tags,
media,
currentDocument,
annotationNote,
annotationTag,
@ -24,7 +26,6 @@ const EditorPage = ({
modalEditorState,
docType,
mode,
tags,
toggles,
setDocType,
onDocumentClick,
@ -43,7 +44,7 @@ const EditorPage = ({
<Content>
{mode === 'READ_MODE' &&
<EditorSidebarOptions
docs={helpers.documentsOfDocType(docType, chapters, notes, tags)}
docs={helpers.documentsOfDocType(docType, chapters, notes, tags, media)}
currentDocument={currentDocument}
docType={docType}
setDocType={setDocType}
@ -83,6 +84,7 @@ const mapStateToProps = state => {
chapters: state.chapters,
notes: state.notes,
tags: state.tags,
media: state.media,
mode: state.mode,
currentDocument: state.currentDocument,
annotationNote: state.annotationNote,
@ -129,6 +131,7 @@ const mapDispatchToProps = dispatch => {
EditorPage.propTypes = {
notes: PropTypes.arrayOf(PropTypes.object),
tags: PropTypes.arrayOf(PropTypes.object),
media: PropTypes.arrayOf(PropTypes.object),
currentDocument: PropTypes.object,
annotationNote: PropTypes.object,
annotationTag: PropTypes.object,

View File

@ -13,6 +13,7 @@ const EditorSidebar = ({
chapters,
notes,
tags,
media,
docType,
currentDocument,
onDocumentClick,
@ -25,7 +26,7 @@ const EditorSidebar = ({
<SidebarSpacer />
<NewDocumentButton onClick={()=>onNewDocumentClick(docType)} docType={docType}/>
<SidebarSpacer />
<DocumentList docs={helpers.documentsOfDocType(docType, chapters, notes, tags)} currentDocument={currentDocument} onDocumentClick={onDocumentClick} docType={docType} path={'/edit/'}/>
<DocumentList docs={helpers.documentsOfDocType(docType, chapters, notes, tags, media)} currentDocument={currentDocument} onDocumentClick={onDocumentClick} docType={docType} path={'/edit/'}/>
</div>
</div>
@ -34,6 +35,7 @@ const mapStateToProps = state => {
notes: state.notes,
chapters: state.chapters,
tags: state.tags,
media: state.media,
docType: state.docType,
currentDocument: state.currentDocument,
}
@ -57,6 +59,7 @@ EditorSidebar.propTypes = {
chapters: PropTypes.arrayOf(PropTypes.object),
notes: PropTypes.arrayOf(PropTypes.object),
tags: PropTypes.arrayOf(PropTypes.object),
media: PropTypes.arrayOf(PropTypes.object),
currentDocument: PropTypes.object,
docType: PropTypes.string,
onDocumentClick: PropTypes.func,

View File

@ -27,8 +27,10 @@ const ReaderSidebar = ({
const mapStateToProps = state => {
return {
chapters: state.chapters,
notes: state.notes,
chapters: state.chapters,
tags: state.tags,
media: state.media,
docType: state.docType,
currentDocument: state.currentDocument,
toggles: state.toggles,

View File

@ -10,6 +10,7 @@ const joyceRouter = store => next => action => {
const chapters = store.getState().chapters
const notes = store.getState().notes
const tags = store.getState().tags
const media = store.getState().media
const currentDocument = store.getState().currentDocument
const docType = store.getState().docType
// Path
@ -18,55 +19,68 @@ const joyceRouter = store => next => action => {
const pathNumber = regex.checkPathForNumber(path) ? regex.parseNumberFromPath(path) : undefined
switch(action.type) {
case '@@router/LOCATION_CHANGE':
if (regex.checkIfRedirectPath(path) && currentDocument.hasOwnProperty('id')) {
store.dispatch(push(docType === 'chapters' ? String(currentDocument.number) : currentDocument.id))
}
if (regex.checkNoteReaderRoute(path) && regex.checkIfRedirectPath(path) && notes.length > 0) {
store.dispatch(actions.setCurrentDocument(notes[0].id, 'notes'))
}
if (regex.checkNoteEditorRoute(path) && regex.checkIfRedirectPath(path) && notes.length > 0) {
store.dispatch(actions.setCurrentDocument(notes[0].id, 'notes'))
}
if (regex.checkTagEditorRoute(path) && regex.checkIfRedirectPath(path) && tags.length > 0) {
store.dispatch(actions.setCurrentDocument(tags[0].id, 'tags'))
}
if (regex.checkChapterEditorRoute(path) && regex.checkIfRedirectPath(path) && chapters.length > 0) {
store.dispatch(actions.setCurrentDocument(chapters[0].id, 'chapters'))
}
if (regex.checkNoteReaderRoute(path) || regex.checkNoteEditorRoute(path)) {
store.dispatch(actions.setDocType('notes'))
}
if (regex.checkTagEditorRoute(path)) {
store.dispatch(actions.setDocType('tags'))
}
if (regex.checkRootRedirectRoute(path) && chapters.length > 0) {
store.dispatch(actions.setCurrentDocument(chapters[0].id, 'chapters'))
}
if (regex.checkNoteBaseRoute(path)) {
store.dispatch(actions.setDocType('notes'))
// If a docType can be parsed from the path, set it
if (regex.checkIfDocTypePath(path)) {
store.dispatch(actions.setDocType(regex.parseDocTypeFromPath(path)))
}
// If path is /edit and docType isn't chapters, push the docType to the path
if (regex.checkEditBaseRoute(path)){
if (docType === 'notes') {
store.dispatch(push('/edit/notes'))
if (docType !== 'chapters') {
store.dispatch(push('/edit/' + docType))
}
}
// If path ends in :id...
if (regex.checkIfRedirectPath(path)) {
// And currentDocument is set, push the right identifier
if (currentDocument.hasOwnProperty('id')) {
store.dispatch(push(docType === 'chapters' ? String(currentDocument.number) : currentDocument.id))
}
// And path is /:id and chapters are loaded, set currentDocument to first chapter
else if (regex.checkIfRootPath(path) && chapters.length > 0) {
console.log('THIS IS HAPPENING')
store.dispatch(actions.setCurrentDocument(chapters[0].id, 'chapters'))
}
// And path has a docType and docs are loaded, set currentDocument to first doc of that type
else if (regex.checkIfDocTypePath(path)) {
switch(regex.parseDocTypeFromPath) {
case 'notes':
if (notes.length > 0) {
store.dispatch(actions.setCurrentDocument(notes[0].id, 'notes'))
}
case 'tags':
if (tags.length > 0) {
store.dispatch(actions.setCurrentDocument(tags[0].id, 'tags'))
}
case 'media':
if (media.length > 0) {
store.dispatch(actions.setCurrentDocument(media[0].id, 'media'))
}
default:
break
}
}
}
case 'GET_DOCUMENT_LIST':
if (action.status === 'success' && action.docType === docType && !currentDocument.id) {
if (regex.checkIfRedirectPath(path)) {
// If path ends in :id, set currentDocument to the first from the returned list
if (regex.checkIfRedirectPath(path) && action.data.length > 0) {
store.dispatch(actions.setCurrentDocument(action.data[0].id, action.docType))
}
// If docType is chapters and path ends in a number, find chapter matching that number and set its ID to currentDocument
if (action.docType === 'chapters' && pathNumber !== undefined) {
for (const chapter of action.data) {
if (chapter.number === pathNumber) {
store.dispatch(actions.setCurrentDocument(chapter.id, action.docType))
}
}
// If path ends in an ID, set it to the currentDocument
} else if (pathID !== undefined) {
store.dispatch(actions.setCurrentDocument(pathID, action.docType))
}
}
break
case 'SET_EDITOR_DOC_TYPE':
// If path starts with /edit, set the path appropriate for the docType
if (regex.checkEditRoute(path)) {
if (action.docType === 'chapters') {
store.dispatch(push('/edit'))
@ -77,6 +91,7 @@ const joyceRouter = store => next => action => {
break
case 'GET_DOCUMENT_TEXT':
if (action.status === 'success' && action.state === 'currentDocument') {
// After successfully retrieving a currentDocument, push its identifier to the path
store.dispatch(push(action.docType === 'chapters' ? String(action.data.number) : action.data.id))
}
break

View File

@ -19,10 +19,12 @@ const helpers = {
break
case 'tags':
return 'Tags'
case 'media':
return 'Media'
break
}
},
documentsOfDocType: (docType, chapters, notes, tags) => {
documentsOfDocType: (docType, chapters, notes, tags, media) => {
switch(docType) {
case 'chapters':
return chapters
@ -32,6 +34,8 @@ const helpers = {
break
case 'tags':
return tags
case 'media':
return media
break
}
}

View File

@ -7,60 +7,61 @@ const regexCheckBaseFunction = (path, pattern) => {
}
}
const regexParseBaseFunction = (path, pattern) => {
const regexParseBaseFunction = (path, pattern, n=1) => {
const match = pattern.exec(path)
if (match) {
return match[1]
return match[n]
} else {
return null
}
}
const patterns = {
PATH_WITH_NUMBER: /\/([0-9]{1,3})$/,
PATH_WITH_ID: /\/([0-9A-Za-z0-9\-\_]{18,})$/,
PATH_WITH_DOC_TYPE: /^\/(edit\/)*(notes|tags|chapters|media)/,
PATH_WITH_ID_REDIRECT: /\/(\:id)$/,
PATH_ROOT: /^\/(\:id)*$/,
PATH_EDITOR: /^\/edit(\/)*/,
PATH_BASE_EDITOR: /^\/edit$/,
HEX_COLOR: /(^[0-9A-F]{6})$|(^[0-9A-F]{3}$)/,
}
const regex = {
// Route Checks
checkIfRedirectPath: path => {
return regexCheckBaseFunction(path, /\/(\:id)$/)
},
checkNoteBaseRoute: path => {
return regexCheckBaseFunction(path, /^\/notes$/)
},
checkEditBaseRoute: path => {
return regexCheckBaseFunction(path, /^\/edit$/)
},
checkEditRoute: path => {
return regexCheckBaseFunction(path, /^\/edit\//)
},
checkNoteReaderRoute: path => {
return regexCheckBaseFunction(path, /^\/notes\/([0-9a-zA-Z\-\_]{18,}|\:id)/)
},
checkChapterEditorRoute: path => {
return regexCheckBaseFunction(path, /^\/edit\/([0-9]{1,3}|\:id)/)
},
checkNoteEditorRoute: path => {
return regexCheckBaseFunction(path, /^\/edit\/notes\/([0-9a-zA-Z\-\_]{18,}|\:id)/)
},
checkTagEditorRoute : path => {
return regexCheckBaseFunction(path, /^\/edit\/tags\/([0-9a-zA-Z\-\_]{18,}|\:id)/)
},
checkPathForNumber: path => {
return regexCheckBaseFunction(path, /\/[0-9]{1,3}$/)
},
checkRootRedirectRoute: path => {
return regexCheckBaseFunction(path, /^\/\:id$/)
return regexCheckBaseFunction(path, patterns.PATH_WITH_NUMBER)
},
checkPathForID: path => {
return regexCheckBaseFunction(path, /\/([0-9A-Za-z0-9\-\_]{18,})$/)
return regexCheckBaseFunction(path, patterns.PATH_WITH_ID)
},
checkIfDocTypePath: path => {
return regexCheckBaseFunction(path, patterns.PATH_WITH_DOC_TYPE)
},
checkIfRedirectPath: path => {
return regexCheckBaseFunction(path, patterns.PATH_WITH_ID_REDIRECT)
},
checkIfRootPath: path => {
return regexCheckBaseFunction(path, patterns.PATH_ROOT)
},
checkEditRoute: path => {
return regexCheckBaseFunction(path, patterns.PATH_EDITOR)
},
checkEditBaseRoute: path => {
return regexCheckBaseFunction(path, patterns.PATH_BASE_EDITOR)
},
// Route Parsers
parseNumberFromPath: path => {
return Number(regexParseBaseFunction(path, /\/([0-9]{1,3})$/))
return Number(regexParseBaseFunction(path, patterns.PATH_WITH_NUMBER))
},
parseIDFromPath: path => {
return regexParseBaseFunction(path, /\/([0-9A-Za-z0-9\-\_]{18,})$/)
return regexParseBaseFunction(path, patterns.PATH_WITH_ID)
},
parseDocTypeFromPath: path => {
return regexParseBaseFunction(path, patterns.PATH_WITH_DOC_TYPE, 2)
},
// Validation Checks
checkColorPickerHexValue: input => {
return regexCheckBaseFunction(input, /(^[0-9A-F]{6})$|(^[0-9A-F]{3}$)/)
return regexCheckBaseFunction(input, patterns.HEX_COLOR)
}
}

View File

@ -1,18 +0,0 @@
const loadingToggle = (state=true, action) => {
switch(action.type) {
case 'GET_DOCUMENT_TEXT':
if (action.status === 'request' && action.state === 'currentDocument') {
return true
} else if (action.status === 'success' && action.state === 'currentDocument') {
return false
}
case 'GET_DOCUMENT_LIST':
if (action.status === 'success' && !action.data[0] && action.state === 'currentDocType') {
return false
}
default:
return state
}
}
export default loadingToggle

20
src/reducers/media.js Normal file
View File

@ -0,0 +1,20 @@
const media = (state=[], action) => {
switch(action.type) {
case 'GET_DOCUMENT_LIST':
if (action.status === 'success' && action.docType === 'media') {
return action.data
} else { return state }
case 'DELETE_DOCUMENT':
if (action.status === 'success' && action.docType === 'media') {
return action.data
} else { return state }
case 'SAVE_DOCUMENT':
if (action.status === 'success' && action.docType === 'media') {
return action.data
} else { return state }
default:
return state
}
}
export default media

View File

@ -6,6 +6,7 @@ import { routerReducer } from 'react-router-redux'
import chapters from './chapters'
import notes from './notes'
import tags from './tags'
import media from './media'
import currentDocument from './currentDocument'
import annotationNote from './annotationNote'
import annotationTag from './annotationTag'
@ -36,6 +37,7 @@ const reduceJoyce = combineReducers({
chapters,
notes,
tags,
media,
currentDocument,
annotationNote,
annotationTag,

View File

@ -21,11 +21,17 @@ const toggles = (state=initialState, action) => {
}
case 'GET_DOCUMENT_LIST':
if (action.status === 'success' && !action.data[0] && action.state === 'currentDocType') {
// if (action.status === 'success' && action.state === 'currentDocType') {
return {
...state,
loading: false
}
}
case 'CREATE_DOCUMENT':
return {
...state,
loading: false
}
// Highlights
case 'TOGGLE_HIGHLIGHT':
return {

View File

@ -65,6 +65,9 @@
height: 68vh;
}
// #editor_content.edit_mode.media {
// height: 30vh;
// }
#editor_content.annotate_mode {
height: 73vh;