revises APIError import structure, updates Localizer and StepNav
This commit is contained in:
@@ -24,6 +24,13 @@ module.exports = {
|
|||||||
"aspects": ["invalidHref", "preferButton"]
|
"aspects": ["invalidHref", "preferButton"]
|
||||||
}],
|
}],
|
||||||
"jsx-a11y/click-events-have-key-events": 0,
|
"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,
|
"react/no-array-index-key": 0,
|
||||||
"max-len": 0,
|
"max-len": 0,
|
||||||
"react/no-danger": 0,
|
"react/no-danger": 0,
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
useAsTitle: 'email',
|
useAsTitle: 'email',
|
||||||
useAsUsername: 'email',
|
useAsUsername: 'email',
|
||||||
|
passwordIndex: 1,
|
||||||
policies: {
|
policies: {
|
||||||
create: (req, res, next) => {
|
create: (req, res, next) => {
|
||||||
return next();
|
return next();
|
||||||
|
|||||||
@@ -21,18 +21,20 @@ const requests = {
|
|||||||
post: (url, body) =>
|
post: (url, body) =>
|
||||||
fetch(`${url}`, {
|
fetch(`${url}`, {
|
||||||
method: 'post',
|
method: 'post',
|
||||||
body,
|
body: JSON.stringify(body),
|
||||||
headers: {
|
headers: {
|
||||||
...setJWT()
|
...setJWT(),
|
||||||
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
|
||||||
put: (url, body) =>
|
put: (url, body) =>
|
||||||
fetch(`${url}`, {
|
fetch(`${url}`, {
|
||||||
method: 'put',
|
method: 'put',
|
||||||
body,
|
body: JSON.stringify(body),
|
||||||
headers: {
|
headers: {
|
||||||
...setJWT()
|
...setJWT(),
|
||||||
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect, Fragment } from 'react';
|
||||||
import Cookies from 'universal-cookie';
|
import Cookies from 'universal-cookie';
|
||||||
import {
|
import {
|
||||||
Route, Switch, withRouter, Redirect,
|
Route, Switch, withRouter, Redirect,
|
||||||
@@ -56,67 +56,71 @@ const Routes = () => {
|
|||||||
if (cookies.get('token')) {
|
if (cookies.get('token')) {
|
||||||
return (
|
return (
|
||||||
<DefaultTemplate>
|
<DefaultTemplate>
|
||||||
<Route
|
<Switch>
|
||||||
path={`${match.url}/media-library`}
|
<Route
|
||||||
component={MediaLibrary}
|
path={`${match.url}/media-library`}
|
||||||
/>
|
component={MediaLibrary}
|
||||||
<Route
|
/>
|
||||||
path={`${match.url}/create-user`}
|
<Route
|
||||||
component={CreateUser}
|
path={`${match.url}/create-user`}
|
||||||
/>
|
component={CreateUser}
|
||||||
<Route
|
/>
|
||||||
path={`${match.url}/`}
|
<Route
|
||||||
exact
|
path={`${match.url}/`}
|
||||||
component={Dashboard}
|
exact
|
||||||
/>
|
component={Dashboard}
|
||||||
|
/>
|
||||||
|
|
||||||
{config.collections.map((collection) => {
|
{config.collections.map((collection) => {
|
||||||
const components = collection.components ? collection.components : {};
|
const components = collection.components ? collection.components : {};
|
||||||
return (
|
return (
|
||||||
<Switch key={collection.slug}>
|
<Fragment key={collection.slug}>
|
||||||
<Route
|
<Route
|
||||||
path={`${match.url}/collections/${collection.slug}/create`}
|
path={`${match.url}/collections/${collection.slug}/create`}
|
||||||
exact
|
exact
|
||||||
render={(routeProps) => {
|
render={(routeProps) => {
|
||||||
return (
|
return (
|
||||||
<Edit
|
<Edit
|
||||||
{...routeProps}
|
{...routeProps}
|
||||||
collection={collection}
|
collection={collection}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Route
|
<Route
|
||||||
path={`${match.url}/collections/${collection.slug}/:id`}
|
path={`${match.url}/collections/${collection.slug}/:id`}
|
||||||
exact
|
exact
|
||||||
render={(routeProps) => {
|
render={(routeProps) => {
|
||||||
return (
|
return (
|
||||||
<Edit
|
<Edit
|
||||||
{...routeProps}
|
{...routeProps}
|
||||||
collection={collection}
|
collection={collection}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Route
|
<Route
|
||||||
path={`${match.url}/collections/${collection.slug}`}
|
path={`${match.url}/collections/${collection.slug}`}
|
||||||
exact
|
exact
|
||||||
render={(routeProps) => {
|
render={(routeProps) => {
|
||||||
const ListComponent = components.List ? components.List : List;
|
const ListComponent = components.List ? components.List : List;
|
||||||
return (
|
return (
|
||||||
<ListComponent
|
<ListComponent
|
||||||
{...routeProps}
|
{...routeProps}
|
||||||
collection={collection}
|
collection={collection}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
</Fragment>
|
||||||
</Switch>
|
);
|
||||||
);
|
})}
|
||||||
})}
|
<Route>
|
||||||
|
<h1>Not Found</h1>
|
||||||
|
</Route>
|
||||||
|
</Switch>
|
||||||
</DefaultTemplate>
|
</DefaultTemplate>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,6 +70,8 @@ const Form = (props) => {
|
|||||||
|
|
||||||
setProcessing(true);
|
setProcessing(true);
|
||||||
|
|
||||||
|
console.log(data);
|
||||||
|
|
||||||
// Make the API call from the action
|
// Make the API call from the action
|
||||||
api.requests[method.toLowerCase()](action, data).then(
|
api.requests[method.toLowerCase()](action, data).then(
|
||||||
(res) => {
|
(res) => {
|
||||||
|
|||||||
@@ -1,117 +1,163 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { useContext, useEffect } from 'react';
|
||||||
import FormContext from '../../Form/Context'
|
import PropTypes from 'prop-types';
|
||||||
|
import FormContext from '../../Form/Context';
|
||||||
|
import Tooltip from '../../../modules/Tooltip';
|
||||||
|
|
||||||
import './index.scss';
|
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) {
|
const {
|
||||||
super(props);
|
name,
|
||||||
|
id,
|
||||||
|
value,
|
||||||
|
required,
|
||||||
|
initialValue,
|
||||||
|
valueOverride,
|
||||||
|
onChange,
|
||||||
|
} = props;
|
||||||
|
|
||||||
this.state = {
|
const sendField = (valueToSend) => {
|
||||||
init: false
|
formContext.setValue({
|
||||||
};
|
name,
|
||||||
}
|
value: valueToSend,
|
||||||
|
valid: required && validate
|
||||||
sendField(value) {
|
? validate(valueToSend || '', type)
|
||||||
this.props.context.setValue({
|
: true,
|
||||||
name: this.props.name,
|
|
||||||
value: value,
|
|
||||||
valid: this.props.required && validate
|
|
||||||
? validate(value || '', this.props.type)
|
|
||||||
: true
|
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
componentDidMount() {
|
useEffect(() => {
|
||||||
let value = this.props.value ? this.props.value : '';
|
let valueToInitialize = value;
|
||||||
value = this.props.initialValue ? this.props.initialValue : value;
|
if (initialValue) valueToInitialize = initialValue;
|
||||||
value = this.props.valueOverride ? this.props.valueOverride : value;
|
if (valueOverride) valueToInitialize = valueOverride;
|
||||||
this.sendField(value);
|
sendField(valueToInitialize);
|
||||||
|
}, []);
|
||||||
|
|
||||||
this.setState({
|
useEffect(() => {
|
||||||
init: true
|
sendField(valueOverride);
|
||||||
});
|
}, [valueOverride]);
|
||||||
}
|
|
||||||
|
|
||||||
componentDidUpdate(prevProps) {
|
useEffect(() => {
|
||||||
if (prevProps.valueOverride !== this.props.valueOverride) {
|
sendField(initialValue);
|
||||||
this.sendField(this.props.valueOverride);
|
}, [initialValue]);
|
||||||
}
|
|
||||||
|
|
||||||
if (prevProps.initialValue !== this.props.initialValue) {
|
const classList = [baseClass, type];
|
||||||
this.sendField(this.props.initialValue);
|
const valid = formContext.fields[name] ? formContext.fields[name].valid : true;
|
||||||
}
|
const showError = valid === false && formContext.submitted;
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
if (showError) classList.push('error');
|
||||||
const valid = this.props.context.fields[this.props.name]
|
|
||||||
? this.props.context.fields[this.props.name].valid
|
|
||||||
: true;
|
|
||||||
|
|
||||||
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 (
|
|
||||||
<PassedComponent {...this.props}
|
|
||||||
className={className}
|
|
||||||
value={value}
|
|
||||||
label={<Label {...this.props} />}
|
|
||||||
error={<Error showError={showError} type={this.props.type} />}
|
|
||||||
onChange={e => {
|
|
||||||
this.sendField(e.target.value);
|
|
||||||
this.props.onChange && this.props.onChange(e);
|
|
||||||
}} />
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const Label = props => {
|
|
||||||
if (props.label) {
|
|
||||||
return (
|
|
||||||
<label htmlFor={props.id ? props.id : props.name}>
|
|
||||||
{props.label}
|
|
||||||
{props.required &&
|
|
||||||
<span className="required">*</span>
|
|
||||||
}
|
|
||||||
</label>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Error = props => {
|
|
||||||
if (props.showError) {
|
|
||||||
return (
|
|
||||||
<Tooltip className="error-message">
|
|
||||||
{props.error && errors[props.error]}
|
|
||||||
|
|
||||||
{!props.error && errors}
|
|
||||||
</Tooltip>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const FieldTypeWithContext = props => {
|
|
||||||
return (
|
return (
|
||||||
<FormContext.Consumer>
|
<PassedComponent
|
||||||
{context => <FieldType {...props} context={context} />}
|
{...props}
|
||||||
</FormContext.Consumer>
|
className={classes}
|
||||||
|
value={valueToRender}
|
||||||
|
label={(
|
||||||
|
<Label
|
||||||
|
htmlFor={id || name}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
error={(
|
||||||
|
<Error
|
||||||
|
showError={showError}
|
||||||
|
type={type}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
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 (
|
||||||
|
<label htmlFor={htmlFor}>
|
||||||
|
{label}
|
||||||
|
{required
|
||||||
|
&& <span className="required">*</span>
|
||||||
|
}
|
||||||
|
</label>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 (
|
||||||
|
<Tooltip className="error-message">
|
||||||
|
{error && errors[error]}
|
||||||
|
{!error && errors}
|
||||||
|
</Tooltip>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
Error.defaultProps = {
|
||||||
|
showError: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
Error.propTypes = {
|
||||||
|
error: PropTypes.string.isRequired,
|
||||||
|
showError: PropTypes.bool,
|
||||||
|
};
|
||||||
|
|
||||||
|
return FieldType;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default asFieldType;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
import Sidebar from '../Sidebar';
|
import Sidebar from '../Sidebar';
|
||||||
import StepNav from '../../modules/StepNav';
|
import StepNav, { StepNavProvider } from '../../modules/StepNav';
|
||||||
import Localizer from '../../modules/Localizer';
|
import Localizer from '../../modules/Localizer';
|
||||||
|
|
||||||
import './index.scss';
|
import './index.scss';
|
||||||
@@ -9,15 +10,24 @@ const DefaultTemplate = ({ children }) => {
|
|||||||
return (
|
return (
|
||||||
<div className="default-template">
|
<div className="default-template">
|
||||||
<div className="wrap">
|
<div className="wrap">
|
||||||
<Sidebar />
|
<StepNavProvider>
|
||||||
<div className="eyebrow">
|
<Sidebar />
|
||||||
<StepNav />
|
<div className="eyebrow">
|
||||||
<Localizer />
|
<StepNav />
|
||||||
</div>
|
<Localizer />
|
||||||
{children}
|
</div>
|
||||||
|
{children}
|
||||||
|
</StepNavProvider>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
DefaultTemplate.propTypes = {
|
||||||
|
children: PropTypes.oneOfType([
|
||||||
|
PropTypes.arrayOf(PropTypes.node),
|
||||||
|
PropTypes.node,
|
||||||
|
]).isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
export default DefaultTemplate;
|
export default DefaultTemplate;
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { withRouter, NavLink, Link } from 'react-router-dom';
|
import { useLocation, NavLink, Link } from 'react-router-dom';
|
||||||
import { connect } from 'react-redux';
|
|
||||||
import config from 'payload-config';
|
import config from 'payload-config';
|
||||||
|
|
||||||
import Arrow from '../../graphics/Arrow';
|
import Arrow from '../../graphics/Arrow';
|
||||||
@@ -8,11 +7,7 @@ import Icon from '../../graphics/Icon';
|
|||||||
|
|
||||||
import './index.scss';
|
import './index.scss';
|
||||||
|
|
||||||
const mapState = state => ({
|
const Sidebar = () => {
|
||||||
config: state.common.config,
|
|
||||||
});
|
|
||||||
|
|
||||||
const Sidebar = (props) => {
|
|
||||||
const {
|
const {
|
||||||
collections,
|
collections,
|
||||||
globals,
|
globals,
|
||||||
@@ -21,6 +16,8 @@ const Sidebar = (props) => {
|
|||||||
},
|
},
|
||||||
} = config;
|
} = config;
|
||||||
|
|
||||||
|
const location = useLocation();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<aside className="sidebar">
|
<aside className="sidebar">
|
||||||
<Link to="/">
|
<Link to="/">
|
||||||
@@ -37,7 +34,7 @@ const Sidebar = (props) => {
|
|||||||
</NavLink>
|
</NavLink>
|
||||||
{collections && Object.keys(collections).map((key, i) => {
|
{collections && Object.keys(collections).map((key, i) => {
|
||||||
const href = `${admin}/collections/${collections[key].slug}`;
|
const href = `${admin}/collections/${collections[key].slug}`;
|
||||||
const classes = props.location.pathname.indexOf(href) > -1
|
const classes = location.pathname.indexOf(href) > -1
|
||||||
? 'active'
|
? 'active'
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
@@ -57,7 +54,7 @@ const Sidebar = (props) => {
|
|||||||
<nav>
|
<nav>
|
||||||
{globals && globals.map((global, i) => {
|
{globals && globals.map((global, i) => {
|
||||||
const href = `${admin}/globals/${global.slug}`;
|
const href = `${admin}/globals/${global.slug}`;
|
||||||
const classes = props.location.pathname.indexOf(href) > -1
|
const classes = location.pathname.indexOf(href) > -1
|
||||||
? 'active'
|
? 'active'
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
@@ -77,4 +74,4 @@ const Sidebar = (props) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default withRouter(connect(mapState)(Sidebar));
|
export default Sidebar;
|
||||||
|
|||||||
@@ -1,66 +1,64 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { Link } from 'react-router-dom';
|
||||||
import { Link, withRouter } from 'react-router-dom';
|
import config from 'payload-config';
|
||||||
import Arrow from '../../graphics/Arrow';
|
|
||||||
import qs from 'qs';
|
import qs from 'qs';
|
||||||
|
import { useLocale } from '../../utilities/Locale';
|
||||||
|
import { useSearchParams } from '../../utilities/SearchParams';
|
||||||
|
import Arrow from '../../graphics/Arrow';
|
||||||
|
|
||||||
import './index.scss';
|
import './index.scss';
|
||||||
|
|
||||||
const mapState = state => ({
|
const baseClass = 'localizer';
|
||||||
config: state.common.config,
|
|
||||||
locale: state.common.locale,
|
|
||||||
searchParams: state.common.searchParams
|
|
||||||
})
|
|
||||||
|
|
||||||
class Localizer extends Component {
|
const Localizer = () => {
|
||||||
|
const [active, setActive] = useState(false);
|
||||||
|
const activeLocale = useLocale();
|
||||||
|
const searchParams = useSearchParams();
|
||||||
|
|
||||||
constructor() {
|
const { locales } = config.localization ? config.localization : { locales: [] };
|
||||||
super();
|
|
||||||
|
|
||||||
this.state = {
|
if (locales.length <= 1) return null;
|
||||||
active: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
toggleActive = () =>
|
const classes = [
|
||||||
this.setState({ active: !this.state.active })
|
baseClass,
|
||||||
|
active && `${baseClass}--active`,
|
||||||
|
].filter(Boolean).join(' ');
|
||||||
|
|
||||||
render() {
|
return (
|
||||||
let locales = [];
|
<div className={classes}>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => setActive(!active)}
|
||||||
|
className={`${baseClass}__current`}
|
||||||
|
>
|
||||||
|
<Arrow />
|
||||||
|
{activeLocale}
|
||||||
|
</button>
|
||||||
|
<ul>
|
||||||
|
{locales.map((locale, i) => {
|
||||||
|
if (activeLocale === locale) return null;
|
||||||
|
|
||||||
if (this.props.config && this.props.config.localization) locales = this.props.config.localization.locales;
|
const newParams = {
|
||||||
|
...searchParams,
|
||||||
|
locale,
|
||||||
|
};
|
||||||
|
|
||||||
if (locales.length <= 1) return null;
|
const search = qs.stringify(newParams);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`localizer${this.state.active ? ' active' : ''}`}>
|
<li key={i}>
|
||||||
<button onClick={this.toggleActive} className="current-locale">
|
<Link
|
||||||
<Arrow />{this.props.locale}
|
to={{ search }}
|
||||||
</button>
|
onClick={() => setActive(false)}
|
||||||
<ul>
|
>
|
||||||
{locales.map((locale, i) => {
|
{locale}
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
if (locale === this.props.locale) return null;
|
export default Localizer;
|
||||||
|
|
||||||
const newParams = {
|
|
||||||
...this.props.searchParams,
|
|
||||||
locale
|
|
||||||
};
|
|
||||||
|
|
||||||
const search = qs.stringify(newParams);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<li key={i}>
|
|
||||||
<Link to={{ search }} onClick={this.toggleActive}>
|
|
||||||
{locale}
|
|
||||||
</Link>
|
|
||||||
</li>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default withRouter(connect(mapState)(Localizer));
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
.localizer {
|
.localizer {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
.current-locale {
|
&__current {
|
||||||
@extend %uppercase-label;
|
@extend %uppercase-label;
|
||||||
@extend %btn-reset;
|
@extend %btn-reset;
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -43,7 +43,7 @@
|
|||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.active {
|
&--active {
|
||||||
svg {
|
svg {
|
||||||
transform: rotate(-90deg);
|
transform: rotate(-90deg);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,8 +72,7 @@ const StatusList = () => {
|
|||||||
|
|
||||||
export {
|
export {
|
||||||
StatusListProvider,
|
StatusListProvider,
|
||||||
StatusList,
|
|
||||||
useStatusList,
|
useStatusList,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Context;
|
export default StatusList;
|
||||||
|
|||||||
@@ -1,36 +1,74 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { useState, createContext, useContext } from 'react';
|
||||||
import { connect } from 'react-redux';
|
import PropTypes from 'prop-types';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import Arrow from '../../graphics/Arrow';
|
import Arrow from '../../graphics/Arrow';
|
||||||
|
|
||||||
import './index.scss';
|
import './index.scss';
|
||||||
|
|
||||||
const mapStateToProps = state => ({
|
const Context = createContext({});
|
||||||
nav: state.common.stepNav
|
|
||||||
});
|
|
||||||
|
|
||||||
class StepNav extends Component {
|
const StepNavProvider = ({ children }) => {
|
||||||
render() {
|
const [nav, setNav] = useState([]);
|
||||||
const dashboardLabel = <span>Dashboard</span>;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<nav className="step-nav">
|
<Context.Provider value={{
|
||||||
{this.props.nav.length > 0
|
nav,
|
||||||
? <Link to="/">{dashboardLabel}<Arrow /></Link>
|
setNav,
|
||||||
: dashboardLabel
|
}}
|
||||||
}
|
>
|
||||||
{this.props.nav.map((item, i) => {
|
{children}
|
||||||
const StepLabel = <span key={i}>{item.label}</span>;
|
</Context.Provider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const Step = this.props.nav.length === i + 1
|
StepNavProvider.propTypes = {
|
||||||
? StepLabel
|
children: PropTypes.oneOfType([
|
||||||
: <Link to={item.url} key={i}>{StepLabel}<Arrow /></Link>;
|
PropTypes.arrayOf(PropTypes.node),
|
||||||
|
PropTypes.node,
|
||||||
|
]).isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
return Step;
|
const useStepNav = () => useContext(Context);
|
||||||
})}
|
|
||||||
</nav>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default connect(mapStateToProps)(StepNav);
|
const StepNav = () => {
|
||||||
|
const dashboardLabel = <span>Dashboard</span>;
|
||||||
|
const { nav } = useStepNav();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<nav className="step-nav">
|
||||||
|
{nav.length > 0
|
||||||
|
? (
|
||||||
|
<Link to="/">
|
||||||
|
{dashboardLabel}
|
||||||
|
<Arrow />
|
||||||
|
</Link>
|
||||||
|
)
|
||||||
|
: dashboardLabel
|
||||||
|
}
|
||||||
|
{nav.map((item, i) => {
|
||||||
|
const StepLabel = <span key={i}>{item.label}</span>;
|
||||||
|
|
||||||
|
const Step = nav.length === i + 1
|
||||||
|
? StepLabel
|
||||||
|
: (
|
||||||
|
<Link
|
||||||
|
to={item.url}
|
||||||
|
key={i}
|
||||||
|
>
|
||||||
|
{StepLabel}
|
||||||
|
<Arrow />
|
||||||
|
</Link>
|
||||||
|
);
|
||||||
|
|
||||||
|
return Step;
|
||||||
|
})}
|
||||||
|
</nav>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export {
|
||||||
|
StepNavProvider,
|
||||||
|
useStepNav,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default StepNav;
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import React, { createContext, useContext } from 'react';
|
import React, { createContext, useContext } from 'react';
|
||||||
import config from 'payload-config';
|
import config from 'payload-config';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import searchParamsContext from '../SearchParams';
|
import { useSearchParams } from '../SearchParams';
|
||||||
|
|
||||||
const Context = createContext({});
|
const Context = createContext({});
|
||||||
|
|
||||||
export const LocaleProvider = ({ children }) => {
|
export const LocaleProvider = ({ children }) => {
|
||||||
const searchParams = useContext(searchParamsContext);
|
const searchParams = useSearchParams();
|
||||||
|
|
||||||
let activeLocale = null;
|
let activeLocale = null;
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { createContext } from 'react';
|
import React, { createContext, useContext } from 'react';
|
||||||
import { useLocation } from 'react-router-dom';
|
import { useLocation } from 'react-router-dom';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import qs from 'qs';
|
import qs from 'qs';
|
||||||
@@ -27,4 +27,4 @@ SearchParamsProvider.propTypes = {
|
|||||||
]).isRequired,
|
]).isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Context;
|
export const useSearchParams = () => useContext(Context);
|
||||||
|
|||||||
@@ -1,22 +0,0 @@
|
|||||||
import { Component } from 'react';
|
|
||||||
import { connect } from 'react-redux';
|
|
||||||
|
|
||||||
const mapDispatchToProps = dispatch => ({
|
|
||||||
set: nav => dispatch({ type: 'SET_STEP_NAV', payload: nav })
|
|
||||||
});
|
|
||||||
|
|
||||||
class SetStepNav extends Component {
|
|
||||||
componentDidMount() {
|
|
||||||
this.props.set(this.props.nav);
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidUpdate(prevProps) {
|
|
||||||
if (prevProps.nav !== this.props.nav) {
|
|
||||||
this.props.set(this.props.nav);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render() { return null; }
|
|
||||||
}
|
|
||||||
|
|
||||||
export default connect(null, mapDispatchToProps)(SetStepNav);
|
|
||||||
@@ -14,9 +14,23 @@ const handleAjaxResponse = (res) => {
|
|||||||
cookies.set('token', res.token, { path: '/' });
|
cookies.set('token', res.token, { path: '/' });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const passwordField = {
|
||||||
|
name: 'password',
|
||||||
|
label: 'Password',
|
||||||
|
type: 'password',
|
||||||
|
};
|
||||||
|
|
||||||
const baseClass = 'create-first-user';
|
const baseClass = 'create-first-user';
|
||||||
|
|
||||||
const CreateFirstUser = () => {
|
const CreateFirstUser = () => {
|
||||||
|
const fields = [...config.user.fields];
|
||||||
|
|
||||||
|
if (config.user.passwordIndex) {
|
||||||
|
fields.splice(config.user.passwordIndex, 0, passwordField);
|
||||||
|
} else {
|
||||||
|
fields.push(passwordField);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ContentBlock className={baseClass}>
|
<ContentBlock className={baseClass}>
|
||||||
<div className={`${baseClass}__wrap`}>
|
<div className={`${baseClass}__wrap`}>
|
||||||
@@ -25,9 +39,9 @@ const CreateFirstUser = () => {
|
|||||||
<Form
|
<Form
|
||||||
handleAjaxResponse={handleAjaxResponse}
|
handleAjaxResponse={handleAjaxResponse}
|
||||||
method="POST"
|
method="POST"
|
||||||
action="/first-user"
|
action="/first-register"
|
||||||
>
|
>
|
||||||
<RenderFields fields={config.user.fields} />
|
<RenderFields fields={fields} />
|
||||||
<FormSubmit>Create</FormSubmit>
|
<FormSubmit>Create</FormSubmit>
|
||||||
</Form>
|
</Form>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ class ExtendableError extends Error {
|
|||||||
* Class representing an API error.
|
* Class representing an API error.
|
||||||
* @extends ExtendableError
|
* @extends ExtendableError
|
||||||
*/
|
*/
|
||||||
export class APIError extends ExtendableError {
|
class APIError extends ExtendableError {
|
||||||
/**
|
/**
|
||||||
* Creates an API error.
|
* Creates an API error.
|
||||||
* @param {string} message - Error message.
|
* @param {string} message - Error message.
|
||||||
@@ -30,3 +30,5 @@ export class APIError extends ExtendableError {
|
|||||||
super(message, status, isPublic);
|
super(message, status, isPublic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default APIError;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { APIError } from './APIError';
|
import APIError from './APIError';
|
||||||
|
|
||||||
export class DuplicateCollection extends APIError {
|
export class DuplicateCollection extends APIError {
|
||||||
constructor(config) {
|
constructor(config) {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { APIError } from './APIError';
|
import APIError from './APIError';
|
||||||
|
|
||||||
export class DuplicateGlobal extends APIError {
|
export class DuplicateGlobal extends APIError {
|
||||||
constructor(config) {
|
constructor(config) {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { APIError } from './APIError';
|
import APIError from './APIError';
|
||||||
|
|
||||||
export class MissingCollectionLabel extends APIError {
|
export class MissingCollectionLabel extends APIError {
|
||||||
constructor(config) {
|
constructor(config) {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { APIError } from './APIError';
|
import APIError from './APIError';
|
||||||
|
|
||||||
export class MissingGlobalLabel extends APIError {
|
export class MissingGlobalLabel extends APIError {
|
||||||
constructor(config) {
|
constructor(config) {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import httpStatus from 'http-status';
|
import httpStatus from 'http-status';
|
||||||
import { APIError } from './APIError';
|
import APIError from './APIError';
|
||||||
|
|
||||||
export class NotFound extends APIError {
|
export class NotFound extends APIError {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
|||||||
Reference in New Issue
Block a user