Bootstrapped validation for groups

This commit is contained in:
Philipp Czora
2018-08-01 13:40:54 +02:00
parent d7292dc60c
commit bc10ce587d
6 changed files with 77 additions and 29 deletions

View File

@@ -5,14 +5,17 @@ import InputField from "../../components/forms/InputField";
import { SubmitButton } from "../../components/buttons";
import { translate } from "react-i18next";
import type { Group } from "../types/Group";
import * as validator from "./groupValidation"
export interface Props {
t: string => string;
submitForm: Group => void;
type Props = {
t: string => string,
submitForm: Group => void
}
export interface State {
group: Group;
type State = {
group: Group,
nameValidationError: boolean,
descriptionValidationError: boolean
}
class GroupForm extends React.Component<Props, State> {
@@ -28,21 +31,27 @@ class GroupForm extends React.Component<Props, State> {
_links: {},
members: [],
type: "",
}
},
nameValidationError: false,
descriptionValidationError: false
};
}
onSubmit = (event: Event) => {
event.preventDefault();
this.props.submitForm(this.state.group);
};
isValid = () => {
return true;
const group = this.state.group;
return !(this.state.nameValidationError || this.state.descriptionValidationError || group.name);
}
submit = (event: Event) => {
event.preventDefault();
this.props.submitForm(this.state.group)
if (this.isValid) {
this.props.submitForm(this.state.group)
}
}
render() {
@@ -51,15 +60,15 @@ class GroupForm extends React.Component<Props, State> {
<form onSubmit={this.onSubmit}>
<InputField
label={t("group.name")}
errorMessage=""
errorMessage="group name invalid"
onChange={this.handleGroupNameChange}
validationError={false}
validationError={this.state.nameValidationError}
/>
<InputField
label={t("group.description")}
errorMessage=""
onChange={this.handleDescriptionChange}
validationError={false}
validationError={this.state.descriptionValidationError}
/>
<SubmitButton label={t("group-form.submit")} />
</form>
@@ -68,19 +77,14 @@ class GroupForm extends React.Component<Props, State> {
handleGroupNameChange = (name: string) => {
this.setState({
group: {
...this.state.group,
name
}
nameValidationError: !validator.isNameValid(name),
group: {...this.state.group, name}
});
};
handleDescriptionChange = (description: string) => {
this.setState({
group: {
...this.state.group,
description
}
group: {...this.state.group, description }
});
};
}

View File

@@ -0,0 +1,10 @@
// @flow
//TODO: How should a group be validated
//TODO: Tests!
const nameRegex = /^([A-z0-9.\-_@]|[^ ]([A-z0-9.\-_@ ]*[A-z0-9.\-_@]|[^\s])?)$/;
export const isNameValid = (name: string) => {
return nameRegex.test(name);
};

View File

@@ -3,17 +3,19 @@ import React from "react";
import Page from "../../components/layout/Page";
import { translate } from "react-i18next";
import GroupForm from "./GroupForm";
import GroupForm from "../components/GroupForm";
import { connect } from "react-redux";
import { createGroup } from "../modules/groups";
import type { Group } from "../types/Group";
import type { History } from "history";
export interface Props {
t: string => string;
createGroup: Group => void;
type Props = {
t: string => string,
createGroup: (group: Group, callback?: () => void) => void,
history: History
}
export interface State {}
type State = {}
class AddGroup extends React.Component<Props, State> {
render() {
@@ -27,14 +29,18 @@ class AddGroup extends React.Component<Props, State> {
);
}
groupCreated = () => {
console.log("pushing history")
this.props.history.push("/groups")
}
createGroup = (group: Group) => {
this.props.createGroup(group);
this.props.createGroup(group, this.groupCreated)
};
}
const mapDispatchToProps = dispatch => {
return {
createGroup: (group: Group) => dispatch(createGroup(group))
createGroup: (group: Group, callback?: () => void) => dispatch(createGroup(group, callback))
};
};

View File

@@ -133,12 +133,16 @@ export function fetchGroupFailure(name: string, error: Error): Action {
}
//create group
export function createGroup(group: Group) {
export function createGroup(group: Group, callback?: () => void) {
return function(dispatch: Dispatch) {
dispatch(createGroupPending());
return apiClient
.postWithContentType(GROUPS_URL, group, CONTENT_TYPE_GROUP)
.then(() => dispatch(createGroupSuccess()))
.then(() => {
dispatch(createGroupSuccess())
if (callback) {
callback();
}})
.catch(error => {
dispatch(
createGroupFailure(
@@ -168,6 +172,11 @@ export function createGroupFailure(error: Error) {
};
}
export function createGroupReset() {
return {
type: CREATE_GROUP_RESET
}
}
//delete group
export function deleteGroup(group: Group, callback?: () => void) {

View File

@@ -205,6 +205,25 @@ describe("groups fetch()", () => {
});
});
it("should call the callback after creating group", () => {
fetchMock.postOnce(GROUPS_URL, {
status: 201
});
let called = false;
const callMe = () => {
called = true;
}
const store = mockStore({});
return store.dispatch(createGroup(humanGroup, callMe)).then(() => {
const actions = store.getActions();
expect(actions[0].type).toEqual(CREATE_GROUP_PENDING);
expect(actions[1].type).toEqual(CREATE_GROUP_SUCCESS);
expect(called).toEqual(true);
});
});
it("should fail creating group on HTTP 500", () => {
fetchMock.postOnce(GROUPS_URL, {
status: 500

View File

@@ -1,7 +1,7 @@
//@flow
import React from "react";
import { connect } from "react-redux";
import UserForm from "./../components/UserForm";
import UserForm from "../components/UserForm";
import type { User } from "../types/User";
import type { History } from "history";
import {