@craftercms/studio-ui
Version:
Services, components, models & utils to build CrafterCMS authoring extensions.
170 lines (168 loc) • 6.72 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 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;