Skip to content

Commit

Permalink
Chore/program indicator refactor (#492)
Browse files Browse the repository at this point in the history
* push to fix tests

* added rc files

* push to test

* Fixed the tests

* fix typo

* moved arrow stepper to its own file

* refactored selectors to start with get according to convention, moved arrow stepper to its own file, moved step actions to stepper

* fixed merge conflicts
  • Loading branch information
John Melin authored Jun 11, 2018
1 parent b8247a6 commit 174af5b
Show file tree
Hide file tree
Showing 55 changed files with 3,656 additions and 2,191 deletions.
12 changes: 5 additions & 7 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -1,21 +1,19 @@
{
"presets": [
[
"es2015",
{
"modules": false
}
],
["env", { "modules": false }],
"react",
"stage-0"
],
"env": {
"test": {
"presets": ["es2015", "react", "stage-0"],
"presets": ["env", "react", "stage-0"],
"only": [
"src/*.js",
"src/**/*.js",
"config/*.js"
],
"plugins": [
"babel-plugin-dynamic-import-node"
]
}
}
Expand Down
4 changes: 4 additions & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
"browser": true,
"jest": true
},
"rules": {
"no-param-reassign": [2, { "props": false }],
"import/no-extraneous-dependencies": 0
},
"parser": "babel-eslint",
"parserOptions": {
"ecmaFeatures": {
Expand Down
51 changes: 27 additions & 24 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,17 @@
"profile": "yarn start -- --profile"
},
"devDependencies": {
"babel": "^6.5.2",
"babel-core": "^6.13.2",
"babel-eslint": "^8.0.1",
"babel-loader": "^7.0.0",
"babel": "^6.23.0",
"babel-jest": "^23.0.1",
"babel-core": "^6.26.3",
"babel-eslint": "^8.2.3",
"babel-loader": "latest",
"babel-plugin-dynamic-import-node": "^1.2.0",
"babel-plugin-transform-runtime": "^6.12.0",
"babel-polyfill": "^6.26.0",
"babel-preset-env": "^1.7.0",
"babel-preset-es2015": "^6.13.2",
"babel-preset-react": "^6.11.1",
"babel-preset-react": "^6.24.1",
"babel-preset-stage-0": "^6.5.0",
"classnames": "^2.2.3",
"css-loader": "^0.28.1",
Expand All @@ -39,34 +43,24 @@
"d3-color": "^1.0.2",
"d3-format": "^1.0.2",
"d3-scale": "^1.0.3",
"enzyme": "^3.0.0",
"enzyme-adapter-react-15": "^1.0.0",
"eslint-config-dhis2": "3.0.7",
"fbjs": "^0.8.8",
"glob": "^7.1.1",
"html-webpack-plugin": "^2.26.0",
"ignore-styles": "^5.0.1",
"jest": "^23.0.1",
"jest-enzyme": "^4.0.0",
"json-loader": "^0.5.4",
"lodash.isfinite": "^3.3.1",
"lodash.isnumber": "^3.0.3",
"loglevel": "^1.4.0",
"material-ui": "^0.17.0",
"moment": "^2.16.0",
"node-fetch": "^1.6.3",
"node-pre-gyp": "^0.6.30",
"node-sass": "4.9.0",
"precommit-hook": "^3.0.0",
"react": "^15.3.1",
"react-addons-create-fragment": "^15.5.4",
"react-addons-css-transition-group": "^15.3.1",
"react-addons-linked-state-mixin": "^15.3.1",
"react-addons-perf": "^15.3.1",
"react-addons-shallow-compare": "^15.3.1",
"react-addons-test-utils": "^15.3.1",
"react-color": "^2.11.7",
"react-dnd": "^2.4.0",
"react-dnd-html5-backend": "^2.4.1",
"react-dom": "^15.3.1",
"react-router": "^3.0.0",
"react-tap-event-plugin": "^2.0.1",
"recompose": "^0.23.1",
"redux-logger": "^3.0.6",
"sass-loader": "^6.0.5",
Expand All @@ -77,19 +71,28 @@
"webpack-visualizer-plugin": "^0.1.5"
},
"dependencies": {
"babel-polyfill": "^6.13.0",
"d2": "^29.1.3",
"d2-ui": "29.0.11",
"enzyme": "^3.0.0",
"enzyme-adapter-react-15": "^1.0.0",
"jest": "^21.2.1",
"jest-enzyme": "^4.0.0",
"material-ui": "^0.17.0",
"nyc": "10.1.2",
"prop-types": "^15.6.0",
"react": "^15.3.1",
"react-addons-create-fragment": "^15.5.4",
"react-addons-css-transition-group": "^15.3.1",
"react-addons-linked-state-mixin": "^15.3.1",
"react-addons-perf": "^15.3.1",
"react-addons-shallow-compare": "^15.3.1",
"react-addons-test-utils": "^15.3.1",
"react-color": "^2.11.7",
"react-dnd": "^2.4.0",
"react-dnd-html5-backend": "^2.4.1",
"react-dom": "^15.3.1",
"react-loadable": "^5.4.0",
"react-redux": "^5.0.3",
"react-router": "^3.0.0",
"react-sortable-hoc": "^0.6.1",
"react-speed-dial": "^0.4.7",
"react-tap-event-plugin": "^2.0.1",
"react-test-renderer": "15",
"redux": "^3.6.0",
"redux-observable": "0.18.0",
Expand Down
41 changes: 15 additions & 26 deletions src/EditModel/EditModelForm.component.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { Observable } from 'rxjs';
import { getInstance } from 'd2/lib/d2';
import { isString } from 'd2-utilizr';

import { Step, Stepper, StepButton } from 'material-ui/Stepper';
import CircularProgress from 'd2-ui/lib/circular-progress/CircularProgress';
import Translate from 'd2-ui/lib/i18n/Translate.mixin';
import FormBuilder from 'd2-ui/lib/forms/FormBuilder.component';
Expand All @@ -27,6 +26,7 @@ import snackActions from '../Snackbar/snack.actions';
import appState from '../App/appStateStore';
import { createFieldConfigForModelTypes, addUniqueValidatorWhenUnique } from './formHelpers';
import { applyRulesToFieldConfigs, getRulesForModelType } from './form-rules';
import { getStepFields, createStepper } from './stepper/stepper';
import getFirstInvalidFieldMessage from './form-helpers/validateFields';

const currentSection$ = appState
Expand Down Expand Up @@ -162,16 +162,12 @@ export default React.createClass({
renderStepper() {
const steps = fieldGroups.for(this.props.modelType);
const stepCount = steps.length;

return stepCount > 1 ? (
<Stepper activeStep={this.state.activeStep} linear={false} style={{ margin: '0 -16px' }}>
{steps.map((step, s) => (
<Step key={s}>
<StepButton onClick={() => this.setActiveStep(s)}>{this.getTranslation(step.label)}</StepButton>
</Step>
))}
</Stepper>
) : null;
return stepCount > 1 &&
createStepper({
steps,
activeStep: this.state.activeStep,
stepperClicked: this.setActiveStep,
});
},

renderForm() {
Expand Down Expand Up @@ -214,7 +210,6 @@ export default React.createClass({
if (this.state.loading) {
return (<div>Loading data....</div>);
}

return this.renderForm();
},

Expand All @@ -224,20 +219,14 @@ export default React.createClass({
* an outer div that receives the props.style.
*/
setActiveStep(step) {
const stepsByField = fieldGroups.groupsByField(this.props.modelType);
if (stepsByField) {
this.setState({
activeStep: step,
fieldConfigs: this.state.fieldConfigs.map((field) => {
if (stepsByField[field.name] === step) {
field.props.style = { display: 'block' };
} else {
field.props.style = { display: 'none' };
}
return field;
}),
});
}
this.setState({
activeStep: step,
fieldConfigs: getStepFields(
step,
this.state.fieldConfigs,
this.props.modelType,
),
});
},

setFormRef(form) {
Expand Down
19 changes: 17 additions & 2 deletions src/EditModel/FormActionButtons.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import React from 'react';
import PropTypes from 'prop-types';

import { connect } from 'react-redux';
import withProps from 'recompose/withProps';
import { compose } from 'lodash/fp';

import SaveButton from './SaveButton.component';
import CancelButton from './CancelButton.component';

import { goToAndScrollUp } from '../router-utils';
import eventProgramStore from './event-program/eventProgramStore';

const styles = {
cancelButton: {
Expand All @@ -22,7 +25,7 @@ export default function FormActionButtons({ onSaveAction, onCancelAction, isDirt
);
}

export function createConnectedFormActionButtonsForSchema(mapDispatchToProps, mapStateToProps = null) {
export function createConnectedFormActionButtonsForSchema(mapDispatchToProps = null, mapStateToProps = null) {
const onCancelActionCreator = (groupName, schema) => () => goToAndScrollUp(`/list/${groupName}/${schema}`);

const enhance = compose(
Expand All @@ -34,3 +37,15 @@ export function createConnectedFormActionButtonsForSchema(mapDispatchToProps, ma

return enhance(FormActionButtons);
}

FormActionButtons.propTypes = {
onSaveAction: PropTypes.func.isRequired,
onCancelAction: PropTypes.func.isRequired,
isDirtyHandler: PropTypes.func,
isSaving: PropTypes.bool,
};

FormActionButtons.defaultProps = {
isDirtyHandler: () => {},
isSaving: false,
};
4 changes: 1 addition & 3 deletions src/EditModel/actions.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
export const createActionCreator = type => payload => ({ type, payload });

// SnackBar
export const NOTIFY_USER = 'NOTIFY_USER';
export const notifyUser = createActionCreator(NOTIFY_USER);

export const STEPPER_RESET_ACTIVE_STEP = 'STEPPER_RESET_ACTIVE_STEP';
export const resetActiveStep = createActionCreator(STEPPER_RESET_ACTIVE_STEP);
57 changes: 40 additions & 17 deletions src/EditModel/epicHelpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,25 +46,48 @@ export function createModelToEditEpic(actionType, store, storeProp) {
.ofType(actionType)
.map(action => action.payload)
.flatMap(({ field, value }) => store
.take(1)
.map(storePropGetter)
.map((model) => {
// Apply the new value to the model
if (isAttributeValue(model, field)) {
updateAttributeValue(model, field, value);
} else {
updateRegularValue(model, field, value);
}
.take(1)
.map(storePropGetter)
.map((model) => {
// Apply the new value to the model
if (isAttributeValue(model, field)) {
updateAttributeValue(model, field, value);
} else {
updateRegularValue(model, field, value);
}

// Write back the state to the store
store.setState(
storePropSetter(model, { ...store.getState() })
);
})
// Write back the state to the store
store.setState(
storePropSetter(model, { ...store.getState() }),
);
}),
)
.flatMapTo(emptyAction$);
}

export function addChangedFieldValueToModel({ field, value }, store, storeProp) {
const storePropGetter = get(storeProp);
const storePropSetter = set(storeProp);

return store
.take(1)
.map(storePropGetter)
.map((model) => {
// Apply the new value to the model
if (isAttributeValue(model, field)) {
updateAttributeValue(model, field, value);
} else {
updateRegularValue(model, field, value);
}

// Write back the state to the store
store.setState(
storePropSetter(model, { ...store.getState() }),
);
return model;
});
}

export function createModelToEditProgramStageEpic(actionType, store, storeProp) {
const storePropGetter = get(storeProp);

Expand All @@ -87,15 +110,15 @@ export function createModelToEditProgramStageEpic(actionType, store, storeProp)
and we therefore copy the name to displayName to show in lists etc. This does not get sent
to the server, and upon reloading the model, the server-defined displayName will be shown */

if(field === 'name') {
if (field === 'name') {
updateRegularValue(model, 'displayName', value);
}
}
// Write back the state to the store
store.setState(
storePropSetter(model, store.getState() )
storePropSetter(model, store.getState()),
);
})
}),
)
.flatMapTo(emptyAction$);
}
7 changes: 4 additions & 3 deletions src/EditModel/event-program/__tests__/actions.spec.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as actions from '../actions';
import { NOTIFY_USER, notifyUser } from '../../actions';

describe('Event Program actions', () => {
describe('for stepper', () => {
Expand Down Expand Up @@ -107,16 +108,16 @@ describe('Event Program actions', () => {

describe('for notifying users', () => {
test('should defined the notification constants', () => {
expect(actions.NOTIFY_USER).toBe('NOTIFY_USER');
expect(NOTIFY_USER).toBe('NOTIFY_USER');
});

test('should create a notify user action when calling notifyUser', () => {
const expectedAction = {
type: actions.NOTIFY_USER,
type: NOTIFY_USER,
payload: undefined,
};

expect(actions.notifyUser()).toEqual(expectedAction);
expect(notifyUser()).toEqual(expectedAction);
});
});
});
Loading

0 comments on commit 174af5b

Please sign in to comment.