diff --git a/.eslintrc.js b/.eslintrc.js index 3c76d5678..1932d38cf 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -24,6 +24,13 @@ module.exports = { "aspects": ["invalidHref", "preferButton"] }], "jsx-a11y/click-events-have-key-events": 0, + "jsx-a11y/label-has-for": [2, { + "components": ["Label"], + "required": { + "every": ["id"] + }, + "allowChildren": false + }], "react/no-array-index-key": 0, "max-len": 0, "react/no-danger": 0, diff --git a/demo/collections/User.js b/demo/collections/User.js index 36d257861..b34a5c984 100644 --- a/demo/collections/User.js +++ b/demo/collections/User.js @@ -8,6 +8,7 @@ module.exports = { }, useAsTitle: 'email', useAsUsername: 'email', + passwordIndex: 1, policies: { create: (req, res, next) => { return next(); diff --git a/src/client/api.js b/src/client/api.js index 52f0b95a0..8c4c2efd9 100644 --- a/src/client/api.js +++ b/src/client/api.js @@ -21,18 +21,20 @@ const requests = { post: (url, body) => fetch(`${url}`, { method: 'post', - body, + body: JSON.stringify(body), headers: { - ...setJWT() + ...setJWT(), + 'Content-Type': 'application/json', }, }), put: (url, body) => fetch(`${url}`, { method: 'put', - body, + body: JSON.stringify(body), headers: { - ...setJWT() + ...setJWT(), + 'Content-Type': 'application/json', }, }), }; diff --git a/src/client/components/Routes.js b/src/client/components/Routes.js index d6e0e094d..3269e500d 100644 --- a/src/client/components/Routes.js +++ b/src/client/components/Routes.js @@ -1,4 +1,4 @@ -import React, { useState, useEffect } from 'react'; +import React, { useState, useEffect, Fragment } from 'react'; import Cookies from 'universal-cookie'; import { Route, Switch, withRouter, Redirect, @@ -56,67 +56,71 @@ const Routes = () => { if (cookies.get('token')) { return ( - - - + + + + - {config.collections.map((collection) => { - const components = collection.components ? collection.components : {}; - return ( - - { - return ( - - ); - }} - /> + {config.collections.map((collection) => { + const components = collection.components ? collection.components : {}; + return ( + + { + return ( + + ); + }} + /> - { - return ( - - ); - }} - /> + { + return ( + + ); + }} + /> - { - const ListComponent = components.List ? components.List : List; - return ( - - ); - }} - /> - - - ); - })} + { + const ListComponent = components.List ? components.List : List; + return ( + + ); + }} + /> + + ); + })} + +

Not Found

+
+
); } diff --git a/src/client/components/forms/Form/index.js b/src/client/components/forms/Form/index.js index b42fdabf6..63b9727eb 100644 --- a/src/client/components/forms/Form/index.js +++ b/src/client/components/forms/Form/index.js @@ -70,6 +70,8 @@ const Form = (props) => { setProcessing(true); + console.log(data); + // Make the API call from the action api.requests[method.toLowerCase()](action, data).then( (res) => { diff --git a/src/client/components/forms/field-types/fieldType/index.js b/src/client/components/forms/field-types/fieldType/index.js index 5053b76cc..d9319e34f 100644 --- a/src/client/components/forms/field-types/fieldType/index.js +++ b/src/client/components/forms/field-types/fieldType/index.js @@ -1,117 +1,163 @@ -import React, { Component } from 'react'; -import FormContext from '../../Form/Context' +import React, { useContext, useEffect } from 'react'; +import PropTypes from 'prop-types'; +import FormContext from '../../Form/Context'; +import Tooltip from '../../../modules/Tooltip'; import './index.scss'; -const fieldType = (PassedComponent, type, validate, errors) => { +const baseClass = 'field-type'; - class FieldType extends Component { +const asFieldType = (PassedComponent, type, validate, errors) => { + const FieldType = (props) => { + const formContext = useContext(FormContext); - constructor(props) { - super(props); + const { + name, + id, + value, + required, + initialValue, + valueOverride, + onChange, + } = props; - this.state = { - init: false - }; - } - - sendField(value) { - this.props.context.setValue({ - name: this.props.name, - value: value, - valid: this.props.required && validate - ? validate(value || '', this.props.type) - : true + const sendField = (valueToSend) => { + formContext.setValue({ + name, + value: valueToSend, + valid: required && validate + ? validate(valueToSend || '', type) + : true, }); - } + }; - componentDidMount() { - let value = this.props.value ? this.props.value : ''; - value = this.props.initialValue ? this.props.initialValue : value; - value = this.props.valueOverride ? this.props.valueOverride : value; - this.sendField(value); + useEffect(() => { + let valueToInitialize = value; + if (initialValue) valueToInitialize = initialValue; + if (valueOverride) valueToInitialize = valueOverride; + sendField(valueToInitialize); + }, []); - this.setState({ - init: true - }); - } + useEffect(() => { + sendField(valueOverride); + }, [valueOverride]); - componentDidUpdate(prevProps) { - if (prevProps.valueOverride !== this.props.valueOverride) { - this.sendField(this.props.valueOverride); - } + useEffect(() => { + sendField(initialValue); + }, [initialValue]); - if (prevProps.initialValue !== this.props.initialValue) { - this.sendField(this.props.initialValue); - } - } + const classList = [baseClass, type]; + const valid = formContext.fields[name] ? formContext.fields[name].valid : true; + const showError = valid === false && formContext.submitted; - render() { - const valid = this.props.context.fields[this.props.name] - ? this.props.context.fields[this.props.name].valid - : true; + if (showError) classList.push('error'); - const showError = valid === false && this.props.context.submitted; + let valueToRender = formContext.fields[name] ? formContext.fields[name].value : ''; - let className = `field-type ${type}${showError ? ' error' : ''}`; + // If valueOverride present, field is being controlled by state outside form + valueToRender = valueOverride || value; - let value = this.props.context.fields[this.props.name] ? this.props.context.fields[this.props.name].value : ''; + const classes = classList.filter(Boolean).join(' '); - // If valueOverride present, field is being controlled by state outside form - value = this.props.valueOverride ? this.props.valueOverride : value; - - return ( - } - error={} - onChange={e => { - this.sendField(e.target.value); - this.props.onChange && this.props.onChange(e); - }} /> - ) - } - } - - const Label = props => { - if (props.label) { - return ( - - ) - } - - return null; - } - - const Error = props => { - if (props.showError) { - return ( - - {props.error && errors[props.error]} - - {!props.error && errors} - - ) - } - - return null; - } - - const FieldTypeWithContext = props => { return ( - - {context => } - + + )} + error={( + + )} + onChange={(e) => { + sendField(e.target.value); + if (onChange && typeof onChange === 'function') onChange(e); + }} + /> ); }; - return FieldTypeWithContext; -} + FieldType.defaultProps = { + value: '', + required: false, + initialValue: '', + valueOverride: '', + onChange: null, + id: '', + }; -export default fieldType; + FieldType.propTypes = { + name: PropTypes.string.isRequired, + value: PropTypes.string, + required: PropTypes.bool, + type: PropTypes.string.isRequired, + initialValue: PropTypes.string, + valueOverride: PropTypes.string, + onChange: PropTypes.func, + id: PropTypes.string, + }; + + const Label = (props) => { + const { + label, required, htmlFor, + } = props; + + if (label) { + return ( + + ); + } + + return null; + }; + + Label.defaultProps = { + required: false, + }; + + Label.propTypes = { + label: PropTypes.string.isRequired, + htmlFor: PropTypes.string.isRequired, + required: PropTypes.bool, + }; + + const Error = (props) => { + const { error, showError } = props; + + if (showError) { + return ( + + {error && errors[error]} + {!error && errors} + + ); + } + + return null; + }; + + Error.defaultProps = { + showError: false, + }; + + Error.propTypes = { + error: PropTypes.string.isRequired, + showError: PropTypes.bool, + }; + + return FieldType; +}; + +export default asFieldType; diff --git a/src/client/components/layout/DefaultTemplate/index.js b/src/client/components/layout/DefaultTemplate/index.js index 0bad7cabc..fc87d7732 100644 --- a/src/client/components/layout/DefaultTemplate/index.js +++ b/src/client/components/layout/DefaultTemplate/index.js @@ -1,6 +1,7 @@ import React from 'react'; +import PropTypes from 'prop-types'; import Sidebar from '../Sidebar'; -import StepNav from '../../modules/StepNav'; +import StepNav, { StepNavProvider } from '../../modules/StepNav'; import Localizer from '../../modules/Localizer'; import './index.scss'; @@ -9,15 +10,24 @@ const DefaultTemplate = ({ children }) => { return (
- -
- - -
- {children} + + +
+ + +
+ {children} +
); }; +DefaultTemplate.propTypes = { + children: PropTypes.oneOfType([ + PropTypes.arrayOf(PropTypes.node), + PropTypes.node, + ]).isRequired, +}; + export default DefaultTemplate; diff --git a/src/client/components/layout/Sidebar/index.js b/src/client/components/layout/Sidebar/index.js index 2955aa5dd..93de21107 100644 --- a/src/client/components/layout/Sidebar/index.js +++ b/src/client/components/layout/Sidebar/index.js @@ -1,6 +1,5 @@ import React from 'react'; -import { withRouter, NavLink, Link } from 'react-router-dom'; -import { connect } from 'react-redux'; +import { useLocation, NavLink, Link } from 'react-router-dom'; import config from 'payload-config'; import Arrow from '../../graphics/Arrow'; @@ -8,11 +7,7 @@ import Icon from '../../graphics/Icon'; import './index.scss'; -const mapState = state => ({ - config: state.common.config, -}); - -const Sidebar = (props) => { +const Sidebar = () => { const { collections, globals, @@ -21,6 +16,8 @@ const Sidebar = (props) => { }, } = config; + const location = useLocation(); + return (