UNPKG

@craftercms/studio-ui

Version:

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

172 lines (170 loc) 6.52 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, useState } from 'react'; import { FormattedMessage } from 'react-intl'; import AddIcon from '@mui/icons-material/Add'; import { fetchAll } from '../../services/groups'; import GroupsGridUI, { GroupsGridSkeletonTable } from '../GroupsGrid'; import EditGroupDialog from '../EditGroupDialog'; import Button from '@mui/material/Button'; import GlobalAppToolbar from '../GlobalAppToolbar'; import Paper from '@mui/material/Paper'; import { useEnhancedDialogState } from '../../hooks/useEnhancedDialogState'; import { useWithPendingChangesCloseRequest } from '../../hooks/useWithPendingChangesCloseRequest'; import SearchBar from '../SearchBar'; import useStyles from '../UserManagement/styles'; import useDebouncedInput from '../../hooks/useDebouncedInput'; import { ApiResponseErrorState } from '../ApiResponseErrorState'; import { EmptyState } from '../EmptyState'; export function GroupManagement() { const [offset, setOffset] = useState(0); const [limit, setLimit] = useState(10); const [fetching, setFetching] = useState(false); const [groups, setGroups] = useState(null); const [error, setError] = useState(); const [selectedGroup, setSelectedGroup] = useState(null); const [showSearchBox, setShowSearchBox] = useState(false); const [keyword, setKeyword] = useState(''); const { classes, cx: clsx } = useStyles(); const fetchGroups = useCallback( (keyword = '', _offset = offset) => { setFetching(true); fetchAll({ limit, offset: _offset, keyword }).subscribe({ next(users) { setGroups(users); setFetching(false); }, error({ response }) { setError(response); setFetching(false); } }); }, [limit, offset] ); useEffect(() => { fetchGroups(); }, [fetchGroups]); const editGroupDialogState = useEnhancedDialogState(); const editGroupDialogPendingChangesCloseRequest = useWithPendingChangesCloseRequest(editGroupDialogState.onClose); const onRowClicked = (group) => { editGroupDialogState.onOpen(); setSelectedGroup(group); }; const onPageChange = (page) => { setOffset(page * limit); }; const onRowsPerPageChange = (e) => { setLimit(e.target.value); }; const onGroupSaved = (group) => { setSelectedGroup(group); fetchGroups(); }; const onGroupDeleted = (group) => { editGroupDialogState.onClose(); fetchGroups(); }; const onGroupDialogClosed = () => { setSelectedGroup(null); }; const onShowSearchBox = () => { setShowSearchBox(!showSearchBox); }; const onSearch = useCallback( (keyword) => { fetchGroups(keyword, 0); }, [fetchGroups] ); const onSearch$ = useDebouncedInput(onSearch, 400); function handleSearchKeyword(keyword) { setKeyword(keyword); onSearch$.next(keyword); } return React.createElement( Paper, { elevation: 0 }, React.createElement(GlobalAppToolbar, { title: React.createElement(FormattedMessage, { id: 'words.groups', defaultMessage: 'Groups' }), leftContent: React.createElement( Button, { startIcon: React.createElement(AddIcon, null), variant: 'outlined', color: 'primary', onClick: () => editGroupDialogState.onOpen() }, React.createElement(FormattedMessage, { id: 'sites.createGroup', defaultMessage: 'Create Group' }) ), rightContent: React.createElement(SearchBar, { classes: { root: clsx(classes.searchBarRoot, !showSearchBox && 'hidden') }, keyword: keyword, onChange: handleSearchKeyword, onDecoratorButtonClick: onShowSearchBox, showActionButton: Boolean(keyword) }) }), error ? React.createElement(ApiResponseErrorState, { error: error }) : fetching ? React.createElement(GroupsGridSkeletonTable, { numOfItems: limit }) : groups ? groups.length ? React.createElement(GroupsGridUI, { groups: groups, onRowClicked: onRowClicked, onPageChange: onPageChange, onRowsPerPageChange: onRowsPerPageChange }) : React.createElement(EmptyState, { title: React.createElement(FormattedMessage, { id: 'groupsGrid.emptyStateMessage', defaultMessage: 'No Groups Found' }) }) : React.createElement(React.Fragment, null), React.createElement(EditGroupDialog, { open: editGroupDialogState.open, group: selectedGroup, onClose: editGroupDialogState.onClose, onClosed: onGroupDialogClosed, onGroupSaved: onGroupSaved, onGroupDeleted: onGroupDeleted, isSubmitting: editGroupDialogState.isSubmitting, isMinimized: editGroupDialogState.isMinimized, hasPendingChanges: editGroupDialogState.hasPendingChanges, onWithPendingChangesCloseRequest: editGroupDialogPendingChangesCloseRequest, onSubmittingAndOrPendingChange: editGroupDialogState.onSubmittingAndOrPendingChange }) ); } export default GroupManagement;