277 lines
9.9 KiB
JavaScript
Raw Normal View History

import React, { memo, useCallback, useMemo, useEffect, useReducer, useRef } from 'react';
2019-07-11 11:35:18 +02:00
import PropTypes from 'prop-types';
2019-10-30 14:47:12 +01:00
import { get } from 'lodash';
import { useHistory, useLocation, useRouteMatch } from 'react-router-dom';
2019-11-21 18:48:13 +01:00
import { BackHeader, LiLink } from 'strapi-helper-plugin';
2019-07-11 11:35:18 +02:00
import pluginId from '../../pluginId';
import Container from '../../components/Container';
import DynamicZone from '../../components/DynamicZone';
import FormWrapper from '../../components/FormWrapper';
import FieldComponent from '../../components/FieldComponent';
2019-10-30 15:32:29 +01:00
import Inputs from '../../components/Inputs';
2019-10-30 14:47:12 +01:00
import SelectWrapper from '../../components/SelectWrapper';
import getInjectedComponents from '../../utils/getComponents';
import EditViewDataManagerProvider from '../EditViewDataManagerProvider';
2019-10-31 11:57:40 +01:00
import EditViewProvider from '../EditViewProvider';
2019-10-30 14:47:12 +01:00
import Header from './Header';
2019-11-08 16:29:51 +01:00
import createAttributesLayout from './utils/createAttributesLayout';
import { LinkWrapper, SubWrapper } from './components';
2019-08-22 17:15:15 +02:00
import init from './init';
2019-07-11 11:35:18 +02:00
import reducer, { initialState } from './reducer';
/* eslint-disable react/no-array-index-key */
const EditView = ({ components, currentEnvironment, layouts, plugins, slug }) => {
const formatLayoutRef = useRef();
formatLayoutRef.current = createAttributesLayout;
// Retrieve push to programmatically navigate between views
const { push } = useHistory();
// Retrieve the search and the pathname
const { search, pathname } = useLocation();
const {
params: { contentType },
} = useRouteMatch('/plugins/content-manager/:contentType');
const isSingleType = contentType === 'singleType';
const [reducerState, dispatch] = useReducer(reducer, initialState, () => init(initialState));
const allLayoutData = useMemo(() => get(layouts, [slug], {}), [layouts, slug]);
const currentContentTypeLayoutData = useMemo(() => get(allLayoutData, ['contentType'], {}), [
allLayoutData,
2019-10-30 18:46:19 +01:00
]);
const currentContentTypeLayout = useMemo(
() => get(currentContentTypeLayoutData, ['layouts', 'edit'], []),
[currentContentTypeLayoutData]
);
const currentContentTypeLayoutRelations = useMemo(
() => get(currentContentTypeLayoutData, ['layouts', 'editRelations'], []),
[currentContentTypeLayoutData]
);
const currentContentTypeSchema = useMemo(
() => get(currentContentTypeLayoutData, ['schema'], {}),
[currentContentTypeLayoutData]
2019-07-11 11:35:18 +02:00
);
const getFieldMetas = useCallback(
fieldName => {
return get(currentContentTypeLayoutData, ['metadatas', fieldName, 'edit'], {});
},
[currentContentTypeLayoutData]
);
const getField = useCallback(
fieldName => {
return get(currentContentTypeSchema, ['attributes', fieldName], {});
},
[currentContentTypeSchema]
);
const getFieldType = useCallback(
fieldName => {
return get(getField(fieldName), ['type'], '');
},
[getField]
);
const getFieldComponentUid = useCallback(
fieldName => {
return get(getField(fieldName), ['component'], '');
},
[getField]
);
2019-11-19 16:17:15 +01:00
// Check if a block is a dynamic zone
const isDynamicZone = useCallback(
block => {
return block.every(subBlock => {
return subBlock.every(obj => getFieldType(obj.name) === 'dynamiczone');
});
},
[getFieldType]
);
2019-07-11 11:35:18 +02:00
useEffect(() => {
2019-09-16 17:47:43 +02:00
// Force state to be cleared when navigation from one entry to another
dispatch({ type: 'RESET_PROPS' });
dispatch({
type: 'SET_LAYOUT_DATA',
formattedContentTypeLayout: formatLayoutRef.current(
currentContentTypeLayout,
currentContentTypeSchema.attributes
),
});
}, [currentContentTypeLayout, currentContentTypeSchema.attributes]);
2019-09-16 17:47:43 +02:00
const { formattedContentTypeLayout, isDraggingComponent } = reducerState.toJS();
2019-09-13 14:46:31 +02:00
// We can't use the getQueryParameters helper here because the search
// can contain 'redirectUrl' several times since we can navigate between documents
const redirectURL = search
.split('redirectUrl=')
.filter((_, index) => index !== 0)
.join('');
const redirectToPreviousPage = () => push(redirectURL);
2019-09-13 14:46:31 +02:00
2019-07-11 11:35:18 +02:00
return (
<EditViewProvider
allLayoutData={allLayoutData}
2019-11-19 16:17:15 +01:00
components={components}
layout={currentContentTypeLayoutData}
isDraggingComponent={isDraggingComponent}
setIsDraggingComponent={() => {
dispatch({
type: 'SET_IS_DRAGGING_COMPONENT',
});
}}
unsetIsDraggingComponent={() => {
dispatch({
type: 'UNSET_IS_DRAGGING_COMPONENT',
});
}}
>
2019-10-30 19:06:40 +01:00
<EditViewDataManagerProvider
allLayoutData={allLayoutData}
redirectToPreviousPage={redirectToPreviousPage}
slug={slug}
>
<BackHeader onClick={redirectToPreviousPage} />
<Container className="container-fluid">
2019-10-30 14:47:12 +01:00
<Header />
2019-11-24 23:44:58 +01:00
<div className="row" style={{ paddingTop: 3 }}>
2019-11-26 16:15:59 +01:00
<div className="col-md-12 col-lg-9" style={{ marginBottom: 13 }}>
{formattedContentTypeLayout.map((block, blockIndex) => {
if (isDynamicZone(block)) {
const {
0: {
0: { name },
},
} = block;
const { max, min } = getField(name);
2019-08-09 13:23:39 +02:00
return <DynamicZone key={blockIndex} name={name} max={max} min={min} />;
}
2019-10-29 19:26:42 +01:00
return (
<FormWrapper key={blockIndex}>
{block.map((fieldsBlock, fieldsBlockIndex) => {
return (
<div className="row" key={fieldsBlockIndex}>
{fieldsBlock.map(({ name, size }, fieldIndex) => {
const isComponent = getFieldType(name) === 'component';
2019-10-30 19:06:40 +01:00
if (isComponent) {
const componentUid = getFieldComponentUid(name);
const isRepeatable = get(getField(name), 'repeatable', false);
const { max, min } = getField(name);
2019-11-08 13:18:45 +01:00
const label = get(getFieldMetas(name), 'label', componentUid);
2019-10-30 19:06:40 +01:00
return (
<FieldComponent
key={componentUid}
componentUid={componentUid}
isRepeatable={isRepeatable}
label={label}
2019-11-08 13:18:45 +01:00
max={max}
min={min}
name={name}
/>
2019-10-30 19:06:40 +01:00
);
}
2019-10-29 19:26:42 +01:00
return (
<div className={`col-${size}`} key={name}>
2019-10-30 15:32:29 +01:00
<Inputs
2019-10-29 19:26:42 +01:00
autoFocus={
blockIndex === 0 && fieldsBlockIndex === 0 && fieldIndex === 0
2019-10-29 19:26:42 +01:00
}
keys={name}
layout={currentContentTypeLayoutData}
name={name}
onChange={() => {}}
2019-10-30 15:32:29 +01:00
/>
2019-10-29 19:26:42 +01:00
</div>
);
})}
</div>
);
})}
</FormWrapper>
);
})}
2019-07-12 14:15:56 +02:00
</div>
2019-07-12 14:15:56 +02:00
<div className="col-md-12 col-lg-3">
{currentContentTypeLayoutRelations.length > 0 && (
<SubWrapper style={{ padding: '0 20px 1px', marginBottom: '25px' }}>
2019-07-22 11:41:27 +02:00
<div style={{ paddingTop: '22px' }}>
{currentContentTypeLayoutRelations.map(relationName => {
2019-10-30 14:47:12 +01:00
const relation = get(
currentContentTypeLayoutData,
['schema', 'attributes', relationName],
{}
);
const relationMetas = get(
currentContentTypeLayoutData,
['metadatas', relationName, 'edit'],
{}
);
2019-07-16 18:53:41 +02:00
2019-10-30 14:47:12 +01:00
return (
<SelectWrapper
{...relation}
{...relationMetas}
key={relationName}
name={relationName}
relationsType={relation.relationType}
/>
);
2019-07-16 18:53:41 +02:00
})}
2019-07-15 13:00:31 +02:00
</div>
2019-07-12 14:15:56 +02:00
</SubWrapper>
)}
2019-07-11 16:53:00 +02:00
<LinkWrapper>
<ul>
<LiLink
message={{
id: 'app.links.configure-view',
2019-07-11 16:53:00 +02:00
}}
icon="layout"
key={`${pluginId}.link`}
url={`${
isSingleType ? `${pathname}/` : ''
}ctm-configurations/edit-settings/content-types`}
2019-07-11 16:53:00 +02:00
onClick={() => {
// emitEvent('willEditContentTypeLayoutFromEditView');
2019-07-11 16:53:00 +02:00
}}
/>
2019-08-22 17:15:15 +02:00
{getInjectedComponents(
'editView',
2019-08-22 17:15:15 +02:00
'right.links',
plugins,
currentEnvironment,
slug
2019-08-22 17:15:15 +02:00
)}
2019-07-11 16:53:00 +02:00
</ul>
</LinkWrapper>
</div>
</div>
</Container>
</EditViewDataManagerProvider>
2019-07-17 17:39:43 +02:00
</EditViewProvider>
2019-07-11 11:35:18 +02:00
);
};
EditView.defaultProps = {
currentEnvironment: 'production',
emitEvent: () => {},
plugins: {},
};
2019-07-10 09:31:26 +02:00
2019-07-11 11:35:18 +02:00
EditView.propTypes = {
currentEnvironment: PropTypes.string,
2019-11-19 16:17:15 +01:00
components: PropTypes.array.isRequired,
emitEvent: PropTypes.func,
layouts: PropTypes.object.isRequired,
2019-10-24 17:08:52 +02:00
slug: PropTypes.string.isRequired,
2019-07-11 16:53:00 +02:00
plugins: PropTypes.object,
2019-07-11 11:35:18 +02:00
};
export { EditView };
2019-07-11 11:35:18 +02:00
export default memo(EditView);