2019-11-06 13:02:48 +01:00
|
|
|
import React, { useCallback, useState } from 'react';
|
2019-11-18 18:14:36 +01:00
|
|
|
|
2019-11-04 09:00:59 +01:00
|
|
|
import { get } from 'lodash';
|
2019-10-29 18:03:06 +01:00
|
|
|
import PropTypes from 'prop-types';
|
2019-11-04 10:10:38 +01:00
|
|
|
import { FormattedMessage } from 'react-intl';
|
|
|
|
|
import pluginId from '../../pluginId';
|
2019-11-04 09:00:59 +01:00
|
|
|
import useDataManager from '../../hooks/useDataManager';
|
2019-11-04 10:10:38 +01:00
|
|
|
import DynamicComponentCard from '../DynamicComponentCard';
|
2019-11-06 16:29:19 +01:00
|
|
|
import FieldComponent from '../FieldComponent';
|
2019-11-04 09:00:59 +01:00
|
|
|
import Button from './Button';
|
2019-11-04 10:10:38 +01:00
|
|
|
import ComponentsPicker from './ComponentsPicker';
|
2019-11-06 16:29:19 +01:00
|
|
|
import ComponentWrapper from './ComponentWrapper';
|
|
|
|
|
import Label from './Label';
|
|
|
|
|
import RoundCTA from './RoundCTA';
|
2019-11-04 09:00:59 +01:00
|
|
|
import Wrapper from './Wrapper';
|
2019-10-29 18:03:06 +01:00
|
|
|
|
2019-11-08 16:17:20 +01:00
|
|
|
const DynamicZone = ({ max, min, name }) => {
|
2019-11-18 18:14:36 +01:00
|
|
|
const [isOpen, setIsOpen] = useState(true);
|
2019-11-04 14:23:46 +01:00
|
|
|
const {
|
|
|
|
|
addComponentToDynamicZone,
|
2019-11-08 16:17:20 +01:00
|
|
|
formErrors,
|
2019-11-04 14:23:46 +01:00
|
|
|
layout,
|
2019-11-06 13:02:48 +01:00
|
|
|
modifiedData,
|
2019-11-06 16:29:19 +01:00
|
|
|
moveComponentUp,
|
|
|
|
|
moveComponentDown,
|
|
|
|
|
removeComponentFromDynamicZone,
|
2019-11-04 14:23:46 +01:00
|
|
|
} = useDataManager();
|
2019-11-18 18:14:36 +01:00
|
|
|
|
2019-11-06 13:02:48 +01:00
|
|
|
const getDynamicDisplayedComponents = useCallback(() => {
|
|
|
|
|
return get(modifiedData, [name], []).map(data => data.__component);
|
|
|
|
|
}, [modifiedData, name]);
|
2019-11-04 14:23:46 +01:00
|
|
|
|
2019-11-08 16:17:20 +01:00
|
|
|
const dynamicZoneErrors = Object.keys(formErrors)
|
|
|
|
|
.filter(key => {
|
|
|
|
|
return key === name;
|
|
|
|
|
})
|
|
|
|
|
.map(key => formErrors[key]);
|
|
|
|
|
|
2019-11-04 09:00:59 +01:00
|
|
|
const dynamicZoneAvailableComponents = get(
|
|
|
|
|
layout,
|
|
|
|
|
['schema', 'attributes', name, 'components'],
|
|
|
|
|
[]
|
|
|
|
|
);
|
2019-11-18 18:14:36 +01:00
|
|
|
|
2019-11-06 16:29:19 +01:00
|
|
|
const metas = get(layout, ['metadatas', name, 'edit'], {});
|
|
|
|
|
const dynamicDisplayedComponentsLength = getDynamicDisplayedComponents()
|
|
|
|
|
.length;
|
2019-11-08 16:17:20 +01:00
|
|
|
const missingComponentNumber = min - dynamicDisplayedComponentsLength;
|
|
|
|
|
const hasError = dynamicZoneErrors.length > 0;
|
|
|
|
|
const hasMinError =
|
|
|
|
|
dynamicZoneErrors.length > 0 &&
|
|
|
|
|
get(dynamicZoneErrors, [0, 'id'], '').includes('min') &&
|
|
|
|
|
!isOpen;
|
2019-11-04 09:00:59 +01:00
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<>
|
2019-11-06 16:29:19 +01:00
|
|
|
{getDynamicDisplayedComponents().length > 0 && (
|
|
|
|
|
<Label>
|
|
|
|
|
<p>{metas.label}</p>
|
|
|
|
|
<p>{metas.description}</p>
|
|
|
|
|
</Label>
|
|
|
|
|
)}
|
|
|
|
|
{getDynamicDisplayedComponents().map((componentUid, index) => {
|
|
|
|
|
// TODO when available
|
|
|
|
|
// const icon = getDynamicComponentSchemaData(componentUid);
|
|
|
|
|
|
|
|
|
|
const showDownIcon =
|
|
|
|
|
dynamicDisplayedComponentsLength > 0 &&
|
|
|
|
|
index < dynamicDisplayedComponentsLength - 1;
|
|
|
|
|
const showUpIcon = dynamicDisplayedComponentsLength > 0 && index > 0;
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<ComponentWrapper key={index}>
|
|
|
|
|
{showDownIcon && (
|
|
|
|
|
<RoundCTA
|
|
|
|
|
style={{ top: -15, right: 30 }}
|
|
|
|
|
onClick={() => moveComponentDown(name, index)}
|
|
|
|
|
>
|
|
|
|
|
<i className="fa fa-arrow-down" />
|
|
|
|
|
</RoundCTA>
|
|
|
|
|
)}
|
|
|
|
|
{showUpIcon && (
|
|
|
|
|
<RoundCTA
|
|
|
|
|
style={{ top: -15, right: 45 }}
|
|
|
|
|
onClick={() => moveComponentUp(name, index)}
|
|
|
|
|
>
|
|
|
|
|
<i className="fa fa-arrow-up" />
|
|
|
|
|
</RoundCTA>
|
|
|
|
|
)}
|
|
|
|
|
<RoundCTA
|
|
|
|
|
style={{ top: -15, right: 0 }}
|
|
|
|
|
onClick={() => removeComponentFromDynamicZone(name, index)}
|
|
|
|
|
>
|
|
|
|
|
<i className="fa fa-trash" />
|
|
|
|
|
</RoundCTA>
|
|
|
|
|
<FieldComponent
|
|
|
|
|
componentUid={componentUid}
|
|
|
|
|
label=""
|
|
|
|
|
name={`${name}.${index}`}
|
|
|
|
|
isFromDynamicZone
|
|
|
|
|
/>
|
|
|
|
|
</ComponentWrapper>
|
|
|
|
|
);
|
|
|
|
|
})}
|
2019-11-18 18:14:36 +01:00
|
|
|
<Wrapper>
|
2019-11-04 09:00:59 +01:00
|
|
|
<Button
|
|
|
|
|
type="button"
|
2019-11-18 18:14:36 +01:00
|
|
|
hasError={hasError}
|
|
|
|
|
className={isOpen && 'isOpen'}
|
2019-11-08 16:17:20 +01:00
|
|
|
onClick={() => {
|
|
|
|
|
if (dynamicDisplayedComponentsLength < max) {
|
|
|
|
|
setIsOpen(prev => !prev);
|
|
|
|
|
} else {
|
|
|
|
|
strapi.notification.info(
|
|
|
|
|
`${pluginId}.components.components.notification.info.maximum-requirement`
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}}
|
2019-11-05 09:07:03 +01:00
|
|
|
/>
|
2019-11-04 10:10:38 +01:00
|
|
|
|
|
|
|
|
<div className="info">
|
|
|
|
|
<FormattedMessage
|
|
|
|
|
id={`${pluginId}.components.DynamicZone.add-compo`}
|
|
|
|
|
values={{ componentName: name }}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
2019-11-08 16:17:20 +01:00
|
|
|
{hasMinError && <div> {missingComponentNumber} missing components</div>}
|
2019-11-04 10:10:38 +01:00
|
|
|
<ComponentsPicker isOpen={isOpen}>
|
2019-11-18 18:14:36 +01:00
|
|
|
<div>
|
|
|
|
|
<p className="componentPickerTitle">
|
|
|
|
|
<FormattedMessage
|
|
|
|
|
id={`${pluginId}.components.DynamicZone.pick-compo`}
|
2019-11-04 14:23:46 +01:00
|
|
|
/>
|
2019-11-18 18:14:36 +01:00
|
|
|
</p>
|
|
|
|
|
<div className="componentsList">
|
|
|
|
|
{dynamicZoneAvailableComponents.map(componentUid => {
|
|
|
|
|
return (
|
|
|
|
|
<DynamicComponentCard
|
|
|
|
|
key={componentUid}
|
|
|
|
|
componentUid={componentUid}
|
|
|
|
|
icon={''}
|
|
|
|
|
onClick={() => {
|
|
|
|
|
setIsOpen(false);
|
|
|
|
|
const shouldCheckErrors = hasError;
|
|
|
|
|
addComponentToDynamicZone(
|
|
|
|
|
name,
|
|
|
|
|
componentUid,
|
|
|
|
|
shouldCheckErrors
|
|
|
|
|
);
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
);
|
|
|
|
|
})}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
2019-11-04 10:10:38 +01:00
|
|
|
</ComponentsPicker>
|
2019-11-04 09:00:59 +01:00
|
|
|
</Wrapper>
|
|
|
|
|
</>
|
|
|
|
|
);
|
2019-10-29 18:03:06 +01:00
|
|
|
};
|
|
|
|
|
|
2019-11-08 16:17:20 +01:00
|
|
|
DynamicZone.defaultProps = {
|
|
|
|
|
max: Infinity,
|
|
|
|
|
min: -Infinity,
|
|
|
|
|
};
|
|
|
|
|
|
2019-10-29 18:03:06 +01:00
|
|
|
DynamicZone.propTypes = {
|
2019-11-08 16:29:51 +01:00
|
|
|
max: PropTypes.number,
|
|
|
|
|
min: PropTypes.number,
|
2019-10-29 18:03:06 +01:00
|
|
|
name: PropTypes.string.isRequired,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export { DynamicZone };
|
2019-11-04 14:23:46 +01:00
|
|
|
export default DynamicZone;
|