Skip to content

Commit

Permalink
feat(sessions): add expected emotions capturing feature ✨
Browse files Browse the repository at this point in the history
  • Loading branch information
brionmario committed Apr 17, 2019
1 parent 838d475 commit 3d0e2ef
Show file tree
Hide file tree
Showing 10 changed files with 352 additions and 137 deletions.
2 changes: 1 addition & 1 deletion src/forms/sessions/create-questionnaire/submit.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import _ from 'lodash';
import validate from './validate';
import store from '../../../redux/store';
import {addNotification} from '../../../redux/actions/notification-actions';
import {createQuestionnaire} from '../../../redux/actions/questionnaire-actions';
import {createQuestionnaire} from '../../../redux/actions/session-actions';

function submit(values, dispatch, props) {
// dirty trick to get around the redux form validation issue.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ import _ from 'lodash';
import {
ADD_QUESTIONNAIRE,
FETCH_QUESTIONNAIRES,
SET_QUESTIONNAIRE_VIEW_CONFIG,
SET_SESSION_VIEW_CONFIG,
SET_SELECTED_QUESTIONNAIRE,
UPDATE_QUESTIONNAIRE
UPDATE_QUESTIONNAIRE,
SET_EXPECTED_EMOTIONS
} from '../types';
import {API_ENDPOINTS} from '../../api';
import {HttpInterceptor} from '../../services';
Expand Down Expand Up @@ -65,7 +66,14 @@ export const setSelectedQuestionnaire = data => (dispatch) => {
});
};

export const setQuestionnaireViewConfig = data => dispatch => dispatch({
type: SET_QUESTIONNAIRE_VIEW_CONFIG,
export const setExpectedEmotions = data => (dispatch) => {
return dispatch({
type: SET_EXPECTED_EMOTIONS,
payload: data,
});
};

export const setSessionViewConfig = data => dispatch => dispatch({
type: SET_SESSION_VIEW_CONFIG,
payload: data,
});
4 changes: 2 additions & 2 deletions src/redux/reducers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { loaderReducer } from './loader-reducer';
import { notificationReducer } from './notification-reducer';
import { userReducer } from './user-reducer';
import { applicationReducer } from './application-reducer';
import { questionnaireReducer } from './questionnaire-reducer';
import { sessionReducer } from './session-reducer';

const appReducer = combineReducers({
form: reduxFormReducer,
Expand All @@ -18,7 +18,7 @@ const appReducer = combineReducers({
notifications: notificationReducer,
users: userReducer,
applications: applicationReducer,
questionnaires: questionnaireReducer,
sessions: sessionReducer,
});

const rootReducer = (state, action) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,22 @@ import _ from 'lodash';
import {
ADD_QUESTIONNAIRE,
FETCH_QUESTIONNAIRES,
SET_QUESTIONNAIRE_VIEW_CONFIG,
SET_SESSION_VIEW_CONFIG,
SET_SELECTED_QUESTIONNAIRE,
UPDATE_QUESTIONNAIRE
UPDATE_QUESTIONNAIRE,
SET_EXPECTED_EMOTIONS
} from '../types';

const initialState = {
questionnaires: [],
newQuestionnaire: {},
selectedQuestionnaire: {},
editedQuestionnaire: {},
questionnaireViewConfig: {}
sessionViewConfig: {},
expectedEmotions: []
};

export function questionnaireReducer(state = initialState, action) {
export function sessionReducer(state = initialState, action) {
switch (action.type) {
case FETCH_QUESTIONNAIRES:
return {
Expand All @@ -39,10 +41,15 @@ export function questionnaireReducer(state = initialState, action) {
...state,
selectedQuestionnaire: action.payload,
};
case SET_QUESTIONNAIRE_VIEW_CONFIG:
case SET_EXPECTED_EMOTIONS:
return {
...state,
questionnaireViewConfig: action.payload,
expectedEmotions: action.payload,
};
case SET_SESSION_VIEW_CONFIG:
return {
...state,
sessionViewConfig: action.payload,
};
default:
return state;
Expand Down
5 changes: 3 additions & 2 deletions src/redux/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,11 @@ export const SET_SELECTED_APPLICATION = 'SET_SELECTED_APPLICATION';
export const SET_APPLICATION_VIEW_CONFIG = 'SET_APPLICATION_VIEW_CONFIG';
export const UPDATE_APPLICATION_SHARING_STATUS = 'UPDATE_APPLICATION_SHARING_STATUS';

// Questionnaires
// Sessions
export const SET_SESSION_VIEW_CONFIG = 'SET_SESSION_VIEW_CONFIG';
export const FETCH_QUESTIONNAIRES = 'FETCH_QUESTIONNAIRES';
export const ADD_QUESTIONNAIRE = 'ADD_QUESTIONNAIRE';
export const UPDATE_QUESTIONNAIRE = 'UPDATE_QUESTIONNAIRE';
export const SET_SELECTED_QUESTIONNAIRE = 'SET_SELECTED_QUESTIONNAIRE';
export const SET_QUESTIONNAIRE_VIEW_CONFIG = 'SET_QUESTIONNAIRE_VIEW_CONFIG';
export const SET_EXPECTED_EMOTIONS = 'SET_EXPECTED_EMOTIONS';

6 changes: 5 additions & 1 deletion src/routes/dashboard.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import {
DashboardView,
ApplicationsView,
NewSessionView,
QuestionnaireView
QuestionnaireView,
EmotionsView
} from '../views';
import testIcon from '../assets/img/icons/test.svg';
import dashboardIcon from '../assets/img/icons/dashboard.svg';
Expand All @@ -21,6 +22,9 @@ const dashboard = [
{
path: '/questionnaire', hide: true, name: 'Questionnaire', icon: testIcon, component: QuestionnaireView, restrictionLevel: 0,
},
{
path: '/emotions', hide: true, name: 'Expected Emotions', icon: testIcon, component: EmotionsView, restrictionLevel: 0,
},
{
redirect: true, path: '/', pathTo: '/dashboard', name: 'Dashboard', restrictionLevel: 0,
},
Expand Down
193 changes: 193 additions & 0 deletions src/views/sessions/emotions.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
import React, {Component} from 'react';
import _ from 'lodash';
import PropTypes from 'prop-types';
import {
Grid,
Row,
Col,
} from 'react-bootstrap';
import {bindActionCreators} from 'redux';
import {connect} from 'react-redux';
import 'react-sliding-pane/dist/react-sliding-pane.css';
import * as applicationActionCreators from '../../redux/actions/application-actions';
import * as sessionActionCreators from '../../redux/actions/session-actions';
import {CustomButton as Button} from '../../elements';
import happinessIcon from '../../assets/img/emotions/happiness.svg';
import sadnessIcon from '../../assets/img/emotions/sadness.svg';
import neutralIcon from '../../assets/img/emotions/neutral.svg';
import disgustIcon from '../../assets/img/emotions/disgust.svg';
import surpriseIcon from '../../assets/img/emotions/surprise.svg';
import fearIcon from '../../assets/img/emotions/fear.svg';
import angerIcon from '../../assets/img/emotions/anger.svg';

class Emotions extends Component {

constructor(props) {
super(props);
this.state = {
emotions: [
{
displayName: 'Happiness',
name: 'happiness',
icon: happinessIcon,
selected: false
},
{
displayName: 'Neutral',
name: 'neutral',
icon: neutralIcon,
selected: false
},
{
displayName: 'Sadness',
name: 'sadness',
icon: sadnessIcon,
selected: false
},
{
displayName: 'Anger',
name: 'anger',
icon: angerIcon,
selected: false
},
{
displayName: 'Disgust',
name: 'disgust',
icon: disgustIcon,
selected: false
},
{
displayName: 'Fear',
name: 'fear',
icon: fearIcon,
selected: false
},
{
displayName: 'Surprise',
name: 'surprise',
icon: surpriseIcon,
selected: false
}
],
selectedEmotions: []
};
}

handleEmotionSelect = (emotion) => {
const {emotions, selectedEmotions} = this.state;
// clone object to avoid mutating
const _emotion = _.cloneDeep(emotion);
_emotion.selected = !_emotion.selected;

// clone array to avoid mutations
const _emotions = _.cloneDeep(emotions);

// Find index and replace item
const index = _.findIndex(_emotions, emotion);
_emotions.splice(index, 1, _emotion);

this.setState({emotions: _emotions});

const _selectedEmotions = _.cloneDeep(selectedEmotions);

if (_emotion.selected) {
_selectedEmotions.push(_emotion.name);
} else {
const index_selected = _.findIndex(_selectedEmotions, _emotion.name);
_selectedEmotions.splice(index_selected, 1, _emotion.name);
}

this.setState({selectedEmotions: _selectedEmotions});
};

handleEmotionSubmit = () => {
const { actions } = this.props;
const { selectedEmotions } = this.state;
actions.sessions.setExpectedEmotions(selectedEmotions);
};

render() {
const {
emotions, selectedEmotions
} = this.state;

return (
<div className="main-content no-padding session-page">
<Grid fluid>
<Row>
<div className="sub-header">
<h5 className="text-white ml-3">Application</h5>
</div>
</Row>
<div className="main-session-content with-top-padding">
<Row>
<Col md={6} mdOffset={3}>
<div className="content-description text-center mb-4">
<h2>Expected Emotions</h2>
<h5 className="text-muted font-weight-light">
Expected emotions may vary from application to application. In order for the system to provide an
accurate Cybersickness score, Please select the expected emotions from bellow.
</h5>
</div>
</Col>
</Row>
<Row>
<div className="grid-card-flex-container">
{
emotions.map(emotion => (
<div className={'grid-card sm mr-2 ml-2 ' + (emotion.selected ? 'selected' : '')}
onClick={() => this.handleEmotionSelect(emotion)}>
<div className="grid-card-thumbnail-container">
<div className="grid-card-thumbnail bg-white mb-1 pt-3 pr-3 pl-3 pb-1">
<img src={emotion.icon} width={80} height={80}/>
</div>
</div>
<div className="grid-card-content-container text-center mb-1">
<div className="grid-card-heading">{emotion.displayName}</div>
</div>
</div>
))
}
</div>
</Row>
</div>
<Row>
<Col md={12}>
<div className="text-center mt-2">
<Button type="submit" bsStyle="primary" disabled={selectedEmotions.length < 1} bsSize="sm" wd fill onClick={this.handleEmotionSubmit}>
Select
</Button>
</div>
</Col>
</Row>
</Grid>
</div>
);
}
}

const injectedPropTypes = {
actions: PropTypes.shape({}),
};

Emotions.propTypes = {
...injectedPropTypes,
};

function mapStateToProps(state) {
return {
selectedApplication: state.applications.selectedApplication,
viewConfig: state.sessions.sessionViewConfig,
};
}

function mapDispatchToProps(dispatch) {
return {
actions: {
sessions: bindActionCreators(sessionActionCreators, dispatch),
applications: bindActionCreators(applicationActionCreators, dispatch),
},
};
}

export default connect(mapStateToProps, mapDispatchToProps)(Emotions);
1 change: 1 addition & 0 deletions src/views/sessions/index.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export { default as NewSessionView } from './new-session';
export { default as QuestionnaireView } from './questionnaire';
export { default as EmotionsView } from './emotions';
Loading

0 comments on commit 3d0e2ef

Please sign in to comment.