Skip to content

Commit

Permalink
validation
Browse files Browse the repository at this point in the history
  • Loading branch information
trap-ck committed Mar 24, 2017
1 parent 43e1021 commit b28fcb2
Show file tree
Hide file tree
Showing 21 changed files with 240 additions and 45 deletions.
5 changes: 4 additions & 1 deletion other/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,10 @@ const coreValidator = {
return length >= min && length <= max;
},
validatePositiveNumber(value) {
return (value || 0) > 0;
return Number(value) && value > 0;
},
validateNotNegativeNumber(value) {
return Number(value) && value >= 0;
},
validateRequiredLookup(value = {}) {
return value && value.value;
Expand Down
2 changes: 1 addition & 1 deletion server/db.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"user":[{"id":"a8b10cfc-c418-4141-b28e-b5f31e18a660","name":"Denis","nickName":"trap-ck"},{"id":"187a85fe-4197-40c3-9e9c-9f238816dbc4","name":"Inna","nickName":"emma"},{"id":"889baa49-4ed7-4366-9f45-7ad339f37422","name":"Alisa","nickName":"Lisa"}],"expenseCategory":[{"id":"38a3664a-c82d-4d11-a9a9-5e83742b9efa","title":"General","isNotVisibleInList":false},{"id":"ab6edd80-06b9-4b5c-b431-0f24020f3333","title":"Special","isNotVisibleInList":false}],"expense":[{"id":"3d4371a1-58da-4b77-847f-6216cbf3a86c","title":"112233","category":"38a3664a-c82d-4d11-a9a9-5e83742b9efa","amount":12,"date":"2017-02-28T22:00:00.000Z","author":"187a85fe-4197-40c3-9e9c-9f238816dbc4","description":""},{"id":"4c7c9ab4-6fa0-492d-85d7-0ac44444d1f7","title":"Fuel","category":"ab6edd80-06b9-4b5c-b431-0f24020f3333","amount":1000,"date":"2017-03-11T22:00:00.000Z","author":"a8b10cfc-c418-4141-b28e-b5f31e18a660","description":""},{"id":"78d1d5a1-17ee-4881-a6a8-818a3b0a0b45","title":"123","category":"38a3664a-c82d-4d11-a9a9-5e83742b9efa","amount":1,"date":"2017-03-22T22:00:00.000Z","author":"a8b10cfc-c418-4141-b28e-b5f31e18a660","description":""}],"monthExpenseLimit":[{"id":"b539e0b7-cdfb-4e45-8ef2-6679f5fba764","month":2,"year":2017,"income":36000,"limit":20000}]}
{"user":[{"id":"a8b10cfc-c418-4141-b28e-b5f31e18a660","name":"Denis","nickName":"trap-ck"},{"id":"187a85fe-4197-40c3-9e9c-9f238816dbc4","name":"Inna","nickName":"emma"},{"id":"889baa49-4ed7-4366-9f45-7ad339f37422","name":"Alisa","nickName":"Lisa"}],"expenseCategory":[{"id":"38a3664a-c82d-4d11-a9a9-5e83742b9efa","title":"Gen","isNotVisibleInList":false},{"id":"ab6edd80-06b9-4b5c-b431-0f24020f3333","title":"Special","isNotVisibleInList":false}],"expense":[{"id":"3d4371a1-58da-4b77-847f-6216cbf3a86c","title":"123","category":"38a3664a-c82d-4d11-a9a9-5e83742b9efa","amount":12,"date":"2017-03-23T22:00:00.000Z","author":"187a85fe-4197-40c3-9e9c-9f238816dbc4","description":"123"},{"id":"4c7c9ab4-6fa0-492d-85d7-0ac44444d1f7","title":"Fuel","category":"ab6edd80-06b9-4b5c-b431-0f24020f3333","amount":1000,"date":"2017-03-11T22:00:00.000Z","author":"a8b10cfc-c418-4141-b28e-b5f31e18a660","description":""}],"monthExpenseLimit":[{"id":"b539e0b7-cdfb-4e45-8ef2-6679f5fba764","month":2,"year":2017,"income":36000,"limit":20000}]}
1 change: 1 addition & 0 deletions src/components/budget-page/budget-main-date-filter.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const BudgetMainDateFilter = props => {
options = {months.data.map(m => {return {label: m.title, value: m.number};})}
onChange = {props.onMonthChange}
containerClassName = {"current-month-edit-container"}
isFocusCanceled
/>
<div className = {"current-year-edit-container"}>
<input
Expand Down
2 changes: 1 addition & 1 deletion src/components/budget-page/expense-categories-manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@ class ExpenseCategoriesManager extends React.Component {
render() {
return (
<div>
<ExpenseCategoriesList/>
<div>
<button onClick = {this.props.toggleNewExpenseCategoryVisible}>
{this.props.isNewExpenseCategoryVisible ? "-" : "+"}
</button>
{this.props.isNewExpenseCategoryVisible ? <NewExpenseCategory/> : null}
</div>
<ExpenseCategoriesList/>
</div>
);
}
Expand Down
4 changes: 3 additions & 1 deletion src/components/budget-page/expense-category.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, {PropTypes} from "react";
import {getTextValueByColumnType, getEditValueByColumnType} from "../../../other/utils";
import EditableValue from "../common/editable-value";
import validator from "../../helpers/form-validators/expense-category-validator";
import entityStructure from "../../static-data/entity-info/entity-sctructure";
import entityColumnTypes from "../../static-data/entity-info/entity-column-types";

Expand Down Expand Up @@ -38,7 +39,8 @@ class ExpenseCategory extends React.Component {
this.props.expenseCategory[key],
this.props.expenseCategory)
}
>
validator={validator}
>
{
getTextValueByColumnType(
"expenseCategory",
Expand Down
8 changes: 7 additions & 1 deletion src/components/budget-page/expenses-list.js
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,13 @@ const mapStateToProps = (state, ownProps) => {
expenses: state.budget.expenses.filter(e =>
e.category === ownProps.category &&
(ownProps.dateFilterValue ? getDateColumnEqualityComparisonResult(e.date, ownProps.dateFilterValue) : true)
),
)
.sort((a,b) => {
if (a.title > b.title) return 1;
else if (b.title > a.title) return -1;
else return 0;
})
.sort((a,b) => new Date(a.date).getTime() - new Date(b.date).getTime()),
isLoading: state.isLoading,
currentMonth: state.budget.ui.currentMonth.number,
currentYear: state.budget.ui.currentYear
Expand Down
3 changes: 3 additions & 0 deletions src/components/budget-page/month-expense-limit.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, {PropTypes} from "react";
import {getTextValueByColumnType, getEditValueByColumnType} from "../../../other/utils";
import EditableValue from "../common/editable-value";
import validator from "../../helpers/form-validators/expense-limit-validator";
import entityStructure from "../../static-data/entity-info/entity-sctructure";
import entityColumnTypes from "../../static-data/entity-info/entity-column-types";

Expand Down Expand Up @@ -36,6 +37,8 @@ class MonthExpenseLimit extends React.Component {
this.props.monthExpenseLimit[key],
this.props.monthExpenseLimit)
}
validator={validator}
entity={this.props.monthExpenseLimit}
>
{
getTextValueByColumnType(
Expand Down
1 change: 1 addition & 0 deletions src/components/budget-page/month-expense-limits-list.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ class MonthExpenseLimitsList extends React.Component {
<BooleanInput
value = {this.props.isShowCurrentMonthLimitOnly}
onChange = {this.onCurrentMonthOnlyChange}
isFocusCanceled
/>
</LabelCover>
<PreloaderContainer isLoading = {this.props.isLoading} isLoadingToken = {this.isLoadingToken}>
Expand Down
32 changes: 26 additions & 6 deletions src/components/budget-page/new-expense-category.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import * as actionCreators from "../../redux/actions/action-creators";
import InputByColumnType from "../common/input-by-column-type";
import PreloaderContainer from "../common/preloader-container";
import entityStructure from "../../static-data/entity-info/entity-sctructure";
import validator from "../../helpers/form-validators/expense-category-validator";
import guid from "uuid/v4";
import toastr from "toastr";

Expand All @@ -14,17 +15,32 @@ class NewExpenseCategory extends React.Component {
this.onChange = this.onChange.bind(this);
this.saveNewExpenseCategory = this.saveNewExpenseCategory.bind(this);
this.isLoadingToken = guid();
this.state = {
validationInfo: []
}
}

componentWillUnmount() {
this.props.removeIsLoading(this.isLoadingToken);
}

componentDidMount() {
this.refs.title.refs.title.refs.input.focus();
}

onChange(column, value, e) {
this.props.newExpenseCategoryChange(column, value, e);
}

saveNewExpenseCategory() {
const validationResult = validator.validate(this.props.newExpenseCategory);
if (validationResult.length) {
this.setState(Object.assign({}, this.state, {validationInfo: [...validationResult]}));
return;
}
if (this.state.validationInfo.length) {
this.setState(Object.assign({}, this.state, {validationInfo: []}));
}
this.props.addNewExpenseCategory(this.props.newExpenseCategory, this.isLoadingToken)
.then(() => toastr.success("New expense category added"));
}
Expand All @@ -41,13 +57,17 @@ class NewExpenseCategory extends React.Component {
.filter(c => !entityStructure.expenseCategory.columns[c].isSystem)
.map(
c => <InputByColumnType
key = {c}
entityName = "expenseCategory"
columnName = {c}
value = {this.props.newExpenseCategory[c]}
onChange = {this.onChange}
ref = {c}
key = {c}
entityName = "expenseCategory"
columnName = {c}
value = {this.props.newExpenseCategory[c]}
onChange = {this.onChange}
validationMessage = {
this.state.validationInfo.filter(i => i.name === c).map(i => i.message)[0] || ""
}
/>
)
)
}
</div>
</div>
Expand Down
5 changes: 5 additions & 0 deletions src/components/budget-page/new-expense.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ class NewExpense extends React.Component {
}
}

componentDidMount() {
this.refs.title.refs.title.refs.input.focus();
}

componentWillUnmount() {
this.props.removeIsLoading(this.isLoadingToken);
}
Expand Down Expand Up @@ -53,6 +57,7 @@ class NewExpense extends React.Component {
.filter(c => !entityStructure.expense.columns[c].isSystem)
.map(
c => <InputByColumnType
ref = {c}
key = {c}
entityName = "expense"
columnName = {c}
Expand Down
10 changes: 9 additions & 1 deletion src/components/common/boolean-input.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ class BooleanInput extends React.Component {
this.onChange = this.onChange.bind(this);
}

componentDidMount() {
if (!this.props.isFocusCanceled) {
this.refs.input.focus();
}
}

onChange(e) {
this.props.onChange(this.props.tag, e.target.checked, e);
}
Expand All @@ -14,6 +20,7 @@ class BooleanInput extends React.Component {
return (
<div className={this.props.containerClassName}>
<input
ref="input"
className = {this.props.inputClassName}
type = "checkbox"
checked = {!!this.props.value}
Expand All @@ -29,7 +36,8 @@ BooleanInput.propTypes = {
value: PropTypes.bool,
containerClassName: PropTypes.string,
inputClassName: PropTypes.string,
tag: PropTypes.string
tag: PropTypes.string,
isFocusCanceled: PropTypes.bool
};

BooleanInput.defaultProps = {
Expand Down
15 changes: 15 additions & 0 deletions src/components/common/date-input.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,32 @@ class DateInput extends React.Component {
constructor(props) {
super(props);
this.onChange = this.onChange.bind(this);
this.onKeyPress = this.onKeyPress.bind(this);
}

componentDidMount() {
this.refs.input.focus();
}

onChange(dateString, {dateMoment}) {
this.props.onChange(this.props.tag, new Date(dateMoment._d));
}

onKeyPress(e) {
if(e.key == "Enter"){
e.preventDefault();
e.stopPropagation();
this.refs.input.getInput().blur();
}
}

render() {
return (<DateField
forceValidDate
ref="input"
onChange={this.onChange}
onBlur={this.onBlur}
onKeyPress={this.onKeyPress}
value={this.props.value}
updateOnDateClick
expandOnFocus={false}
Expand Down
75 changes: 52 additions & 23 deletions src/components/common/dropdown-input.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,57 @@ import React, {PropTypes} from "react";
import {SimpleSelect} from "react-selectize";
import "react-selectize/themes/index.css";

const DropDownInput = props => {
const onChange = (item = {}) => {
props.onChange(props.tag, {label: item.label, value: item.value, isDropDown: true}, item);
},
onBlur = (item = {}) => {
class DropDownInput extends React.Component {
constructor(props) {
super(props);
this.onChange = this.onChange.bind(this);
this.onBlur = this.onBlur.bind(this);
this.onOpenChange = this.onOpenChange.bind(this);
this.onKeyPress = this.onKeyPress.bind(this);
}

componentDidMount() {
if (!this.props.isFocusCanceled) {
this.refs.input.refs.select.focusOnInput();
}
this.refs.input.refs.select.refs.control.addEventListener("keypress", this.onKeyPress);
}

onChange(item = {}) {
this.props.onChange(this.props.tag, {label: item.label, value: item.value, isDropDown: true}, item);
}
onBlur(item = {}) {
item.value = item.value || {};
props.onBlur(props.tag, {label: item.value.label, value: item.value.value, isDropDown: true}, item);
},
onOpenChange = isOpened => {props.onOpenChange(isOpened);};
return (
<div className = {props.containerClassName}>
<SimpleSelect
className = {props.inputClassName}
value = {props.value}
onValueChange = {onChange}
onBlur = {onBlur}
onOpenChange = {onOpenChange}
options = {props.options}
placeholder = {props.placeholder}
/>
</div>
);
};
this.props.onBlur(this.props.tag, {label: item.value.label, value: item.value.value, isDropDown: true}, item);
}

onOpenChange(isOpened) {
this.props.onOpenChange(isOpened);
}

onKeyPress(e) {
if(e.key == "Enter"){
this.refs.input.blur();
}
}

render() {
return (
<div className={this.props.containerClassName}>
<SimpleSelect
ref="input"
className={this.props.inputClassName}
value={this.props.value}
onValueChange={this.onChange}
onBlur={this.onBlur}
onOpenChange={this.onOpenChange}
options={this.props.options}
placeholder={this.props.placeholder}
/>
</div>
);
}
}


DropDownInput.propTypes = {
Expand All @@ -37,7 +65,8 @@ DropDownInput.propTypes = {
containerClassName: PropTypes.string,
inputClassName: PropTypes.string,
tag: PropTypes.string,
placeholder: PropTypes.string
placeholder: PropTypes.string,
isFocusCanceled: PropTypes.bool
};

DropDownInput.defaultProps = {
Expand Down
11 changes: 7 additions & 4 deletions src/components/common/editable-value.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,15 +53,17 @@ class EditableValue extends React.Component {

onEditBlur(column, value, e) {
if (this.props.validator) {
const validationResult = this.props.validator.validateColumn(this.props.columnName, this.state.editValue);
const validationResult = this.props.validator.validateColumn(
this.props.columnName, this.state.editValue, this.props.entity
);
if (!validationResult.success) {
this.setState(Object.assign({}, this.state, {validationMessage: validationResult.message}));
return;
} else {
this.setState(Object.assign({}, this.state, {validationMessage: ""}));
this.setState(Object.assign({}, this.state, {validationMessage: "", isEditMode: false}));
}
}
this.setState(Object.assign({}, this.state, {isEditMode: false}));
//this.setState(Object.assign({}, this.state, {isEditMode: false}));
this.notifyParentIfValueChanged();
}

Expand All @@ -86,7 +88,8 @@ EditableValue.propTypes = {
value: PropTypes.oneOfType([PropTypes.string, PropTypes.object, PropTypes.bool, PropTypes.number]),
onBlur: PropTypes.func,
validator: PropTypes.object,
validationMessage: PropTypes.string
validationMessage: PropTypes.string,
entity: PropTypes.object
};

EditableValue.defaultProps = {
Expand Down
1 change: 1 addition & 0 deletions src/components/common/input-by-column-type.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ class InputByColumnType extends React.Component {
this.props.isLabelHidden ? "div" : LabelCover,
this.props.isLabelHidden ? undefined : {caption: column.caption},
React.cloneElement(this.getComponent(column), {
ref: this.props.columnName,
value: this.props.value,
onChange: this.props.onChange,
onBlur: this.props.onBlur,
Expand Down
Loading

0 comments on commit b28fcb2

Please sign in to comment.