UNPKG

@craftercms/studio-ui

Version:

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

170 lines (168 loc) 6.72 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 React, { useCallback, useEffect, useMemo, useState } from 'react'; import { useIntl } from 'react-intl'; import { nnou } from '../../utils/object'; import { ErrorBoundary } from '../ErrorBoundary/ErrorBoundary'; import LoadingState from '../LoadingState/LoadingState'; import { componentInstanceDragEnded, componentInstanceDragStarted, fetchComponentsByContentType, setContentTypeFilter, setPreviewEditMode } from '../../state/actions/preview'; import { useDispatch } from 'react-redux'; import SearchBar from '../SearchBar/SearchBar'; import { getHostToGuestBus } from '../../utils/subjects'; import Select from '@mui/material/Select'; import MenuItem from '@mui/material/MenuItem'; import { useSelection } from '../../hooks/useSelection'; import { useDebouncedInput } from '../../hooks/useDebouncedInput'; import translations from './translations'; import useStyles from './styles'; import PreviewBrowseComponentsPanelUI from './PreviewBrowseComponentsPanelUI'; import { useActiveSiteId } from '../../hooks/useActiveSiteId'; export function PreviewBrowseComponentsPanel() { const { classes } = useStyles(); const dispatch = useDispatch(); const siteId = useActiveSiteId(); const componentsState = useSelection((state) => state.preview.components); const [keyword, setKeyword] = useState(componentsState.query.keywords); const contentTypesBranch = useSelection((state) => state.contentTypes); const editMode = useSelection((state) => state.preview.editMode); const contentTypes = contentTypesBranch.byId ? Object.values(contentTypesBranch.byId).filter( (contentType) => contentType.type === 'component' && !contentType.id.includes('/level-descriptor') ) : null; const items = useMemo(() => { var _a, _b; let items = (_b = (_a = componentsState.page[componentsState.pageNumber]) === null || _a === void 0 ? void 0 : _a.map((id) => componentsState.byId[id])) !== null && _b !== void 0 ? _b : []; if (componentsState.contentTypeFilter !== 'all') { items = items.filter((item) => item.craftercms.contentTypeId === componentsState.contentTypeFilter); } return items; }, [componentsState]); useEffect(() => { if (siteId && contentTypesBranch.isFetching === false) { dispatch(fetchComponentsByContentType({})); } }, [siteId, contentTypesBranch, dispatch]); const { formatMessage } = useIntl(); const hostToGuest$ = getHostToGuestBus(); const onDragStart = (item) => { if (!editMode) { dispatch(setPreviewEditMode({ editMode: true })); } hostToGuest$.next({ type: componentInstanceDragStarted.type, payload: { instance: item, contentType: contentTypesBranch.byId[item.craftercms.contentTypeId] } }); }; const onDragEnd = () => hostToGuest$.next({ type: componentInstanceDragEnded.type }); const onSearch = useCallback( (keywords) => dispatch(fetchComponentsByContentType({ keywords, offset: 0 })), [dispatch] ); const onSearch$ = useDebouncedInput(onSearch, 600); function onPageChanged(newPage) { dispatch(fetchComponentsByContentType({ offset: newPage })); } function onRowsPerPageChange(e) { dispatch(fetchComponentsByContentType({ offset: 0, limit: e.target.value })); } function handleSearchKeyword(keyword) { setKeyword(keyword); onSearch$.next(keyword); } function handleSelectChange(value) { dispatch(setContentTypeFilter(value)); } return React.createElement( React.Fragment, null, React.createElement( ErrorBoundary, null, React.createElement( 'div', { className: classes.search }, React.createElement(SearchBar, { placeholder: formatMessage(translations.filter), showActionButton: Boolean(keyword), onChange: handleSearchKeyword, keyword: keyword, autoFocus: true }), contentTypes && React.createElement( Select, { size: 'small', value: componentsState.contentTypeFilter, displayEmpty: true, className: classes.select, onChange: (event) => handleSelectChange(event.target.value) }, React.createElement(MenuItem, { value: 'all' }, formatMessage(translations.allContentTypes)), contentTypes.map((contentType, i) => { return React.createElement(MenuItem, { value: contentType.id, key: i }, contentType.name); }) ) ), componentsState.isFetching ? React.createElement(LoadingState, { title: formatMessage(translations.loading) }) : ((nnou(componentsState.pageNumber) && nnou(componentsState.page[componentsState.pageNumber])) || !componentsState.contentTypeFilter) && React.createElement(PreviewBrowseComponentsPanelUI, { items: items, count: componentsState.count, pageNumber: componentsState.pageNumber, limit: componentsState.query.limit, onPageChanged: onPageChanged, onRowsPerPageChange: onRowsPerPageChange, onDragStart: onDragStart, onDragEnd: onDragEnd }) ) ); } export default PreviewBrowseComponentsPanel;