diff --git a/assets/src/application/services/utilities/dom/canUseDOM.ts b/assets/src/application/services/utilities/dom/canUseDOM.ts new file mode 100644 index 00000000000..c5bfbbac485 --- /dev/null +++ b/assets/src/application/services/utilities/dom/canUseDOM.ts @@ -0,0 +1,3 @@ +const canUseDOM = !!(typeof window !== 'undefined' && window.document && window.document.createElement); + +export default canUseDOM; diff --git a/assets/src/application/services/utilities/dom/index.ts b/assets/src/application/services/utilities/dom/index.ts index deaf6e7f8fb..30123ab6076 100644 --- a/assets/src/application/services/utilities/dom/index.ts +++ b/assets/src/application/services/utilities/dom/index.ts @@ -1 +1,2 @@ +export { default as canUseDOM } from './canUseDOM'; export { default as getHTMLElementClientRect } from './getHTMLElementClientRect'; diff --git a/assets/src/application/ui/display/confirm/useConfirm.tsx b/assets/src/application/ui/display/confirm/useConfirm.tsx index 64d6b4bcb03..bd071364b7a 100644 --- a/assets/src/application/ui/display/confirm/useConfirm.tsx +++ b/assets/src/application/ui/display/confirm/useConfirm.tsx @@ -8,10 +8,10 @@ import { Button as ButtonAdapter } from '@infraUI/inputs'; import { ConfirmProps } from './types'; -const useConfirm: React.FC = ({ children, buttonProps, onConfirm, title }) => { +const useConfirm: React.FC = ({ buttonProps, onConfirm, title }) => { const { isOpen, onOpen, onClose } = useDisclosure(); const cancelRef = React.useRef(); - const onDelete = useCallback(() => { + const onClickHandler = useCallback(() => { if (typeof onConfirm === 'function') { onConfirm(); } @@ -27,7 +27,7 @@ const useConfirm: React.FC = ({ children, buttonProps, onConfirm, header={buttonProps?.tooltip} isOpen={isOpen} leastDestructiveRef={cancelRef} - okButton={} + okButton={} onClose={onClose} title={title} /> diff --git a/assets/src/application/ui/forms/modalForm/RenderModalForm.tsx b/assets/src/application/ui/forms/modalForm/RenderModalForm.tsx index 8bad05d67e6..7bb788ad336 100644 --- a/assets/src/application/ui/forms/modalForm/RenderModalForm.tsx +++ b/assets/src/application/ui/forms/modalForm/RenderModalForm.tsx @@ -3,9 +3,9 @@ import { __ } from '@wordpress/i18n'; import { SaveOutlined } from '@ant-design/icons'; import { ButtonProps } from '@infraUI/inputs'; -import { Close } from '@appDisplay/icons'; import { ConfirmClose } from '@appDisplay/confirm'; -import { Modal } from '@infraUI/layout/modal'; +import { ModalWithAlert } from '@appLayout/modal'; +import { modalCloseButtonProps } from '@infraUI/layout/modal'; import { RenderModalFormProps } from './types'; @@ -32,16 +32,7 @@ const RenderModalForm: React.FC = ({ const onReset = useCallback(() => form.reset(), [form.reset]); - const closeButton = ( - - ); + const closeButton = !pristine && ; const submitButtonProps: ButtonProps = useMemo( () => ({ @@ -66,19 +57,19 @@ const RenderModalForm: React.FC = ({ ); return ( - {children} - + ); }; diff --git a/assets/src/application/ui/forms/modalForm/styles.scss b/assets/src/application/ui/forms/modalForm/styles.scss index 352bbcc2396..09764e77711 100644 --- a/assets/src/application/ui/forms/modalForm/styles.scss +++ b/assets/src/application/ui/forms/modalForm/styles.scss @@ -1,15 +1,3 @@ .ee-modal-form { max-width: 75rem !important; - .confirm-close { - display: inline-flex; - position: absolute; - top: 8px; - right: 12px; - min-width: auto; - width: var(--ee-padding-big); - height: var(--ee-padding-big); - svg { - margin: 0; - } - } } diff --git a/assets/src/application/ui/layout/index.ts b/assets/src/application/ui/layout/index.ts index f62986b879c..f5bcc1e796b 100644 --- a/assets/src/application/ui/layout/index.ts +++ b/assets/src/application/ui/layout/index.ts @@ -2,4 +2,5 @@ export * from './formModal'; export * from './entityActionsMenu'; export * from './entityList'; export * from './dropdownMenu'; + export { default as EntityPaperFrame } from './EntityPaperFrame'; diff --git a/assets/src/application/ui/layout/modal/ModalWithAlert.tsx b/assets/src/application/ui/layout/modal/ModalWithAlert.tsx new file mode 100644 index 00000000000..86e36da1b38 --- /dev/null +++ b/assets/src/application/ui/layout/modal/ModalWithAlert.tsx @@ -0,0 +1,63 @@ +import React, { useEffect } from 'react'; +import { useDisclosure } from '@chakra-ui/core'; +import { __ } from '@wordpress/i18n'; +import { canUseDOM } from '@appServices/utilities/dom'; +import { ESCAPE } from '@wordpress/keycodes'; + +import { AlertDialog } from '@infraUI/display'; +import { Button as ButtonAdapter } from '@infraUI/inputs'; +import { Modal, ModalProps } from '@infraUI/layout/modal'; + +interface Props extends ModalProps { + cancelBtnText?: string; + header?: string; + okBtnText?: string; + showAlertOnEscape: boolean; +} + +const ModalWithAlert: React.FC = ({ children, showAlertOnEscape, ...props }) => { + const { isOpen, onOpen, onClose } = useDisclosure(); + const cancelRef = React.useRef(); + const cancelBtnText = props.cancelBtnText || __('No'); + const header = props.header || __('Are you sure you want to close this?'); + const okBtnText = props.okBtnText || __('Yes'); + const onEscape = ({ keyCode }): void => { + if (keyCode === ESCAPE) { + onOpen(); + } + }; + + useEffect(() => { + if (canUseDOM) { + document.addEventListener('keydown', onEscape); + } + + return () => { + if (canUseDOM) { + document.removeEventListener('keydown', onEscape); + } + }; + }, []); + + return ( + <> + + {children} + + {showAlertOnEscape && ( + } + header={header} + isOpen={isOpen} + leastDestructiveRef={cancelRef} + okButton={ + + } + onClose={onClose} + /> + )} + + ); +}; + +export default ModalWithAlert; diff --git a/assets/src/application/ui/layout/modal/index.ts b/assets/src/application/ui/layout/modal/index.ts new file mode 100644 index 00000000000..a06ed011faf --- /dev/null +++ b/assets/src/application/ui/layout/modal/index.ts @@ -0,0 +1 @@ +export { default as ModalWithAlert } from './ModalWithAlert'; diff --git a/assets/src/domain/eventEditor/ui/ticketAssignmentsManager/components/TicketAssignmentsManagerModal.tsx b/assets/src/domain/eventEditor/ui/ticketAssignmentsManager/components/TicketAssignmentsManagerModal.tsx deleted file mode 100644 index f3ede73eaa5..00000000000 --- a/assets/src/domain/eventEditor/ui/ticketAssignmentsManager/components/TicketAssignmentsManagerModal.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import React from 'react'; -import { __ } from '@wordpress/i18n'; - -import { Modal } from '@infraUI/layout/modal'; - -import TicketAssignmentsManager from './TicketAssignmentsManager'; -import useCancelButtonProps from '../buttons/useCancelButtonProps'; -import useSubmitButtonProps from '../buttons/useSubmitButtonProps'; -import { useTAMContext } from '../context'; - -import './styles.scss'; - -const TicketAssignmentsManagerModal: React.FC = () => { - const { onCloseModal, title } = useTAMContext(); - const cancelButtonProps = useCancelButtonProps(); - const submitButtonProps = useSubmitButtonProps(); - - return ( - - - - ); -}; - -export default TicketAssignmentsManagerModal; diff --git a/assets/src/domain/eventEditor/ui/ticketAssignmentsManager/components/TicketAssignmentsManagerModal/buttons/CloseModal.tsx b/assets/src/domain/eventEditor/ui/ticketAssignmentsManager/components/TicketAssignmentsManagerModal/buttons/CloseModal.tsx new file mode 100644 index 00000000000..c6e76c4d399 --- /dev/null +++ b/assets/src/domain/eventEditor/ui/ticketAssignmentsManager/components/TicketAssignmentsManagerModal/buttons/CloseModal.tsx @@ -0,0 +1,20 @@ +import React, { useCallback } from 'react'; +import { __ } from '@wordpress/i18n'; + +import { ConfirmClose } from '@appDisplay/confirm'; +import { modalCloseButtonProps } from '@infraUI/layout/modal'; +import { useTAMContext } from '../../../context'; + +const CloseModal: React.FC = () => { + const { dataState, onCloseModal } = useTAMContext(); + + const { hasOrphanEntities } = dataState; + + const hasErrors = hasOrphanEntities(); + + const onConfirm = useCallback(onCloseModal, [hasErrors]); + + return hasErrors ? : null; +}; + +export default React.memo(CloseModal); diff --git a/assets/src/domain/eventEditor/ui/ticketAssignmentsManager/buttons/useCancelButtonProps.tsx b/assets/src/domain/eventEditor/ui/ticketAssignmentsManager/components/TicketAssignmentsManagerModal/buttons/useCancelButtonProps.tsx similarity index 92% rename from assets/src/domain/eventEditor/ui/ticketAssignmentsManager/buttons/useCancelButtonProps.tsx rename to assets/src/domain/eventEditor/ui/ticketAssignmentsManager/components/TicketAssignmentsManagerModal/buttons/useCancelButtonProps.tsx index 5632a5fbf5b..d28f74c97dc 100644 --- a/assets/src/domain/eventEditor/ui/ticketAssignmentsManager/buttons/useCancelButtonProps.tsx +++ b/assets/src/domain/eventEditor/ui/ticketAssignmentsManager/components/TicketAssignmentsManagerModal/buttons/useCancelButtonProps.tsx @@ -2,7 +2,7 @@ import { useCallback, useMemo } from 'react'; import { __ } from '@wordpress/i18n'; import { ButtonProps } from '@infraUI/inputs'; -import { useTAMContext } from '../context'; +import { useTAMContext } from '../../../context'; const useCancelButtonProps = (): ButtonProps => { const { dataState, onCloseModal } = useTAMContext(); diff --git a/assets/src/domain/eventEditor/ui/ticketAssignmentsManager/buttons/useSubmitButtonProps.tsx b/assets/src/domain/eventEditor/ui/ticketAssignmentsManager/components/TicketAssignmentsManagerModal/buttons/useSubmitButtonProps.tsx similarity index 87% rename from assets/src/domain/eventEditor/ui/ticketAssignmentsManager/buttons/useSubmitButtonProps.tsx rename to assets/src/domain/eventEditor/ui/ticketAssignmentsManager/components/TicketAssignmentsManagerModal/buttons/useSubmitButtonProps.tsx index 1fd46da6711..ff60179a5c4 100644 --- a/assets/src/domain/eventEditor/ui/ticketAssignmentsManager/buttons/useSubmitButtonProps.tsx +++ b/assets/src/domain/eventEditor/ui/ticketAssignmentsManager/components/TicketAssignmentsManagerModal/buttons/useSubmitButtonProps.tsx @@ -2,8 +2,8 @@ import { useCallback, useMemo } from 'react'; import { __ } from '@wordpress/i18n'; import { ButtonProps } from '@infraUI/inputs'; -import { useOnSubmitAssignments } from '../data'; -import { useTAMContext } from '../context'; +import { useOnSubmitAssignments } from '../../../data'; +import { useTAMContext } from '../../../context'; const useSubmitButtonProps = (): ButtonProps => { const { dataState, onCloseModal } = useTAMContext(); diff --git a/assets/src/domain/eventEditor/ui/ticketAssignmentsManager/components/TicketAssignmentsManagerModal/index.tsx b/assets/src/domain/eventEditor/ui/ticketAssignmentsManager/components/TicketAssignmentsManagerModal/index.tsx new file mode 100644 index 00000000000..5dc7201cd75 --- /dev/null +++ b/assets/src/domain/eventEditor/ui/ticketAssignmentsManager/components/TicketAssignmentsManagerModal/index.tsx @@ -0,0 +1,42 @@ +import React from 'react'; +import { __ } from '@wordpress/i18n'; + +import { ModalWithAlert } from '@appLayout/modal'; + +import CloseModalButton from './buttons/CloseModal'; +import TicketAssignmentsManager from '../TicketAssignmentsManager'; +import useCancelButtonProps from './buttons/useCancelButtonProps'; +import useSubmitButtonProps from './buttons/useSubmitButtonProps'; +import { useTAMContext } from '../../context'; + +import '../styles.scss'; + +const TicketAssignmentsManagerModal: React.FC = () => { + const { + dataState: { hasOrphanEntities }, + onCloseModal, + title, + } = useTAMContext(); + const cancelButtonProps = useCancelButtonProps(); + const submitButtonProps = useSubmitButtonProps(); + + const hasErrors = hasOrphanEntities(); + + return ( + } + isOpen={true} + onClose={onCloseModal} + showAlertOnEscape={hasErrors} + submitButtonProps={submitButtonProps} + title={title || __('Ticket Assignment Manager')} + > + + + ); +}; + +export default TicketAssignmentsManagerModal; diff --git a/assets/src/infrastructure/ui/layout/modal/index.ts b/assets/src/infrastructure/ui/layout/modal/index.ts index 0699f0d6eca..117127411c5 100644 --- a/assets/src/infrastructure/ui/layout/modal/index.ts +++ b/assets/src/infrastructure/ui/layout/modal/index.ts @@ -1,3 +1,4 @@ export { default as Modal } from './Modal'; +export { default as modalCloseButtonProps } from './modalCloseButtonProps'; export * from './types'; diff --git a/assets/src/infrastructure/ui/layout/modal/modalCloseButtonProps/index.tsx b/assets/src/infrastructure/ui/layout/modal/modalCloseButtonProps/index.tsx new file mode 100644 index 00000000000..7c49a2fa865 --- /dev/null +++ b/assets/src/infrastructure/ui/layout/modal/modalCloseButtonProps/index.tsx @@ -0,0 +1,14 @@ +import { __ } from '@wordpress/i18n'; + +import { ButtonProps } from '@infraUI/inputs'; +import { Close } from '@appDisplay/icons'; + +import './styles.scss'; + +const modalCloseButtonProps: ButtonProps = { + className: 'ee-confirm-close', + icon: Close, + variant: 'unstyled', +}; + +export default modalCloseButtonProps; diff --git a/assets/src/infrastructure/ui/layout/modal/modalCloseButtonProps/styles.scss b/assets/src/infrastructure/ui/layout/modal/modalCloseButtonProps/styles.scss new file mode 100644 index 00000000000..9e306b27d56 --- /dev/null +++ b/assets/src/infrastructure/ui/layout/modal/modalCloseButtonProps/styles.scss @@ -0,0 +1,17 @@ +// this selector is used for specificity +[role='alertdialog'] { + .ee-confirm-close { + display: inline-flex; + position: absolute; + top: 8px; + right: 12px; + min-width: auto; + width: var(--ee-padding-big); + height: var(--ee-padding-big); + svg { + height: var(--ee-border-radius-big); + margin: 0; + width: var(--ee-border-radius-big); + } + } +} diff --git a/package.json b/package.json index 0d509039688..f833efff3ae 100644 --- a/package.json +++ b/package.json @@ -95,6 +95,7 @@ }, "devDependencies": { "@apollo/react-testing": "^3.1.4", + "@babel/compat-data": "^7.9.0", "@babel/core": "^7.9.0", "@babel/plugin-proposal-class-properties": "^7.8.3", "@babel/plugin-transform-runtime": "^7.9.0",