diff --git a/packages/core/admin/admin/src/components/Notifications/Notification/index.js b/packages/core/admin/admin/src/components/Notifications/Notification/index.js index 3dfffc2728..75e97d3f2d 100644 --- a/packages/core/admin/admin/src/components/Notifications/Notification/index.js +++ b/packages/core/admin/admin/src/components/Notifications/Notification/index.js @@ -1,40 +1,12 @@ import React, { useEffect, useCallback } from 'react'; import PropTypes from 'prop-types'; -import { Padded, Text, Flex } from '@buffetjs/core'; import { useIntl } from 'react-intl'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { Remove } from '@buffetjs/icons'; -import { NotificationWrapper, IconWrapper, LinkArrow, RemoveWrapper } from './styledComponents'; - -const types = { - success: { - icon: 'check', - color: 'green', - }, - warning: { - icon: 'exclamation', - color: 'orange', - }, - info: { - icon: 'info', - color: 'blue', - }, -}; +import { Alert } from '@strapi/parts/Alert'; +import { Link } from '@strapi/parts/Link'; const Notification = ({ dispatch, notification }) => { const { formatMessage } = useIntl(); - - const { - title, - message, - link, - type, - id, - onClose, - timeout, - blockTransition, - centered, - } = notification; + const { message, link, type, id, onClose, timeout, blockTransition } = notification; const formattedMessage = msg => (typeof msg === 'string' ? msg : formatMessage(msg, msg.values)); const handleClose = useCallback(() => { @@ -61,62 +33,53 @@ const Notification = ({ dispatch, notification }) => { return () => clearTimeout(timeoutToClear); }, [blockTransition, handleClose, timeout]); + let variant; + let alertTitle; + + if (type === 'info') { + variant = 'default'; + alertTitle = formatMessage({ + id: 'notification.default.title', + defaultMessage: 'Information Alert:', + }); + } else if (type === 'warning') { + alertTitle = formatMessage({ + id: 'notification.warning.title', + defaultMessage: 'Warning Alert:', + }); + variant = 'danger'; + } else { + alertTitle = formatMessage({ + id: 'notification.success.title', + defaultMessage: 'Success Alert:', + }); + variant = 'success'; + } + return ( - - - - - - - - {title && ( - - {formattedMessage(title)} - - )} - - {message && ( - {formattedMessage(message)} - )} - {link && ( - - - - - {formattedMessage(link.label)} - - {link.target === '_blank' && ( - - - - )} - - - - )} - - - - - - - - + + {formatMessage({ + id: link.label?.id || link.label, + defaultMessage: link.label?.defaultMessage || link.label?.id || link.label, + })} + + ) : ( + undefined + ) + } + onClose={handleClose} + closeLabel="Close" + title={alertTitle} + variant={variant} + > + {formattedMessage({ + id: message?.id || message, + defaultMessage: message?.defaultMessage || message?.id || message, + })} + ); }; @@ -131,7 +94,6 @@ Notification.defaultProps = { onClose: () => null, timeout: 2500, blockTransition: false, - centered: false, }, }; @@ -147,14 +109,6 @@ Notification.propTypes = { values: PropTypes.object, }), ]), - title: PropTypes.oneOfType([ - PropTypes.string, - PropTypes.shape({ - id: PropTypes.string.isRequired, - defaultMessage: PropTypes.string, - values: PropTypes.object, - }), - ]), link: PropTypes.shape({ target: PropTypes.string, url: PropTypes.string.isRequired, @@ -171,7 +125,6 @@ Notification.propTypes = { onClose: PropTypes.func, timeout: PropTypes.number, blockTransition: PropTypes.bool, - centered: PropTypes.bool, }), }; diff --git a/packages/core/admin/admin/src/components/Notifications/Notification/styledComponents.js b/packages/core/admin/admin/src/components/Notifications/Notification/styledComponents.js deleted file mode 100644 index 70d7fada4c..0000000000 --- a/packages/core/admin/admin/src/components/Notifications/Notification/styledComponents.js +++ /dev/null @@ -1,68 +0,0 @@ -import styled from 'styled-components'; -import { Arrow } from '@buffetjs/icons'; - -const NotificationWrapper = styled.div` - position: relative; - - pointer-events: auto; - - &:hover { - box-shadow: 0 1px 5px 0 rgba(0, 0, 0, 0.2); - } -`; - -// border-top-right-radius: ${({ theme }) => theme.main.sizes.borderRadius}; -// border-bottom-right-radius: ${({ theme }) => theme.main.sizes.borderRadius}; -// margin-bottom: ${({ theme }) => theme.main.sizes.paddings.sm}; -// box-shadow: 0 2px 4px 0 ${({ theme }) => theme.main.colors.darkGrey}; -// background-color: ${props => props.theme.main.colors.white}; -// border-left: 2px solid ${({ theme, color }) => theme.main.colors[color]}; -// overflow: hidden; -// z-index: 10; -// color: ${({ color, theme }) => theme.main.colors[color]}; -// transition: all 0.15s ease; -// width: 400px; -// min-height: 60px; -// margin-left: ${({ centered }) => (centered ? '0px' : '240px')}; - -const IconWrapper = styled.div` - border: 1px solid; - padding: 5px; - border-radius: 50%; - width: 20px; - height: 20px; - display: flex; - align-items: center; - justify-content: center; - font-size: 10px; -`; - -const LinkArrow = styled(Arrow)` - transform: rotate(45deg); - margin-top: 4px; - color: ${({ theme }) => theme.main.colors.blue}; -`; - -const RemoveWrapper = styled.div` - position: relative; - display: flex; - width: 20px; - cursor: pointer; - opacity: 0.6; - font-size: 1.4rem; - color: #bbc2bf; - transition: opacity 0.1s ease; - -webkit-font-smoothing: antialiased; - - &:hover { - opacity: 1; - } - - svg { - margin: auto; - font-size: 1.3rem; - font-weight: 100 !important; - } -`; - -export { NotificationWrapper, IconWrapper, LinkArrow, RemoveWrapper }; diff --git a/packages/core/admin/admin/src/components/Notifications/Wrapper.js b/packages/core/admin/admin/src/components/Notifications/Wrapper.js index 8ec390d002..63a7f4ccf2 100644 --- a/packages/core/admin/admin/src/components/Notifications/Wrapper.js +++ b/packages/core/admin/admin/src/components/Notifications/Wrapper.js @@ -1,19 +1,12 @@ import styled from 'styled-components'; -import { TransitionGroup } from 'react-transition-group'; +import { Row } from '@strapi/parts'; -const Wrapper = styled(TransitionGroup)` - display: flex; - align-items: center; - flex-direction: column; +const Wrapper = styled(Row)` position: fixed; - top: 72px; - left: 0; + top: 46px; right: 0; + left: 0; z-index: 1100; - list-style: none; - width: 100%; - overflow-y: hidden; - pointer-events: none; `; export default Wrapper; diff --git a/packages/core/admin/admin/src/components/Notifications/index.js b/packages/core/admin/admin/src/components/Notifications/index.js index 1d1b0fb4d3..7a99668b51 100644 --- a/packages/core/admin/admin/src/components/Notifications/index.js +++ b/packages/core/admin/admin/src/components/Notifications/index.js @@ -1,15 +1,14 @@ import { NotificationsProvider } from '@strapi/helper-plugin'; import React, { useReducer } from 'react'; import PropTypes from 'prop-types'; -// import { CSSTransition } from 'react-transition-group'; - -// import Notification from './Notification'; +import { Box } from '@strapi/parts/Box'; +import { Stack } from '@strapi/parts/Stack'; +import Notification from './Notification'; import reducer, { initialState } from './reducer'; -// import NotificationsWrapper from './Wrapper'; +import NotificationsWrapper from './Wrapper'; const Notifications = ({ children }) => { - // const [{ notifications }, dispatch] = useReducer(reducer, initialState); - const [, dispatch] = useReducer(reducer, initialState); + const [{ notifications }, dispatch] = useReducer(reducer, initialState); const displayNotification = config => { dispatch({ @@ -20,30 +19,20 @@ const Notifications = ({ children }) => { return ( + + + {notifications.map(notification => { + return ( + + + + ); + })} + + {children} ); - - // FIXME - // return ( - // - // - // {notifications.map(notification => ( - // - // - // - // ))} - // - // {children} - // - // ); }; Notifications.propTypes = { diff --git a/packages/core/admin/admin/src/components/Notifications/reducer.js b/packages/core/admin/admin/src/components/Notifications/reducer.js index 60d45ef757..1d67d1696f 100644 --- a/packages/core/admin/admin/src/components/Notifications/reducer.js +++ b/packages/core/admin/admin/src/components/Notifications/reducer.js @@ -19,13 +19,10 @@ const notificationReducer = (state = initialState, action) => id: 'notification.success.saved', defaultMessage: 'Saved', }), - title: get(action, ['config', 'title'], null), link: get(action, ['config', 'link'], null), timeout: get(action, ['config', 'timeout'], 2500), blockTransition: get(action, ['config', 'blockTransition'], false), - uid: get(action, ['config', 'uid'], null), onClose: get(action, ['config', 'onClose'], null), - centered: get(action, ['config', 'centered'], false), }); draftState.notifId = state.notifId + 1; break; diff --git a/packages/core/admin/admin/src/components/Notifications/tests/index.test.js b/packages/core/admin/admin/src/components/Notifications/tests/index.test.js new file mode 100644 index 0000000000..078d10bd95 --- /dev/null +++ b/packages/core/admin/admin/src/components/Notifications/tests/index.test.js @@ -0,0 +1,176 @@ +/** + * + * Tests for Notifications + * + */ + +import React from 'react'; +import { render, fireEvent, screen } from '@testing-library/react'; +import { IntlProvider } from 'react-intl'; +import { useNotification } from '@strapi/helper-plugin'; +import { act } from 'react-dom/test-utils'; +import Theme from '../../Theme'; +import Notifications from '../index'; + +const messages = { + en: {}, +}; + +describe('', () => { + it('renders and matches the snapshot', () => { + const { + container: { firstChild }, + } = render( + + + +
+ + + + ); + + expect(firstChild).toMatchInlineSnapshot(` + .c0 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + -webkit-box-pack: space-around; + -webkit-justify-content: space-around; + -ms-flex-pack: space-around; + justify-content: space-around; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + } + + .c2 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + } + + .c2 > * { + margin-top: 0; + margin-bottom: 0; + } + + .c2 > * + * { + margin-top: 0px; + } + + .c1 { + position: fixed; + top: 46px; + right: 0; + left: 0; + z-index: 1100; + } + +
+
+
+ `); + }); + + it('should display a notification correctly', async () => { + const Button = () => { + const toggleNotification = useNotification(); + + const handleClick = () => { + toggleNotification({ type: 'success', message: 'simple notif' }); + }; + + return ( + + ); + }; + + render( + + + + + ); + }; + + render( + + + + + + ); +}; +```