318 lines
10 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 } 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 = ({
2019-11-19 16:17:15 +01:00
components,
2019-07-11 16:53:00 +02:00
currentEnvironment,
2019-07-11 11:35:18 +02:00
layouts,
2019-07-11 16:53:00 +02:00
plugins,
slug,
}) => {
const formatLayoutRef = useRef();
formatLayoutRef.current = createAttributesLayout;
// Retrieve push to programmatically navigate between views
const { push } = useHistory();
// Retrieve the search
const { search } = useLocation();
// eslint-disable-next-line react-hooks/exhaustive-deps
2019-07-11 11:35:18 +02:00
const [reducerState, dispatch] = useReducer(reducer, initialState, () =>
init(initialState)
);
2019-10-30 18:46:19 +01:00
const allLayoutData = useMemo(() => get(layouts, [slug], {}), [
layouts,
slug,
]);
const currentContentTypeLayoutData = useMemo(
2019-10-30 18:46:19 +01:00
() => get(allLayoutData, ['contentType'], {}),
[allLayoutData]
);
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) => {
2019-10-30 19:06:40 +01:00
const isComponent =
getFieldType(name) === 'component';
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
}
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 && (
2019-07-12 14:15:56 +02:00
<SubWrapper
2019-12-06 18:27:07 +01:00
style={{ padding: '0 20px 1px', marginBottom: '25px' }}
2019-07-12 14:15:56 +02:00
>
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="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);