-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Refactor topic highlighter container (#45)
* Add babel plugin transform-class-properties to assist binding 'this' in React components. * PybossaHighlighter now saving highlights to Pybossa. * Restore old article reducer state to fix regression. Last commit with front-end calling old API. * Change front-end to use new paged highlighter_tasks2 endpoint. Code designed to precisely separate real Pybossa and mock Pybossa API calls. Remove old API fetches from front-end. * Remove Article component - it's only adding three divs. Merge into topicPicker. * Factor out real and mock API into container classes inheriting from TopicHighlighter. * HighlighterTasks container handles fetching, so TopicHighlighter is now a component.
- Loading branch information
1 parent
9df2fa3
commit 554905f
Showing
23 changed files
with
368 additions
and
460 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,36 +1,13 @@ | ||
export function fetchArticle(articleId) { | ||
return (dispatch) => { | ||
dispatch({ type: 'FETCH_ARTICLE', articleId}); | ||
let host = "http://localhost:5000"; | ||
return fetch(host + `/api/articles/${articleId}/?format=json`) | ||
.then(response => response.json()) | ||
.then( | ||
(response) => dispatch({ type: 'FETCH_ARTICLE_SUCCESS', response}), | ||
(error) => dispatch({ type: 'FETCH_ARTICLE_FAIL', error}) | ||
); | ||
}; | ||
} | ||
|
||
export function postArticleHighlights(highlightsString, articleId) { | ||
return (dispatch) => { | ||
dispatch({ type: 'POST_HIGHLIGHTS'}); | ||
|
||
return fetch(`http://localhost:5000/api/postHighlights/${articleId}`, { | ||
method: 'POST', | ||
body: highlightsString | ||
}) | ||
.then(response => response.json()) | ||
.then( | ||
(response) => dispatch({ type: 'POST_HIGHLIGHTS_SUCCESS'}, response), | ||
(error) => dispatch({ type: 'POST_HIGHLIGHTS_FAIL', error}) | ||
); | ||
export function storeArticle(article) { | ||
return { | ||
type: 'FETCH_ARTICLE_SUCCESS', | ||
response: article | ||
}; | ||
} | ||
|
||
export function storeArticle(article) { | ||
return (dispatch) => { | ||
dispatch({ type: 'FETCH_ARTICLE_SUCCESS', | ||
response: article | ||
}); | ||
export function storeSaveAndNext(saveAndNext) { | ||
return { | ||
type: 'POST_HIGHLIGHTS_CALLBACK', | ||
saveAndNext: saveAndNext | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
import { storeProject } from 'actions/project'; | ||
import { storeArticle, storeSaveAndNext } from 'actions/article'; | ||
import { storeTopics } from 'actions/topicPicker'; | ||
|
||
import { normalize, Schema, arrayOf } from 'normalizr'; | ||
|
||
let taskSchema = new Schema('tasks'); | ||
let taskList = { results: arrayOf(taskSchema) }; | ||
|
||
function storeTasks(dispatch, pagedTasks) { | ||
// Until back-end returns task ids, copy article id as the task id | ||
pagedTasks.results = pagedTasks.results.map( | ||
(task) => ({...task, id: task.article.id}) | ||
); | ||
// Normalize data structure and dispatch | ||
const taskDatabase = normalize(pagedTasks, taskList); | ||
// Replace or push task IDs to queue | ||
dispatch({type: 'FETCH_HIGHLIGHT_TASKS_SUCCESS', | ||
pagedTasks, | ||
taskDatabase | ||
}); | ||
// Make a copy of the unique task Ids collected by normalize | ||
let taskQueue = taskDatabase.result.results.slice(); | ||
dispatch({type: 'UPDATE_HIGHLIGHT_TASK_QUEUE', taskQueue}); | ||
} | ||
|
||
function postArticleHighlights(highlightsString, articleId) { | ||
return (dispatch) => { | ||
dispatch({ type: 'POST_HIGHLIGHTS'}); | ||
|
||
return fetch(`http://localhost:5000/api/postHighlights/${articleId}`, { | ||
method: 'POST', | ||
body: highlightsString | ||
}) | ||
.then(response => response.json()) | ||
.then( | ||
(response) => dispatch({ type: 'POST_HIGHLIGHTS_SUCCESS'}, response), | ||
(error) => dispatch({ type: 'POST_HIGHLIGHTS_FAIL', error}) | ||
); | ||
}; | ||
} | ||
|
||
function presentTask(dispatch, getState) { | ||
const taskReducer = getState().highlightTasks; | ||
const taskDB = taskReducer.taskDatabase.entities.tasks; | ||
let taskQueue = taskReducer.taskQueue.slice(); | ||
if (taskQueue.length > 0) { | ||
const taskId = taskQueue.shift(); | ||
const task = taskDB[taskId]; | ||
dispatch(storeProject(task.project)); | ||
dispatch(storeArticle(task.article)); | ||
dispatch(storeTopics(task.topics)); | ||
// Dispatch an action to clear any existing highlights | ||
// dispatch(XXXX); | ||
dispatch({type: 'UPDATE_HIGHLIGHT_TASK_QUEUE', taskQueue}); | ||
dispatch({type: 'CURRENT_HIGHLIGHT_TASK', taskId}); | ||
|
||
function onSaveAndNext(highlights) { | ||
// dispatch save highight action which will return a promise, so | ||
// promise.then( call this ) to load next task | ||
// or better, deep copy highlights and don't wait to show next task | ||
presentTask(dispatch, getState); | ||
} | ||
// Tricky part: We have loaded the task, now we also provide the | ||
// callback that the U button can use to save the data and trigger | ||
// loading the next task. | ||
dispatch(storeSaveAndNext(onSaveAndNext)); | ||
} else { | ||
// TODO: update store with done flag and show nicely in UI | ||
console.log('No more tasks.'); | ||
throw new Error('No more tasks.'); | ||
} | ||
} | ||
|
||
export function runNextTask() { | ||
return (dispatch, getState) => presentTask(dispatch, getState); | ||
} | ||
|
||
export function fetchHighlightTasks(pageParam) { | ||
return (dispatch, getState) => { | ||
dispatch({type: 'FETCH_HIGHLIGHT_TASKS'}); | ||
let host = "http://localhost:5000"; | ||
let pageParam = pageParam ? pageParam : ''; | ||
return fetch(host + `/api/highlighter_tasks2/?format=json${pageParam}`) | ||
.then(response => response.json()) | ||
.then(pagedTasks => { | ||
storeTasks(dispatch, pagedTasks); | ||
presentTask(dispatch, getState); | ||
}, | ||
error => dispatch({type: 'FETCH_HIGHLIGHT_TASKS_FAIL', error}) | ||
) | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,22 +1,8 @@ | ||
export function fetchProject() { | ||
return (dispatch) => { | ||
dispatch({ type: 'FETCH_PROJECT'}); | ||
|
||
return fetch(`http://localhost:5000/api/projects/?format=json`) | ||
.then(response => response.json()) | ||
.then( | ||
(response) => dispatch({ type: 'FETCH_PROJECT_SUCCESS', response}), | ||
(error) => dispatch({ type: 'FETCH_PROJECT_FAIL', error}) | ||
); | ||
}; | ||
} | ||
|
||
export function storeProject(project) { | ||
return (dispatch) => { | ||
dispatch({ type: 'FETCH_PROJECT_SUCCESS', | ||
response: { | ||
results: [project] | ||
} | ||
}); | ||
return { | ||
type: 'FETCH_PROJECT_SUCCESS', | ||
response: { | ||
results: [project] | ||
} | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
import React, { Component } from 'react'; | ||
import ReactDOM from 'react-dom'; | ||
import ReactCSSTransitionsGroup from 'react-addons-css-transition-group'; | ||
|
||
import { colors } from 'utils/colors'; | ||
import HighlightTool from 'components/HighlightTool'; | ||
import TopicPicker from 'components/TopicPicker'; | ||
import Project from 'components/Project'; | ||
|
||
import { styles } from './styles.scss'; | ||
|
||
export class TopicHighlighter extends Component { | ||
constructor(props) { | ||
super(props); | ||
} | ||
|
||
// Babel plugin transform-class-properties allows us to use | ||
// ES2016 property initializer syntax. So the arrow function | ||
// will bind 'this' of the class. (React.createClass does automatically.) | ||
onSaveAndNext = () => { | ||
this.props.saveAndNext(this.props.highlights); | ||
} | ||
|
||
render() { | ||
// TODO: Detect if done | ||
// return (<div>DONE</div>) | ||
|
||
let loadingClass = this.props.article.isFetching ? 'loading' : ''; | ||
|
||
return ( | ||
<ReactCSSTransitionsGroup transitionName='fadein' | ||
transitionAppear | ||
transitionAppearTimeout={500} | ||
transitionEnterTimeout={500} | ||
transitionLeaveTimeout={500}> | ||
<div className={loadingClass}></div> | ||
<div className='topic-picker-wrapper'> | ||
<TopicPicker topics={this.props.topics} /> | ||
</div> | ||
<div className='article-wrapper'> | ||
<Project /> | ||
<ReactCSSTransitionsGroup transitionName='fade-between' | ||
transitionAppear | ||
transitionAppearTimeout={500} | ||
transitionEnterTimeout={500} | ||
transitionLeaveTimeout={500}> | ||
<div className="article" key={this.props.article.articleId}> | ||
<div className='article__header-text'> | ||
</div> | ||
<div id='article-container'> | ||
<HighlightTool | ||
text={this.props.article.text} | ||
topics={this.props.topics.results} | ||
colors={colors} | ||
currentTopicId={this.props.currentTopicId} | ||
/> | ||
</div> | ||
</div> | ||
</ReactCSSTransitionsGroup> | ||
<br/> | ||
<button onClick={this.onSaveAndNext}>Save and Next</button> | ||
<div className="space"></div> | ||
</div> | ||
</ReactCSSTransitionsGroup> | ||
); | ||
} | ||
}; |
30 changes: 23 additions & 7 deletions
30
app/components/Article/styles.scss → app/components/TopicHighlighter/styles.scss
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,25 +1,41 @@ | ||
@import 'app/styles/_mixins.scss'; | ||
@import 'app/styles/_variables.scss'; | ||
|
||
.topic-picker-wrapper { | ||
padding-left: 0 !important; | ||
} | ||
|
||
.article-wrapper { | ||
margin: 2em 1em 2em 275px; | ||
} | ||
|
||
.loading { | ||
width: 100%; | ||
height: 100%; | ||
z-index: 100; | ||
top: 0px; | ||
left: 0px; | ||
position: fixed; | ||
background-color: rgba(30, 30, 30, 0.3); | ||
} | ||
|
||
.space { | ||
height: 100px; | ||
} | ||
|
||
.article { | ||
@include newspaper; | ||
transition: opacity $transition-slow; | ||
margin-bottom: 10px; | ||
line-height: 2.2; | ||
|
||
&.is-fetching { | ||
border: 2px dotted black; //TODO: REMOVE THESE TEMP STYLES | ||
opacity: 0.5; | ||
} | ||
|
||
.article__header-text { | ||
padding: 10px; | ||
margin-bottom: 10px; | ||
} | ||
|
||
#article-container { | ||
padding: 1em; | ||
border: 1px solid black; | ||
} | ||
|
||
} |
Oops, something went wrong.