@craftercms/studio-ui
Version:
Services, components, models & utils to build CrafterCMS authoring extensions.
203 lines (201 loc) • 7.28 kB
JavaScript
/*
* 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;