Skip to content

Commit

Permalink
Feature/widget validation (#86)
Browse files Browse the repository at this point in the history
  • Loading branch information
Bartłomiej Jackowiak authored Nov 13, 2019
1 parent 3ebc2ed commit 7a8939f
Show file tree
Hide file tree
Showing 33 changed files with 658 additions and 581 deletions.
27 changes: 3 additions & 24 deletions cogboard-webapp/src/components/AddBoard.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,15 @@
import React from 'react';
import { useDispatch, useSelector } from 'react-redux';
import styled from '@emotion/styled/macro';

import { useToggle } from '../hooks';
import { addNewBoard } from '../actions/thunks';
import { getIsAuthenticated } from '../selectors';

import { Button, IconButton } from '@material-ui/core';
import { IconButton } from '@material-ui/core';
import { Add } from '@material-ui/icons';
import AppDialog from './AppDialog';
import CancelButton from './CancelButton';
import BoardForm from './BoardForm';

const StyledCancelButton = styled(CancelButton)`
margin-left: 20px;
`;

const AddBoard = () => {
const [dialogOpened, openDialog, handleDialogClose] = useToggle();
const dispatch = useDispatch();
Expand Down Expand Up @@ -51,23 +45,8 @@ const AddBoard = () => {
title="Add new board"
>
<BoardForm
onSubmit={handleAddActionClick}
renderActions={() => (
<>
<Button
color="primary"
variant="contained"
type="submit"
data-cy="board-form-submit-button"
>
Add
</Button>
<StyledCancelButton
handleCancelClick={handleDialogClose}
data-cy="board-form-cancel-button"
/>
</>
)}
handleSubmit={handleAddActionClick}
handleCancel={handleDialogClose}
/>
</AppDialog>
</>
Expand Down
31 changes: 5 additions & 26 deletions cogboard-webapp/src/components/AddWidget.js
Original file line number Diff line number Diff line change
@@ -1,51 +1,30 @@
import React from 'react';
import { func } from 'prop-types';
import { useDispatch, useSelector } from 'react-redux';
import styled from '@emotion/styled/macro';

import { addNewWidget } from '../actions/thunks';

import Button from '@material-ui/core/Button';
import CancelButton from './CancelButton';
import WidgetForm from './WidgetForm';

const StyledCancelButton = styled(CancelButton)`
margin-left: 20px;
`;

const AddWidget = ({ closeDialog }) => {
const currentBoardId = useSelector(({ ui }) => ui.currentBoard);
const dispatch = useDispatch();

const handleAddClick = values => () => {
const handleAddWidget = ( values ) => {
dispatch(addNewWidget({ currentBoardId, values }));
closeDialog();
};

return (
<WidgetForm
renderActions={values => (
<>
<Button
onClick={handleAddClick(values)}
color="primary"
variant="contained"
data-cy="widget-form-submit-button"
>
Add
</Button>
<StyledCancelButton
handleCancelClick={closeDialog}
data-cy="widget-form-cancel-button"
/>
</>
)}
handleSubmit={handleAddWidget}
handleCancel={closeDialog}
/>
);
};

AddWidget.propTypes = {
closeDialog: func.isRequired
closeDialog: func.isRequired,
};

export default AddWidget;
export default AddWidget;
151 changes: 44 additions & 107 deletions cogboard-webapp/src/components/BoardForm/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,121 +2,58 @@ import React from 'react';
import { useSelector } from 'react-redux';
import { string, number, bool } from 'prop-types';

import {
FormControl,
FormControlLabel,
Switch,
TextField
} from '@material-ui/core';
import { StyledFieldset, StyledValidationMessages } from './styled';
import { useFormData } from '../../hooks';
import { getBoards } from '../../selectors';
import { createValidationSchema } from './validators';
import { trimLeadingZeros } from '../../helpers';
import { createValidationSchema } from '../validation';

import NumberInput from '../widgets/dialogFields/NumberInput';
import { Button } from '@material-ui/core';
import DynamicForm from '../DynamicForm';
import { StyledCancelButton } from './styled';

const BoardForm = ({
onSubmit,
renderActions,
boardId,
...initialFormValues
}) => {
const boards = useSelector(getBoards);
const validationSchema = createValidationSchema(boardId, boards);
const { values, handleChange, handleSubmit, errors } = useFormData(
initialFormValues,
validationSchema,
true
);

const handleNumberInput = event => {
const {
target: { value }
} = event;
import { BOARD_TITLE_LENGTH_LIMIT, BOARD_COLUMNS_MIN, BOARD_COLUMNS_MAX, SWITCH_INTERVAL_MIN } from '../../constants';

event.target.value = trimLeadingZeros(value);
const BoardForm = ({ handleSubmit, handleCancel, boardId, ...initialFormValues }) => {
const boards = useSelector(getBoards);
const formFields = ['UniqueTitleField', 'ColumnField', 'AutoSwitchField', 'SwitchInterval'];
const constraints = {
'UniqueTitleField' : {
max: BOARD_TITLE_LENGTH_LIMIT,
boardId: boardId,
boards: boards,
},
'ColumnField': {
min: BOARD_COLUMNS_MIN,
max: BOARD_COLUMNS_MAX,
},
'SwitchInterval': {
min: SWITCH_INTERVAL_MIN,
}
};

const validationSchema = createValidationSchema(formFields, constraints);
const {values, handleChange, withValidation, errors} = useFormData(initialFormValues, {initialSchema: validationSchema, onChange: true});

return (
<form onSubmit={handleSubmit(onSubmit)} noValidate="novalidate">
<StyledFieldset component="fieldset">
<TextField
onChange={handleChange('title')}
id="title"
InputLabelProps={{
shrink: true
}}
label="Title"
margin="normal"
value={values.title}
error={errors.title !== undefined}
helperText={
<StyledValidationMessages
messages={errors.title}
data-cy={'board-form-title-error'}
/>
}
inputProps={{ 'data-cy': 'board-form-title-input' }}
/>
<NumberInput
onChange={handleChange('columns')}
onInput={handleNumberInput}
id="columns"
InputLabelProps={{
shrink: true
}}
inputProps={{ 'data-cy': 'board-form-columns-input' }}
label="Columns"
margin="normal"
value={values.columns}
error={errors.columns !== undefined}
FormHelperTextProps={{ component: 'div' }}
helperText={
<StyledValidationMessages
messages={errors.columns}
data-cy="board-form-columns-error"
/>
}
/>
<FormControl margin="normal">
<FormControlLabel
control={
<Switch
onChange={handleChange('autoSwitch')}
checked={values.autoSwitch}
color="primary"
value="autoSwitch"
inputProps={{ 'data-cy': 'board-form-auto-switch-checkbox' }}
/>
}
label="Auto switch"
/>
</FormControl>
{values.autoSwitch && (
<NumberInput
onChange={handleChange('switchInterval')}
onInput={handleNumberInput}
id="switchInterval"
InputLabelProps={{
shrink: true
}}
label="Switch interval [s]"
margin="normal"
value={values.switchInterval}
error={errors.switchInterval !== undefined}
FormHelperTextProps={{ component: 'div' }}
helperText={
<StyledValidationMessages
messages={errors.switchInterval}
data-cy="board-form-switch-interval-error"
/>
}
inputProps={{ 'data-cy': 'board-form-switch-interval-input' }}
/>
)}
</StyledFieldset>
{renderActions()}
<form onSubmit={withValidation(handleSubmit)} noValidate="novalidate">
<DynamicForm
fields={formFields}
values={values}
handleChange={handleChange}
errors={errors}
rootName='board-form'
/>
<Button
color="primary"
variant="contained"
type="submit"
data-cy="board-form-submit-button"
>
Save
</Button>
<StyledCancelButton
handleCancelClick={handleCancel}
data-cy="board-form-cancel-button"
/>
</form>
);
};
Expand Down
15 changes: 3 additions & 12 deletions cogboard-webapp/src/components/BoardForm/styled.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,7 @@
import styled from '@emotion/styled/macro';

import { FormControl } from '@material-ui/core';
import ValidationMessages from '../ValidationMessages';
import CancelButton from '../CancelButton';

export const StyledFieldset = styled(FormControl)`
display: flex;
margin-bottom: 32px;
min-width: 300px;
`;

export const StyledValidationMessages = styled(ValidationMessages)`
list-style-type: none;
margin: 0;
padding: 0;
export const StyledCancelButton = styled(CancelButton)`
margin-left: 20px;
`;
48 changes: 0 additions & 48 deletions cogboard-webapp/src/components/BoardForm/validators.js

This file was deleted.

2 changes: 2 additions & 0 deletions cogboard-webapp/src/components/DropdownField.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const DropdownField = props => {
children,
dropdownItems,
itemsUrl,
dataCy,
...other
} = props;
const initialLoaded = !itemsUrl;
Expand Down Expand Up @@ -53,6 +54,7 @@ const DropdownField = props => {
input={<Input name={name} id={id} />}
name={name}
SelectDisplayProps={other}
data-cy={dataCy}
>
{loaded && children(options)}
</Select>
Expand Down
25 changes: 25 additions & 0 deletions cogboard-webapp/src/components/DynamicForm/helpers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { splitPropsGroupName } from '../../helpers';

export const camelToKebab = ( string ) => string.replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g, '$1-$2').toLowerCase();

export const createValueRef = (values, initialValue, name) => {
const [groupName, propName] = splitPropsGroupName(name);

if (groupName) {
if (!values[groupName]) {
values[groupName] = {};
}

if(values[groupName][propName] === undefined) {
values[groupName][propName] = initialValue;
}

return values[groupName][propName];
}

if (values[propName] === undefined) {
values[propName] = initialValue;
}

return values[propName];
};
Loading

0 comments on commit 7a8939f

Please sign in to comment.