diff --git a/src/components/TurkHit/index.js b/src/components/TurkHit/index.js
index 1c3e9383715552cf40df60ab2d6693f701c894d8..517143a2ddd99a726ce1f8a8388381f2980c1956 100644
--- a/src/components/TurkHit/index.js
+++ b/src/components/TurkHit/index.js
@@ -1,73 +1,126 @@
-import React, { PropTypes } from 'react';
+import React, { PropTypes, Component } from 'react';
import defaultForm from './defaultForm';
import './styles.scss';
+import turkHitPropTypes from '../../containers/Dimensions/propTypes';
+import turkStatus from './turkStatus';
-export default function TurkHit({ createHit, hitDecision, address, building_id, hit }) {
- let hitStatus =
;
- const createBtn = (
- createHit({ ...defaultForm, address, building_id })}
- className="btn btn-primary"
- >
- Create Hit
-
- );
+class TurkHit extends Component {
+ constructor(props) {
+ super(props);
- // Loading HIT
- if (hit.loading) {
- return Loading...
;
- } else if (hit.error.message && hit.error.response.status !== 404) {
- return {hit.error.message}
;
+ // TODO not being used
+ this.state = {
+ error: false,
+ };
}
- if (!hit.error.message && hit.status !== '') {
- let fileActions =
;
+ renderDownloadLink = () => {
+ const buildings = this.props.hit.boxBuildingList;
+ /* eslint-disable jsx-a11y/href-no-hash*/
+ return (
+ 0 ? buildings.slice(-1)[0].url_download : '#'}
+ >
+ Download
+
+ );
+ }
+
+ renderCreateHitButton = () => {
+ const { createHit, address, building_id } = this.props;
+ return (
+ createHit({ ...defaultForm, address, building_id })}
+ className="btn btn-primary"
+ >
+ Create Hit
+
+ );
+ }
+
+ renderHitActions = () => {
+ const { hitDecision, building_id } = this.props;
+ return (
+
+ hitDecision(building_id, 1)}
+ >
+ Approve
+
+ hitDecision(building_id, 0)}
+ >
+ Reject
+
+
+ );
+ }
+
+ render() {
+ const { hit } = this.props;
+ const { status } = this.props.hit;
+ let mainContent =
;
+
+ if (hit.loading) {
+ return Loading...
;
+ } else if (hit.error && hit.error.response.status !== 404) {
+ return (
+
+ Retrieving HIT error. Response message: {hit.error.message}
+
+ );
+ }
- if (hit.status === 'Reviewable') {
- fileActions = (
+ if (status !== '') {
+ const currStatus = turkStatus[status];
+ mainContent = (
+
+ {turkStatus[status].message}
+ {currStatus.createBtn && this.renderCreateHitButton()}
+
+ {currStatus.downloadLink && this.renderDownloadLink()}
+ {currStatus.fileActions && this.renderHitActions()}
+
+
+ );
+ } else {
+ mainContent = (
-
Download File
-
hitDecision(building_id, 1)}
- >
- Approve
-
-
hitDecision(building_id, 0)}
- >
- Reject
-
+
HIT has not been created yet.
+ {this.renderCreateHitButton()}
);
- } else if (hit.status === 'Rejected'
- || hit.status === 'Expired'
- || hit.status === 'Disposed') {
- fileActions = createBtn;
}
- hitStatus = (
+ return (
- HIT Status: {hit.status}
- {fileActions}
+
+ Failed to create HIT. Response message: {hit.create.error.message}
+
+
+
Mechanical Turk
+
Definitions
+
+ Amazon Mechanical Turk is a marketplace for workers to complete Human
+ Intelligence Tasks or HITs.
+
+ We will be creating HITs for workers to measure the dimensions of a building.
+ HITs have 6 days to be completed from date of creation.
+
+
+ {mainContent}
);
- } else {
- hitStatus = createBtn;
- }
-
- // Creating HIT -- error message
- if (hit.create.error.message) {
- return {hit.create.error.message}
;
}
-
- return (
-
- {hitStatus}
-
- );
}
TurkHit.propTypes = {
@@ -75,14 +128,7 @@ TurkHit.propTypes = {
hitDecision: PropTypes.func,
address: PropTypes.string,
building_id: PropTypes.number,
- hit: PropTypes.shape({
- id: PropTypes.string,
- status: PropTypes.string,
- loading: PropTypes.boolean,
- error: PropTypes.boolean,
- create: PropTypes.shape({
- loading: PropTypes.boolean,
- error: PropTypes.boolean,
- }),
- }),
+ hit: turkHitPropTypes,
};
+
+export default TurkHit;
diff --git a/src/components/TurkHit/turkStatus.js b/src/components/TurkHit/turkStatus.js
new file mode 100644
index 0000000000000000000000000000000000000000..5b9478b42459456d04a201b17a543edecd16eec9
--- /dev/null
+++ b/src/components/TurkHit/turkStatus.js
@@ -0,0 +1,44 @@
+export default {
+ Assignable: {
+ message: 'HIT has been submitted to mechanical turk and is waiting for worker.',
+ createBtn: false,
+ fileActions: false,
+ downloadLink: false,
+ },
+ Unassignable: {
+ message: 'Worker is finding the measurements of the building.',
+ createBtn: false,
+ fileActions: false,
+ downloadLink: false,
+ },
+ Reviewable: {
+ message: 'Measurements have been submitted. Check if the file is correct and either approve or reject.',
+ createBtn: false,
+ fileActions: true,
+ downloadLink: true,
+ },
+ Accepted: {
+ message: 'HIT is completed and has been accepted.',
+ createBtn: false,
+ fileActions: false,
+ downloadLink: true,
+ },
+ Rejected: {
+ message: 'The HIT has been rejected.',
+ createBtn: true,
+ fileActions: false,
+ downloadLink: true,
+ },
+ Disposed: {
+ message: 'The HIT has been deleted from mechanical turk. Create a new HIT.',
+ createBtn: true,
+ fileActions: false,
+ downloadLink: false,
+ },
+ Expired: {
+ message: 'The HIT has been expired and must be recreated.',
+ createBtn: true,
+ fileActions: false,
+ downloadLink: false,
+ },
+};
diff --git a/src/containers/BuildingOverview/constants.js b/src/containers/BuildingOverview/constants.js
index 4ed5fd68462fab08fa820f6f60430820d4a0c1e7..25650cab4a7ecc0110cac9202331cfc7ff8c005f 100644
--- a/src/containers/BuildingOverview/constants.js
+++ b/src/containers/BuildingOverview/constants.js
@@ -1,12 +1,3 @@
export const LOAD_BUILDING_DETAIL = 'LOAD_BUILDING_DETAIL';
export const LOAD_BUILDING_DETAIL_SUCCEES = 'LOAD_BUILDING_DETAIL_SUCCEES';
export const LOAD_BUILDING_DETAIL_ERROR = 'LOAD_BUILDING_DETAIL_ERROR';
-export const LOAD_HIT = 'LOAD_HIT';
-export const LOAD_HIT_SUCCESS = 'LOAD_HIT_SUCCESS';
-export const LOAD_HIT_ERROR = 'LOAD_HIT_ERROR';
-export const CREATE_HIT = 'CREATE_HIT';
-export const CREATE_HIT_SUCCESS = 'CREATE_HIT_SUCCESS';
-export const CREATE_HIT_ERROR = 'CREATE_HIT_ERROR';
-export const DECIDE_HIT = 'DECIDE_HIT';
-export const DECIDE_HIT_SUCCESS = 'DECIDE_HIT_SUCCESS';
-export const DECIDE_HIT_ERROR = 'DECIDE_HIT_ERROR';
diff --git a/src/containers/BuildingOverview/index.js b/src/containers/BuildingOverview/index.js
index 24e62a013bad97834df47bcb6eea584a9196f5fd..f55618172b7d4d57a639a822b5aa65a1494ebbe9 100644
--- a/src/containers/BuildingOverview/index.js
+++ b/src/containers/BuildingOverview/index.js
@@ -3,27 +3,19 @@ import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import buildingDetailPropTypes from './buildingDetailPropType';
-import {
- loadBuildingDetail,
- loadHit,
- createHit,
- hitDecision,
-} from './actions';
+import { loadBuildingDetail } from './actions';
import './styles.scss';
import BuildingOverviewTop from '../../components/BuildingOverviewTop';
-import TurkHit from '../../components/TurkHit';
class BuildingOverview extends Component {
componentDidMount() {
this.props.loadBuildingDetail(this.props.params.buildingID);
- this.props.loadHit(this.props.params.buildingID);
}
render() {
let mainContent =
;
- let hit =
;
if (this.props.buildingDetail.overview.error) {
mainContent = (
@@ -37,22 +29,11 @@ class BuildingOverview extends Component {
building={this.props.buildingDetail.overview}
/>
);
-
- hit = (
-
- );
}
return (
{mainContent}
- {hit}
);
}
@@ -62,17 +43,11 @@ BuildingOverview.propTypes = {
buildingDetail: buildingDetailPropTypes,
params: PropTypes.objectOf(PropTypes.string),
loadBuildingDetail: PropTypes.func,
- loadHit: PropTypes.func,
- createHit: PropTypes.func,
- hitDecision: PropTypes.func,
};
function mapDispatchToProps(dispatch) {
return bindActionCreators({
loadBuildingDetail,
- loadHit,
- createHit,
- hitDecision,
}, dispatch);
}
diff --git a/src/containers/BuildingOverview/reducer.js b/src/containers/BuildingOverview/reducer.js
index fca4094058eef1955ce2d35672e13ac8e92a3d1a..198aa937aec6ba919354178094adb739a62a71df 100644
--- a/src/containers/BuildingOverview/reducer.js
+++ b/src/containers/BuildingOverview/reducer.js
@@ -2,15 +2,6 @@ import {
LOAD_BUILDING_DETAIL,
LOAD_BUILDING_DETAIL_SUCCEES,
LOAD_BUILDING_DETAIL_ERROR,
- LOAD_HIT,
- LOAD_HIT_SUCCESS,
- LOAD_HIT_ERROR,
- CREATE_HIT,
- CREATE_HIT_SUCCESS,
- CREATE_HIT_ERROR,
- DECIDE_HIT,
- DECIDE_HIT_SUCCESS,
- DECIDE_HIT_ERROR,
} from './constants';
const initState = {
@@ -18,20 +9,6 @@ const initState = {
loading: false,
error: false,
},
- hit: {
- id: '',
- status: '',
- loading: false,
- error: false,
- create: {
- loading: false,
- error: false,
- },
- approval: {
- loading: false,
- error: false,
- },
- },
};
export default function (state = initState, action) {
@@ -66,115 +43,6 @@ export default function (state = initState, action) {
},
};
- case LOAD_HIT:
- return {
- ...state,
- hit: {
- ...state.hit,
- status: '',
- loading: true,
- error: false,
- },
- };
-
- case LOAD_HIT_SUCCESS:
- return {
- ...state,
- hit: {
- ...state.hit,
- status: action.payload.data.status,
- url: action.payload.data.hit_url,
- loading: false,
- error: false,
- },
- };
-
- case LOAD_HIT_ERROR:
- return {
- ...state,
- hit: {
- ...state.hit,
- loading: false,
- error: action.error,
- },
- };
-
- case CREATE_HIT:
- return {
- ...state,
- hit: {
- ...state.hit,
- create: {
- loading: true,
- error: false,
- },
- },
- };
-
- case CREATE_HIT_SUCCESS:
- return {
- ...state,
- hit: {
- id: action.payload.data.hit_id,
- status: action.payload.data.status,
- loading: false,
- error: false,
- create: {
- loading: false,
- error: false,
- },
- },
- };
-
- case CREATE_HIT_ERROR:
- return {
- ...state,
- hit: {
- ...state.hit,
- create: {
- loading: false,
- error: action.error,
- },
- },
- };
-
- case DECIDE_HIT:
- return {
- ...state,
- hit: {
- ...state.hit,
- approval: {
- loading: true,
- error: false,
- },
- },
- };
-
- case DECIDE_HIT_SUCCESS:
- return {
- ...state,
- hit: {
- ...state.hit,
- status: action.payload.data.hit_status,
- approval: {
- loading: false,
- error: false,
- },
- },
- };
-
- case DECIDE_HIT_ERROR:
- return {
- ...state,
- hit: {
- ...state.hit,
- approval: {
- loading: false,
- error: action.error,
- },
- },
- };
-
default:
return state;
}
diff --git a/src/containers/BuildingOverview/sagas.js b/src/containers/BuildingOverview/sagas.js
index 2a410499591eb17fbb8889f814f018186ce27c88..284e2d74fe22b0be394ca7d9cd6611fde7babcc5 100644
--- a/src/containers/BuildingOverview/sagas.js
+++ b/src/containers/BuildingOverview/sagas.js
@@ -1,23 +1,14 @@
import { call, put, takeEvery } from 'redux-saga/effects';
import request from '../../utils/request';
-import { getHeaders, turkURL, buildingsURL } from '../../utils/rest_services';
+import { getHeaders, buildingsURL } from '../../utils/rest_services';
import {
LOAD_BUILDING_DETAIL,
- LOAD_HIT,
- CREATE_HIT,
- DECIDE_HIT,
} from './constants';
import {
buildingDetailLoaded,
buildingDetailLoadingError,
- hitLoaded,
- hitLoadingError,
- createHitSuccess,
- createHitError,
- hitDecisionSuccess,
- hitDecisionError,
} from './actions';
/**
@@ -42,68 +33,12 @@ function* getBuildingDetail(action) {
}
}
-function* loadHit(action) {
- const buildingId = action.payload;
- const data = yield call(request, `${turkURL}${buildingId}`, {
- method: 'GET',
- headers: getHeaders(),
- });
-
- if (!data.err) {
- yield put(hitLoaded(data));
- } else {
- yield put(hitLoadingError(data.err));
- }
-}
-
-/**
- * Mechanical Turk HIT creation request/response handler
- *
- * @param {object} action Form data of mechanical turk job
- */
-function* createHit(action) {
- const turkHitFormData = action.payload;
- const data = yield call(request, turkURL, {
- method: 'POST',
- headers: getHeaders(),
- body: JSON.stringify(turkHitFormData),
- });
-
- if (!data.err) {
- yield put(createHitSuccess(data));
- } else {
- yield put(createHitError(data.err));
- }
-}
-
-/**
- * Approve or reject HIT request/response handler
- *
- * @param {number} action 1 or 0 representing approve or reject
- */
-function* approveHit(action) {
- const data = yield call(request, `${turkURL}${action.buildingId}`, {
- method: 'PUT',
- headers: getHeaders(),
- body: JSON.stringify({ accept: action.decision }),
- });
-
- if (!data.err) {
- yield put(hitDecisionSuccess(data));
- } else {
- yield put(hitDecisionError(data.err));
- }
-}
-
/**
* Watches for LOAD_BUILDING_DETAIL & CREATE_HIT actions and calls
* the appropriate handler function.
*/
function* buildingDetailWatcher() {
yield takeEvery(LOAD_BUILDING_DETAIL, getBuildingDetail);
- yield takeEvery(LOAD_HIT, loadHit);
- yield takeEvery(CREATE_HIT, createHit);
- yield takeEvery(DECIDE_HIT, approveHit);
}
export default buildingDetailWatcher;
diff --git a/src/containers/Dimensions/actions.js b/src/containers/Dimensions/actions.js
new file mode 100644
index 0000000000000000000000000000000000000000..0600cfea77247821da68142fa3a042a5f93e5033
--- /dev/null
+++ b/src/containers/Dimensions/actions.js
@@ -0,0 +1,137 @@
+import 'whatwg-fetch';
+import {
+ LOAD_HIT,
+ LOAD_HIT_SUCCESS,
+ LOAD_HIT_ERROR,
+ CREATE_HIT,
+ CREATE_HIT_SUCCESS,
+ CREATE_HIT_ERROR,
+ DECIDE_HIT,
+ DECIDE_HIT_SUCCESS,
+ DECIDE_HIT_ERROR,
+} from './constants';
+
+/**
+ * Load status of HIT
+ * TODO The HIT status should be loaded from the building detail route
+ *
+ * @param {string} buildingId The current buildingID
+ * @returns {object} An action object with a type of
+ * LOAD_HIT passing the building_id
+ */
+export function loadHit(buildingId) {
+ return {
+ type: LOAD_HIT,
+ payload: buildingId,
+ };
+}
+
+/**
+ * Dispatched when the hit status was successfully loaded
+ *
+ * @param {string} hitStatus The HIT status
+ * @returns {object} An action object with a type of
+ * LOAD_HIT_SUCCESS passing the hit status
+ */
+export function hitLoaded(hitStatus) {
+ return {
+ type: LOAD_HIT_SUCCESS,
+ payload: hitStatus,
+ };
+}
+
+/**
+ * Dispatched when loading the hit status fails
+ *
+ * @param {object} error The error
+ * @returns {object} An action object with a type of
+ * LOAD_HIT passing the hit status
+ */
+export function hitLoadingError(error) {
+ return {
+ type: LOAD_HIT_ERROR,
+ error,
+ };
+}
+
+/**
+ * Create mturk HIT, this action starts the request saga
+ *
+ * @param {object} formData The mturk form data
+ * @returns {object} An action object with a type of CREATE_HIT
+ */
+export function createHit(formData) {
+ return {
+ type: CREATE_HIT,
+ payload: formData,
+ };
+}
+
+/**
+ * Dispatched when the mturk HIT was successfully created
+ *
+ * @param {object} hitData The created hit data
+ * @returns {object} An action object with a type of CREATE_HIT_SUCCESS
+ */
+export function createHitSuccess(hitData) {
+ return {
+ type: CREATE_HIT_SUCCESS,
+ payload: hitData,
+ };
+}
+
+/**
+ * Dispatched when creating the mturk HIT fails
+ *
+ * @param {object} error The error
+ * @return {object} An action object with a type of CREATE_HIT_ERROR
+ * passing the error
+ */
+export function createHitError(error) {
+ return {
+ type: CREATE_HIT_ERROR,
+ error,
+ };
+}
+
+/**
+ * Dispatched when user selects approve or reject HIT
+ *
+ * @param {int} buildingId Id of building
+ * @param {int} decision 1 or 0 representing approve or reject
+ * @returns {object} An action object with a type of DECIDE_HIT
+ * passing the decision of the user
+ */
+export function hitDecision(buildingId, decision) {
+ return {
+ type: DECIDE_HIT,
+ buildingId,
+ decision,
+ };
+}
+
+/**
+ * Dispatched when the hit was successfully approved or disapproved
+ *
+ * @returns {object}
+ */
+export function hitDecisionSuccess(data) {
+ return {
+ type: DECIDE_HIT_SUCCESS,
+ payload: data,
+ };
+}
+
+/**
+ * Dispatched when there is a error approving or rejecting a HIT
+ *
+ * @param error The error
+ * @returns {object} An action object with a type of DECIDE_HIT_ERROR
+ * passing the error
+ */
+export function hitDecisionError(error) {
+ return {
+ type: DECIDE_HIT_ERROR,
+ error,
+ };
+}
diff --git a/src/containers/Dimensions/constants.js b/src/containers/Dimensions/constants.js
new file mode 100644
index 0000000000000000000000000000000000000000..7d202767b2d5df08df3049adc550d2d234cfa050
--- /dev/null
+++ b/src/containers/Dimensions/constants.js
@@ -0,0 +1,9 @@
+export const LOAD_HIT = 'LOAD_HIT';
+export const LOAD_HIT_SUCCESS = 'LOAD_HIT_SUCCESS';
+export const LOAD_HIT_ERROR = 'LOAD_HIT_ERROR';
+export const CREATE_HIT = 'CREATE_HIT';
+export const CREATE_HIT_SUCCESS = 'CREATE_HIT_SUCCESS';
+export const CREATE_HIT_ERROR = 'CREATE_HIT_ERROR';
+export const DECIDE_HIT = 'DECIDE_HIT';
+export const DECIDE_HIT_SUCCESS = 'DECIDE_HIT_SUCCESS';
+export const DECIDE_HIT_ERROR = 'DECIDE_HIT_ERROR';
diff --git a/src/containers/Dimensions/index.js b/src/containers/Dimensions/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..70077e5628618c0b9954a66c63d1df85e50e93ee
--- /dev/null
+++ b/src/containers/Dimensions/index.js
@@ -0,0 +1,73 @@
+import React, { Component, PropTypes } from 'react';
+import { connect } from 'react-redux';
+import { bindActionCreators } from 'redux';
+
+import {
+ loadHit,
+ createHit,
+ hitDecision,
+} from './actions';
+
+import {
+ loadBuildingDetail,
+} from '../BuildingOverview/actions';
+
+import buildingDetailPropTypes from '../BuildingOverview/buildingDetailPropType';
+import turkHitPropTypes from './propTypes';
+
+import './styles.css';
+import TurkHit from '../../components/TurkHit';
+
+
+class Dimensions extends Component {
+ componentDidMount() {
+ /* eslint-disable camelcase */
+ const { address, building_id } = this.props.buildingDetail.overview;
+
+ this.props.loadHit(this.props.buildingId);
+ if (!address || this.props.buildingId !== building_id) {
+ this.props.loadBuildingDetail(this.props.buildingId);
+ }
+ }
+
+ render() {
+ return (
+
+
+
+ );
+ }
+}
+
+Dimensions.propTypes = {
+ buildingId: PropTypes.string,
+ buildingDetail: buildingDetailPropTypes,
+ dimensions: PropTypes.shape({
+ hit: turkHitPropTypes,
+ }),
+ loadHit: PropTypes.func,
+ createHit: PropTypes.func,
+ hitDecision: PropTypes.func,
+ loadBuildingDetail: PropTypes.func,
+};
+
+function mapDispatchToProps(dispatch) {
+ return bindActionCreators({
+ loadHit,
+ createHit,
+ hitDecision,
+ loadBuildingDetail,
+ }, dispatch);
+}
+
+function mapStateToProps({ dimensions, buildingDetail }) {
+ return { dimensions, buildingDetail };
+}
+
+export default connect(mapStateToProps, mapDispatchToProps)(Dimensions);
diff --git a/src/containers/Dimensions/propTypes.js b/src/containers/Dimensions/propTypes.js
new file mode 100644
index 0000000000000000000000000000000000000000..8ca01f5449d61c939fb643775d06922f962c13d4
--- /dev/null
+++ b/src/containers/Dimensions/propTypes.js
@@ -0,0 +1,17 @@
+import { PropTypes } from 'react';
+
+export default PropTypes.shape({
+ id: PropTypes.string,
+ status: PropTypes.string,
+ loading: PropTypes.boolean,
+ error: PropTypes.boolean,
+ boxBuildingList: PropTypes.arrayOf(
+ PropTypes.shape({
+ url_download: PropTypes.string,
+ })
+ ),
+ create: PropTypes.shape({
+ loading: PropTypes.boolean,
+ error: PropTypes.boolean,
+ }),
+});
diff --git a/src/containers/Dimensions/reducer.js b/src/containers/Dimensions/reducer.js
new file mode 100644
index 0000000000000000000000000000000000000000..bed3ed97a8625d4fc4fa175497a2aeca17a25f64
--- /dev/null
+++ b/src/containers/Dimensions/reducer.js
@@ -0,0 +1,136 @@
+import {
+ LOAD_HIT,
+ LOAD_HIT_SUCCESS,
+ LOAD_HIT_ERROR,
+ CREATE_HIT,
+ CREATE_HIT_SUCCESS,
+ CREATE_HIT_ERROR,
+ DECIDE_HIT,
+ DECIDE_HIT_SUCCESS,
+ DECIDE_HIT_ERROR,
+} from './constants';
+
+const initState = {
+ hit: {
+ id: '',
+ status: '',
+ loading: false,
+ error: false,
+ boxBuildingList: [],
+ create: {
+ loading: false,
+ error: false,
+ },
+ approval: {
+ loading: false,
+ error: false,
+ },
+ },
+};
+
+export default function (state = initState, action) {
+ switch (action.type) {
+ case LOAD_HIT:
+ return {
+ hit: {
+ ...state.hit,
+ status: '',
+ loading: true,
+ error: false,
+ },
+ };
+
+ case LOAD_HIT_SUCCESS:
+ return {
+ hit: {
+ ...state.hit,
+ status: action.payload.data.status,
+ boxBuildingList: action.payload.data.box_building_list,
+ loading: false,
+ error: false,
+ },
+ };
+
+ case LOAD_HIT_ERROR:
+ return {
+ hit: {
+ ...state.hit,
+ loading: false,
+ error: action.error,
+ },
+ };
+
+ case CREATE_HIT:
+ return {
+ hit: {
+ ...state.hit,
+ create: {
+ loading: true,
+ error: false,
+ },
+ },
+ };
+
+ case CREATE_HIT_SUCCESS:
+ return {
+ hit: {
+ id: action.payload.data.hit_id,
+ status: action.payload.data.status,
+ loading: false,
+ error: false,
+ create: {
+ loading: false,
+ error: false,
+ },
+ },
+ };
+
+ case CREATE_HIT_ERROR:
+ return {
+ hit: {
+ ...state.hit,
+ create: {
+ loading: false,
+ error: action.error,
+ },
+ },
+ };
+
+ case DECIDE_HIT:
+ return {
+ hit: {
+ ...state.hit,
+ approval: {
+ loading: true,
+ error: false,
+ },
+ },
+ };
+
+ case DECIDE_HIT_SUCCESS:
+ return {
+ hit: {
+ ...state.hit,
+ status: action.payload.data.hit_status,
+ approval: {
+ loading: false,
+ error: false,
+ },
+ },
+ };
+
+ case DECIDE_HIT_ERROR:
+ return {
+ hit: {
+ ...state.hit,
+ approval: {
+ loading: false,
+ error: action.error,
+ },
+ },
+ };
+
+ default:
+ return state;
+ }
+}
diff --git a/src/containers/Dimensions/sagas.js b/src/containers/Dimensions/sagas.js
new file mode 100644
index 0000000000000000000000000000000000000000..ee04cd3c617ac50c669a23137fb3b4f7da5fe34d
--- /dev/null
+++ b/src/containers/Dimensions/sagas.js
@@ -0,0 +1,88 @@
+import { call, put, takeEvery } from 'redux-saga/effects';
+import request from '../../utils/request';
+import { getHeaders, turkURL } from '../../utils/rest_services';
+
+import {
+ LOAD_HIT,
+ CREATE_HIT,
+ DECIDE_HIT,
+} from './constants';
+
+import {
+ hitLoaded,
+ hitLoadingError,
+ createHitSuccess,
+ createHitError,
+ hitDecisionSuccess,
+ hitDecisionError,
+} from './actions';
+
+/**
+ * Load Mechanical Turk HIT request/response handler
+ *
+ * @param {object} action Payload attribute with buildingId
+ */
+function* loadHit(action) {
+ const buildingId = action.payload;
+ const data = yield call(request, `${turkURL}${buildingId}`, {
+ method: 'GET',
+ headers: getHeaders(),
+ });
+
+ if (!data.err) {
+ yield put(hitLoaded(data));
+ } else {
+ yield put(hitLoadingError(data.err));
+ }
+}
+
+/**
+ * Mechanical Turk HIT creation request/response handler
+ *
+ * @param {object} action Form data of mechanical turk job
+ */
+function* createHit(action) {
+ const turkHitFormData = action.payload;
+ const data = yield call(request, turkURL, {
+ method: 'POST',
+ headers: getHeaders(),
+ body: JSON.stringify(turkHitFormData),
+ });
+
+ if (!data.err) {
+ yield put(createHitSuccess(data));
+ } else {
+ yield put(createHitError(data.err));
+ }
+}
+
+/**
+ * Approve or reject HIT request/response handler
+ *
+ * @param {number} action 1 or 0 representing approve or reject
+ */
+function* approveHit(action) {
+ const data = yield call(request, `${turkURL}${action.buildingId}`, {
+ method: 'PUT',
+ headers: getHeaders(),
+ body: JSON.stringify({ accept: action.decision }),
+ });
+
+ if (!data.err) {
+ yield put(hitDecisionSuccess(data));
+ } else {
+ yield put(hitDecisionError(data.err));
+ }
+}
+
+/**
+ * Watches for LOAD_BUILDING_DETAIL & CREATE_HIT actions and calls
+ * the appropriate handler function.
+ */
+function* dimensionsWatcher() {
+ yield takeEvery(LOAD_HIT, loadHit);
+ yield takeEvery(CREATE_HIT, createHit);
+ yield takeEvery(DECIDE_HIT, approveHit);
+}
+
+export default dimensionsWatcher;
diff --git a/src/containers/Dimensions/styles.css b/src/containers/Dimensions/styles.css
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/reducers.js b/src/reducers.js
index 248796275a16072b312dcd8cf15073b220110e3c..6870601e215350285ac1fffc1c76a57a40dedfab 100644
--- a/src/reducers.js
+++ b/src/reducers.js
@@ -4,10 +4,12 @@ import { routerReducer } from 'react-router-redux';
import SearchBarReducer from './containers/SearchBar/reducer';
import BuildingOverviewReducer from './containers/BuildingOverview/reducer';
import GoogleLoginReducer from './containers/GoogleLogin/reducer';
+import DimensionsReducer from './containers/Dimensions/reducer';
export default combineReducers({
routing: routerReducer,
buildingList: SearchBarReducer,
buildingDetail: BuildingOverviewReducer,
googleLogin: GoogleLoginReducer,
+ dimensions: DimensionsReducer,
});
diff --git a/src/routes.js b/src/routes.js
index c64dc2a6222300e7819750bba89ad3e9e19d5082..4410848dac39d82c76bac89c313ba151331feb88 100644
--- a/src/routes.js
+++ b/src/routes.js
@@ -8,6 +8,7 @@ import NotFound from './screens/NotFound';
import HomePage from './screens/HomePage';
import BuildingDetail from './screens/BuildingDetail';
import BuildingOverview from './containers/BuildingOverview';
+import Dimensions from './containers/Dimensions';
import Utilities from './components/Utilities';
import Dummy from './components/dummyComponent';
@@ -21,7 +22,7 @@ export default (
-
+
diff --git a/src/sagas.js b/src/sagas.js
index 09714c28f5379d808a6964ddd7c9f85c5a863d00..1f35dcd14a543fdd3d029faa7f3065980c09c2a0 100644
--- a/src/sagas.js
+++ b/src/sagas.js
@@ -1,7 +1,9 @@
import buildingOverviewSaga from './containers/BuildingOverview/sagas';
+import dimensionsSaga from './containers/Dimensions/sagas';
export default function* rootSaga() {
yield [
buildingOverviewSaga(),
+ dimensionsSaga(),
];
}