UNPKG

@craftercms/studio-ui

Version:

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

369 lines (367 loc) 10.6 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, { useState } from 'react'; import Dialog from '@mui/material/Dialog'; import { defineMessages, FormattedMessage, useIntl } from 'react-intl'; import { makeStyles } from 'tss-react/mui'; import Typography from '@mui/material/Typography'; import Checkbox from '@mui/material/Checkbox'; import IconButton from '@mui/material/IconButton'; import MoreVertIcon from '@mui/icons-material/MoreVertRounded'; import ContextMenu from '../ContextMenu'; import { markForTranslation } from '../../services/translation'; import { showErrorDialog } from '../../state/reducers/dialogs/error'; import { useDispatch } from 'react-redux'; import palette from '../../styles/palette'; import DialogBody from '../DialogBody/DialogBody'; import DialogHeader from '../DialogHeader'; import SingleItemSelector from '../SingleItemSelector'; import ActionsBar from '../ActionsBar'; import { useActiveSiteId } from '../../hooks/useActiveSiteId'; import { useUnmount } from '../../hooks/useUnmount'; const translations = defineMessages({ mark: { id: 'contentLocalization.mark', defaultMessage: 'Mark for translation' }, approveTranslation: { id: 'contentLocalization.approve', defaultMessage: 'Approve translation' }, deleteTranslation: { id: 'contentLocalization.delete', defaultMessage: 'Delete translation' }, locales: { id: 'words.locales', defaultMessage: 'Locales' }, status: { id: 'words.status', defaultMessage: 'Status' }, edit: { id: 'words.edit', defaultMessage: 'Edit' }, schedule: { id: 'words.schedule', defaultMessage: 'Schedule' }, delete: { id: 'words.delete', defaultMessage: 'Delete' }, approve: { id: 'words.approve', defaultMessage: 'Approve' }, review: { id: 'words.review', defaultMessage: 'Review' } }); const useStyles = makeStyles()((theme) => ({ singleItemSelector: { marginBottom: '10px' }, contentLocalizationRoot: { background: palette.white, border: '1px solid rgba(0, 0, 0, .125)', minHeight: '30vh', '& header': { marginBottom: '5px' } }, icon: { marginLeft: 'auto', padding: '9px' }, checkbox: { color: theme.palette.primary.main }, flex: { display: 'flex', alignItems: 'center' }, headerTitle: { fontWeight: 'bold', paddingRight: '20px' }, locale: { paddingRight: '20px' }, width30: { width: '30%' }, menuPaper: { width: '182px' }, menuList: { padding: 0 }, menuItemRoot: { whiteSpace: 'initial' } })); const localizationMap = { en: 'English, US (en)', en_gb: 'English, UK (en_gb)', es: 'Spanish, Spain (es)', fr: 'French (fr)', de: 'German (de)' }; const menuSections = [ { id: 'edit', label: translations.edit }, { id: 'review', label: translations.review }, { id: 'mark', label: translations.mark }, { id: 'approve', label: translations.approve }, { id: 'delete', label: translations.delete } ]; const menuOptions = [ { id: 'edit', label: translations.edit }, { id: 'schedule', label: translations.schedule }, { id: 'delete', label: translations.delete }, { id: 'approve', label: translations.approve } ]; export function ContentLocalizationDialog(props) { const { open, onClose } = props; return React.createElement( Dialog, { open: open, onClose: onClose, fullWidth: true }, React.createElement(ContentLocalizationDialogUI, Object.assign({}, props)) ); } function ContentLocalizationDialogUI(props) { const { formatMessage } = useIntl(); const dispatch = useDispatch(); const { classes, cx } = useStyles(); const { onClose, locales, item, rootPath, onItemChange } = props; const [selected, setSelected] = useState([]); const [openSelector, setOpenSelector] = useState(false); const site = useActiveSiteId(); const [menu, setMenu] = useState({ activeItem: null, anchorEl: null }); const onOpenCustomMenu = (locale, anchorEl) => { setMenu({ activeItem: locale, anchorEl }); }; const onCloseCustomMenu = () => { setMenu({ activeItem: null, anchorEl: null }); }; const onMenuItemClicked = (option) => { switch (option) { case 'mark': { markForTranslation(site, menu.activeItem.path, menu.activeItem.localeCode).subscribe( () => { setMenu({ activeItem: null, anchorEl: null }); }, ({ response }) => { dispatch( showErrorDialog({ error: response }) ); } ); break; } default: break; } }; const handleSelect = (checked, id) => { const _selected = [...selected]; if (checked) { if (!_selected.includes(id)) { _selected.push(id); } } else { let index = _selected.indexOf(id); if (index >= 0) { _selected.splice(index, 1); } } setSelected(_selected); }; const toggleSelectAll = () => { if (locales.length === selected.length) { setSelected([]); } else { setSelected(locales.map((locale) => locale.id)); } }; const onOptionClicked = (option) => { // TODO: Widget menu option clicked }; useUnmount(props.onClosed); return React.createElement( React.Fragment, null, React.createElement(DialogHeader, { title: React.createElement(FormattedMessage, { id: 'contentLocalization.title', defaultMessage: 'Content Localization' }), onCloseButtonClick: onClose }), React.createElement( DialogBody, null, React.createElement(SingleItemSelector, { label: React.createElement(FormattedMessage, { id: 'words.item', defaultMessage: 'Item' }), classes: { root: classes.singleItemSelector }, open: openSelector, onClose: () => setOpenSelector(false), onDropdownClick: () => setOpenSelector(!openSelector), rootPath: rootPath, selectedItem: item, onItemClicked: (item) => { onItemChange(item); setOpenSelector(false); } }), React.createElement( 'section', { className: classes.contentLocalizationRoot }, selected.length > 0 ? React.createElement(ActionsBar, { isIndeterminate: selected.length > 0 && selected.length < locales.length, onOptionClicked: onOptionClicked, options: menuOptions, isChecked: selected.length === locales.length, onCheckboxChange: toggleSelectAll }) : React.createElement( 'header', { className: classes.flex }, React.createElement(Checkbox, { color: 'primary', className: classes.checkbox, onChange: toggleSelectAll }), React.createElement( React.Fragment, null, React.createElement( Typography, { variant: 'subtitle2', className: cx(classes.headerTitle, classes.width30) }, formatMessage(translations.locales) ), React.createElement( Typography, { variant: 'subtitle2', className: classes.headerTitle }, formatMessage(translations.status) ) ) ), locales === null || locales === void 0 ? void 0 : locales.map((locale) => React.createElement( 'div', { className: classes.flex, key: locale.id }, React.createElement(Checkbox, { color: 'primary', className: classes.checkbox, checked: selected === null || selected === void 0 ? void 0 : selected.includes(locale.id), onChange: (event) => handleSelect(event.currentTarget.checked, locale.id) }), React.createElement( Typography, { variant: 'subtitle2', className: cx(classes.locale, classes.width30) }, localizationMap[locale.localeCode] ), React.createElement(Typography, { variant: 'subtitle2', className: classes.locale }, locale.status), React.createElement( IconButton, { 'aria-label': 'options', className: classes.icon, onClick: (e) => onOpenCustomMenu(locale, e.currentTarget), size: 'large' }, React.createElement(MoreVertIcon, null) ) ) ) ) ), React.createElement(ContextMenu, { anchorEl: menu.anchorEl, open: Boolean(menu.anchorEl), classes: { paper: classes.menuPaper }, onClose: onCloseCustomMenu, options: [menuSections], onMenuItemClicked: onMenuItemClicked }) ); } export default ContentLocalizationDialog;