Modified reader entry point to use react-router with redux

This commit is contained in:
Alex Hunt 2018-04-29 19:49:18 -04:00
parent a6cf429335
commit a5043b3ea1
10 changed files with 101 additions and 57 deletions

View File

@ -24,10 +24,7 @@
+ Make Remove Highlight Work with Contextual Disabling +
TODAY:
- Implement React-Router
NEXT: Bring everything under single entry point w/ React Router
SHORT LIST:
- Make Annotate Mode Ignore Keyboard Input

View File

@ -1,8 +1,11 @@
from flask import Blueprint, render_template, abort
from flask import Blueprint, render_template, abort, redirect
from jinja2 import TemplateNotFound
reader = Blueprint('reader', __name__)
@reader.route('/')
def show_reader():
return render_template('reader.html')
@reader.route('/', defaults={'path': ''})
def redirect_root(path):
return redirect('/1')
@reader.route('/<path:path>')
def show_reader(path):
return render_template('reader.html')

View File

@ -11,16 +11,20 @@
"author": "Alex Hunt",
"license": "ISC",
"dependencies": {
"react": "^16.0.0",
"react-dom": "^16.0.0",
"react-redux": "^5.0.6",
"redux": "^3.7.2",
"bootstrap": "^4.1.0",
"draft-js": "^0.10.4",
"draft-js-export-html": "^1.2.0",
"draft-js-import-html": "^1.2.1",
"bootstrap": "^4.1.0",
"font-awesome": "^4.7.0",
"history": "^4.7.2",
"popper.js": "^1.12.6",
"font-awesome": "^4.7.0"
"react": "^16.0.0",
"react-dom": "^16.0.0",
"react-redux": "^5.0.6",
"react-router": "^4.2.0",
"react-router-dom": "^4.2.2",
"react-router-redux": "^5.0.0-alpha.9",
"redux": "^3.7.2"
},
"devDependencies": {
"babel-core": "^6.26.0",

View File

@ -1,4 +1,6 @@
import React from 'react'
import { Link } from 'react-router-dom'
import romanize from '../mixins/romanize'
export const ReaderEditButton = ({onClick}) =>
@ -19,9 +21,9 @@ export const ReaderAnnotateButton = ({onClick}) =>
export const ChapterButton = ({chapter, currentChapter, onClick}) =>
<div className ='chapter_button text-center'>
<button onClick={()=>onClick(chapter.id)} className={currentChapter.id === chapter.id ? 'btn btn-dark btn-lg' : 'btn btn-outline-dark btn-lg inactive_button'}>
<Link to={'/'+ chapter.number} className={currentChapter.id === chapter.id ? 'btn btn-dark btn-lg active_button' : 'btn btn-outline-dark btn-lg inactive_button'}>
{romanize(chapter.number)}. {chapter.title}
</button>
</Link>
</div>
export const NoteButton = ({note, currentNote, onClick}) =>

View File

@ -1,5 +1,6 @@
import React from 'react'
import { connect } from 'react-redux'
import { Route } from 'react-router'
import Navbar from '../components/navbar'
import Content from '../components/content'
@ -13,20 +14,22 @@ const JoyceReaderPage = ({currentDocument, loadingToggle, annotationNote}) =>
<div>
<Navbar />
<div id='joyce_reader' className='container-fluid'>
<div className="row">
<JoyceReaderSidebarContainer />
<Content>
{loadingToggle === true &&
<LoadingSpinner size={4} />
}
{(Object.keys(currentDocument).length > 0 && loadingToggle === false) &&
<JoyceReaderContentContainer />
}
{(Object.keys(currentDocument).length === 0 && loadingToggle === false) &&
<ReaderWelcome />
}
</Content>
</div>
<Route path='/'>
<div className="row">
<JoyceReaderSidebarContainer />
<Content>
{loadingToggle === true &&
<LoadingSpinner size={4} />
}
{(Object.keys(currentDocument).length > 0 && loadingToggle === false) &&
<JoyceReaderContentContainer />
}
{(Object.keys(currentDocument).length === 0 && loadingToggle === false) &&
<ReaderWelcome />
}
</Content>
</div>
</Route>
</div>
<AnnotationModal annotationNote={annotationNote} />
</div>

View File

@ -28,8 +28,9 @@ store.dispatch(getDocumentList({
state: 'currentDocType'
}))
// Hacky way to fetch first chapter after async call above has completed.
// TODO: Add number lookup to API?
// TODO: Remove when
// API can handle number lookups
// Routing can handle / => /1
setTimeout(
() => {
const firstDocument = getFirstDocument(store, docType)

View File

@ -49,6 +49,21 @@ const convertToPlainText = contentState => {
)
}
const selectChapterIDByNumber = (store, number) => {
for (const chapter of store.getState().chapters) {
if (number === chapter.number) {
return chapter.id
}
}
}
const parseNumberFromPath = path => {
const match = /^\/([0-9]*)/.exec(path)
const number = Number(match[1])
console.log('Hey!', number)
return number
}
// API Middleware
export const joyceAPI = store => next => action => {
next(action)
@ -60,6 +75,12 @@ export const joyceAPI = store => next => action => {
store.dispatch(getDocumentList(response))
)
}
if (action.status === 'success' && action.state === 'initialPageLoad') {
HTTPGetDocumentList(action.docType, action.state).then(response => {
const pathName = store.getState().routerReducer.location.pathname
store.dispatch(setCurrentDocument(selectChapterIDByNumber(store, parseNumberFromPath(pathName)), action.docType))
})
}
break
case 'GET_DOCUMENT_TEXT':
if (action.status === 'request') {
@ -144,7 +165,15 @@ export const joyceAPI = store => next => action => {
store.dispatch(getSearchResults(response))
)
}
break
break
case '@@router/LOCATION_CHANGE':
if (/^\/[0-9]*/.test(action.payload.pathname)) {
for (const chapter of store.getState().chapters) {
if (action.payload.pathname === '/' + chapter.number) {
store.dispatch(setCurrentDocument(chapter.id, 'chapters'))
}
}
}
default:
break
}

View File

@ -1,42 +1,42 @@
// node_modules
import React from 'react'
import ReactDOM from 'react-dom'
import { createStore, applyMiddleware } from 'redux'
import { Provider } from 'react-redux'
import 'bootstrap'
import { ConnectedRouter, routerReducer, routerMiddleware, push } from 'react-router-redux'
import createHistory from 'history/createBrowserHistory'
// import 'bootstrap'
// src packages
import reduceReader from './reducers/reduceReader'
import { getDocumentList } from './actions/apiActions'
import { setCurrentDocument, setDocType } from './actions/userActions'
import { logger, joyceAPI } from './middleware/'
import { getFirstDocument } from './mixins/firstDocument'
import JoyceReaderPageContainer from './containers/joyceReaderPageContainer'
import JoyceEditorPageContainer from './containers/joyceEditorPageContainer'
// TODO: Pass routing from Flask?
let docType = 'chapters'
let store = createStore(reduceReader, applyMiddleware(logger, joyceAPI))
const history = createHistory()
const router = routerMiddleware(history)
const docType = 'chapters'
const store = createStore(reduceReader, applyMiddleware(logger, joyceAPI, router))
store.dispatch(setDocType(docType))
ReactDOM.render(
<Provider store={store}>
<JoyceReaderPageContainer />
<ConnectedRouter history={history}>
<div>
<JoyceReaderPageContainer />
</div>
</ConnectedRouter>
</Provider>,
document.getElementById('wrapper')
)
store.dispatch(getDocumentList({
docType: docType,
state: 'currentDocType'
}))
// Hacky way to fetch first chapter after async call above has completed.
// TODO: Add number lookup to API?
setTimeout(
() => {
const firstDocument = getFirstDocument(store, docType)
if (firstDocument) {
store.dispatch(setCurrentDocument(firstDocument.id, docType))
}
},
1000
)
state: 'initialPageLoad'
}))

View File

@ -8,6 +8,8 @@ import annotationNote from './annotationNote'
import highlightToggle from './highlightToggle'
import loadingToggle from './loadingToggle'
import docType from './docType'
import { routerReducer } from 'react-router-redux'
const reduceReader = combineReducers({
chapters,
@ -17,7 +19,8 @@ const reduceReader = combineReducers({
docType,
currentDocument,
highlightToggle,
loadingToggle
loadingToggle,
routerReducer
})
export default reduceReader

View File

@ -20,24 +20,26 @@
border: 1px solid $border_color;
}
.chapter_button > button {
.chapter_button > a {
width: 100%;
margin: 0.25% 0;
padding: 0.2rem 1rem;
font-size: 1rem;
box-shadow: 2px 5px 10px 1px rgba(0, 0, 0, 0.3);
// &:not(.active_button) {
// background-color: rgba(250, 250, 250, 0.8);
// }
}
button {
background-color: rgba(250, 250, 250, 0.8);
}
.chapter_button > button.inactive_button:not(:hover) {
background-color: rgba(250, 250, 250, 0.8);
.chapter_button > a.inactive_button:not(:hover) {
background-color: rgba(250, 250, 250, 1);
}
.note_button > button.inactive_button:not(:hover) {
.note_button > a.inactive_button:not(:hover) {
background-color: rgba(250, 250, 250, 0.8);
}