UNPKG

@craftercms/studio-ui

Version:

Services, components, models & utils to build CrafterCMS authoring extensions.

203 lines (201 loc) 7.28 kB
/* * Copyright (C) 2007-2022 Crafter Software Corporation. All Rights Reserved. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 as published by * the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ /* * Copyright (C) 2007-2022 Crafter Software Corporation. All Rights Reserved. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as published by * the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ import { useActiveSiteId } from '../../hooks/useActiveSiteId'; import { useDispatch } from 'react-redux'; import React, { useEffect, useMemo, useState } from 'react'; import { fetchLegacyContentTypes } from '../../services/contentTypes'; import { showErrorDialog } from '../../state/reducers/dialogs/error'; import { useLogicResource } from '../../hooks/useLogicResource'; import { useSubject } from '../../hooks/useSubject'; import { debounceTime } from 'rxjs/operators'; import DialogBody from '../DialogBody/DialogBody'; import { Box, Checkbox, FormControlLabel } from '@mui/material'; import SingleItemSelector from '../SingleItemSelector'; import { FormattedMessage } from 'react-intl'; import SearchBar from '../SearchBar/SearchBar'; import { SuspenseWithEmptyState } from '../Suspencified/Suspencified'; import { ContentTypesGrid, ContentTypesLoader } from '../NewContentDialog'; import DialogFooter from '../DialogFooter/DialogFooter'; import { makeStyles } from 'tss-react/mui'; const useStyles = makeStyles()(() => ({ compact: { marginRight: 'auto', paddingLeft: '20px' }, dialogContent: { minHeight: 455 }, searchBox: { minWidth: '33%' }, emptyStateImg: { width: 250, marginBottom: 17 } })); export function ChangeContentTypeDialogContainer(props) { const { item, onContentTypeSelected, compact = false, rootPath, selectedContentType } = props; const site = useActiveSiteId(); const dispatch = useDispatch(); const { classes } = useStyles(); const [isCompact, setIsCompact] = useState(compact); const [openSelector, setOpenSelector] = useState(false); const [selectedItem, setSelectedItem] = useState(item); const [contentTypes, setContentTypes] = useState(); const [keyword, setKeyword] = useState(''); const [debounceKeyword, setDebounceKeyword] = useState(''); const onSelectedContentType = (contentType) => { onContentTypeSelected === null || onContentTypeSelected === void 0 ? void 0 : onContentTypeSelected({ newContentTypeId: contentType.form }); }; useEffect(() => { if (selectedItem.path) { fetchLegacyContentTypes(site, selectedItem.path).subscribe( (response) => { setContentTypes( response.filter( (contentType) => contentType.type === selectedItem.systemType && contentType.name !== selectedItem.contentTypeId ) ); }, (response) => { dispatch(showErrorDialog({ error: response })); } ); } }, [dispatch, selectedItem, site]); const resource = useLogicResource( useMemo(() => ({ contentTypes, debounceKeyword }), [contentTypes, debounceKeyword]), { shouldResolve: ({ contentTypes }) => Boolean(contentTypes), shouldReject: () => null, shouldRenew: (source, resource) => resource.complete, resultSelector: ({ contentTypes, debounceKeyword }) => { return contentTypes.filter((contentType) => contentType.label.toLowerCase().includes(debounceKeyword.toLowerCase()) ); }, errorSelector: () => null } ); const onSearch$ = useSubject(); useEffect(() => { onSearch$.pipe(debounceTime(400)).subscribe((keywords) => { setDebounceKeyword(keywords); }); }); const onSearch = (keyword) => { onSearch$.next(keyword); setKeyword(keyword); }; return React.createElement( React.Fragment, null, React.createElement( DialogBody, { classes: { root: classes.dialogContent } }, React.createElement( Box, { display: 'flex', justifyContent: 'space-between', alignItems: 'center' }, React.createElement( Box, null, React.createElement(SingleItemSelector, { label: React.createElement(FormattedMessage, { id: 'words.item', defaultMessage: 'Item' }), open: openSelector, onClose: () => setOpenSelector(false), onDropdownClick: () => setOpenSelector(!openSelector), rootPath: rootPath, selectedItem: selectedItem, onItemClicked: (item) => { setOpenSelector(false); setSelectedItem(item); } }) ), React.createElement( Box, { className: classes.searchBox }, React.createElement(SearchBar, { onChange: onSearch, keyword: keyword, autoFocus: true, showActionButton: Boolean(keyword) }) ) ), React.createElement( SuspenseWithEmptyState, { resource: resource, suspenseProps: { fallback: React.createElement(ContentTypesLoader, { numOfItems: 6, isCompact: isCompact }) }, withEmptyStateProps: { emptyStateProps: { classes: { image: classes.emptyStateImg }, title: React.createElement(FormattedMessage, { id: 'changeContentTypeDialog.emptyStateMessage', defaultMessage: 'No Content Types Found' }) } } }, React.createElement(ContentTypesGrid, { resource: resource, isCompact: isCompact, onTypeOpen: onSelectedContentType, selectedContentType: selectedContentType }) ) ), React.createElement( DialogFooter, null, React.createElement(FormControlLabel, { className: classes.compact, control: React.createElement(Checkbox, { checked: isCompact, onChange: () => setIsCompact(!isCompact), color: 'primary' }), label: React.createElement(FormattedMessage, { id: 'words.compact', defaultMessage: 'Compact' }) }) ) ); } export default ChangeContentTypeDialogContainer;