diff --git a/plugins/woocommerce-admin/changelogs/feature-7242-inbox-notes-in-panel-with-header b/plugins/woocommerce-admin/changelogs/feature-7242-inbox-notes-in-panel-with-header new file mode 100644 index 00000000000..1823b90e8dc --- /dev/null +++ b/plugins/woocommerce-admin/changelogs/feature-7242-inbox-notes-in-panel-with-header @@ -0,0 +1,4 @@ +Significance: minor +Type: Update + +Update the inbox panel with the new design #7864 diff --git a/plugins/woocommerce-admin/client/header/activity-panel/panels/inbox/inbox.scss b/plugins/woocommerce-admin/client/header/activity-panel/panels/inbox/inbox.scss index 67111dd6f0c..9d7d204601d 100644 --- a/plugins/woocommerce-admin/client/header/activity-panel/panels/inbox/inbox.scss +++ b/plugins/woocommerce-admin/client/header/activity-panel/panels/inbox/inbox.scss @@ -1,8 +1,4 @@ .woocommerce-layout__activity-panel-content { - .woocommerce-inbox-message, - .woocommerce-notification-panels > div { - margin-top: $gap-large; - } .woocommerce-abbreviated-notifications { border-top: 1px solid $gray-200; diff --git a/plugins/woocommerce-admin/client/inbox-panel/index.js b/plugins/woocommerce-admin/client/inbox-panel/index.js index 4a8f38b5b69..0627f389843 100644 --- a/plugins/woocommerce-admin/client/inbox-panel/index.js +++ b/plugins/woocommerce-admin/client/inbox-panel/index.js @@ -3,7 +3,13 @@ */ import { __, _n } from '@wordpress/i18n'; import { useEffect, useState } from '@wordpress/element'; -import { EmptyContent, Section } from '@woocommerce/components'; +import { + EmptyContent, + Section, + Badge, + EllipsisMenu, +} from '@woocommerce/components'; +import { Card, CardHeader, Button } from '@wordpress/components'; import { NOTES_STORE_NAME, useUserPreferences, @@ -14,8 +20,8 @@ import { recordEvent } from '@woocommerce/tracks'; import { CSSTransition, TransitionGroup } from 'react-transition-group'; import { InboxNoteCard, - InboxDismissConfirmationModal, InboxNotePlaceholder, + Text, } from '@woocommerce/experimental'; /** @@ -53,7 +59,7 @@ const renderNotes = ( { isBatchUpdating, lastRead, notes, - onDismiss, + dismissNote, onNoteActionClick, } ) => { if ( isBatchUpdating ) { @@ -78,31 +84,51 @@ const renderNotes = ( { const notesArray = Object.keys( notes ).map( ( key ) => notes[ key ] ); return ( - - { notesArray.map( ( note ) => { - const { id: noteId, is_deleted: isDeleted } = note; - if ( isDeleted ) { - return null; - } - return ( - - + + + + { __( 'Inbox', 'woocommerce-admin' ) } + + + + ( + + + { __( 'Hide this', 'woocommerce-admin' ) } + + + ) } + /> + + + { notesArray.map( ( note ) => { + const { id: noteId, is_deleted: isDeleted } = note; + if ( isDeleted ) { + return null; + } + return ( + - - ); - } ) } - + timeout={ 500 } + classNames="woocommerce-inbox-message" + > + + + ); + } ) } + + ); }; @@ -131,13 +157,9 @@ const INBOX_QUERY = { const InboxPanel = () => { const { createNotice } = useDispatch( 'core/notices' ); - const { - batchUpdateNotes, - removeAllNotes, - removeNote, - updateNote, - triggerNoteAction, - } = useDispatch( NOTES_STORE_NAME ); + const { removeNote, updateNote, triggerNoteAction } = useDispatch( + NOTES_STORE_NAME + ); const { isError, isResolvingNotes, isBatchUpdating, notes } = useSelect( ( select ) => { const { @@ -159,7 +181,6 @@ const InboxPanel = () => { ); const { updateUserPreferences, ...userPrefs } = useUserPreferences(); const [ lastRead ] = useState( userPrefs.activity_panel_inbox_last_read ); - const [ dismiss, setDismiss ] = useState(); useEffect( () => { const mountTime = Date.now(); @@ -170,80 +191,46 @@ const InboxPanel = () => { updateUserPreferences( userDataFields ); }, [] ); - const onDismiss = ( note, type ) => { - setDismiss( { note, type } ); - }; - - const closeDismissModal = async ( confirmed = false ) => { - const noteNameDismissAll = dismiss.type === 'all' ? true : false; + const dismissNote = ( note ) => { const screen = getScreenName(); recordEvent( 'inbox_action_dismiss', { - note_name: dismiss.note.name, - note_title: dismiss.note.title, - note_name_dismiss_all: noteNameDismissAll, - note_name_dismiss_confirmation: confirmed, + note_name: note.name, + note_title: note.title, + note_name_dismiss_all: false, + note_name_dismiss_confirmation: true, screen, } ); - if ( confirmed ) { - const noteId = dismiss.note.id; - const removeAll = ! noteId || noteNameDismissAll; - try { - let notesRemoved = []; - if ( removeAll ) { - notesRemoved = await removeAllNotes( { - status: INBOX_QUERY.status, - } ); - } else { - const noteRemoved = await removeNote( noteId ); - notesRemoved = [ noteRemoved ]; - } - setDismiss( undefined ); - createNotice( - 'success', - notesRemoved.length > 1 - ? __( 'All messages dismissed', 'woocommerce-admin' ) - : __( 'Message dismissed', 'woocommerce-admin' ), - { - actions: [ - { - label: __( 'Undo', 'woocommerce-admin' ), - onClick: () => { - if ( notesRemoved.length > 1 ) { - batchUpdateNotes( - notesRemoved.map( - ( note ) => note.id - ), - { - is_deleted: 0, - } - ); - } else { - updateNote( noteId, { - is_deleted: 0, - } ); - } - }, + const noteId = note.id; + try { + removeNote( noteId ); + createNotice( + 'success', + __( 'Message dismissed', 'woocommerce-admin' ), + { + actions: [ + { + label: __( 'Undo', 'woocommerce-admin' ), + onClick: () => { + updateNote( noteId, { + is_deleted: 0, + } ); }, - ], - } - ); - } catch ( e ) { - const numberOfNotes = removeAll ? notes.length : 1; - createNotice( - 'error', - _n( - 'Message could not be dismissed', - 'Messages could not be dismissed', - numberOfNotes, - 'woocommerce-admin' - ) - ); - setDismiss( undefined ); - } - } else { - setDismiss( undefined ); + }, + ], + } + ); + } catch ( e ) { + createNotice( + 'error', + _n( + 'Message could not be dismissed', + 'Messages could not be dismissed', + 1, + 'woocommerce-admin' + ) + ); } }; @@ -292,16 +279,10 @@ const InboxPanel = () => { isBatchUpdating, lastRead, notes, - onDismiss, + dismissNote, onNoteActionClick, } ) } - { dismiss && ( - closeDismissModal( true ) } - /> - ) } > ); diff --git a/plugins/woocommerce-admin/client/inbox-panel/index.scss b/plugins/woocommerce-admin/client/inbox-panel/index.scss index 03211f7180c..3e9ce19b99e 100644 --- a/plugins/woocommerce-admin/client/inbox-panel/index.scss +++ b/plugins/woocommerce-admin/client/inbox-panel/index.scss @@ -34,3 +34,9 @@ transform: translateX(50%); transition: opacity 500ms, transform 500ms, max-height 500ms; } + +.wooocommerce-inbox-card__header { + .woocommerce-badge { + margin-left: 16px; + } +} diff --git a/plugins/woocommerce-admin/packages/experimental/CHANGELOG.md b/plugins/woocommerce-admin/packages/experimental/CHANGELOG.md index 010a8f89f7a..d8925222665 100644 --- a/plugins/woocommerce-admin/packages/experimental/CHANGELOG.md +++ b/plugins/woocommerce-admin/packages/experimental/CHANGELOG.md @@ -1,6 +1,7 @@ # Unreleased - Renaming remindMeLater() to onSnooze() for consistency. #7616 +- Applied new Inbox 2.0 design to the inbox-note component. #7864 # 2.0.3 diff --git a/plugins/woocommerce-admin/packages/experimental/src/inbox-note/action.tsx b/plugins/woocommerce-admin/packages/experimental/src/inbox-note/action.tsx index c1014854f5a..06044eadf91 100644 --- a/plugins/woocommerce-admin/packages/experimental/src/inbox-note/action.tsx +++ b/plugins/woocommerce-admin/packages/experimental/src/inbox-note/action.tsx @@ -47,7 +47,7 @@ export const InboxNoteActionButton: React.FC< InboxNoteActionProps > = ( { return ( void; + onDismiss?: ( note: InboxNote ) => void; onNoteActionClick?: ( note: InboxNote, action: InboxNoteAction ) => void; onBodyLinkClick?: ( note: InboxNote, link: string ) => void; onNoteVisible?: ( note: InboxNote ) => void; className?: string; }; -const DropdownWithPopoverProps = Dropdown as React.ComponentType< - Dropdown.Props & { popoverProps: Omit< Popover.Props, 'children' > } ->; - const InboxNoteCard: React.FC< InboxNoteProps > = ( { note, lastRead, @@ -73,7 +69,6 @@ const InboxNoteCard: React.FC< InboxNoteProps > = ( { } ) => { const [ clickedActionText, setClickedActionText ] = useState( false ); const hasBeenSeen = useRef( false ); - const toggleButtonRef = useRef< HTMLButtonElement >( null ); const linkCallbackRef = useCallbackOnLinkClick( ( innerLink ) => { if ( onBodyLinkClick ) { onBodyLinkClick( note, innerLink ); @@ -91,101 +86,18 @@ const InboxNoteCard: React.FC< InboxNoteProps > = ( { } }; - const handleBlur = ( event: React.FocusEvent, onClose: () => void ) => { - const dropdownClasses = [ - 'woocommerce-admin-dismiss-notification', - 'components-popover__content', - 'components-dropdown__content', - ]; - // This line is for IE compatibility. - let relatedTarget: EventTarget | Element | null = null; - if ( event.relatedTarget ) { - relatedTarget = event.relatedTarget; - } else if ( toggleButtonRef.current ) { - const ownerDoc = toggleButtonRef.current.ownerDocument; - relatedTarget = ownerDoc ? ownerDoc.activeElement : null; - } - let isClickOutsideDropdown = false; - if ( relatedTarget && 'className' in relatedTarget ) { - const classNames = relatedTarget.className; - isClickOutsideDropdown = dropdownClasses.some( ( cName ) => - classNames.includes( cName ) - ); - } - if ( isClickOutsideDropdown ) { - event.preventDefault(); - } else { - onClose(); - } - }; - - const onDropdownDismiss = ( - type: 'note' | 'all', - onToggle: () => void - ) => { - if ( onDismiss ) { - onDismiss( note, type ); - } - onToggle(); - }; - const renderDismissButton = () => { if ( clickedActionText ) { return null; } return ( - ( - { - ( event.target as HTMLElement ).focus(); - onToggle(); - } } - ref={ toggleButtonRef } - onBlur={ ( event: React.FocusEvent ) => - handleBlur( event, onClose ) - } - > - { __( 'Dismiss', 'woocommerce-admin' ) } - - ) } - focusOnMount={ false } - popoverProps={ { noArrow: true } } - renderContent={ ( { onToggle } ) => ( - - - - onDropdownDismiss( 'note', onToggle ) - } - > - { __( - 'Dismiss this message', - 'woocommerce-admin' - ) } - - - - - onDropdownDismiss( 'all', onToggle ) - } - > - { __( - 'Dismiss all messages', - 'woocommerce-admin' - ) } - - - - ) } - /> + onDismiss && onDismiss( note ) } + > + { __( 'Dismiss', 'woocommerce-admin' ) } + ); }; @@ -249,7 +161,7 @@ const InboxNoteCard: React.FC< InboxNoteProps > = ( { ! dateCreatedGmt || new Date( dateCreatedGmt + 'Z' ).getTime() > lastRead; const date = dateCreated; - const hasImage = layout !== 'plain' && layout !== ''; + const hasImage = layout === 'thumbnail'; const cardClassName = classnames( 'woocommerce-inbox-message', className, diff --git a/plugins/woocommerce-admin/packages/experimental/src/inbox-note/style.scss b/plugins/woocommerce-admin/packages/experimental/src/inbox-note/style.scss index 0d548ff8cb2..811d96be201 100644 --- a/plugins/woocommerce-admin/packages/experimental/src/inbox-note/style.scss +++ b/plugins/woocommerce-admin/packages/experimental/src/inbox-note/style.scss @@ -4,7 +4,7 @@ background: $studio-white; border-radius: 2px; @include font-size( 13 ); - margin: 0 0 $gap-large; + margin: 0 0; -ms-box-orient: horizontal; &.banner { -webkit-flex-direction: column; @@ -22,13 +22,21 @@ height: 100%; } } + &:hover { + background: $gray-100; + cursor: pointer; + .woocommerce-inbox-message__actions button.woocommerce-admin-dismiss-notification { + visibility: visible; + } + } .woocommerce-homepage-column & { margin: 20px 0; } &:not(.is-placeholder) { - border: 1px solid $gray-200; + border: 0; + border-bottom: 1px solid $gray-200; } .line { @@ -91,6 +99,10 @@ } } +.woocommerce-inbox-message__wrapper .woocommerce-inbox-message__content { + padding-bottom: 0; +} + .woocommerce-inbox-message__text { color: $gray-700; font-style: normal; @@ -114,9 +126,6 @@ } .woocommerce-inbox-message__actions { - padding-top: $gap; - border-top: 1px solid $gray-200; - // Ensures any immediate child with a sibling has space between the items & > * + * { margin-left: 0.5em; @@ -125,7 +134,21 @@ a, button { cursor: pointer; + &.is-link { + text-decoration: none; + } } + + border-top: 0; + + button.woocommerce-admin-dismiss-notification { + color: $gray-700; + &:hover { + box-shadow: none !important; + } + visibility: hidden; + } + .components-dropdown { display: inline; @@ -150,6 +173,10 @@ } } } +.woocommerce-inbox-message__wrapper .woocommerce-inbox-message__actions { + padding-top: 0; +} + .woocommerce-inbox-dismiss-confirmation_modal { text-align: left; } diff --git a/plugins/woocommerce-admin/packages/experimental/src/inbox-note/test/inbox-note.tsx b/plugins/woocommerce-admin/packages/experimental/src/inbox-note/test/inbox-note.tsx index 6395f69ae57..bbc44f70bcb 100644 --- a/plugins/woocommerce-admin/packages/experimental/src/inbox-note/test/inbox-note.tsx +++ b/plugins/woocommerce-admin/packages/experimental/src/inbox-note/test/inbox-note.tsx @@ -155,7 +155,7 @@ describe( 'InboxNoteCard', () => { } ); describe( 'callbacks', () => { - it( 'should call onDismiss with note type when "Dismiss this message" is clicked', () => { + it( 'should call onDismiss with note when "Dismiss this message" is clicked', () => { const onDismiss = jest.fn(); const { getByText } = render( { /> ); userEvent.click( getByText( 'Dismiss' ) ); - userEvent.click( getByText( 'Dismiss this message' ) ); - expect( onDismiss ).toHaveBeenCalledWith( note, 'note' ); - } ); - - it( 'should call onDismiss with all type when "Dismiss all messages" is clicked', () => { - const onDismiss = jest.fn(); - const { getByText } = render( - - ); - userEvent.click( getByText( 'Dismiss' ) ); - userEvent.click( getByText( 'Dismiss all messages' ) ); - expect( onDismiss ).toHaveBeenCalledWith( note, 'all' ); + expect( onDismiss ).toHaveBeenCalledWith( note ); } ); it( 'should call onNoteActionClick with specific action when action is clicked', () => {