UNPKG

@plone/volto

Version:
141 lines (129 loc) 4.27 kB
/** * Document view component. * @module components/theme/View/DefaultView */ import React from 'react'; import PropTypes from 'prop-types'; import { Container as SemanticContainer, Segment, Grid, Label, } from 'semantic-ui-react'; import config from '@plone/volto/registry'; import { getSchema } from '@plone/volto/actions/schema/schema'; import { getWidget } from '@plone/volto/helpers/Widget/utils'; import RenderBlocks from '@plone/volto/components/theme/View/RenderBlocks'; import { hasBlocksData } from '@plone/volto/helpers/Blocks/Blocks'; import { getBaseUrl } from '@plone/volto/helpers/Url/Url'; import { useDispatch, useSelector } from 'react-redux'; import isEqual from 'lodash/isEqual'; /** * Component to display the default view. * @function DefaultView * @param {Object} content Content object. * @returns {string} Markup of the component. */ const DefaultView = (props) => { const { content, location } = props; const path = getBaseUrl(location?.pathname || ''); const dispatch = useDispatch(); const { views } = config.widgets; const contentSchema = useSelector((state) => state.schema?.schema); const fieldsetsToExclude = [ 'categorization', 'dates', 'ownership', 'settings', ]; const fieldsets = contentSchema?.fieldsets.filter( (fs) => !fieldsetsToExclude.includes(fs.id), ); // TL;DR: There is a flash of the non block-based view because of the reset // of the content on route change. Subscribing to the content change at this // level has nasty implications, so we can't watch the Redux state for loaded // content flag here (because it forces an additional component update) // Instead, we can watch if the content is "empty", but this has a drawback // since the locking mechanism inserts a `lock` key before the content is there. // So "empty" means `content` is present, but only with a `lock` key, thus the next // ugly condition comes to life const contentLoaded = content && !isEqual(Object.keys(content), ['lock']); React.useEffect(() => { content?.['@type'] && !hasBlocksData(content) && dispatch(getSchema(content['@type'], location.pathname)); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); const Container = config.getComponent({ name: 'Container' }).component || SemanticContainer; // If the content is not yet loaded, then do not show anything return contentLoaded ? ( hasBlocksData(content) ? ( <Container id="page-document"> <RenderBlocks {...props} path={path} /> </Container> ) : ( <Container id="page-document"> {fieldsets?.map((fs) => { return ( <div className="fieldset" key={fs.id}> {fs.id !== 'default' && <h2>{fs.title}</h2>} {fs.fields?.map((f, key) => { let field = { ...contentSchema?.properties[f], id: f, widget: getWidget(f, contentSchema?.properties[f]), }; let Widget = views?.getWidget(field); return f !== 'title' ? ( <Grid celled="internally" key={key}> <Grid.Row> <Label title={field.id}>{field.title}:</Label> </Grid.Row> <Grid.Row> <Segment basic> <Widget value={content[f]} /> </Segment> </Grid.Row> </Grid> ) : ( <Widget key={key} value={content[f]} /> ); })} </div> ); })} </Container> ) ) : null; }; /** * Property types. * @property {Object} propTypes Property types. * @static */ DefaultView.propTypes = { /** * Content of the object */ content: PropTypes.shape({ /** * Title of the object */ title: PropTypes.string, /** * Description of the object */ description: PropTypes.string, /** * Text of the object */ text: PropTypes.shape({ /** * Data of the text of the object */ data: PropTypes.string, }), }).isRequired, }; export default DefaultView;